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)
{
case SETSU_EVENT_DEVICE_ADDED:
setsu_connect(setsu, event->path);
setsu_connect(setsu, event->path, event->dev_type);
break;
case SETSU_EVENT_DEVICE_REMOVED:
for(auto it=setsu_ids.begin(); it!=setsu_ids.end();)

View file

@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.2)
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")
@ -17,9 +17,8 @@ find_package(Udev REQUIRED)
find_package(Evdev REQUIRED)
target_link_libraries(setsu Udev::libudev Evdev::libevdev)
if(SETSU_BUILD_DEMO)
add_executable(setsu-demo
demo/main.c)
target_link_libraries(setsu-demo setsu)
if(SETSU_BUILD_DEMOS)
add_executable(setsu-demo-touchpad demo/touchpad.c)
target_link_libraries(setsu-demo-touchpad setsu)
endif()

View file

@ -68,11 +68,15 @@ void event(SetsuEvent *event, void *user)
switch(event->type)
{
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!");
break;
}
case SETSU_EVENT_DEVICE_REMOVED:
if(event->dev_type != SETSU_DEVICE_TYPE_TOUCHPAD)
break;
LOG("Device removed: %s\n", event->path);
break;
case SETSU_EVENT_TOUCH_DOWN:

View file

@ -13,13 +13,18 @@ typedef struct setsu_t Setsu;
typedef struct setsu_device_t SetsuDevice;
typedef int SetsuTrackingId;
typedef enum {
SETSU_DEVICE_TYPE_TOUCHPAD,
SETSU_DEVICE_TYPE_MOTION
} SetsuDeviceType;
typedef enum {
/* 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,
/* 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
* be disconnected and their pointers will be invalid immediately
* after the callback for this event returns. */
@ -53,7 +58,11 @@ typedef struct setsu_event_t
SetsuEventType type;
union
{
const char *path;
struct
{
const char *path;
SetsuDeviceType dev_type;
};
struct
{
SetsuDevice *dev;
@ -75,11 +84,11 @@ typedef void (*SetsuEventCb)(SetsuEvent *event, void *user);
Setsu *setsu_new();
void setsu_free(Setsu *setsu);
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);
const char *setsu_device_get_path(SetsuDevice *dev);
uint32_t setsu_device_get_width(SetsuDevice *dev);
uint32_t setsu_device_get_height(SetsuDevice *dev);
uint32_t setsu_device_touchpad_get_width(SetsuDevice *dev);
uint32_t setsu_device_touchpad_get_height(SetsuDevice *dev);
#ifdef __cplusplus
}

View file

@ -25,6 +25,7 @@
typedef struct setsu_avail_device_t
{
struct setsu_avail_device_t *next;
SetsuDeviceType type;
char *path;
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
@ -36,27 +37,38 @@ typedef struct setsu_device_t
{
struct setsu_device_t *next;
char *path;
SetsuDeviceType type;
int fd;
struct libevdev *evdev;
int min_x, min_y, max_x, max_y;
struct {
/* Saves the old tracking id that was just up-ed.
* also for handling "atomic" up->down
* 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
* tracking id that must be reported as up. */
int tracking_id_prev;
union
{
struct
{
int min_x, min_y, max_x, max_y;
int tracking_id;
int x, y;
bool downed;
bool pos_dirty;
} slots[SLOTS_COUNT];
unsigned int slot_cur;
struct
{
/* Saves the old tracking id that was just up-ed.
* also for handling "atomic" up->down
* 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
* tracking id that must be reported as up. */
int tracking_id_prev;
uint64_t buttons_prev;
uint64_t buttons_cur;
int tracking_id;
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;
struct setsu_t
@ -131,8 +143,8 @@ static void scan_udev(Setsu *setsu)
if(udev_enumerate_add_match_subsystem(udev_enum, "input") < 0)
goto beach;
if(udev_enumerate_add_match_property(udev_enum, "ID_INPUT_TOUCHPAD", "1") < 0)
goto beach;
//if(udev_enumerate_add_match_property(udev_enum, "ID_INPUT_TOUCHPAD", "1") < 0)
// goto beach;
if(udev_enumerate_scan_devices(udev_enum) < 0)
goto beach;
@ -153,7 +165,7 @@ beach:
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[] = {
// vendor id, model id
@ -162,8 +174,18 @@ static bool is_device_interesting(struct udev_device *dev)
0x54c, 0x0ce6 // DualSense
};
// 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"))
const char *touchpad_str = udev_device_get_property_value(dev, "ID_INPUT_TOUCHPAD");
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;
uint32_t vendor;
@ -221,12 +243,14 @@ static void update_udev_device(Setsu *setsu, struct udev_device *dev)
}
// not yet added
if(!is_device_interesting(dev))
SetsuDeviceType type;
if(!is_device_interesting(dev, &type))
return;
SetsuAvailDevice *adev = calloc(1, sizeof(SetsuAvailDevice));
if(!adev)
return;
adev->type = type;
adev->path = strdup(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;
}
SetsuDevice *setsu_connect(Setsu *setsu, const char *path)
SetsuDevice *setsu_connect(Setsu *setsu, const char *path, SetsuDeviceType type)
{
SetsuDevice *dev = calloc(1, sizeof(SetsuDevice));
if(!dev)
@ -281,6 +305,7 @@ SetsuDevice *setsu_connect(Setsu *setsu, const char *path)
dev->path = strdup(path);
if(!dev->path)
goto error;
dev->type = type;
dev->fd = open(dev->path, O_RDONLY | O_NONBLOCK);
if(dev->fd == -1)
@ -292,15 +317,23 @@ SetsuDevice *setsu_connect(Setsu *setsu, const char *path)
goto error;
}
dev->min_x = libevdev_get_abs_minimum(dev->evdev, ABS_X);
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++)
switch(type)
{
dev->slots[i].tracking_id_prev = -1;
dev->slots[i].tracking_id = -1;
case SETSU_DEVICE_TYPE_TOUCHPAD:
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;
@ -342,14 +375,18 @@ const char *setsu_device_get_path(SetsuDevice *dev)
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)
@ -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),
ev->value);
#endif
#define S dev->slots[dev->slot_cur]
switch(ev->type)
if(ev->type == EV_SYN && ev->code == SYN_REPORT)
{
case EV_ABS:
switch(ev->code)
device_drain(setsu, dev, cb, user);
return;
}
switch(dev->type)
{
case SETSU_DEVICE_TYPE_TOUCHPAD:
switch(ev->type)
{
case ABS_MT_SLOT:
if((unsigned int)ev->value >= SLOTS_COUNT)
case EV_ABS:
#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;
}
dev->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;
if(ev->value)
dev->touchpad.buttons_cur |= button;
else
dev->touchpad.buttons_cur &= ~button;
break;
}
}
break;
case EV_KEY: {
uint64_t button = button_from_evdev(ev->code);
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);
case SETSU_DEVICE_TYPE_MOTION:
// TODO: handle the events
break;
}
#undef S
}
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;
#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)
for(size_t i=0; i<SLOTS_COUNT; i++)
switch(dev->type)
{
if(dev->slots[i].tracking_id_prev != -1)
{
BEGIN_EVENT(SETSU_EVENT_TOUCH_UP);
event.tracking_id = dev->slots[i].tracking_id_prev;
SEND_EVENT();
dev->slots[i].tracking_id_prev = -1;
}
if(dev->slots[i].downed)
{
BEGIN_EVENT(SETSU_EVENT_TOUCH_DOWN);
event.tracking_id = dev->slots[i].tracking_id;
SEND_EVENT();
dev->slots[i].downed = false;
}
if(dev->slots[i].pos_dirty)
{
BEGIN_EVENT(SETSU_EVENT_TOUCH_POSITION);
event.tracking_id = dev->slots[i].tracking_id;
event.x = (uint32_t)(dev->slots[i].x - dev->min_x);
event.y = (uint32_t)(dev->slots[i].y - dev->min_y);
SEND_EVENT();
dev->slots[i].pos_dirty = false;
}
}
case SETSU_DEVICE_TYPE_TOUCHPAD:
for(size_t i=0; i<SLOTS_COUNT; i++)
{
if(dev->touchpad.slots[i].tracking_id_prev != -1)
{
BEGIN_EVENT(SETSU_EVENT_TOUCH_UP);
event.tracking_id = dev->touchpad.slots[i].tracking_id_prev;
SEND_EVENT();
dev->touchpad.slots[i].tracking_id_prev = -1;
}
if(dev->touchpad.slots[i].downed)
{
BEGIN_EVENT(SETSU_EVENT_TOUCH_DOWN);
event.tracking_id = dev->touchpad.slots[i].tracking_id;
SEND_EVENT();
dev->touchpad.slots[i].downed = false;
}
if(dev->touchpad.slots[i].pos_dirty)
{
BEGIN_EVENT(SETSU_EVENT_TOUCH_POSITION);
event.tracking_id = dev->touchpad.slots[i].tracking_id;
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;
for(uint64_t i=0; i<64; i++)
{
if(buttons_diff & 1)
{
uint64_t button = 1 << i;
BEGIN_EVENT((dev->buttons_cur & button) ? SETSU_EVENT_BUTTON_DOWN : SETSU_EVENT_BUTTON_UP);
event.button = button;
SEND_EVENT();
}
buttons_diff >>= 1;
if(!buttons_diff)
uint64_t buttons_diff = dev->touchpad.buttons_prev ^ dev->touchpad.buttons_cur;
for(uint64_t i=0; i<64; i++)
{
if(buttons_diff & 1)
{
uint64_t button = 1 << i;
BEGIN_EVENT((dev->touchpad.buttons_cur & button) ? SETSU_EVENT_BUTTON_DOWN : SETSU_EVENT_BUTTON_UP);
event.button = button;
SEND_EVENT();
}
buttons_diff >>= 1;
if(!buttons_diff)
break;
}
dev->touchpad.buttons_prev = dev->touchpad.buttons_cur;
break;
case SETSU_DEVICE_TYPE_MOTION:
// TODO
break;
}
dev->buttons_prev = dev->buttons_cur;
#undef BEGIN_EVENT
#undef SEND_EVENT
}