450 lines
13 KiB
C
450 lines
13 KiB
C
/****************************************************************************
|
|
*
|
|
* 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: Direct keyboard event handling module. This module contains
|
|
* code to process raw scan code information, convert it to
|
|
* virtual scan codes and do code page translation to ASCII
|
|
* for different international keyboard layouts.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/*---------------------------- Implementation -----------------------------*/
|
|
|
|
/****************************************************************************
|
|
PARAMETERS:
|
|
scanCode - Keyboard scan code to translate
|
|
table - Code page table to search
|
|
count - Number of entries in the code page table
|
|
|
|
REMARKS:
|
|
This function translates the scan codes from keyboard scan codes to ASCII
|
|
codes using a binary search on the code page table.
|
|
****************************************************************************/
|
|
static uchar translateScan(
|
|
uchar scanCode,
|
|
codepage_entry_t *table,
|
|
int count)
|
|
{
|
|
codepage_entry_t *test;
|
|
int n,pivot,val;
|
|
|
|
for (n = count; n > 0; ) {
|
|
pivot = n >> 1;
|
|
test = table + pivot;
|
|
val = scanCode - test->scanCode;
|
|
if (val < 0)
|
|
n = pivot;
|
|
else if (val == 0)
|
|
return test->asciiCode;
|
|
else {
|
|
table = test + 1;
|
|
n -= pivot + 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
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.
|
|
{secret}
|
|
****************************************************************************/
|
|
void _EVT_maskKeyCode(
|
|
event_t *evt)
|
|
{
|
|
int ascii,scan = EVT_scanCode(evt->message);
|
|
|
|
evt->message &= ~0xFF;
|
|
if (evt->modifiers & EVT_NUMLOCK) {
|
|
if ((ascii = translateScan(scan,EVT.codePage->numPad,EVT.codePage->numPadLen)) != 0) {
|
|
evt->message |= ascii;
|
|
return;
|
|
}
|
|
}
|
|
if (evt->modifiers & EVT_CTRLSTATE) {
|
|
evt->message |= translateScan(scan,EVT.codePage->ctrl,EVT.codePage->ctrlLen);
|
|
return;
|
|
}
|
|
if (evt->modifiers & EVT_CAPSLOCK) {
|
|
if (evt->modifiers & EVT_SHIFTKEY) {
|
|
if ((ascii = translateScan(scan,EVT.codePage->shiftCaps,EVT.codePage->shiftCapsLen)) != 0) {
|
|
evt->message |= ascii;
|
|
return;
|
|
}
|
|
}
|
|
else {
|
|
if ((ascii = translateScan(scan,EVT.codePage->caps,EVT.codePage->capsLen)) != 0) {
|
|
evt->message |= ascii;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
if (evt->modifiers & EVT_SHIFTKEY) {
|
|
if ((ascii = translateScan(scan,EVT.codePage->shift,EVT.codePage->shiftLen)) != 0) {
|
|
evt->message |= ascii;
|
|
return;
|
|
}
|
|
}
|
|
evt->message |= translateScan(scan,EVT.codePage->normal,EVT.codePage->normalLen);
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Returns true if the key with the specified scan code is being held down.
|
|
****************************************************************************/
|
|
static ibool _EVT_isKeyDown(
|
|
uchar scanCode)
|
|
{
|
|
if (scanCode > 0x7F)
|
|
return false;
|
|
else
|
|
return EVT.keyTable[scanCode] != 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
PARAMETERS:
|
|
what - Event code
|
|
message - Event message (ASCII code and scan code)
|
|
|
|
REMARKS:
|
|
Adds a new keyboard event to the event queue. This routine is called from
|
|
within the keyboard interrupt subroutine!
|
|
|
|
NOTE: Interrupts are OFF when this routine is called by the keyboard ISR,
|
|
and we leave them OFF the entire time.
|
|
****************************************************************************/
|
|
static void addKeyEvent(
|
|
uint what,
|
|
uint message)
|
|
{
|
|
event_t evt;
|
|
|
|
if (EVT.count < EVENTQSIZE) {
|
|
/* Save information in event record */
|
|
evt.when = _EVT_getTicks();
|
|
evt.what = what;
|
|
evt.message = message | 0x10000UL;
|
|
evt.where_x = 0;
|
|
evt.where_y = 0;
|
|
evt.relative_x = 0;
|
|
evt.relative_y = 0;
|
|
evt.modifiers = EVT.keyModifiers;
|
|
if (evt.what == EVT_KEYREPEAT) {
|
|
if (EVT.oldKey != -1)
|
|
EVT.evtq[EVT.oldKey].message += 0x10000UL;
|
|
else {
|
|
EVT.oldKey = EVT.freeHead;
|
|
addEvent(&evt); /* Add to tail of event queue */
|
|
}
|
|
}
|
|
else {
|
|
#ifdef __QNX__
|
|
_EVT_maskKeyCode(&evt);
|
|
#endif
|
|
addEvent(&evt); /* Add to tail of event queue */
|
|
}
|
|
EVT.oldMove = -1;
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
This function waits for the keyboard controller to set the ready-for-write
|
|
bit.
|
|
****************************************************************************/
|
|
static int kbWaitForWriteReady(void)
|
|
{
|
|
int timeout = 8192;
|
|
while ((timeout > 0) && (PM_inpb(0x64) & 0x02))
|
|
timeout--;
|
|
return (timeout > 0);
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
This function waits for the keyboard controller to set the ready-for-read
|
|
bit.
|
|
****************************************************************************/
|
|
static int kbWaitForReadReady(void)
|
|
{
|
|
int timeout = 8192;
|
|
while ((timeout > 0) && (!(PM_inpb(0x64) & 0x01)))
|
|
timeout--;
|
|
return (timeout > 0);
|
|
}
|
|
|
|
/****************************************************************************
|
|
PARAMETERS:
|
|
data - Data to send to the keyboard
|
|
|
|
REMARKS:
|
|
This function sends a data byte to the keyboard controller.
|
|
****************************************************************************/
|
|
static int kbSendData(
|
|
uchar data)
|
|
{
|
|
int resends = 4;
|
|
int timeout, temp;
|
|
|
|
do {
|
|
if (!kbWaitForWriteReady())
|
|
return 0;
|
|
PM_outpb(0x60,data);
|
|
timeout = 8192;
|
|
while (--timeout > 0) {
|
|
if (!kbWaitForReadReady())
|
|
return 0;
|
|
temp = PM_inpb(0x60);
|
|
if (temp == 0xFA)
|
|
return 1;
|
|
if (temp == 0xFE)
|
|
break;
|
|
}
|
|
} while ((resends-- > 0) && (timeout > 0));
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
PARAMETERS:
|
|
modifiers - Keyboard modifier flags
|
|
|
|
REMARKS:
|
|
This function re-programs the LED's on the keyboard to the values stored
|
|
in the passed in modifier flags. If the 'allowLEDS' flag is false, this
|
|
function does nothing.
|
|
****************************************************************************/
|
|
static void setLEDS(
|
|
uint modifiers)
|
|
{
|
|
if (EVT.allowLEDS) {
|
|
if (!kbSendData(0xED) || !kbSendData((modifiers>>9) & 7)) {
|
|
kbSendData(0xF4);
|
|
}
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Function to process raw scan codes read from the keyboard controller.
|
|
|
|
NOTE: Interrupts are OFF when this routine is called by the keyboard ISR,
|
|
and we leave them OFF the entire time.
|
|
{secret}
|
|
****************************************************************************/
|
|
void processRawScanCode(
|
|
int scan)
|
|
{
|
|
static int pauseLoop = 0;
|
|
static int extended = 0;
|
|
int what;
|
|
|
|
if (pauseLoop) {
|
|
/* Skip scan codes until the pause key sequence has been read */
|
|
pauseLoop--;
|
|
}
|
|
else if (scan == 0xE0) {
|
|
/* This signals the start of an extended scan code sequence */
|
|
extended = 1;
|
|
}
|
|
else if (scan == 0xE1) {
|
|
/* The Pause key sends a strange scan code sequence, which is:
|
|
*
|
|
* E1 1D 52 E1 9D D2
|
|
*
|
|
* However there is never any release code nor any auto-repeat for
|
|
* this key. For this reason we simply ignore the key and skip the
|
|
* next 5 scan codes read from the keyboard.
|
|
*/
|
|
pauseLoop = 5;
|
|
}
|
|
else {
|
|
/* Process the scan code normally (it may be an extended code
|
|
* however!). Bit 7 means key was released, and bits 0-6 are the
|
|
* scan code.
|
|
*/
|
|
what = (scan & 0x80) ? EVT_KEYUP : EVT_KEYDOWN;
|
|
scan &= 0x7F;
|
|
if (extended) {
|
|
extended = 0;
|
|
if (scan == 0x2A || scan == 0x36) {
|
|
/* Ignore these extended scan code sequences. These are
|
|
* used by the keyboard controller to wrap around certain
|
|
* key sequences for the keypad (and when NUMLOCK is down
|
|
* internally).
|
|
*/
|
|
return;
|
|
}
|
|
|
|
/* Convert extended codes for key sequences that we map to
|
|
* virtual scan codes so the user can detect them in their
|
|
* code.
|
|
*/
|
|
switch (scan) {
|
|
case KB_leftCtrl: scan = KB_rightCtrl; break;
|
|
case KB_leftAlt: scan = KB_rightAlt; break;
|
|
case KB_divide: scan = KB_padDivide; break;
|
|
case KB_enter: scan = KB_padEnter; break;
|
|
case KB_padTimes: scan = KB_sysReq; break;
|
|
}
|
|
}
|
|
else {
|
|
/* Convert regular scan codes for key sequences that we map to
|
|
* virtual scan codes so the user can detect them in their
|
|
* code.
|
|
*/
|
|
switch (scan) {
|
|
case KB_left: scan = KB_padLeft; break;
|
|
case KB_right: scan = KB_padRight; break;
|
|
case KB_up: scan = KB_padUp; break;
|
|
case KB_down: scan = KB_padDown; break;
|
|
case KB_insert: scan = KB_padInsert; break;
|
|
case KB_delete: scan = KB_padDelete; break;
|
|
case KB_home: scan = KB_padHome; break;
|
|
case KB_end: scan = KB_padEnd; break;
|
|
case KB_pageUp: scan = KB_padPageUp; break;
|
|
case KB_pageDown: scan = KB_padPageDown; break;
|
|
}
|
|
}
|
|
|
|
/* Determine if the key is an UP, DOWN or REPEAT and maintain the
|
|
* up/down status of all keys in our global key array.
|
|
*/
|
|
if (what == EVT_KEYDOWN) {
|
|
if (EVT.keyTable[scan])
|
|
what = EVT_KEYREPEAT;
|
|
else
|
|
EVT.keyTable[scan] = scan;
|
|
}
|
|
else {
|
|
EVT.keyTable[scan] = 0;
|
|
}
|
|
|
|
/* Handle shift key modifiers */
|
|
if (what != EVT_KEYREPEAT) {
|
|
switch (scan) {
|
|
case KB_capsLock:
|
|
if (what == EVT_KEYDOWN)
|
|
EVT.keyModifiers ^= EVT_CAPSLOCK;
|
|
setLEDS(EVT.keyModifiers);
|
|
break;
|
|
case KB_numLock:
|
|
if (what == EVT_KEYDOWN)
|
|
EVT.keyModifiers ^= EVT_NUMLOCK;
|
|
setLEDS(EVT.keyModifiers);
|
|
break;
|
|
case KB_scrollLock:
|
|
if (what == EVT_KEYDOWN)
|
|
EVT.keyModifiers ^= EVT_SCROLLLOCK;
|
|
setLEDS(EVT.keyModifiers);
|
|
break;
|
|
case KB_leftShift:
|
|
if (what == EVT_KEYUP)
|
|
EVT.keyModifiers &= ~EVT_LEFTSHIFT;
|
|
else
|
|
EVT.keyModifiers |= EVT_LEFTSHIFT;
|
|
break;
|
|
case KB_rightShift:
|
|
if (what == EVT_KEYUP)
|
|
EVT.keyModifiers &= ~EVT_RIGHTSHIFT;
|
|
else
|
|
EVT.keyModifiers |= EVT_RIGHTSHIFT;
|
|
break;
|
|
case KB_leftCtrl:
|
|
if (what == EVT_KEYUP)
|
|
EVT.keyModifiers &= ~EVT_LEFTCTRL;
|
|
else
|
|
EVT.keyModifiers |= EVT_LEFTCTRL;
|
|
break;
|
|
case KB_rightCtrl:
|
|
if (what == EVT_KEYUP)
|
|
EVT.keyModifiers &= ~EVT_RIGHTCTRL;
|
|
else
|
|
EVT.keyModifiers |= EVT_RIGHTCTRL;
|
|
break;
|
|
case KB_leftAlt:
|
|
if (what == EVT_KEYUP)
|
|
EVT.keyModifiers &= ~EVT_LEFTALT;
|
|
else
|
|
EVT.keyModifiers |= EVT_LEFTALT;
|
|
break;
|
|
case KB_rightAlt:
|
|
if (what == EVT_KEYUP)
|
|
EVT.keyModifiers &= ~EVT_RIGHTALT;
|
|
else
|
|
EVT.keyModifiers |= EVT_RIGHTALT;
|
|
break;
|
|
#ifdef SUPPORT_CTRL_ALT_DEL
|
|
case KB_delete:
|
|
if ((EVT.keyModifiers & EVT_CTRLSTATE) && (EVT.keyModifiers & EVT_ALTSTATE))
|
|
Reboot();
|
|
break;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/* Add the untranslated key code to the event queue. All
|
|
* translation to ASCII from the key codes occurs when the key
|
|
* is extracted from the queue, saving time in the low level
|
|
* interrupt handler.
|
|
*/
|
|
addKeyEvent(what,scan << 8);
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
DESCRIPTION:
|
|
Enables/disables the update of the keyboard LED status indicators.
|
|
|
|
HEADER:
|
|
event.h
|
|
|
|
PARAMETERS:
|
|
enable - True to enable, false to disable
|
|
|
|
REMARKS:
|
|
Enables the update of the keyboard LED status indicators. Sometimes it may
|
|
be convenient in the application to turn off the updating of the LED
|
|
status indicators (such as if a game is using the CAPSLOCK key for some
|
|
function). Passing in a value of FALSE to this function will turn off all
|
|
the LEDS, and stop updating them when the internal status changes (note
|
|
however that internally we still keep track of the toggle key status!).
|
|
****************************************************************************/
|
|
void EVTAPI EVT_allowLEDS(
|
|
ibool enable)
|
|
{
|
|
EVT.allowLEDS = true;
|
|
if (enable)
|
|
setLEDS(EVT.keyModifiers);
|
|
else
|
|
setLEDS(0);
|
|
EVT.allowLEDS = enable;
|
|
}
|