FreeBASIC  0.91.0
io_inkey.c
Go to the documentation of this file.
1 /* console INKEY() function */
2 
3 #include "../fb.h"
4 #include "fb_private_console.h"
5 #include <termcap.h>
6 
7 /*#define DEBUG_TGETSTR*/
8 #ifdef DEBUG_TGETSTR
9 #include <ctype.h>
10 #endif
11 
12 #define KEY_BUFFER_LEN 256
13 
14 #define KEY_MOUSE 0x200
15 
16 typedef struct NODE
17 {
18  char key;
19  short code;
20  struct NODE *next, *child;
21 } NODE;
22 
23 typedef struct KEY_DATA
24 {
25  char *cap;
26  int code;
27 } KEY_DATA;
28 
29 /* see also termcap(5) man page */
30 static const KEY_DATA key_data[] = {
31  { "kb", KEY_BACKSPACE },
32  { "kT", KEY_TAB },
33  { "k1", KEY_F1 },
34  { "k2", KEY_F2 },
35  { "k3", KEY_F3 },
36  { "k4", KEY_F4 },
37  { "k5", KEY_F5 },
38  { "k6", KEY_F6 },
39  { "k7", KEY_F7 },
40  { "k8", KEY_F8 },
41  { "k9", KEY_F9 },
42  { "k;", KEY_F10 },
43  { "kh", KEY_HOME },
44  { "ku", KEY_UP },
45  { "kP", KEY_PAGE_UP },
46  { "kl", KEY_LEFT },
47  { "kr", KEY_RIGHT },
48  { "@7", KEY_END },
49  { "kd", KEY_DOWN },
50  { "kN", KEY_PAGE_DOWN },
51  { "kI", KEY_INS },
52  { "kD", KEY_DEL },
53  { NULL, 0 }
54 };
55 
57 static NODE *root_node = NULL;
58 
59 static void add_key(NODE **node, char *key, short code)
60 {
61  NODE *n;
62 
80  for (n = *node; n; n = n->next) {
81  if (n->key == *key) {
82  add_key(&n->child, key + 1, code);
83  return;
84  }
85  }
86  n = malloc(sizeof(NODE));
87  n->child = NULL;
88  n->next = *node;
89  n->key = *key;
90  n->code = 0;
91  *node = n;
92 
93  if (*(key + 1))
94  add_key(&n->child, key + 1, code);
95  else
96  n->code = code;
97 }
98 
99 static void init_keys()
100 {
101  KEY_DATA *data;
102  char *key;
103 
104  for (data = (KEY_DATA *)key_data; data->cap; data++) {
118  key = tgetstr(data->cap, NULL);
119 
120 #ifdef DEBUG_TGETSTR
121  fprintf(stderr, "tgetstr( %s ) =", data->cap);
122  if( key ) {
123  int i;
124  for( i = 0; i < strlen( key ); i++ ) {
125  if( isprint( key[i] ) ) {
126  fprintf(stderr, " %c", key[i]);
127  } else {
128  fprintf(stderr, " 0x%2x", key[i]);
129  }
130  }
131  } else {
132  fprintf(stderr, " (null)");
133  }
134  fprintf(stderr, "\n");
135 #endif
136 
137  if (key) {
138  add_key(&root_node, key + 1, data->code);
139  }
140  }
141  add_key(&root_node, "[M", KEY_MOUSE);
142 }
143 
144 static int get_input()
145 {
146  NODE *node;
147  int k, cb, cx, cy;
148 
149  k = __fb_con.keyboard_getch();
150  if (k == '\e') {
151  k = __fb_con.keyboard_getch();
152  if (k == EOF)
153  return 27;
154 
155  /* init the tree (on the first received escape sequence) */
156  if (!root_node)
157  init_keys();
158 
159  /* look up the escape sequence in the tree */
160  node = root_node;
161  while (node) {
162  if (k == node->key) {
163  if (node->code) {
164  if (node->code == KEY_MOUSE) {
165  cb = __fb_con.keyboard_getch();
166  cx = __fb_con.keyboard_getch();
167  cy = __fb_con.keyboard_getch();
168  if (__fb_con.mouse_update)
169  __fb_con.mouse_update(cb, cx, cy);
170  return -1;
171  }
172  return node->code;
173  }
174  k = __fb_con.keyboard_getch();
175  if (k == -1)
176  return -1;
177  node = node->child;
178  continue;
179  }
180  node = node->next;
181  }
182 
183  /* not found yet, skip rest and ignore */
184  while(__fb_con.keyboard_getch() >= 0)
185  ;
186 
187  return -1;
188  }
189 
190  return k;
191 }
192 
193 /* assumes BG_LOCK(), because it can be called from the background thread,
194  through fb_hTermQuery() */
195 void fb_hAddCh( int k )
196 {
197  if (k == 0x7F)
198  k = 8;
199  else if (k == '\n')
200  k = '\r';
201 
202  key_buffer[key_tail] = k;
203  if (((key_tail + 1) & (KEY_BUFFER_LEN - 1)) == key_head)
204  key_head = (key_head + 1) & (KEY_BUFFER_LEN - 1);
205  key_tail = (key_tail + 1) & (KEY_BUFFER_LEN - 1);
206 }
207 
208 int fb_hGetCh(int remove)
209 {
210  int k;
211 
212  k = get_input();
213  if (k >= 0) {
214  BG_LOCK();
215  fb_hAddCh( k );
216  BG_UNLOCK();
217  }
218  if (key_head != key_tail) {
219  k = key_buffer[key_head];
220  if (remove)
221  key_head = (key_head + 1) & (KEY_BUFFER_LEN - 1);
222  }
223 
224  return k;
225 }
226 
228 {
229  FBSTRING *res;
230  int ch;
231 
232  if (!__fb_con.inited)
233  return &__fb_ctx.null_desc;
234 
235  if ((ch = fb_hGetCh(TRUE)) >= 0) {
236  res = fb_hMakeInkeyStr( ch );
237  } else {
238  res = &__fb_ctx.null_desc;
239  }
240 
241  return res;
242 }
243 
244 int fb_ConsoleGetkey( void )
245 {
246  int key;
247 
248  if (!__fb_con.inited)
249  return fgetc(stdin);
250 
251  while ((key = fb_hGetCh(TRUE)) < 0)
252  fb_Sleep( -1 );
253 
254  return key;
255 }
256 
257 int fb_ConsoleKeyHit( void )
258 {
259  if (!__fb_con.inited)
260  return feof(stdin) ? FALSE : TRUE;
261 
262  return (fb_hGetCh(FALSE) < 0) ? 0 : 1;
263 }