Fawkes API  Fawkes Development Version
getkey.cpp
00001 /***************************************************************************
00002  *  getkey.cpp - getkey returns a keypress in non-blocking manner
00003  *
00004  *  Created: Thu Jun 04 19:08:13 2009 (from RCSoftX)
00005  *  Copyright  2009  Masrur Doostdar <doostdar@kbsg.rwth-aachen.de>
00006  *
00007  ****************************************************************************/
00008 
00009 /*  This program is free software; you can redistribute it and/or modify
00010  *  it under the terms of the GNU General Public License as published by
00011  *  the Free Software Foundation; either version 2 of the License, or
00012  *  (at your option) any later version.
00013  *
00014  *  This program is distributed in the hope that it will be useful,
00015  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  *  GNU Library General Public License for more details.
00018  *
00019  *  Read the full text in the LICENSE.GPL file in the doc directory.
00020  */
00021 
00022 #include <utils/system/getkey.h>
00023 #include <core/exception.h>
00024 #include <cerrno>
00025 #include <cstdio>
00026 #include <unistd.h>
00027 #include <termios.h>
00028 #include <fcntl.h>
00029 
00030 
00031 namespace fawkes {
00032 
00033 /** Set non-blocking flag on STDIN.
00034  * Sets the 0_NONBLOCK Flag to 1, so that the read command in the
00035  * getkey()-method wont block the programm till a input is made (see also
00036  * libc manual, pages 105 and 117).
00037  */
00038 static void
00039 set_nonblock_flag()  
00040 {
00041   int oldflags;
00042 
00043   oldflags  = fcntl(STDIN_FILENO, F_GETFL, 0);
00044   oldflags |= O_NONBLOCK;
00045   fcntl(STDIN_FILENO, F_SETFL, oldflags);
00046 }
00047 
00048 
00049 /** Clear non-blocking flag on STDIN. */
00050 static void
00051 clear_nonblock_flag()
00052 {
00053   int oldflags;
00054   
00055   oldflags  = fcntl(STDIN_FILENO, F_GETFL, 0);
00056   oldflags &= ~O_NONBLOCK; 
00057   fcntl(STDIN_FILENO, F_SETFL, oldflags);
00058 }
00059 
00060 
00061 /** Get value of a single key-press non-blocking.
00062  * This method checks if a new keypress has happened and returns the value in
00063  * this case. Otherwise it returns 0. The method does not block.
00064  * @param timeout_decisecs If less than 0 wait forever, if 0 non-blocking
00065  * (returns 0 if no key pressed immediately, if greater than 0 it is the
00066  * timeout in deciseconds.
00067  * @return key pressed or 0 (no key read)
00068  */
00069 char
00070 getkey(int timeout_decisecs)
00071 {
00072   bool blocking = (timeout_decisecs != 0);
00073   char buf[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
00074   struct termios tattr,              // new terminal attributes
00075     saved_attributes;                // restore the original settings
00076   
00077   if (! blocking) set_nonblock_flag();
00078   tcgetattr(STDIN_FILENO, &saved_attributes);   // save the original attributes
00079   
00080   tcgetattr(STDIN_FILENO, &tattr);        // set the new attributes
00081   tattr.c_lflag   &= ~(ICANON);           // Clear ICANON
00082   tattr.c_lflag   &= ~(ECHO);             // and ECHO
00083   if (timeout_decisecs < 0) {
00084     tattr.c_cc[VMIN] = 1;                 // wait for one byte
00085     tattr.c_cc[VTIME]= 0;                 // no timeout
00086   } else if (timeout_decisecs > 0) {
00087     tattr.c_cc[VMIN] = 0;                 // do not wait for incoming bytes
00088     tattr.c_cc[VTIME]= timeout_decisecs;  // timeout
00089   } else {
00090     tattr.c_cc[VMIN] = 0;                 // do not wait for incoming bytes
00091     tattr.c_cc[VTIME]= 0;                 // no timeout
00092   }
00093   tcsetattr(STDIN_FILENO, TCSANOW, &tattr);
00094   
00095   ssize_t read_bytes = read(STDIN_FILENO, buf, 1);
00096   
00097   tcsetattr(STDIN_FILENO, TCSANOW, &saved_attributes);
00098   if (! blocking) clear_nonblock_flag();
00099   
00100   if (read_bytes == 1) {
00101     return buf[0];
00102   } else {
00103     throw Exception(errno, "Failed to read key from keyboard (getkey)");
00104   }
00105 }
00106 
00107 } // end namespace fawkes
00108