1 /****************************************************************************
3 * SciTech OS Portability Manager 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: Direct keyboard event handling module. This module contains
28 * code to process raw scan code information, convert it to
29 * virtual scan codes and do code page translation to ASCII
30 * for different international keyboard layouts.
32 ****************************************************************************/
34 /*---------------------------- Implementation -----------------------------*/
36 /****************************************************************************
38 scanCode - Keyboard scan code to translate
39 table - Code page table to search
40 count - Number of entries in the code page table
43 This function translates the scan codes from keyboard scan codes to ASCII
44 codes using a binary search on the code page table.
45 ****************************************************************************/
46 static uchar translateScan(
48 codepage_entry_t *table,
51 codepage_entry_t *test;
54 for (n = count; n > 0; ) {
57 val = scanCode - test->scanCode;
61 return test->asciiCode;
70 /****************************************************************************
72 This macro/function is used to converts the scan codes reported by the
73 keyboard to our event libraries normalised format. We only have one scan
74 code for the 'A' key, and use shift modifiers to determine if it is a
75 Ctrl-F1, Alt-F1 etc. The raw scan codes from the keyboard work this way,
76 but the OS gives us 'cooked' scan codes, we have to translate them back
79 ****************************************************************************/
80 void _EVT_maskKeyCode(
83 int ascii,scan = EVT_scanCode(evt->message);
85 evt->message &= ~0xFF;
86 if (evt->modifiers & EVT_NUMLOCK) {
87 if ((ascii = translateScan(scan,EVT.codePage->numPad,EVT.codePage->numPadLen)) != 0) {
88 evt->message |= ascii;
92 if (evt->modifiers & EVT_CTRLSTATE) {
93 evt->message |= translateScan(scan,EVT.codePage->ctrl,EVT.codePage->ctrlLen);
96 if (evt->modifiers & EVT_CAPSLOCK) {
97 if (evt->modifiers & EVT_SHIFTKEY) {
98 if ((ascii = translateScan(scan,EVT.codePage->shiftCaps,EVT.codePage->shiftCapsLen)) != 0) {
99 evt->message |= ascii;
104 if ((ascii = translateScan(scan,EVT.codePage->caps,EVT.codePage->capsLen)) != 0) {
105 evt->message |= ascii;
110 if (evt->modifiers & EVT_SHIFTKEY) {
111 if ((ascii = translateScan(scan,EVT.codePage->shift,EVT.codePage->shiftLen)) != 0) {
112 evt->message |= ascii;
116 evt->message |= translateScan(scan,EVT.codePage->normal,EVT.codePage->normalLen);
119 /****************************************************************************
121 Returns true if the key with the specified scan code is being held down.
122 ****************************************************************************/
123 static ibool _EVT_isKeyDown(
129 return EVT.keyTable[scanCode] != 0;
132 /****************************************************************************
135 message - Event message (ASCII code and scan code)
138 Adds a new keyboard event to the event queue. This routine is called from
139 within the keyboard interrupt subroutine!
141 NOTE: Interrupts are OFF when this routine is called by the keyboard ISR,
142 and we leave them OFF the entire time.
143 ****************************************************************************/
144 static void addKeyEvent(
150 if (EVT.count < EVENTQSIZE) {
151 /* Save information in event record */
152 evt.when = _EVT_getTicks();
154 evt.message = message | 0x10000UL;
159 evt.modifiers = EVT.keyModifiers;
160 if (evt.what == EVT_KEYREPEAT) {
161 if (EVT.oldKey != -1)
162 EVT.evtq[EVT.oldKey].message += 0x10000UL;
164 EVT.oldKey = EVT.freeHead;
165 addEvent(&evt); /* Add to tail of event queue */
170 _EVT_maskKeyCode(&evt);
172 addEvent(&evt); /* Add to tail of event queue */
178 /****************************************************************************
180 This function waits for the keyboard controller to set the ready-for-write
182 ****************************************************************************/
183 static int kbWaitForWriteReady(void)
186 while ((timeout > 0) && (PM_inpb(0x64) & 0x02))
188 return (timeout > 0);
191 /****************************************************************************
193 This function waits for the keyboard controller to set the ready-for-read
195 ****************************************************************************/
196 static int kbWaitForReadReady(void)
199 while ((timeout > 0) && (!(PM_inpb(0x64) & 0x01)))
201 return (timeout > 0);
204 /****************************************************************************
206 data - Data to send to the keyboard
209 This function sends a data byte to the keyboard controller.
210 ****************************************************************************/
211 static int kbSendData(
218 if (!kbWaitForWriteReady())
222 while (--timeout > 0) {
223 if (!kbWaitForReadReady())
225 temp = PM_inpb(0x60);
231 } while ((resends-- > 0) && (timeout > 0));
235 /****************************************************************************
237 modifiers - Keyboard modifier flags
240 This function re-programs the LED's on the keyboard to the values stored
241 in the passed in modifier flags. If the 'allowLEDS' flag is false, this
242 function does nothing.
243 ****************************************************************************/
248 if (!kbSendData(0xED) || !kbSendData((modifiers>>9) & 7)) {
254 /****************************************************************************
256 Function to process raw scan codes read from the keyboard controller.
258 NOTE: Interrupts are OFF when this routine is called by the keyboard ISR,
259 and we leave them OFF the entire time.
261 ****************************************************************************/
262 void processRawScanCode(
265 static int pauseLoop = 0;
266 static int extended = 0;
270 /* Skip scan codes until the pause key sequence has been read */
273 else if (scan == 0xE0) {
274 /* This signals the start of an extended scan code sequence */
277 else if (scan == 0xE1) {
278 /* The Pause key sends a strange scan code sequence, which is:
282 * However there is never any release code nor any auto-repeat for
283 * this key. For this reason we simply ignore the key and skip the
284 * next 5 scan codes read from the keyboard.
289 /* Process the scan code normally (it may be an extended code
290 * however!). Bit 7 means key was released, and bits 0-6 are the
293 what = (scan & 0x80) ? EVT_KEYUP : EVT_KEYDOWN;
297 if (scan == 0x2A || scan == 0x36) {
298 /* Ignore these extended scan code sequences. These are
299 * used by the keyboard controller to wrap around certain
300 * key sequences for the keypad (and when NUMLOCK is down
306 /* Convert extended codes for key sequences that we map to
307 * virtual scan codes so the user can detect them in their
311 case KB_leftCtrl: scan = KB_rightCtrl; break;
312 case KB_leftAlt: scan = KB_rightAlt; break;
313 case KB_divide: scan = KB_padDivide; break;
314 case KB_enter: scan = KB_padEnter; break;
315 case KB_padTimes: scan = KB_sysReq; break;
319 /* Convert regular scan codes for key sequences that we map to
320 * virtual scan codes so the user can detect them in their
324 case KB_left: scan = KB_padLeft; break;
325 case KB_right: scan = KB_padRight; break;
326 case KB_up: scan = KB_padUp; break;
327 case KB_down: scan = KB_padDown; break;
328 case KB_insert: scan = KB_padInsert; break;
329 case KB_delete: scan = KB_padDelete; break;
330 case KB_home: scan = KB_padHome; break;
331 case KB_end: scan = KB_padEnd; break;
332 case KB_pageUp: scan = KB_padPageUp; break;
333 case KB_pageDown: scan = KB_padPageDown; break;
337 /* Determine if the key is an UP, DOWN or REPEAT and maintain the
338 * up/down status of all keys in our global key array.
340 if (what == EVT_KEYDOWN) {
341 if (EVT.keyTable[scan])
342 what = EVT_KEYREPEAT;
344 EVT.keyTable[scan] = scan;
347 EVT.keyTable[scan] = 0;
350 /* Handle shift key modifiers */
351 if (what != EVT_KEYREPEAT) {
354 if (what == EVT_KEYDOWN)
355 EVT.keyModifiers ^= EVT_CAPSLOCK;
356 setLEDS(EVT.keyModifiers);
359 if (what == EVT_KEYDOWN)
360 EVT.keyModifiers ^= EVT_NUMLOCK;
361 setLEDS(EVT.keyModifiers);
364 if (what == EVT_KEYDOWN)
365 EVT.keyModifiers ^= EVT_SCROLLLOCK;
366 setLEDS(EVT.keyModifiers);
369 if (what == EVT_KEYUP)
370 EVT.keyModifiers &= ~EVT_LEFTSHIFT;
372 EVT.keyModifiers |= EVT_LEFTSHIFT;
375 if (what == EVT_KEYUP)
376 EVT.keyModifiers &= ~EVT_RIGHTSHIFT;
378 EVT.keyModifiers |= EVT_RIGHTSHIFT;
381 if (what == EVT_KEYUP)
382 EVT.keyModifiers &= ~EVT_LEFTCTRL;
384 EVT.keyModifiers |= EVT_LEFTCTRL;
387 if (what == EVT_KEYUP)
388 EVT.keyModifiers &= ~EVT_RIGHTCTRL;
390 EVT.keyModifiers |= EVT_RIGHTCTRL;
393 if (what == EVT_KEYUP)
394 EVT.keyModifiers &= ~EVT_LEFTALT;
396 EVT.keyModifiers |= EVT_LEFTALT;
399 if (what == EVT_KEYUP)
400 EVT.keyModifiers &= ~EVT_RIGHTALT;
402 EVT.keyModifiers |= EVT_RIGHTALT;
404 #ifdef SUPPORT_CTRL_ALT_DEL
406 if ((EVT.keyModifiers & EVT_CTRLSTATE) && (EVT.keyModifiers & EVT_ALTSTATE))
413 /* Add the untranslated key code to the event queue. All
414 * translation to ASCII from the key codes occurs when the key
415 * is extracted from the queue, saving time in the low level
418 addKeyEvent(what,scan << 8);
422 /****************************************************************************
424 Enables/disables the update of the keyboard LED status indicators.
430 enable - True to enable, false to disable
433 Enables the update of the keyboard LED status indicators. Sometimes it may
434 be convenient in the application to turn off the updating of the LED
435 status indicators (such as if a game is using the CAPSLOCK key for some
436 function). Passing in a value of FALSE to this function will turn off all
437 the LEDS, and stop updating them when the internal status changes (note
438 however that internally we still keep track of the toggle key status!).
439 ****************************************************************************/
440 void EVTAPI EVT_allowLEDS(
443 EVT.allowLEDS = true;
445 setLEDS(EVT.keyModifiers);
448 EVT.allowLEDS = enable;