Added format protection block to avoid re-ordering of header files according to formatting rules.
270 lines
6.5 KiB
C
270 lines
6.5 KiB
C
#define LOG_MODULE "mouse"
|
|
|
|
// clang-format off
|
|
// Don't format because the order is important here
|
|
#include <windows.h>
|
|
#include <initguid.h>
|
|
// clang-format on
|
|
|
|
#include <malloc.h>
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <wchar.h>
|
|
|
|
#include "geninput/hid.h"
|
|
#include "geninput/mouse.h"
|
|
|
|
#include "util/defs.h"
|
|
#include "util/log.h"
|
|
#include "util/mem.h"
|
|
#include "util/str.h"
|
|
|
|
enum mouse_ctl_no {
|
|
MOUSE_CTL_BTN1,
|
|
MOUSE_CTL_BTN2,
|
|
MOUSE_CTL_BTN3,
|
|
MOUSE_CTL_BTN4,
|
|
MOUSE_CTL_BTN5,
|
|
MOUSE_CTL_X,
|
|
MOUSE_CTL_Y,
|
|
MOUSE_CTL_WHEEL,
|
|
|
|
MOUSE_CTL_COUNT
|
|
};
|
|
|
|
struct mouse {
|
|
struct hid_ri super;
|
|
wchar_t *name;
|
|
long last_x;
|
|
long last_y;
|
|
long values[MOUSE_CTL_COUNT];
|
|
};
|
|
|
|
static const struct hid_control mouse_controls[MOUSE_CTL_COUNT] = {
|
|
/* Left, right, middle, AUX1, AUX2 buttons */
|
|
{0x00090001, 0x00000000, 0x00000001, 0},
|
|
{0x00090002, 0x00000000, 0x00000001, 0},
|
|
{0x00090003, 0x00000000, 0x00000001, 0},
|
|
{0x00090004, 0x00000000, 0x00000001, 0},
|
|
{0x00090005, 0x00000000, 0x00000001, 0},
|
|
|
|
/* X axis */
|
|
{0x00010030, 0xC0000000, 0x3FFFFFFF, HID_FLAG_RELATIVE},
|
|
|
|
/* Y axis */
|
|
{0x00010031, 0xC0000000, 0x3FFFFFFF, HID_FLAG_RELATIVE},
|
|
|
|
/* Mouse wheel */
|
|
{0x00010038, 0xFFFF8000, 0x00007FFF, HID_FLAG_RELATIVE},
|
|
};
|
|
|
|
static const uint16_t mouse_down_flg[] = {
|
|
RI_MOUSE_BUTTON_1_DOWN,
|
|
RI_MOUSE_BUTTON_2_DOWN,
|
|
RI_MOUSE_BUTTON_3_DOWN,
|
|
RI_MOUSE_BUTTON_4_DOWN,
|
|
RI_MOUSE_BUTTON_5_DOWN,
|
|
};
|
|
|
|
static const uint16_t mouse_up_flg[] = {
|
|
RI_MOUSE_BUTTON_1_UP,
|
|
RI_MOUSE_BUTTON_2_UP,
|
|
RI_MOUSE_BUTTON_3_UP,
|
|
RI_MOUSE_BUTTON_4_UP,
|
|
RI_MOUSE_BUTTON_5_UP,
|
|
};
|
|
|
|
DEFINE_GUID(
|
|
mouse_guid,
|
|
0x378DE44C,
|
|
0x56EF,
|
|
0x11D1,
|
|
0xBC,
|
|
0x8C,
|
|
0x00,
|
|
0xA0,
|
|
0xC9,
|
|
0x14,
|
|
0x05,
|
|
0xDD);
|
|
|
|
static bool mouse_get_device_usage(const struct hid *hid, uint32_t *usage);
|
|
static bool
|
|
mouse_get_name(const struct hid *hid, wchar_t *chars, size_t *nchars);
|
|
static bool mouse_get_controls(
|
|
const struct hid *hid, struct hid_control *controls, size_t *ncontrols);
|
|
static bool mouse_get_lights(
|
|
const struct hid *hid, struct hid_light *lights, size_t *nlights);
|
|
static bool
|
|
mouse_get_value(struct hid *hid, size_t control_no, int32_t *out_value);
|
|
static bool
|
|
mouse_set_light(struct hid *hid, size_t light_no, uint32_t intensity);
|
|
static void mouse_handle_event(struct hid_ri *hid_ri, const RAWINPUT *ri);
|
|
static void mouse_close(struct hid *hid);
|
|
|
|
static const struct hid_ri_vtbl mouse_vtbl = {
|
|
{/* .close = */ mouse_close,
|
|
/* .get_device_usage = */ mouse_get_device_usage,
|
|
/* .get_name = */ mouse_get_name,
|
|
/* .get_controls = */ mouse_get_controls,
|
|
/* .get_lights = */ mouse_get_lights,
|
|
/* .get_value = */ mouse_get_value,
|
|
/* .set_light = */ mouse_set_light},
|
|
/* .handle_event = */ mouse_handle_event};
|
|
|
|
void mouse_create(struct hid_ri **hid_ri, const char *dev_node)
|
|
{
|
|
struct mouse *m;
|
|
char *tmp;
|
|
|
|
m = xcalloc(sizeof(*m));
|
|
m->super.vptr = &mouse_vtbl;
|
|
m->name = hid_ri_init_name(&mouse_guid, dev_node);
|
|
|
|
*hid_ri = &m->super;
|
|
|
|
if (!wstr_narrow(m->name, &tmp)) {
|
|
tmp = str_dup("???");
|
|
}
|
|
|
|
log_misc("Opened mouse on dev node %s", dev_node);
|
|
log_misc("... Product: %s", tmp);
|
|
|
|
free(tmp);
|
|
}
|
|
|
|
static bool mouse_get_device_usage(const struct hid *hid, uint32_t *usage)
|
|
{
|
|
*usage = MOUSE_DEVICE_USAGE;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
mouse_get_name(const struct hid *hid, wchar_t *chars, size_t *nchars)
|
|
{
|
|
struct mouse *m = containerof(hid, struct mouse, super);
|
|
|
|
return hid_ri_get_name(chars, nchars, m->name);
|
|
}
|
|
|
|
static bool mouse_get_controls(
|
|
const struct hid *hid, struct hid_control *controls, size_t *ncontrols)
|
|
{
|
|
return hid_ri_get_controls(
|
|
controls, ncontrols, mouse_controls, MOUSE_CTL_COUNT);
|
|
}
|
|
|
|
static bool mouse_get_lights(
|
|
const struct hid *hid, struct hid_light *lights, size_t *nlights)
|
|
{
|
|
log_assert(nlights != NULL);
|
|
|
|
if (lights == NULL) {
|
|
*nlights = 0;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
mouse_get_value(struct hid *hid, size_t control_no, int32_t *out_value)
|
|
{
|
|
struct mouse *m = containerof(hid, struct mouse, super);
|
|
long tmp;
|
|
|
|
log_assert(control_no < MOUSE_CTL_COUNT);
|
|
|
|
switch (control_no) {
|
|
case MOUSE_CTL_BTN1:
|
|
case MOUSE_CTL_BTN2:
|
|
case MOUSE_CTL_BTN3:
|
|
case MOUSE_CTL_BTN4:
|
|
case MOUSE_CTL_BTN5:
|
|
*out_value = m->values[control_no];
|
|
|
|
return true;
|
|
|
|
case MOUSE_CTL_X:
|
|
case MOUSE_CTL_Y:
|
|
case MOUSE_CTL_WHEEL:
|
|
do {
|
|
tmp = m->values[control_no];
|
|
} while (InterlockedCompareExchange(
|
|
&m->values[control_no], 0, tmp) != tmp);
|
|
|
|
*out_value = tmp;
|
|
|
|
return true;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static bool
|
|
mouse_set_light(struct hid *hid, size_t light_no, uint32_t intensity)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
static void mouse_handle_event(struct hid_ri *hid_ri, const RAWINPUT *ri)
|
|
{
|
|
struct mouse *m = containerof(hid_ri, struct mouse, super);
|
|
long tmp;
|
|
long dwheel;
|
|
long dx;
|
|
long dy;
|
|
int i;
|
|
|
|
if (ri->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) {
|
|
dx = ri->data.mouse.lLastX - m->last_x;
|
|
dy = ri->data.mouse.lLastY - m->last_y;
|
|
|
|
m->last_x = ri->data.mouse.lLastX;
|
|
m->last_y = ri->data.mouse.lLastY;
|
|
} else {
|
|
dx = ri->data.mouse.lLastX;
|
|
dy = ri->data.mouse.lLastY;
|
|
|
|
m->last_x += dx;
|
|
m->last_y += dy;
|
|
}
|
|
|
|
do {
|
|
tmp = m->values[MOUSE_CTL_X];
|
|
} while (InterlockedCompareExchange(
|
|
&m->values[MOUSE_CTL_X], tmp + dx, tmp) != tmp);
|
|
|
|
do {
|
|
tmp = m->values[MOUSE_CTL_Y];
|
|
} while (InterlockedCompareExchange(
|
|
&m->values[MOUSE_CTL_Y], tmp + dy, tmp) != tmp);
|
|
|
|
if (ri->data.mouse.usButtonFlags & RI_MOUSE_WHEEL) {
|
|
dwheel = ri->data.mouse.usButtonData;
|
|
|
|
do {
|
|
tmp = m->values[MOUSE_CTL_WHEEL];
|
|
} while (InterlockedCompareExchange(
|
|
&m->values[MOUSE_CTL_WHEEL], tmp + dwheel, tmp) != tmp);
|
|
}
|
|
|
|
for (i = 0; i < 5; i++) {
|
|
if (ri->data.mouse.usButtonFlags & mouse_down_flg[i]) {
|
|
m->values[i] = 1;
|
|
} else if (ri->data.mouse.usButtonFlags & mouse_up_flg[i]) {
|
|
m->values[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void mouse_close(struct hid *hid)
|
|
{
|
|
struct mouse *m = containerof(hid, struct mouse, super);
|
|
|
|
free(m->name);
|
|
free(m);
|
|
}
|