2 Copyright 2004-2020 Chris Tallon; 2012 Marten Richter
4 This file is part of VOMP.
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.
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.
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/>.
20 #include <linux/input.h>
21 #include <sys/types.h>
23 #include <sys/ioctl.h>
33 #include <libcec/cec.h>
34 #include <libcec/cecloader.h>
39 #include "woptionpane.h"
41 #include "messagequeue.h"
42 #include "command.h" // FIXME - get rid after predefined message targets
44 #include "inputlinux.h"
46 #define W_G_HCW(type,code) ((static_cast<ULLONG>(type) << 32) | code)
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*/
53 InputLinux::InputLinux()
57 InputLinux::~InputLinux()
59 for (unsigned int i = 0; i < devices.size(); i++)
65 #define test_bit(input,b) ((1 << ((b) % 8))&(input)[b / 8] )
67 int InputLinux::init(const char*)
69 if (initted) return 0;
74 for (int eventid = 0; eventid < 100; eventid++)
77 sprintf(buffer,"/dev/input/event%d", eventid);
80 if (stat(buffer, &test_buf) == 0)
82 Log::getInstance()->log("InputLinux", Log::NOTICE, "Probe /dev/input/event%d", eventid);
84 unsigned long ev_type = 0;
85 int new_fd = open(buffer, O_RDONLY);
88 Log::getInstance()->log("InputLinux", Log::NOTICE, "Can not open /dev/input/event%d", eventid);
92 if (ioctl(new_fd, EVIOCGBIT(0, EV_MAX), &ev_type) < 0)
94 Log::getInstance()->log("InputLinux", Log::NOTICE, "Ioctl failed /dev/input/event%d %d", eventid, errno);
98 //Now test if it generates keyboard presses
99 if (test_bit(reinterpret_cast<char*>(&ev_type), EV_KEY))
101 Log::getInstance()->log("InputLinux", Log::NOTICE, "Add /dev/input/event%d to List", eventid);
102 devices.push_back(new_fd);
104 // Grab the device - make it exclusive to vomp. Fixes rubbish input going to console in background
105 ioctl(new_fd, EVIOCGRAB, 1);
116 int InputLinux::initCec() {
118 // bcm_host_init(); //may be move to custom hardware init?
120 Log::getInstance()->log("InputLinux", Log::NOTICE, "Init LibCEC");
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;
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;
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);
143 strncpy(cec_config.strDeviceName,"vomp",sizeof(cec_config.strDeviceName));
146 cec_config.callbackParam = NULL; // I do not care
147 cec_config.callbacks = &cec_callbacks;
149 cec_adap = LibCecInitialise(&cec_config);
151 Log::getInstance()->log("InputLinux", Log::ERR, "Init LibCEC failed");
154 cec_adap->InitVideoStandalone();
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);
161 cec_adapter cec_devices[10];
162 int adap_num=cec_adap->FindAdapters(cec_devices,10,NULL);
165 Log::getInstance()->log("InputLinux", Log::ERR, "CEC:Failed to find adapter");
170 Log::getInstance()->log("InputLinux", Log::NOTICE, "CEC: No adapter found");
174 #if CEC_LIB_VERSION_MAJOR >= 4
175 if (!cec_adap->Open(cec_adapter_descriptors[0].strComName)) {
177 if (!cec_adap->Open(cec_devices[0].comm)) {
179 Log::getInstance()->log("InputLinux", Log::ERR, "CEC:Failed to open adapter");
183 if (!cec_adap->SetActiveSource(cec_config.deviceTypes[0])) {
184 Log::getInstance()->log("InputLinux", Log::ERR, "CEC:Failed set active source");
194 int InputLinux::shutdown()
196 if (!initted) return 0;
199 while (devices.size())
201 int cur_fd = devices.back();
203 ioctl(cur_fd, EVIOCGRAB, 0);
211 void InputLinux::deinitCec()
214 Log::getInstance()->log("InputLinux", Log::NOTICE, "Shutdown libcec begin");
215 cec_adap->SetInactiveView();
217 vc_cec_register_callback(NULL, NULL);//deactivate callback!
218 UnloadLibCec(cec_adap);
220 Log::getInstance()->log("InputLinux", Log::NOTICE, "Shutdown libcec end");
225 UCHAR InputLinux::TranslateHWCFixed(ULLONG code)
229 case W_G_HCW(W_HCW_KC, KEY_DOWN):
231 case W_G_HCW(W_HCW_KC, KEY_UP):
233 case W_G_HCW(W_HCW_KC, KEY_LEFT):
235 case W_G_HCW(W_HCW_KC, KEY_RIGHT):
237 case W_G_HCW(W_HCW_KC, KEY_M):
238 case W_G_HCW(W_HCW_KC, KEY_MEDIA):
240 case W_G_HCW(W_HCW_KC, KEY_BACKSPACE):
241 case W_G_HCW(W_HCW_KC, KEY_EXIT):
243 case W_G_HCW(W_HCW_KC, KEY_ENTER):
244 case W_G_HCW(W_HCW_KC, KEY_SPACE):
245 case W_G_HCW(W_HCW_KC, KEY_OK):
249 case W_G_HCW(W_HCW_CEC, CEC_USER_CONTROL_CODE_DOWN):
251 case W_G_HCW(W_HCW_CEC, CEC_USER_CONTROL_CODE_UP):
253 case W_G_HCW(W_HCW_CEC, CEC_USER_CONTROL_CODE_LEFT):
255 case W_G_HCW(W_HCW_CEC, CEC_USER_CONTROL_CODE_RIGHT):
257 case W_G_HCW(W_HCW_CEC, CEC_USER_CONTROL_CODE_ROOT_MENU):
258 case W_G_HCW(W_HCW_CEC, CEC_USER_CONTROL_CODE_CONTENTS_MENU):
259 case W_G_HCW(W_HCW_CEC, CEC_USER_CONTROL_CODE_SETUP_MENU):
261 case W_G_HCW(W_HCW_CEC, CEC_USER_CONTROL_CODE_EXIT ):
263 case W_G_HCW(W_HCW_CEC, CEC_USER_CONTROL_CODE_ENTER):
264 case W_G_HCW(W_HCW_CEC, CEC_USER_CONTROL_CODE_SELECT):
265 case W_G_HCW(W_HCW_CEC, CEC_USER_CONTROL_CODE_AN_RETURN):
267 case W_G_HCW(W_HCW_KC, KEY_SLEEP):
268 case W_G_HCW(W_HCW_KC, KEY_POWER):
269 case W_G_HCW(W_HCW_KC, KEY_ESC):
270 case W_G_HCW(W_HCW_CEC, CEC_USER_CONTROL_CODE_POWER):
278 const char* InputLinux::HardcodedTranslateStr(UCHAR command)
293 return tr("Backspace, Back");
295 return tr("Return, Space");
302 void InputLinux::InitHWCListwithDefaults()
304 // Processing VK_Messages
305 translist[W_G_HCW(W_HCW_KC,KEY_9)] = NINE;
306 translist[W_G_HCW(W_HCW_KC,KEY_8)] = EIGHT;
307 translist[W_G_HCW(W_HCW_KC,KEY_7)] = SEVEN;
308 translist[W_G_HCW(W_HCW_KC,KEY_6)] = SIX;
309 translist[W_G_HCW(W_HCW_KC,KEY_5)] = FIVE;
310 translist[W_G_HCW(W_HCW_KC,KEY_4)] = FOUR;
311 translist[W_G_HCW(W_HCW_KC,KEY_3)] = THREE;
312 translist[W_G_HCW(W_HCW_KC,KEY_2)] = TWO;
313 translist[W_G_HCW(W_HCW_KC,KEY_1)] = ONE;
314 translist[W_G_HCW(W_HCW_KC,KEY_0)] = ZERO;
315 translist[W_G_HCW(W_HCW_KC,KEY_KPDOT)] = STAR;
316 // translist[W_G_HCW(W_HCW_KC,KEY_#)] = HASH;
318 translist[W_G_HCW(W_HCW_KC,KEY_KP9)] = NINE;
319 translist[W_G_HCW(W_HCW_KC,KEY_KP8)] = EIGHT;
320 translist[W_G_HCW(W_HCW_KC,KEY_KP7)] = SEVEN;
321 translist[W_G_HCW(W_HCW_KC,KEY_KP6)] = SIX;
322 translist[W_G_HCW(W_HCW_KC,KEY_KP5)] = FIVE;
323 translist[W_G_HCW(W_HCW_KC,KEY_KP4)] = FOUR;
324 translist[W_G_HCW(W_HCW_KC,KEY_KP3)] = THREE;
325 translist[W_G_HCW(W_HCW_KC,KEY_KP2)] = TWO;
326 translist[W_G_HCW(W_HCW_KC,KEY_KP1)] = ONE;
327 translist[W_G_HCW(W_HCW_KC,KEY_KP0)] = ZERO;
329 translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_9)] = NINE;
330 translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_8)] = EIGHT;
331 translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_7)] = SEVEN;
332 translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_6)] = SIX;
333 translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_5)] = FIVE;
334 translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_4)] = FOUR;
335 translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_3)] = THREE;
336 translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_2)] = TWO;
337 translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_1)] = ONE;
338 translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_0)] = ZERO;
339 translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_STAR)] = STAR;
340 translist[W_G_HCW(W_HCW_KC,KEY_NUMERIC_POUND)] = HASH;
343 translist[W_G_HCW(W_HCW_KC,KEY_J)] = GO; //j for JUMP TO instead of go to
344 translist[W_G_HCW(W_HCW_KC,KEY_R)] = RED;
345 translist[W_G_HCW(W_HCW_KC,KEY_G)] = GREEN;
346 translist[W_G_HCW(W_HCW_KC,KEY_Y)] = YELLOW;
347 translist[W_G_HCW(W_HCW_KC,KEY_B)] = BLUE;
348 //Processing Remote Style Messages
349 translist[W_G_HCW(W_HCW_KC,KEY_GREEN)] = GREEN;
350 translist[W_G_HCW(W_HCW_KC,KEY_RED)] = RED;
351 translist[W_G_HCW(W_HCW_KC,KEY_YELLOW)] = YELLOW;
352 translist[W_G_HCW(W_HCW_KC,KEY_BLUE)] = BLUE;
353 translist[W_G_HCW(W_HCW_KC,KEY_MENU)] = MENU;
355 translist[W_G_HCW(W_HCW_KC,KEY_RECORD)] = RECORD;
356 translist[W_G_HCW(W_HCW_KC,KEY_PLAY)] = PLAY; //Playback Televison
357 translist[W_G_HCW(W_HCW_KC,KEY_PAUSE)] = PAUSE;
358 translist[W_G_HCW(W_HCW_KC,KEY_STOP)] = STOP;
359 translist[W_G_HCW(W_HCW_KC,KEY_PLAYPAUSE)] = PLAYPAUSE;
360 translist[W_G_HCW(W_HCW_KC,KEY_P)] = PLAYPAUSE;
361 translist[W_G_HCW(W_HCW_KC,KEY_NEXT)] = SKIPFORWARD;
362 translist[W_G_HCW(W_HCW_KC,KEY_F2)] = SKIPFORWARD;
363 translist[W_G_HCW(W_HCW_KC,KEY_PREVIOUS)] = SKIPBACK;
364 translist[W_G_HCW(W_HCW_KC,KEY_F1)] = SKIPBACK;
365 translist[W_G_HCW(W_HCW_KC,KEY_FORWARD)] = FORWARD;
366 translist[W_G_HCW(W_HCW_KC,KEY_FASTFORWARD)] = FORWARD;
367 translist[W_G_HCW(W_HCW_KC,KEY_F)] = FORWARD;
368 translist[W_G_HCW(W_HCW_KC,KEY_BACK)] = REVERSE;
369 translist[W_G_HCW(W_HCW_KC,KEY_REWIND)] = REVERSE;
370 translist[W_G_HCW(W_HCW_KC,KEY_T)] = REVERSE;
371 translist[W_G_HCW(W_HCW_KC,KEY_MUTE)] = MUTE;
372 translist[W_G_HCW(W_HCW_KC,KEY_F8)] = MUTE;
373 translist[W_G_HCW(W_HCW_KC,KEY_F10)] = VOLUMEUP;
374 translist[W_G_HCW(W_HCW_KC,KEY_F9)] = VOLUMEDOWN;
375 translist[W_G_HCW(W_HCW_KC,KEY_VOLUMEUP)] = VOLUMEUP;
376 translist[W_G_HCW(W_HCW_KC,KEY_VOLUMEDOWN)] = VOLUMEDOWN;
377 translist[W_G_HCW(W_HCW_KC,KEY_CHANNELUP)] = CHANNELUP;
378 translist[W_G_HCW(W_HCW_KC,KEY_CHANNELDOWN)] = CHANNELDOWN;
379 translist[W_G_HCW(W_HCW_KC,KEY_PAGEUP)] = CHANNELUP;
380 translist[W_G_HCW(W_HCW_KC,KEY_PAGEDOWN)] = CHANNELDOWN;
383 //Processing CEC_Messages
384 translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_NUMBER9)] = NINE;
385 translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_NUMBER8)] = EIGHT;
386 translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_NUMBER7)] = SEVEN;
387 translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_NUMBER6)] = SIX;
388 translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_NUMBER5)] = FIVE;
389 translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_NUMBER4)] = FOUR;
390 translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_NUMBER3)] = THREE;
391 translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_NUMBER2)] = TWO;
392 translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_NUMBER1)] = ONE;
393 translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_NUMBER0)] = ZERO;
394 //translist[W_G_HCW(W_HCW_CEC,KEY_KPDOT)] = STAR;
398 //translist[W_G_HCW(W_HCW_CEC,KEY_J)] = GO; //j for JUMP TO instead of go to
399 translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_F2_RED)] = RED;
400 translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_F3_GREEN)] = GREEN;
401 translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_F4_YELLOW)] = YELLOW;
402 translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_F1_BLUE)] = BLUE;
403 //Processing Remote Style Messages
404 translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_FAVORITE_MENU)] = MENU;
406 translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_RECORD)] = RECORD;
407 translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_PLAY)] = PLAY; //Playback Televison
408 translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_PAUSE)] = PAUSE;
409 translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_STOP)] = STOP;
410 translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_PAUSE_PLAY_FUNCTION)] = PLAYPAUSE;
411 translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_FORWARD)] = SKIPFORWARD;
412 translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_BACKWARD)] = SKIPBACK;
413 translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_FAST_FORWARD )] = FORWARD;
414 translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_REWIND)] = REVERSE;
415 translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_MUTE)] = MUTE;
416 translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_VOLUME_UP)] = VOLUMEUP;
417 translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_VOLUME_DOWN)] = VOLUMEDOWN;
418 translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_CHANNEL_UP )] = CHANNELUP;
419 translist[W_G_HCW(W_HCW_CEC,CEC_USER_CONTROL_CODE_CHANNEL_DOWN)] = CHANNELDOWN;
422 #define NAMETRICK(pre, code) linux_keymap[pre ## code]= #code
423 #define NAMETRICK2(pre, code) cec_keymap[pre ## code]= #code
424 //extracte from linux/input.h
426 static const char * linux_keymap[KEY_MAX+1];
427 static const char * cec_keymap[CEC_USER_CONTROL_CODE_MAX+1];
429 void InputLinux::InitKeymap()
431 for (int i=0;i<KEY_MAX+1;i++)
433 linux_keymap[i] = NULL;
436 NAMETRICK(KEY_,RESERVED);
448 NAMETRICK(KEY_,MINUS);
449 NAMETRICK(KEY_,EQUAL);
450 NAMETRICK(KEY_,BACKSPACE);
462 NAMETRICK(KEY_,LEFTBRACE);
463 NAMETRICK(KEY_,RIGHTBRACE);
464 NAMETRICK(KEY_,ENTER);
465 NAMETRICK(KEY_,LEFTCTRL);
475 NAMETRICK(KEY_,SEMICOLON);
476 NAMETRICK(KEY_,APOSTROPHE);
477 NAMETRICK(KEY_,GRAVE);
478 NAMETRICK(KEY_,LEFTSHIFT);
479 NAMETRICK(KEY_,BACKSLASH);
487 NAMETRICK(KEY_,COMMA);
489 NAMETRICK(KEY_,SLASH);
490 NAMETRICK(KEY_,RIGHTSHIFT);
491 NAMETRICK(KEY_,KPASTERISK);
492 NAMETRICK(KEY_,LEFTALT);
493 NAMETRICK(KEY_,SPACE);
494 NAMETRICK(KEY_,CAPSLOCK);
505 NAMETRICK(KEY_,NUMLOCK);
506 NAMETRICK(KEY_,SCROLLLOCK);
510 NAMETRICK(KEY_,KPMINUS);
514 NAMETRICK(KEY_,KPPLUS);
519 NAMETRICK(KEY_,KPDOT);
522 NAMETRICK(KEY_,KPENTER);
523 NAMETRICK(KEY_,RIGHTCTRL);
524 NAMETRICK(KEY_,KPSLASH);
525 NAMETRICK(KEY_,SYSRQ);
526 NAMETRICK(KEY_,RIGHTALT);
527 NAMETRICK(KEY_,LINEFEED);
528 NAMETRICK(KEY_,HOME);
530 NAMETRICK(KEY_,PAGEUP);
531 NAMETRICK(KEY_,LEFT);
532 NAMETRICK(KEY_,RIGHT);
534 NAMETRICK(KEY_,DOWN);
535 NAMETRICK(KEY_,PAGEDOWN);
536 NAMETRICK(KEY_,INSERT);
537 NAMETRICK(KEY_,DELETE);
538 NAMETRICK(KEY_,MACRO);
539 NAMETRICK(KEY_,MUTE);
540 NAMETRICK(KEY_,VOLUMEDOWN);
541 NAMETRICK(KEY_,VOLUMEUP);
542 NAMETRICK(KEY_,POWER);
543 NAMETRICK(KEY_,KPEQUAL);
544 NAMETRICK(KEY_,KPPLUSMINUS);
545 NAMETRICK(KEY_,PLAY);
546 NAMETRICK(KEY_,PAUSE);
547 NAMETRICK(KEY_,SCALE);
548 NAMETRICK(KEY_,KPCOMMA);
550 NAMETRICK(KEY_,LEFTMETA);
551 NAMETRICK(KEY_,RIGHTMETA);
552 NAMETRICK(KEY_,COMPOSE);
553 NAMETRICK(KEY_,STOP);
554 NAMETRICK(KEY_,AGAIN);
555 NAMETRICK(KEY_,PROPS);
556 NAMETRICK(KEY_,UNDO);
557 NAMETRICK(KEY_,FRONT);
558 NAMETRICK(KEY_,COPY);
559 NAMETRICK(KEY_,OPEN);
560 NAMETRICK(KEY_,PASTE);
561 NAMETRICK(KEY_,FIND);
563 NAMETRICK(KEY_,HELP);
564 NAMETRICK(KEY_,MENU);
565 NAMETRICK(KEY_,CALC);
566 NAMETRICK(KEY_,SETUP);
567 NAMETRICK(KEY_,SLEEP);
568 NAMETRICK(KEY_,WAKEUP);
569 NAMETRICK(KEY_,FILE);
570 NAMETRICK(KEY_,SENDFILE);
571 NAMETRICK(KEY_,DELETEFILE);
572 NAMETRICK(KEY_,XFER);
573 NAMETRICK(KEY_,PROG1);
574 NAMETRICK(KEY_,PROG2);
576 NAMETRICK(KEY_,MSDOS);
577 NAMETRICK(KEY_,COFFEE);
578 NAMETRICK(KEY_,DIRECTION);
579 NAMETRICK(KEY_,CYCLEWINDOWS);
580 NAMETRICK(KEY_,MAIL);
581 NAMETRICK(KEY_,BOOKMARKS);
582 NAMETRICK(KEY_,COMPUTER);
583 NAMETRICK(KEY_,BACK);
584 NAMETRICK(KEY_,FORWARD);
585 NAMETRICK(KEY_,FASTFORWARD);
586 NAMETRICK(KEY_,CLOSECD);
587 NAMETRICK(KEY_,EJECTCD);
588 NAMETRICK(KEY_,EJECTCLOSECD);
589 NAMETRICK(KEY_,NEXTSONG);
590 NAMETRICK(KEY_,PLAYPAUSE);
591 NAMETRICK(KEY_,PREVIOUSSONG);
592 NAMETRICK(KEY_,STOPCD);
593 NAMETRICK(KEY_,RECORD);
594 NAMETRICK(KEY_,REWIND);
595 NAMETRICK(KEY_,PHONE);
597 NAMETRICK(KEY_,CONFIG);
598 NAMETRICK(KEY_,HOMEPAGE);
599 NAMETRICK(KEY_,REFRESH);
600 NAMETRICK(KEY_,EXIT);
601 NAMETRICK(KEY_,MOVE);
602 NAMETRICK(KEY_,EDIT);
603 NAMETRICK(KEY_,SCROLLUP);
604 NAMETRICK(KEY_,SCROLLDOWN);
605 NAMETRICK(KEY_,KPLEFTPAREN);
606 NAMETRICK(KEY_,KPRIGHTPAREN);
608 NAMETRICK(KEY_,REDO);
610 NAMETRICK(KEY_,SELECT);
611 NAMETRICK(KEY_,GOTO);
612 NAMETRICK(KEY_,CLEAR);
613 NAMETRICK(KEY_,POWER2);
614 NAMETRICK(KEY_,OPTION);
615 NAMETRICK(KEY_,INFO);
616 NAMETRICK(KEY_,TIME);
617 NAMETRICK(KEY_,VENDOR);
618 NAMETRICK(KEY_,ARCHIVE);
619 NAMETRICK(KEY_,PROGRAM);
620 NAMETRICK(KEY_,CHANNEL);
621 NAMETRICK(KEY_,FAVORITES);
625 NAMETRICK(KEY_,LANGUAGE);
626 NAMETRICK(KEY_,TITLE);
627 NAMETRICK(KEY_,SUBTITLE);
628 NAMETRICK(KEY_,ANGLE);
629 NAMETRICK(KEY_,ZOOM);
630 NAMETRICK(KEY_,MODE);
631 NAMETRICK(KEY_,KEYBOARD);
632 NAMETRICK(KEY_,SCREEN);
634 NAMETRICK(KEY_,GREEN);
635 NAMETRICK(KEY_,YELLOW);
636 NAMETRICK(KEY_,BLUE);
637 NAMETRICK(KEY_,CHANNELUP);
638 NAMETRICK(KEY_,CHANNELDOWN);
639 NAMETRICK(KEY_,FIRST);
640 NAMETRICK(KEY_,LAST);
642 NAMETRICK(KEY_,NEXT);
643 NAMETRICK(KEY_,RESTART);
644 NAMETRICK(KEY_,SLOW);
645 NAMETRICK(KEY_,SHUFFLE);
646 NAMETRICK(KEY_,BREAK);
647 NAMETRICK(KEY_,PREVIOUS);
648 NAMETRICK(KEY_,DIGITS);
649 NAMETRICK(KEY_,TEEN);
650 NAMETRICK(KEY_,TWEN);
651 NAMETRICK(KEY_,VIDEOPHONE);
652 NAMETRICK(KEY_,GAMES);
653 NAMETRICK(KEY_,ZOOMIN);
654 NAMETRICK(KEY_,ZOOMOUT);
655 NAMETRICK(KEY_,ZOOMRESET);
656 NAMETRICK(KEY_,DOLLAR);
657 NAMETRICK(KEY_,EURO);
658 NAMETRICK(KEY_,MEDIA);
659 NAMETRICK(KEY_,FRAMEBACK);
660 NAMETRICK(KEY_,FRAMEFORWARD);
661 NAMETRICK(KEY_,CONTEXT_MENU);
662 NAMETRICK(KEY_,MEDIA_REPEAT);
663 NAMETRICK(KEY_,NUMERIC_0);
664 NAMETRICK(KEY_,NUMERIC_1);
665 NAMETRICK(KEY_,NUMERIC_2);
666 NAMETRICK(KEY_,NUMERIC_3);
667 NAMETRICK(KEY_,NUMERIC_4);
668 NAMETRICK(KEY_,NUMERIC_5);
669 NAMETRICK(KEY_,NUMERIC_6);
670 NAMETRICK(KEY_,NUMERIC_7);
671 NAMETRICK(KEY_,NUMERIC_8);
672 NAMETRICK(KEY_,NUMERIC_9);
673 NAMETRICK(KEY_,NUMERIC_STAR);
674 NAMETRICK(KEY_,NUMERIC_POUND);
676 for (int i=0; i < CEC_USER_CONTROL_CODE_MAX + 1; i++)
678 cec_keymap[i] = NULL;
681 NAMETRICK2(CEC_USER_CONTROL_CODE_,SELECT);
682 NAMETRICK2(CEC_USER_CONTROL_CODE_,UP);
683 NAMETRICK2(CEC_USER_CONTROL_CODE_,DOWN);
684 NAMETRICK2(CEC_USER_CONTROL_CODE_,LEFT);
685 NAMETRICK2(CEC_USER_CONTROL_CODE_,RIGHT);
686 NAMETRICK2(CEC_USER_CONTROL_CODE_,RIGHT_UP);
687 NAMETRICK2(CEC_USER_CONTROL_CODE_,RIGHT_DOWN);
688 NAMETRICK2(CEC_USER_CONTROL_CODE_,LEFT_UP);
689 NAMETRICK2(CEC_USER_CONTROL_CODE_,LEFT_DOWN);
690 NAMETRICK2(CEC_USER_CONTROL_CODE_,ROOT_MENU);
691 NAMETRICK2(CEC_USER_CONTROL_CODE_,SETUP_MENU);
692 NAMETRICK2(CEC_USER_CONTROL_CODE_,CONTENTS_MENU);
693 NAMETRICK2(CEC_USER_CONTROL_CODE_,FAVORITE_MENU);
694 NAMETRICK2(CEC_USER_CONTROL_CODE_,EXIT);
695 NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER0);
696 NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER1);
697 NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER2);
698 NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER3);
699 NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER4);
700 NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER5);
701 NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER6);
702 NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER7);
703 NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER8);
704 NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER9);
705 NAMETRICK2(CEC_USER_CONTROL_CODE_,DOT);
706 NAMETRICK2(CEC_USER_CONTROL_CODE_,ENTER);
707 NAMETRICK2(CEC_USER_CONTROL_CODE_,CLEAR);
708 NAMETRICK2(CEC_USER_CONTROL_CODE_,NEXT_FAVORITE);
709 NAMETRICK2(CEC_USER_CONTROL_CODE_,CHANNEL_UP);
710 NAMETRICK2(CEC_USER_CONTROL_CODE_,CHANNEL_DOWN);
711 NAMETRICK2(CEC_USER_CONTROL_CODE_,PREVIOUS_CHANNEL);
712 NAMETRICK2(CEC_USER_CONTROL_CODE_,SOUND_SELECT);
713 NAMETRICK2(CEC_USER_CONTROL_CODE_,INPUT_SELECT);
714 NAMETRICK2(CEC_USER_CONTROL_CODE_,DISPLAY_INFORMATION);
715 NAMETRICK2(CEC_USER_CONTROL_CODE_,HELP);
716 NAMETRICK2(CEC_USER_CONTROL_CODE_,PAGE_UP);
717 NAMETRICK2(CEC_USER_CONTROL_CODE_,PAGE_DOWN);
718 NAMETRICK2(CEC_USER_CONTROL_CODE_,POWER );
719 NAMETRICK2(CEC_USER_CONTROL_CODE_,VOLUME_UP );
720 NAMETRICK2(CEC_USER_CONTROL_CODE_,VOLUME_DOWN );
721 NAMETRICK2(CEC_USER_CONTROL_CODE_,MUTE );
722 NAMETRICK2(CEC_USER_CONTROL_CODE_,PLAY );
723 NAMETRICK2(CEC_USER_CONTROL_CODE_,STOP );
724 NAMETRICK2(CEC_USER_CONTROL_CODE_,PAUSE );
725 NAMETRICK2(CEC_USER_CONTROL_CODE_,RECORD );
726 NAMETRICK2(CEC_USER_CONTROL_CODE_,REWIND );
727 NAMETRICK2(CEC_USER_CONTROL_CODE_,FAST_FORWARD );
728 NAMETRICK2(CEC_USER_CONTROL_CODE_,EJECT );
729 NAMETRICK2(CEC_USER_CONTROL_CODE_,FORWARD );
730 NAMETRICK2(CEC_USER_CONTROL_CODE_,BACKWARD );
731 NAMETRICK2(CEC_USER_CONTROL_CODE_,STOP_RECORD );
732 NAMETRICK2(CEC_USER_CONTROL_CODE_,PAUSE_RECORD );
733 NAMETRICK2(CEC_USER_CONTROL_CODE_,ANGLE );
734 NAMETRICK2(CEC_USER_CONTROL_CODE_,SUB_PICTURE );
735 NAMETRICK2(CEC_USER_CONTROL_CODE_,VIDEO_ON_DEMAND );
736 NAMETRICK2(CEC_USER_CONTROL_CODE_,ELECTRONIC_PROGRAM_GUIDE );
737 NAMETRICK2(CEC_USER_CONTROL_CODE_,TIMER_PROGRAMMING );
738 NAMETRICK2(CEC_USER_CONTROL_CODE_,INITIAL_CONFIGURATION );
739 NAMETRICK2(CEC_USER_CONTROL_CODE_,PLAY_FUNCTION );
740 NAMETRICK2(CEC_USER_CONTROL_CODE_,PAUSE_PLAY_FUNCTION );
741 NAMETRICK2(CEC_USER_CONTROL_CODE_,RECORD_FUNCTION );
742 NAMETRICK2(CEC_USER_CONTROL_CODE_,PAUSE_RECORD_FUNCTION );
743 NAMETRICK2(CEC_USER_CONTROL_CODE_,STOP_FUNCTION );
744 NAMETRICK2(CEC_USER_CONTROL_CODE_,MUTE_FUNCTION );
745 NAMETRICK2(CEC_USER_CONTROL_CODE_,RESTORE_VOLUME_FUNCTION );
746 NAMETRICK2(CEC_USER_CONTROL_CODE_,TUNE_FUNCTION );
747 NAMETRICK2(CEC_USER_CONTROL_CODE_,SELECT_MEDIA_FUNCTION );
748 NAMETRICK2(CEC_USER_CONTROL_CODE_,SELECT_AV_INPUT_FUNCTION );
749 NAMETRICK2(CEC_USER_CONTROL_CODE_,SELECT_AUDIO_INPUT_FUNCTION );
750 NAMETRICK2(CEC_USER_CONTROL_CODE_,POWER_TOGGLE_FUNCTION );
751 NAMETRICK2(CEC_USER_CONTROL_CODE_,POWER_OFF_FUNCTION );
752 NAMETRICK2(CEC_USER_CONTROL_CODE_,POWER_ON_FUNCTION );
753 NAMETRICK2(CEC_USER_CONTROL_CODE_,F1_BLUE );
754 NAMETRICK2(CEC_USER_CONTROL_CODE_,F2_RED );
755 NAMETRICK2(CEC_USER_CONTROL_CODE_,F3_GREEN );
756 NAMETRICK2(CEC_USER_CONTROL_CODE_,F4_YELLOW );
757 NAMETRICK2(CEC_USER_CONTROL_CODE_,F5 );
758 NAMETRICK2(CEC_USER_CONTROL_CODE_,DATA );
759 NAMETRICK2(CEC_USER_CONTROL_CODE_,AN_RETURN );
760 NAMETRICK2(CEC_USER_CONTROL_CODE_,AN_CHANNELS_LIST );
761 NAMETRICK2(CEC_USER_CONTROL_CODE_,MAX );
766 char* InputLinux::HCWDesc(unsigned long long hcw)
769 unsigned int type = static_cast<unsigned int>(hcw >> 32);
770 unsigned int vk = static_cast<ULONG>(hcw);
778 const char *desc=linux_keymap[vk];
780 strncpy(rt, desc, 9);
782 sprintf(rt, "0x%x", vk);
788 const char* desc = cec_keymap[vk];
790 strncpy(rt, desc, 9);
792 sprintf(rt, "0x%x", vk);
799 sprintf(rt,"R: %X",ri);
806 void InputLinux::changePowerState(bool poweron)
812 //Log::getInstance()->log("InputLinux", Log::DEBUG, "CEC set active source");
813 cec_adap->SetActiveSource(cec_config.deviceTypes[0]);
817 //Log::getInstance()->log("InputLinux", Log::DEBUG, "CEC set inactive view");
818 cec_adap->SetInactiveView();
823 #if CEC_LIB_VERSION_MAJOR >= 4
825 // libcec4 API changed these params to pointers rather than copies, and the returns to void
826 // Otherwise, these two blocks of code are the same
828 void InputLinux::cecLogMessage(void* /* param */, const cec_log_message* message)
830 Log::getInstance()->log("InputLinux", Log::DEBUG, "CECLOG: %lld %d %s", message->time, message->level, message->message);
833 void InputLinux::cecKeyPress(void* /* param */, const cec_keypress* key)
835 //Log::getInstance()->log("InputLinux", Log::DEBUG, "Incoming cec key %d %d", key->keycode,key->duration);
836 if (key->duration == 0) static_cast<InputLinux*>(Input::getInstance())->incomingCECkey(key->keycode);
839 void InputLinux::cecCommand(void* /* param */, const cec_command* command)
841 Log::getInstance()->log("InputLinux", Log::DEBUG, "CECCommand: %d",command->opcode);
842 switch (command->opcode) {
843 case CEC_OPCODE_STANDBY: {
844 if (command->initiator==CECDEVICE_TV) {
845 static_cast<InputLinux*>(Input::getInstance())->incomingPowerkey(POWEROFF);
848 case CEC_OPCODE_DECK_CONTROL: {
849 if (command->initiator==CECDEVICE_TV && command->parameters.size == 1
850 && command->parameters[0]==CEC_DECK_CONTROL_MODE_STOP) {
851 static_cast<InputLinux*>(Input::getInstance())->incomingCECkey(CEC_USER_CONTROL_CODE_STOP);
856 case CEC_OPCODE_PLAY: {
857 if (command->initiator==CECDEVICE_TV && command->parameters.size == 1) {
858 if (command->parameters[0]==CEC_PLAY_MODE_PLAY_FORWARD) {
859 static_cast<InputLinux*>(Input::getInstance())->incomingCECkey(CEC_USER_CONTROL_CODE_PLAY);
860 } else if (command->parameters[0]==CEC_PLAY_MODE_PLAY_STILL) {
861 static_cast<InputLinux*>(Input::getInstance())->incomingCECkey(CEC_USER_CONTROL_CODE_PAUSE);
872 void InputLinux::cecConfigurationChanged(void* /* param */, const libcec_configuration*)
874 Log::getInstance()->log("InputLinux", Log::DEBUG, "CECConfig:"/*,config->string()*/);
879 int InputLinux::cecLogMessage(void *param, const cec_log_message message)
881 Log::getInstance()->log("InputLinux", Log::DEBUG, "CECLOG: %lld %d %s", message.time, message.level, message.message);
885 int InputLinux::cecKeyPress(void*param, const cec_keypress key)
887 //Log::getInstance()->log("InputLinux", Log::DEBUG, "Incoming cec key %d %d", key.keycode,key.duration);
888 if (key.duration == 0) ((InputLinux*)Input::getInstance())->incomingCECkey(key.keycode);
892 int InputLinux::cecCommand(void *param, const cec_command command)
894 Log::getInstance()->log("InputLinux", Log::DEBUG, "CECCommand: %d",command.opcode);
895 switch (command.opcode) {
896 case CEC_OPCODE_STANDBY: {
897 if (command.initiator==CECDEVICE_TV) {
898 ((InputLinux*)Input::getInstance())->incomingPowerkey(POWEROFF);
901 case CEC_OPCODE_DECK_CONTROL: {
902 if (command.initiator==CECDEVICE_TV && command.parameters.size == 1
903 && command.parameters[0]==CEC_DECK_CONTROL_MODE_STOP) {
904 ((InputLinux*)Input::getInstance())->incomingCECkey(CEC_USER_CONTROL_CODE_STOP);
909 case CEC_OPCODE_PLAY: {
910 if (command.initiator==CECDEVICE_TV && command.parameters.size == 1) {
911 if (command.parameters[0]==CEC_PLAY_MODE_PLAY_FORWARD) {
912 ((InputLinux*)Input::getInstance())->incomingCECkey(CEC_USER_CONTROL_CODE_PLAY);
913 } else if (command.parameters[0]==CEC_PLAY_MODE_PLAY_STILL) {
914 ((InputLinux*)Input::getInstance())->incomingCECkey(CEC_USER_CONTROL_CODE_PAUSE);
926 int InputLinux::cecConfigurationChanged(void *param, const libcec_configuration config)
928 Log::getInstance()->log("InputLinux", Log::DEBUG, "CECConfig:"/*,config.string()*/);
935 void InputLinux::cecSourceActivated(void* /* param */, const cec_logical_address address, const uint8_t activated)
937 Log::getInstance()->log("InputLinux", Log::DEBUG, "CECSourceActivated: %d %d", address, activated);
940 static_cast<InputLinux*>(Input::getInstance())->incomingPowerkey(POWERON);
944 void InputLinux::incomingCECkey(int keys)
946 // Send INPUT message
947 Message* m = new Message();
948 m->message = Message::INPUT_EVENT;
949 m->to = Command::getInstance();
951 m->parameter = static_cast<UCHAR>(TranslateHWC(W_G_HCW(W_HCW_CEC, keys)));
952 MessageQueue::getInstance()->postMessage(m);
955 void InputLinux::incomingPowerkey(UCHAR key)
957 // Send INPUT message
958 Message* m = new Message();
959 m->message = Message::INPUT_EVENT;
960 m->to = Command::getInstance();
963 MessageQueue::getInstance()->postMessage(m);
966 bool InputLinux::loadOptionsfromServer(VDR* vdr)
970 name = vdr->configLoad("InputLinux", "HandleVolume");
974 if (STRCASECMP(name, "Vomp") == 0) cechandlesvolume = false;
975 else if (STRCASECMP(name, "Cec") == 0) cechandlesvolume = true;
978 return Input::loadOptionsfromServer(vdr);
981 bool InputLinux::saveOptionstoServer()
983 if (cechandlesvolume) VDR::getInstance()->configSave("InputLinux", "HandleVolume","Cec");
984 else VDR::getInstance()->configSave("InputLinux", "HandleVolume","Vomp");
986 return Input::saveOptionstoServer();
989 bool InputLinux::addOptionsToPanes(int panenumber,Options *options,WOptionPane* pane)
991 if (!Input::addOptionsToPanes(panenumber, options, pane)) return false;
996 static const char* volumeopts[]={"Vomp","Cec"};
997 option = new Option(100,tr("Volume handled by"), "InputLinux","HandleVolume",Option::TYPE_TEXT,/*4,2*/2,0,0,volumeopts,NULL,false,this);
998 options->push_back(option);
999 pane->addOptionLine(option);
1005 bool InputLinux::handleOptionChanges(Option* option)
1007 if (Input::handleOptionChanges(option))
1009 switch (option->id) {
1011 if (STRCASECMP(option->options[option->userSetChoice], "Vomp") == 0) {
1012 cechandlesvolume=false;
1013 } else if (STRCASECMP(option->options[option->userSetChoice], "Cec")
1015 cechandlesvolume=true;
1017 Log::getInstance()->log("InputLinux", Log::DEBUG, "Set volume handling to to %s %d",option->options[option->userSetChoice],cechandlesvolume);
1026 void InputLinux::volumeUp()
1028 cec_adap->VolumeUp();
1031 void InputLinux::volumeDown()
1033 cec_adap->VolumeDown();
1036 void InputLinux::volumeMute()
1038 #if CEC_LIB_VERSION_MAJOR >= 4
1039 cec_adap->AudioToggleMute();
1041 cec_adap->MuteAudio();
1045 void InputLinux::informStopEventLoop()
1047 listenLoopStop = true;
1048 write(pfds[1], "1", 1); // break the select in getButtonPress
1051 void InputLinux::eventLoop()
1056 if (pipe2(pfds, O_NONBLOCK) == -1)
1058 Log::getInstance()->log("InputLinux", Log::ERR, "pipe2() fail");
1062 Log::getInstance()->log("InputLinux", Log::INFO, "Listen loop");
1066 if (listenLoopStop) break;
1071 for (unsigned int i = 0; i < devices.size(); i++)
1073 int cur_fd = devices[i];
1074 maxfd = max(cur_fd, maxfd);
1075 FD_SET(cur_fd, &readfds);
1078 FD_SET(pfds[0], &readfds);
1079 maxfd = max(pfds[0], maxfd);
1081 // 0 = nothing happened and timeout expired
1082 // >0 = num of descriptors that changed
1084 if (select(maxfd + 1, &readfds, NULL, NULL, NULL) < 1)
1086 Log::getInstance()->log("InputLinux", Log::ERR, "Select fail");
1090 if (FD_ISSET(pfds[0], &readfds))
1092 // assume quit signal
1093 Log::getInstance()->log("InputLinux", Log::NOTICE, "pfds quit");
1096 // FUTURE: read the byte and do different things? Read listenLoopStop and maybe other bools?
1099 for (unsigned int i = 0; i < devices.size(); i++)
1101 int cur_fd = devices[i];
1102 if (FD_ISSET(cur_fd, &readfds))
1104 struct input_event ev;
1105 int count = read(cur_fd, &ev, sizeof(ev));
1106 if (count == sizeof(ev))
1108 if (ev.type == EV_KEY && ev.value == 1)
1110 // Send INPUT message
1111 Message* m = new Message();
1112 m->message = Message::INPUT_EVENT;
1113 m->to = Command::getInstance();
1115 m->parameter = static_cast<UCHAR>(TranslateHWC(W_G_HCW(W_HCW_KC,ev.code)));
1116 MessageQueue::getInstance()->postMessage(m);
1127 // FIXME surely NA_SIGNAL can go