Merge pull request #2966 from Voyager1/uniquedvdid-use-libdvdnav
[vuplus_xbmc] / xbmc / input / linux / LinuxInputDevices.cpp
1 /*
2  *  Portions copied from DirectFB:
3  *      Copyright (C) 2001-2009  The world wide DirectFB Open Source Community (directfb.org)
4  *      Copyright (C) 2000-2004  Convergence (integrated media) GmbH
5  *      All rights reserved.
6  *      Written by Denis Oliver Kropp <dok@directfb.org>,
7  *      Andreas Hundt <andi@fischlustig.de>,
8  *      Sven Neumann <neo@directfb.org>,
9  *      Ville Syrjälä <syrjala@sci.fi> and
10  *      Claudio Ciccani <klan@users.sf.net>.
11  *
12  *      Copyright (C) 2005-2013 Team XBMC
13  *      http://xbmc.org
14  *
15  *  This Program is free software; you can redistribute it and/or modify
16  *  it under the terms of the GNU General Public License as published by
17  *  the Free Software Foundation; either version 2, or (at your option)
18  *  any later version.
19  *
20  *  This Program is distributed in the hope that it will be useful,
21  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
22  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23  *  GNU General Public License for more details.
24  *
25  *  You should have received a copy of the GNU General Public License
26  *  along with XBMC; see the file COPYING.  If not, see
27  *  <http://www.gnu.org/licenses/>.
28  *
29  */
30 #include "system.h"
31 #if defined(HAS_LINUX_EVENTS)
32
33 #include <linux/version.h>
34
35 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
36 typedef unsigned long kernel_ulong_t;
37 #define BITS_PER_LONG    (sizeof(long)*8)
38 #endif
39
40 #include <linux/input.h>
41
42 #ifndef EV_CNT
43 #define EV_CNT (EV_MAX+1)
44 #define KEY_CNT (KEY_MAX+1)
45 #define REL_CNT (REL_MAX+1)
46 #define ABS_CNT (ABS_MAX+1)
47 #define LED_CNT (LED_MAX+1)
48 #endif
49
50 /* compat defines for older kernel like 2.4.x */
51 #ifndef EV_SYN
52 #define EV_SYN                  0x00
53 #define SYN_REPORT              0
54 #define SYN_CONFIG              1
55 #define ABS_TOOL_WIDTH          0x1c
56 #define BTN_TOOL_DOUBLETAP      0x14d
57 #define BTN_TOOL_TRIPLETAP      0x14e
58 #endif
59
60 #ifndef EVIOCGLED
61 #define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len)
62 #endif
63
64 #ifndef EVIOCGRAB
65 #define EVIOCGRAB _IOW('E', 0x90, int)
66 #endif
67
68 #ifdef STANDALONE
69 #define XBMC_BUTTON_LEFT    1
70 #define XBMC_BUTTON_MIDDLE  2
71 #define XBMC_BUTTON_RIGHT 3
72 #define XBMC_BUTTON_WHEELUP 4
73 #define XBMC_BUTTON_WHEELDOWN 5
74 #endif
75
76 #include <linux/keyboard.h>
77 #include <linux/kd.h>
78
79 #include <string.h>
80 #include <unistd.h>
81 #include <errno.h>
82 #include <fcntl.h>
83
84 #include <sys/types.h>
85 #include <sys/stat.h>
86 #include <sys/ioctl.h>
87 #include <stdlib.h>
88 #include <stdio.h>
89
90 #include "guilib/GraphicContext.h"
91 #include "input/XBMC_keysym.h"
92 #include "LinuxInputDevices.h"
93 #include "input/MouseStat.h"
94 #include "utils/log.h"
95
96 #ifndef BITS_PER_LONG
97 #define BITS_PER_LONG        (sizeof(long) * 8)
98 #endif
99 #define NBITS(x)             ((((x)-1)/BITS_PER_LONG)+1)
100 #define OFF(x)               ((x)%BITS_PER_LONG)
101 #define BIT(x)               (1UL<<OFF(x))
102 #define LONG(x)              ((x)/BITS_PER_LONG)
103 #undef test_bit
104 #define test_bit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
105
106 #ifndef D_ARRAY_SIZE
107 #define D_ARRAY_SIZE(array)        ((int)(sizeof(array) / sizeof((array)[0])))
108 #endif
109
110 #define MAX_LINUX_INPUT_DEVICES 16
111
112 static const
113 XBMCKey basic_keycodes[] = { XBMCK_UNKNOWN, XBMCK_ESCAPE, XBMCK_1, XBMCK_2, XBMCK_3,
114     XBMCK_4, XBMCK_5, XBMCK_6, XBMCK_7, XBMCK_8, XBMCK_9, XBMCK_0, XBMCK_MINUS,
115     XBMCK_EQUALS, XBMCK_BACKSPACE,
116
117     XBMCK_TAB, XBMCK_q, XBMCK_w, XBMCK_e, XBMCK_r, XBMCK_t, XBMCK_y, XBMCK_u, XBMCK_i,
118     XBMCK_o, XBMCK_p, XBMCK_LEFTBRACKET, XBMCK_RIGHTBRACKET, XBMCK_RETURN,
119
120     XBMCK_LCTRL, XBMCK_a, XBMCK_s, XBMCK_d, XBMCK_f, XBMCK_g, XBMCK_h, XBMCK_j,
121     XBMCK_k, XBMCK_l, XBMCK_SEMICOLON, XBMCK_QUOTE, XBMCK_BACKQUOTE,
122
123     XBMCK_LSHIFT, XBMCK_BACKSLASH, XBMCK_z, XBMCK_x, XBMCK_c, XBMCK_v, XBMCK_b,
124     XBMCK_n, XBMCK_m, XBMCK_COMMA, XBMCK_PERIOD, XBMCK_SLASH, XBMCK_RSHIFT,
125     XBMCK_KP_MULTIPLY, XBMCK_LALT, XBMCK_SPACE, XBMCK_CAPSLOCK,
126
127     XBMCK_F1, XBMCK_F2, XBMCK_F3, XBMCK_F4, XBMCK_F5, XBMCK_F6, XBMCK_F7, XBMCK_F8,
128     XBMCK_F9, XBMCK_F10, XBMCK_NUMLOCK, XBMCK_SCROLLOCK,
129
130     XBMCK_KP7, XBMCK_KP8, XBMCK_KP9, XBMCK_KP_MINUS, XBMCK_KP4, XBMCK_KP5,
131     XBMCK_KP6, XBMCK_KP_PLUS, XBMCK_KP1, XBMCK_KP2, XBMCK_KP3, XBMCK_KP0,
132     XBMCK_KP_PERIOD,
133
134     /*KEY_103RD,*/XBMCK_BACKSLASH,
135     /*KEY_F13,*/XBMCK_F13,
136     /*KEY_102ND*/XBMCK_LESS,
137
138     XBMCK_F11, XBMCK_F12, XBMCK_F14, XBMCK_F15,
139     XBMCK_UNKNOWN,XBMCK_UNKNOWN,XBMCK_UNKNOWN, /*XBMCK_F16, XBMCK_F17, XBMCK_F18,*/
140     XBMCK_UNKNOWN, XBMCK_UNKNOWN, /*XBMCK_F19, XBMCK_F20,*/
141
142     XBMCK_KP_ENTER, XBMCK_RCTRL, XBMCK_KP_DIVIDE, XBMCK_PRINT, XBMCK_MODE,
143
144     /*KEY_LINEFEED*/XBMCK_UNKNOWN,
145
146     XBMCK_HOME, XBMCK_UP, XBMCK_PAGEUP, XBMCK_LEFT, XBMCK_RIGHT, XBMCK_END,
147     XBMCK_DOWN, XBMCK_PAGEDOWN, XBMCK_INSERT, XBMCK_DELETE,
148
149     /*KEY_MACRO,*/XBMCK_UNKNOWN,
150
151     XBMCK_VOLUME_MUTE, XBMCK_VOLUME_DOWN, XBMCK_VOLUME_UP, XBMCK_POWER, XBMCK_KP_EQUALS,
152
153     /*KEY_KPPLUSMINUS,*/XBMCK_UNKNOWN,
154
155     XBMCK_PAUSE, XBMCK_UNKNOWN, XBMCK_UNKNOWN, /*DFB_FUNCTION_KEY(21), DFB_FUNCTION_KEY(22), */
156     XBMCK_UNKNOWN, XBMCK_UNKNOWN, /*DFB_FUNCTION_KEY(23), DFB_FUNCTION_KEY(24),*/
157
158     /*DIKI_KP_SEPARATOR*/XBMCK_UNKNOWN, XBMCK_LMETA, XBMCK_RMETA, XBMCK_LSUPER,
159
160     XBMCK_MEDIA_STOP,
161
162     /*DIKS_AGAIN, DIKS_PROPS, DIKS_UNDO, DIKS_FRONT, DIKS_COPY,
163      DIKS_OPEN, DIKS_PASTE, DIKS_FIND, DIKS_CUT,*/
164     XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN,
165     XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN,
166
167     XBMCK_HELP,
168
169     /* DIKS_MENU, DIKS_CALCULATOR, DIKS_SETUP, */
170     XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN,
171
172     /*KEY_SLEEP, KEY_WAKEUP, KEY_FILE, KEY_SENDFILE, KEY_DELETEFILE,
173      KEY_XFER,*/
174     XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN,
175     XBMCK_UNKNOWN,
176
177     /*KEY_PROG1, KEY_PROG2,*/
178     XBMCK_UNKNOWN, XBMCK_UNKNOWN,
179
180     /*DIKS_INTERNET*/ XBMCK_UNKNOWN,
181
182     /*KEY_MSDOS, KEY_COFFEE, KEY_DIRECTION, KEY_CYCLEWINDOWS,*/
183     XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN,
184
185     /*DIKS_MAIL*/ XBMCK_UNKNOWN,
186
187     /*KEY_BOOKMARKS, KEY_COMPUTER, */
188     XBMCK_UNKNOWN, XBMCK_UNKNOWN,
189
190     /*DIKS_BACK, DIKS_FORWARD,*/
191     XBMCK_UNKNOWN, XBMCK_UNKNOWN,
192
193     /*KEY_CLOSECD, KEY_EJECTCD, KEY_EJECTCLOSECD,*/
194     XBMCK_EJECT, XBMCK_EJECT, XBMCK_EJECT,
195
196     XBMCK_MEDIA_NEXT_TRACK, XBMCK_MEDIA_PLAY_PAUSE, XBMCK_MEDIA_PREV_TRACK, XBMCK_MEDIA_STOP, XBMCK_RECORD,
197     XBMCK_REWIND, XBMCK_PHONE,
198
199     /*KEY_ISO,*/XBMCK_UNKNOWN,
200     /*KEY_CONFIG,*/XBMCK_UNKNOWN,
201     /*KEY_HOMEPAGE, KEY_REFRESH,*/XBMCK_UNKNOWN, XBMCK_SHUFFLE,
202
203     /*DIKS_EXIT*/XBMCK_UNKNOWN, /*KEY_MOVE,*/XBMCK_UNKNOWN, /*DIKS_EDITOR*/XBMCK_UNKNOWN,
204
205     /*KEY_SCROLLUP,*/XBMCK_PAGEUP,
206     /*KEY_SCROLLDOWN,*/XBMCK_PAGEDOWN,
207     /*KEY_KPLEFTPAREN,*/XBMCK_UNKNOWN,
208     /*KEY_KPRIGHTPAREN,*/XBMCK_UNKNOWN,
209
210     /* unused codes 181-182: */
211     XBMCK_UNKNOWN, XBMCK_UNKNOWN,
212
213 /*
214     DFB_FUNCTION_KEY(13), DFB_FUNCTION_KEY(14), DFB_FUNCTION_KEY(15),
215     DFB_FUNCTION_KEY(16), DFB_FUNCTION_KEY(17), DFB_FUNCTION_KEY(18),
216     DFB_FUNCTION_KEY(19), DFB_FUNCTION_KEY(20), DFB_FUNCTION_KEY(21),
217     DFB_FUNCTION_KEY(22), DFB_FUNCTION_KEY(23), DFB_FUNCTION_KEY(24),
218 */
219     XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN,
220     XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN,
221     XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN,
222     XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN,
223
224     /* unused codes 195-199: */
225     XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN,
226
227     /* KEY_PLAYCD, KEY_PAUSECD */
228     XBMCK_PLAY, XBMCK_PAUSE,
229
230     /*KEY_PROG3, KEY_PROG4,*/
231     XBMCK_UNKNOWN, XBMCK_UNKNOWN,
232
233     XBMCK_UNKNOWN,
234
235     /*KEY_SUSPEND, KEY_CLOSE*/
236     XBMCK_UNKNOWN, XBMCK_UNKNOWN,
237
238     /* KEY_PLAY */
239     XBMCK_PLAY,
240
241     /* KEY_FASTFORWARD */
242     XBMCK_FASTFORWARD,
243
244     /* KEY_BASSBOOST */
245     XBMCK_UNKNOWN,
246
247     /* KEY_PRINT */
248     XBMCK_PRINT,
249
250     /* KEY_HP             */XBMCK_UNKNOWN,
251     /* KEY_CAMERA         */XBMCK_UNKNOWN,
252     /* KEY_SOUND          */XBMCK_UNKNOWN,
253     /* KEY_QUESTION       */XBMCK_HELP,
254     /* KEY_EMAIL          */XBMCK_UNKNOWN,
255     /* KEY_CHAT           */XBMCK_UNKNOWN,
256     /* KEY_SEARCH         */XBMCK_UNKNOWN,
257     /* KEY_CONNECT        */XBMCK_UNKNOWN,
258     /* KEY_FINANCE        */XBMCK_UNKNOWN,
259     /* KEY_SPORT          */XBMCK_UNKNOWN,
260     /* KEY_SHOP           */XBMCK_UNKNOWN,
261     /* KEY_ALTERASE       */XBMCK_UNKNOWN,
262     /* KEY_CANCEL         */XBMCK_UNKNOWN,
263     /* KEY_BRIGHTNESSDOWN */XBMCK_UNKNOWN,
264     /* KEY_BRIGHTNESSUP   */XBMCK_UNKNOWN,
265     /* KEY_MEDIA          */XBMCK_UNKNOWN, };
266
267 /*
268   In the future we may want it...
269
270 static const
271 int ext_keycodes[] = { DIKS_OK, DIKS_SELECT, DIKS_GOTO, DIKS_CLEAR,
272     DIKS_POWER2, DIKS_OPTION, DIKS_INFO, DIKS_TIME, DIKS_VENDOR, DIKS_ARCHIVE,
273     DIKS_PROGRAM, DIKS_CHANNEL, DIKS_FAVORITES, DIKS_EPG, DIKS_PVR, DIKS_MHP,
274     DIKS_LANGUAGE, DIKS_TITLE, DIKS_SUBTITLE, DIKS_ANGLE, DIKS_ZOOM, DIKS_MODE,
275     DIKS_KEYBOARD, DIKS_SCREEN, DIKS_PC, DIKS_TV, DIKS_TV2, DIKS_VCR,
276     DIKS_VCR2, DIKS_SAT, DIKS_SAT2, DIKS_CD, DIKS_TAPE, DIKS_RADIO, DIKS_TUNER,
277     DIKS_PLAYER, DIKS_TEXT, DIKS_DVD, DIKS_AUX, DIKS_MP3, DIKS_AUDIO,
278     DIKS_VIDEO, DIKS_DIRECTORY, DIKS_LIST, DIKS_MEMO, DIKS_CALENDAR, DIKS_RED,
279     DIKS_GREEN, DIKS_YELLOW, DIKS_BLUE, DIKS_CHANNEL_UP, DIKS_CHANNEL_DOWN,
280     DIKS_FIRST, DIKS_LAST, DIKS_AB, DIKS_NEXT, DIKS_RESTART, DIKS_SLOW,
281     DIKS_SHUFFLE, DIKS_FASTFORWARD, DIKS_PREVIOUS, DIKS_NEXT, DIKS_DIGITS,
282     DIKS_TEEN, DIKS_TWEN, DIKS_BREAK };
283 */
284
285 typedef enum
286 {
287   LI_DEVICE_NONE     = 0,
288   LI_DEVICE_MOUSE    = 1,
289   LI_DEVICE_JOYSTICK = 2,
290   LI_DEVICE_KEYBOARD = 4,
291   LI_DEVICE_REMOTE   = 8
292 } LinuxInputDeviceType;
293
294 typedef enum
295 {
296   LI_CAPS_KEYS    = 1,
297   LI_CAPS_BUTTONS = 2,
298   LI_CAPS_AXES    = 4,
299 } LinuxInputCapsType;
300
301 static char remoteStatus = 0xFF; // paired, battery OK
302
303 CLinuxInputDevice::CLinuxInputDevice(const std::string fileName, int index)
304 {
305   m_fd = -1;
306   m_vt_fd = -1;
307   m_hasLeds = false;
308   m_fileName = fileName;
309   m_ledState[0] = false;
310   m_ledState[1] = false;
311   m_ledState[2] = false;
312   m_mouseX = 0;
313   m_mouseY = 0;
314   m_deviceIndex = index;
315   m_keyMods = XBMCKMOD_NONE;
316   m_lastKeyMods = XBMCKMOD_NONE;
317   strcpy(m_deviceName, "");
318   m_deviceType = 0;
319   m_devicePreferredId = 0;
320   m_deviceCaps = 0;
321   m_deviceMinKeyCode = 0;
322   m_deviceMaxKeyCode = 0;
323   m_deviceMaxAxis = 0;
324   m_bUnplugged = false;
325
326   Open();
327 }
328
329 CLinuxInputDevice::~CLinuxInputDevice()
330 {
331   Close();
332 }
333
334 /*
335  * Translates a Linux input keycode into an XBMC keycode.
336  */
337 XBMCKey CLinuxInputDevice::TranslateKey(unsigned short code)
338 {
339   if (code < D_ARRAY_SIZE(basic_keycodes))
340     return basic_keycodes[code];
341
342 /*
343   In the future we may want it...
344
345   if (code >= KEY_OK)
346     if (code - KEY_OK < D_ARRAY_SIZE(ext_keycodes))
347       return ext_keycodes[code - KEY_OK];
348 */
349
350   return XBMCK_UNKNOWN;
351 }
352
353 int CLinuxInputDevice::KeyboardGetSymbol(unsigned short value)
354 {
355   unsigned char type = KTYP(value);
356   unsigned char index = KVAL(value);
357
358   switch (type)
359   {
360   case KT_FN:
361     if (index < 15)
362       return XBMCK_F1 + index;
363     break;
364   case KT_LETTER:
365   case KT_LATIN:
366     switch (index)
367     {
368     case 0x1c:
369       return XBMCK_PRINT;
370     case 0x7f:
371       return XBMCK_BACKSPACE;
372     case 0xa4:
373       return XBMCK_EURO; /* euro currency sign */
374     default:
375       return index;
376     }
377     break;
378
379 /*
380   case KT_DEAD:
381     switch (value)
382     {
383     case K_DGRAVE:
384       return DIKS_DEAD_GRAVE;
385
386     case K_DACUTE:
387       return DIKS_DEAD_ACUTE;
388
389     case K_DCIRCM:
390       return DIKS_DEAD_CIRCUMFLEX;
391
392     case K_DTILDE:
393       return DIKS_DEAD_TILDE;
394
395     case K_DDIERE:
396       return DIKS_DEAD_DIAERESIS;
397
398     case K_DCEDIL:
399       return DIKS_DEAD_CEDILLA;
400
401     default:
402       break;
403     }
404     break;
405
406   case KT_PAD:
407     if (index <= 9 && level != DIKSI_BASE)
408       return (DFBInputDeviceKeySymbol) (DIKS_0 + index);
409     break;
410 */
411   }
412
413   return XBMCK_UNKNOWN;
414 }
415
416 unsigned short CLinuxInputDevice::KeyboardReadValue(unsigned char table, unsigned char index)
417 {
418   struct kbentry entry;
419
420   entry.kb_table = table;
421   entry.kb_index = index;
422   entry.kb_value = 0;
423
424   if (ioctl(m_vt_fd, KDGKBENT, &entry))
425   {
426     CLog::Log(LOGWARNING, "CLinuxInputDevice::KeyboardReadValue: KDGKBENT (table: %d, index: %d) "
427         "failed!\n", table, index);
428     return 0;
429   }
430
431   return entry.kb_value;
432 }
433
434 XBMCMod CLinuxInputDevice::UpdateModifiers(XBMC_Event& devt)
435 {
436   XBMCMod modifier = XBMCKMOD_NONE;
437   switch (devt.key.keysym.sym)
438   {
439     case XBMCK_LSHIFT: modifier = XBMCKMOD_LSHIFT; break;
440     case XBMCK_RSHIFT: modifier = XBMCKMOD_RSHIFT; break;
441     case XBMCK_LCTRL: modifier = XBMCKMOD_LCTRL; break;
442     case XBMCK_RCTRL: modifier = XBMCKMOD_RCTRL; break;
443     case XBMCK_LALT: modifier = XBMCKMOD_LALT; break;
444     case XBMCK_RALT: modifier = XBMCKMOD_RALT; break;
445     case XBMCK_LMETA: modifier = XBMCKMOD_LMETA; break;
446     case XBMCK_RMETA: modifier = XBMCKMOD_RMETA; break;
447     default: break;
448   }
449
450   if (devt.key.type == XBMC_KEYDOWN)
451   {
452     m_keyMods |= modifier;
453   }
454   else
455   {
456     m_keyMods &= ~modifier;
457   }
458
459   if (devt.key.type == XBMC_KEYDOWN)
460   {
461     modifier = XBMCKMOD_NONE;
462     switch (devt.key.keysym.sym)
463     {
464       case XBMCK_NUMLOCK: modifier = XBMCKMOD_NUM; break;
465       case XBMCK_CAPSLOCK: modifier = XBMCKMOD_CAPS; break;
466       default: break;
467     }
468
469     if (m_keyMods & modifier)
470     {
471       m_keyMods &= ~modifier;
472     }
473     else
474     {
475       m_keyMods |= modifier;
476     }
477   }
478
479   return (XBMCMod) m_keyMods;
480 }
481
482 /*
483  * Translates key and button events.
484  */
485 bool CLinuxInputDevice::KeyEvent(const struct input_event& levt, XBMC_Event& devt)
486 {
487   int code = levt.code;
488
489   /* map touchscreen and smartpad events to button mouse */
490   if (code == BTN_TOUCH || code == BTN_TOOL_FINGER)
491     code = BTN_MOUSE;
492
493   if ((code >= BTN_MOUSE && code < BTN_JOYSTICK) || code == BTN_TOUCH)
494   {
495     /* ignore repeat events for buttons */
496     if (levt.value == 2)
497       return false;
498
499     devt.type = levt.value ? XBMC_MOUSEBUTTONDOWN : XBMC_MOUSEBUTTONUP;
500     devt.button.state = levt.value ? XBMC_PRESSED : XBMC_RELEASED;
501     devt.button.type = devt.type;
502     devt.button.x = m_mouseX;
503     devt.button.y = m_mouseY;
504
505     switch (levt.code)
506     {
507       case BTN_RIGHT:
508         devt.button.button = XBMC_BUTTON_RIGHT;
509         break;
510
511       case BTN_LEFT:
512         devt.button.button = XBMC_BUTTON_LEFT;
513         break;
514
515       case BTN_MIDDLE:
516         devt.button.button = XBMC_BUTTON_RIGHT;
517         break;
518
519       case BTN_FORWARD:
520         devt.button.button = XBMC_BUTTON_WHEELDOWN;
521         break;
522
523       case BTN_BACK:
524         devt.button.button = XBMC_BUTTON_WHEELUP;
525         break;
526
527       case BTN_TOUCH:
528         devt.button.button = XBMC_BUTTON_LEFT;
529         break;
530
531       case BTN_TOOL_DOUBLETAP:
532         devt.button.button = XBMC_BUTTON_RIGHT;
533         break;
534
535       default:
536         CLog::Log(LOGWARNING, "CLinuxInputDevice::KeyEvent: Unknown mouse button code: %d\n", levt.code);
537         return false;
538     }
539   }
540   else
541   {
542     XBMCKey key = TranslateKey(code);
543
544     if (key == XBMCK_UNKNOWN)
545       return false;
546
547     devt.type = levt.value ? XBMC_KEYDOWN : XBMC_KEYUP;
548     devt.key.type = devt.type;
549     devt.key.keysym.scancode = code;
550     devt.key.keysym.sym = key;
551     devt.key.keysym.mod = UpdateModifiers(devt);
552     devt.key.keysym.unicode = 0;
553
554     KeymapEntry entry;
555     entry.code = code;
556     if (GetKeymapEntry(entry))
557     {
558       int keyMapValue;
559       if (devt.key.keysym.mod & (XBMCKMOD_SHIFT | XBMCKMOD_CAPS)) keyMapValue = entry.shift;
560       else if (devt.key.keysym.mod & XBMCKMOD_ALT) keyMapValue = entry.alt;
561       else if (devt.key.keysym.mod & XBMCKMOD_META) keyMapValue = entry.altShift;
562       else keyMapValue = entry.base;
563
564       if (keyMapValue != XBMCK_UNKNOWN)
565       {
566         devt.key.keysym.sym = (XBMCKey) keyMapValue;
567         if (keyMapValue > 0 && keyMapValue < 127)
568         {
569           devt.key.keysym.unicode = devt.key.keysym.sym;
570         }
571       }
572     }
573   }
574
575   return true;
576 }
577
578 /*
579  * Translates relative axis events.
580  */
581 bool CLinuxInputDevice::RelEvent(const struct input_event& levt, XBMC_Event& devt)
582 {
583   switch (levt.code)
584   {
585   case REL_X:
586     m_mouseX += levt.value;
587     devt.motion.xrel = levt.value;
588     devt.motion.yrel = 0;
589     break;
590
591   case REL_Y:
592     m_mouseY += levt.value;
593     devt.motion.xrel = 0;
594     devt.motion.yrel = levt.value;
595     break;
596
597   case REL_Z:
598   case REL_WHEEL:
599   default:
600     CLog::Log(LOGWARNING, "CLinuxInputDevice::RelEvent: Unknown rel event code: %d\n", levt.code);
601     return false;
602   }
603
604   // limit the mouse to the screen width
605   m_mouseX = std::min(g_graphicsContext.GetWidth(), m_mouseX);
606   m_mouseX = std::max(0, m_mouseX);
607
608   // limit the mouse to the screen height
609   m_mouseY = std::min(g_graphicsContext.GetHeight(), m_mouseY);
610   m_mouseY = std::max(0, m_mouseY);
611
612
613   devt.type = XBMC_MOUSEMOTION;
614   devt.motion.type = XBMC_MOUSEMOTION;
615   devt.motion.x = m_mouseX;
616   devt.motion.y = m_mouseY;
617   devt.motion.state = 0;
618   devt.motion.which = m_deviceIndex;
619
620
621   return true;
622 }
623
624 /*
625  * Translates absolute axis events.
626  */
627 bool CLinuxInputDevice::AbsEvent(const struct input_event& levt, XBMC_Event& devt)
628 {
629   switch (levt.code)
630   {
631   case ABS_X:
632     m_mouseX = levt.value;
633     break;
634
635   case ABS_Y:
636     m_mouseY = levt.value;
637     break;
638   
639   case ABS_MISC:
640     remoteStatus = levt.value & 0xFF;
641     break;
642
643   case ABS_Z:
644   default:
645     return false;
646   }
647
648   devt.type = XBMC_MOUSEMOTION;
649   devt.motion.type = XBMC_MOUSEMOTION;
650   devt.motion.x = m_mouseX;
651   devt.motion.y = m_mouseY;
652   devt.motion.state = 0;
653   devt.motion.xrel = 0;
654   devt.motion.yrel = 0;
655   devt.motion.which = m_deviceIndex;
656
657   return true;
658 }
659
660 /*
661  * Translates a Linux input event into a DirectFB input event.
662  */
663 bool CLinuxInputDevice::TranslateEvent(const struct input_event& levt,
664     XBMC_Event& devt)
665 {
666   switch (levt.type)
667   {
668   case EV_KEY:
669     return KeyEvent(levt, devt);
670
671   case EV_REL:
672     if (m_bSkipNonKeyEvents)
673     {
674       CLog::Log(LOGINFO, "read a relative event which will be ignored (device name %s) (file name %s)", m_deviceName, m_fileName.c_str());
675       return false;
676     }
677
678     return RelEvent(levt, devt);
679
680   case EV_ABS:
681     if (m_bSkipNonKeyEvents)
682     {
683       CLog::Log(LOGINFO, "read an absolute event which will be ignored (device name %s) (file name %s)", m_deviceName, m_fileName.c_str());
684       return false;
685     }
686
687     return AbsEvent(levt, devt);
688
689   default:
690     ;
691   }
692
693   return false;
694 }
695
696 void CLinuxInputDevice::SetLed(int led, int state)
697 {
698   struct input_event levt;
699
700   levt.type = EV_LED;
701   levt.code = led;
702   levt.value = !!state;
703
704   write(m_fd, &levt, sizeof(levt));
705 }
706
707 /*
708  * Input thread reading from device.
709  * Generates events on incoming data.
710  */
711 XBMC_Event CLinuxInputDevice::ReadEvent()
712 {
713   int readlen;
714   struct input_event levt;
715
716   XBMC_Event devt;
717
718   while (1)
719   {
720     bzero(&levt, sizeof(levt));
721
722     bzero(&devt, sizeof(devt));
723     devt.type = XBMC_NOEVENT;
724
725     if(m_devicePreferredId == LI_DEVICE_NONE)
726       return devt;
727
728     readlen = read(m_fd, &levt, sizeof(levt));
729
730     if (readlen <= 0)
731     {
732       if (errno == ENODEV)
733       {
734         CLog::Log(LOGINFO,"input device was unplugged %s",m_deviceName);
735         m_bUnplugged = true;
736       }
737
738       break;
739     }
740
741     //printf("read event readlen = %d device name %s m_fileName %s\n", readlen, m_deviceName, m_fileName.c_str());
742
743     // sanity check if we realy read the event
744     if(readlen != sizeof(levt))
745     {
746       printf("CLinuxInputDevice: read error : %s\n", strerror(errno));
747       break;
748     }
749
750     if (!TranslateEvent(levt, devt))
751       continue;
752
753     /* Flush previous event with DIEF_FOLLOW? */
754     if (devt.type != XBMC_NOEVENT)
755     {
756       //printf("new event! type = %d\n", devt.type);
757       //printf("key: %d %d %d %c\n", devt.key.keysym.scancode, devt.key.keysym.sym, devt.key.keysym.mod, devt.key.keysym.unicode);
758
759       if (m_hasLeds && (m_keyMods != m_lastKeyMods))
760       {
761         SetLed(LED_NUML, m_keyMods & XBMCKMOD_NUM);
762         SetLed(LED_CAPSL, m_keyMods & XBMCKMOD_CAPS);
763         m_lastKeyMods = m_keyMods;
764       }
765
766       break;
767     }
768   }
769
770   return devt;
771 }
772
773 void CLinuxInputDevice::SetupKeyboardAutoRepeat(int fd)
774 {
775   bool enable = true;
776
777 #if defined(HAS_AMLPLAYER)
778   // ignore the native aml driver named 'key_input',
779   //  it is the dedicated power key handler (am_key_input)
780   if (strncmp(m_deviceName, "key_input", strlen("key_input")) == 0)
781     return;
782   // ignore the native aml driver named 'aml_keypad',
783   //  it is the dedicated IR remote handler (amremote)
784   else if (strncmp(m_deviceName, "aml_keypad", strlen("aml_keypad")) == 0)
785     return;
786
787   // turn off any keyboard autorepeat, there is a kernel bug
788   // where if the cpu is max'ed then key up is missed and
789   // we get a flood of EV_REP that never stop until next
790   // key down/up. Very nasty when seeking during video playback.
791   enable = false;
792 #endif
793
794   if (enable)
795   {
796     int kbdrep[2] = { 400, 80 };
797     ioctl(fd, EVIOCSREP, kbdrep);
798   }
799   else
800   {
801     struct input_event event;
802     memset(&event, 0, sizeof(event));
803
804     gettimeofday(&event.time, NULL);
805     event.type  = EV_REP;
806     event.code  = REP_DELAY;
807     event.value = 0;
808     write(fd, &event, sizeof(event));
809
810     gettimeofday(&event.time, NULL);
811     event.type  = EV_REP;
812     event.code  = REP_PERIOD;
813     event.value = 0;
814     write(fd, &event, sizeof(event));
815
816     CLog::Log(LOGINFO, "CLinuxInputDevice: auto key repeat disabled on device '%s'\n", m_deviceName);
817   }
818 }
819
820 /*
821  * Fill device information.
822  * Queries the input device and tries to classify it.
823  */
824 void CLinuxInputDevice::GetInfo(int fd)
825 {
826   unsigned int num_keys = 0;
827   unsigned int num_ext_keys = 0;
828   unsigned int num_buttons = 0;
829   unsigned int num_rels = 0;
830   unsigned int num_abs = 0;
831
832   unsigned long evbit[NBITS(EV_CNT)];
833   unsigned long keybit[NBITS(KEY_CNT)];
834
835   /* get device name */
836   bzero(m_deviceName, sizeof(m_deviceName));
837   ioctl(fd, EVIOCGNAME(sizeof(m_deviceName)-1), m_deviceName);
838
839   if (strncmp(m_deviceName, "D-Link Boxee D-Link Boxee Receiver", strlen("D-Link Boxee D-Link Boxee Receiver")) == 0)
840   {
841     m_bSkipNonKeyEvents = true;
842   }
843   else
844   {
845     m_bSkipNonKeyEvents = false;
846   }
847   CLog::Log(LOGINFO, "opened device '%s' (file name %s), m_bSkipNonKeyEvents %d\n", m_deviceName, m_fileName.c_str(), m_bSkipNonKeyEvents);
848
849   /* get event type bits */
850   ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit);
851
852   if (test_bit( EV_KEY, evbit ))
853   {
854     int i;
855
856     /* get keyboard bits */
857     ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit);
858
859     /**  count typical keyboard keys only */
860     for (i = KEY_Q; i <= KEY_M; i++)
861       if (test_bit( i, keybit ))
862         num_keys++;
863
864     for (i = KEY_OK; i < KEY_CNT; i++)
865       if (test_bit( i, keybit ))
866         num_ext_keys++;
867
868     for (i = BTN_MOUSE; i < BTN_JOYSTICK; i++)
869       if (test_bit( i, keybit ))
870         num_buttons++;
871   }
872
873 #ifndef HAS_INTELCE
874   unsigned long relbit[NBITS(REL_CNT)];
875   unsigned long absbit[NBITS(ABS_CNT)];
876
877   if (test_bit( EV_REL, evbit ))
878   {
879     int i;
880
881     /* get bits for relative axes */
882     ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit);
883
884     for (i = 0; i < REL_CNT; i++)
885       if (test_bit( i, relbit ))
886         num_rels++;
887   }
888
889   if (test_bit( EV_ABS, evbit ))
890   {
891     int i;
892
893     /* get bits for absolute axes */
894     ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit);
895
896     for (i = 0; i < ABS_PRESSURE; i++)
897       if (test_bit( i, absbit ))
898         num_abs++;
899   }
900
901   /* Mouse, Touchscreen or Smartpad ? */
902   if ((test_bit( EV_KEY, evbit ) && (test_bit( BTN_TOUCH, keybit )
903       || test_bit( BTN_TOOL_FINGER, keybit ))) || ((num_rels >= 2
904       && num_buttons) || (num_abs == 2 && (num_buttons == 1))))
905     m_deviceType |= LI_DEVICE_MOUSE;
906   else if (num_abs && num_buttons) /* Or a Joystick? */
907     m_deviceType |= LI_DEVICE_JOYSTICK;
908 #endif
909
910   /* A Keyboard, do we have at least some letters? */
911   if (num_keys > 20)
912   {
913     m_deviceType |= LI_DEVICE_KEYBOARD;
914     m_deviceCaps |= LI_CAPS_KEYS;
915
916     m_deviceMinKeyCode = 0;
917     m_deviceMaxKeyCode = 127;
918   }
919
920   /* A Remote Control? */
921   if (num_ext_keys)
922   {
923     m_deviceType |= LI_DEVICE_REMOTE;
924     m_deviceCaps |= LI_CAPS_KEYS;
925   }
926
927   /* Buttons */
928   if (num_buttons)
929   {
930     m_deviceCaps |= LI_CAPS_BUTTONS;
931     m_deviceMaxKeyCode = num_buttons - 1;
932   }
933
934   /* Axes */
935   if (num_rels || num_abs)
936   {
937     m_deviceCaps |= LI_CAPS_AXES;
938     m_deviceMaxAxis = std::max(num_rels, num_abs) - 1;
939   }
940
941   /* Decide which primary input device to be. */
942   if (m_deviceType & LI_DEVICE_KEYBOARD)
943     m_devicePreferredId = LI_DEVICE_KEYBOARD;
944   else if (m_deviceType & LI_DEVICE_REMOTE)
945     m_devicePreferredId = LI_DEVICE_REMOTE;
946   else if (m_deviceType & LI_DEVICE_JOYSTICK)
947     m_devicePreferredId = LI_DEVICE_JOYSTICK;
948   else if (m_deviceType & LI_DEVICE_MOUSE)
949     m_devicePreferredId = LI_DEVICE_MOUSE;
950   else
951     m_devicePreferredId = LI_DEVICE_NONE;
952
953   //printf("type: %d\n", m_deviceType);
954   //printf("caps: %d\n", m_deviceCaps);
955   //printf("pref: %d\n", m_devicePreferredId);
956 }
957
958 char* CLinuxInputDevice::GetDeviceName()
959 {
960   return m_deviceName;
961 }
962
963 bool CLinuxInputDevice::IsUnplugged()
964 {
965   return m_bUnplugged;
966 }
967
968 bool CLinuxInputDevices::CheckDevice(const char *device)
969 {
970   int fd;
971
972   /* Check if we are able to open the device */
973   fd = open(device, O_RDWR);
974   if (fd < 0)
975     return false;
976
977   if (ioctl(fd, EVIOCGRAB, 1) && errno != EINVAL)
978   {
979     close(fd);
980     return false;
981   }
982
983   ioctl(fd, EVIOCGRAB, 0);
984
985   close(fd);
986
987   return true;
988 }
989
990 /* exported symbols */
991
992 /*
993  * Return the number of available devices.
994  * Called once during initialization of DirectFB.
995  */
996 void CLinuxInputDevices::InitAvailable()
997 {
998   CSingleLock lock(m_devicesListLock);
999
1000   /* Close any devices that may have been initialized previously */
1001   for (size_t i = 0; i < m_devices.size(); i++)
1002   {
1003     delete m_devices[i];
1004   }
1005   m_devices.clear();
1006
1007   int deviceId = 0;
1008
1009   /* No devices specified. Try to guess some. */
1010   for (int i = 0; i < MAX_LINUX_INPUT_DEVICES; i++)
1011   {
1012     char buf[32];
1013
1014     snprintf(buf, 32, "/dev/input/event%d", i);
1015     if (CheckDevice(buf))
1016     {
1017       CLog::Log(LOGINFO, "Found input device %s", buf);
1018       m_devices.push_back(new CLinuxInputDevice(buf, deviceId));
1019       ++deviceId;
1020     }
1021   }
1022 }
1023
1024 /*
1025  * Check for hot plugged devices.
1026  */
1027 void CLinuxInputDevices::CheckHotplugged()
1028 {
1029   CSingleLock lock(m_devicesListLock);
1030
1031   int deviceId = m_devices.size();
1032
1033   /* No devices specified. Try to guess some. */
1034   for (int i = 0; i < MAX_LINUX_INPUT_DEVICES; i++)
1035   {
1036     char buf[32];
1037     bool ispresent = false;
1038
1039     snprintf(buf, 32, "/dev/input/event%d", i);
1040
1041     for (size_t j = 0; j < m_devices.size(); j++)
1042     {
1043       if (strcmp(m_devices[j]->GetDeviceName(),buf) == 0)
1044       {
1045         ispresent = true;
1046         break;
1047       }
1048     }
1049
1050     if (!ispresent && CheckDevice(buf))
1051     {
1052       CLog::Log(LOGINFO, "Found input device %s", buf);
1053       m_devices.push_back(new CLinuxInputDevice(buf, deviceId));
1054       ++deviceId;
1055     }
1056   }
1057 }
1058
1059 /*
1060  * Open the device, fill out information about it,
1061  * allocate and fill private data, start input thread.
1062  */
1063 bool CLinuxInputDevice::Open()
1064 {
1065   int fd, ret;
1066   unsigned long ledbit[NBITS(LED_CNT)];
1067
1068   /* open device */
1069   fd = open(m_fileName.c_str(), O_RDWR | O_NONBLOCK);
1070   if (fd < 0)
1071   {
1072     CLog::Log(LOGERROR, "CLinuxInputDevice: could not open device: %s\n", m_fileName.c_str());
1073     return false;
1074   }
1075
1076   /* grab device */
1077   ret = ioctl(fd, EVIOCGRAB, 1);
1078   if (ret && errno != EINVAL)
1079   {
1080     CLog::Log(LOGERROR, "CLinuxInputDevice: could not grab device: %s\n", m_fileName.c_str());
1081     close(fd);
1082     return false;
1083   }
1084
1085   // Set the socket to non-blocking
1086   int opts = 0;
1087   if ((opts = fcntl(fd, F_GETFL)) < 0)
1088   {
1089     CLog::Log(LOGERROR, "CLinuxInputDevice %s: fcntl(F_GETFL) failed: %s", __FUNCTION__ , strerror(errno));
1090     close(fd);
1091     return false;
1092   }
1093
1094   opts = (opts | O_NONBLOCK);
1095   if (fcntl(fd, F_SETFL, opts) < 0)
1096   {
1097     CLog::Log(LOGERROR, "CLinuxInputDevice %s: fcntl(F_SETFL) failed: %s", __FUNCTION__, strerror(errno));
1098     close(fd);
1099     return false;
1100   }
1101
1102   /* fill device info structure */
1103   GetInfo(fd);
1104
1105   if (m_deviceType & LI_DEVICE_KEYBOARD)
1106     SetupKeyboardAutoRepeat(fd);
1107
1108   m_fd = fd;
1109   m_vt_fd = -1;
1110
1111   if (m_deviceMinKeyCode >= 0 && m_deviceMaxKeyCode >= m_deviceMinKeyCode)
1112   {
1113     if (m_vt_fd < 0)
1114       m_vt_fd = open("/dev/tty0", O_RDWR | O_NOCTTY);
1115  
1116     if (m_vt_fd < 0)
1117       m_vt_fd = open("/dev/tty1", O_RDWR | O_NOCTTY);
1118
1119     if (m_vt_fd < 0)
1120       CLog::Log(LOGWARNING, "no keymap support (requires /dev/tty0 - CONFIG_VT)");
1121   }
1122
1123   /* check if the device has LEDs */
1124   ret = ioctl(fd, EVIOCGBIT(EV_LED, sizeof(ledbit)), ledbit);
1125   if (ret < 0)
1126           CLog::Log(LOGWARNING, "DirectFB/linux_input: could not get LED bits" );
1127   else
1128     m_hasLeds = test_bit( LED_SCROLLL, ledbit ) || test_bit( LED_NUML, ledbit )
1129         || test_bit( LED_CAPSL, ledbit );
1130
1131   if (m_hasLeds)
1132   {
1133     /* get LED state */
1134     ret = ioctl(fd, EVIOCGLED(sizeof(m_ledState)), m_ledState);
1135     if (ret < 0)
1136     {
1137       CLog::Log(LOGERROR, "DirectFB/linux_input: could not get LED state");
1138       goto driver_open_device_error;
1139     }
1140
1141     /* turn off LEDs */
1142     SetLed(LED_SCROLLL, 0);
1143     SetLed(LED_NUML, 0);
1144     SetLed(LED_CAPSL, 0);
1145   }
1146
1147   return true;
1148
1149 driver_open_device_error:
1150
1151   ioctl(fd, EVIOCGRAB, 0);
1152   if (m_vt_fd >= 0)
1153   {
1154     close(m_vt_fd);
1155     m_vt_fd = -1;
1156   }
1157   close(fd);
1158   m_fd = -1;
1159
1160   return false;
1161 }
1162
1163 /*
1164  * Fetch one entry from the kernel keymap.
1165  */
1166 bool CLinuxInputDevice::GetKeymapEntry(KeymapEntry& entry)
1167 {
1168   int code = entry.code;
1169   unsigned short value;
1170   //DFBInputDeviceKeyIdentifier identifier;
1171
1172   if (m_vt_fd < 0)
1173     return false;
1174
1175   // to support '+'  and '/' with Boxee's remote control we do something ugly like this for now
1176   if (KVAL(code) == 98)
1177   {
1178     code = K(KTYP(code),53);
1179   }
1180
1181   /* fetch the base level */
1182   value = KeyboardGetSymbol(KeyboardReadValue(K_NORMTAB, code));
1183   //printf("base=%d typ=%d code %d\n", KVAL(value), KTYP(value), code);
1184
1185   /* write base level symbol to entry */
1186   entry.base = value; //KeyboardGetSymbol(code, value, LI_KEYLEVEL_BASE);
1187
1188   /* fetch the shifted base level */
1189   value = KeyboardGetSymbol(KeyboardReadValue(K_SHIFTTAB, entry.code));
1190   //printf("shift=%d\n", value);
1191
1192   /* write shifted base level symbol to entry */
1193   entry.shift = value; //KeyboardGetSymbol(code, value, LI_KEYLEVEL_SHIFT);
1194
1195   // to support '+'  and '/' with Boxee's remote control we could do ugly something like this for now
1196   if (KVAL(code) == 78)
1197   {
1198     //code = K(KTYP(code),13);
1199     //entry.code = K(KTYP(code),13);
1200     entry.base = K(KTYP(code),43);
1201   }
1202
1203   /* fetch the alternative level */
1204   value = KeyboardGetSymbol(KeyboardReadValue(K_ALTTAB, entry.code));
1205   //printf("alt=%d\n", value);
1206
1207   /* write alternative level symbol to entry */
1208   entry.alt = value; //KeyboardGetSymbol(code, value, LI_KEYLEVEL_ALT);
1209
1210   /* fetch the shifted alternative level */
1211   value = KeyboardGetSymbol(KeyboardReadValue(K_ALTSHIFTTAB, entry.code));
1212   //printf("altshift=%d\n", value);
1213
1214   /* write shifted alternative level symbol to entry */
1215   entry.altShift = value; //KeyboardGetSymbol(code, value, LI_KEYLEVEL_ALT_SHIFT);
1216
1217   return true;
1218 }
1219
1220 /*
1221  * End thread, close device and free private data.
1222  */
1223 void CLinuxInputDevice::Close()
1224 {
1225   /* release device */
1226   ioctl(m_fd, EVIOCGRAB, 0);
1227
1228   if (m_vt_fd >= 0)
1229     close(m_vt_fd);
1230
1231   /* close file */
1232   close(m_fd);
1233 }
1234
1235 XBMC_Event CLinuxInputDevices::ReadEvent()
1236 {
1237   if (m_bReInitialize)
1238   {
1239     InitAvailable();
1240     m_bReInitialize = false;
1241   }
1242   else
1243   {
1244     time_t now;
1245     time(&now);
1246
1247     if ((now - m_lastHotplugCheck) >= 10)
1248     {
1249       CheckHotplugged();
1250       m_lastHotplugCheck = now;
1251     }
1252   }
1253
1254   CSingleLock lock(m_devicesListLock);
1255
1256   XBMC_Event event;
1257   event.type = XBMC_NOEVENT;
1258
1259   for (size_t i = 0; i < m_devices.size(); i++)
1260   {
1261     event = m_devices[i]->ReadEvent();
1262     if (event.type != XBMC_NOEVENT)
1263     {
1264       break;
1265     }
1266
1267     if (m_devices[i]->IsUnplugged())
1268     {
1269       m_bReInitialize = true;
1270       break;
1271     }
1272   }
1273
1274   return event;
1275 }
1276
1277 /*
1278    - 0x7F -> if not paired, battery OK
1279    - 0xFF -> if paired, battery OK
1280    - 0x00 -> if not paired, battery low
1281    - 0x80 -> if paired, battery low
1282 */
1283 bool CLinuxInputDevices::IsRemoteLowBattery()
1284 {
1285   bool bLowBattery = !(remoteStatus & 0xF);
1286   return bLowBattery;
1287 }
1288
1289 bool CLinuxInputDevices::IsRemoteNotPaired()
1290 {
1291   bool bRemoteNotPaired = !(remoteStatus & 0x70) || !(remoteStatus & 0x80);
1292   return bRemoteNotPaired;
1293 }
1294
1295 /*
1296 int main()
1297 {
1298   CLinuxInputDevices devices;
1299   devices.InitAvailable();
1300   while (1)
1301   {
1302     XBMC_Event event = devices.ReadEvent();
1303     if (event.type != XBMC_NOEVENT)
1304     {
1305       printf("%d\n", event.type);
1306     }
1307     usleep(1000);
1308   }
1309
1310 }
1311 */
1312 #endif