vdr  1.7.27
remote.c
Go to the documentation of this file.
00001 /*
00002  * remote.c: General Remote Control handling
00003  *
00004  * See the main source file 'vdr.c' for copyright information and
00005  * how to reach the author.
00006  *
00007  * $Id: remote.c 2.5 2012/01/16 16:57:00 kls Exp $
00008  */
00009 
00010 #include "remote.h"
00011 #include <fcntl.h>
00012 #define __STDC_FORMAT_MACROS // Required for format specifiers
00013 #include <inttypes.h>
00014 #include <netinet/in.h>
00015 #include <string.h>
00016 #include <sys/types.h>
00017 #include <sys/time.h>
00018 #include <unistd.h>
00019 #include "tools.h"
00020 
00021 // --- cRemote ---------------------------------------------------------------
00022 
00023 #define INITTIMEOUT   10000 // ms
00024 #define REPEATTIMEOUT  1000 // ms
00025 
00026 eKeys cRemote::keys[MaxKeys];
00027 int cRemote::in = 0;
00028 int cRemote::out = 0;
00029 cTimeMs cRemote::repeatTimeout(-1);
00030 cRemote *cRemote::learning = NULL;
00031 char *cRemote::unknownCode = NULL;
00032 cMutex cRemote::mutex;
00033 cCondVar cRemote::keyPressed;
00034 const char *cRemote::keyMacroPlugin = NULL;
00035 const char *cRemote::callPlugin = NULL;
00036 bool cRemote::enabled = true;
00037 time_t cRemote::lastActivity = 0;
00038 
00039 cRemote::cRemote(const char *Name)
00040 {
00041   name = Name ? strdup(Name) : NULL;
00042   Remotes.Add(this);
00043 }
00044 
00045 cRemote::~cRemote()
00046 {
00047   Remotes.Del(this, false);
00048   free(name);
00049 }
00050 
00051 const char *cRemote::GetSetup(void)
00052 {
00053   return Keys.GetSetup(Name());
00054 }
00055 
00056 void cRemote::PutSetup(const char *Setup)
00057 {
00058   Keys.PutSetup(Name(), Setup);
00059 }
00060 
00061 bool cRemote::Initialize(void)
00062 {
00063   if (Ready()) {
00064      char *NewCode = NULL;
00065      eKeys Key = Get(INITTIMEOUT, &NewCode);
00066      if (Key != kNone || NewCode)
00067         return true;
00068      }
00069   return false;
00070 }
00071 
00072 void cRemote::Clear(void)
00073 {
00074   cMutexLock MutexLock(&mutex);
00075   in = out = 0;
00076   if (learning) {
00077      free(unknownCode);
00078      unknownCode = NULL;
00079      }
00080 }
00081 
00082 bool cRemote::Put(eKeys Key, bool AtFront)
00083 {
00084   if (Key != kNone) {
00085      cMutexLock MutexLock(&mutex);
00086      if (in != out && (keys[out] & k_Repeat) && (Key & k_Release))
00087         Clear();
00088      int d = out - in;
00089      if (d <= 0)
00090         d = MaxKeys + d;
00091      if (d - 1 > 0) {
00092         if (AtFront) {
00093            if (--out < 0)
00094               out = MaxKeys - 1;
00095            keys[out] = Key;
00096            }
00097         else {
00098            keys[in] = Key;
00099            if (++in >= MaxKeys)
00100               in = 0;
00101            }
00102         keyPressed.Broadcast();
00103         return true;
00104         }
00105      return false;
00106      }
00107   return true; // only a real key shall report an overflow!
00108 }
00109 
00110 bool cRemote::PutMacro(eKeys Key)
00111 {
00112   const cKeyMacro *km = KeyMacros.Get(Key);
00113   if (km) {
00114      keyMacroPlugin = km->Plugin();
00115      cMutexLock MutexLock(&mutex);
00116      for (int i = km->NumKeys(); --i > 0; ) {
00117          if (!Put(km->Macro()[i], true))
00118             return false;
00119          }
00120      }
00121   return true;
00122 }
00123 
00124 bool cRemote::Put(uint64_t Code, bool Repeat, bool Release)
00125 {
00126   char buffer[32];
00127   snprintf(buffer, sizeof(buffer), "%016"PRIX64, Code);
00128   return Put(buffer, Repeat, Release);
00129 }
00130 
00131 bool cRemote::Put(const char *Code, bool Repeat, bool Release)
00132 {
00133   if (learning && this != learning)
00134      return false;
00135   eKeys Key = Keys.Get(Name(), Code);
00136   if (Key != kNone) {
00137      if (Repeat)
00138         Key = eKeys(Key | k_Repeat);
00139      if (Release)
00140         Key = eKeys(Key | k_Release);
00141      return Put(Key);
00142      }
00143   if (learning) {
00144      free(unknownCode);
00145      unknownCode = strdup(Code);
00146      keyPressed.Broadcast();
00147      }
00148   return false;
00149 }
00150 
00151 bool cRemote::CallPlugin(const char *Plugin)
00152 {
00153   cMutexLock MutexLock(&mutex);
00154   if (!callPlugin) {
00155      callPlugin = Plugin;
00156      Put(k_Plugin);
00157      return true;
00158      }
00159   return false;
00160 }
00161 
00162 const char *cRemote::GetPlugin(void)
00163 {
00164   cMutexLock MutexLock(&mutex);
00165   const char *p = keyMacroPlugin;
00166   if (p)
00167      keyMacroPlugin = NULL;
00168   else {
00169      p = callPlugin;
00170      callPlugin = NULL;
00171      }
00172   return p;
00173 }
00174 
00175 bool cRemote::HasKeys(void)
00176 {
00177   cMutexLock MutexLock(&mutex);
00178   return in != out && !(keys[out] & k_Repeat);
00179 }
00180 
00181 eKeys cRemote::Get(int WaitMs, char **UnknownCode)
00182 {
00183   for (;;) {
00184       cMutexLock MutexLock(&mutex);
00185       if (in != out) {
00186          eKeys k = keys[out];
00187          if (++out >= MaxKeys)
00188             out = 0;
00189          if ((k & k_Repeat) != 0)
00190             repeatTimeout.Set(REPEATTIMEOUT);
00191          TriggerLastActivity();
00192          return enabled ? k : kNone;
00193          }
00194       else if (!WaitMs || !keyPressed.TimedWait(mutex, WaitMs) && repeatTimeout.TimedOut())
00195          return kNone;
00196       else if (learning && UnknownCode && unknownCode) {
00197          *UnknownCode = unknownCode;
00198          unknownCode = NULL;
00199          return kNone;
00200          }
00201       }
00202 }
00203 
00204 void cRemote::TriggerLastActivity(void)
00205 {
00206   lastActivity = time(NULL);
00207 }
00208 
00209 // --- cRemotes --------------------------------------------------------------
00210 
00211 cRemotes Remotes;
00212 
00213 // --- cKbdRemote ------------------------------------------------------------
00214 
00215 struct tKbdMap {
00216   eKbdFunc func;
00217   uint64_t code;
00218   };
00219 
00220 static tKbdMap KbdMap[] = {
00221   { kfF1,     0x0000001B5B31317EULL },
00222   { kfF2,     0x0000001B5B31327EULL },
00223   { kfF3,     0x0000001B5B31337EULL },
00224   { kfF4,     0x0000001B5B31347EULL },
00225   { kfF5,     0x0000001B5B31357EULL },
00226   { kfF6,     0x0000001B5B31377EULL },
00227   { kfF7,     0x0000001B5B31387EULL },
00228   { kfF8,     0x0000001B5B31397EULL },
00229   { kfF9,     0x0000001B5B32307EULL },
00230   { kfF10,    0x0000001B5B32317EULL },
00231   { kfF11,    0x0000001B5B32327EULL },
00232   { kfF12,    0x0000001B5B32337EULL },
00233   { kfUp,     0x00000000001B5B41ULL },
00234   { kfDown,   0x00000000001B5B42ULL },
00235   { kfLeft,   0x00000000001B5B44ULL },
00236   { kfRight,  0x00000000001B5B43ULL },
00237   { kfHome,   0x00000000001B5B48ULL },
00238   { kfEnd,    0x00000000001B5B46ULL },
00239   { kfPgUp,   0x000000001B5B357EULL },
00240   { kfPgDown, 0x000000001B5B367EULL },
00241   { kfIns,    0x000000001B5B327EULL },
00242   { kfDel,    0x000000001B5B337EULL },
00243   { kfNone,   0x0000000000000000ULL }
00244   };
00245 
00246 bool cKbdRemote::kbdAvailable = false;
00247 bool cKbdRemote::rawMode = false;
00248 
00249 cKbdRemote::cKbdRemote(void)
00250 :cRemote("KBD")
00251 ,cThread("KBD remote control")
00252 {
00253   tcgetattr(STDIN_FILENO, &savedTm);
00254   struct termios tm;
00255   if (tcgetattr(STDIN_FILENO, &tm) == 0) {
00256      tm.c_iflag = 0;
00257      tm.c_lflag &= ~(ICANON | ECHO);
00258      tm.c_cc[VMIN] = 0;
00259      tm.c_cc[VTIME] = 0;
00260      tcsetattr(STDIN_FILENO, TCSANOW, &tm);
00261      }
00262   kbdAvailable = true;
00263   Start();
00264 }
00265 
00266 cKbdRemote::~cKbdRemote()
00267 {
00268   kbdAvailable = false;
00269   Cancel(3);
00270   tcsetattr(STDIN_FILENO, TCSANOW, &savedTm);
00271 }
00272 
00273 void cKbdRemote::SetRawMode(bool RawMode)
00274 {
00275   rawMode = RawMode;
00276 }
00277 
00278 uint64_t cKbdRemote::MapFuncToCode(int Func)
00279 {
00280   for (tKbdMap *p = KbdMap; p->func != kfNone; p++) {
00281       if (p->func == Func)
00282          return p->code;
00283       }
00284   return (Func <= 0xFF) ? Func : 0;
00285 }
00286 
00287 int cKbdRemote::MapCodeToFunc(uint64_t Code)
00288 {
00289   for (tKbdMap *p = KbdMap; p->func != kfNone; p++) {
00290       if (p->code == Code)
00291          return p->func;
00292       }
00293   if (Code <= 0xFF)
00294      return Code;
00295   return kfNone;
00296 }
00297 
00298 int cKbdRemote::ReadKey(void)
00299 {
00300   cPoller Poller(STDIN_FILENO);
00301   if (Poller.Poll(50)) {
00302      uchar ch = 0;
00303      int r = safe_read(STDIN_FILENO, &ch, 1);
00304      if (r == 1)
00305         return ch;
00306      if (r < 0)
00307         LOG_ERROR_STR("cKbdRemote");
00308      }
00309   return -1;
00310 }
00311 
00312 uint64_t cKbdRemote::ReadKeySequence(void)
00313 {
00314   uint64_t k = 0;
00315   int key1;
00316 
00317   if ((key1 = ReadKey()) >= 0) {
00318      k = key1;
00319      if (key1 == 0x1B) {
00320         // Start of escape sequence
00321         if ((key1 = ReadKey()) >= 0) {
00322            k <<= 8;
00323            k |= key1 & 0xFF;
00324            switch (key1) {
00325              case 0x4F: // 3-byte sequence
00326                   if ((key1 = ReadKey()) >= 0) {
00327                      k <<= 8;
00328                      k |= key1 & 0xFF;
00329                      }
00330                   break;
00331              case 0x5B: // 3- or more-byte sequence
00332                   if ((key1 = ReadKey()) >= 0) {
00333                      k <<= 8;
00334                      k |= key1 & 0xFF;
00335                      switch (key1) {
00336                        case 0x31 ... 0x3F: // more-byte sequence
00337                        case 0x5B: // strange, may apparently occur
00338                             do {
00339                                if ((key1 = ReadKey()) < 0)
00340                                   break; // Sequence ends here
00341                                k <<= 8;
00342                                k |= key1 & 0xFF;
00343                                } while (key1 != 0x7E);
00344                             break;
00345                        default: ;
00346                        }
00347                      }
00348                   break;
00349              default: ;
00350              }
00351            }
00352         }
00353      }
00354   return k;
00355 }
00356 
00357 void cKbdRemote::Action(void)
00358 {
00359   while (Running()) {
00360         uint64_t Command = ReadKeySequence();
00361         if (Command) {
00362            if (rawMode || !Put(Command)) {
00363               int func = MapCodeToFunc(Command);
00364               if (func)
00365                  Put(KBDKEY(func));
00366               }
00367            }
00368         }
00369 }