Add Motion Stub to Setsu

This commit is contained in:
Florian Märkl 2021-01-06 11:31:13 +01:00
commit abc9a27208
No known key found for this signature in database
GPG key ID: 125BC8A5A6A1E857
5 changed files with 196 additions and 130 deletions

View file

@ -409,7 +409,7 @@ void StreamSession::HandleSetsuEvent(SetsuEvent *event)
switch(event->type) switch(event->type)
{ {
case SETSU_EVENT_DEVICE_ADDED: case SETSU_EVENT_DEVICE_ADDED:
setsu_connect(setsu, event->path); setsu_connect(setsu, event->path, event->dev_type);
break; break;
case SETSU_EVENT_DEVICE_REMOVED: case SETSU_EVENT_DEVICE_REMOVED:
for(auto it=setsu_ids.begin(); it!=setsu_ids.end();) for(auto it=setsu_ids.begin(); it!=setsu_ids.end();)

View file

@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.2)
project(libsetsu) project(libsetsu)
option(SETSU_BUILD_DEMO "Build testing executable for libsetsu" OFF) option(SETSU_BUILD_DEMOS "Build testing executables for libsetsu" OFF)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
@ -17,9 +17,8 @@ find_package(Udev REQUIRED)
find_package(Evdev REQUIRED) find_package(Evdev REQUIRED)
target_link_libraries(setsu Udev::libudev Evdev::libevdev) target_link_libraries(setsu Udev::libudev Evdev::libevdev)
if(SETSU_BUILD_DEMO) if(SETSU_BUILD_DEMOS)
add_executable(setsu-demo add_executable(setsu-demo-touchpad demo/touchpad.c)
demo/main.c) target_link_libraries(setsu-demo-touchpad setsu)
target_link_libraries(setsu-demo setsu)
endif() endif()

View file

@ -68,11 +68,15 @@ void event(SetsuEvent *event, void *user)
switch(event->type) switch(event->type)
{ {
case SETSU_EVENT_DEVICE_ADDED: { case SETSU_EVENT_DEVICE_ADDED: {
SetsuDevice *dev = setsu_connect(setsu, event->path); if(event->dev_type != SETSU_DEVICE_TYPE_TOUCHPAD)
break;
SetsuDevice *dev = setsu_connect(setsu, event->path, SETSU_DEVICE_TYPE_TOUCHPAD);
LOG("Device added: %s, connect %s\n", event->path, dev ? "succeeded" : "FAILED!"); LOG("Device added: %s, connect %s\n", event->path, dev ? "succeeded" : "FAILED!");
break; break;
} }
case SETSU_EVENT_DEVICE_REMOVED: case SETSU_EVENT_DEVICE_REMOVED:
if(event->dev_type != SETSU_DEVICE_TYPE_TOUCHPAD)
break;
LOG("Device removed: %s\n", event->path); LOG("Device removed: %s\n", event->path);
break; break;
case SETSU_EVENT_TOUCH_DOWN: case SETSU_EVENT_TOUCH_DOWN:

View file

@ -13,13 +13,18 @@ typedef struct setsu_t Setsu;
typedef struct setsu_device_t SetsuDevice; typedef struct setsu_device_t SetsuDevice;
typedef int SetsuTrackingId; typedef int SetsuTrackingId;
typedef enum {
SETSU_DEVICE_TYPE_TOUCHPAD,
SETSU_DEVICE_TYPE_MOTION
} SetsuDeviceType;
typedef enum { typedef enum {
/* New device available to connect. /* New device available to connect.
* Event will have path set to the new device. */ * Event will have path and type set to the new device. */
SETSU_EVENT_DEVICE_ADDED, SETSU_EVENT_DEVICE_ADDED,
/* Previously available device removed. /* Previously available device removed.
* Event will have path set to the new device. * Event will have path and type set to the removed device.
* Any SetsuDevice connected to this path will automatically * Any SetsuDevice connected to this path will automatically
* be disconnected and their pointers will be invalid immediately * be disconnected and their pointers will be invalid immediately
* after the callback for this event returns. */ * after the callback for this event returns. */
@ -53,7 +58,11 @@ typedef struct setsu_event_t
SetsuEventType type; SetsuEventType type;
union union
{ {
const char *path; struct
{
const char *path;
SetsuDeviceType dev_type;
};
struct struct
{ {
SetsuDevice *dev; SetsuDevice *dev;
@ -75,11 +84,11 @@ typedef void (*SetsuEventCb)(SetsuEvent *event, void *user);
Setsu *setsu_new(); Setsu *setsu_new();
void setsu_free(Setsu *setsu); void setsu_free(Setsu *setsu);
void setsu_poll(Setsu *setsu, SetsuEventCb cb, void *user); void setsu_poll(Setsu *setsu, SetsuEventCb cb, void *user);
SetsuDevice *setsu_connect(Setsu *setsu, const char *path); SetsuDevice *setsu_connect(Setsu *setsu, const char *path, SetsuDeviceType type);
void setsu_disconnect(Setsu *setsu, SetsuDevice *dev); void setsu_disconnect(Setsu *setsu, SetsuDevice *dev);
const char *setsu_device_get_path(SetsuDevice *dev); const char *setsu_device_get_path(SetsuDevice *dev);
uint32_t setsu_device_get_width(SetsuDevice *dev); uint32_t setsu_device_touchpad_get_width(SetsuDevice *dev);
uint32_t setsu_device_get_height(SetsuDevice *dev); uint32_t setsu_device_touchpad_get_height(SetsuDevice *dev);
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -25,6 +25,7 @@
typedef struct setsu_avail_device_t typedef struct setsu_avail_device_t
{ {
struct setsu_avail_device_t *next; struct setsu_avail_device_t *next;
SetsuDeviceType type;
char *path; char *path;
bool connect_dirty; // whether the connect has not been sent as an event yet bool connect_dirty; // whether the connect has not been sent as an event yet
bool disconnect_dirty; // whether the disconnect has not been sent as an event yet bool disconnect_dirty; // whether the disconnect has not been sent as an event yet
@ -36,27 +37,38 @@ typedef struct setsu_device_t
{ {
struct setsu_device_t *next; struct setsu_device_t *next;
char *path; char *path;
SetsuDeviceType type;
int fd; int fd;
struct libevdev *evdev; struct libevdev *evdev;
int min_x, min_y, max_x, max_y;
struct { union
/* Saves the old tracking id that was just up-ed. {
* also for handling "atomic" up->down struct
* i.e. when there is an up, then down with a different tracking id {
* in a single frame (before SYN_REPORT), this saves the old int min_x, min_y, max_x, max_y;
* tracking id that must be reported as up. */
int tracking_id_prev;
int tracking_id; struct
int x, y; {
bool downed; /* Saves the old tracking id that was just up-ed.
bool pos_dirty; * also for handling "atomic" up->down
} slots[SLOTS_COUNT]; * i.e. when there is an up, then down with a different tracking id
unsigned int slot_cur; * in a single frame (before SYN_REPORT), this saves the old
* tracking id that must be reported as up. */
int tracking_id_prev;
uint64_t buttons_prev; int tracking_id;
uint64_t buttons_cur; int x, y;
bool downed;
bool pos_dirty;
} slots[SLOTS_COUNT];
unsigned int slot_cur;
uint64_t buttons_prev;
uint64_t buttons_cur;
} touchpad;
struct
{
} motion;
};
} SetsuDevice; } SetsuDevice;
struct setsu_t struct setsu_t
@ -131,8 +143,8 @@ static void scan_udev(Setsu *setsu)
if(udev_enumerate_add_match_subsystem(udev_enum, "input") < 0) if(udev_enumerate_add_match_subsystem(udev_enum, "input") < 0)
goto beach; goto beach;
if(udev_enumerate_add_match_property(udev_enum, "ID_INPUT_TOUCHPAD", "1") < 0) //if(udev_enumerate_add_match_property(udev_enum, "ID_INPUT_TOUCHPAD", "1") < 0)
goto beach; // goto beach;
if(udev_enumerate_scan_devices(udev_enum) < 0) if(udev_enumerate_scan_devices(udev_enum) < 0)
goto beach; goto beach;
@ -153,7 +165,7 @@ beach:
udev_enumerate_unref(udev_enum); udev_enumerate_unref(udev_enum);
} }
static bool is_device_interesting(struct udev_device *dev) static bool is_device_interesting(struct udev_device *dev, SetsuDeviceType *type)
{ {
static const uint32_t device_ids[] = { static const uint32_t device_ids[] = {
// vendor id, model id // vendor id, model id
@ -162,8 +174,18 @@ static bool is_device_interesting(struct udev_device *dev)
0x54c, 0x0ce6 // DualSense 0x54c, 0x0ce6 // DualSense
}; };
// Filter mouse-device (/dev/input/mouse*) away and only keep the evdev (/dev/input/event*) one: const char *touchpad_str = udev_device_get_property_value(dev, "ID_INPUT_TOUCHPAD");
if(!udev_device_get_property_value(dev, "ID_INPUT_TOUCHPAD_INTEGRATION")) const char *accel_str = udev_device_get_property_value(dev, "ID_INPUT_ACCELEROMETER");
if(touchpad_str && !strcmp(touchpad_str, "1"))
{
// Filter mouse-device (/dev/input/mouse*) away and only keep the evdev (/dev/input/event*) one:
if(!udev_device_get_property_value(dev, "ID_INPUT_TOUCHPAD_INTEGRATION"))
return false;
*type = SETSU_DEVICE_TYPE_TOUCHPAD;
}
else if(touchpad_str && !strcmp(touchpad_str, "1"))
*type = SETSU_DEVICE_TYPE_MOTION;
else
return false; return false;
uint32_t vendor; uint32_t vendor;
@ -221,12 +243,14 @@ static void update_udev_device(Setsu *setsu, struct udev_device *dev)
} }
// not yet added // not yet added
if(!is_device_interesting(dev)) SetsuDeviceType type;
if(!is_device_interesting(dev, &type))
return; return;
SetsuAvailDevice *adev = calloc(1, sizeof(SetsuAvailDevice)); SetsuAvailDevice *adev = calloc(1, sizeof(SetsuAvailDevice));
if(!adev) if(!adev)
return; return;
adev->type = type;
adev->path = strdup(path); adev->path = strdup(path);
if(!adev->path) if(!adev->path)
{ {
@ -272,7 +296,7 @@ bool get_dev_ids(const char *path, uint32_t *vendor_id, uint32_t *model_id)
return true; return true;
} }
SetsuDevice *setsu_connect(Setsu *setsu, const char *path) SetsuDevice *setsu_connect(Setsu *setsu, const char *path, SetsuDeviceType type)
{ {
SetsuDevice *dev = calloc(1, sizeof(SetsuDevice)); SetsuDevice *dev = calloc(1, sizeof(SetsuDevice));
if(!dev) if(!dev)
@ -281,6 +305,7 @@ SetsuDevice *setsu_connect(Setsu *setsu, const char *path)
dev->path = strdup(path); dev->path = strdup(path);
if(!dev->path) if(!dev->path)
goto error; goto error;
dev->type = type;
dev->fd = open(dev->path, O_RDONLY | O_NONBLOCK); dev->fd = open(dev->path, O_RDONLY | O_NONBLOCK);
if(dev->fd == -1) if(dev->fd == -1)
@ -292,15 +317,23 @@ SetsuDevice *setsu_connect(Setsu *setsu, const char *path)
goto error; goto error;
} }
dev->min_x = libevdev_get_abs_minimum(dev->evdev, ABS_X); switch(type)
dev->min_y = libevdev_get_abs_minimum(dev->evdev, ABS_Y);
dev->max_x = libevdev_get_abs_maximum(dev->evdev, ABS_X);
dev->max_y = libevdev_get_abs_maximum(dev->evdev, ABS_Y);
for(size_t i=0; i<SLOTS_COUNT; i++)
{ {
dev->slots[i].tracking_id_prev = -1; case SETSU_DEVICE_TYPE_TOUCHPAD:
dev->slots[i].tracking_id = -1; dev->touchpad.min_x = libevdev_get_abs_minimum(dev->evdev, ABS_X);
dev->touchpad.min_y = libevdev_get_abs_minimum(dev->evdev, ABS_Y);
dev->touchpad.max_x = libevdev_get_abs_maximum(dev->evdev, ABS_X);
dev->touchpad.max_y = libevdev_get_abs_maximum(dev->evdev, ABS_Y);
for(size_t i=0; i<SLOTS_COUNT; i++)
{
dev->touchpad.slots[i].tracking_id_prev = -1;
dev->touchpad.slots[i].tracking_id = -1;
}
break;
case SETSU_DEVICE_TYPE_MOTION:
// TODO: init to defaults
break;
} }
dev->next = setsu->dev; dev->next = setsu->dev;
@ -342,14 +375,18 @@ const char *setsu_device_get_path(SetsuDevice *dev)
return dev->path; return dev->path;
} }
uint32_t setsu_device_get_width(SetsuDevice *dev) uint32_t setsu_device_touchpad_get_width(SetsuDevice *dev)
{ {
return dev->max_x - dev->min_x; if(dev->type != SETSU_DEVICE_TYPE_TOUCHPAD)
return 0;
return dev->touchpad.max_x - dev->touchpad.min_x;
} }
uint32_t setsu_device_get_height(SetsuDevice *dev) uint32_t setsu_device_touchpad_get_height(SetsuDevice *dev)
{ {
return dev->max_y - dev->min_y; if(dev->type != SETSU_DEVICE_TYPE_TOUCHPAD)
return 0;
return dev->touchpad.max_y - dev->touchpad.min_y;
} }
void kill_avail_device(Setsu *setsu, SetsuAvailDevice *adev) void kill_avail_device(Setsu *setsu, SetsuAvailDevice *adev)
@ -466,59 +503,68 @@ static void device_event(Setsu *setsu, SetsuDevice *dev, struct input_event *ev,
libevdev_event_code_get_name(ev->type, ev->code), libevdev_event_code_get_name(ev->type, ev->code),
ev->value); ev->value);
#endif #endif
#define S dev->slots[dev->slot_cur] if(ev->type == EV_SYN && ev->code == SYN_REPORT)
switch(ev->type)
{ {
case EV_ABS: device_drain(setsu, dev, cb, user);
switch(ev->code) return;
}
switch(dev->type)
{
case SETSU_DEVICE_TYPE_TOUCHPAD:
switch(ev->type)
{ {
case ABS_MT_SLOT: case EV_ABS:
if((unsigned int)ev->value >= SLOTS_COUNT) #define S dev->touchpad.slots[dev->touchpad.slot_cur]
switch(ev->code)
{ {
SETSU_LOG("slot too high\n"); case ABS_MT_SLOT:
if((unsigned int)ev->value >= SLOTS_COUNT)
{
SETSU_LOG("slot too high\n");
break;
}
dev->touchpad.slot_cur = ev->value;
break;
case ABS_MT_TRACKING_ID:
if(S.tracking_id != -1 && S.tracking_id_prev == -1)
{
// up the tracking id
S.tracking_id_prev = S.tracking_id;
// reset the rest
S.x = S.y = 0;
S.pos_dirty = false;
}
S.tracking_id = ev->value;
if(ev->value != -1)
S.downed = true;
break;
case ABS_MT_POSITION_X:
S.x = ev->value;
S.pos_dirty = true;
break;
case ABS_MT_POSITION_Y:
S.y = ev->value;
S.pos_dirty = true;
break;
}
break;
#undef S
case EV_KEY: {
uint64_t button = button_from_evdev(ev->code);
if(!button)
break; break;
} if(ev->value)
dev->slot_cur = ev->value; dev->touchpad.buttons_cur |= button;
break; else
case ABS_MT_TRACKING_ID: dev->touchpad.buttons_cur &= ~button;
if(S.tracking_id != -1 && S.tracking_id_prev == -1)
{
// up the tracking id
S.tracking_id_prev = S.tracking_id;
// reset the rest
S.x = S.y = 0;
S.pos_dirty = false;
}
S.tracking_id = ev->value;
if(ev->value != -1)
S.downed = true;
break;
case ABS_MT_POSITION_X:
S.x = ev->value;
S.pos_dirty = true;
break;
case ABS_MT_POSITION_Y:
S.y = ev->value;
S.pos_dirty = true;
break; break;
}
} }
break; break;
case EV_KEY: { case SETSU_DEVICE_TYPE_MOTION:
uint64_t button = button_from_evdev(ev->code); // TODO: handle the events
if(!button)
break;
if(ev->value)
dev->buttons_cur |= button;
else
dev->buttons_cur &= ~button;
break;
}
case EV_SYN:
if(ev->code == SYN_REPORT)
device_drain(setsu, dev, cb, user);
break; break;
} }
#undef S
} }
static void device_drain(Setsu *setsu, SetsuDevice *dev, SetsuEventCb cb, void *user) static void device_drain(Setsu *setsu, SetsuDevice *dev, SetsuEventCb cb, void *user)
@ -526,48 +572,56 @@ static void device_drain(Setsu *setsu, SetsuDevice *dev, SetsuEventCb cb, void *
SetsuEvent event; SetsuEvent event;
#define BEGIN_EVENT(tp) do { memset(&event, 0, sizeof(event)); event.dev = dev; event.type = tp; } while(0) #define BEGIN_EVENT(tp) do { memset(&event, 0, sizeof(event)); event.dev = dev; event.type = tp; } while(0)
#define SEND_EVENT() do { cb(&event, user); } while (0) #define SEND_EVENT() do { cb(&event, user); } while (0)
for(size_t i=0; i<SLOTS_COUNT; i++) switch(dev->type)
{ {
if(dev->slots[i].tracking_id_prev != -1) case SETSU_DEVICE_TYPE_TOUCHPAD:
{ for(size_t i=0; i<SLOTS_COUNT; i++)
BEGIN_EVENT(SETSU_EVENT_TOUCH_UP); {
event.tracking_id = dev->slots[i].tracking_id_prev; if(dev->touchpad.slots[i].tracking_id_prev != -1)
SEND_EVENT(); {
dev->slots[i].tracking_id_prev = -1; BEGIN_EVENT(SETSU_EVENT_TOUCH_UP);
} event.tracking_id = dev->touchpad.slots[i].tracking_id_prev;
if(dev->slots[i].downed) SEND_EVENT();
{ dev->touchpad.slots[i].tracking_id_prev = -1;
BEGIN_EVENT(SETSU_EVENT_TOUCH_DOWN); }
event.tracking_id = dev->slots[i].tracking_id; if(dev->touchpad.slots[i].downed)
SEND_EVENT(); {
dev->slots[i].downed = false; BEGIN_EVENT(SETSU_EVENT_TOUCH_DOWN);
} event.tracking_id = dev->touchpad.slots[i].tracking_id;
if(dev->slots[i].pos_dirty) SEND_EVENT();
{ dev->touchpad.slots[i].downed = false;
BEGIN_EVENT(SETSU_EVENT_TOUCH_POSITION); }
event.tracking_id = dev->slots[i].tracking_id; if(dev->touchpad.slots[i].pos_dirty)
event.x = (uint32_t)(dev->slots[i].x - dev->min_x); {
event.y = (uint32_t)(dev->slots[i].y - dev->min_y); BEGIN_EVENT(SETSU_EVENT_TOUCH_POSITION);
SEND_EVENT(); event.tracking_id = dev->touchpad.slots[i].tracking_id;
dev->slots[i].pos_dirty = false; event.x = (uint32_t)(dev->touchpad.slots[i].x - dev->touchpad.min_x);
} event.y = (uint32_t)(dev->touchpad.slots[i].y - dev->touchpad.min_y);
} SEND_EVENT();
dev->touchpad.slots[i].pos_dirty = false;
}
}
uint64_t buttons_diff = dev->buttons_prev ^ dev->buttons_cur; uint64_t buttons_diff = dev->touchpad.buttons_prev ^ dev->touchpad.buttons_cur;
for(uint64_t i=0; i<64; i++) for(uint64_t i=0; i<64; i++)
{ {
if(buttons_diff & 1) if(buttons_diff & 1)
{ {
uint64_t button = 1 << i; uint64_t button = 1 << i;
BEGIN_EVENT((dev->buttons_cur & button) ? SETSU_EVENT_BUTTON_DOWN : SETSU_EVENT_BUTTON_UP); BEGIN_EVENT((dev->touchpad.buttons_cur & button) ? SETSU_EVENT_BUTTON_DOWN : SETSU_EVENT_BUTTON_UP);
event.button = button; event.button = button;
SEND_EVENT(); SEND_EVENT();
} }
buttons_diff >>= 1; buttons_diff >>= 1;
if(!buttons_diff) if(!buttons_diff)
break;
}
dev->touchpad.buttons_prev = dev->touchpad.buttons_cur;
break;
case SETSU_DEVICE_TYPE_MOTION:
// TODO
break; break;
} }
dev->buttons_prev = dev->buttons_cur;
#undef BEGIN_EVENT #undef BEGIN_EVENT
#undef SEND_EVENT #undef SEND_EVENT
} }