From d267c7ed24f86dbbec24ecb06d59e4d24b769cb0 Mon Sep 17 00:00:00 2001 From: martii Date: Tue, 25 Feb 2014 00:09:14 +0100 Subject: [PATCH] driver/rcinput: implement long key press support (but no rcsim/yWeb support at this time) driver/rcinput: drop unused gettimeofday code Origin commit data ------------------ Commit: https://github.com/neutrino-images/ni-neutrino/commit/7826ab0fcad8bc98975d07a99e6e66c5c2aae753 Author: martii Date: 2014-02-25 (Tue, 25 Feb 2014) --- data/locale/deutsch.locale | 2 + data/locale/english.locale | 2 + src/driver/rcinput.cpp | 308 ++++++++++++++++++---------------- src/driver/rcinput.h | 16 +- src/gui/keybind_setup.cpp | 20 +++ src/gui/widget/keychooser.cpp | 2 + src/neutrino.cpp | 2 + src/system/helpers.h | 3 + src/system/locals.h | 2 + src/system/locals_intern.h | 2 + src/system/settings.h | 2 + 11 files changed, 215 insertions(+), 146 deletions(-) diff --git a/data/locale/deutsch.locale b/data/locale/deutsch.locale index fbc619da5..287f53b3c 100644 --- a/data/locale/deutsch.locale +++ b/data/locale/deutsch.locale @@ -674,6 +674,7 @@ keybindingmenu.channellist Kanalliste keybindingmenu.channelup Kanal hoch keybindingmenu.head Tasten-Belegungen bearbeiten keybindingmenu.lastchannel Letzter Kanal +keybindingmenu.longkeypress_duration Langer Tastendruck keybindingmenu.misc Sonstige keybindingmenu.mode_left_right_key_tv Funktion li/re Tasten im TV-Modus keybindingmenu.mode_left_right_key_tv_infobar Infobar einblenden @@ -958,6 +959,7 @@ menu.hint_leds_record Definiert, ob die Power-LEDs blinken sollen, wenn eine Auf menu.hint_leds_standby Definiert den Status der Power-LEDs im Standby menu.hint_leds_tv Definiert den Status der Power-LEDs im TV-Modus menu.hint_load Laden der Neutrino-HD-Einstellungen aus einer Datei +menu.hint_longkeypress_duration Tasten, die länger als die angegebene Zeit betätigt werden, werden als "langer Tastendruck" behandelt. menu.hint_lua Plugins ausführen menu.hint_make_hdlist Bei aktiver Option wird ein Bouquet namens 'HD' erzeugt, in dem alle HD-Sender zusammengefasst sind menu.hint_make_newlist Nach einer Kanalsuche wird ein Bouquet namens 'neue Kanäle' erzeugt diff --git a/data/locale/english.locale b/data/locale/english.locale index ec15f61b5..88f3c24d8 100644 --- a/data/locale/english.locale +++ b/data/locale/english.locale @@ -674,6 +674,7 @@ keybindingmenu.channellist Channellist keybindingmenu.channelup channel up keybindingmenu.head Edit Keybindings keybindingmenu.lastchannel Quick Zap +keybindingmenu.longkeypress_duration Long key-press keybindingmenu.misc Misc keybindingmenu.mode_left_right_key_tv Left/Right Key Behavior in TV-Mode keybindingmenu.mode_left_right_key_tv_infobar Show Infobar @@ -958,6 +959,7 @@ menu.hint_leds_record LEDs state when box recording menu.hint_leds_standby LEDs state in soft-standby mode menu.hint_leds_tv Working LEDs state menu.hint_load Load Neutrino-HD GUI settings from file +menu.hint_longkeypress_duration A key press will be considered as "long key press" if it's pressed longer than the specified time. menu.hint_lua Run Plugins menu.hint_make_hdlist Auto-create HD channel list based on\nchannel type and name menu.hint_make_newlist Create list of recently added channels diff --git a/src/driver/rcinput.cpp b/src/driver/rcinput.cpp index 2c39718b6..d10aa2164 100644 --- a/src/driver/rcinput.cpp +++ b/src/driver/rcinput.cpp @@ -5,6 +5,7 @@ 2003 thegoodguy Copyright (C) 2008-2012 Stefan Seyfried + Copyright (C) 2013-2014 martii License: GPL @@ -29,6 +30,7 @@ #include #include +#include #include #include @@ -42,6 +44,7 @@ #endif /* KEYBOARD_INSTEAD_OF_REMOTE_CONTROL */ #include #include +#include #include #include @@ -51,12 +54,14 @@ #include #include -#include +//#include +#include #include +#include +#include #include //#define RCDEBUG -//#define USE_GETTIMEOFDAY #define ENABLE_REPEAT_CHECK @@ -67,6 +72,7 @@ typedef struct input_event t_input_event; static struct termio orig_termio; static bool saved_orig_termio = false; #endif /* KEYBOARD_INSTEAD_OF_REMOTE_CONTROL */ +static bool input_stopped = false; /********************************************************************************* * Constructor - opens rc-input device, selects rc-hardware and starts threads @@ -75,6 +81,8 @@ static bool saved_orig_termio = false; CRCInput::CRCInput() { timerid= 1; + repeatkeys = NULL; + longPressAny = false; // pipe for internal event-queue // ----------------------------- @@ -106,7 +114,7 @@ CRCInput::CRCInput() int clilen; memset(&servaddr, 0, sizeof(struct sockaddr_un)); servaddr.sun_family = AF_UNIX; - strcpy(servaddr.sun_path, NEUTRINO_UDS_NAME); + cstrncpy(servaddr.sun_path, NEUTRINO_UDS_NAME, sizeof(servaddr.sun_path)); clilen = sizeof(servaddr.sun_family) + strlen(servaddr.sun_path); unlink(NEUTRINO_UDS_NAME); @@ -137,30 +145,34 @@ CRCInput::CRCInput() repeat_block = repeat_block_generic = 0; open(); rc_last_key = KEY_MAX; - firstKey = true; + longPressEnd = 0; //select and setup remote control hardware set_rc_hw(); } -void CRCInput::open() +/* if dev is given, open device with index , if not (re)open all */ +void CRCInput::open(int dev) { - close(); + if (dev == -1) + close(); for (int i = 0; i < NUMBER_OF_EVENT_DEVICES; i++) { - if ((fd_rc[i] = ::open(RC_EVENT_DEVICE[i], O_RDONLY)) == -1) - perror(RC_EVENT_DEVICE[i]); - else - { - fcntl(fd_rc[i], F_SETFL, O_NONBLOCK); + if (dev != -1) { + if (i != dev || fd_rc[i] != -1) + continue; } + if ((fd_rc[i] = ::open(RC_EVENT_DEVICE[i], O_RDWR|O_NONBLOCK|O_CLOEXEC)) == -1) + perror(RC_EVENT_DEVICE[i]); printf("CRCInput::open: %s fd %d\n", RC_EVENT_DEVICE[i], fd_rc[i]); } //+++++++++++++++++++++++++++++++++++++++ #ifdef KEYBOARD_INSTEAD_OF_REMOTE_CONTROL fd_keyb = STDIN_FILENO; + if (fd_rc[0] < 0) + fd_rc[0] = fd_keyb; #else fd_keyb = 0; #endif /* KEYBOARD_INSTEAD_OF_REMOTE_CONTROL */ @@ -267,6 +279,7 @@ CRCInput::~CRCInput() **************************************************************************/ void CRCInput::stopInput() { + input_stopped = true; close(); } @@ -278,6 +291,7 @@ void CRCInput::restartInput() { close(); open(); + input_stopped = false; } #if 0 //never used @@ -335,13 +349,7 @@ int CRCInput::messageLoop( bool anyKeyCancels, int timeout ) int CRCInput::addTimer(uint64_t Interval, bool oneshot, bool correct_time ) { -#ifdef USE_GETTIMEOFDAY - struct timeval tv; - gettimeofday( &tv, NULL ); - uint64_t timeNow = (uint64_t) tv.tv_usec + (uint64_t)((uint64_t) tv.tv_sec * (uint64_t) 1000000); -#else uint64_t timeNow = time_monotonic_us(); -#endif timer _newtimer; if (!oneshot) @@ -373,19 +381,6 @@ int CRCInput::addTimer(uint64_t Interval, bool oneshot, bool correct_time ) return _newtimer.id; } -#ifdef USE_GETTIMEOFDAY -int CRCInput::addTimer(struct timeval Timeout) -{ - uint64_t timesout = (uint64_t) Timeout.tv_usec + (uint64_t)((uint64_t) Timeout.tv_sec * (uint64_t) 1000000); - return addTimer( timesout, true, false ); -} - -int CRCInput::addTimer(const time_t *Timeout) -{ - return addTimer( (uint64_t)*Timeout* (uint64_t) 1000000, true, false ); -} -#endif - void CRCInput::killTimer(uint32_t &id) { //printf("killing timer %d\n", id); @@ -405,13 +400,7 @@ void CRCInput::killTimer(uint32_t &id) int CRCInput::checkTimers() { int _id = 0; -#ifdef USE_GETTIMEOFDAY - struct timeval tv; - gettimeofday( &tv, NULL ); - uint64_t timeNow = (uint64_t) tv.tv_usec + (uint64_t)((uint64_t) tv.tv_sec * (uint64_t) 1000000); -#else uint64_t timeNow = time_monotonic_us(); -#endif std::vector::iterator e; for ( e= timers.begin(); e!= timers.end(); ++e ) if ( e->times_out< timeNow+ 2000 ) @@ -451,36 +440,18 @@ int CRCInput::checkTimers() int64_t CRCInput::calcTimeoutEnd(const int timeout_in_seconds) { -#ifdef USE_GETTIMEOFDAY - struct timeval tv; - gettimeofday(&tv, NULL); - return (uint64_t) tv.tv_usec + (uint64_t)((uint64_t) tv.tv_sec + (uint64_t)timeout_in_seconds) * (uint64_t) 1000000; -#else return time_monotonic_us() + ((uint64_t)timeout_in_seconds * (uint64_t) 1000000); -#endif } int64_t CRCInput::calcTimeoutEnd_MS(const int timeout_in_milliseconds) { -#ifdef USE_GETTIMEOFDAY - struct timeval tv; - gettimeofday(&tv, NULL); - uint64_t timeNow = (uint64_t) tv.tv_usec + (uint64_t)((uint64_t) tv.tv_sec * (uint64_t) 1000000); -#else uint64_t timeNow = time_monotonic_us(); -#endif return ( timeNow + timeout_in_milliseconds * 1000 ); } void CRCInput::getMsgAbsoluteTimeout(neutrino_msg_t * msg, neutrino_msg_data_t * data, uint64_t *TimeoutEnd, bool bAllowRepeatLR) { -#ifdef USE_GETTIMEOFDAY - struct timeval tv; - gettimeofday( &tv, NULL ); - uint64_t timeNow = (uint64_t) tv.tv_usec + (uint64_t)((uint64_t) tv.tv_sec * (uint64_t) 1000000); -#else uint64_t timeNow = time_monotonic_us(); -#endif uint64_t diff; if ( *TimeoutEnd < timeNow+ 100 ) @@ -490,16 +461,6 @@ void CRCInput::getMsgAbsoluteTimeout(neutrino_msg_t * msg, neutrino_msg_data_t * //printf("CRCInput::getMsgAbsoluteTimeout diff %llx TimeoutEnd %llx now %llx\n", diff, *TimeoutEnd, timeNow); getMsg_us( msg, data, diff, bAllowRepeatLR ); -#ifdef USE_GETTIMEOFDAY - if ( *msg == NeutrinoMessages::EVT_TIMESET ) - { - // recalculate timeout.... - //uint64_t ta= *TimeoutEnd; - *TimeoutEnd= *TimeoutEnd + *(int64_t*) *data; - - //printf("[getMsgAbsoluteTimeout]: EVT_TIMESET - recalculate timeout\n%llx/%llx - %llx/%llx\n", timeNow, *(int64_t*) *data, *TimeoutEnd, ta ); - } -#endif } void CRCInput::getMsg(neutrino_msg_t * msg, neutrino_msg_data_t * data, int Timeout, bool bAllowRepeatLR) @@ -512,6 +473,43 @@ void CRCInput::getMsg_ms(neutrino_msg_t * msg, neutrino_msg_data_t * data, int T getMsg_us(msg, data, (uint64_t) Timeout * 1000, bAllowRepeatLR); } +uint32_t *CRCInput::setAllowRepeat(uint32_t *rk) { + uint32_t *r = repeatkeys; + repeatkeys = rk; + return r; +} + +bool checkLongPress(uint32_t key); // keybind_setup.cpp + +bool CRCInput::mayLongPress(uint32_t key, bool bAllowRepeatLR) +{ + if (mayRepeat(key, bAllowRepeatLR)) + return false; + if (longPressAny) + return true; + return checkLongPress(key); +} + +bool CRCInput::mayRepeat(uint32_t key, bool bAllowRepeatLR) +{ + if((key == RC_up) || (key == RC_down) + || (key == RC_plus) || (key == RC_minus) + || (key == RC_page_down) || (key == RC_page_up) + || ((bAllowRepeatLR) && ((key == RC_left ) || (key == RC_right)))) + return true; + + if (repeatkeys) { + uint32_t *k = repeatkeys; + while (*k != RC_nokey) { + if (*k == key) { + return true; + } + k++; + } + } + return false; +} + void CRCInput::getMsg_us(neutrino_msg_t * msg, neutrino_msg_data_t * data, uint64_t Timeout, bool bAllowRepeatLR) { static uint64_t last_keypress = 0ULL; @@ -527,27 +525,28 @@ void CRCInput::getMsg_us(neutrino_msg_t * msg, neutrino_msg_data_t * data, uint6 int timer_id; fd_set rfds; - t_input_event ev; *data = 0; + /* reopen a missing input device + * TODO: real hot-plugging, e.g. of keyboards and triggering this loop... + * right now it is only run if some event is happening "by accident" */ + if (!input_stopped) { + for (int i = 0; i < NUMBER_OF_EVENT_DEVICES; i++) { + if (fd_rc[i] == -1) + open(i); + } + } + // wiederholung reinmachen - dass wirklich die ganze zeit bis timeout gewartet wird! -#ifdef USE_GETTIMEOFDAY - gettimeofday( &tv, NULL ); - uint64_t getKeyBegin = (uint64_t) tv.tv_usec + (uint64_t)((uint64_t) tv.tv_sec * (uint64_t) 1000000); -#else uint64_t getKeyBegin = time_monotonic_us(); -#endif + while(1) { + /* we later check for ev.type = EV_SYN which is 0x00, so set something invalid here... */ timer_id = 0; if ( !timers.empty() ) { -#ifdef USE_GETTIMEOFDAY - gettimeofday( &tv, NULL ); - uint64_t t_n= (uint64_t) tv.tv_usec + (uint64_t)((uint64_t) tv.tv_sec * (uint64_t) 1000000); -#else uint64_t t_n = time_monotonic_us(); -#endif if ( timers[0].times_out< t_n ) { timer_id = checkTimers(); @@ -816,17 +815,17 @@ void CRCInput::getMsg_us(neutrino_msg_t * msg, neutrino_msg_data_t * data, uint6 break; case NeutrinoMessages::EVT_POPUP : *msg = NeutrinoMessages::EVT_POPUP; - *data = (unsigned) p; + *data = (unsigned long) p; dont_delete_p = true; break; case NeutrinoMessages::EVT_EXTMSG : *msg = NeutrinoMessages::EVT_EXTMSG; - *data = (unsigned) p; + *data = (unsigned long) p; dont_delete_p = true; break; case NeutrinoMessages::CHANGEMODE : // Change *msg = NeutrinoMessages::CHANGEMODE; - *data = *(unsigned*) p; + *data = *(unsigned long*) p; break; case NeutrinoMessages::STANDBY_TOGGLE : *msg = NeutrinoMessages::STANDBY_TOGGLE; @@ -842,7 +841,7 @@ void CRCInput::getMsg_us(neutrino_msg_t * msg, neutrino_msg_data_t * data, uint6 break; case NeutrinoMessages::EVT_START_PLUGIN : *msg = NeutrinoMessages::EVT_START_PLUGIN; - *data = (unsigned) p; + *data = (unsigned long) p; dont_delete_p = true; break; case NeutrinoMessages::LOCK_RC : @@ -920,12 +919,6 @@ void CRCInput::getMsg_us(neutrino_msg_t * msg, neutrino_msg_data_t * data, uint6 if ((int64_t)last_keypress > *(int64_t*)p) last_keypress += *(int64_t *)p; -#ifdef USE_GETTIMEOFDAY - // Timer anpassen - for(std::vector::iterator e = timers.begin(); e != timers.end(); ++e) - if (e->correct_time) - e->times_out+= *(int64_t*) p; -#endif *msg = NeutrinoMessages::EVT_TIMESET; *data = (neutrino_msg_data_t) p; dont_delete_p = true; @@ -1110,7 +1103,7 @@ void CRCInput::getMsg_us(neutrino_msg_t * msg, neutrino_msg_data_t * data, uint6 { case CTimerdClient::EVT_ANNOUNCE_RECORD : *msg = NeutrinoMessages::ANNOUNCE_RECORD; - *data = (unsigned) p; + *data = (unsigned long) p; dont_delete_p = true; break; case CTimerdClient::EVT_ANNOUNCE_ZAPTO : @@ -1132,17 +1125,17 @@ void CRCInput::getMsg_us(neutrino_msg_t * msg, neutrino_msg_data_t * data, uint6 break; case CTimerdClient::EVT_RECORD_START : *msg = NeutrinoMessages::RECORD_START; - *data = (unsigned) p; + *data = (unsigned long) p; dont_delete_p = true; break; case CTimerdClient::EVT_RECORD_STOP : *msg = NeutrinoMessages::RECORD_STOP; - *data = (unsigned) p; + *data = (unsigned long) p; dont_delete_p = true; break; case CTimerdClient::EVT_ZAPTO : *msg = NeutrinoMessages::ZAPTO; - *data = (unsigned) p; + *data = (unsigned long) p; dont_delete_p = true; break; case CTimerdClient::EVT_SHUTDOWN : @@ -1159,15 +1152,14 @@ void CRCInput::getMsg_us(neutrino_msg_t * msg, neutrino_msg_data_t * data, uint6 break; case CTimerdClient::EVT_REMIND : *msg = NeutrinoMessages::REMIND; - *data = (unsigned) p; + *data = (unsigned long) p; dont_delete_p = true; break; case CTimerdClient::EVT_EXEC_PLUGIN : *msg = NeutrinoMessages::EVT_START_PLUGIN; - *data = (unsigned) p; + *data = (unsigned long) p; dont_delete_p = true; break; - default : printf("[neutrino] event INITID_TIMERD - unknown eventID 0x%x\n", emsg.eventID ); @@ -1195,10 +1187,21 @@ void CRCInput::getMsg_us(neutrino_msg_t * msg, neutrino_msg_data_t * data, uint6 } else printf("[neutrino] event - unknown initiatorID 0x%x\n", emsg.initiatorID); - if ( !dont_delete_p ) - { - delete[] p;//new [] delete [] - p= NULL; + + switch (emsg.eventID) { + case NeutrinoMessages::EVT_CURRENTEPG: + case NeutrinoMessages::EVT_NEXTEPG: + { + CSectionsdClient::CurrentNextInfo *cn = (CSectionsdClient::CurrentNextInfo *) p; + delete cn; + p = NULL; + break; + } + default: + if (!dont_delete_p) { + delete[] p; + p = NULL; + } } } } @@ -1219,25 +1222,57 @@ void CRCInput::getMsg_us(neutrino_msg_t * msg, neutrino_msg_data_t * data, uint6 for (int i = 0; i < NUMBER_OF_EVENT_DEVICES; i++) { if ((fd_rc[i] != -1) && (FD_ISSET(fd_rc[i], &rfds))) { - int ret; - ret = read(fd_rc[i], &ev, sizeof(t_input_event)); - - if(ret != sizeof(t_input_event)) + t_input_event ev; + int ret = read(fd_rc[i], &ev, sizeof(t_input_event)); + if (ret != sizeof(t_input_event)) { + if (errno == ENODEV) { + /* hot-unplugged? */ + ::close(fd_rc[i]); + fd_rc[i] = -1; + } continue; - SHTDCNT::getInstance()->resetSleepTimer(); - if (firstKey) { - firstKey = false; - CTimerManager::getInstance()->cancelShutdownOnWakeup(); } + if (ev.type == EV_SYN) + continue; /* ignore... */ + SHTDCNT::getInstance()->resetSleepTimer(); uint32_t trkey = translate(ev.code); #ifdef DEBUG - printf("key: %04x value %d, translate: %04x -%s-\n", ev.code, ev.value, trkey, getKeyName(trkey).c_str()); + printf("%d key: %04x value %d, translate: %04x -%s-\n", ev.value, ev.code, ev.value, trkey, getKeyName(trkey).c_str()); #endif if (trkey == RC_nokey) continue; + + if (g_settings.longkeypress_duration > LONGKEYPRESS_OFF) { + uint64_t longPressNow = time_monotonic_us(); + if (ev.value == 0 && longPressEnd) { + if (longPressNow < longPressEnd) { + // Key was a potential long press, but wasn't pressed long enough + longPressEnd = 0; + ev.value = 1; + } else { + // Long-press, key released after time limit + longPressEnd = 0; + continue; + } + } else if (ev.value == 1 && mayLongPress(trkey, bAllowRepeatLR)) { + // A long-press may start here. + longPressEnd = longPressNow + 1000 * g_settings.longkeypress_duration; + rc_last_key = KEY_MAX; + continue; + } else if (ev.value == 2 && longPressEnd) { + if (longPressEnd < longPressNow) { + // Key was pressed long enough. + ev.value = 1; + trkey |= RC_Repeat; + } else { + // Long-press, but key still not released. Skip. + continue; + } + } + } + if (ev.value) { #ifdef RCDEBUG - printf("got keydown native key: %04x %04x, translate: %04x -%s-\n", ev.code, ev.code&0x1f, translate(ev.code, 0), getKeyName(translate(ev.code, 0)).c_str()); printf("rc_last_key %04x rc_last_repeat_key %04x\n\n", rc_last_key, rc_last_repeat_key); #endif uint64_t now_pressed; @@ -1245,21 +1280,17 @@ void CRCInput::getMsg_us(neutrino_msg_t * msg, neutrino_msg_data_t * data, uint6 tv = ev.time; now_pressed = (uint64_t) tv.tv_usec + (uint64_t)((uint64_t) tv.tv_sec * (uint64_t) 1000000); - if (ev.code == rc_last_key) { + if (trkey == rc_last_key) { /* only allow selected keys to be repeated */ - /* (why?) */ - if( (trkey == RC_up) || (trkey == RC_down ) || - (trkey == RC_plus ) || (trkey == RC_minus ) || - (trkey == RC_page_down ) || (trkey == RC_page_up ) || - ((bAllowRepeatLR) && ((trkey == RC_left ) || (trkey == RC_right))) || - (g_settings.shutdown_real_rcdelay && ((trkey == RC_standby) && (cs_get_revision() > 7))) ) + if (mayRepeat(trkey, bAllowRepeatLR) || + (g_settings.shutdown_real_rcdelay && ((trkey == RC_standby) && (cs_get_revision() > 7))) ) { #ifdef ENABLE_REPEAT_CHECK - if (rc_last_repeat_key != ev.code) { + if (rc_last_repeat_key != trkey) { if ((now_pressed > last_keypress + repeat_block) || /* accept all keys after time discontinuity: */ (now_pressed < last_keypress)) - rc_last_repeat_key = ev.code; + rc_last_repeat_key = trkey; else keyok = false; } @@ -1271,7 +1302,7 @@ void CRCInput::getMsg_us(neutrino_msg_t * msg, neutrino_msg_data_t * data, uint6 else rc_last_repeat_key = KEY_MAX; - rc_last_key = ev.code; + rc_last_key = trkey; if (keyok) { #ifdef ENABLE_REPEAT_CHECK @@ -1292,9 +1323,6 @@ void CRCInput::getMsg_us(neutrino_msg_t * msg, neutrino_msg_data_t * data, uint6 } /* if (ev.value) */ else { // clear rc_last_key on keyup event -#ifdef RCDEBUG - printf("got keyup native key: %04x %04x, translate: %04x -%s-\n", ev.code, ev.code&0x1f, translate(ev.code, 0), getKeyName(translate(ev.code, 0)).c_str() ); -#endif rc_last_key = KEY_MAX; if (trkey == RC_standby) { *msg = RC_standby; @@ -1329,12 +1357,7 @@ void CRCInput::getMsg_us(neutrino_msg_t * msg, neutrino_msg_data_t * data, uint6 else { //timeout neu kalkulieren -#ifdef USE_GETTIMEOFDAY - gettimeofday( &tv, NULL ); - int64_t getKeyNow = (int64_t) tv.tv_usec + (int64_t)((int64_t) tv.tv_sec * (int64_t) 1000000); -#else int64_t getKeyNow = time_monotonic_us(); -#endif int64_t diff = (getKeyNow - getKeyBegin); if( Timeout <= (uint64_t) diff ) { @@ -1485,20 +1508,6 @@ const char * CRCInput::getSpecialKeyName(const unsigned int key) return "radio"; case RC_text: return "text"; -#if 0 - case RC_shift_red: - return "shift-red"; - case RC_shift_green: - return "shift-green"; - case RC_shift_yellow: - return "shift-yellow"; - case RC_shift_blue: - return "shift-blue"; - case RC_shift_tv: - return "shift-tv"; - case RC_shift_radio: - return "shift-radio"; -#endif case RC_epg: return "epg"; case RC_recall: @@ -1566,16 +1575,24 @@ const char * CRCInput::getSpecialKeyName(const unsigned int key) } std::string CRCInput::getKeyName(const unsigned int key) +{ + std::string res(getKeyNameC(key & ~RC_Repeat)); + if ((key & RC_Repeat) && res != "unknown") + res += " (long)"; + return res; +} + +const char *CRCInput::getKeyNameC(const unsigned int key) { int lunicode_value = getUnicodeValue(key); if (lunicode_value == -1) return getSpecialKeyName(key); else { - char tmp[2]; + static char tmp[2]; tmp[0] = lunicode_value; tmp[1] = 0; - return std::string(tmp); + return tmp; } } @@ -1585,8 +1602,15 @@ std::string CRCInput::getKeyName(const unsigned int key) **************************************************************************/ int CRCInput::translate(int code) { - if(code == 0x100) code = RC_up; - else if(code == 0x101) code = RC_down; + switch(code) + { + case 0x100: // FIXME -- needed? + return RC_up; + case 0x101: // FIXME -- needed? + return RC_down; + default: + break; + } if ((code >= 0) && (code <= KEY_MAX)) return code; diff --git a/src/driver/rcinput.h b/src/driver/rcinput.h index 228374297..bee874e6a 100644 --- a/src/driver/rcinput.h +++ b/src/driver/rcinput.h @@ -115,8 +115,8 @@ */ -typedef uint32_t neutrino_msg_t; -typedef uint32_t neutrino_msg_data_t; +typedef unsigned long neutrino_msg_t; +typedef unsigned long neutrino_msg_data_t; #define NEUTRINO_UDS_NAME "/tmp/neutrino.sock" @@ -141,6 +141,9 @@ class CRCInput uint32_t timerid; std::vector timers; + uint32_t *repeatkeys; + uint64_t longPressEnd; + bool longPressAny; int fd_pipe_high_priority[2]; int fd_pipe_low_priority[2]; int fd_gamerc; @@ -151,15 +154,16 @@ class CRCInput int fd_max; int clickfd; - bool firstKey; __u16 rc_last_key; void set_dsp(); - void open(); + void open(int dev = -1); void close(); int translate(int code); void calculateMaxFd(void); int checkTimers(); + bool mayRepeat(uint32_t key, bool bAllowRepeatLR = false); + bool mayLongPress(uint32_t key, bool bAllowRepeatLR = false); #ifdef IOC_IR_SET_PRI_PROTOCOL void set_rc_hw(ir_protocol_t ir_protocol, unsigned int ir_address); #endif @@ -287,8 +291,10 @@ class CRCInput static int getNumericValue(const neutrino_msg_t key); static unsigned int convertDigitToKey(const unsigned int digit); static int getUnicodeValue(const neutrino_msg_t key); + uint32_t *setAllowRepeat(uint32_t *); static const char * getSpecialKeyName(const unsigned int key); + static const char *getKeyNameC(const unsigned int key); static std::string getKeyName(const unsigned int key); int addTimer(uint64_t Interval, bool oneshot= true, bool correct_time= true ); @@ -312,6 +318,8 @@ class CRCInput void close_click(); void play_click(); void reset_dsp(int rate); + + void setLongPressAny(bool b) { longPressAny = b; }; }; diff --git a/src/gui/keybind_setup.cpp b/src/gui/keybind_setup.cpp index 08bd0ac0e..b17b8e3cf 100644 --- a/src/gui/keybind_setup.cpp +++ b/src/gui/keybind_setup.cpp @@ -194,6 +194,17 @@ const key_settings_struct_t key_settings[CKeybindSetup::KEYBINDS_COUNT] = {LOCALE_EXTRA_KEY_PIC_SIZE, &g_settings.key_pic_size_active, LOCALE_MENU_HINT_KEY_PIC_SIZE_ACTIVE } }; +// used by driver/rcinput.cpp +bool checkLongPress(uint32_t key) +{ + if (g_settings.longkeypress_duration == LONGKEYPRESS_OFF) + return false; + key |= CRCInput::RC_Repeat; + for (unsigned int i = 0; i < CKeybindSetup::KEYBINDS_COUNT; i++) + if ((uint32_t)*key_settings[i].keyvalue_p == key) + return true; + return false; +} int CKeybindSetup::showKeySetup() { @@ -242,9 +253,18 @@ int CKeybindSetup::showKeySetup() mc->setHint("", LOCALE_MENU_HINT_KEY_HARDWARE); keySettings->addItem(mc); } + std::string ms_number_format("%d "); ms_number_format += g_Locale->getText(LOCALE_UNIT_SHORT_MILLISECOND); CMenuOptionNumberChooser *cc; + + cc = new CMenuOptionNumberChooser(LOCALE_KEYBINDINGMENU_LONGKEYPRESS_DURATION, + &g_settings.longkeypress_duration, true, LONGKEYPRESS_OFF, 9999, NULL, 0, LONGKEYPRESS_OFF, LOCALE_OPTIONS_OFF); + cc->setNumberFormat(ms_number_format); + cc->setNumericInput(true); + cc->setHint("", LOCALE_MENU_HINT_LONGKEYPRESS_DURATION); + keySettings->addItem(cc); + cc = new CMenuOptionNumberChooser(LOCALE_KEYBINDINGMENU_REPEATBLOCK, &g_settings.repeat_blocker, true, 0, 999); cc->setNumberFormat(ms_number_format); diff --git a/src/gui/widget/keychooser.cpp b/src/gui/widget/keychooser.cpp index ed146b8fa..f11a0d28b 100644 --- a/src/gui/widget/keychooser.cpp +++ b/src/gui/widget/keychooser.cpp @@ -119,6 +119,7 @@ int CKeyChooserItem::exec(CMenuTarget* parent, const std::string &) paint(); g_RCInput->clearRCMsg(); + g_RCInput->setLongPressAny(true); timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_MENU] == 0 ? 0xFFFF : g_settings.timing[SNeutrinoSettings ::TIMING_MENU]); @@ -138,6 +139,7 @@ int CKeyChooserItem::exec(CMenuTarget* parent, const std::string &) goto get_Message; } + g_RCInput->setLongPressAny(false); hide(); return res; } diff --git a/src/neutrino.cpp b/src/neutrino.cpp index af3e0e685..f259ca06f 100644 --- a/src/neutrino.cpp +++ b/src/neutrino.cpp @@ -3880,6 +3880,7 @@ void CNeutrinoApp::loadKeys(const char * fname) g_settings.key_click = tconfig.getInt32( "key_click", 1 ); g_settings.repeat_blocker = tconfig.getInt32("repeat_blocker", 150); g_settings.repeat_genericblocker = tconfig.getInt32("repeat_genericblocker", 100); + g_settings.longkeypress_duration = tconfig.getInt32("longkeypress_duration", LONGKEYPRESS_OFF); g_settings.bouquetlist_mode = tconfig.getInt32( "bouquetlist_mode", 0 ); g_settings.sms_channel = tconfig.getInt32( "sms_channel", 0 ); @@ -3947,6 +3948,7 @@ void CNeutrinoApp::saveKeys(const char * fname) tconfig.setInt32( "key_click", g_settings.key_click ); tconfig.setInt32( "repeat_blocker", g_settings.repeat_blocker ); tconfig.setInt32( "repeat_genericblocker", g_settings.repeat_genericblocker ); + tconfig.setInt32( "longkeypress_duration", g_settings.longkeypress_duration ); tconfig.setInt32( "bouquetlist_mode", g_settings.bouquetlist_mode ); tconfig.setInt32( "sms_channel", g_settings.sms_channel ); diff --git a/src/system/helpers.h b/src/system/helpers.h index b494a2500..1a68cb316 100644 --- a/src/system/helpers.h +++ b/src/system/helpers.h @@ -23,6 +23,7 @@ */ #include +#include #include #include @@ -80,4 +81,6 @@ template std::string to_string(C i) return s.str(); } +inline void cstrncpy(char *dest, const char * const src, size_t n) { n--; strncpy(dest, src, n); dest[n] = 0; } +inline void cstrncpy(char *dest, const std::string &src, size_t n) { n--; strncpy(dest, src.c_str(), n); dest[n] = 0; } #endif diff --git a/src/system/locals.h b/src/system/locals.h index c6ac6e6df..d6d27d4a6 100644 --- a/src/system/locals.h +++ b/src/system/locals.h @@ -701,6 +701,7 @@ typedef enum LOCALE_KEYBINDINGMENU_CHANNELUP, LOCALE_KEYBINDINGMENU_HEAD, LOCALE_KEYBINDINGMENU_LASTCHANNEL, + LOCALE_KEYBINDINGMENU_LONGKEYPRESS_DURATION, LOCALE_KEYBINDINGMENU_MISC, LOCALE_KEYBINDINGMENU_MODE_LEFT_RIGHT_KEY_TV, LOCALE_KEYBINDINGMENU_MODE_LEFT_RIGHT_KEY_TV_INFOBAR, @@ -985,6 +986,7 @@ typedef enum LOCALE_MENU_HINT_LEDS_STANDBY, LOCALE_MENU_HINT_LEDS_TV, LOCALE_MENU_HINT_LOAD, + LOCALE_MENU_HINT_LONGKEYPRESS_DURATION, LOCALE_MENU_HINT_LUA, LOCALE_MENU_HINT_MAKE_HDLIST, LOCALE_MENU_HINT_MAKE_NEWLIST, diff --git a/src/system/locals_intern.h b/src/system/locals_intern.h index f17d1f15d..1dd98deda 100644 --- a/src/system/locals_intern.h +++ b/src/system/locals_intern.h @@ -701,6 +701,7 @@ const char * locale_real_names[] = "keybindingmenu.channelup", "keybindingmenu.head", "keybindingmenu.lastchannel", + "keybindingmenu.longkeypress_duration", "keybindingmenu.misc", "keybindingmenu.mode_left_right_key_tv", "keybindingmenu.mode_left_right_key_tv_infobar", @@ -985,6 +986,7 @@ const char * locale_real_names[] = "menu.hint_leds_standby", "menu.hint_leds_tv", "menu.hint_load", + "menu.hint_longkeypress_duration", "menu.hint_lua", "menu.hint_make_hdlist", "menu.hint_make_newlist", diff --git a/src/system/settings.h b/src/system/settings.h index b2354cbdc..460e17744 100644 --- a/src/system/settings.h +++ b/src/system/settings.h @@ -477,6 +477,8 @@ struct SNeutrinoSettings int channellist_show_channellogo; int repeat_blocker; int repeat_genericblocker; +#define LONGKEYPRESS_OFF 499 + int longkeypress_duration; int remote_control_hardware; int audiochannel_up_down_enable;