Fawkes API  Fawkes Development Version
getkey.cpp
1 /***************************************************************************
2  * getkey.cpp - getkey returns a keypress in non-blocking manner
3  *
4  * Created: Thu Jun 04 19:08:13 2009 (from RCSoftX)
5  * Copyright 2009 Masrur Doostdar <doostdar@kbsg.rwth-aachen.de>
6  *
7  ****************************************************************************/
8 
9 /* This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU Library General Public License for more details.
18  *
19  * Read the full text in the LICENSE.GPL file in the doc directory.
20  */
21 
22 #include <utils/system/getkey.h>
23 #include <core/exception.h>
24 #include <cerrno>
25 #include <cstdio>
26 #include <unistd.h>
27 #include <termios.h>
28 #include <fcntl.h>
29 
30 
31 namespace fawkes {
32 
33 /** Set non-blocking flag on STDIN.
34  * Sets the 0_NONBLOCK Flag to 1, so that the read command in the
35  * getkey()-method wont block the programm till a input is made (see also
36  * libc manual, pages 105 and 117).
37  */
38 static void
40 {
41  int oldflags;
42 
43  oldflags = fcntl(STDIN_FILENO, F_GETFL, 0);
44  oldflags |= O_NONBLOCK;
45  fcntl(STDIN_FILENO, F_SETFL, oldflags);
46 }
47 
48 
49 /** Clear non-blocking flag on STDIN. */
50 static void
52 {
53  int oldflags;
54 
55  oldflags = fcntl(STDIN_FILENO, F_GETFL, 0);
56  oldflags &= ~O_NONBLOCK;
57  fcntl(STDIN_FILENO, F_SETFL, oldflags);
58 }
59 
60 
61 /** Get value of a single key-press non-blocking.
62  * This method checks if a new keypress has happened and returns the value in
63  * this case. Otherwise it returns 0. The method does not block.
64  * @param timeout_decisecs If less than 0 wait forever, if 0 non-blocking
65  * (returns 0 if no key pressed immediately, if greater than 0 it is the
66  * timeout in deciseconds.
67  * @return key pressed or 0 (no key read)
68  */
69 char
70 getkey(int timeout_decisecs)
71 {
72  bool blocking = (timeout_decisecs != 0);
73  char buf[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
74  struct termios tattr, // new terminal attributes
75  saved_attributes; // restore the original settings
76 
77  if (! blocking) set_nonblock_flag();
78  tcgetattr(STDIN_FILENO, &saved_attributes); // save the original attributes
79 
80  tcgetattr(STDIN_FILENO, &tattr); // set the new attributes
81  tattr.c_lflag &= ~(ICANON); // Clear ICANON
82  tattr.c_lflag &= ~(ECHO); // and ECHO
83  if (timeout_decisecs < 0) {
84  tattr.c_cc[VMIN] = 1; // wait for one byte
85  tattr.c_cc[VTIME]= 0; // no timeout
86  } else if (timeout_decisecs > 0) {
87  tattr.c_cc[VMIN] = 0; // do not wait for incoming bytes
88  tattr.c_cc[VTIME]= timeout_decisecs; // timeout
89  } else {
90  tattr.c_cc[VMIN] = 0; // do not wait for incoming bytes
91  tattr.c_cc[VTIME]= 0; // no timeout
92  }
93  tcsetattr(STDIN_FILENO, TCSANOW, &tattr);
94 
95  ssize_t read_bytes = read(STDIN_FILENO, buf, 1);
96 
97  tcsetattr(STDIN_FILENO, TCSANOW, &saved_attributes);
98  if (! blocking) clear_nonblock_flag();
99 
100  if (read_bytes == 1) {
101  return buf[0];
102  } else {
103  throw Exception(errno, "Failed to read key from keyboard (getkey)");
104  }
105 }
106 
107 } // end namespace fawkes
108 
static void set_nonblock_flag()
Set non-blocking flag on STDIN.
Definition: getkey.cpp:39
Fawkes library namespace.
char getkey(int timeout_decisecs)
Get value of a single key-press non-blocking.
Definition: getkey.cpp:70
Base class for exceptions in Fawkes.
Definition: exception.h:36
static void clear_nonblock_flag()
Clear non-blocking flag on STDIN.
Definition: getkey.cpp:51