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 <core/exception.h>
23 #include <utils/system/getkey.h>
24 
25 #include <cerrno>
26 #include <cstdio>
27 #include <fcntl.h>
28 #include <termios.h>
29 #include <unistd.h>
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 /** Clear non-blocking flag on STDIN. */
49 static void
51 {
52  int oldflags;
53 
54  oldflags = fcntl(STDIN_FILENO, F_GETFL, 0);
55  oldflags &= ~O_NONBLOCK;
56  fcntl(STDIN_FILENO, F_SETFL, oldflags);
57 }
58 
59 /** Get value of a single key-press non-blocking.
60  * This method checks if a new keypress has happened and returns the value in
61  * this case. Otherwise it returns 0. The method does not block.
62  * @param timeout_decisecs If less than 0 wait forever, if 0 non-blocking
63  * (returns 0 if no key pressed immediately, if greater than 0 it is the
64  * timeout in deciseconds.
65  * @return key pressed or 0 (no key read)
66  */
67 char
68 getkey(int timeout_decisecs)
69 {
70  bool blocking = (timeout_decisecs != 0);
71  char buf[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
72  struct termios tattr, // new terminal attributes
73  saved_attributes; // restore the original settings
74 
75  if (!blocking)
77  tcgetattr(STDIN_FILENO, &saved_attributes); // save the original attributes
78 
79  tcgetattr(STDIN_FILENO, &tattr); // set the new attributes
80  tattr.c_lflag &= ~(ICANON); // Clear ICANON
81  tattr.c_lflag &= ~(ECHO); // and ECHO
82  if (timeout_decisecs < 0) {
83  tattr.c_cc[VMIN] = 1; // wait for one byte
84  tattr.c_cc[VTIME] = 0; // no timeout
85  } else if (timeout_decisecs > 0) {
86  tattr.c_cc[VMIN] = 0; // do not wait for incoming bytes
87  tattr.c_cc[VTIME] = timeout_decisecs; // timeout
88  } else {
89  tattr.c_cc[VMIN] = 0; // do not wait for incoming bytes
90  tattr.c_cc[VTIME] = 0; // no timeout
91  }
92  tcsetattr(STDIN_FILENO, TCSANOW, &tattr);
93 
94  ssize_t read_bytes = read(STDIN_FILENO, buf, 1);
95 
96  tcsetattr(STDIN_FILENO, TCSANOW, &saved_attributes);
97  if (!blocking)
99 
100  if (read_bytes == 1) {
101  return buf[0];
102  } else if (read_bytes < 0) {
103  throw Exception(errno, "Failed to read key from keyboard (getkey)");
104  } else {
105  return 0;
106  }
107 }
108 
109 } // end namespace fawkes
fawkes::set_nonblock_flag
static void set_nonblock_flag()
Set non-blocking flag on STDIN.
Definition: getkey.cpp:45
fawkes
fawkes::clear_nonblock_flag
static void clear_nonblock_flag()
Clear non-blocking flag on STDIN.
Definition: getkey.cpp:56
fawkes::getkey
char getkey(int timeout_decisecs)
Get value of a single key-press non-blocking.
Definition: getkey.cpp:74