From 90a219a3756a9043f5f10e7a63aeb0235f954dce Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Sat, 5 Oct 2013 21:15:55 -0700 Subject: [PATCH] Fixed bug where a Logitech wireless keyboard with built-in mouse touchpad didn't get recongized as both devices. --- src/core/linux/SDL_udev.c | 32 ++-- src/core/linux/SDL_udev.h | 13 +- src/input/evdev/SDL_evdev.c | 264 +++++++++++---------------- src/input/evdev/SDL_evdev.h | 7 - src/joystick/linux/SDL_sysjoystick.c | 6 +- 5 files changed, 134 insertions(+), 188 deletions(-) diff --git a/src/core/linux/SDL_udev.c b/src/core/linux/SDL_udev.c index 82f3e6636094e..c08c287e814b7 100644 --- a/src/core/linux/SDL_udev.c +++ b/src/core/linux/SDL_udev.c @@ -279,7 +279,7 @@ device_event(SDL_UDEV_deviceevent type, struct udev_device *dev) { const char *subsystem; const char *val = NULL; - SDL_UDEV_deviceclass devclass = 0; + int devclass = 0; const char *path; SDL_UDEV_CallbackList *item; @@ -291,32 +291,26 @@ device_event(SDL_UDEV_deviceevent type, struct udev_device *dev) subsystem = _this->udev_device_get_subsystem(dev); if (SDL_strcmp(subsystem, "sound") == 0) { devclass = SDL_UDEV_DEVICE_SOUND; - } - else if (SDL_strcmp(subsystem, "input") == 0) { + } else if (SDL_strcmp(subsystem, "input") == 0) { val = _this->udev_device_get_property_value(dev, "ID_INPUT_JOYSTICK"); if (val != NULL && SDL_strcmp(val, "1") == 0 ) { - devclass = SDL_UDEV_DEVICE_JOYSTICK; + devclass |= SDL_UDEV_DEVICE_JOYSTICK; } - if (devclass == 0) { - val = _this->udev_device_get_property_value(dev, "ID_INPUT_MOUSE"); - if (val != NULL && SDL_strcmp(val, "1") == 0 ) { - devclass = SDL_UDEV_DEVICE_MOUSE; - } + val = _this->udev_device_get_property_value(dev, "ID_INPUT_MOUSE"); + if (val != NULL && SDL_strcmp(val, "1") == 0 ) { + devclass |= SDL_UDEV_DEVICE_MOUSE; } - - if (devclass == 0) { - val = _this->udev_device_get_property_value(dev, "ID_INPUT_KEYBOARD"); - if (val != NULL && SDL_strcmp(val, "1") == 0 ) { - devclass = SDL_UDEV_DEVICE_KEYBOARD; - } + + val = _this->udev_device_get_property_value(dev, "ID_INPUT_KEYBOARD"); + if (val != NULL && SDL_strcmp(val, "1") == 0 ) { + devclass |= SDL_UDEV_DEVICE_KEYBOARD; } - + if (devclass == 0) { return; } - } - else { + } else { return; } @@ -401,4 +395,4 @@ SDL_UDEV_DelCallback(SDL_UDEV_Callback cb) } -#endif /* SDL_USE_LIBUDEV */ \ No newline at end of file +#endif /* SDL_USE_LIBUDEV */ diff --git a/src/core/linux/SDL_udev.h b/src/core/linux/SDL_udev.h index 0ec86db1c5f94..1c26f11044a2e 100644 --- a/src/core/linux/SDL_udev.h +++ b/src/core/linux/SDL_udev.h @@ -46,15 +46,16 @@ typedef enum SDL_UDEV_DEVICEREMOVED } SDL_UDEV_deviceevent; +/* A device can be any combination of these classes */ typedef enum { - SDL_UDEV_DEVICE_MOUSE = 0x0001, - SDL_UDEV_DEVICE_KEYBOARD, - SDL_UDEV_DEVICE_JOYSTICK, - SDL_UDEV_DEVICE_SOUND + SDL_UDEV_DEVICE_MOUSE = 0x0001, + SDL_UDEV_DEVICE_KEYBOARD = 0x0002, + SDL_UDEV_DEVICE_JOYSTICK = 0x0004, + SDL_UDEV_DEVICE_SOUND = 0x0008 } SDL_UDEV_deviceclass; -typedef void (*SDL_UDEV_Callback)(SDL_UDEV_deviceevent udev_type, SDL_UDEV_deviceclass udev_class, const char *devpath); +typedef void (*SDL_UDEV_Callback)(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath); typedef struct SDL_UDEV_CallbackList { SDL_UDEV_Callback callback; @@ -111,4 +112,4 @@ extern void SDL_UDEV_DelCallback(SDL_UDEV_Callback cb); #endif /* HAVE_LIBUDEV_H */ -#endif /* _SDL_udev_h */ \ No newline at end of file +#endif /* _SDL_udev_h */ diff --git a/src/input/evdev/SDL_evdev.c b/src/input/evdev/SDL_evdev.c index b9b64730604f5..497cd40d18c7f 100644 --- a/src/input/evdev/SDL_evdev.c +++ b/src/input/evdev/SDL_evdev.c @@ -62,8 +62,8 @@ static void SDL_EVDEV_sync_device(SDL_evdevlist_item *item); static int SDL_EVDEV_device_removed(const char *devpath); #if SDL_USE_LIBUDEV -static int SDL_EVDEV_device_added(const SDL_UDEV_deviceclass devclass, const char *devpath); -void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_type, SDL_UDEV_deviceclass udev_class, const char *devpath); +static int SDL_EVDEV_device_added(const char *devpath); +void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath); #endif /* SDL_USE_LIBUDEV */ static SDL_Scancode EVDEV_Keycodes[] = { @@ -403,7 +403,6 @@ SDL_EVDEV_Init(void) /* We need a physical terminal (not PTS) to be able to translate key code to symbols via the kernel tables */ _this->console_fd = SDL_EVDEV_get_console_fd(); - } _this->ref_count += 1; @@ -445,43 +444,28 @@ SDL_EVDEV_Quit(void) } #if SDL_USE_LIBUDEV -void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_type, SDL_UDEV_deviceclass udev_class, const char *devpath) +void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath) { - SDL_EVDEV_deviceclass devclass; - if (devpath == NULL) { return; } - switch( udev_class ) - { - case SDL_UDEV_DEVICE_MOUSE: - devclass = SDL_EVDEV_DEVICE_MOUSE; - break; - - case SDL_UDEV_DEVICE_KEYBOARD: - devclass = SDL_EVDEV_DEVICE_KEYBOARD; - break; - - default: - return; + if (!(udev_class & (SDL_UDEV_DEVICE_MOUSE|SDL_UDEV_DEVICE_KEYBOARD))) { + return; } - - switch( udev_type ) - { - case SDL_UDEV_DEVICEADDED: - SDL_EVDEV_device_added(devclass, devpath); - break; - - case SDL_UDEV_DEVICEREMOVED: - SDL_EVDEV_device_removed(devpath); - break; + + switch( udev_type ) { + case SDL_UDEV_DEVICEADDED: + SDL_EVDEV_device_added(devpath); + break; - default: - break; + case SDL_UDEV_DEVICEREMOVED: + SDL_EVDEV_device_removed(devpath); + break; + default: + break; } - } #endif /* SDL_USE_LIBUDEV */ @@ -507,137 +491,114 @@ SDL_EVDEV_Poll(void) SDL_UDEV_Poll(); #endif + mouse = SDL_GetMouse(); + for (item = _this->first; item != NULL; item = item->next) { while ((len = read(item->fd, events, (sizeof events))) > 0) { len /= sizeof(events[0]); for (i = 0; i < len; ++i) { - switch(item->devclass) { - case SDL_EVDEV_DEVICE_KEYBOARD: - switch (events[i].type) { - case EV_KEY: - scan_code = SDL_EVDEV_translate_keycode(events[i].code); - if (scan_code != SDL_SCANCODE_UNKNOWN) { - if (events[i].value == 0) { - SDL_SendKeyboardKey(SDL_RELEASED, scan_code); - } - else if (events[i].value == 1 || events[i].value == 2 /* Key repeated */ ) { - SDL_SendKeyboardKey(SDL_PRESSED, scan_code); + switch (events[i].type) { + case EV_KEY: + if (events[i].code >= BTN_MOUSE && events[i].code < BTN_MOUSE + SDL_arraysize(EVDEV_MouseButtons)) { + mouse_button = events[i].code - BTN_MOUSE; + if (events[i].value == 0) { + SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_RELEASED, EVDEV_MouseButtons[mouse_button]); + } else if (events[i].value == 1) { + SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_PRESSED, EVDEV_MouseButtons[mouse_button]); + } + break; + } + + /* Probably keyboard */ + scan_code = SDL_EVDEV_translate_keycode(events[i].code); + if (scan_code != SDL_SCANCODE_UNKNOWN) { + if (events[i].value == 0) { + SDL_SendKeyboardKey(SDL_RELEASED, scan_code); + } else if (events[i].value == 1 || events[i].value == 2 /* Key repeated */ ) { + SDL_SendKeyboardKey(SDL_PRESSED, scan_code); #ifdef SDL_INPUT_LINUXKD - if (_this->console_fd >= 0) { - kbe.kb_index = events[i].code; - /* Convert the key to an UTF-8 char */ - /* Ref: http://www.linuxjournal.com/article/2783 */ - modstate = SDL_GetModState(); - kbe.kb_table = 0; - - /* Ref: http://graphics.stanford.edu/~seander/bithacks.html#ConditionalSetOrClearBitsWithoutBranching */ - kbe.kb_table |= -( (modstate & KMOD_LCTRL) != 0) & (1 << KG_CTRLL | 1 << KG_CTRL); - kbe.kb_table |= -( (modstate & KMOD_RCTRL) != 0) & (1 << KG_CTRLR | 1 << KG_CTRL); - kbe.kb_table |= -( (modstate & KMOD_LSHIFT) != 0) & (1 << KG_SHIFTL | 1 << KG_SHIFT); - kbe.kb_table |= -( (modstate & KMOD_RSHIFT) != 0) & (1 << KG_SHIFTR | 1 << KG_SHIFT); - kbe.kb_table |= -( (modstate & KMOD_LALT) != 0) & (1 << KG_ALT); - kbe.kb_table |= -( (modstate & KMOD_RALT) != 0) & (1 << KG_ALTGR); - - if(ioctl(_this->console_fd, KDGKBENT, (unsigned long)&kbe) == 0 && - ( (KTYP(kbe.kb_value) == KT_LATIN) || (KTYP(kbe.kb_value) == KT_ASCII) || (KTYP(kbe.kb_value) == KT_LETTER) )) - { - kval = KVAL(kbe.kb_value); - - /* While there's a KG_CAPSSHIFT symbol, it's not useful to build the table index with it - * because 1 << KG_CAPSSHIFT overflows the 8 bits of kb_table - * So, we do the CAPS LOCK logic here. Note that isalpha depends on the locale! - */ - if ( modstate & KMOD_CAPS && isalpha(kval) ) { - if ( isupper(kval) ) { - kval = tolower(kval); - } - else { - kval = toupper(kval); - } - } - - /* Convert to UTF-8 and send */ - end = SDL_UCS4ToUTF8( kval, keysym); - *end = '\0'; - SDL_SendKeyboardText(keysym); + if (_this->console_fd >= 0) { + kbe.kb_index = events[i].code; + /* Convert the key to an UTF-8 char */ + /* Ref: http://www.linuxjournal.com/article/2783 */ + modstate = SDL_GetModState(); + kbe.kb_table = 0; + + /* Ref: http://graphics.stanford.edu/~seander/bithacks.html#ConditionalSetOrClearBitsWithoutBranching */ + kbe.kb_table |= -( (modstate & KMOD_LCTRL) != 0) & (1 << KG_CTRLL | 1 << KG_CTRL); + kbe.kb_table |= -( (modstate & KMOD_RCTRL) != 0) & (1 << KG_CTRLR | 1 << KG_CTRL); + kbe.kb_table |= -( (modstate & KMOD_LSHIFT) != 0) & (1 << KG_SHIFTL | 1 << KG_SHIFT); + kbe.kb_table |= -( (modstate & KMOD_RSHIFT) != 0) & (1 << KG_SHIFTR | 1 << KG_SHIFT); + kbe.kb_table |= -( (modstate & KMOD_LALT) != 0) & (1 << KG_ALT); + kbe.kb_table |= -( (modstate & KMOD_RALT) != 0) & (1 << KG_ALTGR); + + if (ioctl(_this->console_fd, KDGKBENT, (unsigned long)&kbe) == 0 && + ((KTYP(kbe.kb_value) == KT_LATIN) || (KTYP(kbe.kb_value) == KT_ASCII) || (KTYP(kbe.kb_value) == KT_LETTER))) + { + kval = KVAL(kbe.kb_value); + + /* While there's a KG_CAPSSHIFT symbol, it's not useful to build the table index with it + * because 1 << KG_CAPSSHIFT overflows the 8 bits of kb_table + * So, we do the CAPS LOCK logic here. Note that isalpha depends on the locale! + */ + if ( modstate & KMOD_CAPS && isalpha(kval) ) { + if ( isupper(kval) ) { + kval = tolower(kval); + } else { + kval = toupper(kval); } } -#endif + + /* Convert to UTF-8 and send */ + end = SDL_UCS4ToUTF8( kval, keysym); + *end = '\0'; + SDL_SendKeyboardText(keysym); } } - break; - - default: - break; - } - break; /* SDL_EVDEV_DEVICE_KEYBOARD */ - - case SDL_EVDEV_DEVICE_MOUSE: - mouse = SDL_GetMouse(); - switch (events[i].type) { - case EV_KEY: - mouse_button = events[i].code - BTN_MOUSE; - if (mouse_button >= 0 && mouse_button < SDL_arraysize(EVDEV_MouseButtons)) { - if (events[i].value == 0) { - SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_RELEASED, EVDEV_MouseButtons[mouse_button]); - } - else if (events[i].value == 1) { - SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_PRESSED, EVDEV_MouseButtons[mouse_button]); - } - } - break; - case EV_ABS: - switch(events[i].code) { - case ABS_X: - SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, events[i].value, mouse->y); - break; - case ABS_Y: - SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, mouse->x, events[i].value); - break; - default: - break; - } - break; - case EV_REL: - switch(events[i].code) { - case REL_X: - SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, events[i].value, 0); - break; - case REL_Y: - SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, 0, events[i].value); - break; - case REL_WHEEL: - SDL_SendMouseWheel(mouse->focus, mouse->mouseID, 0, events[i].value); - break; - case REL_HWHEEL: - SDL_SendMouseWheel(mouse->focus, mouse->mouseID, events[i].value, 0); - break; - default: - break; - } - break; - default: - break; +#endif /* SDL_INPUT_LINUXKD */ } - break; /* SDL_EVDEV_DEVICE_MOUSE */ - + } + break; + case EV_ABS: + switch(events[i].code) { + case ABS_X: + SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, events[i].value, mouse->y); + break; + case ABS_Y: + SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, mouse->x, events[i].value); + break; default: break; + } + break; + case EV_REL: + switch(events[i].code) { + case REL_X: + SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, events[i].value, 0); + break; + case REL_Y: + SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, 0, events[i].value); + break; + case REL_WHEEL: + SDL_SendMouseWheel(mouse->focus, mouse->mouseID, 0, events[i].value); + break; + case REL_HWHEEL: + SDL_SendMouseWheel(mouse->focus, mouse->mouseID, events[i].value, 0); + break; + default: + break; + } + break; + case EV_SYN: + switch (events[i].code) { + case SYN_DROPPED: + SDL_EVDEV_sync_device(item); + break; + default: + break; + } + break; } - - - /* Handle events not specific to any type of device */ - switch (events[i].type) { - case EV_SYN: - switch (events[i].code) { - case SYN_DROPPED : - SDL_EVDEV_sync_device(item); - break; - default: - break; - } - } - } } } @@ -665,7 +626,7 @@ SDL_EVDEV_sync_device(SDL_evdevlist_item *item) #if SDL_USE_LIBUDEV static int -SDL_EVDEV_device_added(const SDL_UDEV_deviceclass devclass, const char *devpath) +SDL_EVDEV_device_added(const char *devpath) { SDL_evdevlist_item *item; @@ -681,9 +642,6 @@ SDL_EVDEV_device_added(const SDL_UDEV_deviceclass devclass, const char *devpath) return SDL_OutOfMemory(); } - item->devclass = devclass; - - item->fd = open(devpath, O_RDONLY, 0); if (item->fd < 0) { SDL_free(item); diff --git a/src/input/evdev/SDL_evdev.h b/src/input/evdev/SDL_evdev.h index d63b87f7a9961..34f369d28712e 100644 --- a/src/input/evdev/SDL_evdev.h +++ b/src/input/evdev/SDL_evdev.h @@ -29,17 +29,10 @@ #include "SDL_events.h" #include -typedef enum -{ - SDL_EVDEV_DEVICE_MOUSE = 0x0001, - SDL_EVDEV_DEVICE_KEYBOARD -} SDL_EVDEV_deviceclass; - typedef struct SDL_evdevlist_item { char *path; int fd; - SDL_EVDEV_deviceclass devclass; struct SDL_evdevlist_item *next; } SDL_evdevlist_item; diff --git a/src/joystick/linux/SDL_sysjoystick.c b/src/joystick/linux/SDL_sysjoystick.c index 686731397edb7..93a374e5d315a 100644 --- a/src/joystick/linux/SDL_sysjoystick.c +++ b/src/joystick/linux/SDL_sysjoystick.c @@ -57,7 +57,7 @@ static int MaybeAddDevice(const char *path); #if SDL_USE_LIBUDEV static int MaybeRemoveDevice(const char *path); -void joystick_udev_callback(SDL_UDEV_deviceevent udev_type, SDL_UDEV_deviceclass udev_class, const char *devpath); +void joystick_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath); #endif /* SDL_USE_LIBUDEV */ @@ -136,11 +136,11 @@ IsJoystick(int fd, char *namebuf, const size_t namebuflen, SDL_JoystickGUID *gui } #if SDL_USE_LIBUDEV -void joystick_udev_callback(SDL_UDEV_deviceevent udev_type, SDL_UDEV_deviceclass udev_class, const char *devpath) +void joystick_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath) { int instance; - if (devpath == NULL || udev_class != SDL_UDEV_DEVICE_JOYSTICK) { + if (devpath == NULL || !(udev_class & SDL_UDEV_DEVICE_JOYSTICK)) { return; }