| /**************************************************************************** |
| * |
| * SciTech OS Portability Manager 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: Any |
| * |
| * Description: Main implementation for the SciTech cross platform event |
| * library. This module contains all the generic cross platform |
| * code, and pulls in modules specific to each target OS |
| * environment. |
| * |
| ****************************************************************************/ |
| |
| #include "event.h" |
| #include "pmapi.h" |
| #include <time.h> |
| #include <signal.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include "oshdr.h" |
| |
| /*--------------------------- Global variables ----------------------------*/ |
| |
| #define EVENTQSIZE 100 /* Number of events in event queue */ |
| #define JOY_NUM_AXES 4 /* Number of joystick axes supported */ |
| |
| static struct { |
| int mx,my; /* Current mouse position */ |
| int head; /* Head of event queue */ |
| int tail; /* Tail of event queue */ |
| int freeHead; /* Head of free list */ |
| int count; /* No. of items currently in queue */ |
| event_t evtq[EVENTQSIZE]; /* The queue structure itself */ |
| int oldMove; /* Previous movement event */ |
| int oldKey; /* Previous key repeat event */ |
| int oldJoyMove; /* Previous joystick movement event */ |
| int joyMask; /* Mask of joystick axes present */ |
| int joyMin[JOY_NUM_AXES]; |
| int joyCenter[JOY_NUM_AXES]; |
| int joyMax[JOY_NUM_AXES]; |
| int joyPrev[JOY_NUM_AXES]; |
| int joyButState; |
| ulong doubleClick; |
| ulong autoRepeat; |
| ulong autoDelay; |
| ulong autoTicks; |
| ulong doubleClickThresh; |
| ulong firstAuto; |
| int autoMouse_x; |
| int autoMouse_y; |
| event_t downMouse; |
| ulong keyModifiers; /* Current keyboard modifiers */ |
| uchar keyTable[128]; /* Table of key up/down flags */ |
| ibool allowLEDS; /* True if LEDS should change */ |
| _EVT_userEventFilter userEventCallback; |
| _EVT_mouseMoveHandler mouseMove; |
| _EVT_heartBeatCallback heartBeat; |
| void *heartBeatParams; |
| codepage_t *codePage; |
| } EVT; |
| |
| /*---------------------------- Implementation -----------------------------*/ |
| |
| #if defined(__REALDOS__) || defined(__SMX32__) |
| /* {secret} */ |
| void EVTAPI _EVT_cCodeStart(void) {} |
| #endif |
| |
| /* External assembler functions */ |
| |
| int EVTAPI _EVT_readJoyAxis(int mask,int *axis); |
| int EVTAPI _EVT_readJoyButtons(void); |
| |
| /* Forward declaration */ |
| |
| ulong _EVT_getTicks(void); |
| |
| /**************************************************************************** |
| PARAMETERS: |
| evt - Event to add to the event queue |
| |
| REMARKS: |
| Adds an event to the event queue by tacking it onto the tail of the event |
| queue. This routine assumes that at least one spot is available on the |
| freeList for the event to be inserted. |
| |
| NOTE: Interrupts MUST be OFF while this routine is called to ensure we have |
| mutually exclusive access to our internal data structures for |
| interrupt driven systems (like under DOS). |
| ****************************************************************************/ |
| static void addEvent( |
| event_t *evt) |
| { |
| int evtID; |
| |
| /* Check for mouse double click events */ |
| if (evt->what & EVT_MOUSEEVT) { |
| EVT.autoMouse_x = evt->where_x; |
| EVT.autoMouse_y = evt->where_y; |
| if ((evt->what & EVT_MOUSEDOWN) && !(evt->message & EVT_DBLCLICK)) { |
| /* Determine if the last mouse event was a double click event */ |
| uint diff_x = ABS(evt->where_x - EVT.downMouse.where_x); |
| uint diff_y = ABS(evt->where_y - EVT.downMouse.where_y); |
| if ((evt->message == EVT.downMouse.message) |
| && ((evt->when - EVT.downMouse.when) <= EVT.doubleClick) |
| && (diff_x <= EVT.doubleClickThresh) |
| && (diff_y <= EVT.doubleClickThresh)) { |
| evt->message |= EVT_DBLCLICK; |
| EVT.downMouse = *evt; |
| EVT.downMouse.when = 0; |
| } |
| else |
| EVT.downMouse = *evt; |
| EVT.autoTicks = _EVT_getTicks(); |
| } |
| else if (evt->what & EVT_MOUSEUP) { |
| EVT.downMouse.what = EVT_NULLEVT; |
| EVT.firstAuto = true; |
| } |
| } |
| |
| /* Call user supplied callback to modify the event if desired */ |
| if (EVT.userEventCallback) { |
| if (!EVT.userEventCallback(evt)) |
| return; |
| } |
| |
| /* Get spot to place the event from the free list */ |
| evtID = EVT.freeHead; |
| EVT.freeHead = EVT.evtq[EVT.freeHead].next; |
| |
| /* Add to the EVT.tail of the event queue */ |
| evt->next = -1; |
| evt->prev = EVT.tail; |
| if (EVT.tail != -1) |
| EVT.evtq[EVT.tail].next = evtID; |
| else |
| EVT.head = evtID; |
| EVT.tail = evtID; |
| EVT.evtq[evtID] = *evt; |
| EVT.count++; |
| } |
| |
| /**************************************************************************** |
| REMARKS: |
| Internal function to initialise the event queue to the empty state. |
| ****************************************************************************/ |
| static void initEventQueue(void) |
| { |
| int i; |
| |
| /* Build free list, and initialize global data structures */ |
| for (i = 0; i < EVENTQSIZE; i++) |
| EVT.evtq[i].next = i+1; |
| EVT.evtq[EVENTQSIZE-1].next = -1; /* Terminate list */ |
| EVT.count = EVT.freeHead = 0; |
| EVT.head = EVT.tail = -1; |
| EVT.oldMove = -1; |
| EVT.oldKey = -1; |
| EVT.oldJoyMove = -1; |
| EVT.joyButState = 0; |
| EVT.mx = EVT.my = 0; |
| EVT.keyModifiers = 0; |
| EVT.allowLEDS = true; |
| |
| /* Set default values for mouse double click and mouse auto events */ |
| EVT.doubleClick = 440; |
| EVT.autoRepeat = 55; |
| EVT.autoDelay = 330; |
| EVT.autoTicks = 0; |
| EVT.doubleClickThresh = 5; |
| EVT.firstAuto = true; |
| EVT.autoMouse_x = EVT.autoMouse_y = 0; |
| memset(&EVT.downMouse,0,sizeof(EVT.downMouse)); |
| |
| /* Setup default pointers for event library */ |
| EVT.userEventCallback = NULL; |
| EVT.codePage = &_CP_US_English; |
| |
| /* Initialise the joystick module and do basic calibration (which assumes |
| * the joystick is centered. |
| */ |
| EVT.joyMask = EVT_joyIsPresent(); |
| } |
| |
| #if defined(NEED_SCALE_JOY_AXIS) || !defined(USE_OS_JOYSTICK) |
| /**************************************************************************** |
| REMARKS: |
| This function scales a joystick axis value to normalised form. |
| ****************************************************************************/ |
| static int scaleJoyAxis( |
| int raw, |
| int axis) |
| { |
| int scaled,range; |
| |
| /* Make sure the joystick is calibrated properly */ |
| if (EVT.joyCenter[axis] - EVT.joyMin[axis] < 5) |
| return raw; |
| if (EVT.joyMax[axis] - EVT.joyCenter[axis] < 5) |
| return raw; |
| |
| /* Now scale the coordinates to -128 to 127 */ |
| raw -= EVT.joyCenter[axis]; |
| if (raw < 0) |
| range = EVT.joyCenter[axis]-EVT.joyMin[axis]; |
| else |
| range = EVT.joyMax[axis]-EVT.joyCenter[axis]; |
| scaled = (raw * 128) / range; |
| if (scaled < -128) |
| scaled = -128; |
| if (scaled > 127) |
| scaled = 127; |
| return scaled; |
| } |
| #endif |
| |
| #if defined(__SMX32__) |
| #include "smx/event.c" |
| #elif defined(__RTTARGET__) |
| #include "rttarget/event.c" |
| #elif defined(__REALDOS__) |
| #include "dos/event.c" |
| #elif defined(__WINDOWS32__) |
| #include "win32/event.c" |
| #elif defined(__OS2__) |
| #if defined(__OS2_PM__) |
| #include "os2pm/event.c" |
| #else |
| #include "os2/event.c" |
| #endif |
| #elif defined(__LINUX__) |
| #if defined(__USE_X11__) |
| #include "x11/event.c" |
| #else |
| #include "linux/event.c" |
| #endif |
| #elif defined(__QNX__) |
| #if defined(__USE_PHOTON__) |
| #include "photon/event.c" |
| #elif defined(__USE_X11__) |
| #include "x11/event.c" |
| #else |
| #include "qnx/event.c" |
| #endif |
| #elif defined(__BEOS__) |
| #include "beos/event.c" |
| #else |
| #error Event library not ported to this platform yet! |
| #endif |
| |
| /*------------------------ Public interface routines ----------------------*/ |
| |
| /* If USE_OS_JOYSTICK is defined, the OS specific libraries will implement |
| * the joystick code rather than using the generic OS portable version. |
| */ |
| |
| #ifndef USE_OS_JOYSTICK |
| /**************************************************************************** |
| DESCRIPTION: |
| Returns the mask indicating what joystick axes are attached. |
| |
| HEADER: |
| event.h |
| |
| REMARKS: |
| This function is used to detect the attached joysticks, and determine |
| what axes are present and functioning. This function will re-detect any |
| attached joysticks when it is called, so if the user forgot to attach |
| the joystick when the application started, you can call this function to |
| re-detect any newly attached joysticks. |
| |
| SEE ALSO: |
| EVT_joySetLowerRight, EVT_joySetCenter, EVT_joyIsPresent |
| ****************************************************************************/ |
| int EVTAPI EVT_joyIsPresent(void) |
| { |
| int mask,i; |
| |
| memset(EVT.joyMin,0,sizeof(EVT.joyMin)); |
| memset(EVT.joyCenter,0,sizeof(EVT.joyCenter)); |
| memset(EVT.joyMax,0,sizeof(EVT.joyMax)); |
| memset(EVT.joyPrev,0,sizeof(EVT.joyPrev)); |
| EVT.joyButState = 0; |
| #ifdef __LINUX__ |
| PM_init(); |
| #endif |
| mask = _EVT_readJoyAxis(EVT_JOY_AXIS_ALL,EVT.joyCenter); |
| if (mask) { |
| for (i = 0; i < JOY_NUM_AXES; i++) |
| EVT.joyMax[i] = EVT.joyCenter[i]*2; |
| } |
| return mask; |
| } |
| |
| /**************************************************************************** |
| DESCRIPTION: |
| Polls the joystick for position and button information. |
| |
| HEADER: |
| event.h |
| |
| REMARKS: |
| This routine is used to poll analogue joysticks for button and position |
| information. It should be called once for each main loop of the user |
| application, just before processing all pending events via EVT_getNext. |
| All information polled from the joystick will be posted to the event |
| queue for later retrieval. |
| |
| Note: Most analogue joysticks will provide readings that change even |
| though the joystick has not moved. Hence if you call this routine |
| you will likely get an EVT_JOYMOVE event every time through your |
| event loop. |
| |
| SEE ALSO: |
| EVT_getNext, EVT_peekNext, EVT_joySetUpperLeft, EVT_joySetLowerRight, |
| EVT_joySetCenter, EVT_joyIsPresent |
| ****************************************************************************/ |
| void EVTAPI EVT_pollJoystick(void) |
| { |
| event_t evt; |
| int i,axis[JOY_NUM_AXES],newButState,mask,moved,ps; |
| |
| if (EVT.joyMask) { |
| /* Read joystick axes and post movement events if they have |
| * changed since the last time we polled. Until the events are |
| * actually flushed, we keep modifying the same joystick movement |
| * event, so you won't get multiple movement event |
| */ |
| mask = _EVT_readJoyAxis(EVT.joyMask,axis); |
| newButState = _EVT_readJoyButtons(); |
| moved = false; |
| for (i = 0; i < JOY_NUM_AXES; i++) { |
| if (mask & (EVT_JOY_AXIS_X1 << i)) |
| axis[i] = scaleJoyAxis(axis[i],i); |
| else |
| axis[i] = EVT.joyPrev[i]; |
| if (axis[i] != EVT.joyPrev[i]) |
| moved = true; |
| } |
| if (moved) { |
| memcpy(EVT.joyPrev,axis,sizeof(EVT.joyPrev)); |
| ps = _EVT_disableInt(); |
| if (EVT.oldJoyMove != -1) { |
| /* Modify the existing joystick movement event */ |
| EVT.evtq[EVT.oldJoyMove].message = newButState; |
| EVT.evtq[EVT.oldJoyMove].where_x = EVT.joyPrev[0]; |
| EVT.evtq[EVT.oldJoyMove].where_y = EVT.joyPrev[1]; |
| EVT.evtq[EVT.oldJoyMove].relative_x = EVT.joyPrev[2]; |
| EVT.evtq[EVT.oldJoyMove].relative_y = EVT.joyPrev[3]; |
| } |
| else if (EVT.count < EVENTQSIZE) { |
| /* Add a new joystick movement event */ |
| EVT.oldJoyMove = EVT.freeHead; |
| memset(&evt,0,sizeof(evt)); |
| evt.what = EVT_JOYMOVE; |
| evt.message = EVT.joyButState; |
| evt.where_x = EVT.joyPrev[0]; |
| evt.where_y = EVT.joyPrev[1]; |
| evt.relative_x = EVT.joyPrev[2]; |
| evt.relative_y = EVT.joyPrev[3]; |
| addEvent(&evt); |
| } |
| _EVT_restoreInt(ps); |
| } |
| |
| /* Read the joystick buttons, and post events to reflect the change |
| * in state for the joystick buttons. |
| */ |
| if (newButState != EVT.joyButState) { |
| if (EVT.count < EVENTQSIZE) { |
| /* Add a new joystick click event */ |
| ps = _EVT_disableInt(); |
| memset(&evt,0,sizeof(evt)); |
| evt.what = EVT_JOYCLICK; |
| evt.message = newButState; |
| EVT.evtq[EVT.oldJoyMove].where_x = EVT.joyPrev[0]; |
| EVT.evtq[EVT.oldJoyMove].where_y = EVT.joyPrev[1]; |
| EVT.evtq[EVT.oldJoyMove].relative_x = EVT.joyPrev[2]; |
| EVT.evtq[EVT.oldJoyMove].relative_y = EVT.joyPrev[3]; |
| addEvent(&evt); |
| _EVT_restoreInt(ps); |
| } |
| EVT.joyButState = newButState; |
| } |
| } |
| } |
| |
| /**************************************************************************** |
| DESCRIPTION: |
| Calibrates the joystick upper left position |
| |
| HEADER: |
| event.h |
| |
| REMARKS: |
| This function can be used to zero in on better joystick calibration factors, |
| which may work better than the default simplistic calibration (which assumes |
| the joystick is centered when the event library is initialised). |
| To use this function, ask the user to hold the stick in the upper left |
| position and then have them press a key or button. and then call this |
| function. This function will then read the joystick and update the |
| calibration factors. |
| |
| Usually, assuming that the stick was centered when the event library was |
| initialized, you really only need to call EVT_joySetLowerRight since the |
| upper left position is usually always 0,0 on most joysticks. However, the |
| safest procedure is to call all three calibration functions. |
| |
| SEE ALSO: |
| EVT_joySetUpperLeft, EVT_joySetLowerRight, EVT_joyIsPresent |
| ****************************************************************************/ |
| void EVTAPI EVT_joySetUpperLeft(void) |
| { |
| _EVT_readJoyAxis(EVT_JOY_AXIS_ALL,EVT.joyMin); |
| } |
| |
| /**************************************************************************** |
| DESCRIPTION: |
| Calibrates the joystick lower right position |
| |
| HEADER: |
| event.h |
| |
| REMARKS: |
| This function can be used to zero in on better joystick calibration factors, |
| which may work better than the default simplistic calibration (which assumes |
| the joystick is centered when the event library is initialised). |
| To use this function, ask the user to hold the stick in the lower right |
| position and then have them press a key or button. and then call this |
| function. This function will then read the joystick and update the |
| calibration factors. |
| |
| Usually, assuming that the stick was centered when the event library was |
| initialized, you really only need to call EVT_joySetLowerRight since the |
| upper left position is usually always 0,0 on most joysticks. However, the |
| safest procedure is to call all three calibration functions. |
| |
| SEE ALSO: |
| EVT_joySetUpperLeft, EVT_joySetCenter, EVT_joyIsPresent |
| ****************************************************************************/ |
| void EVTAPI EVT_joySetLowerRight(void) |
| { |
| _EVT_readJoyAxis(EVT_JOY_AXIS_ALL,EVT.joyMax); |
| } |
| |
| /**************************************************************************** |
| DESCRIPTION: |
| Calibrates the joystick center position |
| |
| HEADER: |
| event.h |
| |
| REMARKS: |
| This function can be used to zero in on better joystick calibration factors, |
| which may work better than the default simplistic calibration (which assumes |
| the joystick is centered when the event library is initialised). |
| To use this function, ask the user to hold the stick in the center |
| position and then have them press a key or button. and then call this |
| function. This function will then read the joystick and update the |
| calibration factors. |
| |
| Usually, assuming that the stick was centered when the event library was |
| initialized, you really only need to call EVT_joySetLowerRight since the |
| upper left position is usually always 0,0 on most joysticks. However, the |
| safest procedure is to call all three calibration functions. |
| |
| SEE ALSO: |
| EVT_joySetUpperLeft, EVT_joySetLowerRight, EVT_joySetCenter |
| ****************************************************************************/ |
| void EVTAPI EVT_joySetCenter(void) |
| { |
| _EVT_readJoyAxis(EVT_JOY_AXIS_ALL,EVT.joyCenter); |
| } |
| #endif |
| |
| /**************************************************************************** |
| DESCRIPTION: |
| Posts a user defined event to the event queue |
| |
| HEADER: |
| event.h |
| |
| RETURNS: |
| True if event was posted, false if event queue is full. |
| |
| PARAMETERS: |
| what - Type code for message to post |
| message - Event specific message to post |
| modifiers - Event specific modifier flags to post |
| |
| REMARKS: |
| This routine is used to post user defined events to the event queue. |
| |
| SEE ALSO: |
| EVT_flush, EVT_getNext, EVT_peekNext, EVT_halt |
| ****************************************************************************/ |
| ibool EVTAPI EVT_post( |
| ulong which, |
| ulong what, |
| ulong message, |
| ulong modifiers) |
| { |
| event_t evt; |
| uint ps; |
| |
| if (EVT.count < EVENTQSIZE) { |
| /* Save information in event record */ |
| ps = _EVT_disableInt(); |
| evt.which = which; |
| evt.when = _EVT_getTicks(); |
| evt.what = what; |
| evt.message = message; |
| evt.modifiers = modifiers; |
| addEvent(&evt); /* Add to EVT.tail of event queue */ |
| _EVT_restoreInt(ps); |
| return true; |
| } |
| else |
| return false; |
| } |
| |
| /**************************************************************************** |
| DESCRIPTION: |
| Flushes all events of a specified type from the event queue. |
| |
| PARAMETERS: |
| mask - Mask specifying the types of events that should be removed |
| |
| HEADER: |
| event.h |
| |
| REMARKS: |
| Flushes (removes) all pending events of the specified type from the event |
| queue. You may combine the masks for different event types with a simple |
| logical OR. |
| |
| SEE ALSO: |
| EVT_getNext, EVT_halt, EVT_peekNext |
| ****************************************************************************/ |
| void EVTAPI EVT_flush( |
| ulong mask) |
| { |
| event_t evt; |
| |
| do { /* Flush all events */ |
| EVT_getNext(&evt,mask); |
| } while (evt.what != EVT_NULLEVT); |
| } |
| |
| /**************************************************************************** |
| DESCRIPTION: |
| Halts until and event of the specified type is recieved. |
| |
| HEADER: |
| event.h |
| |
| PARAMETERS: |
| evt - Pointer to |
| mask - Mask specifying the types of events that should be removed |
| |
| REMARKS: |
| This functions halts exceution until an event of the specified type is |
| recieved into the event queue. It does not flush the event queue of events |
| before performing the busy loop. However this function does throw away |
| any events other than the ones you have requested via the event mask, to |
| avoid the event queue filling up with unwanted events (like EVT_KEYUP or |
| EVT_MOUSEMOVE events). |
| |
| SEE ALSO: |
| EVT_getNext, EVT_flush, EVT_peekNext |
| ****************************************************************************/ |
| void EVTAPI EVT_halt( |
| event_t *evt, |
| ulong mask) |
| { |
| do { /* Wait for an event */ |
| if (mask & (EVT_JOYEVT)) |
| EVT_pollJoystick(); |
| EVT_getNext(evt,EVT_EVERYEVT); |
| } while (!(evt->what & mask)); |
| } |
| |
| /**************************************************************************** |
| DESCRIPTION: |
| Peeks at the next pending event in the event queue. |
| |
| HEADER: |
| event.h |
| |
| RETURNS: |
| True if an event is pending, false if not. |
| |
| PARAMETERS: |
| evt - Pointer to structure to return the event info in |
| mask - Mask specifying the types of events that should be removed |
| |
| REMARKS: |
| Peeks at the next pending event of the specified type in the event queue. The |
| mask parameter is used to specify the type of events to be peeked at, and |
| can be any logical combination of any of the flags defined by the |
| EVT_eventType enumeration. |
| |
| In contrast to EVT_getNext, the event is not removed from the event queue. |
| You may combine the masks for different event types with a simple logical OR. |
| |
| SEE ALSO: |
| EVT_flush, EVT_getNext, EVT_halt |
| ****************************************************************************/ |
| ibool EVTAPI EVT_peekNext( |
| event_t *evt, |
| ulong mask) |
| { |
| int evtID; |
| uint ps; |
| |
| if (EVT.heartBeat) |
| EVT.heartBeat(EVT.heartBeatParams); |
| _EVT_pumpMessages(); /* Pump all messages into queue */ |
| EVT.mouseMove(EVT.mx,EVT.my); /* Move the mouse cursor */ |
| evt->what = EVT_NULLEVT; /* Default to null event */ |
| if (EVT.count) { |
| /* It is possible that an event be posted while we are trying |
| * to access the event queue. This would create problems since |
| * we may end up with invalid data for our event queue pointers. To |
| * alleviate this, all interrupts are suspended while we manipulate |
| * our pointers. |
| */ |
| ps = _EVT_disableInt(); /* disable interrupts */ |
| for (evtID = EVT.head; evtID != -1; evtID = EVT.evtq[evtID].next) { |
| if (EVT.evtq[evtID].what & mask) |
| break; /* Found an event */ |
| } |
| if (evtID == -1) { |
| _EVT_restoreInt(ps); |
| return false; /* Event was not found */ |
| } |
| *evt = EVT.evtq[evtID]; /* Return the event */ |
| _EVT_restoreInt(ps); |
| if (evt->what & EVT_KEYEVT) |
| _EVT_maskKeyCode(evt); |
| } |
| return evt->what != EVT_NULLEVT; |
| } |
| |
| /**************************************************************************** |
| DESCRIPTION: |
| Retrieves the next pending event from the event queue. |
| |
| PARAMETERS: |
| evt - Pointer to structure to return the event info in |
| mask - Mask specifying the types of events that should be removed |
| |
| HEADER: |
| event.h |
| |
| RETURNS: |
| True if an event was pending, false if not. |
| |
| REMARKS: |
| Retrieves the next pending event from the event queue, and stores it in a |
| event_t structure. The mask parameter is used to specify the type of events |
| to be removed, and can be any logical combination of any of the flags defined |
| by the EVT_eventType enumeration. |
| |
| The what field of the event contains the event code of the event that was |
| extracted. All application specific events should begin with the EVT_USEREVT |
| code and build from there. Since the event code is stored in an integer, |
| there is a maximum of 32 different event codes that can be distinguished. |
| You can store extra information about the event in the message field to |
| distinguish between events of the same class (for instance the button used in |
| a EVT_MOUSEDOWN event). |
| |
| If an event of the specified type was not in the event queue, the what field |
| of the event will be set to NULLEVT, and the return value will return false. |
| |
| Note: You should /always/ use the EVT_EVERYEVT mask for extracting events |
| from your main event loop handler. Using a mask for only a specific |
| type of event for long periods of time will cause the event queue to |
| fill up with events of the type you are ignoring, eventually causing |
| the application to hang when the event queue becomes full. |
| |
| SEE ALSO: |
| EVT_flush, EVT_halt, EVT_peekNext |
| ****************************************************************************/ |
| ibool EVTAPI EVT_getNext( |
| event_t *evt, |
| ulong mask) |
| { |
| int evtID,next,prev; |
| uint ps; |
| |
| if (EVT.heartBeat) |
| EVT.heartBeat(EVT.heartBeatParams); |
| _EVT_pumpMessages(); /* Pump all messages into queue */ |
| EVT.mouseMove(EVT.mx,EVT.my); /* Move the mouse cursor */ |
| evt->what = EVT_NULLEVT; /* Default to null event */ |
| if (EVT.count) { |
| /* It is possible that an event be posted while we are trying |
| * to access the event queue. This would create problems since |
| * we may end up with invalid data for our event queue pointers. To |
| * alleviate this, all interrupts are suspended while we manipulate |
| * our pointers. |
| */ |
| ps = _EVT_disableInt(); /* disable interrupts */ |
| for (evtID = EVT.head; evtID != -1; evtID = EVT.evtq[evtID].next) { |
| if (EVT.evtq[evtID].what & mask) |
| break; /* Found an event */ |
| } |
| if (evtID == -1) { |
| _EVT_restoreInt(ps); |
| return false; /* Event was not found */ |
| } |
| next = EVT.evtq[evtID].next; |
| prev = EVT.evtq[evtID].prev; |
| if (prev != -1) |
| EVT.evtq[prev].next = next; |
| else |
| EVT.head = next; |
| if (next != -1) |
| EVT.evtq[next].prev = prev; |
| else |
| EVT.tail = prev; |
| *evt = EVT.evtq[evtID]; /* Return the event */ |
| EVT.evtq[evtID].next = EVT.freeHead; /* and return to free list */ |
| EVT.freeHead = evtID; |
| EVT.count--; |
| if (evt->what == EVT_MOUSEMOVE) |
| EVT.oldMove = -1; |
| if (evt->what == EVT_KEYREPEAT) |
| EVT.oldKey = -1; |
| if (evt->what == EVT_JOYMOVE) |
| EVT.oldJoyMove = -1; |
| _EVT_restoreInt(ps); /* enable interrupts */ |
| if (evt->what & EVT_KEYEVT) |
| _EVT_maskKeyCode(evt); |
| } |
| |
| /* If there is no event pending, check if we should generate an auto |
| * mouse down event if the mouse is still currently down. |
| */ |
| if (evt->what == EVT_NULLEVT && EVT.autoRepeat && (mask & EVT_MOUSEAUTO) && (EVT.downMouse.what & EVT_MOUSEDOWN)) { |
| ulong ticks = _EVT_getTicks(); |
| if ((ticks - EVT.autoTicks) >= (EVT.autoRepeat + (EVT.firstAuto ? EVT.autoDelay : 0))) { |
| evt->what = EVT_MOUSEAUTO; |
| evt->message = EVT.downMouse.message; |
| evt->modifiers = EVT.downMouse.modifiers; |
| evt->where_x = EVT.autoMouse_x; |
| evt->where_y = EVT.autoMouse_y; |
| evt->relative_x = 0; |
| evt->relative_y = 0; |
| EVT.autoTicks = evt->when = ticks; |
| EVT.firstAuto = false; |
| } |
| } |
| return evt->what != EVT_NULLEVT; |
| } |
| |
| /**************************************************************************** |
| DESCRIPTION: |
| Installs a user supplied event filter callback for event handling. |
| |
| HEADER: |
| event.h |
| |
| PARAMETERS: |
| userEventFilter - Address of user supplied event filter callback |
| |
| REMARKS: |
| This function allows the application programmer to install an event filter |
| callback for event handling. Once you install your callback, the MGL |
| event handling routines will call your callback with a pointer to the |
| new event that will be placed into the event queue. Your callback can the |
| modify the contents of the event before it is placed into the queue (for |
| instance adding custom information or perhaps high precision timing |
| information). |
| |
| If your callback returns FALSE, the event will be ignore and will not be |
| posted to the event queue. You should always return true from your event |
| callback unless you plan to use the events immediately that they are |
| recieved. |
| |
| Note: Your event callback may be called in response to a hardware |
| interrupt and will be executing in the context of the hardware |
| interrupt handler under MSDOS (ie: keyboard interrupt or mouse |
| interrupt). For this reason the code pages for the callback that |
| you register must be locked in memory with the PM_lockCodePages |
| function. You must also lock down any data pages that your function |
| needs to reference as well. |
| |
| Note: You can also use this filter callback to process events at the |
| time they are activated by the user (ie: when the user hits the |
| key or moves the mouse), but make sure your code runs as fast as |
| possible as it will be executing inside the context of an interrupt |
| handler on some systems. |
| |
| SEE ALSO: |
| EVT_getNext, EVT_peekNext |
| ****************************************************************************/ |
| void EVTAPI EVT_setUserEventFilter( |
| _EVT_userEventFilter filter) |
| { |
| EVT.userEventCallback = filter; |
| } |
| |
| /**************************************************************************** |
| DESCRIPTION: |
| Installs a user supplied event heartbeat callback function. |
| |
| HEADER: |
| event.h |
| |
| PARAMETERS: |
| callback - Address of user supplied event heartbeat callback |
| params - Parameters to pass to the event heartbeat function |
| |
| REMARKS: |
| This function allows the application programmer to install an event heatbeat |
| function that gets called every time that EVT_getNext or EVT_peekNext |
| is called. This is primarily useful for simulating text mode cursors inside |
| event handling code when running in graphics modes as opposed to hardware |
| text modes. |
| |
| SEE ALSO: |
| EVT_getNext, EVT_peekNext, EVT_getHeartBeatCallback |
| ****************************************************************************/ |
| void EVTAPI EVT_setHeartBeatCallback( |
| _EVT_heartBeatCallback callback, |
| void *params) |
| { |
| EVT.heartBeat = callback; |
| EVT.heartBeatParams = params; |
| } |
| |
| |
| /**************************************************************************** |
| DESCRIPTION: |
| Returns the current user supplied event heartbeat callback function. |
| |
| HEADER: |
| event.h |
| |
| PARAMETERS: |
| callback - Place to store the address of user supplied event heartbeat callback |
| params - Place to store the parameters to pass to the event heartbeat function |
| |
| REMARKS: |
| This function retrieves the current event heatbeat function that gets called |
| every time that EVT_getNext or EVT_peekNext is called. |
| |
| SEE ALSO: |
| EVT_getNext, EVT_peekNext, EVT_setHeartBeatCallback |
| ****************************************************************************/ |
| void EVTAPI EVT_getHeartBeatCallback( |
| _EVT_heartBeatCallback *callback, |
| void **params) |
| { |
| *callback = EVT.heartBeat; |
| *params = EVT.heartBeatParams; |
| } |
| |
| /**************************************************************************** |
| DESCRIPTION: |
| Determines if a specified key is currently down. |
| |
| PARAMETERS: |
| scanCode - Scan code to test |
| |
| RETURNS: |
| True of the specified key is currently held down. |
| |
| HEADER: |
| event.h |
| |
| REMARKS: |
| This function determines if a specified key is currently down at the |
| time that the call is made. You simply need to pass in the scan code of |
| the key that you wish to test, and the MGL will tell you if it is currently |
| down or not. The MGL does this by keeping track of the up and down state |
| of all the keys. |
| ****************************************************************************/ |
| ibool EVTAPI EVT_isKeyDown( |
| uchar scanCode) |
| { |
| return _EVT_isKeyDown(scanCode); |
| } |
| |
| /**************************************************************************** |
| DESCRIPTION: |
| Set the mouse position for the event module |
| |
| PARAMETERS: |
| x - X coordinate to move the mouse cursor position to |
| y - Y coordinate to move the mouse cursor position to |
| |
| HEADER: |
| event.h |
| |
| REMARKS: |
| This function moves the mouse cursor position for the event module to the |
| specified location. |
| |
| SEE ALSO: |
| EVT_getMousePos |
| ****************************************************************************/ |
| void EVTAPI EVT_setMousePos( |
| int x, |
| int y) |
| { |
| EVT.mx = x; |
| EVT.my = y; |
| _EVT_setMousePos(&EVT.mx,&EVT.my); |
| EVT.mouseMove(EVT.mx,EVT.my); |
| } |
| |
| /**************************************************************************** |
| DESCRIPTION: |
| Returns the current mouse cursor location. |
| |
| HEADER: |
| event.h |
| |
| PARAMETERS: |
| x - Place to store value for mouse x coordinate (screen coordinates) |
| y - Place to store value for mouse y coordinate (screen coordinates) |
| |
| REMARKS: |
| Obtains the current mouse cursor position in screen coordinates. Normally the |
| mouse cursor location is tracked using the mouse movement events that are |
| posted to the event queue when the mouse moves, however this routine |
| provides an alternative method of polling the mouse cursor location. |
| |
| SEE ALSO: |
| EVT_setMousePos |
| ****************************************************************************/ |
| void EVTAPI EVT_getMousePos( |
| int *x, |
| int *y) |
| { |
| *x = EVT.mx; |
| *y = EVT.my; |
| } |
| |
| /**************************************************************************** |
| DESCRIPTION: |
| Returns the currently active code page for translation of keyboard characters. |
| |
| HEADER: |
| event.h |
| |
| RETURNS: |
| Pointer to the currently active code page translation table. |
| |
| REMARKS: |
| This function is returns a pointer to the currently active code page |
| translation table. See EVT_setCodePage for more information. |
| |
| SEE ALSO: |
| EVT_setCodePage |
| ****************************************************************************/ |
| codepage_t * EVTAPI EVT_getCodePage(void) |
| { |
| return EVT.codePage; |
| } |
| |
| /**************************************************************************** |
| DESCRIPTION: |
| Sets the currently active code page for translation of keyboard characters. |
| |
| HEADER: |
| event.h |
| |
| PARAMETERS: |
| page - New code page to make active |
| |
| REMARKS: |
| This function is used to set a new code page translation table that is used |
| to translate virtual scan code values to ASCII characters for different |
| keyboard configurations. The default is usually US English, although if |
| possible the PM library will auto-detect the correct code page translation |
| for the target OS if OS services are available to determine what type of |
| keyboard is currently attached. |
| |
| SEE ALSO: |
| EVT_getCodePage |
| ****************************************************************************/ |
| void EVTAPI EVT_setCodePage( |
| codepage_t *page) |
| { |
| EVT.codePage = page; |
| } |
| |
| /* The following contains fake C prototypes and documentation for the |
| * macro functions in the event.h header file. These exist soley so |
| * that DocJet will correctly pull in the documentation for these functions. |
| */ |
| #ifdef INCLUDE_DOC_FUNCTIONS |
| |
| /**************************************************************************** |
| DESCRIPTION: |
| Macro to extract the ASCII code from a message. |
| |
| PARAMETERS: |
| message - Message to extract ASCII code from |
| |
| RETURNS: |
| ASCII code extracted from the message. |
| |
| HEADER: |
| event.h |
| |
| REMARKS: |
| Macro to extract the ASCII code from the message field of the event_t |
| structure. You pass the message field to the macro as the parameter and |
| the ASCII code is the result, for example: |
| |
| event_t EVT.myEvent; |
| uchar code; |
| code = EVT_asciiCode(EVT.myEvent.message); |
| |
| SEE ALSO: |
| EVT_scanCode, EVT_repeatCount |
| ****************************************************************************/ |
| uchar EVT_asciiCode( |
| ulong message); |
| |
| /**************************************************************************** |
| DESCRIPTION: |
| Macro to extract the keyboard scan code from a message. |
| |
| HEADER: |
| event.h |
| |
| PARAMETERS: |
| message - Message to extract scan code from |
| |
| RETURNS: |
| Keyboard scan code extracted from the message. |
| |
| REMARKS: |
| Macro to extract the keyboard scan code from the message field of the event |
| structure. You pass the message field to the macro as the parameter and |
| the scan code is the result, for example: |
| |
| event_t EVT.myEvent; |
| uchar code; |
| code = EVT_scanCode(EVT.myEvent.message); |
| |
| NOTE: Scan codes in the event library are not really hardware scan codes, |
| but rather virtual scan codes as generated by a low level keyboard |
| interface driver. All virtual scan code values are defined by the |
| EVT_scanCodesType enumeration, and will be identical across all |
| supports OS'es and platforms. |
| |
| SEE ALSO: |
| EVT_asciiCode, EVT_repeatCount |
| ****************************************************************************/ |
| uchar EVT_scanCode( |
| ulong message); |
| |
| /**************************************************************************** |
| DESCRIPTION: |
| Macro to extract the repeat count from a message. |
| |
| HEADER: |
| event.h |
| |
| PARAMETERS: |
| message - Message to extract repeat count from |
| |
| RETURNS: |
| Repeat count extracted from the message. |
| |
| REMARKS: |
| Macro to extract the repeat count from the message field of the event |
| structure. The repeat count is the number of times that the key repeated |
| before there was another keyboard event to be place in the queue, and |
| allows the event handling code to avoid keyboard buffer overflow |
| conditions when a single key is held down by the user. If you are processing |
| a key repeat code, you will probably want to check this field to see how |
| many key repeats you should process for this message. |
| |
| SEE ALSO: |
| EVT_asciiCode, EVT_repeatCount |
| ****************************************************************************/ |
| short EVT_repeatCount( |
| ulong message); |
| |
| #endif /* DOC FUNCTIONS */ |
| |
| #if defined(__REALDOS__) || defined(__SMX32__) |
| /* {secret} */ |
| void EVTAPI _EVT_cCodeEnd(void) {} |
| #endif |