Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | Related Pages | Examples

ArKeyHandler.cpp

00001 /*
00002 MobileRobots Advanced Robotics Interface for Applications (ARIA)
00003 Copyright (C) 2004, 2005 ActivMedia Robotics LLC
00004 Copyright (C) 2006, 2007 MobileRobots Inc.
00005 
00006      This program is free software; you can redistribute it and/or modify
00007      it under the terms of the GNU General Public License as published by
00008      the Free Software Foundation; either version 2 of the License, or
00009      (at your option) any later version.
00010 
00011      This program is distributed in the hope that it will be useful,
00012      but WITHOUT ANY WARRANTY; without even the implied warranty of
00013      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014      GNU General Public License for more details.
00015 
00016      You should have received a copy of the GNU General Public License
00017      along with this program; if not, write to the Free Software
00018      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 
00020 If you wish to redistribute ARIA under different terms, contact 
00021 MobileRobots for information about a commercial version of ARIA at 
00022 robots@mobilerobots.com or 
00023 MobileRobots Inc, 19 Columbia Drive, Amherst, NH 03031; 800-639-9481
00024 */
00025 
00026 #include "ArExport.h"
00027 #include "ariaOSDef.h"
00028 #include "ArKeyHandler.h"
00029 #include "ArLog.h"
00030 
00031 #ifdef WIN32
00032 #include <conio.h>
00033 #else // if not win32
00034 #include <stdio.h>
00035 #endif
00036 
00037 #include "ariaInternal.h"
00038 
00045 AREXPORT ArKeyHandler::ArKeyHandler(bool blocking, bool addAriaExitCB) :
00046   myAriaExitCB(this, &ArKeyHandler::restore)
00047 {
00048   myAriaExitCB.setName("ArKeyHandlerExit");
00049   if (addAriaExitCB)
00050     Aria::addExitCallback(&myAriaExitCB);
00051   takeKeys(blocking);
00052 }
00053 
00054 AREXPORT ArKeyHandler::~ArKeyHandler()
00055 {
00056   restore();
00057 }
00058 
00059 AREXPORT void ArKeyHandler::takeKeys(bool blocking)
00060 {
00061   myBlocking = blocking;
00062 #ifndef WIN32
00063   struct termios newTermios;
00064 
00065   tcgetattr(fileno(stdin), &myOriginalTermios);
00066   
00067   tcgetattr(fileno(stdin), &newTermios);
00068   
00069   newTermios.c_cc[VTIME] = 0;
00070   if (myBlocking)
00071   {
00072     newTermios.c_cc[VMIN] = 1;
00073   }
00074   else
00075   {
00076 /*
00077   We need 0 here for linux (otherwise the read blocks) but we need 1
00078   for mac osx, there's probably better def to check someday.
00079 */
00080 #ifdef linux
00081     newTermios.c_cc[VMIN] = 0;
00082 #else 
00083     newTermios.c_cc[VMIN] = 1;
00084 #endif 
00085   }
00086   newTermios.c_lflag &= (~ECHO & ~ICANON);
00087   tcsetattr(fileno(stdin), TCSANOW, &newTermios);
00088 
00089 #endif
00090   myRestored = false;
00091 }
00092 
00093 AREXPORT void ArKeyHandler::restore(void)
00094 {
00095 #ifndef WIN32
00096   tcsetattr(fileno(stdin), TCSANOW, &myOriginalTermios);
00097 
00098 #endif
00099   myRestored = true;
00100 }
00101 
00113 AREXPORT bool ArKeyHandler::addKeyHandler(int keyToHandle, ArFunctor *functor)
00114 {
00115   if (myMap.find(keyToHandle) != myMap.end())
00116   {
00117     ArLog::log(ArLog::Normal, "There is already a key to handle '%c' which is number %d 0x%x", keyToHandle, keyToHandle, keyToHandle);
00118     return false;
00119   }
00120   //ArLog::log(ArLog::Verbose, "keyhandler %p added key '%c' number '%d'", 
00121   //this, keyToHandle, keyToHandle);
00122   myMap[keyToHandle] = functor;
00123 
00124   return true;
00125 }
00126 
00134 AREXPORT bool ArKeyHandler::remKeyHandler(int keyToHandle)
00135 {
00136   if (myMap.find(keyToHandle) == myMap.end())
00137   {
00138     //ArLog::log(ArLog::Normal, "There is no key to handle '%c' which is number %d 0x%x", keyToHandle, keyToHandle, keyToHandle);
00139     return false;
00140   }
00141   ArLog::log(ArLog::Verbose, "keyhandler %p removed key '%c' number '%d'",
00142          this, keyToHandle, keyToHandle);
00143   myMap.erase(keyToHandle);
00144   return true;
00145 }
00146 
00154 AREXPORT bool ArKeyHandler::remKeyHandler(ArFunctor *functor)
00155 {
00156   std::map<int, ArFunctor *>::iterator it;
00157   std::list<std::map<int, ArFunctor *>::iterator> iters;
00158   std::list<std::map<int, ArFunctor *>::iterator>::iterator iterIter;
00159 
00160   for (it = myMap.begin(); it != myMap.end(); ++it)
00161   {
00162     if (it->second == functor)
00163     {
00164       iters.push_front(it);
00165     }
00166   }
00167   if (iters.size() > 0)
00168   {
00169     while((iterIter = iters.begin()) != iters.end())
00170     {
00171       myMap.erase((*iterIter));
00172       iters.pop_front();
00173     }
00174     ArLog::log(ArLog::Verbose, "keyhandler %p removed functor %p", this, 
00175            functor);
00176     return true;
00177   }
00178   return false;
00179 }
00180 
00181 AREXPORT void ArKeyHandler::checkKeys(void)
00182 {
00183   int key;
00184   std::map<int, ArFunctor *>::iterator it;
00185 
00186   if (myRestored)
00187     return;
00188 
00189   // get keys until they're gone
00190   while (!myRestored && (key = getKey()) != -1)
00191   {
00192     // if there's something to handle it, handle it
00193     if ((it = myMap.find(key)) != myMap.end())
00194     {
00195       //ArLog::log(ArLog::Verbose, "key '%c' num %d pressed\n", key, key);
00196       it->second->invoke();
00197     }
00198   }
00199 }
00200 
00201 #ifndef WIN32
00202 
00203 AREXPORT int ArKeyHandler::getKey(void)
00204 {
00205  /*
00206   * What follows is a somewhat poor implementation of getch(), basically, since
00207   * we want to get control keys but don't want to have to use curses.
00208   */
00209 
00210   int key;
00211   int k[5] = {-1, -1, -1, -1, -1};   // used for escape sequences
00212 
00213   key = getchar();
00214   switch(key)
00215   {
00216     case -1:
00217     case 0:
00218       return -1;
00219 
00220     //case -1: return ESCAPE; //?
00221     case ' ': return SPACE;
00222     case '\t': return TAB;
00223     case 10: return ENTER;
00224     case 8: return BACKSPACE;
00225     case 127: return BACKSPACE;
00226 
00227     case 27: // Escape key, or Begin special control key sequence
00228       key = getchar();
00229       switch(key)
00230       {
00231         case -1: return ESCAPE;
00232         case 79: // first four F keys
00233           key = getchar();
00234           switch(key)
00235           {
00236             case 80: return F1;
00237             case 81: return F2;
00238             case 82: return F3;
00239             case 83: return F4;
00240             case 70: return END;
00241             case 72: return HOME;
00242             default: return key;
00243           }
00244         case '[':  // keypad keys and extended F-key sequences start with this 
00245           // Read in all characters in the special key sequence. -1 is the
00246           // terminator (no more keys). We also check for the beginning of a new special key
00247           // sequence (27) since if the key repeat is high enough, they begin
00248           // overlapping. TODO: check trailing keys for modifiers line shift and set an
00249           // (optional parameter) bitmask.
00250           for(short i = 0; key != -1 && key != 27 && i < 5; i++) 
00251           {
00252             k[i] = key = getchar();
00253             //printf("ArKeyHandler::getKey: read extended key component %d/%d.\n", k[i], key);
00254           }
00255           ungetc(key, stdin); // put last key back. (Esp. important if it was the beginning of a new control sequence (27).
00256 
00257           switch(k[0])
00258           {
00259             case 65: return UP;
00260             case 66: return DOWN;
00261             case 67: return RIGHT;
00262             case 68: return LEFT; 
00263 
00264             case 51: return DEL;
00265             case 53: return PAGEUP;
00266             case 54: return PAGEDOWN;
00267 
00268             case 50: 
00269               switch(k[1])
00270               {
00271                 case 126: return INSERT;
00272                 case 48:  return F9;
00273                 case 49:  return F10;
00274                 case 51:  return F11;
00275                 case 52:  return F12;
00276               }
00277               return k[1];
00278 
00279 
00280             case 49:
00281               switch(k[1])
00282               {
00283                 case 53: return F5;
00284                 case 55: return F6;
00285                 case 56: return F7;
00286                 case 57: return F8;
00287               }
00288               return k[1];
00289             default: return -1;
00290           }
00291         default: return -1;
00292       }
00293 
00294     default: return key;
00295   }
00296 }
00297 
00298 #if 0
00299 /* This is a previous implementation of getKey(), just for reference or
00300  * quick reversion: */
00301 AREXPORT int ArKeyHandler::getKey(void)
00302 {
00303   char key;
00304 
00305   key = getchar();
00306   if (key == -1 || key == 0)
00307       return -1;
00308 
00309   if (key == 27)
00310   {
00311     key = getchar();
00312     if (key == '[')
00313     {
00314       key = getchar();
00315       if (key == 'A')
00316         return UP;
00317       else if (key == 'B')
00318         return DOWN;
00319       else if (key == 'C')
00320         return RIGHT;
00321       else if (key == 'D')
00322         return LEFT;
00323       else
00324         return getKey();
00325     }
00326     else if (key == -1)
00327       return ESCAPE;
00328     else if (key == 79)
00329     {
00330        key = getchar();
00331        if (key == 'P')
00332          return F1;
00333        else if (key == 'Q')
00334          return F2;
00335        else if (key == 'R')
00336          return F3;
00337        else if (key == 'S')
00338          return F4;
00339        else
00340          return getKey();
00341     }
00342   }
00343   else if (key == ' ')
00344     return SPACE;
00345   else if (key == '\t')
00346     return TAB;
00347   else if (key == 10)
00348     return ENTER;
00349   else if (key == 8 || key == 127)
00350     return BACKSPACE;
00351   return key;
00352 }
00353 #endif
00354 
00355 
00356 #else // if it is win32
00357 
00358 AREXPORT int ArKeyHandler::getKey(void)
00359 {
00360   int key;
00361 
00362   if (!myBlocking && !kbhit())
00363     return -1;
00364 
00365   key = _getch();
00366   if (key == 224)
00367   {
00368     key = _getch();
00369     if (key == 'H')
00370       return UP;
00371     else if (key == 'P')
00372       return DOWN;
00373     else if (key == 'K')
00374       return LEFT;
00375     else if (key == 'M')
00376       return RIGHT;
00377     else 
00378       return getKey();
00379   }
00380   else if (key == 0)
00381   {
00382     key = _getch();
00383     if (key == ';')
00384       return F1;
00385     else if (key == '<')
00386       return F2;
00387     else if (key == '=')
00388       return F3;
00389     else if (key == '>')
00390       return F4;
00391     else if (key == 'H')
00392       return UP;
00393     else if (key == 'P')
00394       return DOWN;
00395     else if (key == 'K')
00396       return LEFT;
00397     else if (key == 'M')
00398       return RIGHT;
00399     else
00400       return getKey();
00401   }
00402   else if (key == ' ')
00403     return SPACE;
00404   else if (key == '\t')
00405     return TAB;
00406   else if (key == 13)
00407     return ENTER;
00408   else if (key == 8)
00409     return BACKSPACE;
00410   else if (key == 27)
00411     return ESCAPE;
00412 
00413   return key;
00414 
00415 }
00416 
00417 #endif // WIN32
00418 

Generated on Tue Feb 20 10:51:40 2007 for Aria by  doxygen 1.4.0