Merge pull request #2658 from arnova/bluray_flag_fix
[vuplus_xbmc] / xbmc / input / linux / LinuxInputDevices.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://www.xbmc.org
4  *
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)
8  *  any later version.
9  *
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.
14  *
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/>.
18  *
19  *  Portions copied from DirectFB:
20
21  (c) Copyright 2001-2009  The world wide DirectFB Open Source Community (directfb.org)
22  (c) Copyright 2000-2004  Convergence (integrated media) GmbH
23  All rights reserved.
24
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>.
30
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.
35
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.
40
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.
45  */
46
47 #include "system.h"
48 #if defined(HAS_LINUX_EVENTS)
49
50 #include <linux/version.h>
51
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)
55 #endif
56
57 #include <linux/input.h>
58
59 #ifndef EV_CNT
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)
65 #endif
66
67 /* compat defines for older kernel like 2.4.x */
68 #ifndef EV_SYN
69 #define EV_SYN                  0x00
70 #define SYN_REPORT              0
71 #define SYN_CONFIG              1
72 #define ABS_TOOL_WIDTH          0x1c
73 #define BTN_TOOL_DOUBLETAP      0x14d
74 #define BTN_TOOL_TRIPLETAP      0x14e
75 #endif
76
77 #ifndef EVIOCGLED
78 #define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len)
79 #endif
80
81 #ifndef EVIOCGRAB
82 #define EVIOCGRAB _IOW('E', 0x90, int)
83 #endif
84
85 #ifdef STANDALONE
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
91 #endif
92
93 #include <linux/keyboard.h>
94 #include <linux/kd.h>
95
96 #include <string.h>
97 #include <unistd.h>
98 #include <errno.h>
99 #include <fcntl.h>
100
101 #include <sys/types.h>
102 #include <sys/stat.h>
103 #include <sys/ioctl.h>
104 #include <stdlib.h>
105 #include <stdio.h>
106
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"
112
113 #ifndef BITS_PER_LONG
114 #define BITS_PER_LONG        (sizeof(long) * 8)
115 #endif
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)
120 #undef test_bit
121 #define test_bit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
122
123 #ifndef D_ARRAY_SIZE
124 #define D_ARRAY_SIZE(array)        ((int)(sizeof(array) / sizeof((array)[0])))
125 #endif
126
127 #define MAX_LINUX_INPUT_DEVICES 16
128
129 static const
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,
133
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,
136
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,
139
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,
143
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,
146
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,
149     XBMCK_KP_PERIOD,
150
151     /*KEY_103RD,*/XBMCK_BACKSLASH,
152     /*KEY_F13,*/XBMCK_F13,
153     /*KEY_102ND*/XBMCK_LESS,
154
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,*/
158
159     XBMCK_KP_ENTER, XBMCK_RCTRL, XBMCK_KP_DIVIDE, XBMCK_PRINT, XBMCK_MODE,
160
161     /*KEY_LINEFEED*/XBMCK_UNKNOWN,
162
163     XBMCK_HOME, XBMCK_UP, XBMCK_PAGEUP, XBMCK_LEFT, XBMCK_RIGHT, XBMCK_END,
164     XBMCK_DOWN, XBMCK_PAGEDOWN, XBMCK_INSERT, XBMCK_DELETE,
165
166     /*KEY_MACRO,*/XBMCK_UNKNOWN,
167
168     XBMCK_VOLUME_MUTE, XBMCK_VOLUME_DOWN, XBMCK_VOLUME_UP, XBMCK_POWER, XBMCK_KP_EQUALS,
169
170     /*KEY_KPPLUSMINUS,*/XBMCK_UNKNOWN,
171
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),*/
174
175     /*DIKI_KP_SEPARATOR*/XBMCK_UNKNOWN, XBMCK_LMETA, XBMCK_RMETA, XBMCK_LSUPER,
176
177     XBMCK_MEDIA_STOP,
178
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,
183
184     XBMCK_HELP,
185
186     /* DIKS_MENU, DIKS_CALCULATOR, DIKS_SETUP, */
187     XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN,
188
189     /*KEY_SLEEP, KEY_WAKEUP, KEY_FILE, KEY_SENDFILE, KEY_DELETEFILE,
190      KEY_XFER,*/
191     XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN,
192     XBMCK_UNKNOWN,
193
194     /*KEY_PROG1, KEY_PROG2,*/
195     XBMCK_UNKNOWN, XBMCK_UNKNOWN,
196
197     /*DIKS_INTERNET*/ XBMCK_UNKNOWN,
198
199     /*KEY_MSDOS, KEY_COFFEE, KEY_DIRECTION, KEY_CYCLEWINDOWS,*/
200     XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN,
201
202     /*DIKS_MAIL*/ XBMCK_UNKNOWN,
203
204     /*KEY_BOOKMARKS, KEY_COMPUTER, */
205     XBMCK_UNKNOWN, XBMCK_UNKNOWN,
206
207     /*DIKS_BACK, DIKS_FORWARD,*/
208     XBMCK_UNKNOWN, XBMCK_UNKNOWN,
209
210     /*KEY_CLOSECD, KEY_EJECTCD, KEY_EJECTCLOSECD,*/
211     XBMCK_EJECT, XBMCK_EJECT, XBMCK_EJECT,
212
213     XBMCK_MEDIA_NEXT_TRACK, XBMCK_MEDIA_PLAY_PAUSE, XBMCK_MEDIA_PREV_TRACK, XBMCK_MEDIA_STOP, XBMCK_RECORD,
214     XBMCK_REWIND, XBMCK_PHONE,
215
216     /*KEY_ISO,*/XBMCK_UNKNOWN,
217     /*KEY_CONFIG,*/XBMCK_UNKNOWN,
218     /*KEY_HOMEPAGE, KEY_REFRESH,*/XBMCK_UNKNOWN, XBMCK_SHUFFLE,
219
220     /*DIKS_EXIT*/XBMCK_UNKNOWN, /*KEY_MOVE,*/XBMCK_UNKNOWN, /*DIKS_EDITOR*/XBMCK_UNKNOWN,
221
222     /*KEY_SCROLLUP,*/XBMCK_PAGEUP,
223     /*KEY_SCROLLDOWN,*/XBMCK_PAGEDOWN,
224     /*KEY_KPLEFTPAREN,*/XBMCK_UNKNOWN,
225     /*KEY_KPRIGHTPAREN,*/XBMCK_UNKNOWN,
226
227     /* unused codes 181-182: */
228     XBMCK_UNKNOWN, XBMCK_UNKNOWN,
229
230 /*
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),
235 */
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,
240
241     /* unused codes 195-199: */
242     XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN, XBMCK_UNKNOWN,
243
244     /* KEY_PLAYCD, KEY_PAUSECD */
245     XBMCK_PLAY, XBMCK_PAUSE,
246
247     /*KEY_PROG3, KEY_PROG4,*/
248     XBMCK_UNKNOWN, XBMCK_UNKNOWN,
249
250     XBMCK_UNKNOWN,
251
252     /*KEY_SUSPEND, KEY_CLOSE*/
253     XBMCK_UNKNOWN, XBMCK_UNKNOWN,
254
255     /* KEY_PLAY */
256     XBMCK_PLAY,
257
258     /* KEY_FASTFORWARD */
259     XBMCK_FASTFORWARD,
260
261     /* KEY_BASSBOOST */
262     XBMCK_UNKNOWN,
263
264     /* KEY_PRINT */
265     XBMCK_PRINT,
266
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, };
283
284 /*
285   In the future we may want it...
286
287 static const
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 };
300 */
301
302 typedef enum
303 {
304   LI_DEVICE_NONE     = 0,
305   LI_DEVICE_MOUSE    = 1,
306   LI_DEVICE_JOYSTICK = 2,
307   LI_DEVICE_KEYBOARD = 4,
308   LI_DEVICE_REMOTE   = 8
309 } LinuxInputDeviceType;
310
311 typedef enum
312 {
313   LI_CAPS_KEYS    = 1,
314   LI_CAPS_BUTTONS = 2,
315   LI_CAPS_AXES    = 4,
316 } LinuxInputCapsType;
317
318 static char remoteStatus = 0xFF; // paired, battery OK
319
320 CLinuxInputDevice::CLinuxInputDevice(const std::string fileName, int index)
321 {
322   m_fd = -1;
323   m_vt_fd = -1;
324   m_hasLeds = false;
325   m_fileName = fileName;
326   m_ledState[0] = false;
327   m_ledState[1] = false;
328   m_ledState[2] = false;
329   m_mouseX = 0;
330   m_mouseY = 0;
331   m_deviceIndex = index;
332   m_keyMods = XBMCKMOD_NONE;
333   m_lastKeyMods = XBMCKMOD_NONE;
334   strcpy(m_deviceName, "");
335   m_deviceType = 0;
336   m_devicePreferredId = 0;
337   m_deviceCaps = 0;
338   m_deviceMinKeyCode = 0;
339   m_deviceMaxKeyCode = 0;
340   m_deviceMaxAxis = 0;
341   m_bUnplugged = false;
342
343   Open();
344 }
345
346 CLinuxInputDevice::~CLinuxInputDevice()
347 {
348   Close();
349 }
350
351 /*
352  * Translates a Linux input keycode into an XBMC keycode.
353  */
354 XBMCKey CLinuxInputDevice::TranslateKey(unsigned short code)
355 {
356   if (code < D_ARRAY_SIZE(basic_keycodes))
357     return basic_keycodes[code];
358
359 /*
360   In the future we may want it...
361
362   if (code >= KEY_OK)
363     if (code - KEY_OK < D_ARRAY_SIZE(ext_keycodes))
364       return ext_keycodes[code - KEY_OK];
365 */
366
367   return XBMCK_UNKNOWN;
368 }
369
370 int CLinuxInputDevice::KeyboardGetSymbol(unsigned short value)
371 {
372   unsigned char type = KTYP(value);
373   unsigned char index = KVAL(value);
374
375   switch (type)
376   {
377   case KT_FN:
378     if (index < 15)
379       return XBMCK_F1 + index;
380     break;
381   case KT_LETTER:
382   case KT_LATIN:
383     switch (index)
384     {
385     case 0x1c:
386       return XBMCK_PRINT;
387     case 0x7f:
388       return XBMCK_BACKSPACE;
389     case 0xa4:
390       return XBMCK_EURO; /* euro currency sign */
391     default:
392       return index;
393     }
394     break;
395
396 /*
397   case KT_DEAD:
398     switch (value)
399     {
400     case K_DGRAVE:
401       return DIKS_DEAD_GRAVE;
402
403     case K_DACUTE:
404       return DIKS_DEAD_ACUTE;
405
406     case K_DCIRCM:
407       return DIKS_DEAD_CIRCUMFLEX;
408
409     case K_DTILDE:
410       return DIKS_DEAD_TILDE;
411
412     case K_DDIERE:
413       return DIKS_DEAD_DIAERESIS;
414
415     case K_DCEDIL:
416       return DIKS_DEAD_CEDILLA;
417
418     default:
419       break;
420     }
421     break;
422
423   case KT_PAD:
424     if (index <= 9 && level != DIKSI_BASE)
425       return (DFBInputDeviceKeySymbol) (DIKS_0 + index);
426     break;
427 */
428   }
429
430   return XBMCK_UNKNOWN;
431 }
432
433 unsigned short CLinuxInputDevice::KeyboardReadValue(unsigned char table, unsigned char index)
434 {
435   struct kbentry entry;
436
437   entry.kb_table = table;
438   entry.kb_index = index;
439   entry.kb_value = 0;
440
441   if (ioctl(m_vt_fd, KDGKBENT, &entry))
442   {
443     CLog::Log(LOGWARNING, "CLinuxInputDevice::KeyboardReadValue: KDGKBENT (table: %d, index: %d) "
444         "failed!\n", table, index);
445     return 0;
446   }
447
448   return entry.kb_value;
449 }
450
451 XBMCMod CLinuxInputDevice::UpdateModifiers(XBMC_Event& devt)
452 {
453   XBMCMod modifier = XBMCKMOD_NONE;
454   switch (devt.key.keysym.sym)
455   {
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;
464     default: break;
465   }
466
467   if (devt.key.type == XBMC_KEYDOWN)
468   {
469     m_keyMods |= modifier;
470   }
471   else
472   {
473     m_keyMods &= ~modifier;
474   }
475
476   if (devt.key.type == XBMC_KEYDOWN)
477   {
478     modifier = XBMCKMOD_NONE;
479     switch (devt.key.keysym.sym)
480     {
481       case XBMCK_NUMLOCK: modifier = XBMCKMOD_NUM; break;
482       case XBMCK_CAPSLOCK: modifier = XBMCKMOD_CAPS; break;
483       default: break;
484     }
485
486     if (m_keyMods & modifier)
487     {
488       m_keyMods &= ~modifier;
489     }
490     else
491     {
492       m_keyMods |= modifier;
493     }
494   }
495
496   return (XBMCMod) m_keyMods;
497 }
498
499 /*
500  * Translates key and button events.
501  */
502 bool CLinuxInputDevice::KeyEvent(const struct input_event& levt, XBMC_Event& devt)
503 {
504   int code = levt.code;
505
506   /* map touchscreen and smartpad events to button mouse */
507   if (code == BTN_TOUCH || code == BTN_TOOL_FINGER)
508     code = BTN_MOUSE;
509
510   if ((code >= BTN_MOUSE && code < BTN_JOYSTICK) || code == BTN_TOUCH)
511   {
512     /* ignore repeat events for buttons */
513     if (levt.value == 2)
514       return false;
515
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;
521
522     switch (levt.code)
523     {
524       case BTN_RIGHT:
525         devt.button.button = XBMC_BUTTON_RIGHT;
526         break;
527
528       case BTN_LEFT:
529         devt.button.button = XBMC_BUTTON_LEFT;
530         break;
531
532       case BTN_MIDDLE:
533         devt.button.button = XBMC_BUTTON_RIGHT;
534         break;
535
536       case BTN_FORWARD:
537         devt.button.button = XBMC_BUTTON_WHEELDOWN;
538         break;
539
540       case BTN_BACK:
541         devt.button.button = XBMC_BUTTON_WHEELUP;
542         break;
543
544       case BTN_TOUCH:
545         devt.button.button = XBMC_BUTTON_LEFT;
546         break;
547
548       case BTN_TOOL_DOUBLETAP:
549         devt.button.button = XBMC_BUTTON_RIGHT;
550         break;
551
552       default:
553         CLog::Log(LOGWARNING, "CLinuxInputDevice::KeyEvent: Unknown mouse button code: %d\n", levt.code);
554         return false;
555     }
556   }
557   else
558   {
559     XBMCKey key = TranslateKey(code);
560
561     if (key == XBMCK_UNKNOWN)
562       return false;
563
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;
570
571     KeymapEntry entry;
572     entry.code = code;
573     if (GetKeymapEntry(entry))
574     {
575       int keyMapValue;
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;
580
581       if (keyMapValue != XBMCK_UNKNOWN)
582       {
583         devt.key.keysym.sym = (XBMCKey) keyMapValue;
584         if (keyMapValue > 0 && keyMapValue < 127)
585         {
586           devt.key.keysym.unicode = devt.key.keysym.sym;
587         }
588       }
589     }
590   }
591
592   return true;
593 }
594
595 /*
596  * Translates relative axis events.
597  */
598 bool CLinuxInputDevice::RelEvent(const struct input_event& levt, XBMC_Event& devt)
599 {
600   switch (levt.code)
601   {
602   case REL_X:
603     m_mouseX += levt.value;
604     devt.motion.xrel = levt.value;
605     devt.motion.yrel = 0;
606     break;
607
608   case REL_Y:
609     m_mouseY += levt.value;
610     devt.motion.xrel = 0;
611     devt.motion.yrel = levt.value;
612     break;
613
614   case REL_Z:
615   case REL_WHEEL:
616   default:
617     CLog::Log(LOGWARNING, "CLinuxInputDevice::RelEvent: Unknown rel event code: %d\n", levt.code);
618     return false;
619   }
620
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);
624
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);
628
629
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;
636
637
638   return true;
639 }
640
641 /*
642  * Translates absolute axis events.
643  */
644 bool CLinuxInputDevice::AbsEvent(const struct input_event& levt, XBMC_Event& devt)
645 {
646   switch (levt.code)
647   {
648   case ABS_X:
649     m_mouseX = levt.value;
650     break;
651
652   case ABS_Y:
653     m_mouseY = levt.value;
654     break;
655   
656   case ABS_MISC:
657     remoteStatus = levt.value & 0xFF;
658     break;
659
660   case ABS_Z:
661   default:
662     return false;
663   }
664
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;
673
674   return true;
675 }
676
677 /*
678  * Translates a Linux input event into a DirectFB input event.
679  */
680 bool CLinuxInputDevice::TranslateEvent(const struct input_event& levt,
681     XBMC_Event& devt)
682 {
683   switch (levt.type)
684   {
685   case EV_KEY:
686     return KeyEvent(levt, devt);
687
688   case EV_REL:
689     if (m_bSkipNonKeyEvents)
690     {
691       CLog::Log(LOGINFO, "read a relative event which will be ignored (device name %s) (file name %s)", m_deviceName, m_fileName.c_str());
692       return false;
693     }
694
695     return RelEvent(levt, devt);
696
697   case EV_ABS:
698     if (m_bSkipNonKeyEvents)
699     {
700       CLog::Log(LOGINFO, "read an absolute event which will be ignored (device name %s) (file name %s)", m_deviceName, m_fileName.c_str());
701       return false;
702     }
703
704     return AbsEvent(levt, devt);
705
706   default:
707     ;
708   }
709
710   return false;
711 }
712
713 void CLinuxInputDevice::SetLed(int led, int state)
714 {
715   struct input_event levt;
716
717   levt.type = EV_LED;
718   levt.code = led;
719   levt.value = !!state;
720
721   write(m_fd, &levt, sizeof(levt));
722 }
723
724 /*
725  * Input thread reading from device.
726  * Generates events on incoming data.
727  */
728 XBMC_Event CLinuxInputDevice::ReadEvent()
729 {
730   int readlen;
731   struct input_event levt;
732
733   XBMC_Event devt;
734
735   while (1)
736   {
737     bzero(&levt, sizeof(levt));
738
739     bzero(&devt, sizeof(devt));
740     devt.type = XBMC_NOEVENT;
741
742     if(m_devicePreferredId == LI_DEVICE_NONE)
743       return devt;
744
745     readlen = read(m_fd, &levt, sizeof(levt));
746
747     if (readlen <= 0)
748     {
749       if (errno == ENODEV)
750       {
751         CLog::Log(LOGINFO,"input device was unplugged %s",m_deviceName);
752         m_bUnplugged = true;
753       }
754
755       break;
756     }
757
758     //printf("read event readlen = %d device name %s m_fileName %s\n", readlen, m_deviceName, m_fileName.c_str());
759
760     // sanity check if we realy read the event
761     if(readlen != sizeof(levt))
762     {
763       printf("CLinuxInputDevice: read error : %s\n", strerror(errno));
764       break;
765     }
766
767     if (!TranslateEvent(levt, devt))
768       continue;
769
770     /* Flush previous event with DIEF_FOLLOW? */
771     if (devt.type != XBMC_NOEVENT)
772     {
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);
775
776       if (m_hasLeds && (m_keyMods != m_lastKeyMods))
777       {
778         SetLed(LED_NUML, m_keyMods & XBMCKMOD_NUM);
779         SetLed(LED_CAPSL, m_keyMods & XBMCKMOD_CAPS);
780         m_lastKeyMods = m_keyMods;
781       }
782
783       break;
784     }
785   }
786
787   return devt;
788 }
789
790 void CLinuxInputDevice::SetupKeyboardAutoRepeat(int fd)
791 {
792   bool enable = true;
793
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)
798     return;
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)
802     return;
803
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.
808   enable = false;
809 #endif
810
811   if (enable)
812   {
813     int kbdrep[2] = { 400, 80 };
814     ioctl(fd, EVIOCSREP, kbdrep);
815   }
816   else
817   {
818     struct input_event event;
819     memset(&event, 0, sizeof(event));
820
821     gettimeofday(&event.time, NULL);
822     event.type  = EV_REP;
823     event.code  = REP_DELAY;
824     event.value = 0;
825     write(fd, &event, sizeof(event));
826
827     gettimeofday(&event.time, NULL);
828     event.type  = EV_REP;
829     event.code  = REP_PERIOD;
830     event.value = 0;
831     write(fd, &event, sizeof(event));
832
833     CLog::Log(LOGINFO, "CLinuxInputDevice: auto key repeat disabled on device '%s'\n", m_deviceName);
834   }
835 }
836
837 /*
838  * Fill device information.
839  * Queries the input device and tries to classify it.
840  */
841 void CLinuxInputDevice::GetInfo(int fd)
842 {
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;
848
849   unsigned long evbit[NBITS(EV_CNT)];
850   unsigned long keybit[NBITS(KEY_CNT)];
851
852   /* get device name */
853   bzero(m_deviceName, sizeof(m_deviceName));
854   ioctl(fd, EVIOCGNAME(sizeof(m_deviceName)-1), m_deviceName);
855
856   if (strncmp(m_deviceName, "D-Link Boxee D-Link Boxee Receiver", strlen("D-Link Boxee D-Link Boxee Receiver")) == 0)
857   {
858     m_bSkipNonKeyEvents = true;
859   }
860   else
861   {
862     m_bSkipNonKeyEvents = false;
863   }
864   CLog::Log(LOGINFO, "opened device '%s' (file name %s), m_bSkipNonKeyEvents %d\n", m_deviceName, m_fileName.c_str(), m_bSkipNonKeyEvents);
865
866   /* get event type bits */
867   ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit);
868
869   if (test_bit( EV_KEY, evbit ))
870   {
871     int i;
872
873     /* get keyboard bits */
874     ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit);
875
876     /**  count typical keyboard keys only */
877     for (i = KEY_Q; i <= KEY_M; i++)
878       if (test_bit( i, keybit ))
879         num_keys++;
880
881     for (i = KEY_OK; i < KEY_CNT; i++)
882       if (test_bit( i, keybit ))
883         num_ext_keys++;
884
885     for (i = BTN_MOUSE; i < BTN_JOYSTICK; i++)
886       if (test_bit( i, keybit ))
887         num_buttons++;
888   }
889
890 #ifndef HAS_INTELCE
891   unsigned long relbit[NBITS(REL_CNT)];
892   unsigned long absbit[NBITS(ABS_CNT)];
893
894   if (test_bit( EV_REL, evbit ))
895   {
896     int i;
897
898     /* get bits for relative axes */
899     ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit);
900
901     for (i = 0; i < REL_CNT; i++)
902       if (test_bit( i, relbit ))
903         num_rels++;
904   }
905
906   if (test_bit( EV_ABS, evbit ))
907   {
908     int i;
909
910     /* get bits for absolute axes */
911     ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit);
912
913     for (i = 0; i < ABS_PRESSURE; i++)
914       if (test_bit( i, absbit ))
915         num_abs++;
916   }
917
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;
925 #endif
926
927   /* A Keyboard, do we have at least some letters? */
928   if (num_keys > 20)
929   {
930     m_deviceType |= LI_DEVICE_KEYBOARD;
931     m_deviceCaps |= LI_CAPS_KEYS;
932
933     m_deviceMinKeyCode = 0;
934     m_deviceMaxKeyCode = 127;
935   }
936
937   /* A Remote Control? */
938   if (num_ext_keys)
939   {
940     m_deviceType |= LI_DEVICE_REMOTE;
941     m_deviceCaps |= LI_CAPS_KEYS;
942   }
943
944   /* Buttons */
945   if (num_buttons)
946   {
947     m_deviceCaps |= LI_CAPS_BUTTONS;
948     m_deviceMaxKeyCode = num_buttons - 1;
949   }
950
951   /* Axes */
952   if (num_rels || num_abs)
953   {
954     m_deviceCaps |= LI_CAPS_AXES;
955     m_deviceMaxAxis = std::max(num_rels, num_abs) - 1;
956   }
957
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;
967   else
968     m_devicePreferredId = LI_DEVICE_NONE;
969
970   //printf("type: %d\n", m_deviceType);
971   //printf("caps: %d\n", m_deviceCaps);
972   //printf("pref: %d\n", m_devicePreferredId);
973 }
974
975 char* CLinuxInputDevice::GetDeviceName()
976 {
977   return m_deviceName;
978 }
979
980 bool CLinuxInputDevice::IsUnplugged()
981 {
982   return m_bUnplugged;
983 }
984
985 bool CLinuxInputDevices::CheckDevice(const char *device)
986 {
987   int fd;
988
989   /* Check if we are able to open the device */
990   fd = open(device, O_RDWR);
991   if (fd < 0)
992     return false;
993
994   if (ioctl(fd, EVIOCGRAB, 1) && errno != EINVAL)
995   {
996     close(fd);
997     return false;
998   }
999
1000   ioctl(fd, EVIOCGRAB, 0);
1001
1002   close(fd);
1003
1004   return true;
1005 }
1006
1007 /* exported symbols */
1008
1009 /*
1010  * Return the number of available devices.
1011  * Called once during initialization of DirectFB.
1012  */
1013 void CLinuxInputDevices::InitAvailable()
1014 {
1015   CSingleLock lock(m_devicesListLock);
1016
1017   /* Close any devices that may have been initialized previously */
1018   for (size_t i = 0; i < m_devices.size(); i++)
1019   {
1020     delete m_devices[i];
1021   }
1022   m_devices.clear();
1023
1024   int deviceId = 0;
1025
1026   /* No devices specified. Try to guess some. */
1027   for (int i = 0; i < MAX_LINUX_INPUT_DEVICES; i++)
1028   {
1029     char buf[32];
1030
1031     snprintf(buf, 32, "/dev/input/event%d", i);
1032     if (CheckDevice(buf))
1033     {
1034       CLog::Log(LOGINFO, "Found input device %s", buf);
1035       m_devices.push_back(new CLinuxInputDevice(buf, deviceId));
1036       ++deviceId;
1037     }
1038   }
1039 }
1040
1041 /*
1042  * Check for hot plugged devices.
1043  */
1044 void CLinuxInputDevices::CheckHotplugged()
1045 {
1046   CSingleLock lock(m_devicesListLock);
1047
1048   int deviceId = m_devices.size();
1049
1050   /* No devices specified. Try to guess some. */
1051   for (int i = 0; i < MAX_LINUX_INPUT_DEVICES; i++)
1052   {
1053     char buf[32];
1054     bool ispresent = false;
1055
1056     snprintf(buf, 32, "/dev/input/event%d", i);
1057
1058     for (size_t j = 0; j < m_devices.size(); j++)
1059     {
1060       if (strcmp(m_devices[j]->GetDeviceName(),buf) == 0)
1061       {
1062         ispresent = true;
1063         break;
1064       }
1065     }
1066
1067     if (!ispresent && CheckDevice(buf))
1068     {
1069       CLog::Log(LOGINFO, "Found input device %s", buf);
1070       m_devices.push_back(new CLinuxInputDevice(buf, deviceId));
1071       ++deviceId;
1072     }
1073   }
1074 }
1075
1076 /*
1077  * Open the device, fill out information about it,
1078  * allocate and fill private data, start input thread.
1079  */
1080 bool CLinuxInputDevice::Open()
1081 {
1082   int fd, ret;
1083   unsigned long ledbit[NBITS(LED_CNT)];
1084
1085   /* open device */
1086   fd = open(m_fileName.c_str(), O_RDWR | O_NONBLOCK);
1087   if (fd < 0)
1088   {
1089     CLog::Log(LOGERROR, "CLinuxInputDevice: could not open device: %s\n", m_fileName.c_str());
1090     return false;
1091   }
1092
1093   /* grab device */
1094   ret = ioctl(fd, EVIOCGRAB, 1);
1095   if (ret && errno != EINVAL)
1096   {
1097     CLog::Log(LOGERROR, "CLinuxInputDevice: could not grab device: %s\n", m_fileName.c_str());
1098     close(fd);
1099     return false;
1100   }
1101
1102   // Set the socket to non-blocking
1103   int opts = 0;
1104   if ((opts = fcntl(fd, F_GETFL)) < 0)
1105   {
1106     CLog::Log(LOGERROR, "CLinuxInputDevice %s: fcntl(F_GETFL) failed: %s", __FUNCTION__ , strerror(errno));
1107     close(fd);
1108     return false;
1109   }
1110
1111   opts = (opts | O_NONBLOCK);
1112   if (fcntl(fd, F_SETFL, opts) < 0)
1113   {
1114     CLog::Log(LOGERROR, "CLinuxInputDevice %s: fcntl(F_SETFL) failed: %s", __FUNCTION__, strerror(errno));
1115     close(fd);
1116     return false;
1117   }
1118
1119   /* fill device info structure */
1120   GetInfo(fd);
1121
1122   if (m_deviceType & LI_DEVICE_KEYBOARD)
1123     SetupKeyboardAutoRepeat(fd);
1124
1125   m_fd = fd;
1126   m_vt_fd = -1;
1127
1128   if (m_deviceMinKeyCode >= 0 && m_deviceMaxKeyCode >= m_deviceMinKeyCode)
1129   {
1130     if (m_vt_fd < 0)
1131       m_vt_fd = open("/dev/tty0", O_RDWR | O_NOCTTY);
1132  
1133     if (m_vt_fd < 0)
1134       m_vt_fd = open("/dev/tty1", O_RDWR | O_NOCTTY);
1135
1136     if (m_vt_fd < 0)
1137       CLog::Log(LOGWARNING, "no keymap support (requires /dev/tty0 - CONFIG_VT)");
1138   }
1139
1140   /* check if the device has LEDs */
1141   ret = ioctl(fd, EVIOCGBIT(EV_LED, sizeof(ledbit)), ledbit);
1142   if (ret < 0)
1143           CLog::Log(LOGWARNING, "DirectFB/linux_input: could not get LED bits" );
1144   else
1145     m_hasLeds = test_bit( LED_SCROLLL, ledbit ) || test_bit( LED_NUML, ledbit )
1146         || test_bit( LED_CAPSL, ledbit );
1147
1148   if (m_hasLeds)
1149   {
1150     /* get LED state */
1151     ret = ioctl(fd, EVIOCGLED(sizeof(m_ledState)), m_ledState);
1152     if (ret < 0)
1153     {
1154       CLog::Log(LOGERROR, "DirectFB/linux_input: could not get LED state");
1155       goto driver_open_device_error;
1156     }
1157
1158     /* turn off LEDs */
1159     SetLed(LED_SCROLLL, 0);
1160     SetLed(LED_NUML, 0);
1161     SetLed(LED_CAPSL, 0);
1162   }
1163
1164   return true;
1165
1166 driver_open_device_error:
1167
1168   ioctl(fd, EVIOCGRAB, 0);
1169   if (m_vt_fd >= 0)
1170   {
1171     close(m_vt_fd);
1172     m_vt_fd = -1;
1173   }
1174   close(fd);
1175   m_fd = -1;
1176
1177   return false;
1178 }
1179
1180 /*
1181  * Fetch one entry from the kernel keymap.
1182  */
1183 bool CLinuxInputDevice::GetKeymapEntry(KeymapEntry& entry)
1184 {
1185   int code = entry.code;
1186   unsigned short value;
1187   //DFBInputDeviceKeyIdentifier identifier;
1188
1189   if (m_vt_fd < 0)
1190     return false;
1191
1192   // to support '+'  and '/' with Boxee's remote control we do something ugly like this for now
1193   if (KVAL(code) == 98)
1194   {
1195     code = K(KTYP(code),53);
1196   }
1197
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);
1201
1202   /* write base level symbol to entry */
1203   entry.base = value; //KeyboardGetSymbol(code, value, LI_KEYLEVEL_BASE);
1204
1205   /* fetch the shifted base level */
1206   value = KeyboardGetSymbol(KeyboardReadValue(K_SHIFTTAB, entry.code));
1207   //printf("shift=%d\n", value);
1208
1209   /* write shifted base level symbol to entry */
1210   entry.shift = value; //KeyboardGetSymbol(code, value, LI_KEYLEVEL_SHIFT);
1211
1212   // to support '+'  and '/' with Boxee's remote control we could do ugly something like this for now
1213   if (KVAL(code) == 78)
1214   {
1215     //code = K(KTYP(code),13);
1216     //entry.code = K(KTYP(code),13);
1217     entry.base = K(KTYP(code),43);
1218   }
1219
1220   /* fetch the alternative level */
1221   value = KeyboardGetSymbol(KeyboardReadValue(K_ALTTAB, entry.code));
1222   //printf("alt=%d\n", value);
1223
1224   /* write alternative level symbol to entry */
1225   entry.alt = value; //KeyboardGetSymbol(code, value, LI_KEYLEVEL_ALT);
1226
1227   /* fetch the shifted alternative level */
1228   value = KeyboardGetSymbol(KeyboardReadValue(K_ALTSHIFTTAB, entry.code));
1229   //printf("altshift=%d\n", value);
1230
1231   /* write shifted alternative level symbol to entry */
1232   entry.altShift = value; //KeyboardGetSymbol(code, value, LI_KEYLEVEL_ALT_SHIFT);
1233
1234   return true;
1235 }
1236
1237 /*
1238  * End thread, close device and free private data.
1239  */
1240 void CLinuxInputDevice::Close()
1241 {
1242   /* release device */
1243   ioctl(m_fd, EVIOCGRAB, 0);
1244
1245   if (m_vt_fd >= 0)
1246     close(m_vt_fd);
1247
1248   /* close file */
1249   close(m_fd);
1250 }
1251
1252 XBMC_Event CLinuxInputDevices::ReadEvent()
1253 {
1254   if (m_bReInitialize)
1255   {
1256     InitAvailable();
1257     m_bReInitialize = false;
1258   }
1259   else
1260   {
1261     time_t now;
1262     time(&now);
1263
1264     if ((now - m_lastHotplugCheck) >= 10)
1265     {
1266       CheckHotplugged();
1267       m_lastHotplugCheck = now;
1268     }
1269   }
1270
1271   CSingleLock lock(m_devicesListLock);
1272
1273   XBMC_Event event;
1274   event.type = XBMC_NOEVENT;
1275
1276   for (size_t i = 0; i < m_devices.size(); i++)
1277   {
1278     event = m_devices[i]->ReadEvent();
1279     if (event.type != XBMC_NOEVENT)
1280     {
1281       break;
1282     }
1283
1284     if (m_devices[i]->IsUnplugged())
1285     {
1286       m_bReInitialize = true;
1287       break;
1288     }
1289   }
1290
1291   return event;
1292 }
1293
1294 /*
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
1299 */
1300 bool CLinuxInputDevices::IsRemoteLowBattery()
1301 {
1302   bool bLowBattery = !(remoteStatus & 0xF);
1303   return bLowBattery;
1304 }
1305
1306 bool CLinuxInputDevices::IsRemoteNotPaired()
1307 {
1308   bool bRemoteNotPaired = !(remoteStatus & 0x70) || !(remoteStatus & 0x80);
1309   return bRemoteNotPaired;
1310 }
1311
1312 /*
1313 int main()
1314 {
1315   CLinuxInputDevices devices;
1316   devices.InitAvailable();
1317   while (1)
1318   {
1319     XBMC_Event event = devices.ReadEvent();
1320     if (event.type != XBMC_NOEVENT)
1321     {
1322       printf("%d\n", event.type);
1323     }
1324     usleep(1000);
1325   }
1326
1327 }
1328 */
1329 #endif