21 #include "../../SDL_internal.h" 23 #ifdef SDL_INPUT_LINUXEV 37 #include <sys/ioctl.h> 39 #include <linux/input.h> 40 #ifdef SDL_INPUT_LINUXKD 42 #include <linux/keyboard.h> 44 #include <linux/tiocl.h> 50 #include "../../core/linux/SDL_udev.h" 52 #include "../../events/SDL_events_c.h" 53 #include "../../events/scancodes_linux.h" 60 typedef struct SDL_evdevlist_item
75 int min_x, max_x, range_x;
76 int min_y, max_y, range_y;
82 EVDEV_TOUCH_SLOTDELTA_NONE = 0,
83 EVDEV_TOUCH_SLOTDELTA_DOWN,
84 EVDEV_TOUCH_SLOTDELTA_UP,
85 EVDEV_TOUCH_SLOTDELTA_MOVE
92 struct SDL_evdevlist_item *next;
95 typedef struct SDL_EVDEV_PrivateData
97 SDL_evdevlist_item *
first;
98 SDL_evdevlist_item *last;
103 } SDL_EVDEV_PrivateData;
105 #define _THIS SDL_EVDEV_PrivateData *_this 108 static SDL_Scancode SDL_EVDEV_translate_keycode(
int keycode);
109 static void SDL_EVDEV_sync_device(SDL_evdevlist_item *item);
110 static int SDL_EVDEV_device_removed(
const char *dev_path);
113 static int SDL_EVDEV_device_added(
const char *dev_path,
int udev_class);
114 void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_type,
int udev_class,
115 const char *dev_path);
118 static Uint8 EVDEV_MouseButtons[] = {
129 static const char* EVDEV_consoles[] = {
144 static int SDL_EVDEV_is_console(
int fd) {
147 return isatty(fd) && ioctl(fd, KDGKBTYPE, &type) == 0 &&
148 (type == KB_101 || type == KB_84);
152 static int SDL_EVDEV_mute_keyboard(
int tty_fd,
int* old_kb_mode)
154 if (!SDL_EVDEV_is_console(tty_fd)) {
158 if (ioctl(tty_fd, KDGKBMODE, old_kb_mode) < 0) {
159 return SDL_SetError(
"Failed to get keyboard mode during muting");
174 static void SDL_EVDEV_unmute_keyboard(
int tty_fd,
int kb_mode)
184 static int SDL_EVDEV_get_active_tty()
186 int i, fd, ret, tty = 0;
188 struct vt_stat vt_state;
189 char path[PATH_MAX + 1];
192 fd = open(EVDEV_consoles[i], O_RDONLY);
194 if (fd < 0 && !SDL_EVDEV_is_console(fd))
197 tiocl = TIOCL_GETFGCONSOLE;
198 if ((ret = ioctl(fd, TIOCLINUX, &tiocl)) >= 0)
200 else if (ioctl(fd, VT_GETSTATE, &vt_state) == 0)
201 tty = vt_state.v_active;
206 sprintf(path,
"/dev/tty%u", tty);
207 fd = open(path, O_RDONLY);
208 if (fd >= 0 && SDL_EVDEV_is_console(fd))
226 if (SDL_UDEV_Init() < 0) {
233 if (SDL_UDEV_AddCallback(SDL_EVDEV_udev_callback) < 0) {
248 _this->console_fd = SDL_EVDEV_get_active_tty();
252 SDL_EVDEV_mute_keyboard(
_this->console_fd, &
_this->kb_mode);
255 _this->ref_count += 1;
267 _this->ref_count -= 1;
269 if (
_this->ref_count < 1) {
271 SDL_UDEV_DelCallback(SDL_EVDEV_udev_callback);
275 if (
_this->console_fd >= 0) {
276 SDL_EVDEV_unmute_keyboard(
_this->console_fd,
_this->kb_mode);
277 close(
_this->console_fd);
282 SDL_EVDEV_device_removed(
_this->first->path);
295 void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_event,
int udev_class,
296 const char* dev_path)
298 if (dev_path ==
NULL) {
303 case SDL_UDEV_DEVICEADDED:
304 if (!(udev_class & (SDL_UDEV_DEVICE_MOUSE | SDL_UDEV_DEVICE_KEYBOARD |
305 SDL_UDEV_DEVICE_TOUCHSCREEN)))
308 SDL_EVDEV_device_added(dev_path, udev_class);
310 case SDL_UDEV_DEVICEREMOVED:
311 SDL_EVDEV_device_removed(dev_path);
319 #ifdef SDL_INPUT_LINUXKD 322 static void SDL_EVDEV_do_text_input(
unsigned short keycode) {
327 char text[2] = { 0 };
329 if (
_this->console_fd < 0)
332 shift_state = TIOCL_GETSHIFTSTATE;
333 if (ioctl(
_this->console_fd, TIOCLINUX, &shift_state) < 0) {
338 kbe.kb_table = shift_state;
339 kbe.kb_index = keycode;
341 if (ioctl(
_this->console_fd, KDGKBENT, &kbe) < 0) {
346 type = KTYP(kbe.kb_value);
368 if (type == KT_LETTER) {
371 if (ioctl(
_this->console_fd, KDGKBLED, &locks_state) < 0) {
376 if (locks_state & K_CAPSLOCK) {
377 kbe.kb_table = shift_state ^ (1 << KG_SHIFT);
379 if (ioctl(
_this->console_fd, KDGKBENT, &kbe) < 0) {
387 if (type != KT_LATIN || KVAL(kbe.kb_value) >= 0x80)
390 *text = KVAL(kbe.kb_value);
398 struct input_event
events[32];
400 SDL_evdevlist_item *item;
404 float norm_x, norm_y;
416 for (item =
_this->first; item !=
NULL; item = item->next) {
417 while ((len = read(item->fd,
events, (
sizeof events))) > 0) {
419 for (i = 0; i <
len; ++
i) {
422 if (item->out_of_sync && item->is_touchscreen &&
430 mouse_button =
events[
i].code - BTN_MOUSE;
440 scan_code = SDL_EVDEV_translate_keycode(
events[i].code);
446 #ifdef SDL_INPUT_LINUXKD 447 SDL_EVDEV_do_text_input(
events[i].code);
455 if (!item->is_touchscreen)
457 item->touchscreen_data->current_slot =
events[
i].value;
459 case ABS_MT_TRACKING_ID:
460 if (!item->is_touchscreen)
463 item->touchscreen_data->slots[item->touchscreen_data->current_slot].tracking_id =
events[
i].value;
464 item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_DOWN;
466 item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_UP;
469 case ABS_MT_POSITION_X:
470 if (!item->is_touchscreen)
472 item->touchscreen_data->slots[item->touchscreen_data->current_slot].x =
events[
i].value;
473 if (item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta == EVDEV_TOUCH_SLOTDELTA_NONE) {
474 item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_MOVE;
477 case ABS_MT_POSITION_Y:
478 if (!item->is_touchscreen)
480 item->touchscreen_data->slots[item->touchscreen_data->current_slot].y =
events[
i].value;
481 if (item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta == EVDEV_TOUCH_SLOTDELTA_NONE) {
482 item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_MOVE;
486 if (item->is_touchscreen)
491 if (item->is_touchscreen)
520 if (!item->is_touchscreen)
523 for(j = 0; j < item->touchscreen_data->max_slots; j++) {
524 norm_x = (float)(item->touchscreen_data->slots[j].x - item->touchscreen_data->min_x) /
525 (float)item->touchscreen_data->range_x;
526 norm_y = (
float)(item->touchscreen_data->slots[
j].y - item->touchscreen_data->min_y) /
527 (
float)item->touchscreen_data->range_y;
529 switch(item->touchscreen_data->slots[j].delta) {
530 case EVDEV_TOUCH_SLOTDELTA_DOWN:
531 SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id,
SDL_TRUE, norm_x, norm_y, 1.0f);
532 item->touchscreen_data->slots[
j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
534 case EVDEV_TOUCH_SLOTDELTA_UP:
536 item->touchscreen_data->slots[
j].tracking_id = -1;
537 item->touchscreen_data->slots[
j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
539 case EVDEV_TOUCH_SLOTDELTA_MOVE:
540 SDL_SendTouchMotion(item->fd, item->touchscreen_data->slots[j].tracking_id, norm_x, norm_y, 1.0f);
541 item->touchscreen_data->slots[
j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
548 if (item->out_of_sync)
549 item->out_of_sync = 0;
552 if (item->is_touchscreen)
553 item->out_of_sync = 1;
554 SDL_EVDEV_sync_device(item);
567 SDL_EVDEV_translate_keycode(
int keycode)
575 SDL_Log(
"The key you just pressed is not recognized by SDL. To help " 576 "get this fixed, please report this to the SDL mailing list " 577 "<sdl@libsdl.org> EVDEV KeyCode %d\n", keycode);
583 #ifdef SDL_USE_LIBUDEV 585 SDL_EVDEV_init_touchscreen(SDL_evdevlist_item* item)
589 struct input_absinfo abs_info;
591 if (!item->is_touchscreen)
594 item->touchscreen_data =
SDL_calloc(1,
sizeof(*item->touchscreen_data));
595 if (item->touchscreen_data ==
NULL)
598 ret = ioctl(item->fd, EVIOCGNAME(
sizeof(name)), name);
601 return SDL_SetError(
"Failed to get evdev touchscreen name");
604 item->touchscreen_data->name =
SDL_strdup(name);
605 if (item->touchscreen_data->name ==
NULL) {
610 ret = ioctl(item->fd, EVIOCGABS(ABS_MT_POSITION_X), &abs_info);
612 SDL_free(item->touchscreen_data->name);
614 return SDL_SetError(
"Failed to get evdev touchscreen limits");
616 item->touchscreen_data->min_x = abs_info.minimum;
617 item->touchscreen_data->max_x = abs_info.maximum;
618 item->touchscreen_data->range_x = abs_info.maximum - abs_info.minimum;
620 ret = ioctl(item->fd, EVIOCGABS(ABS_MT_POSITION_Y), &abs_info);
622 SDL_free(item->touchscreen_data->name);
624 return SDL_SetError(
"Failed to get evdev touchscreen limits");
626 item->touchscreen_data->min_y = abs_info.minimum;
627 item->touchscreen_data->max_y = abs_info.maximum;
628 item->touchscreen_data->range_y = abs_info.maximum - abs_info.minimum;
630 ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
632 SDL_free(item->touchscreen_data->name);
634 return SDL_SetError(
"Failed to get evdev touchscreen limits");
636 item->touchscreen_data->max_slots = abs_info.maximum + 1;
639 item->touchscreen_data->max_slots,
640 sizeof(*item->touchscreen_data->slots));
641 if (item->touchscreen_data->slots ==
NULL) {
642 SDL_free(item->touchscreen_data->name);
647 for(i = 0; i < item->touchscreen_data->max_slots; i++) {
648 item->touchscreen_data->slots[
i].tracking_id = -1;
652 item->touchscreen_data->name);
654 SDL_free(item->touchscreen_data->slots);
655 SDL_free(item->touchscreen_data->name);
665 SDL_EVDEV_destroy_touchscreen(SDL_evdevlist_item* item) {
666 if (!item->is_touchscreen)
670 SDL_free(item->touchscreen_data->slots);
671 SDL_free(item->touchscreen_data->name);
676 SDL_EVDEV_sync_device(SDL_evdevlist_item *item)
680 struct input_absinfo abs_info;
690 __s32* mt_req_values;
694 if (!item->is_touchscreen)
697 mt_req_size =
sizeof(*mt_req_code) +
698 sizeof(*mt_req_values) * item->touchscreen_data->max_slots;
701 if (mt_req_code ==
NULL) {
705 mt_req_values = (__s32*)mt_req_code + 1;
707 *mt_req_code = ABS_MT_TRACKING_ID;
708 ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
713 for(i = 0; i < item->touchscreen_data->max_slots; i++) {
723 if (item->touchscreen_data->slots[i].tracking_id < 0 &&
724 mt_req_values[i] >= 0) {
725 item->touchscreen_data->slots[
i].tracking_id = mt_req_values[
i];
726 item->touchscreen_data->slots[
i].delta = EVDEV_TOUCH_SLOTDELTA_DOWN;
727 }
else if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
728 mt_req_values[i] < 0) {
729 item->touchscreen_data->slots[
i].tracking_id = -1;
730 item->touchscreen_data->slots[
i].delta = EVDEV_TOUCH_SLOTDELTA_UP;
734 *mt_req_code = ABS_MT_POSITION_X;
735 ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
740 for(i = 0; i < item->touchscreen_data->max_slots; i++) {
741 if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
742 item->touchscreen_data->slots[i].x != mt_req_values[i]) {
743 item->touchscreen_data->slots[
i].x = mt_req_values[
i];
744 if (item->touchscreen_data->slots[i].delta ==
745 EVDEV_TOUCH_SLOTDELTA_NONE) {
746 item->touchscreen_data->slots[
i].delta =
747 EVDEV_TOUCH_SLOTDELTA_MOVE;
752 *mt_req_code = ABS_MT_POSITION_Y;
753 ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
758 for(i = 0; i < item->touchscreen_data->max_slots; i++) {
759 if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
760 item->touchscreen_data->slots[i].y != mt_req_values[i]) {
761 item->touchscreen_data->slots[
i].y = mt_req_values[
i];
762 if (item->touchscreen_data->slots[i].delta ==
763 EVDEV_TOUCH_SLOTDELTA_NONE) {
764 item->touchscreen_data->slots[
i].delta =
765 EVDEV_TOUCH_SLOTDELTA_MOVE;
770 ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
775 item->touchscreen_data->current_slot = abs_info.value;
784 SDL_EVDEV_device_added(
const char *dev_path,
int udev_class)
787 SDL_evdevlist_item *item;
790 for (item =
_this->first; item !=
NULL; item = item->next) {
796 item = (SDL_evdevlist_item *)
SDL_calloc(1,
sizeof (SDL_evdevlist_item));
801 item->fd = open(dev_path, O_RDONLY | O_NONBLOCK);
808 if (item->path ==
NULL) {
814 if (udev_class & SDL_UDEV_DEVICE_TOUCHSCREEN) {
815 item->is_touchscreen = 1;
817 if ((ret = SDL_EVDEV_init_touchscreen(item)) < 0) {
827 _this->last->next = item;
831 SDL_EVDEV_sync_device(item);
833 return _this->num_devices++;
838 SDL_EVDEV_device_removed(
const char *dev_path)
840 SDL_evdevlist_item *item;
841 SDL_evdevlist_item *prev =
NULL;
843 for (item =
_this->first; item !=
NULL; item = item->next) {
847 prev->next = item->next;
850 _this->first = item->next;
852 if (item ==
_this->last) {
855 if (item->is_touchscreen) {
856 SDL_EVDEV_destroy_touchscreen(item);
861 _this->num_devices--;
SDL_Mouse * SDL_GetMouse(void)
GLint GLint GLint GLint GLint x
static SDL_Event events[EVENT_BUF_SIZE]
int SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid, SDL_bool down, float x, float y, float pressure)
GLuint const GLchar * name
int SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode)
int SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid, float x, float y, float pressure)
static SDL_VideoDevice * _this
GLuint GLuint GLsizei GLenum type
void * SDL_calloc(size_t nmemb, size_t size)
GLint GLint GLint GLint GLint GLint y
int SDL_SendMouseMotion(SDL_Window *window, SDL_MouseID mouseID, int relative, int x, int y)
GLsizei const GLfloat * value
uint8_t Uint8
An unsigned 8-bit integer type.
int SDL_SendKeyboardText(const char *text)
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int int in j)
void SDL_DelTouch(SDL_TouchID id)
#define SDL_BUTTON_MIDDLE
int SDL_AddTouch(SDL_TouchID touchID, const char *name)
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
#define SDL_assert(condition)
#define SDL_OutOfMemory()
static char text[MAX_TEXT_LENGTH]
static SDL_Scancode const linux_scancode_table[]
#define SDL_arraysize(array)
int SDL_SendMouseWheel(SDL_Window *window, SDL_MouseID mouseID, int x, int y, SDL_MouseWheelDirection direction)
GLsizei const GLchar *const * path
int SDL_SendMouseButton(SDL_Window *window, SDL_MouseID mouseID, Uint8 state, Uint8 button)
SDL_Scancode
The SDL keyboard scancode representation.