[35] | 1 | /* |
---|
[268] | 2 | * libcaca ASCII-Art library |
---|
| 3 | * Copyright (c) 2002, 2003 Sam Hocevar <sam@zoy.org> |
---|
| 4 | * All Rights Reserved |
---|
[35] | 5 | * |
---|
[268] | 6 | * This library is free software; you can redistribute it and/or |
---|
| 7 | * modify it under the terms of the GNU Lesser General Public |
---|
| 8 | * License as published by the Free Software Foundation; either |
---|
| 9 | * version 2 of the License, or (at your option) any later version. |
---|
[35] | 10 | * |
---|
[268] | 11 | * This library is distributed in the hope that it will be useful, |
---|
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
| 14 | * Lesser General Public License for more details. |
---|
[35] | 15 | * |
---|
[268] | 16 | * You should have received a copy of the GNU Lesser General Public |
---|
| 17 | * License along with this library; if not, write to the Free Software |
---|
| 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
---|
| 19 | * 02111-1307 USA |
---|
[35] | 20 | */ |
---|
[17] | 21 | |
---|
[268] | 22 | /** \file io.c |
---|
| 23 | * \version \$Id: io.c 268 2003-12-23 13:27:40Z sam $ |
---|
| 24 | * \author Sam Hocevar <sam@zoy.org> |
---|
| 25 | * \brief Event handling functions |
---|
[205] | 26 | * |
---|
[268] | 27 | * This file contains event handling functions for keyboard and mouse input. |
---|
[205] | 28 | */ |
---|
| 29 | |
---|
[63] | 30 | #include "config.h" |
---|
| 31 | |
---|
[159] | 32 | #if defined(USE_SLANG) |
---|
[147] | 33 | # include <slang.h> |
---|
[265] | 34 | #endif |
---|
| 35 | #if defined(USE_NCURSES) |
---|
[147] | 36 | # include <curses.h> |
---|
[265] | 37 | #endif |
---|
| 38 | #if defined(USE_CONIO) |
---|
[155] | 39 | # include <conio.h> |
---|
[265] | 40 | #endif |
---|
| 41 | #if defined(USE_X11) |
---|
[251] | 42 | # include <X11/Xlib.h> |
---|
| 43 | # include <X11/Xutil.h> |
---|
[147] | 44 | #endif |
---|
| 45 | |
---|
[185] | 46 | #include "caca.h" |
---|
| 47 | #include "caca_internals.h" |
---|
[17] | 48 | |
---|
[213] | 49 | static void _push_key(unsigned int); |
---|
| 50 | static unsigned int _pop_key(void); |
---|
| 51 | static unsigned int _read_key(void); |
---|
[199] | 52 | |
---|
[213] | 53 | #define KEY_BUFLEN 10 |
---|
| 54 | static unsigned int keybuf[KEY_BUFLEN + 1]; /* zero-terminated */ |
---|
| 55 | static int keys = 0; |
---|
[198] | 56 | |
---|
[268] | 57 | /** \brief Get the next mouse or keyboard input event. |
---|
[257] | 58 | * |
---|
[268] | 59 | * This function polls the event queue for mouse or keyboard events and |
---|
| 60 | * returns the event. It is non-blocking and returns zero if no event is |
---|
| 61 | * pending in the queue. See also caca_wait_event() for a blocking version |
---|
| 62 | * of this function. |
---|
| 63 | * |
---|
[257] | 64 | * \return The next event in the queue, or 0 if no event is pending. |
---|
| 65 | */ |
---|
[213] | 66 | unsigned int caca_get_event(void) |
---|
[79] | 67 | { |
---|
[213] | 68 | unsigned int event = 0; |
---|
[198] | 69 | |
---|
[213] | 70 | /* Read all available key events */ |
---|
| 71 | while(keys < KEY_BUFLEN) |
---|
| 72 | { |
---|
| 73 | unsigned int key = _read_key(); |
---|
| 74 | if(!key) |
---|
| 75 | break; |
---|
| 76 | _push_key(key); |
---|
| 77 | } |
---|
[198] | 78 | |
---|
[213] | 79 | if(!keys) |
---|
[199] | 80 | return 0; |
---|
| 81 | |
---|
[213] | 82 | #if defined(USE_NCURSES) |
---|
[265] | 83 | if(_caca_driver == CACA_DRIVER_NCURSES) |
---|
[213] | 84 | { |
---|
[265] | 85 | if(keybuf[0] == KEY_MOUSE) |
---|
| 86 | { |
---|
| 87 | MEVENT mevent; |
---|
| 88 | _pop_key(); |
---|
| 89 | getmouse(&mevent); |
---|
[198] | 90 | |
---|
[265] | 91 | event |= (1) << 16; |
---|
| 92 | event |= (mevent.x) << 8; |
---|
| 93 | event |= (mevent.y) << 0; |
---|
[199] | 94 | |
---|
[265] | 95 | return CACA_EVENT_MOUSE_CLICK | event; |
---|
| 96 | } |
---|
[198] | 97 | |
---|
[265] | 98 | switch(keybuf[0]) |
---|
| 99 | { |
---|
| 100 | case KEY_UP: event = CACA_EVENT_KEY_PRESS | CACA_KEY_UP; break; |
---|
| 101 | case KEY_DOWN: event = CACA_EVENT_KEY_PRESS | CACA_KEY_DOWN; break; |
---|
| 102 | case KEY_LEFT: event = CACA_EVENT_KEY_PRESS | CACA_KEY_LEFT; break; |
---|
| 103 | case KEY_RIGHT: event = CACA_EVENT_KEY_PRESS | CACA_KEY_RIGHT; break; |
---|
[213] | 104 | |
---|
[265] | 105 | case KEY_F(1): event = CACA_EVENT_KEY_PRESS | CACA_KEY_F1; break; |
---|
| 106 | case KEY_F(2): event = CACA_EVENT_KEY_PRESS | CACA_KEY_F2; break; |
---|
| 107 | case KEY_F(3): event = CACA_EVENT_KEY_PRESS | CACA_KEY_F3; break; |
---|
| 108 | case KEY_F(4): event = CACA_EVENT_KEY_PRESS | CACA_KEY_F4; break; |
---|
| 109 | case KEY_F(5): event = CACA_EVENT_KEY_PRESS | CACA_KEY_F5; break; |
---|
| 110 | case KEY_F(6): event = CACA_EVENT_KEY_PRESS | CACA_KEY_F6; break; |
---|
| 111 | case KEY_F(7): event = CACA_EVENT_KEY_PRESS | CACA_KEY_F7; break; |
---|
| 112 | case KEY_F(8): event = CACA_EVENT_KEY_PRESS | CACA_KEY_F8; break; |
---|
| 113 | case KEY_F(9): event = CACA_EVENT_KEY_PRESS | CACA_KEY_F9; break; |
---|
| 114 | case KEY_F(10): event = CACA_EVENT_KEY_PRESS | CACA_KEY_F10; break; |
---|
| 115 | case KEY_F(11): event = CACA_EVENT_KEY_PRESS | CACA_KEY_F11; break; |
---|
| 116 | case KEY_F(12): event = CACA_EVENT_KEY_PRESS | CACA_KEY_F12; break; |
---|
| 117 | } |
---|
[198] | 118 | |
---|
[265] | 119 | if(event) |
---|
| 120 | { |
---|
| 121 | _pop_key(); |
---|
| 122 | return event; |
---|
| 123 | } |
---|
[213] | 124 | } |
---|
| 125 | #endif |
---|
| 126 | |
---|
| 127 | if(keybuf[0] != '\x1b') |
---|
| 128 | return CACA_EVENT_KEY_PRESS | _pop_key(); |
---|
| 129 | |
---|
| 130 | /* |
---|
| 131 | * Handle known escape sequences |
---|
| 132 | */ |
---|
| 133 | |
---|
| 134 | _pop_key(); |
---|
| 135 | |
---|
| 136 | if(keybuf[0] == 'O' && keybuf[1] >= 'P' && keybuf[1] <= 'S') |
---|
| 137 | { |
---|
[203] | 138 | /* ^[OP ^[OQ ^[OR ^[OS */ |
---|
[213] | 139 | static unsigned int keylist[] = |
---|
| 140 | { CACA_KEY_F1, CACA_KEY_F2, CACA_KEY_F3, CACA_KEY_F4 }; |
---|
| 141 | _pop_key(); |
---|
| 142 | return CACA_EVENT_KEY_PRESS | keylist[_pop_key() - 'P']; |
---|
[198] | 143 | } |
---|
[213] | 144 | else if(keybuf[0] == '[' && keybuf[1] >= 'A' && keybuf[1] <= 'D') |
---|
[198] | 145 | { |
---|
[203] | 146 | /* ^[[A ^[[B ^[[C ^[[D */ |
---|
[213] | 147 | static unsigned int keylist[] = |
---|
| 148 | { CACA_KEY_UP, CACA_KEY_DOWN, CACA_KEY_RIGHT, CACA_KEY_LEFT }; |
---|
| 149 | _pop_key(); |
---|
| 150 | return CACA_EVENT_KEY_PRESS | keylist[_pop_key() - 'A']; |
---|
| 151 | } |
---|
| 152 | else if(keybuf[0] == '[' && keybuf[1] == 'M' && |
---|
| 153 | keybuf[2] && keybuf[3] && keybuf[3]) |
---|
| 154 | { |
---|
[203] | 155 | /* ^[[Mxxx */ |
---|
[213] | 156 | _pop_key(); |
---|
| 157 | _pop_key(); |
---|
| 158 | event |= (_pop_key() - ' ') << 16; |
---|
| 159 | event |= (_pop_key() - '!') << 8; |
---|
| 160 | event |= (_pop_key() - '!') << 0; |
---|
[199] | 161 | |
---|
[213] | 162 | return CACA_EVENT_MOUSE_CLICK | event; |
---|
| 163 | } |
---|
| 164 | else if(keybuf[0] == '[' && keybuf[1] == '1' && keybuf[3] == '~' && |
---|
| 165 | keybuf[2] >= '5' && keybuf[2] != '6' && keybuf[2] <= '9') |
---|
| 166 | { |
---|
[203] | 167 | /* ^[[15~ ^[[17~ ^[[18~ ^[[19~ */ |
---|
[213] | 168 | static unsigned int keylist[] = |
---|
| 169 | { CACA_KEY_F5, 0, CACA_KEY_F6, CACA_KEY_F7, CACA_KEY_F8 }; |
---|
| 170 | _pop_key(); |
---|
| 171 | _pop_key(); |
---|
| 172 | event = CACA_EVENT_KEY_PRESS | keylist[_pop_key() - '5']; |
---|
| 173 | _pop_key(); |
---|
| 174 | return event; |
---|
| 175 | } |
---|
| 176 | else if(keybuf[0] == '[' && keybuf[1] == '2' && keybuf[3] == '~' && |
---|
| 177 | keybuf[2] >= '0' && keybuf[2] != '2' && keybuf[2] <= '4') |
---|
| 178 | { |
---|
[203] | 179 | /* ^[[20~ ^[[21~ ^[[23~ ^[[24~ */ |
---|
[213] | 180 | static unsigned int keylist[] = |
---|
| 181 | { CACA_KEY_F9, CACA_KEY_F10, 0, CACA_KEY_F11, CACA_KEY_F12 }; |
---|
| 182 | _pop_key(); |
---|
| 183 | _pop_key(); |
---|
| 184 | event = CACA_EVENT_KEY_PRESS | keylist[_pop_key() - '0']; |
---|
| 185 | _pop_key(); |
---|
| 186 | return event; |
---|
[198] | 187 | } |
---|
| 188 | |
---|
[213] | 189 | /* Unknown escape sequence: return the ESC key */ |
---|
| 190 | return CACA_EVENT_KEY_PRESS | '\x1b'; |
---|
[198] | 191 | } |
---|
| 192 | |
---|
[268] | 193 | /** \brief Wait for the next mouse or keyboard input event. |
---|
| 194 | * |
---|
| 195 | * This function returns the first mouse or keyboard event in the queue. If |
---|
| 196 | * no event is pending, it blocks until an event is received. See also |
---|
| 197 | * caca_get_event() for a non-blocking version of this function. |
---|
| 198 | * |
---|
| 199 | * \return The next event in the queue. |
---|
| 200 | */ |
---|
| 201 | unsigned int caca_wait_event(void) |
---|
| 202 | { |
---|
| 203 | for( ; ; ) |
---|
| 204 | { |
---|
| 205 | unsigned int event = caca_get_event(); |
---|
| 206 | |
---|
| 207 | if(event) |
---|
| 208 | return event; |
---|
| 209 | |
---|
| 210 | usleep(1000); |
---|
| 211 | } |
---|
| 212 | } |
---|
| 213 | |
---|
| 214 | /* |
---|
| 215 | * XXX: The following functions are local. |
---|
| 216 | */ |
---|
| 217 | |
---|
[213] | 218 | static void _push_key(unsigned int key) |
---|
[199] | 219 | { |
---|
[213] | 220 | if(keys == KEY_BUFLEN) |
---|
| 221 | return; |
---|
| 222 | keybuf[keys] = key; |
---|
| 223 | keys++; |
---|
| 224 | keybuf[keys] = 0; |
---|
[199] | 225 | } |
---|
| 226 | |
---|
[213] | 227 | static unsigned int _pop_key(void) |
---|
[199] | 228 | { |
---|
[213] | 229 | int i; |
---|
| 230 | unsigned int key = keybuf[0]; |
---|
| 231 | keys--; |
---|
| 232 | for(i = 0; i < keys; i++) |
---|
| 233 | keybuf[i] = keybuf[i + 1]; |
---|
| 234 | keybuf[keys] = 0; |
---|
| 235 | |
---|
[199] | 236 | return key; |
---|
| 237 | } |
---|
| 238 | |
---|
[213] | 239 | static unsigned int _read_key(void) |
---|
[199] | 240 | { |
---|
[265] | 241 | #if defined(USE_NCURSES) |
---|
| 242 | int intkey; |
---|
| 243 | #endif |
---|
| 244 | #if defined(USE_X11) |
---|
[251] | 245 | XEvent event; |
---|
| 246 | char key; |
---|
[265] | 247 | #endif |
---|
[251] | 248 | |
---|
[265] | 249 | switch(_caca_driver) |
---|
[251] | 250 | { |
---|
[265] | 251 | #if defined(USE_SLANG) |
---|
| 252 | case CACA_DRIVER_SLANG: |
---|
| 253 | return SLang_input_pending(0) ? SLang_getkey() : 0; |
---|
| 254 | #endif |
---|
| 255 | #if defined(USE_NCURSES) |
---|
| 256 | case CACA_DRIVER_NCURSES: |
---|
| 257 | intkey = getch(); |
---|
| 258 | return (intkey == ERR) ? 0 : intkey; |
---|
| 259 | #endif |
---|
| 260 | #if defined(USE_CONIO) |
---|
| 261 | case CACA_DRIVER_CONIO: |
---|
| 262 | return _conio_kbhit() ? getch() : 0; |
---|
| 263 | #endif |
---|
| 264 | #if defined(USE_X11) |
---|
| 265 | case CACA_DRIVER_X11: |
---|
| 266 | while(XCheckWindowEvent(x11_dpy, x11_window, KeyPressMask, &event) |
---|
| 267 | == True) |
---|
[251] | 268 | { |
---|
[265] | 269 | if(event.type == KeyPress) |
---|
| 270 | { |
---|
| 271 | //KeySym keysym; |
---|
| 272 | //keysym = XKeycodeToKeysym(_caca_dpy, event.xkey.keycode, 0); |
---|
| 273 | if(XLookupString(&event.xkey, &key, 1, NULL, NULL)) |
---|
| 274 | return key; |
---|
| 275 | } |
---|
[251] | 276 | } |
---|
[265] | 277 | |
---|
| 278 | return 0; |
---|
| 279 | #endif |
---|
| 280 | default: |
---|
| 281 | break; |
---|
[251] | 282 | } |
---|
| 283 | |
---|
| 284 | return 0; |
---|
[199] | 285 | } |
---|
| 286 | |
---|