Fixed bug where a Logitech wireless keyboard with built-in mouse touchpad didn't get recongized as both devices.

This commit is contained in:
Sam Lantinga 2013-10-05 21:15:55 -07:00
parent 529664278f
commit 90a219a375
5 changed files with 134 additions and 188 deletions

View File

@ -279,7 +279,7 @@ device_event(SDL_UDEV_deviceevent type, struct udev_device *dev)
{ {
const char *subsystem; const char *subsystem;
const char *val = NULL; const char *val = NULL;
SDL_UDEV_deviceclass devclass = 0; int devclass = 0;
const char *path; const char *path;
SDL_UDEV_CallbackList *item; 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); subsystem = _this->udev_device_get_subsystem(dev);
if (SDL_strcmp(subsystem, "sound") == 0) { if (SDL_strcmp(subsystem, "sound") == 0) {
devclass = SDL_UDEV_DEVICE_SOUND; 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"); val = _this->udev_device_get_property_value(dev, "ID_INPUT_JOYSTICK");
if (val != NULL && SDL_strcmp(val, "1") == 0 ) { 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");
val = _this->udev_device_get_property_value(dev, "ID_INPUT_MOUSE"); if (val != NULL && SDL_strcmp(val, "1") == 0 ) {
if (val != NULL && SDL_strcmp(val, "1") == 0 ) { devclass |= SDL_UDEV_DEVICE_MOUSE;
devclass = SDL_UDEV_DEVICE_MOUSE;
}
} }
if (devclass == 0) { val = _this->udev_device_get_property_value(dev, "ID_INPUT_KEYBOARD");
val = _this->udev_device_get_property_value(dev, "ID_INPUT_KEYBOARD"); if (val != NULL && SDL_strcmp(val, "1") == 0 ) {
if (val != NULL && SDL_strcmp(val, "1") == 0 ) { devclass |= SDL_UDEV_DEVICE_KEYBOARD;
devclass = SDL_UDEV_DEVICE_KEYBOARD;
}
} }
if (devclass == 0) { if (devclass == 0) {
return; return;
} }
} } else {
else {
return; return;
} }

View File

@ -46,15 +46,16 @@ typedef enum
SDL_UDEV_DEVICEREMOVED SDL_UDEV_DEVICEREMOVED
} SDL_UDEV_deviceevent; } SDL_UDEV_deviceevent;
/* A device can be any combination of these classes */
typedef enum typedef enum
{ {
SDL_UDEV_DEVICE_MOUSE = 0x0001, SDL_UDEV_DEVICE_MOUSE = 0x0001,
SDL_UDEV_DEVICE_KEYBOARD, SDL_UDEV_DEVICE_KEYBOARD = 0x0002,
SDL_UDEV_DEVICE_JOYSTICK, SDL_UDEV_DEVICE_JOYSTICK = 0x0004,
SDL_UDEV_DEVICE_SOUND SDL_UDEV_DEVICE_SOUND = 0x0008
} SDL_UDEV_deviceclass; } 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 { typedef struct SDL_UDEV_CallbackList {
SDL_UDEV_Callback callback; SDL_UDEV_Callback callback;

View File

@ -62,8 +62,8 @@ static void SDL_EVDEV_sync_device(SDL_evdevlist_item *item);
static int SDL_EVDEV_device_removed(const char *devpath); static int SDL_EVDEV_device_removed(const char *devpath);
#if SDL_USE_LIBUDEV #if SDL_USE_LIBUDEV
static int SDL_EVDEV_device_added(const SDL_UDEV_deviceclass devclass, const char *devpath); static int SDL_EVDEV_device_added(const char *devpath);
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);
#endif /* SDL_USE_LIBUDEV */ #endif /* SDL_USE_LIBUDEV */
static SDL_Scancode EVDEV_Keycodes[] = { 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 */ /* 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->console_fd = SDL_EVDEV_get_console_fd();
} }
_this->ref_count += 1; _this->ref_count += 1;
@ -445,43 +444,28 @@ SDL_EVDEV_Quit(void)
} }
#if SDL_USE_LIBUDEV #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) { if (devpath == NULL) {
return; return;
} }
switch( udev_class ) if (!(udev_class & (SDL_UDEV_DEVICE_MOUSE|SDL_UDEV_DEVICE_KEYBOARD))) {
{ return;
case SDL_UDEV_DEVICE_MOUSE:
devclass = SDL_EVDEV_DEVICE_MOUSE;
break;
case SDL_UDEV_DEVICE_KEYBOARD:
devclass = SDL_EVDEV_DEVICE_KEYBOARD;
break;
default:
return;
} }
switch( udev_type ) switch( udev_type ) {
{ case SDL_UDEV_DEVICEADDED:
case SDL_UDEV_DEVICEADDED: SDL_EVDEV_device_added(devpath);
SDL_EVDEV_device_added(devclass, devpath); break;
break;
case SDL_UDEV_DEVICEREMOVED: case SDL_UDEV_DEVICEREMOVED:
SDL_EVDEV_device_removed(devpath); SDL_EVDEV_device_removed(devpath);
break; break;
default:
break;
default:
break;
} }
} }
#endif /* SDL_USE_LIBUDEV */ #endif /* SDL_USE_LIBUDEV */
@ -507,137 +491,114 @@ SDL_EVDEV_Poll(void)
SDL_UDEV_Poll(); SDL_UDEV_Poll();
#endif #endif
mouse = SDL_GetMouse();
for (item = _this->first; item != NULL; item = item->next) { for (item = _this->first; item != NULL; item = item->next) {
while ((len = read(item->fd, events, (sizeof events))) > 0) { while ((len = read(item->fd, events, (sizeof events))) > 0) {
len /= sizeof(events[0]); len /= sizeof(events[0]);
for (i = 0; i < len; ++i) { for (i = 0; i < len; ++i) {
switch(item->devclass) { switch (events[i].type) {
case SDL_EVDEV_DEVICE_KEYBOARD: case EV_KEY:
switch (events[i].type) { if (events[i].code >= BTN_MOUSE && events[i].code < BTN_MOUSE + SDL_arraysize(EVDEV_MouseButtons)) {
case EV_KEY: mouse_button = events[i].code - BTN_MOUSE;
scan_code = SDL_EVDEV_translate_keycode(events[i].code); if (events[i].value == 0) {
if (scan_code != SDL_SCANCODE_UNKNOWN) { SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_RELEASED, EVDEV_MouseButtons[mouse_button]);
if (events[i].value == 0) { } else if (events[i].value == 1) {
SDL_SendKeyboardKey(SDL_RELEASED, scan_code); SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_PRESSED, EVDEV_MouseButtons[mouse_button]);
} }
else if (events[i].value == 1 || events[i].value == 2 /* Key repeated */ ) { break;
SDL_SendKeyboardKey(SDL_PRESSED, scan_code); }
/* 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 #ifdef SDL_INPUT_LINUXKD
if (_this->console_fd >= 0) { if (_this->console_fd >= 0) {
kbe.kb_index = events[i].code; kbe.kb_index = events[i].code;
/* Convert the key to an UTF-8 char */ /* Convert the key to an UTF-8 char */
/* Ref: http://www.linuxjournal.com/article/2783 */ /* Ref: http://www.linuxjournal.com/article/2783 */
modstate = SDL_GetModState(); modstate = SDL_GetModState();
kbe.kb_table = 0; kbe.kb_table = 0;
/* Ref: http://graphics.stanford.edu/~seander/bithacks.html#ConditionalSetOrClearBitsWithoutBranching */ /* 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_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_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_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_RSHIFT) != 0) & (1 << KG_SHIFTR | 1 << KG_SHIFT);
kbe.kb_table |= -( (modstate & KMOD_LALT) != 0) & (1 << KG_ALT); kbe.kb_table |= -( (modstate & KMOD_LALT) != 0) & (1 << KG_ALT);
kbe.kb_table |= -( (modstate & KMOD_RALT) != 0) & (1 << KG_ALTGR); kbe.kb_table |= -( (modstate & KMOD_RALT) != 0) & (1 << KG_ALTGR);
if(ioctl(_this->console_fd, KDGKBENT, (unsigned long)&kbe) == 0 && 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) )) ((KTYP(kbe.kb_value) == KT_LATIN) || (KTYP(kbe.kb_value) == KT_ASCII) || (KTYP(kbe.kb_value) == KT_LETTER)))
{ {
kval = KVAL(kbe.kb_value); kval = KVAL(kbe.kb_value);
/* While there's a KG_CAPSSHIFT symbol, it's not useful to build the table index with it /* 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 * 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! * So, we do the CAPS LOCK logic here. Note that isalpha depends on the locale!
*/ */
if ( modstate & KMOD_CAPS && isalpha(kval) ) { if ( modstate & KMOD_CAPS && isalpha(kval) ) {
if ( isupper(kval) ) { if ( isupper(kval) ) {
kval = tolower(kval); kval = tolower(kval);
} } else {
else { kval = toupper(kval);
kval = toupper(kval);
}
}
/* Convert to UTF-8 and send */
end = SDL_UCS4ToUTF8( kval, keysym);
*end = '\0';
SDL_SendKeyboardText(keysym);
} }
} }
#endif
/* Convert to UTF-8 and send */
end = SDL_UCS4ToUTF8( kval, keysym);
*end = '\0';
SDL_SendKeyboardText(keysym);
} }
} }
break; #endif /* SDL_INPUT_LINUXKD */
default:
break;
} }
break; /* SDL_EVDEV_DEVICE_KEYBOARD */ }
break;
case SDL_EVDEV_DEVICE_MOUSE: case EV_ABS:
mouse = SDL_GetMouse(); switch(events[i].code) {
switch (events[i].type) { case ABS_X:
case EV_KEY: SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, events[i].value, mouse->y);
mouse_button = events[i].code - BTN_MOUSE; break;
if (mouse_button >= 0 && mouse_button < SDL_arraysize(EVDEV_MouseButtons)) { case ABS_Y:
if (events[i].value == 0) { SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, mouse->x, events[i].value);
SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_RELEASED, EVDEV_MouseButtons[mouse_button]); break;
}
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;
}
break; /* SDL_EVDEV_DEVICE_MOUSE */
default: default:
break; 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 #if SDL_USE_LIBUDEV
static int 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; SDL_evdevlist_item *item;
@ -681,9 +642,6 @@ SDL_EVDEV_device_added(const SDL_UDEV_deviceclass devclass, const char *devpath)
return SDL_OutOfMemory(); return SDL_OutOfMemory();
} }
item->devclass = devclass;
item->fd = open(devpath, O_RDONLY, 0); item->fd = open(devpath, O_RDONLY, 0);
if (item->fd < 0) { if (item->fd < 0) {
SDL_free(item); SDL_free(item);

View File

@ -29,17 +29,10 @@
#include "SDL_events.h" #include "SDL_events.h"
#include <sys/stat.h> #include <sys/stat.h>
typedef enum
{
SDL_EVDEV_DEVICE_MOUSE = 0x0001,
SDL_EVDEV_DEVICE_KEYBOARD
} SDL_EVDEV_deviceclass;
typedef struct SDL_evdevlist_item typedef struct SDL_evdevlist_item
{ {
char *path; char *path;
int fd; int fd;
SDL_EVDEV_deviceclass devclass;
struct SDL_evdevlist_item *next; struct SDL_evdevlist_item *next;
} SDL_evdevlist_item; } SDL_evdevlist_item;

View File

@ -57,7 +57,7 @@
static int MaybeAddDevice(const char *path); static int MaybeAddDevice(const char *path);
#if SDL_USE_LIBUDEV #if SDL_USE_LIBUDEV
static int MaybeRemoveDevice(const char *path); 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 */ #endif /* SDL_USE_LIBUDEV */
@ -136,11 +136,11 @@ IsJoystick(int fd, char *namebuf, const size_t namebuflen, SDL_JoystickGUID *gui
} }
#if SDL_USE_LIBUDEV #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; int instance;
if (devpath == NULL || udev_class != SDL_UDEV_DEVICE_JOYSTICK) { if (devpath == NULL || !(udev_class & SDL_UDEV_DEVICE_JOYSTICK)) {
return; return;
} }