2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
19 * Portions copied from DirectFB:
21 (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
22 (c) Copyright 2000-2004 Convergence (integrated media) GmbH
25 Written by Denis Oliver Kropp <dok@directfb.org>,
26 Andreas Hundt <andi@fischlustig.de>,
27 Sven Neumann <neo@directfb.org>,
28 Ville Syrjälä <syrjala@sci.fi> and
29 Claudio Ciccani <klan@users.sf.net>.
31 This library is free software; you can redistribute it and/or
32 modify it under the terms of the GNU Lesser General Public
33 License as published by the Free Software Foundation; either
34 version 2 of the License, or (at your option) any later version.
36 This library is distributed in the hope that it will be useful,
37 but WITHOUT ANY WARRANTY; without even the implied warranty of
38 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
39 Lesser General Public License for more details.
41 You should have received a copy of the GNU Lesser General Public
42 License along with this library; if not, write to the
43 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
44 Boston, MA 02111-1307, USA.
48 #if defined(HAS_LINUX_EVENTS)
50 #include <linux/version.h>
52 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
53 typedef unsigned long kernel_ulong_t;
54 #define BITS_PER_LONG (sizeof(long)*8)
57 #include <linux/input.h>
60 #define EV_CNT (EV_MAX+1)
61 #define KEY_CNT (KEY_MAX+1)
62 #define REL_CNT (REL_MAX+1)
63 #define ABS_CNT (ABS_MAX+1)
64 #define LED_CNT (LED_MAX+1)
67 /* compat defines for older kernel like 2.4.x */
72 #define ABS_TOOL_WIDTH 0x1c
73 #define BTN_TOOL_DOUBLETAP 0x14d
74 #define BTN_TOOL_TRIPLETAP 0x14e
78 #define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len)
82 #define EVIOCGRAB _IOW('E', 0x90, int)
86 #define XBMC_BUTTON_LEFT 1
87 #define XBMC_BUTTON_MIDDLE 2
88 #define XBMC_BUTTON_RIGHT 3
89 #define XBMC_BUTTON_WHEELUP 4
90 #define XBMC_BUTTON_WHEELDOWN 5
93 #include <linux/keyboard.h>
101 #include <sys/types.h>
102 #include <sys/stat.h>
103 #include <sys/ioctl.h>
107 #include "guilib/GraphicContext.h"
108 #include "input/XBMC_keysym.h"
109 #include "LinuxInputDevices.h"
110 #include "input/MouseStat.h"
111 #include "utils/log.h"
113 #ifndef BITS_PER_LONG
114 #define BITS_PER_LONG (sizeof(long) * 8)
116 #define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
117 #define OFF(x) ((x)%BITS_PER_LONG)
118 #define BIT(x) (1UL<<OFF(x))
119 #define LONG(x) ((x)/BITS_PER_LONG)
121 #define test_bit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
124 #define D_ARRAY_SIZE(array) ((int)(sizeof(array) / sizeof((array)[0])))
127 #define MAX_LINUX_INPUT_DEVICES 16
130 XBMCKey basic_keycodes[] = { XBMCK_UNKNOWN, XBMCK_ESCAPE, XBMCK_1, XBMCK_2, XBMCK_3,
131 XBMCK_4, XBMCK_5, XBMCK_6, XBMCK_7, XBMCK_8, XBMCK_9, XBMCK_0, XBMCK_MINUS,
132 XBMCK_EQUALS, XBMCK_BACKSPACE,
134 XBMCK_TAB, XBMCK_q, XBMCK_w, XBMCK_e, XBMCK_r, XBMCK_t, XBMCK_y, XBMCK_u, XBMCK_i,
135 XBMCK_o, XBMCK_p, XBMCK_LEFTBRACKET, XBMCK_RIGHTBRACKET, XBMCK_RETURN,
137 XBMCK_LCTRL, XBMCK_a, XBMCK_s, XBMCK_d, XBMCK_f, XBMCK_g, XBMCK_h, XBMCK_j,
138 XBMCK_k, XBMCK_l, XBMCK_SEMICOLON, XBMCK_QUOTE, XBMCK_BACKQUOTE,
140 XBMCK_LSHIFT, XBMCK_BACKSLASH, XBMCK_z, XBMCK_x, XBMCK_c, XBMCK_v, XBMCK_b,
141 XBMCK_n, XBMCK_m, XBMCK_COMMA, XBMCK_PERIOD, XBMCK_SLASH, XBMCK_RSHIFT,
142 XBMCK_KP_MULTIPLY, XBMCK_LALT, XBMCK_SPACE, XBMCK_CAPSLOCK,
144 XBMCK_F1, XBMCK_F2, XBMCK_F3, XBMCK_F4, XBMCK_F5, XBMCK_F6, XBMCK_F7, XBMCK_F8,
145 XBMCK_F9, XBMCK_F10, XBMCK_NUMLOCK, XBMCK_SCROLLOCK,
147 XBMCK_KP7, XBMCK_KP8, XBMCK_KP9, XBMCK_KP_MINUS, XBMCK_KP4, XBMCK_KP5,
148 XBMCK_KP6, XBMCK_KP_PLUS, XBMCK_KP1, XBMCK_KP2, XBMCK_KP3, XBMCK_KP0,
151 /*KEY_103RD,*/XBMCK_BACKSLASH,
152 /*KEY_F13,*/XBMCK_F13,
153 /*KEY_102ND*/XBMCK_LESS,
155 XBMCK_F11, XBMCK_F12, XBMCK_F14, XBMCK_F15,
156 XBMCK_UNKNOWN,XBMCK_UNKNOWN,XBMCK_UNKNOWN, /*XBMCK_F16, XBMCK_F17, XBMCK_F18,*/
157 XBMCK_UNKNOWN, XBMCK_UNKNOWN, /*XBMCK_F19, XBMCK_F20,*/
159 XBMCK_KP_ENTER, XBMCK_RCTRL, XBMCK_KP_DIVIDE, XBMCK_PRINT, XBMCK_MODE,
161 /*KEY_LINEFEED*/XBMCK_UNKNOWN,
163 XBMCK_HOME, XBMCK_UP, XBMCK_PAGEUP, XBMCK_LEFT, XBMCK_RIGHT, XBMCK_END,
164 XBMCK_DOWN, XBMCK_PAGEDOWN, XBMCK_INSERT, XBMCK_DELETE,
166 /*KEY_MACRO,*/XBMCK_UNKNOWN,
168 XBMCK_VOLUME_MUTE, XBMCK_VOLUME_DOWN, XBMCK_VOLUME_UP, XBMCK_POWER, XBMCK_KP_EQUALS,
170 /*KEY_KPPLUSMINUS,*/XBMCK_UNKNOWN,
172 XBMCK_PAUSE, XBMCK_UNKNOWN, XBMCK_UNKNOWN, /*DFB_FUNCTION_KEY(21), DFB_FUNCTION_KEY(22), */
173 XBMCK_UNKNOWN, XBMCK_UNKNOWN, /*DFB_FUNCTION_KEY(23), DFB_FUNCTION_KEY(24),*/
175 /*DIKI_KP_SEPARATOR*/XBMCK_UNKNOWN, XBMCK_LMETA, XBMCK_RMETA, XBMCK_LSUPER,
179 /*DIKS_AGAIN, DIKS_PROPS, DIKS_UNDO, DIKS_FRONT, DIKS_COPY,
180 DIKS_OPEN, DIKS_PASTE, DIKS_FIND, DIKS_CUT,*/
181 XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN,
182 XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN,
186 /* DIKS_MENU, DIKS_CALCULATOR, DIKS_SETUP, */
187 XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN,
189 /*KEY_SLEEP, KEY_WAKEUP, KEY_FILE, KEY_SENDFILE, KEY_DELETEFILE,
191 XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN,
194 /*KEY_PROG1, KEY_PROG2,*/
195 XBMCK_UNKNOWN, XBMCK_UNKNOWN,
197 /*DIKS_INTERNET*/ XBMCK_UNKNOWN,
199 /*KEY_MSDOS, KEY_COFFEE, KEY_DIRECTION, KEY_CYCLEWINDOWS,*/
200 XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN,
202 /*DIKS_MAIL*/ XBMCK_UNKNOWN,
204 /*KEY_BOOKMARKS, KEY_COMPUTER, */
205 XBMCK_UNKNOWN, XBMCK_UNKNOWN,
207 /*DIKS_BACK, DIKS_FORWARD,*/
208 XBMCK_UNKNOWN, XBMCK_UNKNOWN,
210 /*KEY_CLOSECD, KEY_EJECTCD, KEY_EJECTCLOSECD,*/
211 XBMCK_EJECT, XBMCK_EJECT, XBMCK_EJECT,
213 XBMCK_MEDIA_NEXT_TRACK, XBMCK_MEDIA_PLAY_PAUSE, XBMCK_MEDIA_PREV_TRACK, XBMCK_MEDIA_STOP, XBMCK_RECORD,
214 XBMCK_REWIND, XBMCK_PHONE,
216 /*KEY_ISO,*/XBMCK_UNKNOWN,
217 /*KEY_CONFIG,*/XBMCK_UNKNOWN,
218 /*KEY_HOMEPAGE, KEY_REFRESH,*/XBMCK_UNKNOWN, XBMCK_SHUFFLE,
220 /*DIKS_EXIT*/XBMCK_UNKNOWN, /*KEY_MOVE,*/XBMCK_UNKNOWN, /*DIKS_EDITOR*/XBMCK_UNKNOWN,
222 /*KEY_SCROLLUP,*/XBMCK_PAGEUP,
223 /*KEY_SCROLLDOWN,*/XBMCK_PAGEDOWN,
224 /*KEY_KPLEFTPAREN,*/XBMCK_UNKNOWN,
225 /*KEY_KPRIGHTPAREN,*/XBMCK_UNKNOWN,
227 /* unused codes 181-182: */
228 XBMCK_UNKNOWN, XBMCK_UNKNOWN,
231 DFB_FUNCTION_KEY(13), DFB_FUNCTION_KEY(14), DFB_FUNCTION_KEY(15),
232 DFB_FUNCTION_KEY(16), DFB_FUNCTION_KEY(17), DFB_FUNCTION_KEY(18),
233 DFB_FUNCTION_KEY(19), DFB_FUNCTION_KEY(20), DFB_FUNCTION_KEY(21),
234 DFB_FUNCTION_KEY(22), DFB_FUNCTION_KEY(23), DFB_FUNCTION_KEY(24),
236 XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN,
237 XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN,
238 XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN,
239 XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN,
241 /* unused codes 195-199: */
242 XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN,
244 /* KEY_PLAYCD, KEY_PAUSECD */
245 XBMCK_PLAY, XBMCK_PAUSE,
247 /*KEY_PROG3, KEY_PROG4,*/
248 XBMCK_UNKNOWN, XBMCK_UNKNOWN,
252 /*KEY_SUSPEND, KEY_CLOSE*/
253 XBMCK_UNKNOWN, XBMCK_UNKNOWN,
258 /* KEY_FASTFORWARD */
267 /* KEY_HP */XBMCK_UNKNOWN,
268 /* KEY_CAMERA */XBMCK_UNKNOWN,
269 /* KEY_SOUND */XBMCK_UNKNOWN,
270 /* KEY_QUESTION */XBMCK_HELP,
271 /* KEY_EMAIL */XBMCK_UNKNOWN,
272 /* KEY_CHAT */XBMCK_UNKNOWN,
273 /* KEY_SEARCH */XBMCK_UNKNOWN,
274 /* KEY_CONNECT */XBMCK_UNKNOWN,
275 /* KEY_FINANCE */XBMCK_UNKNOWN,
276 /* KEY_SPORT */XBMCK_UNKNOWN,
277 /* KEY_SHOP */XBMCK_UNKNOWN,
278 /* KEY_ALTERASE */XBMCK_UNKNOWN,
279 /* KEY_CANCEL */XBMCK_UNKNOWN,
280 /* KEY_BRIGHTNESSDOWN */XBMCK_UNKNOWN,
281 /* KEY_BRIGHTNESSUP */XBMCK_UNKNOWN,
282 /* KEY_MEDIA */XBMCK_UNKNOWN, };
285 In the future we may want it...
288 int ext_keycodes[] = { DIKS_OK, DIKS_SELECT, DIKS_GOTO, DIKS_CLEAR,
289 DIKS_POWER2, DIKS_OPTION, DIKS_INFO, DIKS_TIME, DIKS_VENDOR, DIKS_ARCHIVE,
290 DIKS_PROGRAM, DIKS_CHANNEL, DIKS_FAVORITES, DIKS_EPG, DIKS_PVR, DIKS_MHP,
291 DIKS_LANGUAGE, DIKS_TITLE, DIKS_SUBTITLE, DIKS_ANGLE, DIKS_ZOOM, DIKS_MODE,
292 DIKS_KEYBOARD, DIKS_SCREEN, DIKS_PC, DIKS_TV, DIKS_TV2, DIKS_VCR,
293 DIKS_VCR2, DIKS_SAT, DIKS_SAT2, DIKS_CD, DIKS_TAPE, DIKS_RADIO, DIKS_TUNER,
294 DIKS_PLAYER, DIKS_TEXT, DIKS_DVD, DIKS_AUX, DIKS_MP3, DIKS_AUDIO,
295 DIKS_VIDEO, DIKS_DIRECTORY, DIKS_LIST, DIKS_MEMO, DIKS_CALENDAR, DIKS_RED,
296 DIKS_GREEN, DIKS_YELLOW, DIKS_BLUE, DIKS_CHANNEL_UP, DIKS_CHANNEL_DOWN,
297 DIKS_FIRST, DIKS_LAST, DIKS_AB, DIKS_NEXT, DIKS_RESTART, DIKS_SLOW,
298 DIKS_SHUFFLE, DIKS_FASTFORWARD, DIKS_PREVIOUS, DIKS_NEXT, DIKS_DIGITS,
299 DIKS_TEEN, DIKS_TWEN, DIKS_BREAK };
306 LI_DEVICE_JOYSTICK = 2,
307 LI_DEVICE_KEYBOARD = 4,
309 } LinuxInputDeviceType;
316 } LinuxInputCapsType;
318 static char remoteStatus = 0xFF; // paired, battery OK
320 CLinuxInputDevice::CLinuxInputDevice(const std::string fileName, int index)
325 m_fileName = fileName;
326 m_ledState[0] = false;
327 m_ledState[1] = false;
328 m_ledState[2] = false;
331 m_deviceIndex = index;
332 m_keyMods = XBMCKMOD_NONE;
333 m_lastKeyMods = XBMCKMOD_NONE;
334 strcpy(m_deviceName, "");
336 m_devicePreferredId = 0;
338 m_deviceMinKeyCode = 0;
339 m_deviceMaxKeyCode = 0;
341 m_bUnplugged = false;
346 CLinuxInputDevice::~CLinuxInputDevice()
352 * Translates a Linux input keycode into an XBMC keycode.
354 XBMCKey CLinuxInputDevice::TranslateKey(unsigned short code)
356 if (code < D_ARRAY_SIZE(basic_keycodes))
357 return basic_keycodes[code];
360 In the future we may want it...
363 if (code - KEY_OK < D_ARRAY_SIZE(ext_keycodes))
364 return ext_keycodes[code - KEY_OK];
367 return XBMCK_UNKNOWN;
370 int CLinuxInputDevice::KeyboardGetSymbol(unsigned short value)
372 unsigned char type = KTYP(value);
373 unsigned char index = KVAL(value);
379 return XBMCK_F1 + index;
388 return XBMCK_BACKSPACE;
390 return XBMCK_EURO; /* euro currency sign */
401 return DIKS_DEAD_GRAVE;
404 return DIKS_DEAD_ACUTE;
407 return DIKS_DEAD_CIRCUMFLEX;
410 return DIKS_DEAD_TILDE;
413 return DIKS_DEAD_DIAERESIS;
416 return DIKS_DEAD_CEDILLA;
424 if (index <= 9 && level != DIKSI_BASE)
425 return (DFBInputDeviceKeySymbol) (DIKS_0 + index);
430 return XBMCK_UNKNOWN;
433 unsigned short CLinuxInputDevice::KeyboardReadValue(unsigned char table, unsigned char index)
435 struct kbentry entry;
437 entry.kb_table = table;
438 entry.kb_index = index;
441 if (ioctl(m_vt_fd, KDGKBENT, &entry))
443 CLog::Log(LOGWARNING, "CLinuxInputDevice::KeyboardReadValue: KDGKBENT (table: %d, index: %d) "
444 "failed!\n", table, index);
448 return entry.kb_value;
451 XBMCMod CLinuxInputDevice::UpdateModifiers(XBMC_Event& devt)
453 XBMCMod modifier = XBMCKMOD_NONE;
454 switch (devt.key.keysym.sym)
456 case XBMCK_LSHIFT: modifier = XBMCKMOD_LSHIFT; break;
457 case XBMCK_RSHIFT: modifier = XBMCKMOD_RSHIFT; break;
458 case XBMCK_LCTRL: modifier = XBMCKMOD_LCTRL; break;
459 case XBMCK_RCTRL: modifier = XBMCKMOD_RCTRL; break;
460 case XBMCK_LALT: modifier = XBMCKMOD_LALT; break;
461 case XBMCK_RALT: modifier = XBMCKMOD_RALT; break;
462 case XBMCK_LMETA: modifier = XBMCKMOD_LMETA; break;
463 case XBMCK_RMETA: modifier = XBMCKMOD_RMETA; break;
467 if (devt.key.type == XBMC_KEYDOWN)
469 m_keyMods |= modifier;
473 m_keyMods &= ~modifier;
476 if (devt.key.type == XBMC_KEYDOWN)
478 modifier = XBMCKMOD_NONE;
479 switch (devt.key.keysym.sym)
481 case XBMCK_NUMLOCK: modifier = XBMCKMOD_NUM; break;
482 case XBMCK_CAPSLOCK: modifier = XBMCKMOD_CAPS; break;
486 if (m_keyMods & modifier)
488 m_keyMods &= ~modifier;
492 m_keyMods |= modifier;
496 return (XBMCMod) m_keyMods;
500 * Translates key and button events.
502 bool CLinuxInputDevice::KeyEvent(const struct input_event& levt, XBMC_Event& devt)
504 int code = levt.code;
506 /* map touchscreen and smartpad events to button mouse */
507 if (code == BTN_TOUCH || code == BTN_TOOL_FINGER)
510 if ((code >= BTN_MOUSE && code < BTN_JOYSTICK) || code == BTN_TOUCH)
512 /* ignore repeat events for buttons */
516 devt.type = levt.value ? XBMC_MOUSEBUTTONDOWN : XBMC_MOUSEBUTTONUP;
517 devt.button.state = levt.value ? XBMC_PRESSED : XBMC_RELEASED;
518 devt.button.type = devt.type;
519 devt.button.x = m_mouseX;
520 devt.button.y = m_mouseY;
525 devt.button.button = XBMC_BUTTON_RIGHT;
529 devt.button.button = XBMC_BUTTON_LEFT;
533 devt.button.button = XBMC_BUTTON_RIGHT;
537 devt.button.button = XBMC_BUTTON_WHEELDOWN;
541 devt.button.button = XBMC_BUTTON_WHEELUP;
545 devt.button.button = XBMC_BUTTON_LEFT;
548 case BTN_TOOL_DOUBLETAP:
549 devt.button.button = XBMC_BUTTON_RIGHT;
553 CLog::Log(LOGWARNING, "CLinuxInputDevice::KeyEvent: Unknown mouse button code: %d\n", levt.code);
559 XBMCKey key = TranslateKey(code);
561 if (key == XBMCK_UNKNOWN)
564 devt.type = levt.value ? XBMC_KEYDOWN : XBMC_KEYUP;
565 devt.key.type = devt.type;
566 devt.key.keysym.scancode = code;
567 devt.key.keysym.sym = key;
568 devt.key.keysym.mod = UpdateModifiers(devt);
569 devt.key.keysym.unicode = 0;
573 if (GetKeymapEntry(entry))
576 if (devt.key.keysym.mod & (XBMCKMOD_SHIFT | XBMCKMOD_CAPS)) keyMapValue = entry.shift;
577 else if (devt.key.keysym.mod & XBMCKMOD_ALT) keyMapValue = entry.alt;
578 else if (devt.key.keysym.mod & XBMCKMOD_META) keyMapValue = entry.altShift;
579 else keyMapValue = entry.base;
581 if (keyMapValue != XBMCK_UNKNOWN)
583 devt.key.keysym.sym = (XBMCKey) keyMapValue;
584 if (keyMapValue > 0 && keyMapValue < 127)
586 devt.key.keysym.unicode = devt.key.keysym.sym;
596 * Translates relative axis events.
598 bool CLinuxInputDevice::RelEvent(const struct input_event& levt, XBMC_Event& devt)
603 m_mouseX += levt.value;
604 devt.motion.xrel = levt.value;
605 devt.motion.yrel = 0;
609 m_mouseY += levt.value;
610 devt.motion.xrel = 0;
611 devt.motion.yrel = levt.value;
617 CLog::Log(LOGWARNING, "CLinuxInputDevice::RelEvent: Unknown rel event code: %d\n", levt.code);
621 // limit the mouse to the screen width
622 m_mouseX = std::min(g_graphicsContext.GetWidth(), m_mouseX);
623 m_mouseX = std::max(0, m_mouseX);
625 // limit the mouse to the screen height
626 m_mouseY = std::min(g_graphicsContext.GetHeight(), m_mouseY);
627 m_mouseY = std::max(0, m_mouseY);
630 devt.type = XBMC_MOUSEMOTION;
631 devt.motion.type = XBMC_MOUSEMOTION;
632 devt.motion.x = m_mouseX;
633 devt.motion.y = m_mouseY;
634 devt.motion.state = 0;
635 devt.motion.which = m_deviceIndex;
642 * Translates absolute axis events.
644 bool CLinuxInputDevice::AbsEvent(const struct input_event& levt, XBMC_Event& devt)
649 m_mouseX = levt.value;
653 m_mouseY = levt.value;
657 remoteStatus = levt.value & 0xFF;
665 devt.type = XBMC_MOUSEMOTION;
666 devt.motion.type = XBMC_MOUSEMOTION;
667 devt.motion.x = m_mouseX;
668 devt.motion.y = m_mouseY;
669 devt.motion.state = 0;
670 devt.motion.xrel = 0;
671 devt.motion.yrel = 0;
672 devt.motion.which = m_deviceIndex;
678 * Translates a Linux input event into a DirectFB input event.
680 bool CLinuxInputDevice::TranslateEvent(const struct input_event& levt,
686 return KeyEvent(levt, devt);
689 if (m_bSkipNonKeyEvents)
691 CLog::Log(LOGINFO, "read a relative event which will be ignored (device name %s) (file name %s)", m_deviceName, m_fileName.c_str());
695 return RelEvent(levt, devt);
698 if (m_bSkipNonKeyEvents)
700 CLog::Log(LOGINFO, "read an absolute event which will be ignored (device name %s) (file name %s)", m_deviceName, m_fileName.c_str());
704 return AbsEvent(levt, devt);
713 void CLinuxInputDevice::SetLed(int led, int state)
715 struct input_event levt;
719 levt.value = !!state;
721 write(m_fd, &levt, sizeof(levt));
725 * Input thread reading from device.
726 * Generates events on incoming data.
728 XBMC_Event CLinuxInputDevice::ReadEvent()
731 struct input_event levt;
737 bzero(&levt, sizeof(levt));
739 bzero(&devt, sizeof(devt));
740 devt.type = XBMC_NOEVENT;
742 if(m_devicePreferredId == LI_DEVICE_NONE)
745 readlen = read(m_fd, &levt, sizeof(levt));
751 CLog::Log(LOGINFO,"input device was unplugged %s",m_deviceName);
758 //printf("read event readlen = %d device name %s m_fileName %s\n", readlen, m_deviceName, m_fileName.c_str());
760 // sanity check if we realy read the event
761 if(readlen != sizeof(levt))
763 printf("CLinuxInputDevice: read error : %s\n", strerror(errno));
767 if (!TranslateEvent(levt, devt))
770 /* Flush previous event with DIEF_FOLLOW? */
771 if (devt.type != XBMC_NOEVENT)
773 //printf("new event! type = %d\n", devt.type);
774 //printf("key: %d %d %d %c\n", devt.key.keysym.scancode, devt.key.keysym.sym, devt.key.keysym.mod, devt.key.keysym.unicode);
776 if (m_hasLeds && (m_keyMods != m_lastKeyMods))
778 SetLed(LED_NUML, m_keyMods & XBMCKMOD_NUM);
779 SetLed(LED_CAPSL, m_keyMods & XBMCKMOD_CAPS);
780 m_lastKeyMods = m_keyMods;
790 void CLinuxInputDevice::SetupKeyboardAutoRepeat(int fd)
794 #if defined(HAS_AMLPLAYER)
795 // ignore the native aml driver named 'key_input',
796 // it is the dedicated power key handler (am_key_input)
797 if (strncmp(m_deviceName, "key_input", strlen("key_input")) == 0)
799 // ignore the native aml driver named 'aml_keypad',
800 // it is the dedicated IR remote handler (amremote)
801 else if (strncmp(m_deviceName, "aml_keypad", strlen("aml_keypad")) == 0)
804 // turn off any keyboard autorepeat, there is a kernel bug
805 // where if the cpu is max'ed then key up is missed and
806 // we get a flood of EV_REP that never stop until next
807 // key down/up. Very nasty when seeking during video playback.
813 int kbdrep[2] = { 400, 80 };
814 ioctl(fd, EVIOCSREP, kbdrep);
818 struct input_event event;
819 memset(&event, 0, sizeof(event));
821 gettimeofday(&event.time, NULL);
823 event.code = REP_DELAY;
825 write(fd, &event, sizeof(event));
827 gettimeofday(&event.time, NULL);
829 event.code = REP_PERIOD;
831 write(fd, &event, sizeof(event));
833 CLog::Log(LOGINFO, "CLinuxInputDevice: auto key repeat disabled on device '%s'\n", m_deviceName);
838 * Fill device information.
839 * Queries the input device and tries to classify it.
841 void CLinuxInputDevice::GetInfo(int fd)
843 unsigned int num_keys = 0;
844 unsigned int num_ext_keys = 0;
845 unsigned int num_buttons = 0;
846 unsigned int num_rels = 0;
847 unsigned int num_abs = 0;
849 unsigned long evbit[NBITS(EV_CNT)];
850 unsigned long keybit[NBITS(KEY_CNT)];
852 /* get device name */
853 bzero(m_deviceName, sizeof(m_deviceName));
854 ioctl(fd, EVIOCGNAME(sizeof(m_deviceName)-1), m_deviceName);
856 if (strncmp(m_deviceName, "D-Link Boxee D-Link Boxee Receiver", strlen("D-Link Boxee D-Link Boxee Receiver")) == 0)
858 m_bSkipNonKeyEvents = true;
862 m_bSkipNonKeyEvents = false;
864 CLog::Log(LOGINFO, "opened device '%s' (file name %s), m_bSkipNonKeyEvents %d\n", m_deviceName, m_fileName.c_str(), m_bSkipNonKeyEvents);
866 /* get event type bits */
867 ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit);
869 if (test_bit( EV_KEY, evbit ))
873 /* get keyboard bits */
874 ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit);
876 /** count typical keyboard keys only */
877 for (i = KEY_Q; i <= KEY_M; i++)
878 if (test_bit( i, keybit ))
881 for (i = KEY_OK; i < KEY_CNT; i++)
882 if (test_bit( i, keybit ))
885 for (i = BTN_MOUSE; i < BTN_JOYSTICK; i++)
886 if (test_bit( i, keybit ))
891 unsigned long relbit[NBITS(REL_CNT)];
892 unsigned long absbit[NBITS(ABS_CNT)];
894 if (test_bit( EV_REL, evbit ))
898 /* get bits for relative axes */
899 ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit);
901 for (i = 0; i < REL_CNT; i++)
902 if (test_bit( i, relbit ))
906 if (test_bit( EV_ABS, evbit ))
910 /* get bits for absolute axes */
911 ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit);
913 for (i = 0; i < ABS_PRESSURE; i++)
914 if (test_bit( i, absbit ))
918 /* Mouse, Touchscreen or Smartpad ? */
919 if ((test_bit( EV_KEY, evbit ) && (test_bit( BTN_TOUCH, keybit )
920 || test_bit( BTN_TOOL_FINGER, keybit ))) || ((num_rels >= 2
921 && num_buttons) || (num_abs == 2 && (num_buttons == 1))))
922 m_deviceType |= LI_DEVICE_MOUSE;
923 else if (num_abs && num_buttons) /* Or a Joystick? */
924 m_deviceType |= LI_DEVICE_JOYSTICK;
927 /* A Keyboard, do we have at least some letters? */
930 m_deviceType |= LI_DEVICE_KEYBOARD;
931 m_deviceCaps |= LI_CAPS_KEYS;
933 m_deviceMinKeyCode = 0;
934 m_deviceMaxKeyCode = 127;
937 /* A Remote Control? */
940 m_deviceType |= LI_DEVICE_REMOTE;
941 m_deviceCaps |= LI_CAPS_KEYS;
947 m_deviceCaps |= LI_CAPS_BUTTONS;
948 m_deviceMaxKeyCode = num_buttons - 1;
952 if (num_rels || num_abs)
954 m_deviceCaps |= LI_CAPS_AXES;
955 m_deviceMaxAxis = std::max(num_rels, num_abs) - 1;
958 /* Decide which primary input device to be. */
959 if (m_deviceType & LI_DEVICE_KEYBOARD)
960 m_devicePreferredId = LI_DEVICE_KEYBOARD;
961 else if (m_deviceType & LI_DEVICE_REMOTE)
962 m_devicePreferredId = LI_DEVICE_REMOTE;
963 else if (m_deviceType & LI_DEVICE_JOYSTICK)
964 m_devicePreferredId = LI_DEVICE_JOYSTICK;
965 else if (m_deviceType & LI_DEVICE_MOUSE)
966 m_devicePreferredId = LI_DEVICE_MOUSE;
968 m_devicePreferredId = LI_DEVICE_NONE;
970 //printf("type: %d\n", m_deviceType);
971 //printf("caps: %d\n", m_deviceCaps);
972 //printf("pref: %d\n", m_devicePreferredId);
975 char* CLinuxInputDevice::GetDeviceName()
980 bool CLinuxInputDevice::IsUnplugged()
985 bool CLinuxInputDevices::CheckDevice(const char *device)
989 /* Check if we are able to open the device */
990 fd = open(device, O_RDWR);
994 if (ioctl(fd, EVIOCGRAB, 1) && errno != EINVAL)
1000 ioctl(fd, EVIOCGRAB, 0);
1007 /* exported symbols */
1010 * Return the number of available devices.
1011 * Called once during initialization of DirectFB.
1013 void CLinuxInputDevices::InitAvailable()
1015 CSingleLock lock(m_devicesListLock);
1017 /* Close any devices that may have been initialized previously */
1018 for (size_t i = 0; i < m_devices.size(); i++)
1020 delete m_devices[i];
1026 /* No devices specified. Try to guess some. */
1027 for (int i = 0; i < MAX_LINUX_INPUT_DEVICES; i++)
1031 snprintf(buf, 32, "/dev/input/event%d", i);
1032 if (CheckDevice(buf))
1034 CLog::Log(LOGINFO, "Found input device %s", buf);
1035 m_devices.push_back(new CLinuxInputDevice(buf, deviceId));
1042 * Check for hot plugged devices.
1044 void CLinuxInputDevices::CheckHotplugged()
1046 CSingleLock lock(m_devicesListLock);
1048 int deviceId = m_devices.size();
1050 /* No devices specified. Try to guess some. */
1051 for (int i = 0; i < MAX_LINUX_INPUT_DEVICES; i++)
1054 bool ispresent = false;
1056 snprintf(buf, 32, "/dev/input/event%d", i);
1058 for (size_t j = 0; j < m_devices.size(); j++)
1060 if (strcmp(m_devices[j]->GetDeviceName(),buf) == 0)
1067 if (!ispresent && CheckDevice(buf))
1069 CLog::Log(LOGINFO, "Found input device %s", buf);
1070 m_devices.push_back(new CLinuxInputDevice(buf, deviceId));
1077 * Open the device, fill out information about it,
1078 * allocate and fill private data, start input thread.
1080 bool CLinuxInputDevice::Open()
1083 unsigned long ledbit[NBITS(LED_CNT)];
1086 fd = open(m_fileName.c_str(), O_RDWR | O_NONBLOCK);
1089 CLog::Log(LOGERROR, "CLinuxInputDevice: could not open device: %s\n", m_fileName.c_str());
1094 ret = ioctl(fd, EVIOCGRAB, 1);
1095 if (ret && errno != EINVAL)
1097 CLog::Log(LOGERROR, "CLinuxInputDevice: could not grab device: %s\n", m_fileName.c_str());
1102 // Set the socket to non-blocking
1104 if ((opts = fcntl(fd, F_GETFL)) < 0)
1106 CLog::Log(LOGERROR, "CLinuxInputDevice %s: fcntl(F_GETFL) failed: %s", __FUNCTION__ , strerror(errno));
1111 opts = (opts | O_NONBLOCK);
1112 if (fcntl(fd, F_SETFL, opts) < 0)
1114 CLog::Log(LOGERROR, "CLinuxInputDevice %s: fcntl(F_SETFL) failed: %s", __FUNCTION__, strerror(errno));
1119 /* fill device info structure */
1122 if (m_deviceType & LI_DEVICE_KEYBOARD)
1123 SetupKeyboardAutoRepeat(fd);
1128 if (m_deviceMinKeyCode >= 0 && m_deviceMaxKeyCode >= m_deviceMinKeyCode)
1131 m_vt_fd = open("/dev/tty0", O_RDWR | O_NOCTTY);
1134 m_vt_fd = open("/dev/tty1", O_RDWR | O_NOCTTY);
1137 CLog::Log(LOGWARNING, "no keymap support (requires /dev/tty0 - CONFIG_VT)");
1140 /* check if the device has LEDs */
1141 ret = ioctl(fd, EVIOCGBIT(EV_LED, sizeof(ledbit)), ledbit);
1143 CLog::Log(LOGWARNING, "DirectFB/linux_input: could not get LED bits" );
1145 m_hasLeds = test_bit( LED_SCROLLL, ledbit ) || test_bit( LED_NUML, ledbit )
1146 || test_bit( LED_CAPSL, ledbit );
1151 ret = ioctl(fd, EVIOCGLED(sizeof(m_ledState)), m_ledState);
1154 CLog::Log(LOGERROR, "DirectFB/linux_input: could not get LED state");
1155 goto driver_open_device_error;
1159 SetLed(LED_SCROLLL, 0);
1160 SetLed(LED_NUML, 0);
1161 SetLed(LED_CAPSL, 0);
1166 driver_open_device_error:
1168 ioctl(fd, EVIOCGRAB, 0);
1181 * Fetch one entry from the kernel keymap.
1183 bool CLinuxInputDevice::GetKeymapEntry(KeymapEntry& entry)
1185 int code = entry.code;
1186 unsigned short value;
1187 //DFBInputDeviceKeyIdentifier identifier;
1192 // to support '+' and '/' with Boxee's remote control we do something ugly like this for now
1193 if (KVAL(code) == 98)
1195 code = K(KTYP(code),53);
1198 /* fetch the base level */
1199 value = KeyboardGetSymbol(KeyboardReadValue(K_NORMTAB, code));
1200 //printf("base=%d typ=%d code %d\n", KVAL(value), KTYP(value), code);
1202 /* write base level symbol to entry */
1203 entry.base = value; //KeyboardGetSymbol(code, value, LI_KEYLEVEL_BASE);
1205 /* fetch the shifted base level */
1206 value = KeyboardGetSymbol(KeyboardReadValue(K_SHIFTTAB, entry.code));
1207 //printf("shift=%d\n", value);
1209 /* write shifted base level symbol to entry */
1210 entry.shift = value; //KeyboardGetSymbol(code, value, LI_KEYLEVEL_SHIFT);
1212 // to support '+' and '/' with Boxee's remote control we could do ugly something like this for now
1213 if (KVAL(code) == 78)
1215 //code = K(KTYP(code),13);
1216 //entry.code = K(KTYP(code),13);
1217 entry.base = K(KTYP(code),43);
1220 /* fetch the alternative level */
1221 value = KeyboardGetSymbol(KeyboardReadValue(K_ALTTAB, entry.code));
1222 //printf("alt=%d\n", value);
1224 /* write alternative level symbol to entry */
1225 entry.alt = value; //KeyboardGetSymbol(code, value, LI_KEYLEVEL_ALT);
1227 /* fetch the shifted alternative level */
1228 value = KeyboardGetSymbol(KeyboardReadValue(K_ALTSHIFTTAB, entry.code));
1229 //printf("altshift=%d\n", value);
1231 /* write shifted alternative level symbol to entry */
1232 entry.altShift = value; //KeyboardGetSymbol(code, value, LI_KEYLEVEL_ALT_SHIFT);
1238 * End thread, close device and free private data.
1240 void CLinuxInputDevice::Close()
1242 /* release device */
1243 ioctl(m_fd, EVIOCGRAB, 0);
1252 XBMC_Event CLinuxInputDevices::ReadEvent()
1254 if (m_bReInitialize)
1257 m_bReInitialize = false;
1264 if ((now - m_lastHotplugCheck) >= 10)
1267 m_lastHotplugCheck = now;
1271 CSingleLock lock(m_devicesListLock);
1274 event.type = XBMC_NOEVENT;
1276 for (size_t i = 0; i < m_devices.size(); i++)
1278 event = m_devices[i]->ReadEvent();
1279 if (event.type != XBMC_NOEVENT)
1284 if (m_devices[i]->IsUnplugged())
1286 m_bReInitialize = true;
1295 - 0x7F -> if not paired, battery OK
1296 - 0xFF -> if paired, battery OK
1297 - 0x00 -> if not paired, battery low
1298 - 0x80 -> if paired, battery low
1300 bool CLinuxInputDevices::IsRemoteLowBattery()
1302 bool bLowBattery = !(remoteStatus & 0xF);
1306 bool CLinuxInputDevices::IsRemoteNotPaired()
1308 bool bRemoteNotPaired = !(remoteStatus & 0x70) || !(remoteStatus & 0x80);
1309 return bRemoteNotPaired;
1315 CLinuxInputDevices devices;
1316 devices.InitAvailable();
1319 XBMC_Event event = devices.ReadEvent();
1320 if (event.type != XBMC_NOEVENT)
1322 printf("%d\n", event.type);