Explicit Repeat/Release handling for remote control

This commit is contained in:
Klaus Schmidinger 2000-10-08 11:39:11 +02:00
parent 97c3bb6148
commit 605d8df72a
10 changed files with 134 additions and 80 deletions

10
HISTORY
View File

@ -221,3 +221,13 @@ Video Disk Recorder Revision History
that would display only partially).
- In normal viewing mode the '0' key now toggles between the current and the
previous channel.
2000-10-08: Version 0.66
- Remote control data is now received in a separate thread, which makes things
a lot smoother.
- Repeat and release of remote control keys is now explicitly distinguished.
- In replay mode the search forward/back and skip functions now have two modes:
Pressing the key shortly and releasing it starts the function, and pressing it
again stops it. Pressing and holding down the key starts the function and
releasing the key stops it.

4
MANUAL
View File

@ -118,8 +118,12 @@ Video Disk Recorder User's Manual
Right Runs playback forward or backward at a higher speed; press
again to resume normal speed. If in Pause mode, runs forward or
backward at a slower speed; press again to return to pause mode.
Pressing and holding down the button performs the function until
the button is released again.
- Green
Yellow Skips about 60 seconds back or forward.
Pressing and holding down the button performs the function until
the button is released again.
- Ok Brings up the replay progress display, which shows the date,
time and title of the recording, a progress bar and the
current and total time of the recording.

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: config.h 1.23 2000/10/07 17:34:23 kls Exp $
* $Id: config.h 1.24 2000/10/08 10:38:17 kls Exp $
*/
#ifndef __CONFIG_H
@ -34,9 +34,16 @@ enum eKeys { // "Up" and "Down" must be the first two keys!
kYellow,
kBlue,
k0, k1, k2, k3, k4, k5, k6, k7, k8, k9,
kNone
kNone,
// The following flags are OR'd with the above codes:
k_Repeat = 0x8000,
k_Release = 0x4000,
k_Flags = k_Repeat | k_Release,
};
#define ISNORMALKEY(k) ((k) != kNone && ((k) & k_Flags) == 0)
#define NORMALKEY(k) ((k) & ~k_Flags)
struct tKey {
eKeys type;
char *name;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: interface.c 1.22 2000/10/07 16:42:37 kls Exp $
* $Id: interface.c 1.23 2000/10/08 11:17:11 kls Exp $
*/
#include "interface.h"
@ -58,21 +58,29 @@ void cInterface::Close(void)
cDvbApi::PrimaryDvbApi->Close();
}
unsigned int cInterface::GetCh(bool Wait)
unsigned int cInterface::GetCh(bool Wait, bool *Repeat, bool *Release)
{
if (open)
cDvbApi::PrimaryDvbApi->Flush();
if (!RcIo.InputAvailable())
cFile::AnyFileReady(-1, Wait ? 1000 : 0);
unsigned int Command;
return RcIo.GetCommand(&Command) ? Command : 0;
return RcIo.GetCommand(&Command, Repeat, Release) ? Command : 0;
}
eKeys cInterface::GetKey(bool Wait)
{
if (SVDRP)
SVDRP->Process();
eKeys Key = keyFromWait != kNone ? keyFromWait : Keys.Get(GetCh(Wait));
eKeys Key = keyFromWait;
if (Key == kNone) {
bool Repeat = false, Release = false;
Key = Keys.Get(GetCh(Wait, &Repeat, &Release));
if (Repeat)
Key = eKeys(Key | k_Repeat);
if (Release)
Key = eKeys(Key | k_Release);
}
keyFromWait = kNone;
return Key;
}
@ -90,10 +98,10 @@ eKeys cInterface::Wait(int Seconds, bool KeepChar)
time_t timeout = time(NULL) + Seconds;
for (;;) {
Key = GetKey();
if (Key != kNone || time(NULL) > timeout)
if ((Key != kNone && (NORMALKEY(Key) != kOk || NORMALKEY(Key) == Key)) || time(NULL) > timeout)
break;
}
if (KeepChar)
if (KeepChar && ISNORMALKEY(Key))
keyFromWait = Key;
return Key;
}

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: interface.h 1.14 2000/10/07 16:17:53 kls Exp $
* $Id: interface.h 1.15 2000/10/08 09:51:42 kls Exp $
*/
#ifndef __INTERFACE_H
@ -22,7 +22,7 @@ private:
int cols[MaxCols];
eKeys keyFromWait;
cSVDRP *SVDRP;
unsigned int GetCh(bool Wait = true);
unsigned int GetCh(bool Wait = true, bool *Repeat = NULL, bool *Release = NULL);
void QueryKeys(void);
void HelpButton(int Index, const char *Text, eDvbColor FgColor, eDvbColor BgColor);
eKeys Wait(int Seconds = 1, bool KeepChar = false);

