driver/rcinput: implement long key press support (but no rcsim/yWeb support at this time)

driver/rcinput: drop unused gettimeofday code
This commit is contained in:
martii
2014-02-25 00:09:14 +01:00
committed by svenhoefer
parent 9184ac6266
commit 7826ab0fca
11 changed files with 215 additions and 146 deletions

View File

@@ -5,6 +5,7 @@
2003 thegoodguy
Copyright (C) 2008-2012 Stefan Seyfried
Copyright (C) 2013-2014 martii
License: GPL
@@ -29,6 +30,7 @@
#include <driver/rcinput.h>
#include <driver/abstime.h>
#include <system/helpers.h>
#include <stdio.h>
#include <asm/types.h>
@@ -42,6 +44,7 @@
#endif /* KEYBOARD_INSTEAD_OF_REMOTE_CONTROL */
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/un.h>
#include <sys/socket.h>
@@ -51,12 +54,14 @@
#include <global.h>
#include <driver/shutdown_count.h>
#include <neutrino.h>
//#include <neutrino.h>
#include <neutrinoMessages.h>
#include <timerd/timermanager.h>
#include <timerdclient/timerdclient.h>
#include <sectionsdclient/sectionsdclient.h>
#include <cs_api.h>
//#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 <dev>, 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<timer>::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<timer>::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;