home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Dream 48
/
Amiga_Dream_48.iso
/
Atari
/
c
/
libs
/
nkcc-293.lzh
/
SOURCE
/
NKCC.S
Wrap
Text File
|
1995-11-09
|
154KB
|
3,735 lines
********************************************************************************
*
* Project name : NORMALIZED KEY CODE CONVERTER (NKCC)
* Module name : Main module
* Symbol prefix: nkc
*
* Author : Harald Siegmund (HS)
* Co-Authors : -
* Write access : HS
*
* Notes : The symbol NKCGEM will have to be defined on the assembler's
* command line when translating the source of NKCC. Set its
* value to 1 if you like to create the complete version. A value
* of 0 will supress inclusion of the GEM part, making NKCC a few
* KBytes smaller. Some functions and the GEM parameter arrays
* are not available then.
*
* Translate this source with the Pure assembler:
* pasm [-B] -DNKCGEM=1 -Onkcc.o nkcc.s
* pasm [-B] -DNKCGEM=0 -Onkcc_tos.o nkcc.s
*
* WARNING: Old versions of the Pure assemblers have serious
* bugs! Version Jun 21 1993 works fine.
*
*-------------------------------------------------------------------------------
*END
* Things to do :
*
* - NKCC will support additional (and more complex) deadkeys some time, such
* like Arabian ones. A communication interface between NKCC and a text
* editor will be built in for that purpose (Arabian languages' deadkeys can
* affect existing text!).
*
*-------------------------------------------------------------------------------
* History:
*
* 1989:
* May 14: creation of file (NKCC 1.00)
* Jun 07/15-16/19/21/Jul 11: improvements, changes, debugging
* 1990:
* Jan 13: global functions now available in two versions:
* parameters passed via registers (e.g. for Turbo C)
* parameters passed via stack (underscore before label name)
*
* May 23-24/26-28: creation of NKCC 2.00 (almost every function rewritten)
* Jun 16/27: assembler-entry added by Gerd Knops
* Jun 30/Jul 02: return shift key flags in nkc_multi()/amulti() as NKF?_...
* Jul 09: nkc_kstate()
* Aug 03: nkc_cmp()
* Aug 18: fatal bug in nkc_kstate() fixed
* Sep 15: nkc_timer()
* Sep 15-17/30: own button event handler
* Oct 03: debugging
* nkc_vlink()/vunlink()
* documentation syntax changed (LRef/XRef removed; Reg: changed)
* Oct 05: debugging mouse button handler (problems with menu bar)
* Oct 07: Control/Alternate + character always returns capital characters
* changing key code comparism rules in nkc_cmp()
* Oct 22: debugging nkc_cmp() (did sometimes recognize unique key codes)
* debugging ASCII code input in nkc_amulti()
* Dec 11/15/17: MU_XTIMER
* 1991:
* Jan 11: don't call AES with set MU_XTIMER flag
* Mar 31: ensure that evnt_multi() parameters are restored when being
* corrupted by a bug in AES!!
* Apr 01: debugging
* Apr 13: nkc_conv() renamed to nkc_tconv()
* Apr 13-14: nkc_gconv()
* May 10: debugging (nk_beend())
* May 29: debugging (double shift key compare)
* export nkc_toupper and nkc_tolower
* Jul 05: completing history
* Jul 31: version number before XBRA header
* Aug 06: " is now a deadkey!
* Aug 07: more deadkeys...
* Aug 22: deadkeys can now be enabled/disabled separately
* nkc_set() changed
* nkc_init() returns version #
* bug fixed: nkc_cmp() corrupted high words of D3 and D4
* Sep 07/14: nkc_cmp() improved; NKF?_RESVD now in use
* Nov 05: adjustments to ASCII input feature of TOS 3.06
* Nov 16: bug fixed in nkc_cmp() mechanism
* Control key emulation
* Dec 29: small corrections and extensions of the documentation
* source documentation syntax now in extra file
* 1992:
* Jan 03: changing documentation of nkc_init()
* revising info lines in function headers
* Jan 12: adjusting nkc_init() to its new documentation!
* appending .b respectively .l to all instructions with a default
* operand size which is not .w
* changing macro XBRA_HD
* Feb 11: adjusting button event handler to MINT
* Feb 28: NKCOWNPB switch
* 1993:
* Dec 11: merging the two existing NKCC versions to one source:
* - version number set to $0290
* - NKCNOGEM/NKCOWNPB keys replaced by NKCGEM key
* - NKCC uses its own AES/VDI parameter arrays now
* - nkc_init() gets one more parameter: ^AES global array
* - nkc_toupper and nkc_tolower are functions now
* - dynamic double click time
* - MU_MESAG occured -> don't create self-made button events
* Dec 12: GEM keyboard events: try to get original shift flags from the
* Iorec buffer
* new functions: nkc_n2tos() and nkc_n2gem()
* Dec 13: debugging: ! operator changed to ~ in nk_bestart
* implementing nkc_n2tos()
* size of GEM parameter arrays changed to 32 (larger than required
* but better too big than too small!)
* Dec 16: debugging nkc_n2tos()
* Dec 19: improving nkc_gconv() (scan code translation table)
* debugging nkc_n2tos()
* cosmetic changes
* Dec 23: debugging nkc_vunlink(): return status was garbage!
* 1994:
* May 19: release 2.91:
* don't restore conterm (it may be changed by another process in
* the meantime)
* new deadkeys (/2 /4)
* adding overview of used MadMac directives in the note section of
* the file header
* Jun 27: release 2.92:
* check for illegal scan codes (e.g. $ff under Mag!x)
* Oct 31: adding C prototypes to headers of public functions
* 1995:
* Nov 06: source adjusted for translation with Pure assembler
* Nov 09: release 2.93:
* the additional keys on the Macintosh keyboard are supported now
*
********************************************************************************
*KEY _NAME="NKCC"
*START
****************************************************************************
* ASSEMBLER CONTROL SECTION *
****************************************************************************
*KEY &NKCGEM
* define this symbol on the assembler's command line
* =0 create TOS-version of NKCC (without GEM part)
* =1 create GEM-version of NKCC
.include "nkcc.i" ; NKCC definitions
*END
*KEY _END
*START
****************************************************************************
* EXPORT *
****************************************************************************
; functions
.globl nkc_init ; init NKCC
.globl nkc_exit ; exit NKCC
.globl nkc_set ; set special key flags
.globl nkc_conin ; NKCC key input via GEMDOS
.globl nkc_cstat ; console input status via GEMDOS
.globl nkc_tconv ; TOS key code converter
.globl nkc_gconv ; GEM key code converter
.globl nkc_n2tos ; NKC to TOS key code converter
.globl nkc_n2gem ; NKC to GEM key code converter
.globl nkc_kstate ; return shift key state
.globl nkc_timer ; return 200 Hz system clock
.globl nkc_cmp ; compare two key codes
.globl nkc_vlink ; link function to XBRA vector list
.globl nkc_vunlink ; unlink function from XBRA list
.globl nkc_toupper ; convert character to upper case
.globl nkc_tolower ; convert character to lower case
.if NKCGEM=1
.globl nkc_multi ; NKCC multi event handler
.globl nkc_amulti ; multi event, assembler binding
.globl nkc_contrl ; GEM parameter arrays
.globl nkc_intin
.globl nkc_intout
.globl nkc_adrin
.globl nkc_adrout
.globl nkc_ptsin
.globl nkc_ptsout
.endif ; .if NKCGEM=1
*END
****************************************************************************
* EQUATES *
****************************************************************************
VERSION = $0293 ; NKCC's version #
; AES event mask bits
MU_KEYBD = $0001 ; keyboard
MU_BUTTON = $0002 ; mouse button clicks
MU_M1 = $0004 ; mouse movement #1
MU_M2 = $0008 ; mouse movement #2
MU_MESAG = $0010 ; message
MU_TIMER = $0020 ; timer
conterm = $484 ; .B: system key flags
_hz_200 = $4ba ; .L: 200 Hz system clock
_sysbase = $4f2 ; .L: ^OS header
TIME_ADD = 20 ; wait time to add on each click
; in 1/200 s (-> 100 ms)
****************************************************************************
* ABSOLUTE SECTION *
****************************************************************************
.offset ; button event info block
BI_BSTATE: .ds.w 1 ; requested button state
BI_BMASK: .ds.w 1 ; requested button mask
BI_REVCOND: .ds.w 1 ; event condition reverse flag
BI_MAXCLICKS: .ds.w 1 ; max # of clicks to wait for
BI_DCLTIME: .ds.w 1 ; AES double click time
BI_BMODE: .ds.w 1 ; button handler mode (see
; function nk_butvec)
BI_SBSTATE: .ds.w 1 ; button state at start of event
BI_PRVBSTATE: .ds.w 1 ; previous button state
BI_NCLICKS: .ds.w 1 ; # of mouse clicks
BI_DCBUT: .ds.w 1 ; double click button mask
BI_DCSTATE: .ds.w 1 ; double click button state
BI_BENDTIME: .ds.l 1 ; button event timer end value
BI_BEVALID: .ds.b 1 ; flag: button event valid
BI_CVALID: .ds.b 1 ; flag: button condition valid
BI_LOCK: .ds.b 1 ; flag: button event locked
.even
BI: ; size
.offset ; IOREC structure
IBUF: .ds.l 1 ; ^base of I/O buffer
IBUFSIZ: .ds.w 1 ; size of buffer in bytes
IBUFHD: .ds.w 1 ; head-pointer (offset to last
; used read position
IBUFTL: .ds.w 1 ; tail-pointer (offset to last
; used write position
IBUFLO: .ds.w 1 ; low water mark
IBUFHI: .ds.w 1 ; high water mark
IOREC: ; size
****************************************************************************
* MACROS *
****************************************************************************
****************************************************************************
*
* LWDIVU: divide long value <da> by word value <db>, use <dt> for temp storage
*
* - the result will be stored as LONGword in <da>
* - <db> stays unchanged
* - <da> and <dt> must be data registers
*
****************************************************************************
.macro LWDIVU db,da,dt
move.l &da,&dt ; copy long-value
clr &dt ; clear its low word
swap &dt ; dt.w = high word of long-value
divu &db,&dt ; high word / word-value
swap &da ; long-value, low and high swapped
move &dt,&da ; da.w = result of high/word-value
swap &da ; da.w = low word of long-value
move &da,&dt ; remainder and low-word
divu &db,&dt ; divide by word-value
move &dt,&da ; so we get low word of result
.endm
****************************************************************************
*
* XBRA_HD: XBRA header for NKCC functions
*
* The following structure is stored at the current memory location:
*
* VERSION.L NKCC's version # (actually not a part of a standard XBRA
* header; may be checked in future versions)
* "XBRA".L magic longword
* "NKCC".L NKCC's XBRA-ID
* oldvec.L initial value of buffer for old vector content (passed as
* macro parameter); usually 0
*
****************************************************************************
.macro XBRA_HD oldvec
.dc.l VERSION ; version number
.dc.b "XBRA" ; XBRA header
.dc.b "NKCC" ; ID
.dc.l &oldvec ; chain pointer to next routine
.endm
****************************************************************************
* LOCAL TEXT SECTION *
****************************************************************************
.text
****************************************************************************
*
* nk_gci: GEMDOS console character input
* #
*
* This function returns when
*
* a) either any key is pressed or
* b) the Alternate key is released
*
* The Alternate check can be suppressed by setting the input parameter in
* D0.W to zero. The routine works then just as a "get key" function.
*
* In: D0.W Alternate key check flag:
* zero = don't check it
* non-zero = do Alternate check
*
* Out: D0.W key code in normalized format
* for details see nkc_tconv()
* D1.W flag:
* zero = D0.W not valid; Alternate was released
* non-zero = D1.W valid; Alternate still pressed
* (also returned when Alternate check supressed)
* CCR set according content of D1.W
*
* Reg: D:01234567 A:01234567 CCR
* U***.... ****.... =D1.W
*
****************************************************************************
nk_gci: move d0,d3 ; Alternate check flag
beq.s .getkey ; no check? just get key
move.l pshift,a3 ; ^shift key state
.loop: btst.b #3,(a3) ; Alternate still pressed?
beq.s .abort ; no->
move #11,-(sp) ; Cconis: get key input status
trap #1 ; Gemdos
addq #2,sp ; clean stack
tst d0 ; any key pressed?
beq.s .loop ; no->
.getkey: move #7,-(sp) ; Crawcin: get key
trap #1 ; Gemdos
addq #2,sp ; clean stack
bsr nkc_tconv ; convert key code
moveq.l #-1,d1 ; flag: key code valid
rts ; bye
.abort: moveq.l #0,d1 ; flag: key code not valid
rts ; bye
****************************************************************************
*
* nk_spec: special key code handling
* #
*
* nk_spec() performs the special key handling defined by <sflags> (deadkey
* management, ASCII code input, Control key emulation).
*
* In: D0.W key code in normalized format
* for details see nkc_tconv()
* A0.L ^function which gets new key codes and checks
* the Alternate key state
* For the calling conventions consult nk_gci() or
* nk_mci(). The function MUST NOT modify the CPU
* registers D5-D7 and A5-A6.
*
* Out: D0.W (new) key code in normalized format
* CCR set according contents of D0.W
*
* Reg: D:01234567 A:01234567 CCR
* U******* *******. =D0.W
*
****************************************************************************
nk_spec: move.l a0,a6 ; save ^function
btst.b #NKSb_ALTNUM,sflags + 3 ; ASCII input enabled?
beq.s .ctrlkey ; no->
*------------- ASCII input
moveq.l #0,d6 ; reset digit counter
moveq.l #0,d5 ; reset ASCII code
bra.s .isdigit ; check if valid key
.notvalid: tst d6 ; key not valid; first one?
beq.s .ctrlkey ; yes-> exit
.getkey: move d0,d7 ; save previous key code
moveq.l #-1,d0 ; check Alternate
jsr (a6) ; get key
beq.s .makeascii ; Alternate released? abort loop
.isdigit: move d0,d1 ; key code
and #NKFf_NUM | NKFf_ALT,d1 ; isolate flags
cmp #NKFf_NUM | NKFf_ALT,d1 ; with Alternate and numeric?
bne.s .notvalid ; no->
cmp.b #'0',d0 ; must be in range from 0 ...
blo.s .notvalid
cmp.b #'9',d0 ; ... to 9
bhi.s .notvalid
mulu #10,d5 ; new digit in ASCII code
sub #'0',d0 ; ASCII->number
add d0,d5 ; add new digit
addq #1,d6 ; count digits
cmp #3,d6 ; 3rd digit added?
bne.s .getkey ; no-> next key
.makeascii: move d7,d0 ; previous key code
and #NKFf_CAPS,d0 ; isolate CapsLock flag
move.b d5,d0 ; add key code (ASCII)
*------------- Control key emulation
.ctrlkey: btst.b #NKSb_CTRL,sflags + 3 ; enabled?
beq.s .deadkey ; no ->
btst.l #NKFb_CTRL,d0 ; Control flag set?
beq.s .deadkey ; no ->
btst.l #NKFb_ALT,d0 ; Alternate flag set?
bne.s .deadkey ; yes ->
cmp.b #$40,d0 ; check ASCII code
blo.s .deadkey ; too low ->
cmp.b #$5f,d0 ; check again
bhi.s .deadkey ; too high ->
; clear function and Control flags
and #(!(NKFf_FUNC|NKFf_CTRL)) & $ffff,d0
sub.b #$40,d0 ; new ASCII code
* The Pure assembler believes that !(NKFf_FUNC|NKFf_CTRL) is a LONGWORD constant
* so we have to mask off the upper 16 bits with $ffff. Gosh!
*------------- check if key = deadkey
.deadkey: tst d0 ; function key?
bmi.s .ret ; yes-> no deadkey
lea deadtab,a0 ; ^deadkey table
move sflags,d4 ; deadkey flags
beq.s .exit ; no deadkeys at all->
.finddead: move (a0)+,d2 ; get option flag mask
beq.s .exit ; end of table-> no deadkey
move (a0)+,d1 ; get key code
addq #4,a0 ; skip ^match table
and d4,d2 ; is this deadkey enabled?
beq.s .finddead ; no ->
cmp.b d0,d1 ; deadkey found?
bne.s .finddead ; no->
*------------- key is dead key, get second key and merge them
move.l -4(a0),a5 ; ^deadkey match table
move d0,-(sp) ; save key code
clr d0 ; no Alternate check
jsr (a6) ; get second key
move sflags,-(sp) ; save deadkey flags
clr sflags ; disable deadkeys temporary
move.l a6,a0 ; do ASCII input/ctrl key check
bsr nk_spec ; by calling myself!
move (sp)+,sflags ; restore deadkey flags
move (sp)+,d7 ; restore first key code
tst d0 ; function key?
bmi.s .nomatch ; yes-> doesn't match with deadkey
.findmatch: move (a5)+,d1 ; merged and second key code
beq.s .nomatch ; end of table->
cmp.b d0,d1 ; second key code found?
bne.s .findmatch ; no->
lsr #8,d1 ; yes: merged code in .B
and #NKFf_CAPS,d0 ; clear all except CapsLock
move.b d1,d0 ; CapsLock flag + merged key
bra.s .exit ; exit
.nomatch: move d0,prvkey ; save second key
st.b prvvalid ; set validation flag
move d7,d0 ; return first key
.ret: rts ; bye
.exit: tst d0 ; set CCR
rts ; bye
****************************************************************************
*
* nk_ascmatch: check if ASCII code matches with one from the key code tables
* # R
*
* This functions proofs, if D0.B equals to D4.B, D5.B or D6.B. An according
* flag is returned. The flag bytes in the TOS key code D0.L are modified
* depending on which code matches.
*
* In: D0.L key code in TOS format
* D4.B ASCII code from unshifted key table
* D5.B ASCII code from shifted key table
* D6.B ASCII code from CapsLock key table
*
* Out: D0.L key code in TOS format
* (updated flags in upper byte)
*
* CCR EQ: ASCII code was found
* NE: ASCII code wan't found
*
* Reg: D:01234567 A:01234567 CCR
* U......* ........ flag (see above)
*
****************************************************************************
nk_ascmatch: tst.b d0 ; zero?
bne.s .comp ; no ->
move.l d0,d7 ; copy key code
; Alt/Control already found out?
and.l #(NKFf_ALT|NKFf_CTRL)<<16,d7
bne.s .unknown ; yes ->
.comp: cmp.b d4,d0 ; unshifted?
bne.s .shftst ; no ->
cmp.b d6,d0 ; in CapsLock table, too?
beq.s .exit ; yes ->
bclr.l #NKFb_CAPS+16,d0 ; no: cannot be CapsLock
bra.s .exit ; ->
.shftst: cmp.b d5,d0 ; shifted?
bne.s .cpstst ; no ->
cmp.b d6,d0 ; in CapsLock table, too?
bne.s .shifted ; no ->
btst.l #NKFb_CAPS+16,d0 ; CapsLock active?
bne.s .exit ; yes -> it COULD be generated
; by pressing Shift, but we
; assume CapsLock
.shifted: or.l #NKFf_SHIFT<<16,d0 ; shifted: set both shift flags
bra.s .exit ; ->
.cpstst: cmp.b d6,d0 ; in CapsLock table?
bne.s .unknown ; no ->
bset.l #NKFb_CAPS+16,d0 ; yes: set CapsLock flag
.exit: moveq.l #0,d7 ; found
rts
.unknown: moveq.l #1,d7 ; not found
rts
****************************************************************************
*
* nk_findscan: find scan code
* # R
*
* The
*
* In: D0.W normalized key code
* A0.L ^base of system's key code table
*
* Out: D1.W found scan code (0 = not found)
* CCR set according contents of D1.W
*
* Reg: D:01234567 A:01234567 CCR
* .W...... *....... =D1
*
****************************************************************************
nk_findscan: btst.l #NKFb_NUM,d0 ; on numeric keypad?
beq.s .search ; no ->
move #$4a,d1 ; yes: try all numeric keypad
cmp.b (a0,d1),d0 ; scan codes first
beq.s .found ; it matches ->
move #$4e,d1
cmp.b (a0,d1),d0
beq.s .found
move #$63,d1 ; block starts at $63
.numsearch: cmp.b (a0,d1),d0 ; match?
beq.s .found ; yes ->
addq #1,d1 ; next scan code
cmp #$73,d1 ; block end at $72
blo.s .numsearch ; continue search ->
.search: move #1,d1 ; start with first valid scan code
.mainsearch: cmp.b (a0,d1),d0 ; match?
beq.s .found ; yes ->
addq.b #1,d1 ; next scan code
cmp.b #$78,d1 ; $78 = last valid scan code
blo.s .mainsearch ; continue search ->
moveq.l #0,d1 ; not found
rts
.found: tst d1 ; found; set CCR
rts
.if NKCGEM=1
****************************************************************************
*
* nk_bioscode: convert GEM key code to GEMDOS/BIOS format
* # R
*
* This is a simple converter which takes key codes in AES format (two
* words) and transforms them to the BIOS key format (one longword).
*
* In: D0.W key code
* high byte = scan code, low byte = ASCII code
* D1.W shift key state flags
* Bit 0: right Shift
* Bit 1: left Shift
* Bit 2: Control
* Bit 3: Alternate
*
* Out: D0.L key code in BIOS format
* for details see nkc_tconv()
*
* Reg: D:01234567 A:01234567 CCR
* U*...... *....... *
*
****************************************************************************
nk_bioscode: swap d0 ; key code in high word
move d1,d0 ; shift key state
move.l pshift,a0 ; ^shift key state system variable
move.b (a0),d1 ; get it
and #!NKFf_CAPS,d1 ; isolate CapsLock flag
or d1,d0 ; merge with other shift flags
swap d0 ; shift state in high word
lsl.l #8,d0 ; move 'em up
lsr #8,d0 ; now key code in BIOS format
rts ; bye
****************************************************************************
*
* nk_real_shift: try to get original shift flags of a key code
* #
*
* This function uses the contents of the Iorec keyboard ring buffer to
* restore the original shift flag byte of a key code which has been
* transported through AES' event manager and thus stripped off its
* flag byte.
*
* In: D0.L key code in TOS format
* for details see nkc_tconv()
*
* Out: D0.L updated key code in TOS format
*
* Reg: D:01234567 A:01234567 CCR
* U**..... *....... *
*
****************************************************************************
nk_real_shift: move.l kbdiorec,a0 ; ^keyboard's I/O record
movem.l d3/d4,-(sp) ; save registers
move IBUFHD(a0),d1 ; head pointer
move IBUFTL(a0),d2 ; tail pointer
move iohead,d3 ; NKCC's head pointer
*------------- check if tail pointer has overrun NKCC's head pointer
cmp d1,d2 ; tail < head?
blo.s .tlwrap ; yes -> it has been wrapped around
cmp d3,d1 ; my tail between record's
bhs.s .search ; head and tail?
cmp d2,d3 ; if so, tail has overrun my
blo.s .reset ; head -> reset
bra.s .search ; no overrun ->
.tlwrap: cmp d2,d3 ; my tail below wrapped record's
blo.s .reset ; tail pointer or above head?
cmp d3,d1 ; then tail has overrun my
blo.s .reset ; head -> reset
*------------- find key code in ring buffer
.search: move IBUFSIZ(a0),d2 ; buffer size
move.l IBUF(a0),a0 ; ^base of buffer
move.l d0,d4 ; copy key code
swap d4 ; scan code in low byte of d4
bra.s .find2 ; ->
.find: addq #4,d3 ; advance to next read-position
cmp d2,d3 ; wrap around?
blo.s .getkey ; no ->
moveq.l #0,d3 ; yes: wrap
.getkey: cmp.b 3(a0,d3),d0 ; compare ASCII code
bne.s .find2 ; doesn't match ->
cmp.b 1(a0,d3),d4 ; compare scan code
bne.s .find2 ; doesn't match ->
move.l (a0,d3),d0 ; found: get complete key code
bra.s .exit ; ->
.find2: cmp d1,d3 ; my head has reached buffer's head
bne.s .find ; no ->
.reset: move d1,d3 ; reset head pointer
.exit: move d3,iohead ; save new head pointer
movem.l (sp)+,d3/d4 ; restore registers
rts ; bye
****************************************************************************
*
* nk_mci: multi event console character input
* # U
*
* This function returns when
*
* a) either any key is pressed or
* b) the Alternate key is released
*
* The Alternate check can be suppressed by setting the input parameter in
* D0.W to zero. The routine works then just as a "get key" function.
*
* In: D0.W Alternate key check flag:
* zero = don't check it
* non-zero = do Alternate check
*
* Out: D0.W key code in normalized format
* for details see nkc_tconv()
* D1.W flag:
* zero = D0.W not valid; Alternate was released
* non-zero = D1.W valid; Alternate still pressed
* (also returned when Alternate check supressed)
* CCR set according content of D1.W
*
* Reg: D:01234567 A:01234567 CCR
* U***.... ****.... =D1.W
*
****************************************************************************
nk_mci: move d0,d3 ; save Alternate check flag
move.l pshift,a3 ; ^shift key state variable
.loop: lea nkc_contrl,a0 ; ^control array
move #25,(a0)+ ; opcode
move #16,(a0)+ ; size of intin
move #7,(a0)+ ; size of intout
move #1,(a0)+ ; size of addrin
clr (a0) ; size of addrout
lea nkc_intin,a0 ; ^intin array
move #MU_TIMER|MU_KEYBD,(a0) ; wait for timer and key strokes
clr.l 7*4(a0) ; waiting time: 0 ms = minimum!
move #200,d0 ; opcode for AES
move.l #aespb,d1 ; ^AES parameter block
trap #2 ; call GEM
lea nkc_intout,a0 ; ^intout array
move (a0),d0 ; event mask
move.b (a3),d1 ; shift key state
and #$f,d1 ; clear unused bits
move #MU_KEYBD,d2 ; did keyboard event occur?
and d0,d2 ; check bit
bne.s .keybd ; yes->
move.l kbdiorec,a1 ; ^keyboard's I/O record
move IBUFHD(a1),iohead ; reset NKCC's head pointer
tst d3 ; do Alternate check?
beq.s .loop ; no->
btst.l #3,d1 ; Alternate still pressed?
bne.s .loop ; yes->
moveq.l #0,d1 ; Alternate released: abort
rts
.keybd: move 10(a0),d0 ; key code
bsr nk_bioscode ; convert to BIOS keycode
bsr nk_real_shift ; try to get original shift flags
bsr nkc_tconv ; convert to normalized format
moveq.l #1,d1 ; key code is valid
rts ; bye
****************************************************************************
*
* nk_gemtrap: GEM trap handler
* # S T2
*
* This function is linked to the GEM trap vector at initialization time.
* It waits for evnt_dclick() calls (get/set double click time) and saves
* new click times in an own buffer.
*
* In: D0.W opcode:
* 115 = VDI
* 200 = AES
* A0.L AES/VDI parameter block
*
* Out: -
*
* Reg: D:01234567 A:01234567 CCR
* ..*..... **...... *
*
****************************************************************************
XBRA_HD 0 ; XBRA header
nk_gemtrap: cmp #200,d0 ; AES?
bne.s .exit ; no ->
move.l d1,a0 ; ^parameter block
move.l (a0),a1 ; ^contrl array
cmp #26,(a1) ; opcode for evnt_dclick?
bne.s .exit ; no ->
move.l 8(a0),a1 ; ^intin array
tst 2(a1) ; set new time?
beq.s .exit ; no ->
move (a1),d2 ; yes: get new time
cmp #4,d2 ; limit check
bls.s .save ; ok: save new value
moveq.l #4,d2 ; out of range: use maximum
.save: move d2,bvar+BI_DCLTIME ; save it
.exit: move.l nk_gemtrap-4(pc),-(sp) ; old vector address
rts ; jump to old routine
****************************************************************************
*
* nk_butvec: VDI mouse button change handler
* # I S
*
* This function handles changes of the mouse button state. It is used
* for NKCC's own button event handler, which consists mainly of this
* interrupt and the functions nk_bestart() and nk_beend().
*
* The handler knows several modes (stored in bvar+BU_BMODE.w):
*
* 0 standby mode: no button event in process, waiting for first click
* 1 wait mode: button event in process, but not yet finished: waiting
* for a possible second, third ... click
* 2 hold mode: button event was generated, condition still true (buttons
* are still pressed): repeat button event
*
* In: D0.W current state of mouse buttons
*
* Out: D0.W current state of mouse buttons (unchanged)
*
* Reg: D:01234567 A:01234567 CCR
* ........ ........ *
*
****************************************************************************
XBRA_HD nk_bvret ; XBRA header
* Some milliseconds after the installation of this function, the old vector
* address is not set (VDI has to return first). A mouse click during this
* time would lead to a system crash because the new handler jumps through
* this vector. This is the reason why it's initial content points to a
* RTS instruction. (I know, this is a very very improbable situation, but
* it IS possible! And that's reason enough to prepare for it and write
* some silly lines of comment about it!)
nk_butvec: movem.l d5-d7/a0-a1,-(sp) ; save registers
lea bvar,a1 ; ^button event info block
move d0,d7 ; new button mask
move BI_BSTATE(a1),d6 ; requested button state
eor d6,d7 ; XOR 'em
move BI_BMASK(a1),d6 ; button mask
and d6,d7 ; isolate valid bits
tst BI_REVCOND(a1) ; condition reverse flag
bne.s .rev ; reverse ->
tst d7 ; 0-> all button conditions true
seq.b d6 ; if so, the set d6 to $ff
bra.s .chkmode ; ->
.rev: eor d6,d7 ; invert condition flags
cmp d6,d7 ; at least one condition true?
sne.b d6 ; yes -> set d6 to $ff
* the registers contain now:
*
* d6.b = button condition flag (0=condition false, $ff=condition true)
* d7.w = button condition mask (bits with value 0 indicate true condition)
.chkmode: move.b d6,BI_CVALID(a1) ; save flag
move BI_BMODE(a1),d5 ; check current mode
beq.s .standby ; standby mode ->
subq #1,d5 ; check if wait mode
beq.s .wait ; wait mode ->
*------------- handler is in HOLD mode
.hold: tst.b d6 ; hold mode: button condition true?
beq.s .reset ; no ->
move #1,BI_NCLICKS(a1) ; 1 mouse click
move d0,BI_SBSTATE(a1) ; use current button state
st.b BI_BEVALID(a1) ; generate mouse click
bra .exit
.reset: clr BI_BMODE(a1) ; switch to standby mode
bra.s .exit
*------------- handler is in STANDBY mode
.standby: tst.b BI_BEVALID(a1) ; old click still in buffer?
bne.s .exit ; yes ->
tst.b d6 ; button condition true?
beq.s .exit ; no ->
move d0,BI_SBSTATE(a1) ; save button state
moveq.l #1,d5
move d5,BI_BMODE(a1) ; change to wait mode
move d5,BI_NCLICKS(a1) ; init # of clicks
lea timetab,a0 ; ^double click time table
move BI_DCLTIME(a1),d5 ; double click time
add d5,d5 ; *4 for index
add d5,d5
move.l (a0,d5),d5 ; get double click time
add.l sysclock,d5 ; add current timer value
move.l d5,BI_BENDTIME(a1) ; save as end time
moveq.l #1,d5 ; find first button
.findbut: add d5,d5 ; next button
lsr d7 ; check next bit
bcs.s .findbut ; condition not true ->
lsr d5 ; first found changed button
.dcbut: move d5,BI_DCBUT(a1) ; save double click button mask
and d0,d5 ; get 'active' state
move d5,BI_DCSTATE(a1) ; save it
bra.s .exit ; ->
*------------- handler is in WAIT mode
.wait: tst.b BI_BEVALID(a1) ; old click still in buffer?
bne.s .exit ; yes ->
move BI_DCBUT(a1),d5 ; double click button mask
move BI_PRVBSTATE(a1),d7 ; previous button state
eor d0,d7 ; get button state changes
and d5,d7 ; did dclick button state change?
beq.s .exit ; no ->
and d0,d5 ; isolate state of dclick button
cmp BI_DCSTATE(a1),d5 ; changed it to 'active' state?
bne.s .exit ; no ->
moveq.l #1,d7 ; yes: add 1 to # of clicks
add BI_NCLICKS(a1),d7
cmp BI_MAXCLICKS(a1),d7 ; > max # of clicks to wait for?
bhi.s .exit ; yes ->
move d7,BI_NCLICKS(a1) ; no: save new # of clicks
add.l #TIME_ADD,BI_BENDTIME(a1) ; let user more time to click
*------------- leave interrupt
.exit: move d0,BI_PRVBSTATE(a1) ; save button state
movem.l (sp)+,d5-d7/a0-a1 ; restore registers
move.l nk_butvec-4(pc),-(sp) ; old vector address
nk_bvret: rts ; jump to old routine
****************************************************************************
*
* nk_bestart: start special handling of button event
* #
*
* In: -
*
* Out: D7.W handler mode (used in nk_beend)
*
* Reg: D:01234567 A:01234567 CCR
* **.....W **...... *
*
****************************************************************************
nk_bestart: moveq.l #0,d7 ; default: no special handling
tst.b buthnd ; our handler installed?
beq .exit ; no ->
lea nkc_intin,a0 ; ^event mask
moveq.l #MU_BUTTON,d0 ; request for button event?
and (a0),d0
beq .exit ; no ->
*------------- configure timer event
lea bvar,a1 ; ^button event variables
move 2(a0),d7 ; nclicks + reverse flag
move.b d7,BI_MAXCLICKS+1(a1) ; isolate and save nclicks
clr.b d7 ; isolate reverse flag
move d7,BI_REVCOND(a1) ; save reverse flag
move 4(a0),BI_BMASK(a1) ; save button mask
move 6(a0),BI_BSTATE(a1) ; save button state
; new mouse button parameters:
clr 4(a0) ; mask = 0
clr 6(a0) ; state = 0
moveq.l #1,d7 ; new handler mode
move d7,2(a0) ; also used for new nclicks
; -> button condition always true
*------------- configure timer event
moveq.l #MU_TIMER,d0 ; request for timer event?
and (a0),d0
beq.s .no_timer ; no ->
moveq.l #2,d7 ; new mode
move.l 28(a0),d0 ; time = 0 ms?
beq.s .exit ; yes: fine, exactly what we need
moveq.l #3,d7 ; new mode
swap d0 ; time in Motorola format
cmp.l prvtime,d0 ; identical to previous time?
beq.s .nulltime ; yes ->
move.l d0,prvtime ; no: save timer event value
LWDIVU #5,d0,d1 ; convert to 200 Hz resolution
add.l sysclock,d0 ; + current timer value
move.l d0,tendtime ; this is our timer end value
bra.s .nulltime ; and set own one
*------------- user doesn't want timer events - but we need them!
.no_timer: moveq.l #-1,d0 ; reset previous timer event value
move.l d0,prvtime
or #MU_TIMER,(a0) ; set bit: check timer events
.nulltime: clr.l 28(a0) ; time: 0 ms
.exit: rts ; bye
****************************************************************************
*
* nk_beend: end special handling of button event
* #
*
* In: D7.W handler mode:
* 0 button event handler inactive
* 1 user did not check timer events
* 2 user did check timer events with time = 0 ms
* 3 user did check timer events with time > 0 ms
*
* Out: nkc_intout.W[]:updated mouse event information
*
* Reg: D:01234567 A:01234567 CCR
* **...... **...... *
*
****************************************************************************
nk_beend: lea nkc_intout,a0 ; ^event mask
move d7,d0 ; which mode?
beq .exit ; no special handling
lea bvar,a1 ; ^button event info block
move BI_PRVBSTATE(a1),6(a0) ; return button state
*------------- analyze which events have occured
moveq.l #MU_MESAG,d1 ; did message event occur?
and (a0),d1 ; and with event mask
beq.s .chkflag ; no message event ->
and #!MU_BUTTON,(a0) ; no button event
.chkflag: moveq.l #MU_BUTTON,d1 ; did button event occur?
and (a0),d1 ; (if not: just moving a window
; or something like that)
beq.s .lock ; no -> lock mouse button event
*------------- application has mouse under its control; what now?
tst.b BI_LOCK(a1) ; is button event locked?
bne .unlock ; yes -> unlock it
tst.b BI_BEVALID(a1) ; event valid?
bne.s .butev ; yes ->
*------------- mouse click isn't finished, yet; wait
move BI_BMODE(a1),d1 ; no: get handler mode
beq.s .nombut ; standby mode ->
subq #1,d1 ; wait mode?
beq.s .wait ; yes ->
.hold: clr 12(a0) ; # of clicks = 0
bra.s .evtimer
.wait: move.l BI_BENDTIME(a1),d1 ; button event end time
cmp.l sysclock,d1 ; end of time reached?
bhi.s .nombut ; no ->
addq #1,BI_BMODE(a1) ; change to hold mode
tst.b BI_CVALID(a1) ; was last button condition valid?
bne.s .butev ; yes ->
clr BI_BMODE(a1) ; no: standby mode
.butev: move BI_NCLICKS(a1),12(a0) ; return # of clicks
move BI_SBSTATE(a1),6(a0) ; return start button state
sf.b BI_BEVALID(a1) ; button event fetched
bra.s .evtimer
.nombut: and #!MU_BUTTON,(a0) ; no mouse button event
*------------- timer event handling
.evtimer: subq #1,d0 ; timer event checked by us?
beq.s .nktimer ; yes ->
subq #1,d0 ; 0 ms timer checked by user?
beq.s .exit ; yes ->
.user0: move.l tendtime,d1 ; timer event end time
cmp.l sysclock,d1 ; end of waiting time reached?
bls.s .exit ; yes ->
.nktimer: and #!MU_TIMER,(a0) ; no timer event occured
.exit: move (a0),d0 ; event mask
and #MU_TIMER,d0 ; did a timer event occur?
beq.s .exit2 ; no ->
.treset: moveq.l #-1,d0 ; yes: reset previous timer
move.l d0,prvtime ; event value
.exit2: rts
*------------- AES didn't return MU_BUTTON -> screen manager has taken mouse
* control: don't create MU_BUTTON events
.lock: st.b BI_LOCK(a1) ; lock mouse button event
move #MU_XTIMER,d1 ; lock timer events, too?
and nkc_intin,d1 ; check this flag
beq.s .evtimer ; don't lock ->
bra.s .nktimer ; lock ->
*------------- AES did return MU_BUTTON (applications has mouse under its
* control) but the button events were locked previously: unlock
* them
.unlock: sf.b BI_LOCK(a1) ; unlock mouse button event
clr BI_BMODE(a1) ; reset mode
sf.b BI_BEVALID(a1) ; reset button event flag
bra.s .nombut
****************************************************************************
*
* nk_mctrl: set control array for multi event
* #
*
* In: -
*
* Out: nkc_contrl.W[]: control parameters configured for evnt_multi() call
*
* Reg: D:01234567 A:01234567 CCR
* ........ *....... *
*
****************************************************************************
nk_mctrl: lea nkc_contrl,a0 ; ^control array
move #25,(a0)+ ; opcode
move #16,(a0)+ ; size of intin
move #7,(a0)+ ; size of intout
move #1,(a0)+ ; size of addrin
clr (a0) ; size of addrout
rts ; bye
****************************************************************************
*
* nk_msave: save input parameters for evnt_multi() call in buffer
* #
*
* In: -
*
* Out: multibuf.W[]: first 16 words of nkc_intin and first long of
* nkc_adrin
*
* Reg: D:01234567 A:01234567 CCR
* *******. **...... *
*
****************************************************************************
nk_msave: lea nkc_intin,a0 ; ^intin array
lea multibuf,a1 ; ^save buffer
movem.l (a0)+,d0-d6 ; get first 14 words of nkc_intin
movem.l d0-d6,(a1) ; save 'em in buffer
move.l (a0),7*4(a1) ; save last two words
move.l nkc_adrin,8*4(a1) ; save contents of addrin
rts
****************************************************************************
*
* nk_mrestore: restore evnt_multi() input parameters corrupted by AES(!)
* #
*
* In: -
*
* Out: nkc_contrl.w[]: restored data (5 words)
* nkc_intin.w[] : restored data (16 words)
* nkc_adrin.L[] : restored data (1 longword)
*
* Reg: D:01234567 A:01234567 CCR
* *******. **...... *
*
****************************************************************************
nk_mrestore: lea multibuf,a0 ; ^save buffer
lea nkc_intin,a1 ; ^intin array
movem.l (a0)+,d0-d6 ; first 14 words of nkc_intin
movem.l d0-d6,(a1) ; put them in nkc_intin array
move.l (a0)+,7*4(a1) ; last two words
move.l (a0),nkc_adrin ; restore addrin array
bra.s nk_mctrl ; restore contrl array
.endif ; .if NKCGEM=1
****************************************************************************
*
* nk_200hz: 200 Hz system clock interrupt
* # I S
*
* In: -
*
* Out: -
*
* Reg: D:01234567 A:01234567 CCR
* ........ ........ *
*
****************************************************************************
XBRA_HD 0 ; XBRA header
nk_200hz: move.l _hz_200,sysclock ; just transfer value
move.l nk_200hz-4(pc),-(sp) ; old vector address
rts ; jump to old routine
*START
****************************************************************************
* GLOBAL TEXT SECTION *
****************************************************************************
*END
.text
*START
****************************************************************************
*
* nkc_init: initialize NKCC
* # G U
*
* C prototype: int nkc_init(unsigned long flags,int vdihnd,int *pglobal);
*---------------------------------------------------------------------------
* This function initializes NKCC. It must be called once before any other
* NKCC routine. It performs some tasks that may be important for you to
* know:
*
* - bit 3 of the system variable <conterm> ($484.B) is set
* - a 200 Hz clock interrupt is installed, using the XBRA method (ID is
* "NKCC")
*
* nkc_init() gets some flags which configure NKCC and enable some special
* functions:
*
* NKI?_BUTHND install NKCC's button event handler (see documentation
* NKCC.DOC for details)
* NKI?_BHTOS additional flag: install only, if TOS has mouse click bug
* NKI?_NO200HZ don't install the 200 Hz timer interrupt
*
* Notes:
*
* - if NKCC is assembled as TOS-only version (symbol NKCGEM set to 0),
* both NKI?_BUTHND and NKI?_BHTOS flags are ignored.
*
* - if the button event handler is installed, the NKI?_NO200HZ flag is
* ignored (because the 200 Hz clock is needed by the handler). Besides,
* the initialization continues:
*
* - an own GEM trap handler (trap #2) is installed, using the XBRA method
* (to be up to date when a new double click time is set via the AES
* function evnt_dclick())
*
* - a vex_butv() call (VDI) is made to install a mouse button exchange
* handler
*
* In: D0.L miscellaneous flags (NKI?_...); see above
* D1.W handle of an open VDI workstation
* (must only be valid if the button handler is
* installed)
* A0.L ^applications GLOBAL array (from GEM parameter block)
* not used in the TOS version of NKCC
*
* Out: D0.W NKCC's version number as 4 digit BCD
* (main # in high byte, sub # in low byte)
*
* Reg: D:01234567 A:01234567 CCR
* U**..... **...... *
*
****************************************************************************
*END
nkc_init: move.l a2,-(sp) ; save a2 for Turbo C/Pure C
movem.l d0-d1,-(sp) ; save flags and VDI handle
subq.l #2,sp ; one word local stack space
.if NKCGEM=1
move.l a0,aespb+4 ; keep ^global array
move #1,-(sp) ; device: keyboard
move #14,-(sp) ; function opcode: Iorec
trap #14 ; XBIOS
addq.l #4,sp ; clean stack
move.l d0,kbdiorec ; keep ^IOREC structure
move.l d0,a0 ; load into address register
move IBUFHD(a0),iohead ; keep current head pointer
.endif ; .if NKCGEM=1
*------------- switch to Supervisor mode to have access to system variables
clr.l -(sp) ; use usp as ssp
move #$20,-(sp) ; Super
trap #1 ; GEMDOS
move.l d0,2(sp) ; save old sp
move #$20,(sp) ; Super opcode for next call
*------------- enable auto return of shift/ctrl/alt status
bset.b #3,conterm.w ; set bit for auto shift return
*------------- locate shift state system variable
move.l _sysbase.w,a0 ; ^OS header
move 2(a0),d0 ; get TOS version
move d0,6(sp) ; save it in local stack space
cmp #$0100,d0 ; TOS 1.0?
beq.s .tos10 ; yes ->
move.l $24(a0),pshift ; get ^shift state variable
bra.s .user ; ->
.tos10: move.l #$e1b,pshift ; this is the location in TOS 1.0
*------------- switch back to user mode
.user: trap #1 ; GEMDOS
addq #6,sp ; clean stack
*------------- fetch addresses of TOS' key scan code translation tables
moveq.l #-1,d0 ; the function is also used to
move.l d0,-(sp) ; change the addresses; values
move.l d0,-(sp) ; of -1 as new addresses tell
move.l d0,-(sp) ; XBIOS not to change them
move #$10,-(sp) ; Keytbl
trap #14 ; XBIOS
lea $e(sp),sp ; clean stack
move.l d0,a0 ; ^key table structure
move.l (a0)+,pkey_unshift ; get ^unshifted table
move.l (a0)+,pkey_shift ; get ^shifted table
move.l (a0),pkey_caps ; get ^CapsLock table
*------------- do some other initialization stuff
clr.l sflags ; reset special key flags
clr.b prvvalid ; no previous key code
*------------- install the mouse button handler
move (sp)+,d0 ; TOS version
movem.l (sp),d1-d2 ; restore flags and VDI handle
.if NKCGEM=1
clr.b buthnd ; default: set flag: not installed
btst.l #NKIb_BUTHND,d1 ; install it?
beq .timer ; no ->
btst.l #NKIb_BHTOS,d1 ; check TOS version number?
beq.s .butev ; no ->
cmp #$0104,d0 ; bug appeared in TOS 1.04!
blo .timer ; TOS is ok ->
cmp #$0306,d0 ; bug is solved since TOS 3.06!
bhs .timer ; TOS is ok ->
.butev: bclr.l #NKIb_NO200HZ,d1 ; must install timer interrupt
st.b buthnd ; set flag: handler installed
move d2,vdihnd ; save VDI handle
moveq.l #0,d0 ; do some initializations
lea bvar,a1 ; ^button event info block
move d0,BI_BMODE(a1) ; init interrupt mode
move.b d0,BI_BEVALID(a1) ; mouse click info not valid
move d0,BI_PRVBSTATE(a1) ; init previous button state
move d0,BI_BMASK(a1) ; don't check any button
move.b d0,BI_LOCK(a1) ; mouse button event isn't locked
subq.l #1,d0 ; d0.l = -1
move d0,BI_REVCOND(a1) ; reverse button condition
; -> no mouse click is checked
move.l d0,prvtime ; previous timer event value
lea nkc_contrl,a0 ; set parameter array for vex_butv
move #125,(a0)+ ; opcode
clr.l (a0)+ ; no ptsin/ptsout entries
clr.l (a0)+ ; no intin/intout entries
addq #2,a0 ; entry #5 is unused
move d2,(a0)+ ; handle of workstation
lea nk_butvec(pc),a1 ; ^our handler
move.l a1,(a0)
moveq.l #115,d0 ; opcode: VDI
move.l #vdipb,d1 ; ^parameter block
trap #2 ; execute VDI
move.l nkc_contrl+18,nk_butvec-4 ; save old handler address
lea nkc_contrl,a0 ; set parameter for evnt_dclick
move #26,(a0)+ ; opcode
move #2,(a0)+ ; # of entries in intin
move #1,(a0)+ ; # of entries in intout
clr.l (a0)+ ; no entries in addrin/addrout
clr nkc_intin+2 ; get/set flag: get value
move #200,d0 ; opcode for AES
move.l #aespb,d1 ; ^parameter block
trap #2 ; execute AES
move nkc_intout,bvar+BI_DCLTIME ; save double click time
; install trap #2 handler
moveq.l #34,d0 ; vector number
moveq.l #NKXM_NUM,d1 ; mode: vector number
lea nk_gemtrap(pc),a0 ; ^function to install
bsr nkc_vlink ; install it
.endif ; .if NKCGEM=1
*------------- install 200 Hz clock interrupt
.timer: clr.l sysclock ; init 200 Hz clock for the case
; that the timer won't be installed
movem.l (sp)+,d1-d2 ; restore flags and VDI handle
btst.l #NKIb_NO200HZ,d1 ; install interrupt?
seq.b timerflag ; $00 = no, $ff = yes
bne.s .exit ; no ->
moveq.l #69,d0 ; vector number
moveq.l #NKXM_NUM,d1 ; mode: vector number
lea nk_200hz(pc),a0 ; ^function to install
bsr nkc_vlink ; install it
*------------- restore saved register and exit
.exit: move.l (sp)+,a2 ; restore register
move #VERSION,d0 ; load version #
rts ; bye
*START
****************************************************************************
*
* nkc_exit: exit NKCC
* # G U
*
* C prototype: int nkc_exit(void);
*---------------------------------------------------------------------------
* nkc_exit() must be called before the program is quit. It removes all
* handlers installed in the system.
*
* In: -
*
* Out: D0.W status flag:
* 0 OK
* -1 can't remove 200 Hz clock interrupt
* -2 can't remove trap #2 handler
* -3 can't remove both handlers
* An error can happen if somebody corrupted the
* XBRA vector list. This is fatal!
*
* Reg: D:01234567 A:01234567 CCR
* ***..... **...... =D0.W
*
****************************************************************************
*END
nkc_exit: move.l a2,-(sp) ; save register
*------------- remove 200 Hz system clock interrupt
clr -(sp) ; default remove status for
; timer interrupt
tst.b timerflag ; installed?
beq.s .buthnd ; no ->
moveq.l #69,d0 ; vector number
moveq.l #NKXM_NUM,d1 ; mode: vector number
lea nk_200hz(pc),a0 ; ^function to remove
bsr nkc_vunlink ; remove it
move d0,(sp) ; save remove status
*------------- remove own button event handler
.buthnd: clr -(sp) ; default remove status for
; button event handler
.if NKCGEM=1
tst.b buthnd ; handler installed?
beq.s .exit ; no ->
lea nkc_contrl,a0 ; set paremeter array for vex_butv
move #125,(a0)+ ; opcode
clr.l (a0)+ ; no ptsin/ptsout entries
clr.l (a0)+ ; no intin/intout entries
addq #2,a0 ; entry #5 is unused
move vdihnd,(a0)+ ; handle of workstation
lea nk_butvec(pc),a1 ; ^our handler
move.l -4(a1),(a0) ; ^old routine
moveq.l #115,d0 ; opcode: VDI
move.l #vdipb,d1 ; ^parameter block
trap #2 ; execute VDI
; remove trap #2 handler
moveq.l #34,d0 ; vector number
moveq.l #NKXM_NUM,d1 ; mode: vector number
lea nk_gemtrap(pc),a0 ; ^function to remove
bsr nkc_vunlink ; remove it
move d0,(sp) ; save status
.endif ; .if NKCGEM=1
*------------- restore saved registers and exit
.exit: move (sp)+,d0 ; trap #2 remove error?
beq.s .stat0 ; no ->
move (sp)+,d0 ; 200 Hz clock remove error?
beq.s .stat1 ; no ->
moveq.l #-3,d0 ; both failed!
bra.s .ret
.stat0: move (sp)+,d0 ; 200 Hz clock remove error?
beq.s .ret ; no ->
moveq.l #-1,d0 ; "only" 200 Hz clock failure?
bra.s .ret
.stat1: moveq.l #-2,d0 ; "only" trap #2 remove failure?
.ret: move.l (sp)+,a2 ; restore register
rts ; bye
*START
****************************************************************************
*
* nkc_set: set special key flags
* # G
*
* C prototype: void nkc_set(unsigned long flags);
*---------------------------------------------------------------------------
* This function is used to enable/disable special key handling procedures.
* The features which can be set are:
*
* - direct input of ASCII codes; when switched on, pressing the Alternate
* key plus one of the numbers on the numeric keypad will start the input
* of a decimal ASCII number. The input is finished either when 3 digits
* are typed in or the Alternate key is released. NKCC will return the
* corresponding character with the entered ASCII code. This feature makes
* it possible to use the whole range of the character set (from 0 ... 255).
*
* - deadkey management; when switched on, NKCC will combine some combi-
* nations of two key strokes to one character. This is used to generate
* characters with accents which are not on the keyboard. The supported
* deadkeys are:
*
* ^ + aeiou = âêîôû (NKS?_D_CIRCUM)
* ~ + nNaoAo = ñÑ░▒╖╕ (NKS?_D_TILDE)
* ' + eEaiou = éÉáíóú (NKS?_D_AGUI)
* ` + aeiouA = àèìòù╢ (NKS?_D_GRAVE)
* ╣ + aeiouyAOU = äëïöüÿÄÖÜ (NKS?_D_UMLAUT)
* " + aeiouyAOU = äëïöüÿÄÖÜ (NKS?_D_QUOTE)
* ° + aA = åÅ (NKS?_D_SMOERE)
* , + cC = çÇ (NKS?_D_CEDIL)
* / + oO24 = │▓½¼ (NKS?_D_SLASH)
*
* 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.
*
* Each deadkey can be enabled/disabled separately.
*
* - Control key emulation: Control plus an ASCII code in the range of
* $40...$5F (characters @, A...Z, [, \, ], ^ and _) is converted
* to an ASCII code of $00...$1F.
*
*
* In: D0.L new key flags (bit set = feature on):
* NKS?_ALTNUM ASCII input
* NKS?_D_... deadkey ...
* (NKSf_DEADKEY: all deadkeys)
* NKS?_CTRL control key emulation
*
* Out: -
*
* Reg: D:01234567 A:01234567 CCR
* ***..... **...... *
*
****************************************************************************
*END
nkc_set: move.l d0,sflags ; just save flags
rts ; bye
*START
****************************************************************************
*
* nkc_conin: raw console character input
* # G
*
* C prototype: int nkc_conin(void);
*---------------------------------------------------------------------------
* This routine replaces the Gemdos function Crawcin. However, it returns
* a WORD with the key code in normalized format rather than a LONG with
* the key code in the language dependend TOS format.
*
* In: -
*
* Out: D0.W key code in normalized format
* for details see nkc_tconv()
* CCR set according content of D0.W
*
* Reg: D:01234567 A:01234567 CCR
* W**..... **...... =D0.W
*
****************************************************************************
*END
nkc_conin: tst.b prvvalid ; previous character in buffer?
beq.s .getkey ; no->
clr.b prvvalid ; remove key code from buffer
move prvkey,d0 ; get key code
rts ; bye
.getkey: movem.l d3-d7/a2-a6,-(sp) ; save registers
clr d0 ; don't check Alternate state
bsr nk_gci ; get key code
lea nk_gci(pc),a0 ; ^function to execute
bsr nk_spec ; special key handling
movem.l (sp)+,d3-d7/a2-a6 ; restore registers
rts ; bye
*START
****************************************************************************
*
* nkc_cstat: return console character input status
* # G
*
* C prototype: int nkc_cstat(void);
*---------------------------------------------------------------------------
* This function checks, if a key is in the key input buffer or not.
*
* In: -
*
* Out: D0.W flag:
* 0 no key in buffer
* -1 at least one key in buffer
* CCR set according content of D0.W
*
* Reg: D:01234567 A:01234567 CCR
* W**..... **...... =D0.W
*
****************************************************************************
*END
nkc_cstat: tst.b prvvalid ; previous character in buffer?
sne.b d0 ; $ff = yes, $00 = no
ext d0 ; as word
bne.s .exit ; char available: exit
move.l a2,-(sp) ; save register for Turbo C/Pure C
move #11,-(sp) ; Cconis
trap #1 ; Gemdos
addq #2,sp ; clean stack
move.l (sp)+,a2 ; restore register
tst d0 ; set CCR
.exit: rts ; bye
.if NKCGEM=1
*START
****************************************************************************
*
* nkc_multi: NKCC multi event
* # G U
*
* C prototype: int cdecl nkc_multi(
* int mflags,
* int mbclicks,int mbmask,int mbstate,
* int mm1flags,int mm1x,int mm1y,int mm1width,int mm1height,
* int mm2flags,int mm2x,int mm2y,int mm2width,int mm2height,
* int *mmgpbuff,
* int mtlocount,int mthicount,
* int *mmox,int *mmoy,int *mmbutton,int *mmokstate,
* int *mkreturn,int *mbreturn);
*---------------------------------------------------------------------------
* nkc_multi() is a binding function to the AES multi event handler. The
* only differences are the keyboard events and the shift key state: the key
* codes are returned in normalized format (see nkc_tconv()), the shift key
* state is compatible to the NKF?_... flags. For a detailed description of
* the whole mass of parameters consult your AES manual or compiler handbook!
*
* In: 4(SP).w event mask (MU_...)
* 6(SP).w MU_BUTTON: max # of clicks to wait for
* 8(SP).w MU_BUTTON: mask of buttons to check
* 10(SP).w MU_BUTTON: button states to wait for
* 12(SP).w MU_M1: area enter/leave flag
* 14(SP).w MU_M1: x position of area
* 16(SP).w MU_M1: y position of area
* 18(SP).w MU_M1: width of area
* 20(SP).w MU_M1: height of area
* 22(SP).w MU_M2: area enter/leave flag
* 24(SP).w MU_M2: x position of area
* 26(SP).w MU_M2: y position of area
* 28(SP).w MU_M2: width of area
* 30(SP).w MU_M2: height of area
* 32(SP).L MU_MESAG: ^8 words of message buffer
* 36(SP).w MU_TIMER: low word of time to wait
* 38(SP).w MU_TIMER: high word of time to wait
* 40(SP).L MU_BUTTON/M1/M2: ^word for mouse x
* 44(SP).L MU_BUTTON/M1/M2: ^word for mouse y
* 48(SP).L MU_BUTTON/M1/M2: ^word for button state
* 52(SP).L MU_BUTTON/M1/M2: ^word for shift state
* 56(SP).L MU_KEYBD: ^word for key code in normalized format
* 60(SP).L MU_BUTTON: ^word for # of mouse clicks
*
* Out: D0.W mask of occured events (MU_...)
*
* Reg: D:01234567 A:01234567 CCR
* W**..... **...... *
*
****************************************************************************
*END
nkc_multi: tst.b prvvalid ; previous character in buffer?
beq.s .mevent ; no ->
clr.b prvvalid ; remove key code from buffer
move.l 56(sp),a0 ; ^buffer for key code
move prvkey,(a0) ; return key code
moveq.l #MU_KEYBD,d0 ; a keyboard event occured
rts ; bye
.mevent: movem.l d3-d7/a2-a6,-(sp) ; save registers
*------------- transfer stack arguments to GEM parameter arrays
lea 10*4+4(sp),a0 ; ^first parameter
lea nkc_intin,a1 ; ^integer in array
movem.l (a0)+,d1-d7 ; get the first 14 words
movem.l d1-d7,(a1) ; place them in intin
move.l (a0)+,nkc_adrin ; ^message buffer in addrin
move.l (a0),7*4(a1) ; timer event lo and hi count
bsr nk_mctrl ; setup control array
*------------- execute multi event
bsr nk_bestart ; start handling for button event
bsr nk_msave ; save multi event parameters
.wait: cmp #25,nkc_contrl ; still evnt_multi() opcode?!?
beq.s .aes ; yes ->
bsr nk_mrestore ; NO! AES corrupted it! restore
.aes: lea nkc_intin,a0 ; ^intin
move (a0),-(sp) ; save event mask
and #!MU_XTIMER,(a0) ; clear x-timer flag
move #200,d0 ; opcode for AES
move.l #aespb,d1 ; ^AES parameter block
trap #2 ; call GEM
move (sp)+,nkc_intin ; restore event mask
move nkc_intout,d0 ; mask of occured events
and #MU_KEYBD,d0 ; keyboard event?
bne.s .buthnd ; yes ->
move.l kbdiorec,a0 ; no: get ^keyboard's I/O record
move IBUFHD(a0),iohead ; reset NKCC's head pointer
.buthnd: bsr nk_beend ; end handling of button event
tst nkc_intout ; did any event occur?
beq.s .wait ; no ->
*------------- return intout parameters via pointers
movem.l 10*4+40(sp),a0-a5 ; get return pointers
lea nkc_intout,a6 ; ^intout array
move (a6)+,d0 ; mask of occured events
move (a6)+,(a0) ; mouse x
move (a6)+,(a1) ; mouse y
move (a6)+,(a2) ; mouse button state
move.b 1(a6),(a3) ; shift key state (NKC flag
; compatible!)
clr.b 1(a3) ; clear low byte of shift state
move.l a6,a3 ; ^shift state in intout
move 4(a6),(a5) ; # of mouse clicks
move 2(a6),(a4) ; key code
* You wonder why (a4) is written as last one and (a3) points to intout
* instead of the original return location? This is for the case that
* the caller isn't interested in one or some of the return values and
* let them point to ONE dummy variable.
*------------- check if keyboard event occured and convert key code, if so
moveq.l #MU_KEYBD,d1 ; the flag to test
and d0,d1 ; is it set?
beq.s .exit ; no-> exit
move d0,-(sp) ; save event mask
move.l a4,-(sp) ; save ^key code
move (a4),d0 ; scan code + ASCII code
moveq.l #MU_BUTTON|MU_M1|MU_M2,d1 ; any of the events checked
and 10*4+4+6(a7),d1 ; which return shift state?
bne.s .useiout ; yes->
move.l pshift,a3 ; no: get shift state directly
move.b (a3),d1 ; get it
and #$f,d1 ; isolate valid bits
bra.s .conv
.useiout: move (a3),d1 ; get shift state from intout
.conv: bsr nk_bioscode ; convert to BIOS format
bsr nk_real_shift ; try to get original shift flags
bsr nkc_tconv ; convert to normalized format
lea nk_mci(pc),a0 ; ^function to execute
bsr nk_spec ; special key code handling
move.l (sp)+,a0 ; restore ^key code
move d0,(a0) ; return key code
move (sp)+,d0 ; restore event mask
move d0,nkc_intout ; and intout (changed by nk_spec)
.exit: movem.l (sp)+,d3-d7/a2-a6 ; restore registers
rts ; bye
*START
****************************************************************************
*
* nkc_amulti: NKCC multi event called by Assembler *** added by Gerd Knops
* # G U
*
* See description of nkc_multi()!
*
* usage: instead of move.l #aespb,d1
* move #$c8,d0
* trap #2
*
* do jsr nkc_amulti
*
* In: all parameters for evnt_multi in the AES parameter arrays
*
* Out: values in intout and message buffer
*
* Reg: D:01234567 A:01234567 CCR
* ***..... **...... *
*
****************************************************************************
*END
nkc_amulti: tst.b prvvalid ; previous character in buffer?
beq.s .mevent ; no->
clr.b prvvalid ; remove key code from buffer
clr nkc_intout+8 ; no SHIFT etc.
move prvkey,nkc_intout+10 ; return key code
move #MU_KEYBD,nkc_intout ; a keyboard event occured
rts ; bye
.mevent: movem.l d3-d7/a2-a6,-(sp) ; save registers
move nkc_intin,-(sp) ; events to get
*------------- execute multi event
bsr nk_bestart ; start handling for button event
bsr nk_msave ; save multi event parameters
.wait: cmp #25,nkc_contrl ; still evnt_multi() opcode?!?
beq.s .aes ; yes ->
bsr nk_mrestore ; NO! AES corrupted it! restore
.aes: lea nkc_intin,a0 ; ^intin
move (a0),-(sp) ; save event mask
and #!MU_XTIMER,(a0) ; clear x-timer flag
move #200,d0 ; opcode for AES
move.l #aespb,d1 ; ^AES parameter block
trap #2 ; call GEM
move (sp)+,nkc_intin ; restore event mask
move nkc_intout,d0 ; mask of occured events
and #MU_KEYBD,d0 ; keyboard event?
bne.s .buthnd ; yes ->
move.l kbdiorec,a0 ; no: get ^keyboard's I/O record
move IBUFHD(a0),iohead ; reset NKCC's head pointer
.buthnd: bsr nk_beend ; end handling of button event
tst nkc_intout ; did any event occur?
beq.s .wait ; no ->
move (sp)+,d2 ; events to get
*------------- check if keyboard event occured and convert key code, if so
lea nkc_intout+8,a3 ; ^shift key state
move (a3),d0 ; make in NKF?_... compatible
move.b d0,(a3)
clr.b 1(a3)
move nkc_intout,d0 ; mask of received events
moveq.l #MU_KEYBD,d1 ; the flag to test
and d0,d1 ; is it set?
beq.s .exit ; no-> exit
move d0,-(sp) ; save event mask
move nkc_intout+10,d0 ; scan code + ASCII code
moveq.l #MU_BUTTON|MU_M1|MU_M2,d1 ; any of the events checked
and d2,d1 ; which return shift state?
bne.s .useiout ; yes->
move.l pshift,a3 ; no: get shift state directly
move.b (a3),d1 ; get it
and #$f,d1 ; isolate valid bits
bra.s .conv
.useiout: move nkc_intout+8,d1 ; get shift state from intout
lsr #8,d1 ; in TOS format
.conv: bsr nk_bioscode ; convert to BIOS format
bsr nk_real_shift ; try to get original shift flags
bsr.s nkc_tconv ; convert to normalized format
lea nk_mci(pc),a0 ; ^function to execute
bsr nk_spec ; special key code handling
move d0,nkc_intout+10 ; save keycode
move (sp)+,d0 ; restore event mask
move d0,nkc_intout ; and intout (changed by nk_spec)
.exit: movem.l (sp)+,d3-d7/a2-a6 ; restore registers
rts ; bye
.endif ; .if NKCGEM=1
*START
****************************************************************************
*
* nkc_tconv: TOS key code converter
* # G R
*
* C prototype: int nkc_tconv(long toskey);
*---------------------------------------------------------------------------
* This is the most important function within NKCC: it takes a key code
* returned by TOS and converts it to the sophisticated normalized format.
*
* Note: the raw converter does no deadkey handling, ASCII input or
* Control key emulation.
*
* In: D0.L key code in TOS format:
* 0 1
* bit 31: ignored ignored
* bit 30: ignored ignored
* bit 29: ignored ignored
* bit 28: no CapsLock CapsLock
* bit 27: no Alternate Alternate pressed
* bit 26: no Control Control pressed
* bit 25: no left Shift key left Shift pressed
* bit 24: no right Shift key right Shift pressed
*
* bits 23...16: scan code
* bits 15...08: ignored
* bits 07...00: ASCII code (or rubbish in most cases
* when Control or Alternate is pressed ...)
*
* Out: D0.W normalized key code:
* bits 15...08: flags:
* 0 1
* NKF?_FUNC printable char "function key"
* NKF?_RESVD ignore it ignore it
* NKF?_NUM main keypad numeric keypad
* NKF?_CAPS no CapsLock CapsLock
* NKF?_ALT no Alternate Alternate pressed
* NKF?_CTRL no Control Control pressed
* NKF?_LSH no left Shift key left Shift pressed
* NKF?_RSH no right Shift key right Shift pressed
*
* bits 07...00: key code
* function (NKF?_FUNC set):
* < 32: special key (NK_...)
* >=32: printable char + Control and/or Alternate
* no function (NKF?_FUNC not set):
* printable character (0...255!!!)
*
* CCR set according content of D0.W
*
* Reg: D:01234567 A:01234567 CCR
* U**..... **...... =D0.W
*
****************************************************************************
*END
*
* Usage of the NKF?_RESVD flag:
*
* If the flag is set, the function nkc_cmp(), which evaluates the flag,
* has to check the state of the shift keys when comparing two key codes.
*
* Don't use the flag outside NKCC! Its content and meaning may change
* in future versions without notice!
*
****************************************************************************
nkc_tconv: movem.l d3/d4,-(sp) ; save registers
*------------- separate TOS key code
move.l d0,d1 ; TOS key code
swap d1 ; .W = scan code and flags
move d1,d2 ; copy
move #$ff,d3 ; and-mask
and d3,d0 ; .B = ASCII code
and d3,d1 ; .B = scan code
beq .tos306 ; scancode=zero (key code created
; by ASCII input of TOS 3.06)? ->
and #$1f00,d2 ; .W = key flags (in high byte)
*------------- decide which translation table to use
move d2,d3 ; key flags
and #NKFf_SHIFT,d3 ; isolate bits for shift keys
beq.s .ktab1 ; shift key pressed? no->
move.l pkey_shift,a0 ; yes: use shift table
bra.s .ktab3 ; ->
.ktab1: btst.l #NKFb_CAPS,d2 ; CapsLock?
beq.s .ktab2 ; no->
move.l pkey_caps,a0 ; yes: use CapsLock table
bra.s .ktab3 ; ->
.ktab2: move.l pkey_unshift,a0 ; use unshifted table
*------------- check if scan code is out of range
*
* Illegal scancodes can be used to produce 'macro key codes'. Their format is:
*
* - the scancode must be $84 or larger (should be $ff to work properly with old
* versions of Mag!x)
* - the ASCII code must be in the range $20...$ff (values below are set to $20
* by NKCC)
* - Alternate and Control are not used for the normalized key code. However,
* if at least one of them is non-zero, then the numeric keypad flag will be
* set in the resulting key code.
*
.ktab3: cmp.b #$84,d1 ; illegal scan code?
blo.s .ktab4 ; no ->
move d2,d1 ; flags
and #NKFf_ALT|NKFf_CTRL,d1 ; Alternate or Control?
beq.s .special ; no ->
or #NKFf_NUM,d0 ; yes: set numeric keypad flag
and #NKFf_CAPS|NKFf_SHIFT,d2 ; mask off both flags
.special: or d2,d0 ; combine with ASCII code
or #NKFf_FUNC|NKFf_RESVD,d0 ; set function and resvd
cmp.b #$20,d0 ; ASCII code in range?
bhs .exit ; yes ->
move.b #$20,d0 ; no: use minimum
bra .exit ; ->
*------------- check if Alternate + number: they have simulated scan codes
.ktab4: cmp.b #$78,d1 ; scan code of Alt + number?
blo.s .scan1 ; no->
sub.b #$76,d1 ; yes: calculate REAL scan code
move.b (a0,d1),d0 ; fetch ASCII code
or #NKFf_ALT,d2 ; set Alternate flag
bra .cat_codes ; -> add flag byte and exit
*------------- check if exception scan code from cursor keypad
.scan1: lea xscantab,a1 ; ^exception scan code table
.search_scan: move (a1)+,d3 ; NKC and scan code
bmi.s .tabend ; <0? end of table reached ->
cmp.b d1,d3 ; scan code found?
bne.s .search_scan ; no: continue search ->
lsr #8,d3 ; .B = NKC
moveq.l #0,d0 ; mark: key code found
bra.s .scan2 ; ->
.tabend: moveq.l #0,d3 ; no NKC found yet
*------------- check if rubbish ASCII code and erase it, if so
.scan2: move.b (a0,d1),d4 ; ASCII code from translation table
cmp.b #32,d0 ; ASCII returned by TOS < 32?
bhs.s .scan3 ; no -> can't be rubbish
cmp.b d4,d0 ; yes: compare with table entry
beq.s .scan3 ; equal: that's ok ->
moveq.l #0,d0 ; not equal: rubbish! clear it
*------------- check if ASCII code could only be produced via Alternate key
* combination
.scan3: tst.b d0 ; ASCII code valid?
beq.s .scan4 ; no ->
cmp.b d4,d0 ; compare with table entry
beq.s .scan4 ; equal: normal key ->
and #!NKFf_ALT,d2 ; no: clear Alternate flag
*------------- check if ASCII code found yet, and set it, if not
.scan4: tst.b d0 ; found?
bne.s .scan5 ; yes ->
move.b d3,d0 ; no: use code from exception table
bne.s .scan5 ; now valid? yes ->
move.b d4,d0 ; no: use code from transl. table
*------------- check special case: delete key
.scan5: cmp.b #127,d0 ; ASCII code of Delete?
bne.s .scan6 ; no ->
move.b #NK_DEL,d0 ; yes: set according NKC
*------------- check if key is on numeric keypad (via scan code)
.scan6: cmp.b #$4a,d1 ; numeric pad scan code range?
beq.s .numeric ; yes ->
cmp.b #$4e,d1
beq.s .numeric ; yes ->
cmp.b #$63,d1
blo.s .scan7 ; no ->
cmp.b #$72,d1
bhi.s .scan7 ; no ->
.numeric: or #NKFf_NUM,d2 ; yes: set numeric bit
*------------- check if "function key" and set bit accordingly
.scan7: cmp.b #32,d0 ; ASCII code less than 32?
bhs.s .scan8 ; no ->
or #NKFf_FUNC,d2 ; yes: set function bit
*------------- check special case: Return or Enter key
cmp.b #13,d0 ; Return or Enter key?
bne.s .scan8 ; no ->
btst.l #NKFb_NUM,d2 ; yes: from the numeric pad?
beq.s .scan8 ; no -> it's Return, keep code
moveq.l #NK_ENTER,d0 ; yes: it's Enter; new code
*------------- check if function key (F1-F10) via scan code
.scan8: cmp.b #$54,d1 ; shift + function key?
blo.s .scan9 ; no ->
cmp.b #$5d,d1
bhi.s .scan9 ; no ->
sub.b #$54-$3b,d1 ; yes: scan code for unshifted key
move d2,d3 ; shift flags
and #NKFf_SHIFT,d3 ; any shift key flag set?
bne.s .scan9 ; yes ->
or #NKFf_SHIFT,d2 ; no: set both flags
.scan9: cmp.b #$3b,d1 ; (unshifted) function key?
blo.s .cat_codes ; no ->
cmp.b #$44,d1
bhi.s .cat_codes ; no ->
move.b d1,d0 ; yes: calc NKC
sub.b #$2b,d0
*------------- final flag handling; mix key code (low byte) and flag byte
.cat_codes: move.l pkey_shift,a0 ; ^shifted table
move.b (a0,d1),d3 ; get shifted ASCII code
or d2,d0 ; mix flags with key code
bmi.s .scan10 ; result is "function key"? ->
and #NKFf_CTRL+NKFf_ALT,d2 ; Control or Alternate pressed?
bne.s .scan11 ; yes ->
.scan10: move.l pkey_unshift,a0 ; ^unshifted table
cmp.b (a0,d1),d3 ; shifted ASCII = unshifted ASCII?
beq.s .scan12 ; yes ->
bra.s .exit ; no ->
.scan11: or #NKFf_FUNC,d0 ; Alt/Ctrl + char: set function bit
move.l pkey_caps,a0 ; ^CapsLock table
cmp.b (a0,d1),d3 ; shifted ASCII = CapsLocked ASCII?
bne.s .exit ; no ->
move.b d3,d0 ; yes: use shifted ASCII code
.scan12: or #NKFf_RESVD,d0 ; yes: nkc_cmp() has to check
; the Shift keys
*------------- restore registers and exit
.exit: tst d0 ; set CCR
movem.l (sp)+,d3/d4 ; restore registers
rts ; bye
*------------- special handling for key codes created by TOS' 3.06 ASCII input
.tos306: and #NKFf_CAPS,d2 ; isolate CapsLock flag
or d2,d0 ; merge with ASCII code
movem.l (sp)+,d3/d4 ; restore registers
rts ; bye
*START
****************************************************************************
*
* nkc_gconv: GEM key code converter
* # G R
*
* C prototype: int nkc_gconv(int gemkey);
*---------------------------------------------------------------------------
* Why a second key code converter, you ask? Well, in some cases it might
* happen that the key status byte of the original key code (with states
* of both Shift keys, Control, Alternate and CapsLock) is lost. Then
* this converter function must be called, which uses another algorithm
* to construct the normalized key code.
*
* Notes:
* - the raw converter does no deadkey handling, ASCII input or Control
* key emulation.
* - NKCC does not use this function at all for its own purposes!
* - some key combinations cannot be distinguished without the flag byte!
* For example, "Alternate A" and "Shift Alternate A" produce the same
* result. Whenever possible, use nkc_tconv()!
*
* In: D0.W key code in GEM format:
* bits 15...08: scan code
* bits 07...00: ASCII code
*
* Out: D0.W normalized key code (see nkc_tconv() for details)
* CCR set according content of D0.W
*
* Reg: D:01234567 A:01234567 CCR
* U**..... **...... =D0.W
*
****************************************************************************
*END
nkc_gconv: movem.l d4-d7,-(sp) ; save registers
*------------- find out "real" scan code and convert to TOS key code format
move d0,d1 ; copy key code
lsr #8,d1 ; scan code in d1.w
swap d0 ; move key code to high word
move.l pshift,a0 ; ^key state flags
move.b (a0),d0 ; get 'em
and #NKFf_CAPS>>8,d0 ; isolate CapsLock flag
lea scan_trans,a0 ; ^scan code translation table
.trans: move.l (a0)+,d2 ; get next entry
beq.s .endtrans ; end of table? ->
cmp.b d1,d2 ; scan code found?
bne.s .trans ; no ->
lsr #8,d2 ; "real" scan code
move.b d2,d1 ; use it
swap d2 ; flags to set
or d2,d0 ; set them
.endtrans: swap d0 ; move flags up and key code down
moveq.l #0,d7 ; clear for word operation
move.b d0,d7 ; copy ASCII code
lsl.l #8,d0 ; shift flags and scan code up
move d7,d0 ; restore ASCII code
*------------- try to restore some of the key flags (shift/control/alternate)
move.l pkey_unshift,a0 ; ^unshifted key table
move.b (a0,d1),d4 ; get unshifted code
move.l pkey_shift,a0 ; ^shifted key table
move.b (a0,d1),d5 ; get shifted code
move.l pkey_caps,a0 ; ^CapsLock key table
move.b (a0,d1),d6 ; get CapsLock code
bsr nk_ascmatch ; try to find ASCII code
beq.s .conv ; found ->
move.b #$1f,d2 ; maybe modified by Control key...
and.b d2,d4 ; change ASCII code accordingly
and.b d2,d5
and.b d2,d6
bsr nk_ascmatch ; and try again
bne.s .notfnd ; no match ->
.setctrl: or.l #(NKFf_FUNC|NKFf_CTRL)<<16,d0 ; Control was pressed
bra.s .conv ; ->
.notfnd: move.l pkey_unshift,a0 ; not found: restore all three
move.b (a0,d1),d2 ; ASCII codes
move.l pkey_shift,a0
move.b (a0,d1),d5
move.l pkey_caps,a0
move.b (a0,d1),d6
bsr.s .translate ; translate unshifted code
move.b d2,d4 ; use translated code
move.b d5,d2 ; translate shifted code
bsr.s .translate
move.b d2,d5 ; use translated code
move.b d6,d2 ; translate shifted code
bsr.s .translate
move.b d2,d6 ; use translated code
bsr nk_ascmatch ; last try to locate ASCII code
beq.s .setctrl ; found ->
tst.b d0 ; not found: ASCII code is 0?
bne.s .conv ; no ->
btst.l #NKFb_CTRL+16,d0 ; Control key flag already set?
bne.s .conv ; yes ->
; no: must be Alternate
or.l #(NKFf_FUNC|NKFf_ALT)<<16,d0
*------------- do conversion to normalized format
.conv: bsr nkc_tconv ; do TOS key code conversion
movem.l (sp)+,d4-d7 ; restore registers
tst d0 ; set CCR
rts ; bye
* This small sub function changes the ASCII code in D2.B due to the
* ASCII code translation table asc_trans. The result is returned in D2.B,
* registers D7 and A0 are corrupted.
.translate: lea asc_trans,a0 ; ^translation table
.transloop: move (a0)+,d7 ; get both codes
beq.s .ret ; end of table? ->
cmp.b d2,d7 ; found?
bne.s .transloop ; no ->
lsr #8,d7 ; yes: get translated code
move.b d7,d2 ; and use it
.ret: rts ; bye
*START
****************************************************************************
*
* nkc_n2tos: convert normalized key codes back to TOS format
* # G R
*
* C prototype: long nkc_n2tos(int nkcode);
*---------------------------------------------------------------------------
* In some cases you might have to have key codes in the original TOS format
* again, as returned by the GEMDOS functions Cconin(), Crawcin() or the BIOS
* function Bconin(). Use nkc_n2tos() to convert them. For a detailed
* description of the returned format consult the header of the function
* nkc_tconv().
*
* In: D0.W key code in normalized format
*
* Out: D0.L key code in TOS format:
* bits 24...31: shift key flags
* bits 23...16: scan code
* bits 08...15: reserved (0)
* bits 00...07: ASCII code
* CCR set according content of D0.L
*
* Reg: D:01234567 A:01234567 CCR
* U**..... **...... =D0.L
*
****************************************************************************
*END
nkc_n2tos: move d0,d1 ; normalized key code
and #NKFf_FUNC|NKFf_ALT|NKFf_CTRL,d1 ; isolate flags
cmp #NKFf_FUNC,d1 ; only function flag set?
bne.s .ktab0 ; no ->
cmp.b #$20,d0 ; ASCII code >= $20?
blo.s .ktab0 ; no ->
*------------- macro key
move d0,d1 ; keep normalized key code
and.l #NKFf_CAPS|NKFf_SHIFT,d0 ; isolate usable flags
btst.l #NKFb_NUM,d1 ; numeric keypad flag set?
beq.s .mackey ; no ->
or #NKFf_ALT|NKFf_CTRL,d0 ; yes: set Alternate + Control
.mackey: or.b #$ff,d0 ; scan code always $ff
swap d0 ; flags and scan code in upper word
move.b d1,d0 ; ASCII code
bra .exit ; ->
*------------- select system key table to use
.ktab0: move d0,d1 ; normalized key code
and #NKFf_SHIFT,d1 ; isolate bits for shift keys
beq.s .ktab1 ; shift key pressed? no->
lea n_to_scan_s,a1 ; ^default translation table
move.l pkey_shift,a0 ; yes: use shift table
bra.s .ktab3 ; ->
.ktab1: lea n_to_scan_u,a1 ; ^unshifted translation table
btst.l #NKFb_CAPS,d0 ; CapsLock?
beq.s .ktab2 ; no->
move.l pkey_caps,a0 ; yes: use CapsLock table
bra.s .ktab3 ; ->
.ktab2: move.l pkey_unshift,a0 ; use unshifted table
*------------- handling for ASCII codes >= 32
.ktab3: cmp.b #32,d0 ; ASCII code < 32?
blo.s .lowascii ; yes ->
bsr nk_findscan ; find scan code
bne.s .found ; found ->
btst.l #NKFb_FUNC,d0 ; function flag set?
beq.s .notfound ; no ->
move.l a0,d1 ; save a0
lea tolower,a0 ; ^upper->lower case table
moveq.l #0,d2 ; clear for word operation
move.b d0,d2 ; ASCII code
move.b (a0,d2),d0 ; get lowercased ASCII code
move.l d1,a0 ; restore a0
bsr nk_findscan ; try to find scan code again
bne.s .found ; found ->
*------------- unknown source: treat key code as it was entered using the
* TOS 3.06 direct ASCII input
.notfound: moveq.l #0,d1 ; not found: clear for word op.
move.b d0,d1 ; unchanged ASCII code
and #$1f00,d0 ; keep shift flags only
swap d0 ; -> high word (scan code = 0)
move d1,d0 ; low word: ASCII code
bra .exit ; ->
*------------- handling for ASCII codes < 32
.lowascii: btst.l #NKFb_FUNC,d0 ; function key?
bne.s .func ; yes ->
and #$10ff,d0 ; clear all flags except CapsLock
bra.s .notfound ; ->
.func: moveq.l #0,d1 ; clear for word operation
move.b d0,d1 ; ASCII code (0...$1f)
move d1,d2 ; copy
move.b (a1,d1),d1 ; get scan code
bne.s .getascii ; valid? ->
moveq #0,d0 ; invalid key code!! return 0
bra .exit ; ->
.getascii: lea n_to_scan_u,a1 ; ^unshifted translation table
move.b (a1,d2),d2 ; get scan code from unshifted tab.
move.b (a0,d2),d0 ; get ASCII from system's table
* register contents:
*
* d0.b ASCII code
* d1.b scan code
* d0.hb NKCC flags
*
.found: move d0,d2 ; flags and ASCII code
and #$1f00,d0 ; isolate shift flags
move.b d1,d0 ; merge with scan code
swap d0 ; -> high byte
clr d0 ; erase low word
move.b d2,d0 ; restore ASCII code
*------------- handling for Control key flag
btst.l #NKFb_CTRL,d2 ; control key flag set?
beq.s .alternate ; no ->
cmp.b #$4b,d1 ; scan code = "cursor left"?
bne.s .scanchk2 ; no ->
add.l #$280000,d0 ; change scan code to $73
clr.b d0 ; erase ASCII code
bra.s .exit ; ->
.scanchk2: cmp.b #$4d,d1 ; scan code = "cursor right"?
bne.s .scanchk3 ; no ->
add.l #$270000,d0 ; change scan code to $74
clr.b d0 ; erase ASCII code
bra.s .exit ; ->
.scanchk3: cmp.b #$47,d1 ; scan code = "ClrHome"?
bne.s .ascchk ; no ->
add.l #$300000,d0 ; change scan code to $77
; keep ASCII code in this case! What a mess...
bra.s .exit ; ->
.ascchk: lea asc_trans,a0 ; ^ASCII translation table
.ascloop: move (a0)+,d1 ; get next entry
beq.s .noctrlasc ; end of table ->
cmp.b d0,d1 ; ASCII code found?
bne.s .ascloop ; no -> continue search
lsr #8,d1 ; yes: get translated code
move.b d1,d0 ; use it
bra.s .exit ; ->
.noctrlasc: and.b #$1f,d0 ; mask off upper 3 bits
bra.s .exit ; ->
*------------- handling for Alternate key flag
.alternate: btst.l #NKFb_ALT,d2 ; alternate key flag set?
beq.s .exit ; no ->
cmp.b #2,d1 ; top row on main keyboard?
blo.s .alphachk ; no ->
cmp.b #$d,d1
bhi.s .alphachk ; no ->
add.l #$760000,d0 ; yes: change scan code
clr.b d0 ; and erase ASCII code
bra.s .exit ; ->
.alphachk: cmp.b #'A',d0 ; alpha-characters?
blo.s .exit ; no ->
cmp.b #'z',d0
bhi.s .exit ; no ->
cmp.b #'Z',d0
bls.s .ascii0 ; yes ->
cmp.b #'a',d0
blo.s .exit ; no ->
.ascii0: clr.b d0 ; alpha-character: clear ASCII code
.exit: tst.l d0 ; set CCR
rts ; bye
*START
****************************************************************************
*
* nkc_n2gem: convert normalized key codes back to GEM format
* # G R
*
* C prototype: int nkc_n2gem(int nkcode);
*---------------------------------------------------------------------------
* Similar to nkc_n2tos(), this function converts normalized key codes back
* to the operating system's format. The result is a key code as returned
* by the AES functions evnt_keybd() respectively evnt_multi().
*
* In: D0.W key code in normalized format
*
* Out: D0.W key code in GEM format:
* bits 08...15: scan code
* bits 00...07: ASCII code
* CCR set according content of D0.W
*
* Reg: D:01234567 A:01234567 CCR
* U**..... **...... =D0.W
*
****************************************************************************
*END
nkc_n2gem: bsr nkc_n2tos ; convert
moveq.l #0,d1 ; clear for word operation
move.b d0,d1 ; ASCII code
ror.l #8,d0 ; scan code now in high byte
move.b d1,d0 ; put ASCII into low byte
tst d0 ; set CCR
rts ; bye
*START
****************************************************************************
*
* nkc_kstate: return state of Shift/Control/Alternate/CapsLock in
* normalized format
* # G R
*
* C prototype: int nkc_kstate(void);
*---------------------------------------------------------------------------
* This is a very *FAST* function which returns the state of the Shift/
* Control/Alternate and CapsLock keys in normalized format.
*
* In: -
*
* Out: D0.W normalized key flags:
* 0 1
* NKF?_CAPS no CapsLock CapsLock
* NKF?_ALT no Alternate Alternate pressed
* NKF?_CTRL no Control Control pressed
* NKF?_LSH no left Shift key left Shift pressed
* NKF?_RSH no right Shift key right Shift pressed
*
* CCR set according content of D0.W
*
* Reg: D:01234567 A:01234567 CCR
* w**..... **...... =D0.W
*
****************************************************************************
*END
nkc_kstate: move.l pshift,a0 ; ^shift state variable
move.b (a0),d0 ; get its contents
and #$1f,d0 ; isolate valid bits
lsl #8,d0 ; make it NKC compatible
rts ; bye
*START
****************************************************************************
*
* nkc_timer: return current value of 200 Hz system clock
* # G R
*
* C prototype: unsigned long nkc_timer(void);
*---------------------------------------------------------------------------
* This is a very *FAST* function which returns the content of the 200 Hz
* system clock.
*
* In: -
*
* Out: D0.L current 200 HZ system clock value
*
* Reg: D:01234567 A:01234567 CCR
* w**..... **...... *
*
****************************************************************************
*END
nkc_timer: move.l sysclock,d0 ; just get value
rts ; bye bye
*START
****************************************************************************
*
* nkc_cmp: compare two key codes
* # G R
*
* C prototype: int nkc_cmp(int refkey,int kcode);
*---------------------------------------------------------------------------
* nkc_cmp() compares key codes. What for, you ask? A simple "if key_code1
* = key_code2" would also do it? No! This function follows some specific
* rules, which improve the flexibility of key code comparism.
*
* One of the key codes passed to nkc_cmp() is called the "reference key
* code". The other is the "test key code", which is got from nkc_conin()
* or nkc_multi(). Some flags of the reference code are treated a special
* way:
*
* NKF?_IGNUM (same as NKF?_RESVD)
* if set, the numeric keypad flag doesn't matter
*
* NKF?_CAPS (CapsLock)
* if set, the case of the ASCII code doesn't matter
*
* NKFf_SHIFT (both Shift key flags)
* if BOTH shift flags are set, 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.
*
* In: D0.W reference key code
* D1.W key code to test
*
* Out: D0.W flag: 1 = key codes match
* 0 = key codes don't match
* CCR set according content of D0.W
*
* Reg: D:01234567 A:01234567 CCR
* u**..... **...... =D0.W
*
****************************************************************************
*END
nkc_cmp: movem.l d3-d4,-(sp) ; save registers
move d0,d2 ; reference key code
eor d1,d2 ; XORed with test key code
beq .match ; identical: key codes match
bmi.s .nomatch ; func flag differs -> don't match
tst d0 ; "function" key?
bmi.s .rfunc ; yes ->
*------------- printable character
btst.l #NKFb_IGNUM,d0 ; ignore numeric keypad flag?
bne.s .chkn1 ; yes ->
btst.l #NKFb_NUM,d2 ; numeric key flags equal?
bne.s .nomatch ; no ->
.chkn1: lea toupper,a0 ; ^upper case conversion table
moveq.l #0,d3 ; clear for word operation
move.b d0,d3 ; ASCII code of ref key code
move.b (a0,d3),d4 ; get CapsLocked reference key code
cmp.b d0,d1 ; ASCII code equal?
beq.s .stest ; yes ->
btst.l #NKFb_CAPS,d0 ; no: ignore case?
beq.s .nomatch ; no -> codes don't match
move.b d1,d3 ; ASCII of test key code
cmp.b (a0,d3),d4 ; CapsLocked comparism
beq.s .match ; equal ->
bra.s .nomatch ; not equal ->
.stest: btst.l #NKFb_RESVD,d1 ; check Shift keys?
beq.s .match ; no ->
.stest2: move #NKFf_SHIFT,d4 ; Shift key flags
move d2,d3 ; XORed key codes
and d4,d3 ; shift flags equal?
beq.s .match ; yes ->
move d0,d3 ; reference key code
and d4,d3 ; isolate Shift flags
cmp d3,d4 ; both set?
bne.s .nomatch ; no -> codes don't match
move d1,d3 ; check if any pressed in test code
and d4,d3
bne.s .match ; yes ->
bra.s .nomatch ; no ->
*------------- "function key"
.rfunc: move d2,d3 ; XORed key codes
and #NKFf_ALT|NKFf_CTRL,d3 ; check Alternate and Control
bne.s .nomatch ; different -> codes don't match
cmp.b #32,d0 ; special key or character?
bhs.s .rchar ; character->
cmp.b d0,d1 ; special key codes equal?
beq.s .stest2 ; yes ->
bra.s .nomatch ; no ->
.rchar: btst.l #NKFb_IGNUM,d0 ; ignore numeric keypad flag?
bne.s .chkn2 ; yes ->
btst.l #NKFb_NUM,d2 ; numeric key flags equal?
bne.s .nomatch ; no ->
.chkn2: cmp.b d0,d1 ; ASCII codes equal?
beq.s .stest ; yes ->
.nomatch: movem.l (sp)+,d3-d4 ; restore registers
moveq.l #0,d0 ; codes don't match
rts ; bye
.match: movem.l (sp)+,d3-d4 ; restore registers
moveq.l #1,d0 ; codes match
rts ; bye
*START
****************************************************************************
*
* nkc_vlink: link function to XBRA vector list
* # G U
*
* C prototype: void nkc_vlink(long vector,int mode,void *pfnc);
*---------------------------------------------------------------------------
* This function can be used to change system vectors and let them point
* to own functions, using a standard method. The vector, which should be
* changed, is described by the contents of D0.L and D1.W. It can be
* either a standard vector number, e.g. 2 for the bus error exception
* vector, or the absolute address of the vector, e.g. $502 for the screen
* dump vector. The function to install must have the following header:
*
* .dc.b "XBRA" magic longword
* .dc.b "myID" four ASCII character ID of the function
* (NKCC uses "NKCC", for example)
* .dc.l 0 buffer for the old vector content
* function: ... start of the function code
*
* The function should end with:
*
* move.l function-4(pc),-(sp)
* rts
*
*
* Note: in NKXM_ADR mode, this function automatically switches (temporary)
* to Supervisor mode to prevent bus errors
*
*
* In: D0.L vector descriptor
* D1.W mode:
* NKXM_NUM = D0.L contains a vector number
* NKXM_ADR = D0.L contains a vector address
* A0.L ^function to install (NOT ^XBRA header!)
*
* Out: -4(A0.L).L old content of vector
*
* Reg: D:01234567 A:01234567 CCR
* ***..... **...... *
*
****************************************************************************
*END
nkc_vlink: tst d1 ; which mode?
bne.s .adr ; address ->
*------------- install function by vector number
move.l a2,-(sp) ; save register
move.l a0,-(sp) ; ^function
move d0,-(sp) ; vector number
move #5,-(sp) ; Setexc
moveq.l #-1,d1 ; ^function: don't change
move.l d1,-(sp) ; vector
move d0,-(sp) ; vector number
move #5,-(sp) ; Setexc
trap #13 ; BIOS: get old vector
addq #8,sp ; clean stack
move.l 4(sp),a0 ; ^function
move.l d0,-4(a0) ; save old vector
trap #13 ; BIOS: install routine
addq #8,sp ; clean stack
move.l (sp)+,a2 ; restore register
rts ; bye
*------------- install function by vector address
.adr: movem.l a2-a4,-(sp) ; save registers
move.l a0,a3 ; ^function
move.l d0,a4 ; ^vector
clr.l -(sp) ; use usp as ssp
move #$20,-(sp) ; Super
trap #1 ; GEMDOS
move.l d0,2(sp) ; save old sp
move #$20,(sp) ; Super opcode for next call
move.l (a4),-4(a3) ; save old vector content
move.l a3,(a4) ; install function
trap #1 ; GEMDOS (back to User mode)
addq #6,sp ; clean stack
movem.l (sp)+,a2-a4 ; restore registers
rts ; bye
*START
****************************************************************************
*
* nkc_vunlink: unlink function from XBRA vector list
* # G U
*
* C prototype: int nkc_vunlink(long vector,int mode,void *pfnc);
*---------------------------------------------------------------------------
* nkc_vunlink() removes a function which was installed using the XBRA method.
* For details see nkc_link(). If the XBRA list was corrupted, the function
* aborts with an error code. This happens, when a non-XBRA routine is
* installed on the same vector after the nkc_vlink() call of the function
* to remove.
*
* Note: the function automatically switches (temporary) to Supervisor mode
* to prevent bus errors
*
* In: D0.L vector descriptor
* D1.W mode:
* NKXM_NUM = D0.L contains a vector number
* NKXM_ADR = D0.L contains a vector address
* A0.L ^function to remove (NOT ^XBRA header!)
*
* Out: D0.W status:
* 0 = OK
* -1 = can't remove (XBRA list corrupted)
* CCR set according content of D0.W
*
* Reg: D:01234567 A:01234567 CCR
* U**..... **...... =D0.W
*
****************************************************************************
*END
nkc_vunlink: movem.l d6-d7/a2/a6,-(sp) ; save registers
move.l d0,d7 ; save vector descriptor
move.l a0,a6 ; save function address
move d1,d6 ; save mode
bne.s .adr ; address mode ->
*------------- check vector content by number
moveq.l #-1,d0 ; get current vector
move.l d0,-(sp)
move d7,-(sp) ; vector number
move #5,-(sp) ; Setexc
trap #13 ; BIOS
addq #8,sp ; clean stack
cmp.l d0,a6 ; function still on top?
bne.s .search ; no ->
.restore: move.l -4(a6),-(sp) ; restore old vector
move d7,-(sp) ; vector number
move #5,-(sp) ; Setexc
trap #13 ; BIOS
addq #8,sp ; clean stack
bra.s .okstat ; exit
*------------- check vector content by address
.adr: clr.l -(sp) ; use usp as ssp
move #$20,-(sp) ; Super
trap #1 ; GEMDOS
move.l d0,2(sp) ; save old sp
move #$20,(sp) ; Super opcode for next call
move.l d7,a0 ; vector address
move.l (a0),d0 ; vector content
cmp.l d0,a6 ; function still on top?
bne.s .search ; no ->
move.l -4(a6),(a0) ; yes: remove it
bra.s .okstat ; exit
*------------- somebody installed a handler (hope he used XBRA ...)
.search: move.l d0,a0 ; ^current handler
move.l #'XBRA',d0 ; XBRA ID
.find_hnd: cmp.l -12(a0),d0 ; XBRA ID before routine?
bne.s .error ; no!!! can't remove function!!
move.l -4(a0),a1 ; ^next entry in XBRA list
cmp.l a1,a6 ; next entry in list our function?
beq.s .found ; yes ->
move.l a1,a0 ; no
bra.s .find_hnd ; continue search
.found: move.l -4(a6),-4(a0) ; yes: remove function
.okstat: moveq.l #0,d7 ; no error
bra.s .exit
.error: moveq.l #-1,d7 ; error! can't unlink function!
.exit: tst d6 ; address mode?
beq.s .exit2 ; no ->
trap #1 ; yes: switch to user mode first
addq #6,sp ; with a GEMDOS Super() call
.exit2: move d7,d0 ; status code
movem.l (sp)+,d6-d7/a2/a6 ; restore registers
rts ; bye
*START
****************************************************************************
*
* nkc_toupper: convert character to upper case
* # G
*
* C prototype: unsigned char nkc_toupper(unsigned char chr);
*---------------------------------------------------------------------------
* A character is converted to upper case. Examples:
*
* 'a' -> 'A' (converted)
* '/' -> '/' (unchanged; there's no upper case version for this)
* 'A' -> 'A' (unchanged; already converted)
*
*
* In: D0.B any character
*
* Out: D0.B character converted to upper case
*
* Reg: D:01234567 A:01234567 CCR
* U**..... **...... *
*
****************************************************************************
*END
nkc_toupper: lea toupper,a0 ; ^upper case translation table
and #$ff,d0 ; high byte = 0 for word operation
move.b (a0,d0),d0 ; convert
rts ; bye
*START
****************************************************************************
*
* nkc_tolower: convert character to lower case
* # G
*
* C prototype: unsigned char nkc_tolower(unsigned char chr);
*---------------------------------------------------------------------------
* The counterpart of nkc_toupper(). A character is converted to lower case.
*
* In: D0.B any character
*
* Out: D0.B character converted to lower case
*
* Reg: D:01234567 A:01234567 CCR
* U**..... **...... *
*
****************************************************************************
*END
nkc_tolower: lea tolower,a0 ; ^lower case translation table
and #$ff,d0 ; high byte = 0 for word operation
move.b (a0,d0),d0 ; convert
rts ; bye
****************************************************************************
* LOCAL DATA SECTION *
****************************************************************************
.data
* exception scan code table for cursor block keys
*
* first entry.B: NKCC key code
* second entry.B: scan code returned by TOS
*
* the table is terminated with both entries -1
xscantab: .dc.b NK_UP , $48 ; cursor up
.dc.b NK_DOWN , $50 ; cursor down
.dc.b NK_LEFT , $4b ; cursor left
.dc.b NK_LEFT , $73 ; Control cursor left
.dc.b NK_RIGHT , $4d ; cursor right
.dc.b NK_RIGHT , $74 ; Control cursor right
.dc.b NK_M_PGUP , $49 ; Mac: page up
.dc.b NK_M_PGDOWN , $51 ; Mac: page down
.dc.b NK_M_END , $4f ; Mac: end
.dc.b NK_INS , $52 ; Insert
.dc.b NK_CLRHOME , $47 ; ClrHome
.dc.b NK_CLRHOME , $77 ; Control ClrHome
.dc.b NK_HELP , $62 ; Help
.dc.b NK_UNDO , $61 ; Undo
.dc.b NK_M_F11 , $45 ; Mac: F11
.dc.b NK_M_F12 , $46 ; Mac: F12
.dc.b NK_M_F14 , $37 ; Mac: F14
.dc.w -1
* deadkey table
*
* first entry.B: deadkey option mask (NKSf_D_...), 16 bits shifted down
* second entry.W: ASCII code of deadkey
* third entry.L: ^deadkey match table
*
* the table is terminated with an option mask of 0
deadtab: .dc.w NKSf_D_CIRCUM >> 16
.dc.b 0,'^'
.dc.l d_circum
.dc.w NKSf_D_TILDE >> 16
.dc.b 0,'~'
.dc.l d_tilde
.dc.w NKSf_D_AGUI >> 16
.dc.w $27
.dc.l d_agui
.dc.w NKSf_D_GRAVE >> 16
.dc.b 0,'`'
.dc.l d_grave
.dc.w NKSf_D_UMLAUT >> 16
.dc.b 0,'╣'
.dc.l d_umlaut
.dc.w NKSf_D_QUOTE >> 16
.dc.w $22
.dc.l d_umlaut
.dc.w NKSf_D_SMOERE >> 16
.dc.b 0,'°'
.dc.l d_smoere
.dc.w NKSf_D_CEDIL >> 16
.dc.b 0,','
.dc.l d_cedil
.dc.w NKSf_D_SLASH >> 16
.dc.b 0,'/'
.dc.l d_slash
.dc.w 0
* deadkey match tables
*
* first entry.B: ASCII code generated by pressing deadkey and key code
* second entry.B: key code (of the key which must be pressed directly after
* the deadkey)
*
* the tables are terminated with both entries 0
d_circum: .dc.b '^','^'
.dc.b 'â','a'
.dc.b 'ê','e'
.dc.b 'î','i'
.dc.b 'ô','o'
.dc.b 'û','u'
.dc.w 0
d_tilde: .dc.b '~','~'
.dc.b 'ñ','n'
.dc.b 'Ñ','N'
.dc.b '░','a'
.dc.b '▒','o'
.dc.b '╖','A'
.dc.b '╕','O'
.dc.w 0
d_agui: .dc.b $27,$27 ; ' characters
.dc.b 'é','e'
.dc.b 'É','E'
.dc.b 'á','a'
.dc.b 'í','i'
.dc.b 'ó','o'
.dc.b 'ú','u'
.dc.w 0
d_grave: .dc.b '`','`'
.dc.b 'à','a'
.dc.b 'è','e'
.dc.b 'ì','i'
.dc.b 'ò','o'
.dc.b 'ù','u'
.dc.b '╢','A'
.dc.w 0
d_umlaut: .dc.b '╣','╣'
.dc.b $22,$22 ; " characters
.dc.b 'ä','a'
.dc.b 'ë','e'
.dc.b 'ï','i'
.dc.b 'ö','o'
.dc.b 'ü','u'
.dc.b 'ÿ','y'
.dc.b 'Ä','A'
.dc.b 'Ö','O'
.dc.b 'Ü','U'
.dc.w 0
d_smoere: .dc.b '°','°'
.dc.b 'å','a'
.dc.b 'Å','A'
.dc.w 0
d_cedil: .dc.b ',',','
.dc.b 'ç','c'
.dc.b 'Ç','C'
.dc.w 0
d_slash: .dc.b '/','/'
.dc.b '│','o'
.dc.b '▓','O'
.dc.b '½','2'
.dc.b '¼','4'
.dc.w 0
.if NKCGEM=1
* AES parameter block
aespb: .dc.l nkc_contrl
.dc.l 0 ; set by nkc_init()
.dc.l nkc_intin
.dc.l nkc_intout
.dc.l nkc_adrin
.dc.l nkc_adrout
* VDI parameter block
vdipb: .dc.l nkc_contrl
.dc.l nkc_intin
.dc.l nkc_ptsin
.dc.l nkc_intout
.dc.l nkc_ptsout
* double click time table (values given in 1/200 s)
timetab: .dc.l 85 ; 0.425 s
.dc.l 63 ; 0.315 s
.dc.l 49 ; 0.245 s
.dc.l 42 ; 0.210 s
.dc.l 30 ; 0.150 s
.endif ; .if NKCGEM=1
* lower case to upper case conversion table
* (array of 256 unsigned bytes)
toupper:
.dc.b $00,$01,$02,$03,$04,$05,$06,$07
.dc.b $08,$09,$0a,$0b,$0c,$0d,$0e,$0f
.dc.b $10,$11,$12,$13,$14,$15,$16,$17
.dc.b $18,$19,$1a,$1b,$1c,$1d,$1e,$1f
.dc.b " !",$22,"#$%&",$27,"()*+,-./0123456789:;<=>?"
.dc.b "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[",$5c,"]^_"
.dc.b "`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~"
.dc.b "ÇÜÉâÄ╢ÅÇêëèïîìÄÅÉÆÆôÖòûùÿÖÜ¢£¥₧ƒ"
.dc.b "áíóúÑѪº¿⌐¬½¼¡«»╖╕▓▓╡╡╢╖╕╣║╗╝╜╛┐"
.dc.b "└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀"
.dc.b "αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ "
* upper case to lower case conversion table
* (array of 256 unsigned bytes)
tolower:
.dc.b $00,$01,$02,$03,$04,$05,$06,$07
.dc.b $08,$09,$0a,$0b,$0c,$0d,$0e,$0f
.dc.b $10,$11,$12,$13,$14,$15,$16,$17
.dc.b $18,$19,$1a,$1b,$1c,$1d,$1e,$1f
.dc.b " !",$22,"#$%&",$27,"()*+,-./0123456789:;<=>?"
.dc.b "@abcdefghijklmnopqrstuvwxyz[",$5c,"]^_"
.dc.b "`abcdefghijklmnopqrstuvwxyz{|}~"
.dc.b "çüéâäàåçêëèïîìäåéææôöòûùÿöü¢£¥₧ƒ"
.dc.b "áíóúññªº¿⌐¬½¼¡«»░▒││┤┤à░▒╣║╗╝╜╛┐"
.dc.b "└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀"
.dc.b "αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ "
* note for both tables:
*
* $22 = " character
* $27 = ' character
* $5c = \ character
* scan code translation table
*
* first entry.W : shift flags (NKFf_CTRL/SHIFT/ALT/FUNC), 8 bits shifted down
* second entry.B: real scan code (index into key table)
* third entry.B : simulated scan code (set by OS when the flags specified
* above are set)
*
* The table is terminated with all entries 0.
scan_trans: .dc.w NKFf_SHIFT>>8 ; Shift F1
.dc.b $3b,$54
.dc.w NKFf_SHIFT>>8 ; Shift F2
.dc.b $3c,$55
.dc.w NKFf_SHIFT>>8 ; Shift F3
.dc.b $3d,$56
.dc.w NKFf_SHIFT>>8 ; Shift F4
.dc.b $3e,$57
.dc.w NKFf_SHIFT>>8 ; Shift F5
.dc.b $3f,$58
.dc.w NKFf_SHIFT>>8 ; Shift F6
.dc.b $40,$59
.dc.w NKFf_SHIFT>>8 ; Shift F7
.dc.b $41,$5a
.dc.w NKFf_SHIFT>>8 ; Shift F8
.dc.b $42,$5b
.dc.w NKFf_SHIFT>>8 ; Shift F9
.dc.b $43,$5c
.dc.w NKFf_SHIFT>>8 ; Shift F10
.dc.b $44,$5d
.dc.w (NKFf_FUNC|NKFf_CTRL)>>8 ; Control cursor left
.dc.b $4b,$73
.dc.w (NKFf_FUNC|NKFf_CTRL)>>8 ; Control cursor right
.dc.b $4d,$74
.dc.w (NKFf_FUNC|NKFf_CTRL)>>8 ; Control ClrHome
.dc.b $47,$77
.dc.w (NKFf_FUNC|NKFf_ALT)>>8 ; Alternate top row #1
.dc.b $02,$78
.dc.w (NKFf_FUNC|NKFf_ALT)>>8 ; Alternate top row #2
.dc.b $03,$79
.dc.w (NKFf_FUNC|NKFf_ALT)>>8 ; Alternate top row #3
.dc.b $04,$7a
.dc.w (NKFf_FUNC|NKFf_ALT)>>8 ; Alternate top row #4
.dc.b $05,$7b
.dc.w (NKFf_FUNC|NKFf_ALT)>>8 ; Alternate top row #5
.dc.b $06,$7c
.dc.w (NKFf_FUNC|NKFf_ALT)>>8 ; Alternate top row #6
.dc.b $07,$7d
.dc.w (NKFf_FUNC|NKFf_ALT)>>8 ; Alternate top row #7
.dc.b $08,$7e
.dc.w (NKFf_FUNC|NKFf_ALT)>>8 ; Alternate top row #8
.dc.b $09,$7f
.dc.w (NKFf_FUNC|NKFf_ALT)>>8 ; Alternate top row #9
.dc.b $0a,$80
.dc.w (NKFf_FUNC|NKFf_ALT)>>8 ; Alternate top row #10
.dc.b $0b,$81
.dc.w (NKFf_FUNC|NKFf_ALT)>>8 ; Alternate top row #11
.dc.b $0c,$82
.dc.w (NKFf_FUNC|NKFf_ALT)>>8 ; Alternate top row #12
.dc.b $0d,$83
.dc.l 0 ; terminator
* ASCII code translation table for Control key
*
* first entry.B: modified ASCII code returned by TOS
* second entry.B: original ASCII code as stored in key table
*
* The table is terminated with both entries 0
asc_trans: .dc.b 0,'2' ; Control '2' becomes ASCII 0
.dc.b $1e,'6' ; Control '6' becomes ASCII $1e
.dc.b $1f,'-' ; Control '-' becomes ASCII $1f
.dc.b $a,$d ; Control Return/Enter: $d -> $a
.dc.w 0 ; terminator
* normalized key code -> scan code translation table
* for unshifted key codes
* indexed by function code (NK_...)
n_to_scan_u: .dc.b $00 ; invalid key code
.dc.b $48 ; cursor up
.dc.b $50 ; cursor down
.dc.b $4d ; cursor right
.dc.b $4b ; cursor left
.dc.b $49 ; Mac: page up
.dc.b $51 ; Mac: page down
.dc.b $4f ; Mac: end
.dc.b $0e ; Backspace
.dc.b $0f ; Tab
.dc.b $72 ; Enter
.dc.b $52 ; Insert
.dc.b $47 ; ClrHome
.dc.b $1c ; Return
.dc.b $62 ; Help
.dc.b $61 ; Undo
.dc.b $3b ; function key #1
.dc.b $3c ; function key #2
.dc.b $3d ; function key #3
.dc.b $3e ; function key #4
.dc.b $3f ; function key #5
.dc.b $40 ; function key #6
.dc.b $41 ; function key #7
.dc.b $42 ; function key #8
.dc.b $43 ; function key #9
.dc.b $44 ; function key #10
.dc.b $45 ; Mac: F11
.dc.b $01 ; Esc
.dc.b $46 ; Mac: F12
.dc.b $37 ; Mac: F14
.dc.b $00 ; reserved!
.dc.b $53 ; Delete
* normalized key code -> scan code translation table
* for shifted key codes
* indexed by function code (NK_...)
n_to_scan_s: .dc.b $00 ; invalid key code
.dc.b $48 ; cursor up
.dc.b $50 ; cursor down
.dc.b $4d ; cursor right
.dc.b $4b ; cursor left
.dc.b $49 ; Mac: page up
.dc.b $51 ; Mac: page down
.dc.b $4f ; Mac: end
.dc.b $0e ; Backspace
.dc.b $0f ; Tab
.dc.b $72 ; Enter
.dc.b $52 ; Insert
.dc.b $47 ; ClrHome
.dc.b $1c ; Return
.dc.b $62 ; Help
.dc.b $61 ; Undo
.dc.b $54 ; function key #1
.dc.b $55 ; function key #2
.dc.b $56 ; function key #3
.dc.b $57 ; function key #4
.dc.b $58 ; function key #5
.dc.b $59 ; function key #6
.dc.b $5a ; function key #7
.dc.b $5b ; function key #8
.dc.b $5c ; function key #9
.dc.b $5d ; function key #10
.dc.b $45 ; Mac: F11
.dc.b $01 ; Esc
.dc.b $46 ; Mac: F12
.dc.b $37 ; Mac: F14
.dc.b $00 ; reserved!
.dc.b $53 ; Delete
****************************************************************************
* LOCAL BSS SECTION *
****************************************************************************
.bss
* key code handler
pkey_unshift: .ds.l 1 ; ^unshifted key table
pkey_shift: .ds.l 1 ; ^shifted key table
pkey_caps: .ds.l 1 ; ^CapsLock table
pshift: .ds.l 1 ; ^shift state system variable
sflags: .ds.l 1 ; special key flags
prvkey: .ds.w 1 ; previous key code
prvvalid: .ds.b 1 ; non-zero: prvkey is valid
.even
* button event handler
.if NKCGEM=1
bvar: .ds.b BI ; button event info block
tendtime: .ds.l 1 ; timer event end value
prvtime: .ds.l 1 ; previous timer event value
vdihnd: .ds.w 1 ; handle of VDI workstation
multibuf: .ds.w 16+2 ; buffer for evnt_multi parameters
buthnd: .ds.b 1 ; non-zero:button handler installed
.even
* other stuff
kbdiorec: .ds.l 1 ; ^keyboard Iorec structure
iohead: .ds.w 1 ; NKCC's head pointer
.endif ; .if NKCGEM=1
sysclock: .ds.l 1 ; copy of 200 Hz system clock
timerflag: .ds.b 1 ; non-zero:200 Hz timer installed
.even
*START
****************************************************************************
* GLOBAL BSS SECTION *
****************************************************************************
*END
.bss
*START
* GEM parameter arrays
* (needed if using nkc_amulti())
.if NKCGEM=1
nkc_contrl: .ds.w 32 ; control array
nkc_intin: .ds.w 32 ; integer input array
nkc_intout: .ds.w 32 ; integer output array
nkc_adrin: .ds.l 32 ; address input array
nkc_adrout: .ds.l 32 ; address output array
nkc_ptsin: .ds.l 32 ; pointers input array
nkc_ptsout: .ds.l 32 ; pointers output array
.endif ; .if NKCGEM=1
*END
*START
* End Of File
*END