]> git.vomp.tv Git - vompclient.git/blob - inputlinux.cc
Windows fixes
[vompclient.git] / inputlinux.cc
1 /*
2     Copyright 2004-2020 Chris Tallon; 2012 Marten Richter
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include <stdio.h>
21 #include <linux/input.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <sys/ioctl.h>
25 #include <fcntl.h>
26 #include <errno.h>
27
28 #include <cstdio>
29 #include <iostream>
30 #include <ostream>
31
32 #include "i18n.h"
33 #include "vdr.h"
34 #include "woptionpane.h"
35
36 #include "inputlinux.h"
37
38 #define test_bit(input,b)  ((1 << ((b) % 8))&(input)[b / 8] )
39
40 bool InputLinux::init()
41 {
42   if (initted) return false;
43   initted = 1;
44
45   InitHWCListwithDefaults();
46   InitKeymap();
47
48   for (int eventid = 0; eventid < 100; eventid++)
49   {
50     char buffer[1024];
51     sprintf(buffer,"/dev/input/event%d", eventid);
52
53     struct stat test_buf;
54     if (stat(buffer, &test_buf) == 0)
55     {
56       Log::getInstance()->log("InputLinux", Log::NOTICE, "Probe /dev/input/event%d", eventid);
57       // file exists
58       unsigned long ev_type = 0;
59       int new_fd = open(buffer, O_RDONLY);
60       if (new_fd < 0)
61       {
62         Log::getInstance()->log("InputLinux", Log::NOTICE, "Can not open /dev/input/event%d", eventid);
63         continue;
64       }
65
66       if (ioctl(new_fd, EVIOCGBIT(0, EV_MAX), &ev_type) < 0)
67       {
68         Log::getInstance()->log("InputLinux", Log::NOTICE, "Ioctl failed /dev/input/event%d %d", eventid, errno);
69         close(new_fd);
70       }
71
72       //Now test if it generates keyboard presses
73       if (test_bit(reinterpret_cast<char*>(&ev_type), EV_KEY))
74       {
75         Log::getInstance()->log("InputLinux", Log::NOTICE, "Add /dev/input/event%d to List", eventid);
76         devices.push_back(new_fd);
77
78         // Grab the device - make it exclusive to vomp. Fixes rubbish input going to console in background
79         ioctl(new_fd, EVIOCGRAB, 1);
80       }
81       else
82       {
83         close(new_fd);
84       }
85     }
86   }
87   return true;
88 }
89
90 void InputLinux::shutdown()
91 {
92   if (!initted) return;
93
94   while (devices.size())
95   {
96     int cur_fd = devices.back();
97     devices.pop_back();
98     ioctl(cur_fd, EVIOCGRAB, 0);
99     close(cur_fd);
100   }
101
102   initted = 0;
103 }
104
105 UCHAR InputLinux::TranslateHWCFixed(int code)
106 {
107   // Translate /dev/input codes to VOMP codes for the hard coded buttons
108   switch (code)
109   {
110     case KEY_DOWN:      return DOWN;
111     case KEY_UP:        return UP;
112     case KEY_LEFT:      return LEFT;
113     case KEY_RIGHT:     return RIGHT;
114     case KEY_M:
115     case KEY_MEDIA:     return MENU;
116     case KEY_BACKSPACE:
117     case KEY_EXIT:      return BACK;
118     case KEY_ENTER:
119     case KEY_SPACE:
120     case KEY_OK:        return OK;
121     case KEY_SLEEP:
122     case KEY_POWER:
123     case KEY_ESC:       return POWER;
124     case POWER:         return POWER; // Where does this come from?
125     default:
126       return NA_UNKNOWN;
127   }
128 }
129
130 void InputLinux::InitHWCListwithDefaults()
131 {
132   Log::getInstance()->log("InputLinux", Log::INFO, "InitHWCListwithDefaults");
133
134   // Processing VK_Messages
135   translist[KEY_9] = NINE;
136   translist[KEY_8] = EIGHT;
137   translist[KEY_7] = SEVEN;
138   translist[KEY_6] = SIX;
139   translist[KEY_5] = FIVE;
140   translist[KEY_4] = FOUR;
141   translist[KEY_3] = THREE;
142   translist[KEY_2] = TWO;
143   translist[KEY_1] = ONE;
144   translist[KEY_0] = ZERO;
145   translist[KEY_KPDOT] = STAR;
146   // translist[KEY_#] = HASH;
147
148   translist[KEY_KP9] = NINE;
149   translist[KEY_KP8] = EIGHT;
150   translist[KEY_KP7] = SEVEN;
151   translist[KEY_KP6] = SIX;
152   translist[KEY_KP5] = FIVE;
153   translist[KEY_KP4] = FOUR;
154   translist[KEY_KP3] = THREE;
155   translist[KEY_KP2] = TWO;
156   translist[KEY_KP1] = ONE;
157   translist[KEY_KP0] = ZERO;
158
159   translist[KEY_NUMERIC_9] = NINE;
160   translist[KEY_NUMERIC_8] = EIGHT;
161   translist[KEY_NUMERIC_7] = SEVEN;
162   translist[KEY_NUMERIC_6] = SIX;
163   translist[KEY_NUMERIC_5] = FIVE;
164   translist[KEY_NUMERIC_4] = FOUR;
165   translist[KEY_NUMERIC_3] = THREE;
166   translist[KEY_NUMERIC_2] = TWO;
167   translist[KEY_NUMERIC_1] = ONE;
168   translist[KEY_NUMERIC_0] = ZERO;
169   translist[KEY_NUMERIC_STAR] = STAR;
170   translist[KEY_NUMERIC_POUND] = HASH;
171
172
173   translist[KEY_J] = GO; //j for JUMP TO instead of go to
174   translist[KEY_R] = RED;
175   translist[KEY_G] = GREEN;
176   translist[KEY_Y] = YELLOW;
177   translist[KEY_B] = BLUE;
178   //Processing Remote Style Messages
179   translist[KEY_GREEN] = GREEN;
180   translist[KEY_RED] = RED;
181   translist[KEY_YELLOW] = YELLOW;
182   translist[KEY_BLUE] = BLUE;
183   translist[KEY_MENU] = MENU;
184
185   translist[KEY_RECORD] = RECORD;
186   translist[KEY_PLAY] = PLAY; //Playback Televison
187   translist[KEY_PAUSE] = PAUSE;
188   translist[KEY_STOP] = STOP;
189   translist[KEY_PLAYPAUSE] = PLAYPAUSE;
190   translist[KEY_P] = PLAYPAUSE;
191   translist[KEY_NEXT] = SKIPFORWARD;
192   translist[KEY_F2] = SKIPFORWARD;
193   translist[KEY_PREVIOUS] = SKIPBACK;
194   translist[KEY_F1] = SKIPBACK;
195   translist[KEY_FORWARD] = FORWARD;
196   translist[KEY_FASTFORWARD] = FORWARD;
197   translist[KEY_F] = FORWARD;
198   translist[KEY_BACK] = REVERSE;
199   translist[KEY_REWIND] = REVERSE;
200   translist[KEY_T] = REVERSE;
201   translist[KEY_MUTE] = MUTE;
202   translist[KEY_F8] = MUTE;
203   translist[KEY_F10] = VOLUMEUP;
204   translist[KEY_F9] = VOLUMEDOWN;
205   translist[KEY_VOLUMEUP] = VOLUMEUP;
206   translist[KEY_VOLUMEDOWN] = VOLUMEDOWN;
207   translist[KEY_CHANNELUP] = CHANNELUP;
208   translist[KEY_CHANNELDOWN] = CHANNELDOWN;
209   translist[KEY_PAGEUP] = CHANNELUP;
210   translist[KEY_PAGEDOWN] = CHANNELDOWN;
211 }
212
213 #define NAMETRICK(pre, code) linux_keymap[pre ## code]=  #code
214 //extracte from linux/input.h
215
216 static const char * linux_keymap[KEY_MAX+1];
217
218 void InputLinux::InitKeymap()
219 {
220   for (int i=0;i<KEY_MAX+1;i++)
221   {
222     linux_keymap[i] = NULL;
223   }
224
225   NAMETRICK(KEY_,RESERVED);
226   NAMETRICK(KEY_,ESC);
227   NAMETRICK(KEY_,1);
228   NAMETRICK(KEY_,2);
229   NAMETRICK(KEY_,3);
230   NAMETRICK(KEY_,4);
231   NAMETRICK(KEY_,5);
232   NAMETRICK(KEY_,6);
233   NAMETRICK(KEY_,7);
234   NAMETRICK(KEY_,8);
235   NAMETRICK(KEY_,9);
236   NAMETRICK(KEY_,0);
237   NAMETRICK(KEY_,MINUS);
238   NAMETRICK(KEY_,EQUAL);
239   NAMETRICK(KEY_,BACKSPACE);
240   NAMETRICK(KEY_,TAB);
241   NAMETRICK(KEY_,Q);
242   NAMETRICK(KEY_,W);
243   NAMETRICK(KEY_,E);
244   NAMETRICK(KEY_,R);
245   NAMETRICK(KEY_,T);
246   NAMETRICK(KEY_,Y);
247   NAMETRICK(KEY_,U);
248   NAMETRICK(KEY_,I);
249   NAMETRICK(KEY_,O);
250   NAMETRICK(KEY_,P);
251   NAMETRICK(KEY_,LEFTBRACE);
252   NAMETRICK(KEY_,RIGHTBRACE);
253   NAMETRICK(KEY_,ENTER);
254   NAMETRICK(KEY_,LEFTCTRL);
255   NAMETRICK(KEY_,A);
256   NAMETRICK(KEY_,S);
257   NAMETRICK(KEY_,D);
258   NAMETRICK(KEY_,F);
259   NAMETRICK(KEY_,G);
260   NAMETRICK(KEY_,H);
261   NAMETRICK(KEY_,J);
262   NAMETRICK(KEY_,K);
263   NAMETRICK(KEY_,L);
264   NAMETRICK(KEY_,SEMICOLON);
265   NAMETRICK(KEY_,APOSTROPHE);
266   NAMETRICK(KEY_,GRAVE);
267   NAMETRICK(KEY_,LEFTSHIFT);
268   NAMETRICK(KEY_,BACKSLASH);
269   NAMETRICK(KEY_,Z);
270   NAMETRICK(KEY_,X);
271   NAMETRICK(KEY_,C);
272   NAMETRICK(KEY_,V);
273   NAMETRICK(KEY_,B);
274   NAMETRICK(KEY_,N);
275   NAMETRICK(KEY_,M);
276   NAMETRICK(KEY_,COMMA);
277   NAMETRICK(KEY_,DOT);
278   NAMETRICK(KEY_,SLASH);
279   NAMETRICK(KEY_,RIGHTSHIFT);
280   NAMETRICK(KEY_,KPASTERISK);
281   NAMETRICK(KEY_,LEFTALT);
282   NAMETRICK(KEY_,SPACE);
283   NAMETRICK(KEY_,CAPSLOCK);
284   NAMETRICK(KEY_,F1);
285   NAMETRICK(KEY_,F2);
286   NAMETRICK(KEY_,F3);
287   NAMETRICK(KEY_,F4);
288   NAMETRICK(KEY_,F5);
289   NAMETRICK(KEY_,F6);
290   NAMETRICK(KEY_,F7);
291   NAMETRICK(KEY_,F8);
292   NAMETRICK(KEY_,F9);
293   NAMETRICK(KEY_,F10);
294   NAMETRICK(KEY_,NUMLOCK);
295   NAMETRICK(KEY_,SCROLLLOCK);
296   NAMETRICK(KEY_,KP7);
297   NAMETRICK(KEY_,KP8);
298   NAMETRICK(KEY_,KP9);
299   NAMETRICK(KEY_,KPMINUS);
300   NAMETRICK(KEY_,KP4);
301   NAMETRICK(KEY_,KP5);
302   NAMETRICK(KEY_,KP6);
303   NAMETRICK(KEY_,KPPLUS);
304   NAMETRICK(KEY_,KP1);
305   NAMETRICK(KEY_,KP2);
306   NAMETRICK(KEY_,KP3);
307   NAMETRICK(KEY_,KP0);
308   NAMETRICK(KEY_,KPDOT);
309   NAMETRICK(KEY_,F11);
310   NAMETRICK(KEY_,F12);
311   NAMETRICK(KEY_,KPENTER);
312   NAMETRICK(KEY_,RIGHTCTRL);
313   NAMETRICK(KEY_,KPSLASH);
314   NAMETRICK(KEY_,SYSRQ);
315   NAMETRICK(KEY_,RIGHTALT);
316   NAMETRICK(KEY_,LINEFEED);
317   NAMETRICK(KEY_,HOME);
318   NAMETRICK(KEY_,UP);
319   NAMETRICK(KEY_,PAGEUP);
320   NAMETRICK(KEY_,LEFT);
321   NAMETRICK(KEY_,RIGHT);
322   NAMETRICK(KEY_,END);
323   NAMETRICK(KEY_,DOWN);
324   NAMETRICK(KEY_,PAGEDOWN);
325   NAMETRICK(KEY_,INSERT);
326   NAMETRICK(KEY_,DELETE);
327   NAMETRICK(KEY_,MACRO);
328   NAMETRICK(KEY_,MUTE);
329   NAMETRICK(KEY_,VOLUMEDOWN);
330   NAMETRICK(KEY_,VOLUMEUP);
331   NAMETRICK(KEY_,POWER);
332   NAMETRICK(KEY_,KPEQUAL);
333   NAMETRICK(KEY_,KPPLUSMINUS);
334   NAMETRICK(KEY_,PLAY);
335   NAMETRICK(KEY_,PAUSE);
336   NAMETRICK(KEY_,SCALE);
337   NAMETRICK(KEY_,KPCOMMA);
338   NAMETRICK(KEY_,YEN);
339   NAMETRICK(KEY_,LEFTMETA);
340   NAMETRICK(KEY_,RIGHTMETA);
341   NAMETRICK(KEY_,COMPOSE);
342   NAMETRICK(KEY_,STOP);
343   NAMETRICK(KEY_,AGAIN);
344   NAMETRICK(KEY_,PROPS);
345   NAMETRICK(KEY_,UNDO);
346   NAMETRICK(KEY_,FRONT);
347   NAMETRICK(KEY_,COPY);
348   NAMETRICK(KEY_,OPEN);
349   NAMETRICK(KEY_,PASTE);
350   NAMETRICK(KEY_,FIND);
351   NAMETRICK(KEY_,CUT);
352   NAMETRICK(KEY_,HELP);
353   NAMETRICK(KEY_,MENU);
354   NAMETRICK(KEY_,CALC);
355   NAMETRICK(KEY_,SETUP);
356   NAMETRICK(KEY_,SLEEP);
357   NAMETRICK(KEY_,WAKEUP);
358   NAMETRICK(KEY_,FILE);
359   NAMETRICK(KEY_,SENDFILE);
360   NAMETRICK(KEY_,DELETEFILE);
361   NAMETRICK(KEY_,XFER);
362   NAMETRICK(KEY_,PROG1);
363   NAMETRICK(KEY_,PROG2);
364   NAMETRICK(KEY_,WWW);
365   NAMETRICK(KEY_,MSDOS);
366   NAMETRICK(KEY_,COFFEE);
367   NAMETRICK(KEY_,DIRECTION);
368   NAMETRICK(KEY_,CYCLEWINDOWS);
369   NAMETRICK(KEY_,MAIL);
370   NAMETRICK(KEY_,BOOKMARKS);
371   NAMETRICK(KEY_,COMPUTER);
372   NAMETRICK(KEY_,BACK);
373   NAMETRICK(KEY_,FORWARD);
374   NAMETRICK(KEY_,FASTFORWARD);
375   NAMETRICK(KEY_,CLOSECD);
376   NAMETRICK(KEY_,EJECTCD);
377   NAMETRICK(KEY_,EJECTCLOSECD);
378   NAMETRICK(KEY_,NEXTSONG);
379   NAMETRICK(KEY_,PLAYPAUSE);
380   NAMETRICK(KEY_,PREVIOUSSONG);
381   NAMETRICK(KEY_,STOPCD);
382   NAMETRICK(KEY_,RECORD);
383   NAMETRICK(KEY_,REWIND);
384   NAMETRICK(KEY_,PHONE);
385   NAMETRICK(KEY_,ISO);
386   NAMETRICK(KEY_,CONFIG);
387   NAMETRICK(KEY_,HOMEPAGE);
388   NAMETRICK(KEY_,REFRESH);
389   NAMETRICK(KEY_,EXIT);
390   NAMETRICK(KEY_,MOVE);
391   NAMETRICK(KEY_,EDIT);
392   NAMETRICK(KEY_,SCROLLUP);
393   NAMETRICK(KEY_,SCROLLDOWN);
394   NAMETRICK(KEY_,KPLEFTPAREN);
395   NAMETRICK(KEY_,KPRIGHTPAREN);
396   NAMETRICK(KEY_,NEW);
397   NAMETRICK(KEY_,REDO);
398   NAMETRICK(KEY_,OK);
399   NAMETRICK(KEY_,SELECT);
400   NAMETRICK(KEY_,GOTO);
401   NAMETRICK(KEY_,CLEAR);
402   NAMETRICK(KEY_,POWER2);
403   NAMETRICK(KEY_,OPTION);
404   NAMETRICK(KEY_,INFO);
405   NAMETRICK(KEY_,TIME);
406   NAMETRICK(KEY_,VENDOR);
407   NAMETRICK(KEY_,ARCHIVE);
408   NAMETRICK(KEY_,PROGRAM);
409   NAMETRICK(KEY_,CHANNEL);
410   NAMETRICK(KEY_,FAVORITES);
411   NAMETRICK(KEY_,EPG);
412   NAMETRICK(KEY_,PVR);
413   NAMETRICK(KEY_,MHP);
414   NAMETRICK(KEY_,LANGUAGE);
415   NAMETRICK(KEY_,TITLE);
416   NAMETRICK(KEY_,SUBTITLE);
417   NAMETRICK(KEY_,ANGLE);
418   NAMETRICK(KEY_,ZOOM);
419   NAMETRICK(KEY_,MODE);
420   NAMETRICK(KEY_,KEYBOARD);
421   NAMETRICK(KEY_,SCREEN);
422   NAMETRICK(KEY_,RED);
423   NAMETRICK(KEY_,GREEN);
424   NAMETRICK(KEY_,YELLOW);
425   NAMETRICK(KEY_,BLUE);
426   NAMETRICK(KEY_,CHANNELUP);
427   NAMETRICK(KEY_,CHANNELDOWN);
428   NAMETRICK(KEY_,FIRST);
429   NAMETRICK(KEY_,LAST);
430   NAMETRICK(KEY_,AB);
431   NAMETRICK(KEY_,NEXT);
432   NAMETRICK(KEY_,RESTART);
433   NAMETRICK(KEY_,SLOW);
434   NAMETRICK(KEY_,SHUFFLE);
435   NAMETRICK(KEY_,BREAK);
436   NAMETRICK(KEY_,PREVIOUS);
437   NAMETRICK(KEY_,DIGITS);
438   NAMETRICK(KEY_,TEEN);
439   NAMETRICK(KEY_,TWEN);
440   NAMETRICK(KEY_,VIDEOPHONE);
441   NAMETRICK(KEY_,GAMES);
442   NAMETRICK(KEY_,ZOOMIN);
443   NAMETRICK(KEY_,ZOOMOUT);
444   NAMETRICK(KEY_,ZOOMRESET);
445   NAMETRICK(KEY_,DOLLAR);
446   NAMETRICK(KEY_,EURO);
447   NAMETRICK(KEY_,MEDIA);
448   NAMETRICK(KEY_,FRAMEBACK);
449   NAMETRICK(KEY_,FRAMEFORWARD);
450   NAMETRICK(KEY_,CONTEXT_MENU);
451   NAMETRICK(KEY_,MEDIA_REPEAT);
452   NAMETRICK(KEY_,NUMERIC_0);
453   NAMETRICK(KEY_,NUMERIC_1);
454   NAMETRICK(KEY_,NUMERIC_2);
455   NAMETRICK(KEY_,NUMERIC_3);
456   NAMETRICK(KEY_,NUMERIC_4);
457   NAMETRICK(KEY_,NUMERIC_5);
458   NAMETRICK(KEY_,NUMERIC_6);
459   NAMETRICK(KEY_,NUMERIC_7);
460   NAMETRICK(KEY_,NUMERIC_8);
461   NAMETRICK(KEY_,NUMERIC_9);
462   NAMETRICK(KEY_,NUMERIC_STAR);
463   NAMETRICK(KEY_,NUMERIC_POUND);
464 }
465
466 const char* InputLinux::getHardCodedHardwareKeyNamesForVompKey(UCHAR vompKey)
467 {
468   switch (vompKey)
469   {
470   case DOWN:
471     return tr("Down");
472   case UP:
473     return tr("Up");
474   case LEFT:
475     return tr("Left");
476   case RIGHT:
477     return tr("Right");
478   case MENU:
479     return tr("M");
480   case BACK:
481     return tr("Backspace, Back");
482   case OK:
483     return tr("Return, Space");
484   default:
485     return "";
486   }
487 }
488
489 std::string InputLinux::getHardwareKeyName(int hardwareKey)
490 {
491   const char* desc = linux_keymap[hardwareKey];
492
493   std::string retval;
494
495   if (desc)
496   {
497     retval = desc;
498   }
499   else
500   {
501     char* rt = new char[10];
502     sprintf(rt, "0x%x", hardwareKey);
503     retval = rt;
504   }
505
506   return retval;
507 }
508
509 void InputLinux::EnterLearningMode(UCHAR vompKey)
510 {
511   learnMode = vompKey; // Armed
512 }
513
514 bool InputLinux::start()
515 {
516   Log::getInstance()->log("Input", Log::INFO, "start called");
517
518   threadStartProtect.lock(); // Make sure listenThread is fully initted before start returns
519   listenThread = std::thread( [this]
520   {
521     threadStartProtect.lock();
522     threadStartProtect.unlock();
523     listenLoop();
524   });
525   threadStartProtect.unlock();
526   return true;
527 }
528
529 void InputLinux::stop()
530 {
531   threadStartProtect.lock(); // Also use it to protect against starting while stopping
532
533   if (listenThread.joinable())
534   {
535     listenLoopStop = true;
536     write(pfds[1], "1", 1); // break the select in listenLoop
537     listenThread.join();
538   }
539
540   threadStartProtect.unlock();
541 }
542
543 void InputLinux::listenLoop()
544 {
545   fd_set readfds;
546   int maxfd;
547
548   if (pipe2(pfds, O_NONBLOCK) == -1)
549   {
550     Log::getInstance()->log("InputLinux", Log::ERR, "pipe2() fail");
551     return;
552   }
553
554   Log::getInstance()->log("InputLinux", Log::INFO, "Listen loop");
555
556   while(1)
557   {
558     if (listenLoopStop) break;
559
560     FD_ZERO(&readfds);
561
562     maxfd = 0;
563     for (unsigned int i = 0; i < devices.size(); i++)
564     {
565       int cur_fd = devices[i];
566       maxfd = max(cur_fd, maxfd);
567       FD_SET(cur_fd, &readfds);
568     }
569
570     FD_SET(pfds[0], &readfds);
571     maxfd = max(pfds[0], maxfd);
572
573     // 0 = nothing happened and timeout expired
574     // >0 = num of descriptors that changed
575     // -1 = error
576     if (select(maxfd + 1, &readfds, NULL, NULL, NULL) < 1)
577     {
578       Log::getInstance()->log("InputLinux", Log::ERR, "Select fail");
579       break;
580     }
581
582     if (FD_ISSET(pfds[0], &readfds))
583     {
584       // assume quit signal
585       Log::getInstance()->log("InputLinux", Log::NOTICE, "pfds quit");
586       break;
587
588       // FUTURE: read the byte and do different things? Read listenLoopStop and maybe other bools?
589     }
590
591     for (unsigned int i = 0; i < devices.size(); i++)
592     {
593       int cur_fd = devices[i];
594       if (FD_ISSET(cur_fd, &readfds))
595       {
596         struct input_event ev;
597         int count = read(cur_fd, &ev, sizeof(ev));
598         if (count == sizeof(ev))
599         {
600           if (ev.type == EV_KEY && ev.value == 1)
601           {
602             sendInputKey(TranslateHWC(ev.code));
603           }
604         }
605       }
606     }
607   }
608
609   close(pfds[1]);
610   close(pfds[0]);
611 }
612
613 // FIXME surely NA_SIGNAL can go