]> git.vomp.tv Git - vompclient.git/blob - remotelinux.cc
20 compiler warning fixes
[vompclient.git] / remotelinux.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 <linux/input.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <sys/ioctl.h>
24 #include <fcntl.h>
25 #include <errno.h>
26
27 #include <cstdio>
28 #include <iostream>
29 #include <ostream>
30
31 #include <bcm_host.h>
32
33 #include <libcec/cec.h>
34 #include <libcec/cecloader.h>
35 using namespace CEC;
36
37 #include "i18n.h"
38 #include "vdr.h"
39 #include "woptionpane.h"
40 #include "message.h"
41 #include "messagequeue.h"
42 #include "command.h" // FIXME - get rid after predefined message targets
43
44 #include "remotelinux.h"
45
46 #define W_G_HCW(type,code) ((static_cast<ULLONG>(type) << 32) | code)
47
48 #define W_HCW_KC 1 /* key code as defined by kernel for keyboard and remotes through /dev/input */
49 #define W_HCW_CEC 2 /* HDMI_CEC */
50 #define W_HCW_LIRC 3 /* remote control LIRC*/
51
52
53 RemoteLinux::RemoteLinux()
54 {
55 }
56
57 RemoteLinux::~RemoteLinux()
58 {
59   for (unsigned int i = 0; i < devices.size(); i++)
60   {
61     close(devices[i]);
62   }
63 }
64
65 #define test_bit(input,b)  ((1 << ((b) % 8))&(input)[b / 8] )
66
67 int RemoteLinux::init(const char*)
68 {
69   if (initted) return 0;
70   initted = 1;
71
72   InitKeymap();
73
74   for (int eventid = 0; eventid < 100; eventid++)
75   {
76     char buffer[1024];
77     sprintf(buffer,"/dev/input/event%d", eventid);
78
79     struct stat test_buf;
80     if (stat(buffer, &test_buf) == 0)
81     {
82       Log::getInstance()->log("Remote", Log::NOTICE, "Probe /dev/input/event%d", eventid);
83       // file exists
84       unsigned long ev_type = 0;
85       int new_fd = open(buffer, O_RDONLY);
86       if (new_fd < 0)
87       {
88         Log::getInstance()->log("Remote", Log::NOTICE, "Can not open /dev/input/event%d", eventid);
89         continue;
90       }
91
92       if (ioctl(new_fd, EVIOCGBIT(0, EV_MAX), &ev_type) < 0)
93       {
94         Log::getInstance()->log("Remote", Log::NOTICE, "Ioctl failed /dev/input/event%d %d", eventid, errno);
95         close(new_fd);
96       }
97
98       //Now test if it generates keyboard presses
99       if (test_bit(reinterpret_cast<char*>(&ev_type), EV_KEY))
100       {
101         Log::getInstance()->log("Remote", Log::NOTICE, "Add /dev/input/event%d to List", eventid);
102         devices.push_back(new_fd);
103
104         // Grab the device - make it exclusive to vomp. Fixes rubbish input going to console in background
105         ioctl(new_fd, EVIOCGRAB, 1);
106       }
107       else
108       {
109         close(new_fd);
110       }
111     }
112   }
113   return initCec();
114 }
115
116 int RemoteLinux::initCec() {
117
118   // bcm_host_init(); //may be move to custom hardware init?
119 // now init cec
120         Log::getInstance()->log("Remote", Log::NOTICE, "Init LibCEC");
121         cec_config.Clear();
122         cec_callbacks.Clear();
123 #if CEC_LIB_VERSION_MAJOR >= 4
124         cec_callbacks.logMessage = cecLogMessage;
125         cec_callbacks.keyPress = cecKeyPress;
126         cec_callbacks.commandReceived = cecCommand;
127         cec_callbacks.configurationChanged = cecConfigurationChanged;
128         cec_callbacks.sourceActivated = cecSourceActivated;
129 #else
130         cec_callbacks.CBCecLogMessage = cecLogMessage;
131         cec_callbacks.CBCecKeyPress = cecKeyPress;
132         cec_callbacks.CBCecCommand = cecCommand;
133         cec_callbacks.CBCecConfigurationChanged = cecConfigurationChanged;
134         cec_callbacks.CBCecSourceActivated = cecSourceActivated;
135         cec_config.bUseTVMenuLanguage=1;
136 #endif
137     cec_config.clientVersion=LIBCEC_VERSION_CURRENT;
138         cec_config.bActivateSource=1;
139         //cec_config.deviceTypes.Add(CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
140         cec_config.deviceTypes.Add(CEC_DEVICE_TYPE_RECORDING_DEVICE);
141         //cec_config.deviceTypes.Add(CEC_DEVICE_TYPE_TUNER);
142
143         strncpy(cec_config.strDeviceName,"vomp",sizeof(cec_config.strDeviceName));
144
145
146         cec_config.callbackParam = NULL; // I do not care
147         cec_config.callbacks = &cec_callbacks;
148
149         cec_adap = LibCecInitialise(&cec_config);
150         if (!cec_adap) {
151                 Log::getInstance()->log("Remote", Log::ERR, "Init LibCEC failed");
152                 return 1;
153         }
154         cec_adap->InitVideoStandalone();
155
156
157 #if CEC_LIB_VERSION_MAJOR >= 4
158         cec_adapter_descriptor cec_adapter_descriptors[10];
159         int adap_num=cec_adap->DetectAdapters(cec_adapter_descriptors, 10);
160 #else
161         cec_adapter  cec_devices[10];
162         int adap_num=cec_adap->FindAdapters(cec_devices,10,NULL);
163 #endif
164         if (adap_num<0) {
165                 Log::getInstance()->log("Remote", Log::ERR, "CEC:Failed to find adapter");
166                 return 1;
167
168         }
169         if (adap_num==0) {
170                 Log::getInstance()->log("Remote", Log::NOTICE, "CEC: No adapter found");
171                 return 1;
172
173         }
174 #if CEC_LIB_VERSION_MAJOR >= 4
175         if (!cec_adap->Open(cec_adapter_descriptors[0].strComName)) {
176 #else
177         if (!cec_adap->Open(cec_devices[0].comm)) {
178 #endif
179       Log::getInstance()->log("Remote", Log::ERR, "CEC:Failed to open adapter");
180                 return 1;
181         }
182
183         if (!cec_adap->SetActiveSource(cec_config.deviceTypes[0])) {
184                 Log::getInstance()->log("Remote", Log::ERR, "CEC:Failed set active source");
185                 return 1;
186         }
187
188
189
190
191   return 1;
192 }
193
194 int RemoteLinux::shutdown()
195 {
196   if (!initted) return 0;
197
198   deinitCec();
199   while (devices.size())
200   {
201     int cur_fd = devices.back();
202     devices.pop_back();
203     ioctl(cur_fd, EVIOCGRAB, 0);
204     close(cur_fd);
205   }
206
207   initted = 0;
208   return 1;
209 }
210
211 void RemoteLinux::deinitCec()
212 {
213         if (cec_adap) {
214                 Log::getInstance()->log("Remote", Log::NOTICE, "Shutdown libcec begin");
215                 cec_adap->SetInactiveView();
216                 cec_adap->Close();
217                 vc_cec_register_callback(NULL, NULL);//deactivate callback!
218                 UnloadLibCec(cec_adap);
219                 cec_adap = NULL;
220                 Log::getInstance()->log("Remote", Log::NOTICE, "Shutdown libcec end");
221         }
222
223 }
224 /*
225 UCHAR RemoteLinux::getButtonPress(int waitType) {
226         / * how = 0 - block
227          how = 1 - start new wait
228          how = 2 - continue wait
229          how = 3 - no wait
230          * /
231
232          //in units of 40 ms
233                 Log::getInstance()->log("Remote", Log::NOTICE, "get button press");
234
235         int retval;
236         fd_set readfds;
237         struct timeval tv;
238
239         tv.tv_sec = 0;
240         tv.tv_usec = 40000;
241         if (waitType == 0) {
242                 num_loop = -1;
243         } else if (waitType == 1) {
244
245                 num_loop = 25;
246         } else if (waitType == 2) {
247                 if (num_loop<=0) num_loop = 25;
248         } else if (waitType == 3) {
249                 tv.tv_sec = 0;
250                 tv.tv_usec = 0;
251                 num_loop = 0;
252         }
253
254
255         int ret = 0;
256         while (num_loop!=0) {
257                 ret = NA_UNKNOWN;
258                 FD_ZERO(&readfds);
259
260                 int maxfd = 0;
261                 for (unsigned int i = 0; i < devices.size(); i++) {
262                         int cur_fd = devices[i];
263                         maxfd = max(cur_fd, maxfd);
264                         FD_SET(cur_fd, &readfds);
265                 }
266
267         FD_SET(pfds[0], &readfds);
268         maxfd = max(pfds[0], maxfd);
269
270                 retval = select(maxfd + 1, &readfds, NULL, NULL, &tv);
271                 tv.tv_sec = 0;
272                 tv.tv_usec = 40000;
273                 // 0 = nothing happened
274                 // 1 = data arrived (actually num of descriptors that changed)
275                 // other value = signal or error
276                 if (retval == 0) {
277                         if (hascurcec) {
278                                 hascurcec = false;
279                                 return (UCHAR) TranslateHWC(W_G_HCW(W_HCW_CEC,curcec));
280                         }
281                         if (haspower) {
282                                 haspower =false;
283                                 return powerkey;
284                         }
285                         ret = NA_NONE;
286                 } else {
287                         if (retval == -1) {
288                                 Log::getInstance()->log("Remote", Log::NOTICE, "na_signal");
289                                 return NA_SIGNAL;
290                         }
291
292                         if (FD_ISSET(pfds[0], &readfds))
293             {
294               // quit signal
295               Log::getInstance()->log("Remote", Log::NOTICE, "pfds quit");
296               return NA_SIGNAL; // use NA_SIGNAL for now
297             }
298
299                         for (unsigned int i = 0; i < devices.size(); i++) {
300                                 int cur_fd = devices[i];
301                                 if (FD_ISSET(cur_fd, &readfds)) {
302                                         struct input_event ev;
303                                         int count = read(cur_fd, &ev, sizeof(ev));
304                                         if (count == sizeof(ev)) {
305                                                 if (ev.type == EV_KEY && ev.value == 1) {
306                                                         UCHAR retty=(UCHAR) TranslateHWC(
307                                                                                         W_G_HCW(W_HCW_KC,ev.code));
308                                                         return retty;
309                                                 }
310                                         }
311
312                                 }
313
314                         }
315
316                 }
317                 //Log::getInstance()->log("Remote", Log::NOTICE, "numloop: %d %d",num_loop,retval);
318                 if (num_loop > 0)
319                 num_loop--;
320         }
321         if (ret != 0)
322                 return ret;
323
324         return NA_UNKNOWN;
325
326 }
327 */
328
329 UCHAR RemoteLinux::TranslateHWCFixed(ULLONG code)
330 {
331     switch (code) 
332     {
333     case W_G_HCW(W_HCW_KC, KEY_DOWN):
334         return DOWN;
335     case W_G_HCW(W_HCW_KC, KEY_UP):
336         return UP;
337     case W_G_HCW(W_HCW_KC, KEY_LEFT):
338         return LEFT;
339     case W_G_HCW(W_HCW_KC, KEY_RIGHT):
340         return RIGHT;
341     case W_G_HCW(W_HCW_KC, KEY_M):
342     case W_G_HCW(W_HCW_KC, KEY_MEDIA):
343         return MENU;
344     case W_G_HCW(W_HCW_KC, KEY_BACKSPACE):
345     case W_G_HCW(W_HCW_KC, KEY_EXIT):
346         return BACK;
347     case W_G_HCW(W_HCW_KC, KEY_ENTER):
348     case W_G_HCW(W_HCW_KC, KEY_SPACE):
349     case W_G_HCW(W_HCW_KC, KEY_OK):
350         return OK;
351
352     //CEC
353     case W_G_HCW(W_HCW_CEC, CEC_USER_CONTROL_CODE_DOWN):
354         return DOWN;
355     case W_G_HCW(W_HCW_CEC, CEC_USER_CONTROL_CODE_UP):
356         return UP;
357     case W_G_HCW(W_HCW_CEC, CEC_USER_CONTROL_CODE_LEFT):
358         return LEFT;
359     case W_G_HCW(W_HCW_CEC, CEC_USER_CONTROL_CODE_RIGHT):
360         return RIGHT;
361     case W_G_HCW(W_HCW_CEC, CEC_USER_CONTROL_CODE_ROOT_MENU):
362     case W_G_HCW(W_HCW_CEC, CEC_USER_CONTROL_CODE_CONTENTS_MENU):
363     case W_G_HCW(W_HCW_CEC, CEC_USER_CONTROL_CODE_SETUP_MENU):
364         return MENU;
365     case W_G_HCW(W_HCW_CEC, CEC_USER_CONTROL_CODE_EXIT ):
366         return BACK;
367     case W_G_HCW(W_HCW_CEC, CEC_USER_CONTROL_CODE_ENTER):
368     case W_G_HCW(W_HCW_CEC, CEC_USER_CONTROL_CODE_SELECT):
369     case W_G_HCW(W_HCW_CEC, CEC_USER_CONTROL_CODE_AN_RETURN):
370         return OK;
371     case W_G_HCW(W_HCW_KC, KEY_SLEEP):
372     case W_G_HCW(W_HCW_KC, KEY_POWER):
373     case W_G_HCW(W_HCW_KC, KEY_ESC):
374     case W_G_HCW(W_HCW_CEC, CEC_USER_CONTROL_CODE_POWER):
375     case POWER:
376         return POWER;
377     default:
378         return NA_UNKNOWN;
379     };
380 }
381
382 const char*RemoteLinux::HardcodedTranslateStr(UCHAR command)
383 {
384   switch (command)
385   {
386     case DOWN:
387       return tr("Down");
388     case UP:
389       return tr("Up");
390     case LEFT:
391       return tr("Left");
392     case RIGHT:
393       return tr("Right");
394     case MENU:
395       return tr("M");
396     case BACK:
397       return tr("Backspace, Back");
398     case OK:
399       return tr("Return, Space");
400     default:
401       return NULL;
402   }
403 }
404
405
406 void RemoteLinux::InitHWCListwithDefaults()
407 {
408   // Processing VK_Messages
409   translist[W_G_HCW(W_HCW_KC,KEY_9)] = NINE;
410   translist[W_G_HCW(W_HCW_KC,KEY_8)] = EIGHT;
411   translist[W_G_HCW(W_HCW_KC,KEY_7)] = SEVEN;
412   translist[W_G_HCW(W_HCW_KC,KEY_6)] = SIX;
413   translist[W_G_HCW(W_HCW_KC,KEY_5)] = FIVE;
414   translist[W_G_HCW(W_HCW_KC,KEY_4)] = FOUR;
415   translist[W_G_HCW(W_HCW_KC,KEY_3)] = THREE;
416   translist[W_G_HCW(W_HCW_KC,KEY_2)] = TWO;
417   translist[W_G_HCW(W_HCW_KC,KEY_1)] = ONE;
418   translist[W_G_HCW(W_HCW_KC,KEY_0)] = ZERO;
419   translist[W_G_HCW(W_HCW_KC,KEY_KPDOT)] = STAR;
420   // translist[W_G_HCW(W_HCW_KC,KEY_#)] = HASH;
421
422   translist[W_G_HCW(W_HCW_KC,KEY_KP9)] = NINE;
423   translist[W_G_HCW(W_HCW_KC,KEY_KP8)] = EIGHT;
424   translist[W_G_HCW(W_HCW_KC,KEY_KP7)] = SEVEN;
425   translist[W_G_HCW(W_HCW_KC,KEY_KP6)] = SIX;
426   translist[W_G_HCW(W_HCW_KC,KEY_KP5)] = FIVE;
427   translist[W_G_HCW(W_HCW_KC,KEY_KP4)] = FOUR;
428   translist[W_G_HCW(W_HCW_KC,KEY_KP3)] = THREE;
429   translist[W_G_HCW(W_HCW_KC,KEY_KP2)] = TWO;
430   translist[W_G_HCW(W_HCW_KC,KEY_KP1)] = ONE;
431   translist[W_G_HCW(W_HCW_KC,KEY_KP0)] = ZERO;
432
433   translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_9)] = NINE;
434   translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_8)] = EIGHT;
435   translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_7)] = SEVEN;
436   translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_6)] = SIX;
437   translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_5)] = FIVE;
438   translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_4)] = FOUR;
439   translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_3)] = THREE;
440   translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_2)] = TWO;
441   translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_1)] = ONE;
442   translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_0)] = ZERO;
443   translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_STAR)] = STAR;
444   translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_POUND)] = HASH;
445
446
447   translist[W_G_HCW(W_HCW_KC,KEY_J)] = GO; //j for JUMP TO instead of go to
448   translist[W_G_HCW(W_HCW_KC,KEY_R)] = RED;
449   translist[W_G_HCW(W_HCW_KC,KEY_G)] = GREEN;
450   translist[W_G_HCW(W_HCW_KC,KEY_Y)] = YELLOW;
451   translist[W_G_HCW(W_HCW_KC,KEY_B)] = BLUE;
452   //Processing Remote Style Messages
453   translist[W_G_HCW(W_HCW_KC,KEY_GREEN)] = GREEN;
454   translist[W_G_HCW(W_HCW_KC,KEY_RED)] = RED;
455   translist[W_G_HCW(W_HCW_KC,KEY_YELLOW)] = YELLOW;
456   translist[W_G_HCW(W_HCW_KC,KEY_BLUE)] = BLUE;
457   translist[W_G_HCW(W_HCW_KC,KEY_MENU)] = MENU;
458
459   translist[W_G_HCW(W_HCW_KC,KEY_RECORD)] = RECORD;
460   translist[W_G_HCW(W_HCW_KC,KEY_PLAY)] = PLAY; //Playback Televison
461   translist[W_G_HCW(W_HCW_KC,KEY_PAUSE)] = PAUSE;
462   translist[W_G_HCW(W_HCW_KC,KEY_STOP)] = STOP;
463   translist[W_G_HCW(W_HCW_KC,KEY_PLAYPAUSE)] = PLAYPAUSE;
464   translist[W_G_HCW(W_HCW_KC,KEY_P)] = PLAYPAUSE;
465   translist[W_G_HCW(W_HCW_KC,KEY_NEXT)] = SKIPFORWARD;
466   translist[W_G_HCW(W_HCW_KC,KEY_F2)] = SKIPFORWARD;
467   translist[W_G_HCW(W_HCW_KC,KEY_PREVIOUS)] = SKIPBACK;
468   translist[W_G_HCW(W_HCW_KC,KEY_F1)] = SKIPBACK;
469   translist[W_G_HCW(W_HCW_KC,KEY_FORWARD)] = FORWARD;
470   translist[W_G_HCW(W_HCW_KC,KEY_FASTFORWARD)] = FORWARD;
471   translist[W_G_HCW(W_HCW_KC,KEY_F)] = FORWARD;
472   translist[W_G_HCW(W_HCW_KC,KEY_BACK)] = REVERSE;
473   translist[W_G_HCW(W_HCW_KC,KEY_REWIND)] = REVERSE;
474   translist[W_G_HCW(W_HCW_KC,KEY_T)] = REVERSE;
475   translist[W_G_HCW(W_HCW_KC,KEY_MUTE)] = MUTE;
476   translist[W_G_HCW(W_HCW_KC,KEY_F8)] = MUTE;
477   translist[W_G_HCW(W_HCW_KC,KEY_F10)] = VOLUMEUP;
478   translist[W_G_HCW(W_HCW_KC,KEY_F9)] = VOLUMEDOWN;
479   translist[W_G_HCW(W_HCW_KC,KEY_VOLUMEUP)] = VOLUMEUP;
480   translist[W_G_HCW(W_HCW_KC,KEY_VOLUMEDOWN)] = VOLUMEDOWN;
481   translist[W_G_HCW(W_HCW_KC,KEY_CHANNELUP)] = CHANNELUP;
482   translist[W_G_HCW(W_HCW_KC,KEY_CHANNELDOWN)] = CHANNELDOWN;
483   translist[W_G_HCW(W_HCW_KC,KEY_PAGEUP)] = CHANNELUP;
484   translist[W_G_HCW(W_HCW_KC,KEY_PAGEDOWN)] = CHANNELDOWN;
485
486
487   //Processing CEC_Messages
488   translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_NUMBER9)] = NINE;
489   translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_NUMBER8)] = EIGHT;
490   translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_NUMBER7)] = SEVEN;
491   translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_NUMBER6)] = SIX;
492   translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_NUMBER5)] = FIVE;
493   translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_NUMBER4)] = FOUR;
494   translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_NUMBER3)] = THREE;
495   translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_NUMBER2)] = TWO;
496   translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_NUMBER1)] = ONE;
497   translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_NUMBER0)] = ZERO;
498   //translist[W_G_HCW(W_HCW_CEC,KEY_KPDOT)] = STAR;
499
500
501
502   //translist[W_G_HCW(W_HCW_CEC,KEY_J)] = GO; //j for JUMP TO instead of go to
503   translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_F2_RED)] = RED;
504   translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_F3_GREEN)] = GREEN;
505   translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_F4_YELLOW)] = YELLOW;
506   translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_F1_BLUE)] = BLUE;
507   //Processing Remote Style Messages
508   translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_FAVORITE_MENU)] = MENU;
509
510   translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_RECORD)] = RECORD;
511   translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_PLAY)] = PLAY; //Playback Televison
512   translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_PAUSE)] = PAUSE;
513   translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_STOP)] = STOP;
514   translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_PAUSE_PLAY_FUNCTION)] = PLAYPAUSE;
515   translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_FORWARD)] = SKIPFORWARD;
516   translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_BACKWARD)] = SKIPBACK;
517   translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_FAST_FORWARD )] = FORWARD;
518   translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_REWIND)] = REVERSE;
519   translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_MUTE)] = MUTE;
520   translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_VOLUME_UP)] = VOLUMEUP;
521   translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_VOLUME_DOWN)] = VOLUMEDOWN;
522   translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_CHANNEL_UP )] = CHANNELUP;
523   translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_CHANNEL_DOWN)] = CHANNELDOWN;
524 }
525
526 #define NAMETRICK(pre, code) linux_keymap[pre ## code]=  #code
527 #define NAMETRICK2(pre, code) cec_keymap[pre ## code]=  #code
528 //extracte from linux/input.h
529
530 static const char * linux_keymap[KEY_MAX+1];
531 static const char * cec_keymap[CEC_USER_CONTROL_CODE_MAX+1];
532
533 void RemoteLinux::InitKeymap()
534 {
535   for (int i=0;i<KEY_MAX+1;i++)
536   {
537     linux_keymap[i] = NULL;
538   }
539
540   NAMETRICK(KEY_,RESERVED);
541   NAMETRICK(KEY_,ESC);
542   NAMETRICK(KEY_,1);
543   NAMETRICK(KEY_,2);
544   NAMETRICK(KEY_,3);
545   NAMETRICK(KEY_,4);
546   NAMETRICK(KEY_,5);
547   NAMETRICK(KEY_,6);
548   NAMETRICK(KEY_,7);
549   NAMETRICK(KEY_,8);
550   NAMETRICK(KEY_,9);
551   NAMETRICK(KEY_,0);
552   NAMETRICK(KEY_,MINUS);
553   NAMETRICK(KEY_,EQUAL);
554   NAMETRICK(KEY_,BACKSPACE);
555   NAMETRICK(KEY_,TAB);
556   NAMETRICK(KEY_,Q);
557   NAMETRICK(KEY_,W);
558   NAMETRICK(KEY_,E);
559   NAMETRICK(KEY_,R);
560   NAMETRICK(KEY_,T);
561   NAMETRICK(KEY_,Y);
562   NAMETRICK(KEY_,U);
563   NAMETRICK(KEY_,I);
564   NAMETRICK(KEY_,O);
565   NAMETRICK(KEY_,P);
566   NAMETRICK(KEY_,LEFTBRACE);
567   NAMETRICK(KEY_,RIGHTBRACE);
568   NAMETRICK(KEY_,ENTER);
569   NAMETRICK(KEY_,LEFTCTRL);
570   NAMETRICK(KEY_,A);
571   NAMETRICK(KEY_,S);
572   NAMETRICK(KEY_,D);
573   NAMETRICK(KEY_,F);
574   NAMETRICK(KEY_,G);
575   NAMETRICK(KEY_,H);
576   NAMETRICK(KEY_,J);
577   NAMETRICK(KEY_,K);
578   NAMETRICK(KEY_,L);
579   NAMETRICK(KEY_,SEMICOLON);
580   NAMETRICK(KEY_,APOSTROPHE);
581   NAMETRICK(KEY_,GRAVE);
582   NAMETRICK(KEY_,LEFTSHIFT);
583   NAMETRICK(KEY_,BACKSLASH);
584   NAMETRICK(KEY_,Z);
585   NAMETRICK(KEY_,X);
586   NAMETRICK(KEY_,C);
587   NAMETRICK(KEY_,V);
588   NAMETRICK(KEY_,B);
589   NAMETRICK(KEY_,N);
590   NAMETRICK(KEY_,M);
591   NAMETRICK(KEY_,COMMA);
592   NAMETRICK(KEY_,DOT);
593   NAMETRICK(KEY_,SLASH);
594   NAMETRICK(KEY_,RIGHTSHIFT);
595   NAMETRICK(KEY_,KPASTERISK);
596   NAMETRICK(KEY_,LEFTALT);
597   NAMETRICK(KEY_,SPACE);
598   NAMETRICK(KEY_,CAPSLOCK);
599   NAMETRICK(KEY_,F1);
600   NAMETRICK(KEY_,F2);
601   NAMETRICK(KEY_,F3);
602   NAMETRICK(KEY_,F4);
603   NAMETRICK(KEY_,F5);
604   NAMETRICK(KEY_,F6);
605   NAMETRICK(KEY_,F7);
606   NAMETRICK(KEY_,F8);
607   NAMETRICK(KEY_,F9);
608   NAMETRICK(KEY_,F10);
609   NAMETRICK(KEY_,NUMLOCK);
610   NAMETRICK(KEY_,SCROLLLOCK);
611   NAMETRICK(KEY_,KP7);
612   NAMETRICK(KEY_,KP8);
613   NAMETRICK(KEY_,KP9);
614   NAMETRICK(KEY_,KPMINUS);
615   NAMETRICK(KEY_,KP4);
616   NAMETRICK(KEY_,KP5);
617   NAMETRICK(KEY_,KP6);
618   NAMETRICK(KEY_,KPPLUS);
619   NAMETRICK(KEY_,KP1);
620   NAMETRICK(KEY_,KP2);
621   NAMETRICK(KEY_,KP3);
622   NAMETRICK(KEY_,KP0);
623   NAMETRICK(KEY_,KPDOT);
624   NAMETRICK(KEY_,F11);
625   NAMETRICK(KEY_,F12);
626   NAMETRICK(KEY_,KPENTER);
627   NAMETRICK(KEY_,RIGHTCTRL);
628   NAMETRICK(KEY_,KPSLASH);
629   NAMETRICK(KEY_,SYSRQ);
630   NAMETRICK(KEY_,RIGHTALT);
631   NAMETRICK(KEY_,LINEFEED);
632   NAMETRICK(KEY_,HOME);
633   NAMETRICK(KEY_,UP);
634   NAMETRICK(KEY_,PAGEUP);
635   NAMETRICK(KEY_,LEFT);
636   NAMETRICK(KEY_,RIGHT);
637   NAMETRICK(KEY_,END);
638   NAMETRICK(KEY_,DOWN);
639   NAMETRICK(KEY_,PAGEDOWN);
640   NAMETRICK(KEY_,INSERT);
641   NAMETRICK(KEY_,DELETE);
642   NAMETRICK(KEY_,MACRO);
643   NAMETRICK(KEY_,MUTE);
644   NAMETRICK(KEY_,VOLUMEDOWN);
645   NAMETRICK(KEY_,VOLUMEUP);
646   NAMETRICK(KEY_,POWER);
647   NAMETRICK(KEY_,KPEQUAL);
648   NAMETRICK(KEY_,KPPLUSMINUS);
649   NAMETRICK(KEY_,PLAY);
650   NAMETRICK(KEY_,PAUSE);
651   NAMETRICK(KEY_,SCALE);
652   NAMETRICK(KEY_,KPCOMMA);
653   NAMETRICK(KEY_,YEN);
654   NAMETRICK(KEY_,LEFTMETA);
655   NAMETRICK(KEY_,RIGHTMETA);
656   NAMETRICK(KEY_,COMPOSE);
657   NAMETRICK(KEY_,STOP);
658   NAMETRICK(KEY_,AGAIN);
659   NAMETRICK(KEY_,PROPS);
660   NAMETRICK(KEY_,UNDO);
661   NAMETRICK(KEY_,FRONT);
662   NAMETRICK(KEY_,COPY);
663   NAMETRICK(KEY_,OPEN);
664   NAMETRICK(KEY_,PASTE);
665   NAMETRICK(KEY_,FIND);
666   NAMETRICK(KEY_,CUT);
667   NAMETRICK(KEY_,HELP);
668   NAMETRICK(KEY_,MENU);
669   NAMETRICK(KEY_,CALC);
670   NAMETRICK(KEY_,SETUP);
671   NAMETRICK(KEY_,SLEEP);
672   NAMETRICK(KEY_,WAKEUP);
673   NAMETRICK(KEY_,FILE);
674   NAMETRICK(KEY_,SENDFILE);
675   NAMETRICK(KEY_,DELETEFILE);
676   NAMETRICK(KEY_,XFER);
677   NAMETRICK(KEY_,PROG1);
678   NAMETRICK(KEY_,PROG2);
679   NAMETRICK(KEY_,WWW);
680   NAMETRICK(KEY_,MSDOS);
681   NAMETRICK(KEY_,COFFEE);
682   NAMETRICK(KEY_,DIRECTION);
683   NAMETRICK(KEY_,CYCLEWINDOWS);
684   NAMETRICK(KEY_,MAIL);
685   NAMETRICK(KEY_,BOOKMARKS);
686   NAMETRICK(KEY_,COMPUTER);
687   NAMETRICK(KEY_,BACK);
688   NAMETRICK(KEY_,FORWARD);
689   NAMETRICK(KEY_,FASTFORWARD);
690   NAMETRICK(KEY_,CLOSECD);
691   NAMETRICK(KEY_,EJECTCD);
692   NAMETRICK(KEY_,EJECTCLOSECD);
693   NAMETRICK(KEY_,NEXTSONG);
694   NAMETRICK(KEY_,PLAYPAUSE);
695   NAMETRICK(KEY_,PREVIOUSSONG);
696   NAMETRICK(KEY_,STOPCD);
697   NAMETRICK(KEY_,RECORD);
698   NAMETRICK(KEY_,REWIND);
699   NAMETRICK(KEY_,PHONE);
700   NAMETRICK(KEY_,ISO);
701   NAMETRICK(KEY_,CONFIG);
702   NAMETRICK(KEY_,HOMEPAGE);
703   NAMETRICK(KEY_,REFRESH);
704   NAMETRICK(KEY_,EXIT);
705   NAMETRICK(KEY_,MOVE);
706   NAMETRICK(KEY_,EDIT);
707   NAMETRICK(KEY_,SCROLLUP);
708   NAMETRICK(KEY_,SCROLLDOWN);
709   NAMETRICK(KEY_,KPLEFTPAREN);
710   NAMETRICK(KEY_,KPRIGHTPAREN);
711   NAMETRICK(KEY_,NEW);
712   NAMETRICK(KEY_,REDO);
713   NAMETRICK(KEY_,OK);
714   NAMETRICK(KEY_,SELECT);
715   NAMETRICK(KEY_,GOTO);
716   NAMETRICK(KEY_,CLEAR);
717   NAMETRICK(KEY_,POWER2);
718   NAMETRICK(KEY_,OPTION);
719   NAMETRICK(KEY_,INFO);
720   NAMETRICK(KEY_,TIME);
721   NAMETRICK(KEY_,VENDOR);
722   NAMETRICK(KEY_,ARCHIVE);
723   NAMETRICK(KEY_,PROGRAM);
724   NAMETRICK(KEY_,CHANNEL);
725   NAMETRICK(KEY_,FAVORITES);
726   NAMETRICK(KEY_,EPG);
727   NAMETRICK(KEY_,PVR);
728   NAMETRICK(KEY_,MHP);
729   NAMETRICK(KEY_,LANGUAGE);
730   NAMETRICK(KEY_,TITLE);
731   NAMETRICK(KEY_,SUBTITLE);
732   NAMETRICK(KEY_,ANGLE);
733   NAMETRICK(KEY_,ZOOM);
734   NAMETRICK(KEY_,MODE);
735   NAMETRICK(KEY_,KEYBOARD);
736   NAMETRICK(KEY_,SCREEN);
737   NAMETRICK(KEY_,RED);
738   NAMETRICK(KEY_,GREEN);
739   NAMETRICK(KEY_,YELLOW);
740   NAMETRICK(KEY_,BLUE);
741   NAMETRICK(KEY_,CHANNELUP);
742   NAMETRICK(KEY_,CHANNELDOWN);
743   NAMETRICK(KEY_,FIRST);
744   NAMETRICK(KEY_,LAST);
745   NAMETRICK(KEY_,AB);
746   NAMETRICK(KEY_,NEXT);
747   NAMETRICK(KEY_,RESTART);
748   NAMETRICK(KEY_,SLOW);
749   NAMETRICK(KEY_,SHUFFLE);
750   NAMETRICK(KEY_,BREAK);
751   NAMETRICK(KEY_,PREVIOUS);
752   NAMETRICK(KEY_,DIGITS);
753   NAMETRICK(KEY_,TEEN);
754   NAMETRICK(KEY_,TWEN);
755   NAMETRICK(KEY_,VIDEOPHONE);
756   NAMETRICK(KEY_,GAMES);
757   NAMETRICK(KEY_,ZOOMIN);
758   NAMETRICK(KEY_,ZOOMOUT);
759   NAMETRICK(KEY_,ZOOMRESET);
760   NAMETRICK(KEY_,DOLLAR);
761   NAMETRICK(KEY_,EURO);
762   NAMETRICK(KEY_,MEDIA);
763   NAMETRICK(KEY_,FRAMEBACK);
764   NAMETRICK(KEY_,FRAMEFORWARD);
765   NAMETRICK(KEY_,CONTEXT_MENU);
766   NAMETRICK(KEY_,MEDIA_REPEAT);
767   NAMETRICK(KEY_,NUMERIC_0);
768   NAMETRICK(KEY_,NUMERIC_1);
769   NAMETRICK(KEY_,NUMERIC_2);
770   NAMETRICK(KEY_,NUMERIC_3);
771   NAMETRICK(KEY_,NUMERIC_4);
772   NAMETRICK(KEY_,NUMERIC_5);
773   NAMETRICK(KEY_,NUMERIC_6);
774   NAMETRICK(KEY_,NUMERIC_7);
775   NAMETRICK(KEY_,NUMERIC_8);
776   NAMETRICK(KEY_,NUMERIC_9);
777   NAMETRICK(KEY_,NUMERIC_STAR);
778   NAMETRICK(KEY_,NUMERIC_POUND);
779
780   for (int i=0; i < CEC_USER_CONTROL_CODE_MAX + 1; i++)
781   {
782     cec_keymap[i] = NULL;
783   }
784
785   NAMETRICK2(CEC_USER_CONTROL_CODE_,SELECT);
786   NAMETRICK2(CEC_USER_CONTROL_CODE_,UP);
787   NAMETRICK2(CEC_USER_CONTROL_CODE_,DOWN);
788   NAMETRICK2(CEC_USER_CONTROL_CODE_,LEFT);
789   NAMETRICK2(CEC_USER_CONTROL_CODE_,RIGHT);
790   NAMETRICK2(CEC_USER_CONTROL_CODE_,RIGHT_UP);
791   NAMETRICK2(CEC_USER_CONTROL_CODE_,RIGHT_DOWN);
792   NAMETRICK2(CEC_USER_CONTROL_CODE_,LEFT_UP);
793   NAMETRICK2(CEC_USER_CONTROL_CODE_,LEFT_DOWN);
794   NAMETRICK2(CEC_USER_CONTROL_CODE_,ROOT_MENU);
795   NAMETRICK2(CEC_USER_CONTROL_CODE_,SETUP_MENU);
796   NAMETRICK2(CEC_USER_CONTROL_CODE_,CONTENTS_MENU);
797   NAMETRICK2(CEC_USER_CONTROL_CODE_,FAVORITE_MENU);
798   NAMETRICK2(CEC_USER_CONTROL_CODE_,EXIT);
799   NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER0);
800   NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER1);
801   NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER2);
802   NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER3);
803   NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER4);
804   NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER5);
805   NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER6);
806   NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER7);
807   NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER8);
808   NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER9);
809   NAMETRICK2(CEC_USER_CONTROL_CODE_,DOT);
810   NAMETRICK2(CEC_USER_CONTROL_CODE_,ENTER);
811   NAMETRICK2(CEC_USER_CONTROL_CODE_,CLEAR);
812   NAMETRICK2(CEC_USER_CONTROL_CODE_,NEXT_FAVORITE);
813   NAMETRICK2(CEC_USER_CONTROL_CODE_,CHANNEL_UP);
814   NAMETRICK2(CEC_USER_CONTROL_CODE_,CHANNEL_DOWN);
815   NAMETRICK2(CEC_USER_CONTROL_CODE_,PREVIOUS_CHANNEL);
816   NAMETRICK2(CEC_USER_CONTROL_CODE_,SOUND_SELECT);
817   NAMETRICK2(CEC_USER_CONTROL_CODE_,INPUT_SELECT);
818   NAMETRICK2(CEC_USER_CONTROL_CODE_,DISPLAY_INFORMATION);
819   NAMETRICK2(CEC_USER_CONTROL_CODE_,HELP);
820   NAMETRICK2(CEC_USER_CONTROL_CODE_,PAGE_UP);
821   NAMETRICK2(CEC_USER_CONTROL_CODE_,PAGE_DOWN);
822   NAMETRICK2(CEC_USER_CONTROL_CODE_,POWER );
823   NAMETRICK2(CEC_USER_CONTROL_CODE_,VOLUME_UP );
824   NAMETRICK2(CEC_USER_CONTROL_CODE_,VOLUME_DOWN );
825   NAMETRICK2(CEC_USER_CONTROL_CODE_,MUTE );
826   NAMETRICK2(CEC_USER_CONTROL_CODE_,PLAY );
827   NAMETRICK2(CEC_USER_CONTROL_CODE_,STOP );
828   NAMETRICK2(CEC_USER_CONTROL_CODE_,PAUSE );
829   NAMETRICK2(CEC_USER_CONTROL_CODE_,RECORD );
830   NAMETRICK2(CEC_USER_CONTROL_CODE_,REWIND );
831   NAMETRICK2(CEC_USER_CONTROL_CODE_,FAST_FORWARD );
832   NAMETRICK2(CEC_USER_CONTROL_CODE_,EJECT );
833   NAMETRICK2(CEC_USER_CONTROL_CODE_,FORWARD );
834   NAMETRICK2(CEC_USER_CONTROL_CODE_,BACKWARD );
835   NAMETRICK2(CEC_USER_CONTROL_CODE_,STOP_RECORD );
836   NAMETRICK2(CEC_USER_CONTROL_CODE_,PAUSE_RECORD );
837   NAMETRICK2(CEC_USER_CONTROL_CODE_,ANGLE );
838   NAMETRICK2(CEC_USER_CONTROL_CODE_,SUB_PICTURE );
839   NAMETRICK2(CEC_USER_CONTROL_CODE_,VIDEO_ON_DEMAND );
840   NAMETRICK2(CEC_USER_CONTROL_CODE_,ELECTRONIC_PROGRAM_GUIDE );
841   NAMETRICK2(CEC_USER_CONTROL_CODE_,TIMER_PROGRAMMING );
842   NAMETRICK2(CEC_USER_CONTROL_CODE_,INITIAL_CONFIGURATION );
843   NAMETRICK2(CEC_USER_CONTROL_CODE_,PLAY_FUNCTION );
844   NAMETRICK2(CEC_USER_CONTROL_CODE_,PAUSE_PLAY_FUNCTION );
845   NAMETRICK2(CEC_USER_CONTROL_CODE_,RECORD_FUNCTION );
846   NAMETRICK2(CEC_USER_CONTROL_CODE_,PAUSE_RECORD_FUNCTION );
847   NAMETRICK2(CEC_USER_CONTROL_CODE_,STOP_FUNCTION );
848   NAMETRICK2(CEC_USER_CONTROL_CODE_,MUTE_FUNCTION );
849   NAMETRICK2(CEC_USER_CONTROL_CODE_,RESTORE_VOLUME_FUNCTION );
850   NAMETRICK2(CEC_USER_CONTROL_CODE_,TUNE_FUNCTION );
851   NAMETRICK2(CEC_USER_CONTROL_CODE_,SELECT_MEDIA_FUNCTION );
852   NAMETRICK2(CEC_USER_CONTROL_CODE_,SELECT_AV_INPUT_FUNCTION );
853   NAMETRICK2(CEC_USER_CONTROL_CODE_,SELECT_AUDIO_INPUT_FUNCTION );
854   NAMETRICK2(CEC_USER_CONTROL_CODE_,POWER_TOGGLE_FUNCTION );
855   NAMETRICK2(CEC_USER_CONTROL_CODE_,POWER_OFF_FUNCTION );
856   NAMETRICK2(CEC_USER_CONTROL_CODE_,POWER_ON_FUNCTION );
857   NAMETRICK2(CEC_USER_CONTROL_CODE_,F1_BLUE );
858   NAMETRICK2(CEC_USER_CONTROL_CODE_,F2_RED );
859   NAMETRICK2(CEC_USER_CONTROL_CODE_,F3_GREEN );
860   NAMETRICK2(CEC_USER_CONTROL_CODE_,F4_YELLOW );
861   NAMETRICK2(CEC_USER_CONTROL_CODE_,F5 );
862   NAMETRICK2(CEC_USER_CONTROL_CODE_,DATA );
863   NAMETRICK2(CEC_USER_CONTROL_CODE_,AN_RETURN );
864   NAMETRICK2(CEC_USER_CONTROL_CODE_,AN_CHANNELS_LIST );
865   NAMETRICK2(CEC_USER_CONTROL_CODE_,MAX );
866 }
867
868
869
870 char* RemoteLinux::HCWDesc(unsigned long long hcw)
871 {
872     //Determine type
873     unsigned int type = static_cast<unsigned int>(hcw >> 32);
874     unsigned int vk = static_cast<ULONG>(hcw);
875     char* rt = NULL;
876
877     switch(type)
878     {
879       case W_HCW_KC:
880       {
881         rt = new char[10];
882         const char *desc=linux_keymap[vk];
883         if (desc)
884           strncpy(rt, desc, 9);
885         else
886           sprintf(rt, "0x%x", vk);
887         break;
888       }
889       case W_HCW_CEC:
890       {
891         rt = new char[10];
892         const char* desc = cec_keymap[vk];
893         if (desc)
894           strncpy(rt, desc, 9);
895         else
896           sprintf(rt, "0x%x", vk);
897         break;
898       }
899   /*
900     case W_HCW_LIRC:{
901         ULONG ri=(ULONG)hcw;
902         rt=new char[10];
903         sprintf(rt,"R: %X",ri);
904                   }break;*/
905     }
906
907     return rt;
908 }
909
910 void RemoteLinux::changePowerState(bool poweron)
911 {
912   if (cec_adap)
913   {
914     if (poweron)
915     {
916       //Log::getInstance()->log("Remote", Log::DEBUG, "CEC set active source");
917       cec_adap->SetActiveSource(cec_config.deviceTypes[0]);
918     }
919     else
920     {
921       //Log::getInstance()->log("Remote", Log::DEBUG, "CEC set inactive view");
922       cec_adap->SetInactiveView();
923     }
924   }
925 }
926
927 #if CEC_LIB_VERSION_MAJOR >= 4
928
929 // libcec4 API changed these params to pointers rather than copies, and the returns to void
930 // Otherwise, these two blocks of code are the same
931
932 void RemoteLinux::cecLogMessage(void* /* param */, const cec_log_message* message)
933 {
934   Log::getInstance()->log("Remote", Log::DEBUG, "CECLOG: %lld %d %s", message->time, message->level, message->message);
935 }
936
937 void RemoteLinux::cecKeyPress(void* /* param */, const cec_keypress* key)
938 {
939   //Log::getInstance()->log("Remote", Log::DEBUG, "Incoming cec key %d %d", key->keycode,key->duration);
940   if (key->duration == 0) static_cast<RemoteLinux*>(Remote::getInstance())->incomingCECkey(key->keycode);
941 }
942
943 void RemoteLinux::cecCommand(void* /* param */, const cec_command* command)
944 {
945         Log::getInstance()->log("Remote", Log::DEBUG, "CECCommand: %d",command->opcode);
946         switch (command->opcode) {
947         case CEC_OPCODE_STANDBY: {
948                 if (command->initiator==CECDEVICE_TV) {
949                         static_cast<RemoteLinux*>(Remote::getInstance())->incomingPowerkey(POWEROFF);
950                 }
951         } break;
952         case CEC_OPCODE_DECK_CONTROL: {
953                 if (command->initiator==CECDEVICE_TV && command->parameters.size == 1
954                                 && command->parameters[0]==CEC_DECK_CONTROL_MODE_STOP) {
955                         static_cast<RemoteLinux*>(Remote::getInstance())->incomingCECkey(CEC_USER_CONTROL_CODE_STOP);
956
957                 }
958
959         } break;
960         case CEC_OPCODE_PLAY: {
961                 if (command->initiator==CECDEVICE_TV && command->parameters.size == 1) {
962                         if (command->parameters[0]==CEC_PLAY_MODE_PLAY_FORWARD) {
963                                 static_cast<RemoteLinux*>(Remote::getInstance())->incomingCECkey(CEC_USER_CONTROL_CODE_PLAY);
964                         } else if (command->parameters[0]==CEC_PLAY_MODE_PLAY_STILL) {
965                                 static_cast<RemoteLinux*>(Remote::getInstance())->incomingCECkey(CEC_USER_CONTROL_CODE_PAUSE);
966                         }
967                 }
968
969
970         } break;
971         default:
972                 break;
973         };
974 }
975
976 void RemoteLinux::cecConfigurationChanged(void* /* param */, const libcec_configuration*)
977 {
978         Log::getInstance()->log("Remote", Log::DEBUG, "CECConfig:"/*,config->string()*/);
979 }
980
981 #else
982
983 int RemoteLinux::cecLogMessage(void *param, const cec_log_message message)
984 {
985   Log::getInstance()->log("Remote", Log::DEBUG, "CECLOG: %lld %d %s", message.time, message.level, message.message);
986   return 0;
987 }
988
989 int RemoteLinux::cecKeyPress(void*param, const cec_keypress key)
990 {
991   //Log::getInstance()->log("Remote", Log::DEBUG, "Incoming cec key %d %d", key.keycode,key.duration);
992   if (key.duration == 0) ((RemoteLinux*)Remote::getInstance())->incomingCECkey(key.keycode);
993   return 1;
994 }
995
996 int RemoteLinux::cecCommand(void *param, const cec_command command)
997 {
998         Log::getInstance()->log("Remote", Log::DEBUG, "CECCommand: %d",command.opcode);
999         switch (command.opcode) {
1000         case CEC_OPCODE_STANDBY: {
1001                 if (command.initiator==CECDEVICE_TV) {
1002                         ((RemoteLinux*)Remote::getInstance())->incomingPowerkey(POWEROFF);
1003                 }
1004         } break;
1005         case CEC_OPCODE_DECK_CONTROL: {
1006                 if (command.initiator==CECDEVICE_TV && command.parameters.size == 1
1007                                 && command.parameters[0]==CEC_DECK_CONTROL_MODE_STOP) {
1008                         ((RemoteLinux*)Remote::getInstance())->incomingCECkey(CEC_USER_CONTROL_CODE_STOP);
1009
1010                 }
1011
1012         } break;
1013         case CEC_OPCODE_PLAY: {
1014                 if (command.initiator==CECDEVICE_TV && command.parameters.size == 1) {
1015                         if (command.parameters[0]==CEC_PLAY_MODE_PLAY_FORWARD) {
1016                                 ((RemoteLinux*)Remote::getInstance())->incomingCECkey(CEC_USER_CONTROL_CODE_PLAY);
1017                         } else if (command.parameters[0]==CEC_PLAY_MODE_PLAY_STILL) {
1018                                 ((RemoteLinux*)Remote::getInstance())->incomingCECkey(CEC_USER_CONTROL_CODE_PAUSE);
1019                         }
1020                 }
1021
1022
1023         } break;
1024         default:
1025                 break;
1026         };
1027         return 1;
1028 }
1029
1030 int RemoteLinux::cecConfigurationChanged(void *param, const libcec_configuration config)
1031 {
1032         Log::getInstance()->log("Remote", Log::DEBUG, "CECConfig:"/*,config.string()*/);
1033         return 1;
1034
1035 }
1036
1037 #endif
1038
1039 void  RemoteLinux::cecSourceActivated(void* /* param */, const cec_logical_address address, const uint8_t activated)
1040 {
1041   Log::getInstance()->log("Remote", Log::DEBUG, "CECSourceActivated: %d %d", address, activated);
1042   if (activated == 1)
1043   {
1044     static_cast<RemoteLinux*>(Remote::getInstance())->incomingPowerkey(POWERON);
1045   }
1046 }
1047
1048 void RemoteLinux::incomingCECkey(int keys)
1049 {
1050   // Send INPUT message
1051   Message* m = new Message();
1052   m->message = Message::INPUT_EVENT;
1053   m->to = Command::getInstance();
1054   m->from = this;
1055   m->parameter = static_cast<UCHAR>(TranslateHWC(W_G_HCW(W_HCW_CEC, keys)));
1056   MessageQueue::getInstance()->postMessage(m);
1057 }
1058
1059 void RemoteLinux::incomingPowerkey(UCHAR key)
1060 {
1061   // Send INPUT message
1062   Message* m = new Message();
1063   m->message = Message::INPUT_EVENT;
1064   m->to = Command::getInstance();
1065   m->from = this;
1066   m->parameter = key;
1067   MessageQueue::getInstance()->postMessage(m);
1068 }
1069
1070 bool RemoteLinux::loadOptionsfromServer(VDR* vdr)
1071 {
1072    // Set remote keys
1073   char* name;
1074   name = vdr->configLoad("RemoteLinux", "HandleVolume");
1075
1076   if (name != NULL)
1077   {
1078     if      (STRCASECMP(name, "Vomp") == 0) cechandlesvolume = false;
1079     else if (STRCASECMP(name, "Cec") == 0) cechandlesvolume = true;
1080     delete[] name;
1081   }
1082   return Remote::loadOptionsfromServer(vdr);
1083 }
1084
1085 bool RemoteLinux::saveOptionstoServer()
1086 {
1087   if (cechandlesvolume) VDR::getInstance()->configSave("RemoteLinux", "HandleVolume","Cec");
1088   else VDR::getInstance()->configSave("RemoteLinux", "HandleVolume","Vomp");
1089
1090   return Remote::saveOptionstoServer();
1091 }
1092
1093 bool RemoteLinux::addOptionsToPanes(int panenumber,Options *options,WOptionPane* pane)
1094 {
1095   if (!Remote::addOptionsToPanes(panenumber, options, pane)) return false;
1096
1097   Option* option;
1098   if (panenumber == 2)
1099   {
1100     static const char* volumeopts[]={"Vomp","Cec"};
1101     option = new Option(100,tr("Volume handled by"), "RemoteLinux","HandleVolume",Option::TYPE_TEXT,/*4,2*/2,0,0,volumeopts,NULL,false,this);
1102     options->push_back(option);
1103     pane->addOptionLine(option);
1104   }
1105
1106   return true;
1107 }
1108
1109 bool RemoteLinux::handleOptionChanges(Option* option)
1110 {
1111     if (Remote::handleOptionChanges(option))
1112                 return true;
1113         switch (option->id) {
1114         case 100: {
1115                 if (STRCASECMP(option->options[option->userSetChoice], "Vomp") == 0) {
1116                         cechandlesvolume=false;
1117                 }  else if (STRCASECMP(option->options[option->userSetChoice], "Cec")
1118                                 == 0) {
1119                         cechandlesvolume=true;
1120                 }
1121                 Log::getInstance()->log("Remote", Log::DEBUG, "Set volume handling to to %s %d",option->options[option->userSetChoice],cechandlesvolume);
1122                 return true;
1123         }
1124         break;
1125         };
1126         return false;
1127
1128 }
1129
1130 void RemoteLinux::volumeUp()
1131 {
1132   cec_adap->VolumeUp();
1133 }
1134
1135 void RemoteLinux::volumeDown()
1136 {
1137   cec_adap->VolumeDown();
1138 }
1139
1140 void RemoteLinux::volumeMute()
1141 {
1142 #if CEC_LIB_VERSION_MAJOR >= 4
1143   cec_adap->AudioToggleMute();
1144 #else
1145   cec_adap->MuteAudio();
1146 #endif
1147 }
1148
1149 void RemoteLinux::informStopEventLoop()
1150 {
1151   listenLoopStop = true;
1152   write(pfds[1], "1", 1); // break the select in getButtonPress
1153 }
1154
1155 void RemoteLinux::eventLoop()
1156 {
1157   fd_set readfds;
1158   int maxfd;
1159
1160   if (pipe2(pfds, O_NONBLOCK) == -1)
1161   {
1162     Log::getInstance()->log("RemoteLinux", Log::ERR, "pipe2() fail");
1163     return;
1164   }
1165
1166   Log::getInstance()->log("RemoteLinux", Log::INFO, "Listen loop");
1167
1168   while(1)
1169   {
1170     if (listenLoopStop) break;
1171
1172     FD_ZERO(&readfds);
1173
1174     maxfd = 0;
1175     for (unsigned int i = 0; i < devices.size(); i++)
1176     {
1177       int cur_fd = devices[i];
1178       maxfd = max(cur_fd, maxfd);
1179       FD_SET(cur_fd, &readfds);
1180     }
1181
1182     FD_SET(pfds[0], &readfds);
1183     maxfd = max(pfds[0], maxfd);
1184
1185     // 0 = nothing happened and timeout expired
1186     // >0 = num of descriptors that changed
1187     // -1 = error
1188     if (select(maxfd + 1, &readfds, NULL, NULL, NULL) < 1)
1189     {
1190       Log::getInstance()->log("RemoteLinux", Log::ERR, "Select fail");
1191       break;
1192     }
1193
1194     if (FD_ISSET(pfds[0], &readfds))
1195     {
1196       // assume quit signal
1197       Log::getInstance()->log("Remote", Log::NOTICE, "pfds quit");
1198       break;
1199
1200       // FUTURE: read the byte and do different things? Read listenLoopStop and maybe other bools?
1201     }
1202
1203     for (unsigned int i = 0; i < devices.size(); i++)
1204     {
1205       int cur_fd = devices[i];
1206       if (FD_ISSET(cur_fd, &readfds))
1207       {
1208         struct input_event ev;
1209         int count = read(cur_fd, &ev, sizeof(ev));
1210         if (count == sizeof(ev))
1211         {
1212           if (ev.type == EV_KEY && ev.value == 1)
1213           {
1214             // Send INPUT message
1215             Message* m = new Message();
1216             m->message = Message::INPUT_EVENT;
1217             m->to = Command::getInstance();
1218             m->from = this;
1219             m->parameter = static_cast<UCHAR>(TranslateHWC(W_G_HCW(W_HCW_KC,ev.code)));
1220             MessageQueue::getInstance()->postMessage(m);
1221           }
1222         }
1223       }
1224     }
1225   }
1226
1227   close(pfds[1]);
1228   close(pfds[0]);
1229 }
1230
1231 // FIXME surely NA_SIGNAL can go