vdr
1.7.27
|
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 }