1 /****************************************************************************
3 * SciTech Multi-platform Graphics Library
5 * ========================================================================
7 * The contents of this file are subject to the SciTech MGL Public
8 * License Version 1.0 (the "License"); you may not use this file
9 * except in compliance with the License. You may obtain a copy of
10 * the License at http://www.scitechsoft.com/mgl-license.txt
12 * Software distributed under the License is distributed on an
13 * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 * implied. See the License for the specific language governing
15 * rights and limitations under the License.
17 * The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
19 * The Initial Developer of the Original Code is SciTech Software, Inc.
20 * All Rights Reserved.
22 * ========================================================================
27 * Description: QNX fullscreen console implementation for the SciTech
28 * cross platform event library.
30 ****************************************************************************/
35 /*--------------------------- Global variables ----------------------------*/
38 static struct _mouse_ctrl *_PM_mouse_ctl;
39 static int _PM_keyboard_fd = -1;
40 /*static int _PM_modifiers, _PM_leds; */
42 static int kbd_fd = -1, mouse_fd = -1;
44 static int kill_pid = 0;
45 static ushort keyUpMsg[256] = {0};/* Table of key up messages */
46 static int rangeX,rangeY; /* Range of mouse coordinates */
48 #define TIME_TO_MSEC(__t) ((__t).tv_nsec / 1000000 + (__t).tv_sec * 1000)
54 /* Scancode mappings on QNX for special keys */
61 /* TODO: Fix this and set it up so we can do a binary search! */
91 {126,KB_rightWindows},
97 /* And the keypad with num lock turned on (changes the ASCII code only) */
113 #define NB_KEYMAPS (sizeof(keymaps)/sizeof(keymaps[0]))
114 #define NB_KEYPAD (sizeof(keypad)/sizeof(keypad[0]))
116 /*---------------------------- Implementation -----------------------------*/
118 /****************************************************************************
120 Include generic raw scancode keyboard module.
121 ****************************************************************************/
122 #include "common/keyboard.c"
124 /* These are not used under QNX */
125 #define _EVT_disableInt() 1
126 #define _EVT_restoreInt(flags)
128 /****************************************************************************
130 This function is used to return the number of ticks since system
131 startup in milliseconds. This should be the same value that is placed into
132 the time stamp fields of events, and is used to implement auto mouse down
134 ****************************************************************************/
135 ulong _EVT_getTicks(void)
138 clock_gettime(CLOCK_REALTIME,&t);
139 return (t.tv_nsec / 1000000 + t.tv_sec * 1000);
142 /****************************************************************************
144 Converts a mickey movement value to a pixel adjustment value.
145 ****************************************************************************/
146 static int MickeyToPixel(
149 /* TODO: We can add some code in here to handle 'acceleration' for */
150 /* the mouse cursor. For now just use the mickeys. */
155 /****************************************************************************
157 Retrieves all events from the mouse/keyboard event queue and stuffs them
158 into the MGL event queue for further processing.
159 ****************************************************************************/
160 static void _EVT_pumpMessages(void)
163 struct _keyboard_packet key;
164 struct _mouse_packet ms;
165 static long old_buttons = 0;
166 uint message = 0, but_stat = 0, mods = 0;
169 while (EVT.count < EVENTQSIZE) {
170 rc1 = read(kbd_fd, (void *)&key, sizeof(key));
176 PM_fatalError("Keyboard error");
180 memset(&evt, 0, sizeof(evt));
181 if (key.data.modifiers & KEYMOD_SHIFT)
182 mods |= EVT_LEFTSHIFT;
183 if (key.data.modifiers & KEYMOD_CTRL)
184 mods |= EVT_CTRLSTATE;
185 if (key.data.modifiers & KEYMOD_ALT)
186 mods |= EVT_ALTSTATE;
188 /* Now store the keyboard event data */
189 evt.when = TIME_TO_MSEC(key.time);
190 if (key.data.flags & KEY_SCAN_VALID)
191 evt.message |= (key.data.key_scan & 0x7F) << 8;
192 if ((key.data.flags & KEY_SYM_VALID) &&
193 (((key.data.key_sym & 0xff00) == 0xf000 &&
194 (key.data.key_sym & 0xff) < 0x20) ||
195 key.data.key_sym < 0x80))
196 evt.message |= (key.data.key_sym & 0xFF);
197 evt.modifiers = mods;
198 if (key.data.flags & KEY_DOWN) {
199 evt.what = EVT_KEYDOWN;
200 keyUpMsg[evt.message >> 8] = (ushort)evt.message;
202 else if (key.data.flags & KEY_REPEAT) {
203 evt.message |= 0x10000;
204 evt.what = EVT_KEYREPEAT;
207 evt.what = EVT_KEYUP;
208 evt.message = keyUpMsg[evt.message >> 8];
209 if (evt.message == 0)
211 keyUpMsg[evt.message >> 8] = 0;
214 /* Now add the new event to the event queue */
217 rc2 = read(mouse_fd, (void *)&ms, sizeof (ms));
223 PM_fatalError("Mouse error");
227 memset(&evt, 0, sizeof(evt));
229 (_POINTER_BUTTON_LEFT | _POINTER_BUTTON_RIGHT);
230 if (ms.hdr.buttons & _POINTER_BUTTON_LEFT)
231 but_stat = EVT_LEFTBUT;
232 if ((ms.hdr.buttons & _POINTER_BUTTON_LEFT) !=
233 (old_buttons & _POINTER_BUTTON_LEFT))
234 message = EVT_LEFTBMASK;
235 if (ms.hdr.buttons & _POINTER_BUTTON_RIGHT)
236 but_stat |= EVT_RIGHTBUT;
237 if ((ms.hdr.buttons & _POINTER_BUTTON_RIGHT) !=
238 (old_buttons & _POINTER_BUTTON_RIGHT))
239 message |= EVT_RIGHTBMASK;
240 if (ms.dx || ms.dy) {
242 EVT.mx += MickeyToPixel(ms.dx);
243 EVT.my += MickeyToPixel(ms.dy);
244 if (EVT.mx < 0) EVT.mx = 0;
245 if (EVT.my < 0) EVT.my = 0;
246 if (EVT.mx > rangeX) EVT.mx = rangeX;
247 if (EVT.my > rangeY) EVT.my = rangeY;
248 evt.what = EVT_MOUSEMOVE;
249 evt.when = TIME_TO_MSEC(ms.hdr.time);
250 evt.where_x = EVT.mx;
251 evt.where_y = EVT.my;
252 evt.relative_x = ms.dx;
253 evt.relative_y = ms.dy;
254 evt.modifiers = but_stat;
257 evt.what = ms.hdr.buttons < old_buttons ?
258 EVT_MOUSEUP : EVT_MOUSEDOWN;
259 evt.when = TIME_TO_MSEC(ms.hdr.time);
260 evt.where_x = EVT.mx;
261 evt.where_y = EVT.my;
262 evt.relative_x = ms.dx;
263 evt.relative_y = ms.dy;
264 evt.modifiers = but_stat;
265 evt.message = message;
266 if (ms.hdr.buttons != old_buttons) {
268 old_buttons = ms.hdr.buttons;
276 /****************************************************************************
278 Retrieves all events from the mouse/keyboard event queue and stuffs them
279 into the MGL event queue for further processing.
280 ****************************************************************************/
281 static void _EVT_pumpMessages(void)
283 struct mouse_event ev;
285 static long old_buttons = 0;
286 uint message = 0, but_stat = 0;
291 /* Poll keyboard events */
292 while ((numkeys = read(_PM_keyboard_fd, buf, sizeof buf)) > 0) {
293 for (i = 0; i < numkeys; i++) {
294 processRawScanCode(buf[i]);
298 if (_PM_mouse_ctl == NULL)
301 /* Gobble pending mouse events */
302 while (EVT.count < EVENTQSIZE) {
303 rc = mouse_read(_PM_mouse_ctl, &ev, 1, 0, NULL);
306 PM_fatalError("Mouse error (Input terminated?)");
311 message = 0, but_stat = 0;
312 memset(&evt, 0, sizeof(evt));
314 ev.buttons &= (_MOUSE_LEFT | _MOUSE_RIGHT);
315 if (ev.buttons & _MOUSE_LEFT)
316 but_stat = EVT_LEFTBUT;
317 if ((ev.buttons & _MOUSE_LEFT) != (old_buttons & _MOUSE_LEFT))
318 message = EVT_LEFTBMASK;
319 if (ev.buttons & _MOUSE_RIGHT)
320 but_stat |= EVT_RIGHTBUT;
321 if ((ev.buttons & _MOUSE_RIGHT) != (old_buttons & _MOUSE_RIGHT))
322 message |= EVT_RIGHTBMASK;
323 if (ev.dx || ev.dy) {
325 EVT.mx += MickeyToPixel(ev.dx);
326 EVT.my += MickeyToPixel(ev.dy);
327 if (EVT.mx < 0) EVT.mx = 0;
328 if (EVT.my < 0) EVT.my = 0;
329 if (EVT.mx > rangeX) EVT.mx = rangeX;
330 if (EVT.my > rangeY) EVT.my = rangeY;
331 evt.what = EVT_MOUSEMOVE;
332 evt.when = ev.timestamp*100;
333 evt.where_x = EVT.mx;
334 evt.where_y = EVT.my;
335 evt.relative_x = ev.dx;
336 evt.relative_y = ev.dy;
337 evt.modifiers = but_stat;
340 evt.what = ev.buttons < old_buttons ? EVT_MOUSEUP : EVT_MOUSEDOWN;
341 evt.when = ev.timestamp*100;
342 evt.where_x = EVT.mx;
343 evt.where_y = EVT.my;
344 evt.relative_x = ev.dx;
345 evt.relative_y = ev.dy;
346 evt.modifiers = but_stat;
347 evt.message = message;
348 if (ev.buttons != old_buttons) {
350 old_buttons = ev.buttons;
354 #endif /* __QNXNTO__ */
356 /****************************************************************************
358 This macro/function is used to converts the scan codes reported by the
359 keyboard to our event libraries normalised format. We only have one scan
360 code for the 'A' key, and use shift modifiers to determine if it is a
361 Ctrl-F1, Alt-F1 etc. The raw scan codes from the keyboard work this way,
362 but the OS gives us 'cooked' scan codes, we have to translate them back
364 ****************************************************************************/
365 #define _EVT_maskKeyCode(evt)
367 /****************************************************************************
369 Safely abort the event module upon catching a fatal error.
370 ****************************************************************************/
377 sprintf(buf,"Terminating on signal %d",signo);
381 /****************************************************************************
383 mouseMove - Callback function to call wheneve the mouse needs to be moved
386 Initiliase the event handling module. Here we install our mouse handling ISR
387 to be called whenever any button's are pressed or released. We also build
388 the free list of events in the event queue.
390 We use handler number 2 of the mouse libraries interrupt handlers for our
391 event handling routines.
392 ****************************************************************************/
393 void EVTAPI EVT_init(
394 _EVT_mouseMoveHandler mouseMove)
406 ThreadCtl(_NTO_TCTL_IO, 0); /* So joystick code won't blow up */
409 /* Initialise the event queue */
410 EVT.mouseMove = mouseMove;
412 memset(keyUpMsg,0,sizeof(keyUpMsg));
416 * User may already have input running with the right parameters.
417 * Thus they could start input at boot time, using the output of
418 * inputtrap, passing the the -r flag to make it run as a resource
421 if ((mouse_fd = open("/dev/mouse0", O_RDONLY | O_NONBLOCK)) < 0) {
422 /* Run inputtrap to get the args for input */
423 if ((p = popen("inputtrap", "r")) == NULL)
424 PM_fatalError("Error running 'inputtrap'");
425 fgets(buf, sizeof(buf), p);
428 /* Build the argument list */
431 for (i = 0, argno = 0; i < len && argno < 15;) {
434 * Add flags to input's arg list.
435 * '-r' means run as resource
436 * manager, providing the /dev/mouse
437 * and /dev/keyboard interfaces.
438 * '-P' supresses the /dev/photon
441 iarg[argno++] = "-Pr";
444 while (buf[i] == ' ')
446 if (buf[i] == '\0' || buf[i] == '\n')
448 iarg[argno++] = &buf[i];
450 && buf[i] != '\0' && buf[i] != '\n')
456 if ((kill_pid = spawnvp(P_NOWAITO, iarg[0], iarg)) == -1) {
457 perror("spawning input resmgr");
458 PM_fatalError("Could not start input resmgr");
460 for (i = 0; i < 10; i++) {
461 if (stat("/dev/mouse0", &st) == 0)
465 if ((mouse_fd = open("/dev/mouse0", O_RDONLY|O_NONBLOCK)) < 0) {
466 perror("/dev/mouse0");
467 PM_fatalError("Could not open /dev/mouse0");
470 if ((kbd_fd = open("/dev/keyboard0", O_RDONLY|O_NONBLOCK)) < 0) {
471 perror("/dev/keyboard0");
472 PM_fatalError("Could not open /dev/keyboard0");
475 /* Connect to Input/Mouse for event handling */
476 if (_PM_mouse_ctl == NULL) {
477 _PM_mouse_ctl = mouse_open(0, "/dev/mouse", 0);
479 /* "Mouse" is not running; attempt to start it */
480 if (_PM_mouse_ctl == NULL) {
481 iarg[0] = "mousetrap";
484 if ((kill_pid = spawnvp(P_NOWAITO, iarg[0], (void*)iarg)) == -1)
485 perror("spawn (mousetrap)");
487 for (i = 0; i < 10; i++) {
488 if (stat("/dev/mouse", &st) == 0)
492 _PM_mouse_ctl = mouse_open(0, "/dev/mouse", 0);
496 if (_PM_keyboard_fd == -1)
497 _PM_keyboard_fd = open("/dev/kbd", O_RDONLY|O_NONBLOCK);
500 /* Catch program termination signals so we can clean up properly */
501 signal(SIGABRT, _EVT_abort);
502 signal(SIGFPE, _EVT_abort);
503 signal(SIGINT, _EVT_abort);
506 /****************************************************************************
508 Changes the range of coordinates returned by the mouse functions to the
509 specified range of values. This is used when changing between graphics
510 modes set the range of mouse coordinates for the new display mode.
511 ****************************************************************************/
512 void EVTAPI EVT_setMouseRange(
520 /****************************************************************************
522 Modifes the mouse coordinates as necessary if scaling to OS coordinates,
523 and sets the OS mouse cursor position.
524 ****************************************************************************/
525 #define _EVT_setMousePos(x,y)
527 /****************************************************************************
529 Initiailises the internal event handling modules. The EVT_suspend function
530 can be called to suspend event handling (such as when shelling out to DOS),
531 and this function can be used to resume it again later.
532 ****************************************************************************/
533 void EVT_resume(void)
535 /* Do nothing for QNX */
538 /****************************************************************************
540 Suspends all of our event handling operations. This is also used to
541 de-install the event handling code.
542 ****************************************************************************/
543 void EVT_suspend(void)
545 /* Do nothing for QNX */
548 /****************************************************************************
550 Exits the event module for program terminatation.
551 ****************************************************************************/
562 if (mouse_fd != -1) {
568 /* Restore signal handlers */
569 signal(SIGABRT, SIG_DFL);
570 signal(SIGFPE, SIG_DFL);
571 signal(SIGINT, SIG_DFL);
574 /* Kill the Input/Mouse driver if we have spawned it */
575 if (_PM_mouse_ctl != NULL) {
576 struct _fd_entry fde;
579 /* Find out the pid of the mouse driver */
582 0, _PM_mouse_ctl->fd, &fde) != -1)
585 mouse_close(_PM_mouse_ctl);
586 _PM_mouse_ctl = NULL;
589 /* For some reasons the PID's are different under QNX4,
590 * so we use the old mechanism to kill the mouse server.
598 kill(kill_pid, SIGTERM);