27
menu.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: menu.c 1.30 2000/10/03 14:06:44 kls Exp $
* $Id: menu.c 1.31 2000/10/08 10:47:17 kls Exp $
*/
#include "menu.h"
@ -94,11 +94,11 @@ eOSState cMenuEditIntItem::ProcessKey(eKeys Key)
}
newValue = *value * 10 + (Key - k0);
}
else if (Key == kLeft) { // TODO might want to increase the delta if repeated quickly?
else if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly?
newValue = *value - 1;
fresh = true;
}
else if (Key == kRight) {
else if (NORMALKEY(Key) == kRight) {
newValue = *value + 1;
fresh = true;
}
@ -211,6 +211,7 @@ void cMenuEditDayItem::Set(void)
eOSState cMenuEditDayItem::ProcessKey(eKeys Key)
{
switch (Key) {
case kLeft|k_Repeat:
case kLeft: if (d > 0)
*value = days[--d];
else if (d == 0) {
@ -225,6 +226,7 @@ eOSState cMenuEditDayItem::ProcessKey(eKeys Key)
return cMenuEditIntItem::ProcessKey(Key);
Set();
break;
case kRight|k_Repeat:
case kRight: if (d >= 0) {
*value = days[++d];
if (*value == 0) {
@ -310,7 +312,7 @@ eOSState cMenuEditTimeItem::ProcessKey(eKeys Key)
break;
}
}
else if (Key == kLeft) { // TODO might want to increase the delta if repeated quickly?
else if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly?
if (--mm < 0) {
mm = 59;
if (--hh < 0)
@ -318,7 +320,7 @@ eOSState cMenuEditTimeItem::ProcessKey(eKeys Key)
}
fresh = true;
}
else if (Key == kRight) {
else if (NORMALKEY(Key) == kRight) {
if (++mm > 59) {
mm = 0;
if (++hh > 23)
@ -377,11 +379,11 @@ eOSState cMenuEditChrItem::ProcessKey(eKeys Key)
eOSState state = cMenuEditItem::ProcessKey(Key);
if (state == osUnknown) {
if (Key == kLeft) {
if (NORMALKEY(Key) == kLeft) {
if (current > allowed)
current--;
}
else if (Key == kRight) {
else if (NORMALKEY(Key) == kRight) {
if (*(current + 1))
current++;
}
@ -455,12 +457,14 @@ char cMenuEditStrItem::Inc(char c, bool Up)
eOSState cMenuEditStrItem::ProcessKey(eKeys Key)
{
switch (Key) {
case kLeft|k_Repeat:
case kLeft: if (pos > 0) {
if (value[pos] == '^')
value[pos] = 0;
pos--;
}
break;
case kRight|k_Repeat:
case kRight: if (pos < length && value[pos] != '^' && (pos < int(strlen(value) - 1) || value[pos] != ' ')) {
if (++pos >= int(strlen(value))) {
value[pos] = ' ';
@ -468,9 +472,11 @@ eOSState cMenuEditStrItem::ProcessKey(eKeys Key)
}
}
break;
case kUp|k_Repeat:
case kUp:
case kDown|k_Repeat:
case kDown: if (pos >= 0)
value[pos] = Inc(value[pos], Key == kUp);
value[pos] = Inc(value[pos], NORMALKEY(Key) == kUp);
else
return cMenuEditItem::ProcessKey(Key);
break;
@ -1388,7 +1394,12 @@ eOSState cReplayControl::ProcessKey(eKeys Key)
return osEnd;
case kLeft: dvbApi->Backward(); break;
case kRight: dvbApi->Forward(); break;
case kLeft|k_Release:
case kRight|k_Release:
dvbApi->Play(); break;
case kGreen|k_Repeat:
case kGreen: dvbApi->Skip(-60); break;
case kYellow|k_Repeat:
case kYellow: dvbApi->Skip(60); break;
case kMenu: Hide(); return osMenu; // allow direct switching to menu
case kOk: visible ? Hide() : Show(); break;

4
osd.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: osd.c 1.7 2000/09/10 08:24:50 kls Exp $
* $Id: osd.c 1.8 2000/10/08 10:27:04 kls Exp $
*/
#include "osd.h"
@ -274,7 +274,9 @@ eOSState cOsdMenu::ProcessKey(eKeys Key)
return state;
}
switch (Key) {
case kUp|k_Repeat:
case kUp: CursorUp(); break;
case kDown|k_Repeat:
case kDown: CursorDown(); break;
case kBack: return osBack;
case kOk: if (marked >= 0) {

110
remote.c
View File

@ -6,7 +6,7 @@
*
* Ported to LIRC by Carsten Koch <Carsten.Koch@icem.de> 2000-06-16.
*
* $Id: remote.c 1.16 2000/10/08 09:25:20 kls Exp $
* $Id: remote.c 1.17 2000/10/08 11:39:11 kls Exp $
*/
#include "remote.h"
@ -69,7 +69,7 @@ bool cRcIoKBD::InputAvailable(void)
return f.Ready(false);
}
bool cRcIoKBD::GetCommand(unsigned int *Command)
bool cRcIoKBD::GetCommand(unsigned int *Command, bool *Repeat, bool *Release)
{
if (Command) {
*Command = getch();
@ -93,7 +93,7 @@ cRcIoRCU::cRcIoRCU(char *DeviceName)
address = 0xFFFF;
receivedAddress = 0;
receivedCommand = 0;
receivedData = receivedRepeat = false;
receivedData = receivedRepeat = receivedRelease = false;
lastNumber = 0;
if ((f = open(DeviceName, O_RDWR | O_NONBLOCK)) >= 0) {
struct termios t;
@ -131,8 +131,8 @@ void cRcIoRCU::Action(void)
dsyslog(LOG_INFO, "RCU remote control thread started (pid=%d)", getpid());
unsigned int LastCommand = 0;
int FirstTime = 0;
unsigned int LastCommand = 0;
for (; f >= 0;) {
@ -151,20 +151,23 @@ void cRcIoRCU::Action(void)
// This remote control sends the above command before and after
// each keypress - let's just drop this:
break;
int Now = time_ms();
if (Command != LastCommand) {
receivedAddress = Address;
receivedCommand = Command;
receivedData = true;
FirstTime = Now;
if (!receivedData) { // only accept new data the previous data has been fetched
int Now = time_ms();
if (Command != LastCommand) {
receivedAddress = Address;
receivedCommand = Command;
receivedData = true;
receivedRepeat = receivedRelease = false;
FirstTime = Now;
}
else {
if (Now - FirstTime < REPEATDELAY)
break; // repeat function kicks in after a short delay
receivedData = receivedRepeat = true;
}
LastCommand = Command;
WakeUp();
}
else {
if (Now - FirstTime < REPEATDELAY)
break; // repeat function kicks in after a short delay
receivedData = receivedRepeat = true;
}
LastCommand = Command;
WakeUp();
}
}
else
@ -172,16 +175,15 @@ void cRcIoRCU::Action(void)
}
}
else if (receivedData) { // the last data before releasing the key hasn't been fetched yet
if (receivedRepeat) { // it was a repeat, so let's drop it
//XXX replace it with "released"???
receivedData = receivedRepeat = false;
if (receivedRepeat) { // it was a repeat, so let's make it a release
receivedRepeat = false;
receivedRelease = true;
LastCommand = 0;
//XXX WakeUp();
WakeUp();
}
}
else if (receivedRepeat) { // all data has already been fetched, but the last one was a repeat
//XXX replace it with "released"???
//XXX receivedData = true;
else if (receivedRepeat) { // all data has already been fetched, but the last one was a repeat, so let's generate a release
receivedData = receivedRelease = true;
receivedRepeat = false;
LastCommand = 0;
WakeUp();
@ -266,7 +268,7 @@ void cRcIoRCU::Flush(int WaitMs)
receivedData = receivedRepeat = false;
}
bool cRcIoRCU::GetCommand(unsigned int *Command)
bool cRcIoRCU::GetCommand(unsigned int *Command, bool *Repeat, bool *Release)
{
if (receivedData) { // first we check the boolean flag without a lock, to avoid delays
@ -275,7 +277,10 @@ bool cRcIoRCU::GetCommand(unsigned int *Command)
if (receivedData) { // need to check again, since the status might have changed while waiting for the lock
if (Command)
*Command = receivedCommand;
//XXX repeat!!!
if (Repeat)
*Repeat = receivedRepeat;
if (Release)
*Release = receivedRelease;
receivedData = false;
return true;
}
@ -422,47 +427,47 @@ void cRcIoLIRC::Action(void)
int FirstTime = 0;
char buf[LIRC_BUFFER_SIZE];
char LastKeyName[LIRC_KEY_BUF];
for (; f >= 0;) {
LOCK_THREAD;
if (cFile::FileReady(f, REPEATLIMIT) && read(f, buf, sizeof(buf)) > 21) {
int count;
sscanf(buf, "%*x %x %7s", &count, keyName); // '7' in '%7s' is LIRC_KEY_BUF-1!
int Now = time_ms();
if (count == 0) {
receivedData = true;
FirstTime = Now;
if (!receivedData) { // only accept new data the previous data has been fetched
int count;
sscanf(buf, "%*x %x %7s", &count, LastKeyName); // '7' in '%7s' is LIRC_KEY_BUF-1!
int Now = time_ms();
if (count == 0) {
strcpy(keyName, LastKeyName);
receivedData = true;
receivedRepeat = receivedRelease = false;
FirstTime = Now;
}
else {
if (Now - FirstTime < REPEATDELAY)
continue; // repeat function kicks in after a short delay
receivedData = receivedRepeat = true;
}
WakeUp();
}
else {
if (Now - FirstTime < REPEATDELAY)
continue; // repeat function kicks in after a short delay
receivedData = receivedRepeat = true;
}
WakeUp();
}
else if (receivedData) { // the last data before releasing the key hasn't been fetched yet
if (receivedRepeat) { // it was a repeat, so let's drop it
//XXX replace it with "released"???
receivedData = receivedRepeat = false;
*keyName = 0;
//XXX WakeUp();
if (receivedRepeat) { // it was a repeat, so let's make it a release
receivedRepeat = false;
receivedRelease = true;
WakeUp();
}
}
else if (receivedRepeat) { // all data has already been fetched, but the last one was a repeat
//XXX replace it with "released"???
//XXX receivedData = true;
else if (receivedRepeat) { // all data has already been fetched, but the last one was a repeat, so let's generate a release
receivedData = receivedRelease = true;
receivedRepeat = false;
*keyName = 0;
WakeUp();
}
else
*keyName = 0;
}
}
bool cRcIoLIRC::GetCommand(unsigned int *Command)
bool cRcIoLIRC::GetCommand(unsigned int *Command, bool *Repeat, bool *Release)
{
if (receivedData) { // first we check the boolean flag without a lock, to avoid delays
@ -471,7 +476,10 @@ bool cRcIoLIRC::GetCommand(unsigned int *Command)
if (receivedData) { // need to check again, since the status might have changed while waiting for the lock
if (Command)
*Command = Keys.Encode(keyName);
//XXX repeat!!!
if (Repeat)
*Repeat = receivedRepeat;
if (Release)
*Release = receivedRelease;
receivedData = false;
return true;
}

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: remote.h 1.11 2000/10/07 18:50:51 kls Exp $
* $Id: remote.h 1.12 2000/10/08 11:19:17 kls Exp $
*/
#ifndef __REMOTE_H
@ -30,7 +30,7 @@ public:
virtual bool DetectCode(unsigned char *Code, unsigned short *Address) { return true; }
virtual void Flush(int WaitMs = 0) {}
virtual bool InputAvailable(void) = 0;
virtual bool GetCommand(unsigned int *Command = NULL) = 0;
virtual bool GetCommand(unsigned int *Command = NULL, bool *Repeat = NULL, bool *Release = NULL) = 0;
};
#if defined REMOTE_KBD
@ -43,7 +43,7 @@ public:
virtual ~cRcIoKBD();
virtual void Flush(int WaitMs = 0);
virtual bool InputAvailable(void);
virtual bool GetCommand(unsigned int *Command = NULL);
virtual bool GetCommand(unsigned int *Command = NULL, bool *Repeat = NULL, bool *Release = NULL);
};
#elif defined REMOTE_RCU
@ -55,7 +55,7 @@ private:
unsigned short address;
unsigned short receivedAddress;
unsigned int receivedCommand;
bool receivedData, receivedRepeat;
bool receivedData, receivedRepeat, receivedRelease;
int lastNumber;
bool SendCommand(unsigned char Cmd);
int ReceiveByte(int TimeoutMs = 0);
@ -74,7 +74,7 @@ public:
virtual bool DetectCode(unsigned char *Code, unsigned short *Address);
virtual void Flush(int WaitMs = 0);
virtual bool InputAvailable(void) { return receivedData; }
virtual bool GetCommand(unsigned int *Command = NULL);
virtual bool GetCommand(unsigned int *Command = NULL, bool *Repeat = NULL, bool *Release = NULL);
};
#elif defined REMOTE_LIRC
@ -84,13 +84,13 @@ private:
enum { LIRC_KEY_BUF = 8, LIRC_BUFFER_SIZE = 128 };
int f;
char keyName[LIRC_KEY_BUF];
bool receivedData, receivedRepeat;
bool receivedData, receivedRepeat, receivedRelease;
virtual void Action(void);
public:
cRcIoLIRC(char *DeviceName);
virtual ~cRcIoLIRC();
virtual bool InputAvailable(void) { return receivedData; }
virtual bool GetCommand(unsigned int *Command = NULL);
virtual bool GetCommand(unsigned int *Command = NULL, bool *Repeat = NULL, bool *Release = NULL);
};
#else

10
vdr.c
View File

@ -22,7 +22,7 @@
*
* The project's page is at http://www.cadsoft.de/people/kls/vdr
*
* $Id: vdr.c 1.36 2000/10/03 13:52:26 kls Exp $
* $Id: vdr.c 1.37 2000/10/08 10:32:44 kls Exp $
*/
#include <getopt.h>
@ -257,10 +257,12 @@ int main(int argc, char *argv[])
Menu = new cDirectChannelSelect(key);
break;
// Left/Right rotates trough channel groups:
case kLeft|k_Repeat:
case kLeft:
case kRight|k_Repeat:
case kRight: if (!Interface.Recording()) {
int SaveGroup = CurrentGroup;
if (key == kRight)
if (NORMALKEY(key) == kRight)
CurrentGroup = Channels.GetNextGroup(CurrentGroup) ;
else
CurrentGroup = Channels.GetPrevGroup(CurrentGroup < 1 ? 1 : CurrentGroup);
@ -271,9 +273,11 @@ int main(int argc, char *argv[])
}
break;
// Up/Down Channel Select:
case kUp|k_Repeat:
case kUp:
case kDown|k_Repeat:
case kDown: if (!Interface.Recording()) {
int n = CurrentChannel + (key == kUp ? 1 : -1);
int n = CurrentChannel + (NORMALKEY(key) == kUp ? 1 : -1);
cChannel *channel = Channels.GetByNumber(n);
if (channel)
channel->Switch();