NKCC - NORMALIZED KEY CODE CONVERTER ============================================================================= Release 2.92 Written by Harald Siegmund Copyright (c) 1989-1994 NKCC is Public Domain and may be used by anyone. Don't change or delete any files of the NKCC folder. Please put a small note in your application's info box if it contains NKCC (for example "Keyboard handler by Harald Siegmund"). Thanx! ----------------------------------------------------------------------------- Documentation and program history: 1989: May 14: introducing NKCC (release 1.00) Jun/Jul: improvements, changes, debugging 1990: Jan 13: further improvements May 27-28: creation of file (complete new documentation for NKCC 2.x) Jun 16-27: multi event assembler entry added by Gerd Knops Jun 30: release 1.10: return shift state flags (returned by nkc_multi()) compatible to NKF_... flags Jul 09: release 1.20: new function: nkc_kstate() Aug 03: release 1.30: new function: nkc_cmp() Aug 18: bug fixed in nkc_kstate() Sep 15-16: release 1.40: mouse button event handler; nkc_timer() Oct 03: renaming NKCC II release 1.40 to NKCC release 2.40 function overview Oct 30: removing chapter 6 (notes for users of NKCC 1.xx) Nov 13: release 2.41: NK_LEFT and NK_RIGHT exchanged Dec 11: release 2.50: MU_XTIMER 1991: Jan 11: release 2.51: better handling of MU_XTIMER Apr 14: release 2.60: nkc_conv() renamed to nkc_tconv(); new function nkc_gconv() rearranging and partly rewriting documentation May 10: release 2.61 (debugging) May 29: release 2.62: nkc_toupper, nkc_tolower Jun 08: doing some small corrections of the documentation Aug 06: release 2.63: quote (") is now used as synonym for umlaut (Ή) in deadkey handling Aug 07: more deadkeys... Aug 22: release 2.70: deadkeys can now be enabled/disabled separately additional note in 3.b) nkc_init() now returns version # Sep 07: release 2.71: nkc_cmp() improved NKF_RESVD is now used: in key codes for internal purposes! in reference key code (nkc_cmp()) as flag Nov 05: release 2.72: adjustments to ASCII input feature of TOS 3.06 Nov 16: release 2.80: small bug fixed in nkc_cmp() control key emulation (NKS_CTRL) (see chapter 1) Dec 29: minor changes in source documentation; a few new (less important) symbols were added 1992: Jan 03/06: introducing release 2.81: - nkc_init's first parameter is now an unsigned long - the symbolic identifiers BE_ON/OFF/TOS are redefined, but still have the same meaning - new symbols: NKI_... - chapters 4, 7 and 9 were adjusted respectively completed due to the changes in nkc_init() - chapters 8 and 9 got additional notes about nkc_timer() Feb 14: correcting documentation of nkc_exit() in chapter 4 Feb 28: NKCOWNPB switch 1993: Dec 11: release 2.90: - NKCC_GPB.O and SDOCSYNT.S are no longer part of the package - Selecting the version of NKCC for assembling (GEM or TOS) is done by a different symbol now: NKCGEM - NKCC uses its own AES/VDI parameter arrays now, execpt for the global array, which is passed as additional parameter to function nkc_init() - nkc_toupper and nkc_tolower are functions now rather than arrays - cosmetic changes in the documentation - new developer address Dec 12: introducing new functions nkc_n2tos() and nkc_n2gem() (which convert key codes in normalized format back to the system's format; see NKCC.TXT for details) 1994: Feb 01: adding MausNet address to documentation May 19: release 2.91: - nkc_exit won't touch the system variable contern any longer because it may have been changed by a parallel running process - two new deadkeys were introduced: / + 2 = « / + 4 = ¬ - the synatx of MadMac's directives has been added to the NKCC source file (and NKCC.TXT) Jun 27: release 2.92: - NKCC now recognizes invalid scan codes. Their treatment is described in chapter 3. ----------------------------------------------------------------------------- Developer contact: as adequate systems Gesellschaft fr angemessene Systeml”sungen mbH c/o Harald Siegmund Am Steinern Kreuz 19 D-64297 Darmstadt Germany e-mail address: Harald_Siegmund@kl.maus.de ============================================================================= Table of contents 1. What is NKCC? 2. Files on the disk 3. The normalized key code format 4. NKCC usage 5. NKCC in TOS applications 6. NKCC in GEM applications 7. The button event handler 8. Other fine extra features 9. Symbol overview 1. What is NKCC? ============================================================================= Did you ever try to program a complex keyboard handling? Then you sure know some of the problems coming out of TOS along with the key codes ... a) pressing Alternate + any letter will only return the scan code, which is TOS version-dependend (language) b) some keys get different scan codes when being pressed together with Alternate! For example, hitting the '1' key will return a scan code of 2 (on the German TOS) and an ASCII code of $31 (that's ok). The key combination Alternate + '1' results in a scan code of $78 and an ASCII code of 0! c) the cursor keypad (arrows, Insert, ClrHome, Help and Undo) is a whole chaos! Some of the keys change their scan code when being pressed together with Control. The returned ASCII code is total rubbish and follows no rule. d) some different key combinations return the same key codes. In most cases, Alternate+any key and Alternate+Shift+any key cannot be distinguished. The solution: the Normalized Key Code Converter NKCC solves all of this problems. It converts key codes received from GEMDOS or GEM (multi event) to an own, sophisticated format, which allows to detect all possible key combinations. In addition, NKCC offers some special features: a) Deadkey handling People in countries which know characters with accents often have the problem that they can't reach every character directly from the keyboard. Or imagine a guy who wants to type a French text on a UK TOS - without having characters like € or ‰! This can be done if NKCC was built in his favourite word processor. It transforms combinations of key strokes to one character. The first one is called the deadkey: when you type it, nothing happens - yet. After the second key stroke, NKCC decides what to do. If matching with the first one, it merges both to one key code (for example: ~ plus A will result in ·). If not matching, the program will get both keys (e.g. ~ plus X will directly be passed through the deadkey manager). Deadkeys known by NKCC are ^ + aeiou = ƒˆŒ“– ~ + nNaoAo = €₯°±·Έ ' + eEaiou = ‚ ‘’£ ` + aeiouA = …Š•—Ά Ή + aeiouyAOU = „‰‹”˜Ž™š " + aeiouyAOU = „‰‹”˜Ž™š ψ + aA = † , + cC = ‡€ / + oO24 = ³²«¬ The quote character as synonym for umlaut is e.g. needed on the Dutch keyboard, where neither umlaut characters nor the umlaut itself are available. b) Direct input of ASCII codes NKCC allows the ASCII code of characters to be input directly. Just press the Alternate key and hold it. Then type in the ASCII code on the numeric keyboard (as decimal number). The input is finished when either the Alternate key is relased or three digits are typed in. Values beyond 255 are truncated to 8 bit (e.g. 260 ($104) becomes 4). c) Control key emulation Usually, NKCC returns key combinations like "Control A" as ASCII code $41 (for "A") and with a set Control key flag. If the control key emulation is enabled, "Control A" will return an ASCII code of $01. The Control key flag will be cleared in this case. The Control key emulation converts ... Control + @ to $00 Control + A...Z to $01...$1A Control + [ to $1B Control + \ to $1C Control + ] to $1D Control + ^ to $1E Control + _ to $1F Important note: On several keyboards, some of the key combinations in the list above cannot be recognized and thus not converted. For example, on the German keyboard, the characters "@", "[", "\" and "]" can't be typed in together with the Control key. Their ASCII codes don't appear in any of the TOS key code tables, because they can only be reached when holding the Alternate key. Unfortunately, TOS returns the wrong ASCII code when Control is also held down, making it impossible to find out the original ASCII value. Every deadkey and special feature can be enabled/disabled separately. The best way to see how NKCC works is to start the test utility (TEST.TOS) and hack on the keyboard. 2. Files on the disk ============================================================================= The NKCC folder/disk/archive/whatever should contain the following files: NKCC.S source of NKCC NKCC.SH assembler header file with NKCC definitions NKCC.H C header file with NKCC definitions NKCC.O NKCC as object file (DRI format) NKCC_TOS.O NKCC as object file without GEM part (DRI format) NKCC.TXT excerpt of NKCC.S with all global definitions NKCC.DOC this documentation! TEST.C source of small test utility TEST.TOS test utility as executable program WHATSNEW.TXT information about all new features since the last release 3. The normalized key code format ============================================================================= NKCC returns key codes as 16 bit integer. The low byte contains the ASCII part of the key, the high byte is the location for some flags. Here's the complete format: Bit # Symbolic name Contents ------------------------------------------------------------ 0... 7 ASCII code/key code 8 NKF_LSH left Shift key flag 9 NKF_RSH right Shift key flag 10 NKF_CTRL Control key flag 11 NKF_ALT Alternate key flag 12 NKF_CAPS current state of CapsLock key 13 NKF_NUM numeric keypad flag 14 NKF_RESVD reserved(!) for internal purposes 15 NKF_FUNC function flag Bits 8...11 speak for themself. Bit 12 reflects the current state of the CapsLock key. Bit 13, if set, indicates that the key is located on the numeric keypad. Bit 14 is reserved for internal use and must be ignored. However, it has a special meaning as parameter for the function nkc_cmp(), described in the next chapter. Finally, the MSB of the key code (bit 15) specifies the key type: if set, the key code stands for any function to perform. If not set, it contains any printable character. The bit is set when a) any of the following "function keys" is pressed: Esc, Tab, Backspace, Delete, Return, Help, Undo, Insert, ClrHome, cursor up, cursor down, cursor left, cursor right, Enter, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10 The ASCII code for such keys is less than 32 and defined as NK_... in the header files (e.g. NK_ESC for Escape). b) any key is pressed together with Alternate and/or Control In this case, NKCC always returns the CapsLock variant of a key (e.g. the ASCII part of the key combination Control + A is 'A' rather than 'a'). The function flag was intentionally placed in bit 15 to ease its handling: if (keycode < 0) perform function else use printable character The ASCII code of a printable character spans over the whole number range of an unsigned byte: from 0 up to 255. Please note that some key combinations cannot be caught by NKCC: a) keys which are hold back by TOS: any key of the cursor pad plus Alternate (except Alternate + Undo); they are used for mouse controlling and to start a screen hardcopy. b) characters which can only be typed in when pressing Alternate, such as @\[{]} on the German keyboard. They are treated correctly by NKCC, but they never appear with a set Alternate flag. Characters created by the deadkey handler or the direct ASCII input are returned as if present on the keyboard. None of the flags, except CapsLock, can be set. Key codes created by the Control key emulation never appear with a set Control key flag. Invalid scan codes Older versions of NKCC produced simply garbage when they received a key code with an invalid scan code. Since release 2.92 such key codes are treated a defined way. They are converted to a special case of the normalized format which cannot be achieved by using the regular keyboard. The format is: function flag = 1 alternate flag = 0 control flag = 0 ASCII code >= $20 Or in other words: a printable character with set function flag, but without Alternate and Control flags being set (this cannot occur due to the definition of the normalized key format). What for, you ask? Well, the major reason for this mechanism was a graphics tablet driver I wrote in Spring '94. The graphics tablet has some macro buttons, and I wanted the driver to create key codes for every macro button that was hit (which makes it very easy for applications to receive "macro button events"). The format of a "macro key" is: scan code = $84...$ff ($ff is recommended) ASCII code = $20...$ff (codes less than $20 are set to $20 by NKCC) The flags for CapsLock, LeftShift and RightShift are directly written to the normalized key code. The Alternate and Control flags are evaluated, too: if at least one of them is non-zero then the numeric keypad flag in the converted key code will be set. Back-converting a macro key with the function nkc_n2tos() respectively nkc_n2gem() always results in a scan code of $ff. Both Alternate and Control will be set if the numeric keypad flag was set in the normalized key code. 4. NKCC usage ============================================================================= Working with NKCC is rather simple. Only a few functions have to be called. Before receiving the first key code, NKCC has to be initialized by an nkc_init() call. nkc_init() gets three parameters: The first is a 32 bit integer with some flags, defined as NKI_... in the header file NKCC.H (respectively NKIb_.../NKIf_... in NKCC.SH). The following flags exist: NKI_BUTHND are both used to control the built-in handler for mouse NKI_BHTOS button events, described in the chapter "The button event handler" NKI_NO200HZ if set, NKCC won't install the timer interrupt used for the function nkc_timer(). Note: if the button event handler is being activated, this flag is ignored because the timer is needed then for NKCC-internal purposes. nkc_init()'s second parameter is the handle of a virtual VDI workstation, also needed for the button event handler. It may be zero if the handler is not installed. At last the third parameter is a pointer to the applications GLOBAL array (one of the AES parameter arrays). The pointer isn't used by NKCC_TOS.O. When using NKCC in applications developed with Turbo C respectively Pure C this parameter is _GemParBlk.global (defined in AES.H). The function returns a 16 bit integer with NKCC's version number as 4 digit BCD (main # in high byte, sub # in low byte). The most simple call of nkc_init() would be: nkc_init(0,0,NULL); Accordingly, NKCC has to be turned off before your program is quit. This is done by an nkc_exit() call. The function has no input parameters, but returns a status code: if NKCC has linked itself into the system vectors, and somebody has corrupted the XBRA vector list, it will be unable to deinstall and returns an according error code. This is fatal! Your program must not terminate in this case! Show a warning message and tell the user to reboot. NKCC offers several methods to receive key codes. Their main difference is the kind of program NKCC is linked to: TOS or GEM application/accessory. Consult the according chapters for details. The special handlers for direct ASCII input, deadkey handling etc. are controled via the function nkc_set(). The function gets a long integer with 32 flags as parameter. A set flag enables the feature, a cleared flag disables it. Their symbolic names are: NKS_ALTNUM for direct ASCII input NKS_CTRL for control key emulation NKS_D_... for deadkey management When comparing two normalized key codes, no direct check should be made (like: if (key1 == key2) ...)! Use the function nkc_cmp() instead. It uses some specific rules which improve the flexibility of key code comparism. The function gets two key key codes as parameters, one called "reference key code" and the other "test key code". Some bits of the reference key code (the first parameter) are treated a special way: NKF_IGNUM (same as NKF_RESVD) if set, the numeric keypad flag doesn't matter NKF_CAPS (CapsLock state) if set, the case of the ASCII code doesn't matter NKF_SHIFT (both Shift keys; identical to NKF_LSH | NKF_RSH) if BOTH shift flags are set in the reference key code, the combination of shift key flags in the test key code doesn't matter: only one shift flag has to be set, no matter which one. 5. NKCC in TOS applications ============================================================================= When being used in a TOS type program (without windows, AES dialogs and mouse), the TOS-version of NKCC should be used (file NKCC_TOS.O). Some functions for multi event and mouse handling are missing in that file, making it some KBytes smaller. The functions, which have to be called, are: nkc_conin() works similar to the GEMDOS functions Cconin()/Crawcin() or the BIOS function Bconin(2). It waits until a key is pressed and returns its code in normalized format, as 16 bit integer. The function bases on GEMDOS' Crawcin(). If you like to use Cconin() or Bconin(), just change the system call in the NKCC source. nkc_cstat() replaces Cconis() respectively Bconstat(). It checks, if there is any key code in the OS internal key buffer and returns an according status: 0=no key, -1=at least one key in buffer 6. NKCC in GEM applications ============================================================================= In GEM applications or accessories, NKCC replaces the whole multi event handler with its function nkc_multi(), which gets the same parameters as usual C multi event bindings. The differences are: a) key codes are returned in normalized format b) the key state is returned NKCC compatible, which means: key state flags are placed in bits 8...11 rather than bits 0...3 and can be testet using the NKF_... symbols There's no NKCC function which replaces evnt_keybd(). Please use nkc_multi() instead - or write your own binding! Special extension for assembler programmers - by Gerd Knops ------------------------------------------------------------ When using the event_multi-routine, you probably have code like this in your source-code: ... setting up the aes-arrays, then bsr aes with aes: move.l #aespb,d1 move #$c8,d0 trap #2 rts Simply replace 'bsr aes' with 'bsr nkc_amulti'. Note, that you have to use the AES-arrays from NKCC for this purpose. See chapter 9 for a symbol overview. 7. The button event handler ============================================================================= Some years ago Atari released the long awaited TOS version 1.04. It had some very nice new features and improvements. TOS 1.04 (or a higher version) is a must for every ST user. Unfortunately, the guys in Sunnyvale messed up the multi event handler in the AES, making it impossible to receive mouse button events and timer events with short cycle times in one evnt_multi() call, without having big problems with the double click: the multi event returns immediately when a timer event occurs. If it was just processing a mouse click (waiting for a possible second click), the resulting event mask is MU_TIMER *and* MU_BUTTON! No chance to get through a double click. I spent hours to find a way how I could bypass this problem. Finally, I decided to write an own mouse button event handler, and put it into NKCC. The NKCC button event handler is activated at initialization time. Two flags in the longword passed to nkc_init() control whether the handler should be installed or not: NKI_BUTHND install it NKI_BUTHND|NKI_BHTOS install it, if TOS version has mouse click bug (TOS version >= 1.04 and < 3.06) If the NKI_BUTHND flag is not set, the handler will not be installed (the state of the NKI_BHTOS flag is ignored in this case). The second parameter of nkc_init() is the handle of a virtual VDI workstation, which had to be opened by NKCC's caller (NKCC uses a VDI vex_butv() call). The workstation may not be closed until nkc_exit() was called. If the mouse button event handler has not been installed, the handle is ignored. Another fine feature of the button event handler is an additional flag in the event mask: MU_XTIMER. If this flag is set (together with MU_TIMER), timer events will only return if no redraw-critical user action is taken (like moving windows or sliding through the menu bar). This prevents redraw problems, e.g. when the timer event is used to update a mouse coordinate display. Note: the NKCC button event handler supports the (undocumented) negation flag, which is passed in bit 8 of the parameter (maximum # of mouse clicks to wait for). You don't know this flag? I found an article about it in the c't magazine (I think it was issue 3/90, or maybe 4/90??) - and I damned Atari for their bad documentation. This flag opens the way to check BOTH mouse buttons at the same time without any problems. When set, the return condition is inverted. Let's have a look at an example: mask = evnt_multi(MU_BUTTON,2,3,3,... This doesn't work the way we want: the return condition is "button #0 pressed AND button #1 pressed". But look at this: mask = evnt_multi(MU_BUTTON,0x102,3,0,... Now the condition is "NOT (button #0 released AND button #1 released)". Or in other words: "button #0 pressed OR button #1 pressed". Nice, isn't it?! Final note: the mouse click bug is fixed since TOS version 3.06. Thanks to Atari Corp.! 8. Other fine extra features ============================================================================= NKCC includes some functions primary built in for its own purposes. However, some of this functions could also be useful for the programmers using NKCC, so they are exported and documented. Here's a list of them: nkc_timer() returns the current value of the 200 Hz system clock as unsigned longword. The function is very fast, because it just has to copy the value from an internal static variable to the return register. Note: if NKCC's timer interrupt is not installed, the function will always return 0. See chapter 4 for details. nkc_kstate() returns the current state of the Shift, Control, Alternate and CapsLock keys in NKCC compatible format. This function is very fast, too! nkc_tconv() is the heart of NKCC: the raw key code converter, which transforms a TOS key code to the normalized format. However, it does not perform deadkey handling, ASCII input or Control key emulation. nkc_gconv() is a variant of nkc_tconv(), which gets the key code in GEM format (16 bit integer instead of 32 bit, and NO KEY STATE FLAGS!). nkc_gconv() is surely not perfect - but that's no NKCC's fault! The key state flags are very very important for proper conversion, and without them, several key combinations cannot be distinguished (as meantioned in the first chapter of this documentation). Whenever possible, use nkc_tconv()! nkc_gconv() is more an emergency exit, which should only be used when the key state flags are lost. nkc_n2tos() converts normalized key codes back to TOS format key codes. nkc_n2gem() converts normalized key codes back to GEM format key codes. nkc_vlink() This function links a standard XBRA routine to a vector list. The vector can be chosen either as absolute address (e.g. $502 for the hardcopy vector) or as number (e.g. $02 for the bus error handler vector). nkc_vunlink() The counterpart of nkc_vlink(). A function is removed from an XBRA vector list. nkc_toupper() A character is converted to upper case. In contrast to most C compiler library functions (ctypes.h) this functions treats foreign language characters (e.g. '„', '‚') correctly! nkc_tolower() The counterpart of the previous function: a character is converted to lower case. For a detailed documentation of the functions consult NKCC.TXT. 9. Symbol overview ============================================================================= Here's an overview of all symbols exported by NKCC. Functions are marked with parentheses behind the symbol name: nkc_init() initialize and configure NKCC, optional installation of an own mouse button event handler nkc_exit() exit NKCC (unlink own functions from the system etc.) nkc_set() enable/disable the special key handler functions (deadkeys, direct ASCII input, Control key emulation) nkc_conin() raw console character input in NKCC format (based on GEMDOS' Crawcin()) nkc_cstat() sample console input status (based on GEMDOS' Cconis()) * nkc_multi() AES multi event binding, which returns key codes and shift key flags in normalized format * nkc_amulti() AES multi event binding for assembler programs nkc_tconv() raw key code converter (TOS -> normalized format) nkc_gconv() additional key code converter (GEM -> normalized format) nkc_n2tos() additional key code converter (normalized format -> TOS) nkc_n2gem() additional key code converter (normalized format -> GEM) nkc_kstate() sample state of Shift, Control, Alternate and CapsLock keys in normalized format; very fast! nkc_timer() return current timer value of 200 Hz system clock; very fast! Note: if timer is disabled, the function always returns 0 (see chapter 4) nkc_cmp() compare two key codes due to standard comparism rules nkc_vlink() link function to XBRA vector list nkc_vunlink() unlink function from XBRA vector list nkc_toupper() lower case -> upper case conversion nkc_tolower() upper case -> lower case conversion * nkc_contrl AES/VDI control array * nkc_intin AES/VDI integer input array * nkc_intout AES/VDI integer output array * nkc_adrin AES address input array * nkc_adrout AES address output array (unfortunately the correct names - addrin and addrout - would create a doubly defined symbol because the DRI object file format supports only 8 characters per symbol - gosh!) * nkc_ptsin VDI pointers input array * nkc_ptsout VDI pointers output array (all arrays used for nkc_amulti()) * not available in NKCC_TOS.O which is for TOS applications and excludes the GEM part of NKCC (assembled with the NKCGEM symbol set to 0; see header of NKCC.TXT) ============================================================================= End Of File