Contiki 3.x
ctk-curses.c
1 /*
2  * Copyright (c) 2011, Swedish Institute of Computer Science.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the Contiki operating system.
30  *
31  * Author: François Revol <revol@free.fr>
32  */
33 
34 #include <curses.h>
35 #include <signal.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <term.h>
39 #include <unistd.h>
40 
41 #include "contiki.h"
42 #include "ctk/ctk.h"
43 
44 #include "ctk-curses.h"
45 
46 /* references:
47  * http://math.hws.edu/orr/s04/cpsc225/curses.html
48  * http://linux.die.net/man/3/ncurses
49  * http://linux.die.net/HOWTO/NCURSES-Programming-HOWTO/index.html
50  */
51 
52 #define MKPAIR(bg, fg) (bg << 3 | fg)
53 
54 static unsigned char width;
55 static unsigned char height;
56 
57 static unsigned char color;
58 static unsigned char reversed;
59 
60 static ctk_arch_key_t keys[256];
61 static unsigned char keys_in, keys_out;
62 static unsigned char available;
63 
64 static unsigned short xpos;
65 static unsigned short ypos;
66 static unsigned char button;
67 
68 /* map CTK colors to curses colors */
69 static unsigned char ctk_color_map[8] = {
70  COLOR_BLACK,
71  COLOR_RED,
72  COLOR_GREEN,
73  COLOR_YELLOW,
74  COLOR_BLUE,
75  COLOR_MAGENTA,
76  COLOR_CYAN,
77  COLOR_WHITE
78 };
79 
80 /*-----------------------------------------------------------------------------------*/
81 static unsigned char
82 map_color(unsigned char color)
83 {
84  unsigned char c;
85 
86  c = ctk_color_map[color & 0x0f];
87  c |= ctk_color_map[(color >> 4) & 0x07] << 4;
88  return c;
89 }
90 /*-----------------------------------------------------------------------------------*/
91 static void
92 ctrlhandler(int sig)
93 {
94  /* make sure we call console_exit() to leave the terminal in a clean state */
95  exit(EXIT_SUCCESS);
96 }
97 /*-----------------------------------------------------------------------------------*/
98 void
99 console_init(void)
100 {
101  /* mouse support is ncurses-specific */
102 #ifdef NCURSES_MOUSE_VERSION
103  mmask_t oldmask;
104 #endif
105  static unsigned char done;
106  int bg, fg;
107 
108  if(done) {
109  return;
110  }
111  done = 1;
112 
113  initscr();
114  start_color();
115  cbreak();
116 
117  /* don't echo typed characters */
118  noecho();
119  /* disable return -> newline translation */
120  nonl();
121 
122  /* hide text cursor, CTK draws its own */
123  curs_set(0);
124 
125  intrflush(stdscr, FALSE);
126  keypad(stdscr, TRUE);
127 
128 #ifdef NCURSES_MOUSE_VERSION
129  /* done here because ctk_mouse_init() is called before anyway */
130  mousemask(ALL_MOUSE_EVENTS, &oldmask);
131 #endif
132 
133  screensize(&width, &height);
134 
135  /* we must declare all possible color pairs */
136  for(fg = 0; fg < 8; fg++) {
137  for(bg = 0; bg < 8; bg++) {
138  init_pair(MKPAIR(bg, fg), fg, bg);
139  }
140  }
141 
142  /* set window title */
143  putp("\033]0;Contiki\a");
144 
145  /* don't block on read, just timeout 1ms */
146  timeout(1);
147 
148  /* make sure we return the terminal in a clean state */
149  signal(SIGINT, ctrlhandler);
150  atexit(console_exit);
151 }
152 /*-----------------------------------------------------------------------------------*/
153 void
154 console_exit(void)
155 {
156  static unsigned char done;
157 
158  if(done) {
159  return;
160  }
161  done = 1;
162 
163  revers(0);
164  clrscr();
165  gotoxy(0, 0);
166 
167  endwin();
168 }
169 /*-----------------------------------------------------------------------------------*/
170 unsigned char
171 console_resize(void)
172 {
173  unsigned char new_width;
174  unsigned char new_height;
175 
176  screensize(&new_width, &new_height);
177 
178  if(new_width != width || new_height != height) {
179  width = new_width;
180  height = new_height;
181  return 1;
182  }
183 
184  return 0;
185 }
186 /*-----------------------------------------------------------------------------------*/
187 static void
188 setcolor(void)
189 {
190  int bg, fg;
191  int attrs;
192 
193  fg = (color & 0x0F);
194  bg = (color & 0xF0) >> 4;
195 
196  attrs = COLOR_PAIR(MKPAIR(bg, fg));
197  if(reversed) {
198  attrs |= WA_REVERSE;
199  }
200  attrset(attrs);
201 }
202 /*-----------------------------------------------------------------------------------*/
203 unsigned char
204 wherex(void)
205 {
206  int x, y;
207 
208  getyx(stdscr, y, x);
209  (void)y;
210  return (unsigned char)x;
211 }
212 /*-----------------------------------------------------------------------------------*/
213 unsigned char
214 wherey(void)
215 {
216  int x, y;
217 
218  getyx(stdscr, y, x);
219  (void)x;
220  return (unsigned char)y;
221 }
222 /*-----------------------------------------------------------------------------------*/
223 void
224 clrscr(void)
225 {
226  clear();
227 }
228 /*-----------------------------------------------------------------------------------*/
229 void
230 bgcolor(unsigned char c)
231 {
232  c = map_color(c);
233  color = ((c << 4) | (color & 0xF0));
234  /* Presume this to be one of the first calls. */
235  console_init();
236 }
237 /*-----------------------------------------------------------------------------------*/
238 void
239 bordercolor(unsigned char c)
240 {
241  /* Presume this to be one of the first calls. */
242  console_init();
243 }
244 /*-----------------------------------------------------------------------------------*/
245 void
246 screensize(unsigned char *x, unsigned char *y)
247 {
248  int mx, my;
249 
250  getmaxyx(stdscr, my, mx);
251  *x = (unsigned char)mx;
252  *y = (unsigned char)my;
253 }
254 /*-----------------------------------------------------------------------------------*/
255 void
256 revers(unsigned char c)
257 {
258  reversed = c;
259  setcolor();
260 }
261 /*-----------------------------------------------------------------------------------*/
262 void
263 console_cputc(char c)
264 {
265  int ch = c;
266 
267  /* usually ACS_* don't fit in a char */
268  switch (c) {
269  case CH_ULCORNER:
270  ch = ACS_ULCORNER;
271  break;
272  case CH_LLCORNER:
273  ch = ACS_LLCORNER;
274  break;
275  case CH_URCORNER:
276  ch = ACS_URCORNER;
277  break;
278  case CH_LRCORNER:
279  ch = ACS_LRCORNER;
280  break;
281  default:
282  break;
283  }
284  addch(ch);
285  refresh();
286 }
287 /*-----------------------------------------------------------------------------------*/
288 void
289 console_cputs(char *str)
290 {
291  addstr(str);
292  refresh();
293 }
294 /*-----------------------------------------------------------------------------------*/
295 void
296 cclear(unsigned char length)
297 {
298  hline(' ', length);
299  refresh();
300 }
301 /*-----------------------------------------------------------------------------------*/
302 void
303 chline(unsigned char length)
304 {
305  hline(ACS_HLINE, length);
306  refresh();
307 }
308 /*-----------------------------------------------------------------------------------*/
309 void
310 cvline(unsigned char length)
311 {
312  vline(ACS_VLINE, length);
313 }
314 /*-----------------------------------------------------------------------------------*/
315 void
316 gotoxy(unsigned char x, unsigned char y)
317 {
318  move(y, x);
319 }
320 /*-----------------------------------------------------------------------------------*/
321 void
322 cclearxy(unsigned char x, unsigned char y, unsigned char length)
323 {
324  gotoxy(x, y);
325  cclear(length);
326 }
327 /*-----------------------------------------------------------------------------------*/
328 void
329 chlinexy(unsigned char x, unsigned char y, unsigned char length)
330 {
331  gotoxy(x, y);
332  chline(length);
333 }
334 /*-----------------------------------------------------------------------------------*/
335 void
336 cvlinexy(unsigned char x, unsigned char y, unsigned char length)
337 {
338  gotoxy(x, y);
339  cvline(length);
340 }
341 /*-----------------------------------------------------------------------------------*/
342 void
343 cputsxy(unsigned char x, unsigned char y, char *str)
344 {
345  gotoxy(x, y);
346  console_cputs(str);
347 }
348 /*-----------------------------------------------------------------------------------*/
349 void
350 cputcxy(unsigned char x, unsigned char y, char c)
351 {
352  gotoxy(x, y);
353  console_cputc(c);
354 }
355 /*-----------------------------------------------------------------------------------*/
356 void
357 textcolor(unsigned char c)
358 {
359  color = map_color(c);
360  setcolor();
361 }
362 /*-----------------------------------------------------------------------------------*/
363 static void
364 console_readkey(int k)
365 {
366  ctk_arch_key_t key;
367 
368  key = (ctk_arch_key_t) k;
369  /*fprintf(stderr, "key: %d\n", k); */
370  switch (k) {
371 #ifdef NCURSES_MOUSE_VERSION
372  case KEY_MOUSE:
373  {
374  MEVENT event;
375 
376  if(getmouse(&event) == OK) {
377  xpos = event.x;
378  ypos = event.y;
379  button = event.bstate & BUTTON1_PRESSED
380  || event.bstate & BUTTON1_CLICKED
381  || event.bstate & BUTTON1_DOUBLE_CLICKED;
382  /*fprintf(stderr, "mevent: %d: %d, %d, %d, %lx ; %d\n",
383  event.id, event.x, event.y, event.z, event.bstate, button); */
384  }
385  return;
386  }
387 #endif
388  case KEY_LEFT:
389  key = CH_CURS_LEFT;
390  break;
391  case KEY_UP:
392  key = CH_CURS_UP;
393  break;
394  case KEY_RIGHT:
395  key = CH_CURS_RIGHT;
396  break;
397  case KEY_DOWN:
398  key = CH_CURS_DOWN;
399  break;
400  case KEY_F(9): /* Gnome uses F10 as menu trigger now... */
401  case KEY_F(10):
402  key = CTK_CONF_MENU_KEY;
403  break;
404  case '\r':
405  case KEY_ENTER:
406  key = CH_ENTER;
407  break;
408  case 127:
409  case KEY_BACKSPACE:
410  case KEY_DC:
411  key = CH_DEL;
412  break;
413  case KEY_BTAB:
414  case KEY_CTAB:
415  case KEY_PPAGE:
416  case KEY_PREVIOUS:
417  key = CTK_CONF_WIDGETUP_KEY;
418  break;
419  case KEY_NPAGE:
420  case KEY_NEXT:
421  key = CTK_CONF_WIDGETDOWN_KEY;
422  break;
423  case KEY_STAB:
424  case KEY_HOME:
425  case KEY_END:
426  key = CTK_CONF_WINDOWSWITCH_KEY;
427  break;
428  default:
429  break;
430  }
431  if(key == 0) {
432  return;
433  }
434 
435  memset(keys + keys_in, key, sizeof(ctk_arch_key_t));
436  keys_in++;
437  available++;
438 }
439 /*-----------------------------------------------------------------------------------*/
440 static void
441 console_read(void)
442 {
443  int k;
444 
445  k = getch();
446  if(k != ERR) {
447  console_readkey(k);
448  }
449 }
450 /*-----------------------------------------------------------------------------------*/
451 char
453 {
454  char k;
455 
456  console_read();
457  k = keys[keys_out++];
458 
459  available--;
460  return k;
461 }
462 /*-----------------------------------------------------------------------------------*/
463 unsigned char
465 {
466  console_read();
467  return available;
468 }
469 /*-----------------------------------------------------------------------------------*/
470 void
471 ctk_mouse_init(void)
472 {
473 }
474 /*-----------------------------------------------------------------------------------*/
475 unsigned short
476 ctk_mouse_x(void)
477 {
478  console_read();
479  return xpos;
480 }
481 /*-----------------------------------------------------------------------------------*/
482 unsigned short
483 ctk_mouse_y(void)
484 {
485  console_read();
486  return ypos;
487 }
488 /*-----------------------------------------------------------------------------------*/
489 unsigned short
490 ctk_mouse_xtoc(unsigned short x)
491 {
492  return x;
493 }
494 /*-----------------------------------------------------------------------------------*/
495 unsigned short
496 ctk_mouse_ytoc(unsigned short y)
497 {
498  return y;
499 }
500 /*-----------------------------------------------------------------------------------*/
501 unsigned char
502 ctk_mouse_button(void)
503 {
504  console_read();
505  return button;
506 }
507 /*-----------------------------------------------------------------------------------*/
508 void
509 ctk_mouse_hide(void)
510 {
511 }
512 /*-----------------------------------------------------------------------------------*/
513 void
514 ctk_mouse_show(void)
515 {
516 }
517 /*-----------------------------------------------------------------------------------*/
char ctk_arch_key_t
The keyboard character type of the system.
Definition: ctk-conio.h:40
unsigned char ctk_arch_keyavail(void)
Check if there is a keypress in the keyboard input queue.
Definition: ctk-curses.c:464
#define TRUE
An alias for one, used for clarity.
ctk_arch_key_t ctk_arch_getkey(void)
Get a keypress from the keyboard input queue.
Definition: ctk-curses.c:452
#define FALSE
An alias for zero, used for clarity.
CTK header file.