602 lines
17 KiB
C
602 lines
17 KiB
C
/****************************************************************************
|
|
*
|
|
* SciTech Multi-platform Graphics Library
|
|
*
|
|
* ========================================================================
|
|
*
|
|
* The contents of this file are subject to the SciTech MGL Public
|
|
* License Version 1.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.scitechsoft.com/mgl-license.txt
|
|
*
|
|
* Software distributed under the License is distributed on an
|
|
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
* implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
|
|
*
|
|
* The Initial Developer of the Original Code is SciTech Software, Inc.
|
|
* All Rights Reserved.
|
|
*
|
|
* ========================================================================
|
|
*
|
|
* Language: ANSI C
|
|
* Environment: QNX
|
|
*
|
|
* Description: QNX fullscreen console implementation for the SciTech
|
|
* cross platform event library.
|
|
*
|
|
****************************************************************************/
|
|
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
|
|
/*--------------------------- Global variables ----------------------------*/
|
|
|
|
#ifndef __QNXNTO__
|
|
static struct _mouse_ctrl *_PM_mouse_ctl;
|
|
static int _PM_keyboard_fd = -1;
|
|
/*static int _PM_modifiers, _PM_leds; */
|
|
#else
|
|
static int kbd_fd = -1, mouse_fd = -1;
|
|
#endif
|
|
static int kill_pid = 0;
|
|
static ushort keyUpMsg[256] = {0};/* Table of key up messages */
|
|
static int rangeX,rangeY; /* Range of mouse coordinates */
|
|
|
|
#define TIME_TO_MSEC(__t) ((__t).tv_nsec / 1000000 + (__t).tv_sec * 1000)
|
|
|
|
#define LED_NUM 1
|
|
#define LED_CAP 2
|
|
#define LED_SCR 4
|
|
|
|
/* Scancode mappings on QNX for special keys */
|
|
|
|
typedef struct {
|
|
int scan;
|
|
int map;
|
|
} keymap;
|
|
|
|
/* TODO: Fix this and set it up so we can do a binary search! */
|
|
|
|
keymap keymaps[] = {
|
|
{96, KB_padEnter},
|
|
{74, KB_padMinus},
|
|
{78, KB_padPlus},
|
|
{55, KB_padTimes},
|
|
{98, KB_padDivide},
|
|
{71, KB_padHome},
|
|
{72, KB_padUp},
|
|
{73, KB_padPageUp},
|
|
{75, KB_padLeft},
|
|
{76, KB_padCenter},
|
|
{77, KB_padRight},
|
|
{79, KB_padEnd},
|
|
{80, KB_padDown},
|
|
{81, KB_padPageDown},
|
|
{82, KB_padInsert},
|
|
{83, KB_padDelete},
|
|
{105,KB_left},
|
|
{108,KB_down},
|
|
{106,KB_right},
|
|
{103,KB_up},
|
|
{110,KB_insert},
|
|
{102,KB_home},
|
|
{104,KB_pageUp},
|
|
{111,KB_delete},
|
|
{107,KB_end},
|
|
{109,KB_pageDown},
|
|
{125,KB_leftWindows},
|
|
{126,KB_rightWindows},
|
|
{127,KB_menu},
|
|
{100,KB_rightAlt},
|
|
{97,KB_rightCtrl},
|
|
};
|
|
|
|
/* And the keypad with num lock turned on (changes the ASCII code only) */
|
|
|
|
keymap keypad[] = {
|
|
{71, ASCII_7},
|
|
{72, ASCII_8},
|
|
{73, ASCII_9},
|
|
{75, ASCII_4},
|
|
{76, ASCII_5},
|
|
{77, ASCII_6},
|
|
{79, ASCII_1},
|
|
{80, ASCII_2},
|
|
{81, ASCII_3},
|
|
{82, ASCII_0},
|
|
{83, ASCII_period},
|
|
};
|
|
|
|
#define NB_KEYMAPS (sizeof(keymaps)/sizeof(keymaps[0]))
|
|
#define NB_KEYPAD (sizeof(keypad)/sizeof(keypad[0]))
|
|
|
|
/*---------------------------- Implementation -----------------------------*/
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Include generic raw scancode keyboard module.
|
|
****************************************************************************/
|
|
#include "common/keyboard.c"
|
|
|
|
/* These are not used under QNX */
|
|
#define _EVT_disableInt() 1
|
|
#define _EVT_restoreInt(flags)
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
This function is used to return the number of ticks since system
|
|
startup in milliseconds. This should be the same value that is placed into
|
|
the time stamp fields of events, and is used to implement auto mouse down
|
|
events.
|
|
****************************************************************************/
|
|
ulong _EVT_getTicks(void)
|
|
{
|
|
struct timespec t;
|
|
clock_gettime(CLOCK_REALTIME,&t);
|
|
return (t.tv_nsec / 1000000 + t.tv_sec * 1000);
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Converts a mickey movement value to a pixel adjustment value.
|
|
****************************************************************************/
|
|
static int MickeyToPixel(
|
|
int mickey)
|
|
{
|
|
/* TODO: We can add some code in here to handle 'acceleration' for */
|
|
/* the mouse cursor. For now just use the mickeys. */
|
|
return mickey;
|
|
}
|
|
|
|
#ifdef __QNXNTO__
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Retrieves all events from the mouse/keyboard event queue and stuffs them
|
|
into the MGL event queue for further processing.
|
|
****************************************************************************/
|
|
static void _EVT_pumpMessages(void)
|
|
{
|
|
int rc1, rc2;
|
|
struct _keyboard_packet key;
|
|
struct _mouse_packet ms;
|
|
static long old_buttons = 0;
|
|
uint message = 0, but_stat = 0, mods = 0;
|
|
event_t evt;
|
|
|
|
while (EVT.count < EVENTQSIZE) {
|
|
rc1 = read(kbd_fd, (void *)&key, sizeof(key));
|
|
if (rc1 == -1) {
|
|
if (errno == EAGAIN)
|
|
rc1 = 0;
|
|
else {
|
|
perror("getEvents");
|
|
PM_fatalError("Keyboard error");
|
|
}
|
|
}
|
|
if (rc1 > 0) {
|
|
memset(&evt, 0, sizeof(evt));
|
|
if (key.data.modifiers & KEYMOD_SHIFT)
|
|
mods |= EVT_LEFTSHIFT;
|
|
if (key.data.modifiers & KEYMOD_CTRL)
|
|
mods |= EVT_CTRLSTATE;
|
|
if (key.data.modifiers & KEYMOD_ALT)
|
|
mods |= EVT_ALTSTATE;
|
|
|
|
/* Now store the keyboard event data */
|
|
evt.when = TIME_TO_MSEC(key.time);
|
|
if (key.data.flags & KEY_SCAN_VALID)
|
|
evt.message |= (key.data.key_scan & 0x7F) << 8;
|
|
if ((key.data.flags & KEY_SYM_VALID) &&
|
|
(((key.data.key_sym & 0xff00) == 0xf000 &&
|
|
(key.data.key_sym & 0xff) < 0x20) ||
|
|
key.data.key_sym < 0x80))
|
|
evt.message |= (key.data.key_sym & 0xFF);
|
|
evt.modifiers = mods;
|
|
if (key.data.flags & KEY_DOWN) {
|
|
evt.what = EVT_KEYDOWN;
|
|
keyUpMsg[evt.message >> 8] = (ushort)evt.message;
|
|
}
|
|
else if (key.data.flags & KEY_REPEAT) {
|
|
evt.message |= 0x10000;
|
|
evt.what = EVT_KEYREPEAT;
|
|
}
|
|
else {
|
|
evt.what = EVT_KEYUP;
|
|
evt.message = keyUpMsg[evt.message >> 8];
|
|
if (evt.message == 0)
|
|
continue;
|
|
keyUpMsg[evt.message >> 8] = 0;
|
|
}
|
|
|
|
/* Now add the new event to the event queue */
|
|
addEvent(&evt);
|
|
}
|
|
rc2 = read(mouse_fd, (void *)&ms, sizeof (ms));
|
|
if (rc2 == -1) {
|
|
if (errno == EAGAIN)
|
|
rc2 = 0;
|
|
else {
|
|
perror("getEvents");
|
|
PM_fatalError("Mouse error");
|
|
}
|
|
}
|
|
if (rc2 > 0) {
|
|
memset(&evt, 0, sizeof(evt));
|
|
ms.hdr.buttons &=
|
|
(_POINTER_BUTTON_LEFT | _POINTER_BUTTON_RIGHT);
|
|
if (ms.hdr.buttons & _POINTER_BUTTON_LEFT)
|
|
but_stat = EVT_LEFTBUT;
|
|
if ((ms.hdr.buttons & _POINTER_BUTTON_LEFT) !=
|
|
(old_buttons & _POINTER_BUTTON_LEFT))
|
|
message = EVT_LEFTBMASK;
|
|
if (ms.hdr.buttons & _POINTER_BUTTON_RIGHT)
|
|
but_stat |= EVT_RIGHTBUT;
|
|
if ((ms.hdr.buttons & _POINTER_BUTTON_RIGHT) !=
|
|
(old_buttons & _POINTER_BUTTON_RIGHT))
|
|
message |= EVT_RIGHTBMASK;
|
|
if (ms.dx || ms.dy) {
|
|
ms.dy = -ms.dy;
|
|
EVT.mx += MickeyToPixel(ms.dx);
|
|
EVT.my += MickeyToPixel(ms.dy);
|
|
if (EVT.mx < 0) EVT.mx = 0;
|
|
if (EVT.my < 0) EVT.my = 0;
|
|
if (EVT.mx > rangeX) EVT.mx = rangeX;
|
|
if (EVT.my > rangeY) EVT.my = rangeY;
|
|
evt.what = EVT_MOUSEMOVE;
|
|
evt.when = TIME_TO_MSEC(ms.hdr.time);
|
|
evt.where_x = EVT.mx;
|
|
evt.where_y = EVT.my;
|
|
evt.relative_x = ms.dx;
|
|
evt.relative_y = ms.dy;
|
|
evt.modifiers = but_stat;
|
|
addEvent(&evt);
|
|
}
|
|
evt.what = ms.hdr.buttons < old_buttons ?
|
|
EVT_MOUSEUP : EVT_MOUSEDOWN;
|
|
evt.when = TIME_TO_MSEC(ms.hdr.time);
|
|
evt.where_x = EVT.mx;
|
|
evt.where_y = EVT.my;
|
|
evt.relative_x = ms.dx;
|
|
evt.relative_y = ms.dy;
|
|
evt.modifiers = but_stat;
|
|
evt.message = message;
|
|
if (ms.hdr.buttons != old_buttons) {
|
|
addEvent(&evt);
|
|
old_buttons = ms.hdr.buttons;
|
|
}
|
|
}
|
|
if (rc1 + rc2 == 0)
|
|
break;
|
|
}
|
|
}
|
|
#else
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Retrieves all events from the mouse/keyboard event queue and stuffs them
|
|
into the MGL event queue for further processing.
|
|
****************************************************************************/
|
|
static void _EVT_pumpMessages(void)
|
|
{
|
|
struct mouse_event ev;
|
|
int rc;
|
|
static long old_buttons = 0;
|
|
uint message = 0, but_stat = 0;
|
|
event_t evt;
|
|
char buf[32];
|
|
int numkeys, i;
|
|
|
|
/* Poll keyboard events */
|
|
while ((numkeys = read(_PM_keyboard_fd, buf, sizeof buf)) > 0) {
|
|
for (i = 0; i < numkeys; i++) {
|
|
processRawScanCode(buf[i]);
|
|
}
|
|
}
|
|
|
|
if (_PM_mouse_ctl == NULL)
|
|
return;
|
|
|
|
/* Gobble pending mouse events */
|
|
while (EVT.count < EVENTQSIZE) {
|
|
rc = mouse_read(_PM_mouse_ctl, &ev, 1, 0, NULL);
|
|
if (rc == -1) {
|
|
perror("getEvents");
|
|
PM_fatalError("Mouse error (Input terminated?)");
|
|
}
|
|
if (rc == 0)
|
|
break;
|
|
|
|
message = 0, but_stat = 0;
|
|
memset(&evt, 0, sizeof(evt));
|
|
|
|
ev.buttons &= (_MOUSE_LEFT | _MOUSE_RIGHT);
|
|
if (ev.buttons & _MOUSE_LEFT)
|
|
but_stat = EVT_LEFTBUT;
|
|
if ((ev.buttons & _MOUSE_LEFT) != (old_buttons & _MOUSE_LEFT))
|
|
message = EVT_LEFTBMASK;
|
|
if (ev.buttons & _MOUSE_RIGHT)
|
|
but_stat |= EVT_RIGHTBUT;
|
|
if ((ev.buttons & _MOUSE_RIGHT) != (old_buttons & _MOUSE_RIGHT))
|
|
message |= EVT_RIGHTBMASK;
|
|
if (ev.dx || ev.dy) {
|
|
ev.dy = -ev.dy;
|
|
EVT.mx += MickeyToPixel(ev.dx);
|
|
EVT.my += MickeyToPixel(ev.dy);
|
|
if (EVT.mx < 0) EVT.mx = 0;
|
|
if (EVT.my < 0) EVT.my = 0;
|
|
if (EVT.mx > rangeX) EVT.mx = rangeX;
|
|
if (EVT.my > rangeY) EVT.my = rangeY;
|
|
evt.what = EVT_MOUSEMOVE;
|
|
evt.when = ev.timestamp*100;
|
|
evt.where_x = EVT.mx;
|
|
evt.where_y = EVT.my;
|
|
evt.relative_x = ev.dx;
|
|
evt.relative_y = ev.dy;
|
|
evt.modifiers = but_stat;
|
|
addEvent(&evt);
|
|
}
|
|
evt.what = ev.buttons < old_buttons ? EVT_MOUSEUP : EVT_MOUSEDOWN;
|
|
evt.when = ev.timestamp*100;
|
|
evt.where_x = EVT.mx;
|
|
evt.where_y = EVT.my;
|
|
evt.relative_x = ev.dx;
|
|
evt.relative_y = ev.dy;
|
|
evt.modifiers = but_stat;
|
|
evt.message = message;
|
|
if (ev.buttons != old_buttons) {
|
|
addEvent(&evt);
|
|
old_buttons = ev.buttons;
|
|
}
|
|
}
|
|
}
|
|
#endif /* __QNXNTO__ */
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
This macro/function is used to converts the scan codes reported by the
|
|
keyboard to our event libraries normalised format. We only have one scan
|
|
code for the 'A' key, and use shift modifiers to determine if it is a
|
|
Ctrl-F1, Alt-F1 etc. The raw scan codes from the keyboard work this way,
|
|
but the OS gives us 'cooked' scan codes, we have to translate them back
|
|
to the raw format.
|
|
****************************************************************************/
|
|
#define _EVT_maskKeyCode(evt)
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Safely abort the event module upon catching a fatal error.
|
|
****************************************************************************/
|
|
void _EVT_abort(
|
|
int signo)
|
|
{
|
|
char buf[80];
|
|
|
|
EVT_exit();
|
|
sprintf(buf,"Terminating on signal %d",signo);
|
|
PM_fatalError(buf);
|
|
}
|
|
|
|
/****************************************************************************
|
|
PARAMETERS:
|
|
mouseMove - Callback function to call wheneve the mouse needs to be moved
|
|
|
|
REMARKS:
|
|
Initiliase the event handling module. Here we install our mouse handling ISR
|
|
to be called whenever any button's are pressed or released. We also build
|
|
the free list of events in the event queue.
|
|
|
|
We use handler number 2 of the mouse libraries interrupt handlers for our
|
|
event handling routines.
|
|
****************************************************************************/
|
|
void EVTAPI EVT_init(
|
|
_EVT_mouseMoveHandler mouseMove)
|
|
{
|
|
int i;
|
|
struct stat st;
|
|
char *iarg[16];
|
|
#ifdef __QNXNTO__
|
|
char buf[128];
|
|
FILE *p;
|
|
int argno,len;
|
|
#endif
|
|
|
|
#ifdef __QNXNTO__
|
|
ThreadCtl(_NTO_TCTL_IO, 0); /* So joystick code won't blow up */
|
|
#endif
|
|
|
|
/* Initialise the event queue */
|
|
EVT.mouseMove = mouseMove;
|
|
initEventQueue();
|
|
memset(keyUpMsg,0,sizeof(keyUpMsg));
|
|
|
|
#ifdef __QNXNTO__
|
|
/*
|
|
* User may already have input running with the right parameters.
|
|
* Thus they could start input at boot time, using the output of
|
|
* inputtrap, passing the the -r flag to make it run as a resource
|
|
* manager.
|
|
*/
|
|
if ((mouse_fd = open("/dev/mouse0", O_RDONLY | O_NONBLOCK)) < 0) {
|
|
/* Run inputtrap to get the args for input */
|
|
if ((p = popen("inputtrap", "r")) == NULL)
|
|
PM_fatalError("Error running 'inputtrap'");
|
|
fgets(buf, sizeof(buf), p);
|
|
pclose(p);
|
|
|
|
/* Build the argument list */
|
|
len = strlen(buf);
|
|
iarg[0] = buf;
|
|
for (i = 0, argno = 0; i < len && argno < 15;) {
|
|
if (argno == 1) {
|
|
/*
|
|
* Add flags to input's arg list.
|
|
* '-r' means run as resource
|
|
* manager, providing the /dev/mouse
|
|
* and /dev/keyboard interfaces.
|
|
* '-P' supresses the /dev/photon
|
|
* mechanism.
|
|
*/
|
|
iarg[argno++] = "-Pr";
|
|
continue;
|
|
}
|
|
while (buf[i] == ' ')
|
|
i++;
|
|
if (buf[i] == '\0' || buf[i] == '\n')
|
|
break;
|
|
iarg[argno++] = &buf[i];
|
|
while (buf[i] != ' '
|
|
&& buf[i] != '\0' && buf[i] != '\n')
|
|
i++;
|
|
buf[i++] = '\0';
|
|
}
|
|
iarg[argno] = NULL;
|
|
|
|
if ((kill_pid = spawnvp(P_NOWAITO, iarg[0], iarg)) == -1) {
|
|
perror("spawning input resmgr");
|
|
PM_fatalError("Could not start input resmgr");
|
|
}
|
|
for (i = 0; i < 10; i++) {
|
|
if (stat("/dev/mouse0", &st) == 0)
|
|
break;
|
|
sleep(1);
|
|
}
|
|
if ((mouse_fd = open("/dev/mouse0", O_RDONLY|O_NONBLOCK)) < 0) {
|
|
perror("/dev/mouse0");
|
|
PM_fatalError("Could not open /dev/mouse0");
|
|
}
|
|
}
|
|
if ((kbd_fd = open("/dev/keyboard0", O_RDONLY|O_NONBLOCK)) < 0) {
|
|
perror("/dev/keyboard0");
|
|
PM_fatalError("Could not open /dev/keyboard0");
|
|
}
|
|
#else
|
|
/* Connect to Input/Mouse for event handling */
|
|
if (_PM_mouse_ctl == NULL) {
|
|
_PM_mouse_ctl = mouse_open(0, "/dev/mouse", 0);
|
|
|
|
/* "Mouse" is not running; attempt to start it */
|
|
if (_PM_mouse_ctl == NULL) {
|
|
iarg[0] = "mousetrap";
|
|
iarg[1] = "start";
|
|
iarg[2] = NULL;
|
|
if ((kill_pid = spawnvp(P_NOWAITO, iarg[0], (void*)iarg)) == -1)
|
|
perror("spawn (mousetrap)");
|
|
else {
|
|
for (i = 0; i < 10; i++) {
|
|
if (stat("/dev/mouse", &st) == 0)
|
|
break;
|
|
sleep(1);
|
|
}
|
|
_PM_mouse_ctl = mouse_open(0, "/dev/mouse", 0);
|
|
}
|
|
}
|
|
}
|
|
if (_PM_keyboard_fd == -1)
|
|
_PM_keyboard_fd = open("/dev/kbd", O_RDONLY|O_NONBLOCK);
|
|
#endif
|
|
|
|
/* Catch program termination signals so we can clean up properly */
|
|
signal(SIGABRT, _EVT_abort);
|
|
signal(SIGFPE, _EVT_abort);
|
|
signal(SIGINT, _EVT_abort);
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS
|
|
Changes the range of coordinates returned by the mouse functions to the
|
|
specified range of values. This is used when changing between graphics
|
|
modes set the range of mouse coordinates for the new display mode.
|
|
****************************************************************************/
|
|
void EVTAPI EVT_setMouseRange(
|
|
int xRes,
|
|
int yRes)
|
|
{
|
|
rangeX = xRes;
|
|
rangeY = yRes;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS
|
|
Modifes the mouse coordinates as necessary if scaling to OS coordinates,
|
|
and sets the OS mouse cursor position.
|
|
****************************************************************************/
|
|
#define _EVT_setMousePos(x,y)
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Initiailises the internal event handling modules. The EVT_suspend function
|
|
can be called to suspend event handling (such as when shelling out to DOS),
|
|
and this function can be used to resume it again later.
|
|
****************************************************************************/
|
|
void EVT_resume(void)
|
|
{
|
|
/* Do nothing for QNX */
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS
|
|
Suspends all of our event handling operations. This is also used to
|
|
de-install the event handling code.
|
|
****************************************************************************/
|
|
void EVT_suspend(void)
|
|
{
|
|
/* Do nothing for QNX */
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS
|
|
Exits the event module for program terminatation.
|
|
****************************************************************************/
|
|
void EVT_exit(void)
|
|
{
|
|
#ifdef __QNXNTO__
|
|
char c;
|
|
int flags;
|
|
|
|
if (kbd_fd != -1) {
|
|
close(kbd_fd);
|
|
kbd_fd = -1;
|
|
}
|
|
if (mouse_fd != -1) {
|
|
close(mouse_fd);
|
|
mouse_fd = -1;
|
|
}
|
|
#endif
|
|
|
|
/* Restore signal handlers */
|
|
signal(SIGABRT, SIG_DFL);
|
|
signal(SIGFPE, SIG_DFL);
|
|
signal(SIGINT, SIG_DFL);
|
|
|
|
#ifndef __QNXNTO__
|
|
/* Kill the Input/Mouse driver if we have spawned it */
|
|
if (_PM_mouse_ctl != NULL) {
|
|
struct _fd_entry fde;
|
|
uint pid = 0;
|
|
|
|
/* Find out the pid of the mouse driver */
|
|
if (kill_pid > 0) {
|
|
if (qnx_fd_query(0,
|
|
0, _PM_mouse_ctl->fd, &fde) != -1)
|
|
pid = fde.pid;
|
|
}
|
|
mouse_close(_PM_mouse_ctl);
|
|
_PM_mouse_ctl = NULL;
|
|
|
|
if (pid > 0) {
|
|
/* For some reasons the PID's are different under QNX4,
|
|
* so we use the old mechanism to kill the mouse server.
|
|
*/
|
|
kill(pid, SIGTERM);
|
|
kill_pid = 0;
|
|
}
|
|
}
|
|
#endif
|
|
if (kill_pid > 0) {
|
|
kill(kill_pid, SIGTERM);
|
|
kill_pid = 0;
|
|
}
|
|
}
|