;====================================================================== ; MSX 8255 PPI KEYBOARD COMPATIBLE DRIVER ; ; CREATED BY: DEAN NETHERTON ; KBD.ASM DRIVER USED AS TEMPLATE ; ;====================================================================== ; USAGE: ; THIS DRIVER CAN BE ACTIVED WITHIN THE TMS VIDEO DRIVER ; ADD THE OPTION TO YOUR BUILD CONFIGURATION TO ACTIVATE THE KEYBOARD ; DRIVER: ; MKYENABLE .SET TRUE ; ;====================================================================== ; ; TODO: ; IMPLEMENT MULTIBYTE SCAN CODES (ARROW KEYS, ETC) ; BACKSPACE DOES NOT AUTO-REPEAT ; AUTO DETECT PPI ; #IF (SYSTIM == TM_NONE) .ECHO "*** ERROR: MKY REQUIRES SYSTEM TIMER -- NONE CONFIGURED!!!\n" !!! ; FORCE AN ASSEMBLY ERROR #ENDIF ; ;====================================================================== ; DRIVER - CONSTANTS ;====================================================================== ; MKY_REGA .EQU $A8 MKY_REGB .EQU $A9 MKY_REGC .EQU $AA MKY_REGCMD .EQU $AB PPICMD_CLOW_IN .EQU 1 PPICMD_CLOW_OUT .EQU 0 PPICMD_B_IN .EQU 2 PPICMD_B_OUT .EQU 0 PPICMD_GB_MODE_0 .EQU 0 PPICMD_GB_MODE_1 .EQU 4 PPICMD_CHIGH_IN .EQU 8 PPICMD_CHIGH_OUT .EQU 0 PPICMD_A_IN .EQU 16 PPICMD_A_OUT .EQU 0 PPICMD_GA_MODE_0 .EQU 0 PPICMD_GA_MODE_1 .EQU 32 PPICMD_GA_MODE_2 .EQU 64 PPICMD_COMMAND .EQU 128 ; COUNT FOR PERIOD TO START REPEATING CHARACTERS KEY_REPEAT_INIT: .EQU 30 ; COUNT FOR PERIOD BETWEEN AUTO REPEATING CHARACTERS KEY_REPEAT_PERIOD: .EQU 3 ; COUNT FOR INTERRUPT HANDLER TO TRIGGER KEYBOARD SCANNER (EG: SCAN KEYBOARD ONLY EVERY 3RD INTERRUPT (3/60)) SCAN_INT_PERIOD: .EQU 3 ; NUMBER OF ROWS SUPPORTED BY THE KEYBOARD MATRIX_ROW_COUNT: .EQU 9 ; ASSEMBLER SEEMS TO HAVE WEIRD PROBLEM WITH "'" SINGLE_QUOTE .EQU 39 ; SPECIAL MADE UP VALUE TO MAP FOR CAPS LOCK CAPS_CODE: .EQU $D8 ; TIMING CONSTANTS ; MKY_WAITTO .EQU 0 ; 0 IS MAX WAIT (256) ; ; STATUS BITS (FOR MKY_STATUS) ; MKY_EXT .EQU 01H ; BIT 0, EXTENDED SCANCODE ACTIVE MKY_BREAK .EQU 02H ; BIT 1, THIS IS A KEY UP (BREAK) EVENT MKY_KEYRDY .EQU 80H ; BIT 7, INDICATES A DECODED KEYCODE IS READY ; MKY_DEFRPT .EQU $40 ; DEFAULT REPEAT RATE (.5 SEC DELAY, 30CPS) MKY_DEFSTATE .EQU KBD_NUMLCK ; DEFAULT STATE (NUM LOCK ON) ; --------------.----------------------- ; SCAN CODE TABL.ES S_A .EQU $1C S_B .EQU $32 S_C .EQU $21 S_D .EQU $23 S_E .EQU $24 S_F .EQU $2B S_G .EQU $34 S_H .EQU $33 S_I .EQU $43 S_J .EQU $3B S_K .EQU $42 S_L .EQU $4B S_M .EQU $3A S_N .EQU $31 S_O .EQU $44 S_P .EQU $4D S_Q .EQU $15 S_R .EQU $2D S_S .EQU $1B S_T .EQU $2C S_U .EQU $3C S_V .EQU $2A S_W .EQU $1D S_X .EQU $22 S_Y .EQU $35 S_Z .EQU $1A S_0 .EQU $45 S_1 .EQU $16 S_2 .EQU $1E S_3 .EQU $26 S_4 .EQU $25 S_5 .EQU $2E S_6 .EQU $36 S_7 .EQU $3D S_8 .EQU $3E S_9 .EQU $46 S_SEMICOLON .EQU $4C S_RBRACKET .EQU $5B S_LBRACKET .EQU $54 S_BSLASH .EQU $5D S_EQUALS .EQU $55 S_MINUS .EQU $4E S_SLASH .EQU $4A S_PERIOD .EQU $49 S_COMMA .EQU $41 S_TILDA .EQU $0E S_QUOTE .EQU $52 S_SHIFT .EQU $12 S_CTRL .EQU $14 S_CAPSLOCK .EQU $58 S_DEAD .EQU $00 S_GRAPH .EQU $00 S_CODE .EQU $00 ; perhaps can be mapped to RIGHT ALT S_F1 .EQU $05 S_F2 .EQU $06 S_F3 .EQU $04 S_F4 .EQU $0C S_F5 .EQU $03 S_ESC .EQU $76 S_TAB .EQU $0D S_STOP .EQU $00 ; MAKE -> E0 69, BREAK -> E0 F0 69 S_BACKSPACE .EQU $66 S_SELECT .EQU $00 S_RETURN .EQU $5A S_RIGHT .EQU $00 ; E0 74 --- E0 F0 74 S_DOWN .EQU $00 ; E0 72 --- E0 F0 72 S_UP .EQU $00 ; E0 75 --- E0 F0 75 S_LEFT .EQU $00 ; E0 6B --- E0 F0 6B S_DELETE .EQU $00 ; E0 71 --- E0 F0 71 S_INSERT .EQU $00 ; E0 70 --- E0 F0 70 S_HOME .EQU $00 ; E0 6C --- E0 F0 6C S_SPACE .EQU $29 SCANCODE_TBL: .DB S_7, S_6, S_5, S_4, S_3, S_2, S_1, S_0 ; 00 .DB S_SEMICOLON, S_RBRACKET, S_LBRACKET, S_BSLASH, S_EQUALS, S_MINUS, S_9, S_8 ; 01 .DB S_B, S_A, S_DEAD, S_SLASH, S_PERIOD, S_COMMA, S_TILDA, S_QUOTE ; 02 .DB S_J, S_I, S_H, S_G, S_F, S_E, S_D, S_C ; 03 .DB S_R, S_Q, S_P, S_O, S_N, S_M, S_L, S_K ; 04 .DB S_Z, S_Y, S_X, S_W, S_V, S_U, S_T, S_S ; 05 .DB S_F3, S_F2, S_F1, S_CODE, S_CAPSLOCK, S_GRAPH, S_CTRL, S_SHIFT ; 06 .DB S_RETURN, S_SELECT, S_BACKSPACE, S_STOP, S_TAB, S_ESC, S_F5, S_F4 ; 07 .DB S_RIGHT, S_DOWN, S_UP, S_LEFT, S_DELETE, S_INSERT, S_HOME, S_SPACE ; 08 DEVECHO "MKY: IO=" DEVECHO MKY_REGA DEVECHO "\n" ;__________________________________________________________________________________________________ ; KEYBOARD INITIALIZATION ;__________________________________________________________________________________________________ ; MKY_INIT: CALL NEWLINE ; FORMATTING PRTS("MSXKYB: IO=0x$") LD A, MKY_REGA CALL PRTHEXBYTE CALL PC_SPACE ; FORMATTING #IF (MKYKBLOUT == KBD_US) PRTS("US LAYOUT$") #ELSE #IF (MKYKBLOUT == KBD_DE) PRTS("GERMAN LAYOUT$") #ELSE FAIL !!! UKNOWN KEYBOARD TYPE #ENDIF #ENDIF ; MSX_NOTE: THE MSX BIOS SETS THE PPI CONFIGURATION AT BOOT AND IT SHOULD NOT BE CHANGED ; THE 8255 CONFIGURATION BELOW IS NOT COMPATIBLE WITH THE MSX STANDARD #IF (PLATFORM != PLT_MSX) ; CONFIGURE 8255 PPI PORTS ; A - INPUT (NOT USED) ; B - INPUT (COLUMN LINES) ; C - OUTPUT (ROW LINE SELECTION) LD A, PPICMD_COMMAND | PPICMD_GA_MODE_0 | PPICMD_GB_MODE_0 | PPICMD_A_IN | PPICMD_B_IN | PPICMD_CLOW_OUT | PPICMD_CHIGH_OUT EZ80_IO OUT (MKY_REGCMD), A LD A, 64 ; CAPS OFF EZ80_IO OUT (MKY_REGC), A #ENDIF ; INSTALL INTERRUPT HANDLER LD HL, (VEC_TICK+1) LD (VEC_TICK_MKY+1), HL LD HL, MKY_INT LD (VEC_TICK+1), HL RET ; ;__________________________________________________________________________________________________ ; KEYBOARD FLUSH ;__________________________________________________________________________________________________ ; MKY_FLUSH: XOR A ; A = 0 LD (MKY_STATUS),A ; CLEAR STATUS RET ; ;__________________________________________________________________________________________________ ; KEYBOARD STATUS ;__________________________________________________________________________________________________ ; MKY_STAT: CALL MKY_SCAN ; SCAN AND SET SCANCODE FOR DETECTED KEY EVENT CALL MKY_DECODE ; DECODE THE SCANCODE INTO A KEYCODE JP Z, CIO_IDLE ; RET VIA IDLE PROCESSING IF NO KEY RET ; ;__________________________________________________________________________________________________ ; KEYBOARD READ ; ; RETURNS ASCII VALUE IN E. SEE END OF FILE FOR VALUES RETURNED FOR SPECIAL KEYS ; LIKE PGUP, ARROWS, FUNCTION KEYS, ETC. ;__________________________________________________________________________________________________ ; MKY_READ: CALL MKY_STAT ; KEY READY? ; JR Z, MKY_READ ; NOT READY, KEEP TRYING LD A, (MKY_STATUS) ; GET STATUS AND $01 ; ISOLATE EXTENDED SCANCODE BIT RRCA ; ROTATE IT TO HIGH ORDER BIT LD E, A ; SAVE IT IN E FOR NOW LD A, (MKY_SCANCODE) ; GET SCANCODE OR E ; COMBINE WITH EXTENDED BIT LD C, A ; STORE IT IN C FOR RETURN LD A, (MKY_KEYCODE) ; GET KEYCODE LD E, A ; SAVE IT IN E LD A, (MKY_STATE) ; GET STATE FLAGS LD D, A ; SAVE THEM IN D XOR A ; SIGNAL SUCCESS LD (MKY_STATUS), A ; CLEAR STATUS TO INDICATE BYTE RECEIVED RET ; ;__________________________________________________________________________________________________ ; RETRIEVE THE NEXT SCAN BYTES AVAILABLE ; ; RETURNS ; ; SUCUESS/FAILURE IN A ; ; NUMBER OF BYTES RETURNED IN B (ZERO IF NO SCAN CODES AVAILABLE) ; ; SCAN CODE BYTES IN D, E, H, L, C ; WORK - IN - PROGRESS ;__________________________________________________________________________________________________ MKY_RDSCAN: LD A, (MKY_SCANBUFFLEN) CALL Z, MKY_GENSCODE LD A, (MKY_SCANBUFFLEN) LD B, A LD A, (MKY_SCANBUFF) LD D, A LD A, (MKY_SCANBUFF+1) LD E, A LD A, (MKY_SCANBUFF+2) LD H, A LD A, (MKY_SCANBUFF+3) LD L, A LD A, (MKY_SCANBUFF+4) LD C, A XOR A LD (MKY_SCANBUFFLEN), A RET MKY_SCAN: LD A, (MKY_SCANNED) ; NEED TO WAIT UNTIL A NEW SCAN HAS COMPLETED (MKY_INT) OR A RET Z DI ; CAPTURE THE LATEST KEYBOARD SCANNED STATE XOR A ; CLEAR SCANNED STATE LD (MKY_SCANNED), A LD DE, MKY_SCNKEY ; COPY NEWKEY TO SCNKEY LD HL, MKY_NEWKEY ; AND RESET NEWKEY TO $FF LD B, MATRIX_ROW_COUNT LD C, 255 MKY_SCAN_LP1: LD A, (HL) LD (DE), A LD (HL), C INC HL INC DE DJNZ MKY_SCAN_LP1 EI EX AF, AF' PUSH AF CALL MKY_GENSCODE CALL MKY_RPTGEN POP AF EX AF, AF' RET ; ;__________________________________________________________________________________________________ ; HARDWARE INTERFACE ; ; ; KEYBOARD INPUT STATUS ; A=0, Z SET FOR NOTHING PENDING, OTHERWISE DATA PENDING ; #define MKY_IST LD A, (MKY_SCANBUFFLEN) \ OR A ;__________________________________________________________________________________________________ ; ; GET A RAW DATA BYTE FROM KEYBOARD INTERFACE INTO A WITH TIMEOUT ; MKY_GETDATA: LD B, MKY_WAITTO ; SETUP TO LOOP MKY_GETDATA0: MKY_IST ; GET INPUT REGISTER STATUS JR NZ, MKY_GETDATA1 ; BYTE PENDING, GO GET IT CALL DELAY ; WAIT A BIT DJNZ MKY_GETDATA0 ; LOOP UNTIL COUNTER EXHAUSTED XOR A ; NO DATA, RETURN ZERO RET MKY_GETDATA1: CALL MKY_READBYT OR A ; SET FLAGS RET ;__________________________________________________________________________________________________ ; ; GET A RAW DATA BYTE FROM KEYBOARD INTERFACE INTO A WITH NOTIMEOUT ; MKY_GETDATAX: MKY_IST ; GET INPUT REGISTER STATUS RET Z ; NOTHING THERE, DONE JR MKY_GETDATA1 ; GO GET IT ;__________________________________________________________________________________________________ ; UPDATE KEYBOARD LEDS BASED ON CURRENT TOGGLE FLAGS ;__________________________________________________________________________________________________ ; MKY_SETLEDS: LD A,(MKY_STATE) ; LOAD THE STATE FLAGS AND KBD_CAPSLCK ; CHECK CAPS LOCK JR Z, MKY_LEDCAPSOFF ; ;__________________________________________________________________________________________________ ; ; TURN THE CAPS LED LIGHT ON ; MKY_LEDCAPSON: EZ80_IO IN A, (MKY_REGC) RES 6, A EZ80_IO OUT (MKY_REGC), A RET ; ;__________________________________________________________________________________________________ ; ; TURN THE CAPS LED LIGHT OFF ; MKY_LEDCAPSOFF: EZ80_IO IN A, (MKY_REGC) SET 6, A EZ80_IO OUT (MKY_REGC), A RET ;__________________________________________________________________________________________________ ; DECODING ENGINE ;__________________________________________________________________________________________________ MKY_DECODE: ; ; RUN THE DECODING ENGINE UNTIL EITHER: 1) NO MORE SCANCODES ARE AVAILABLE ; FROM THE KEYBOARD, OR 2) A DECODED KEY VALUE IS AVAILABLE ; ; RETURNS A=0 AND Z SET IF NO KEYCODE READY, OTHERWISE A DECODED KEY VALUE IS AVAILABLE. ; THE DECODED KEY VALUE AND KEY STATE IS STORED IN MKY_KEYCODE AND MKY_STATE. ; ; MKY_STATUS IS NOT CLEARED AT START. IT IS THE CALLER'S RESPONSIBILITY ; TO CLEAR MKY_STATUS WHEN IT HAS RETRIEVED A PENDING VALUE. IF DECODE IS CALLED ; WITH A KEYCODE STILL PENDING, IT WILL JUST RETURN WITHOUT DOING ANYTHING. ; ; Step 0: Check keycode buffer ; if status[keyrdy] ; return ; ; Step 1: Get scancode ; if no scancode ready ; return ; read scancode ; ; Step 2: Detect and handle special keycodes ; if scancode == $AA ; *** handle hot insert somehow *** ; ; Step 3: Detect and handle scancode prefixes ; if scancode == $E0 ; set status[extended] ; goto Step 1 ; ; if scancode == $E1 ; *** handle pause key somehow *** ; ; Step 4: Detect and flag break event ; *** scancode set #1 variation *** ; set status[break] = high bit of scancode ; clear high order bit ; continue to Step 5 ; *** scancode set #2 variation *** ; if scancode == $F0 ; set status[break] ; goto Step 1 ; ; Step 5: Map scancode to keycode ; if status[extended] ; apply extended-map[scancode] -> keycode ; else if state[shifted] ; apply shifted-map[scancode] -> keycode ; else ; apply normal-map[scancode] -> keycode ; ; Step 6: Handle modifier keys ; if keycode is modifier (shift, ctrl, alt, win) ; set (l/r)state[] = not status[break] ; clear modifier bits in state ; set state = (lstate OR rstate OR state) ; goto New Key ; ; Step 7: Complete procesing of key break events ; if status[break] ; goto New Key ; ; Step 8: Handle toggle keys ; if keycode is toggle (capslock, numlock, scrolllock) ; invert (XOR) state[] ; update keyboard LED's ; goto New Key ; ; Step 9: Adjust keycode for control modifier ; if state[ctrl] ; if keycode is 'a'-'z' ; subtract 20 (clear bit 5) from keycode ; if keycode is '@'-'_' ; subtract 40 (clear bit 6) from keycode ; ; Step 10: Adjust keycode for caps lock ; if state[capslock] ; if keycode is 'a'-'z' OR 'A'-'Z' ; toggle (XOR) bit 5 of keycode ; ; Step 11: Handle num pad keys ; REMOVED ; ; Step 12: Detect unknown/invalid keycodes ; if keycode == $FF ; goto New Key ; ; Step 13: Done ; set status[keyrdy] ; return ; ; New Key: ; clear status ; goto Step 1 ; MKY_DEC0: ; CHECK KEYCODE BUFFER LD A,(MKY_STATUS) ; GET CURRENT STATUS AND MKY_KEYRDY ; ISOLATE KEY READY FLAG RET NZ ; ABORT IF KEY IS ALREADY PENDING MKY_DEC1: ; PROCESS NEXT SCANCODE CALL MKY_GETDATAX ; GET THE SCANCODE RET Z ; NO KEY READY, RETURN WITH A=0, Z SET LD (MKY_SCANCODE),A ; SAVE SCANCODE MKY_DEC2: ; DETECT AND HANDLE SPECIAL KEYCODES LD A,(MKY_SCANCODE) ; GET THE CURRENT SCANCODE CP $AA ; KEYBOARD INSERTION? JR NZ,MKY_DEC3 ; NOPE, BYPASS CALL MKY_SETLEDS ; SET LEDS JP MKY_DECNEW ; RESTART THE ENGINE MKY_DEC3: ; DETECT AND HANDLE SCANCODE PREFIXES LD A,(MKY_SCANCODE) ; GET THE CURRENT SCANCODE MKY_DEC3A: ; HANDLE SCANCODE PREFIX $E0 (EXTENDED SCANCODE FOLLOWS) CP $E0 ; EXTENDED KEY PREFIX $E0? JR NZ,MKY_DEC3B ; NOPE MOVE ON LD A,(MKY_STATUS) ; GET STATUS OR MKY_EXT ; SET EXTENDED BIT LD (MKY_STATUS),A ; SAVE STATUS JR MKY_DEC1 ; LOOP TO DO NEXT SCANCODE MKY_DEC3B: ; HANDLE SCANCODE PREFIX $E1 (PAUSE KEY) CP $E1 ; EXTENDED KEY PREFIX $E1 JR NZ,MKY_DEC4 ; NOPE MOVE ON LD A,$EE ; MAP TO KEYCODE $EE LD (MKY_KEYCODE),A ; SAVE IT ; SWALLOW NEXT 7 SCANCODES LD B,7 ; LOOP 5 TIMES MKY_DEC3B1: PUSH BC CALL MKY_GETDATA ; RETRIEVE NEXT SCANCODE POP BC DJNZ MKY_DEC3B1 ; LOOP AS NEEDED JP MKY_DEC6 ; RESUME AFTER MAPPING MKY_DEC4: ; DETECT AND FLAG BREAK EVENT CP $F0 ; BREAK (KEY UP) PREFIX? JR NZ,MKY_DEC5 ; NOPE MOVE ON LD A,(MKY_STATUS) ; GET STATUS OR MKY_BREAK ; SET BREAK BIT LD (MKY_STATUS),A ; SAVE STATUS JR MKY_DEC1 ; LOOP TO DO NEXT SCANCODE MKY_DEC5: ; MAP SCANCODE TO KEYCODE LD A,(MKY_STATUS) ; GET STATUS AND MKY_EXT ; EXTENDED BIT SET? JR Z,MKY_DEC5C ; NOPE, MOVE ON ; PERFORM EXTENDED KEY MAPPING LD A,(MKY_SCANCODE) ; GET SCANCODE LD E,A ; STASH IT IN E LD HL,MKY_MAPEXT ; POINT TO START OF EXT MAP TABLE MKY_DEC5A: LD A,(HL) ; GET FIRST BYTE OF PAIR CP $00 ; END OF TABLE? JP Z,MKY_DECNEW ; UNKNOWN OR BOGUS, START OVER INC HL ; INC HL FOR FUTURE CP E ; DOES MATCH BYTE EQUAL SCANCODE? JR Z,MKY_DEC5B ; YES! JUMP OUT INC HL ; BUMP TO START OF NEXT PAIR JR MKY_DEC5A ; LOOP TO CHECK NEXT TABLE ENTRY MKY_DEC5B: LD A,(HL) ; GET THE KEYCODE VIA MAPPING TABLE LD (MKY_KEYCODE),A ; SAVE IT JR MKY_DEC6 MKY_DEC5C: ; PERFORM REGULAR KEY (NOT EXTENDED) KEY MAPPING LD A,(MKY_SCANCODE) ; GET THE SCANCODE CP MKY_MAPSIZ ; COMPARE TO SIZE OF TABLE JR NC,MKY_DEC6 ; PAST END, SKIP OVER LOOKUP ; SETUP POINTER TO MAPPING TABLE BASED ON SHIFTED OR UNSHIFTED STATE LD A,(MKY_STATE) ; GET STATE AND KBD_SHIFT ; SHIFT ACTIVE? LD HL,MKY_MAPSTD ; LOAD ADDRESS OF NON-SHIFTED MAPPING TABLE JR Z,MKY_DEC5D ; NON-SHIFTED, MOVE ON LD HL,MKY_MAPSHIFT ; LOAD ADDRESS OF SHIFTED MAPPING TABLE MKY_DEC5D: LD A,(MKY_SCANCODE) ; GET THE SCANCODE LD E,A ; SCANCODE TO E FOR TABLE OFFSET LD D,0 ; D -> 0 ADD HL,DE ; COMMIT THE TABLE OFFSET TO HL LD A,(HL) ; GET THE KEYCODE VIA MAPPING TABLE LD (MKY_KEYCODE),A ; SAVE IT MKY_DEC6: ; HANDLE MODIFIER KEYS LD A,(MKY_KEYCODE) ; MAKE SURE WE HAVE KEYCODE CP $B8 ; END OF MODIFIER KEYS JR NC,MKY_DEC7 ; BYPASS MODIFIER KEY CHECKING CP $B0 ; START OF MODIFIER KEYS JR C,MKY_DEC7 ; BYPASS MODIFIER KEY CHECKING LD B,4 ; LOOP COUNTER TO LOOP THRU 4 MODIFIER BITS LD E,$80 ; SETUP E TO ROATE THROUGH MODIFIER STATE BITS SUB $B0 - 1 ; SETUP A TO DECREMENT THROUGH MODIFIER VALUES MKY_DEC6A: RLC E ; SHIFT TO NEXT MODIFIER STATE BIT DEC A ; L-MODIFIER? JR Z,MKY_DEC6B ; YES, HANDLE L-MODIFIER MAKE/BREAK DEC A ; R-MODIFIER? JR Z,MKY_DEC6C ; YES, HANDLE R-MODIFIER MAKE/BREAK DJNZ MKY_DEC6A ; LOOP THRU 4 MODIFIER BITS JR MKY_DEC7 ; FAILSAFE, SHOULD NEVER GET HERE! MKY_DEC6B: ; LEFT STATE KEY MAKE/BREAK (STATE BIT TO SET/CLEAR IN E) LD HL,MKY_LSTATE ; POINT TO LEFT STATE BYTE JR MKY_DEC6D ; CONTINUE MKY_DEC6C: ; RIGHT STATE KEY MAKE/BREAK (STATE BIT TO SET/CLEAR IN E) LD HL,MKY_RSTATE ; POINT TO RIGHT STATE BYTE JR MKY_DEC6D ; CONTINUE MKY_DEC6D: ; BRANCH BASED ON WHETHER THIS IS A MAKE OR BREAK EVENT LD A,(MKY_STATUS) ; GET STATUS FLAGS AND MKY_BREAK ; BREAK EVENT? JR Z,MKY_DEC6E ; NO, HANDLE A MODIFIER KEY MAKE EVENT JR MKY_DEC6F ; YES, HANDLE A MODIFIER BREAK EVENT MKY_DEC6E: ; HANDLE STATE KEY MAKE EVENT LD A,E ; GET THE BIT TO SET OR (HL) ; OR IN THE CURRENT BITS LD (HL),A ; SAVE THE RESULT JR MKY_DEC6G ; CONTINUE MKY_DEC6F: ; HANDLE STATE KEY BREAK EVENT LD A,E ; GET THE BIT TO CLEAR XOR $FF ; FLIP ALL BITS TO SETUP FOR A CLEAR OPERATION AND (HL) ; AND IN THE FLIPPED BITS TO CLEAR DESIRED BIT LD (HL),A ; SAVE THE RESULT JR MKY_DEC6G ; CONTINUE MKY_DEC6G: ; COALESCE L/R STATE FLAGS LD A,(MKY_STATE) ; GET EXISTING STATE BITS AND $F0 ; GET RID OF OLD MODIFIER BITS LD DE,(MKY_LSTATE) ; LOAD BOTH L/R STATE BYTES IN D/E OR E ; MERGE IN LEFT STATE BITS OR D ; MERGE IN RIGHT STATE BITS LD (MKY_STATE),A ; SAVE IT JP MKY_DECNEW ; DONE WITH CURRENT KEYSTROKE MKY_DEC7: ; COMPLETE PROCESSING OF EXTENDED AND KEY BREAK EVENTS LD A,(MKY_STATUS) ; GET CURRENT STATUS FLAGS AND MKY_BREAK ; IS THIS A KEY BREAK EVENT? JP NZ,MKY_DECNEW ; PROCESS NEXT KEY MKY_DEC8: ; HANDLE TOGGLE KEYS LD A,(MKY_KEYCODE) ; GET THE CURRENT KEYCODE INTO A LD E,KBD_CAPSLCK ; SETUP E WITH CAPS LOCK STATE BIT CP $BC ; IS THIS THE CAPS LOCK KEY? JR Z,MKY_DEC8A ; YES, GO TO BIT SET ROUTINE LD E,KBD_NUMLCK ; SETUP E WITH NUM LOCK STATE BIT CP $BD ; IS THIS THE NUM LOCK KEY? JR Z,MKY_DEC8A ; YES, GO TO BIT SET ROUTINE LD E,KBD_SCRLCK ; SETUP E WITH SCROLL LOCK STATE BIT CP $BE ; IS THIS THE SCROLL LOCK KEY? JR Z,MKY_DEC8A ; YES, GO TO BIT SET ROUTINE JR MKY_DEC9 ; NOT A TOGGLE KEY, CONTINUE MKY_DEC8A: ; RECORD THE TOGGLE LD A,(MKY_STATE) ; GET THE CURRENT STATE FLAGS XOR E ; SET THE TOGGLE KEY BIT FROM ABOVE LD (MKY_STATE),A ; SAVE IT CALL MKY_SETLEDS ; UPDATE LED LIGHTS ON KBD JP MKY_DECNEW ; RESTART DECODER FOR A NEW KEY MKY_DEC9: ; ADJUST KEYCODE FOR CONTROL MODIFIER LD A,(MKY_STATE) ; GET THE CURRENT STATE BITS AND KBD_CTRL ; CHECK THE CONTROL BIT JR Z,MKY_DEC10 ; CONTROL KEY NOT PRESSED, MOVE ON LD A,(MKY_KEYCODE) ; GET CURRENT KEYCODE IN A CP 'a' ; COMPARE TO LOWERCASE A JR C,MKY_DEC9A ; BELOW IT, BYPASS CP 'z' + 1 ; COMPARE TO LOWERCASE Z JR NC,MKY_DEC9A ; ABOVE IT, BYPASS RES 5,A ; KEYCODE IN LOWERCASE A-Z RANGE CLEAR BIT 5 TO MAKE IT UPPERCASE MKY_DEC9A: CP '@' ; COMPARE TO @ JR C,MKY_DEC10 ; BELOW IT, BYPASS CP '_' + 1 ; COMPARE TO _ JR NC,MKY_DEC10 ; ABOVE IT, BYPASS RES 6,A ; CONVERT TO CONTROL VALUE BY CLEARING BIT 6 LD (MKY_KEYCODE),A ; UPDATE KEYCODE TO CONTROL VALUE MKY_DEC10: ; ADJUST KEYCODE FOR CAPS LOCK LD A,(MKY_STATE) ; LOAD THE STATE FLAGS AND KBD_CAPSLCK ; CHECK CAPS LOCK JR Z,MKY_DEC12 ; CAPS LOCK NOT ACTIVE, MOVE ON LD A,(MKY_KEYCODE) ; GET THE CURRENT KEYCODE VALUE CP 'a' ; COMPARE TO LOWERCASE A JR C,MKY_DEC10A ; BELOW IT, BYPASS CP 'z' + 1 ; COMPARE TO LOWERCASE Z JR NC,MKY_DEC10A ; ABOVE IT, BYPASS JR MKY_DEC10B ; IN RANGE LOWERCASE A-Z, GO TO CASE SWAPPING LOGIC MKY_DEC10A: CP 'A' ; COMPARE TO UPPERCASE A JR C,MKY_DEC12 ; BELOW IT, BYPASS CP 'Z' + 1 ; COMPARE TO UPPERCASE Z JR NC,MKY_DEC12 ; ABOVE IT, BYPASS JR MKY_DEC10B ; IN RANGE UPPERCASE A-Z, GO TO CASE SWAPPING LOGIC MKY_DEC10B: LD A,(MKY_KEYCODE) ; GET THE CURRENT KEYCODE XOR $20 ; FLIP BIT 5 TO SWAP UPPER/LOWER CASE LD (MKY_KEYCODE),A ; SAVE IT MKY_DEC12: ; DETECT UNKNOWN/INVALID KEYCODES LD A,(MKY_KEYCODE) ; GET THE FINAL KEYCODE CP $FF ; IS IT $FF (UNKNOWN/INVALID) JP Z,MKY_DECNEW ; IF SO, JUST RESTART THE ENGINE MKY_DEC13: ; DONE - RECORD RESULTS LD A,(MKY_STATUS) ; GET CURRENT STATUS OR MKY_KEYRDY ; SET KEY READY BIT LD (MKY_STATUS),A ; SAVE IT XOR A ; A=0 INC A ; SIGNAL SUCCESS WITH A=1 RET MKY_DECNEW: ; START NEW KEYPRESS (CLEAR ALL STATUS BITS) XOR A ; A = 0 LD (MKY_STATUS),A ; CLEAR STATUS JP MKY_DEC1 ; RESTART THE ENGINE ; ;__________________________________________________________________________________________________ ; INTERRUPT HANDLER ; ; SCAN KEYBOARD AND IN THE NEWKEY SCAN STATS ; ;__________________________________________________________________________________________________ ; MKY_INT: LD A, (MKY_RPTACTIVE) ; NO REPEAT KEY IS HELD? OR A JR Z, MKY_INTSCAN1 LD A, (MKY_RPTCNT) ; DECREMENT REPEAT COUNTER DEC A ; DOWN TO ZERO CP $FF JR Z, MKY_INTSCAN1 LD (MKY_RPTCNT), A MKY_INTSCAN1: LD A, (MKY_SCNCNT) ; SCAN THE KEYBOARD EVERY 'SCAN_INT_PERIOD' INTERRUPTS. DEC A LD (MKY_SCNCNT), A JR NZ, VEC_TICK_MKY LD A, SCAN_INT_PERIOD LD (MKY_SCNCNT), A ; SCAN KEYBOARD AND STORE ALL COLUMN RESULTS PER ROW AT MKY_NEWKEY ; EZ80_IO IN A, (MKY_REGC) ; READ AND MASK THE CURRENT STATE OF PPI PORT C AND $F0 LD D, A LD B, MATRIX_ROW_COUNT ; PREPARE TO LOOP THRU THE SCAN ROWS LD HL, MKY_NEWKEY LD C, MKY_REGC MKY_SCAN_LP: EZ80_IO OUT (C), D ; SET ACTIVE ROW EZ80_IO IN A, (MKY_REGB) ; READ ACTIVE COLUMN DATA LD (HL), A ; STORE COLUMN READ VALUE INC HL INC D DJNZ MKY_SCAN_LP ; LOOP UNTIL ALL ROWS READ LD A, $FF ; NOTE THAT A SCAN HAS BEEN DONE LD (MKY_SCANNED), A VEC_TICK_MKY: JP HB_TICK ; ;__________________________________________________________________________________________________ ; COMPARE MKY_OLDKEY O MKY_NEWKEY ; GENERATE SCAN CODES ; ; FOR EACH BIT IN MKY_OLDKEY CP WITH CORRESPONDING BIT IN MKY_SCNKEY ; IF BOTH = 1, THEN NO KEY PRESS - NOTHING CHANGED ; IF BOTH = 0, THEN KEY WAS AND IS STILL PRESSED - NOTHING CHANGED ; IF OLD = 1 AND SCN = 0, KEY WAS PRESSED ; IF OLD = 0 AND SCN = 1, KEY WAS RELEASED ; STOP OF FIRST CHANGE - STORE IN BUFFER, AND RESET/CLEAR BIT IN MKY_OLDKEY ; ALSO SET MKY_RPTACTIVE. NZ -> A KEY IS HELD DOWN, ZERO -> NO KEYS HELD DOWN ; MKY_GENSCODE: XOR A LD (MKY_RPTACTIVE), A ; CLEAR FLAG TO INDICATE A KEYHOLD STATE LD HL, MKY_OLDKEY LD DE, MKY_SCNKEY XOR A EX AF, AF' ; ROW COUNT IN A' MKY_GENSCODE_LPR: LD C, (HL) LD A, (DE) AND C CP $FF JR Z, MKY_GENSCODENXT1 ; ALL KEYS ARE UP AND WERE UP? LD B, 8 ; 8 COLUMN BITS LD A, (DE) MKY_GENSCODE_LPC: RRCA ; ROTATE NEW COLUMN BIT INTO CARRY JR NC, MKY_NEWDWN ; IS KEY DOWN? ; KEY IS UP RRC C ; ROTATE OLD COLUMN BIT INTO CARRY JR C, MKY_GENSCODENXT ; BOTH KEYS UP? ; NEW KEY IS UP, OLD KEY WAS DOWN JR MKY_KEYUP ; STORE NEW KEY RELEASE IN BUFF (A' IF ROW, B IS COLUMN) MKY_NEWDWN: RRC C ; ROTATE OLD COLUMN BIT INTO CARRY JR NC, MKY_KEYHOLD ; BOTH KEYS DOWN? ; NEW KEY IS DOWN, OLD KEY WAS UP JR MKY_KEYDOWN ; STORE NEW KEY PRESS IN BUFF (A' IF ROW, B IS COLUMN) MKY_GENSCODENXT: DJNZ MKY_GENSCODE_LPC MKY_GENSCODENXT1: EX AF, AF' INC A CP MATRIX_ROW_COUNT RET Z EX AF, AF' INC HL INC DE JR MKY_GENSCODE_LPR ; KEY IS PRESSED MKY_KEYHOLD: EX AF, AF' ; GET ROW COUNT CP 6 JR NC, MKY_NORPT ; IF >=6 THEN WE DONT REPEAT LD (MKY_NRPTROW), A EX AF, AF' PUSH AF LD A, B LD (MKY_NRPTCOL), A LD A, $FF ; RECORD FACT THAT A KEY HAS BEEN HELD - FOR LATER TESTING LD (MKY_RPTACTIVE), A ; OF REPEAT FUNCTION POP AF JR MKY_GENSCODENXT MKY_NORPT: EX AF, AF' JR MKY_GENSCODENXT MKY_KEYDOWN: PUSH AF LD A, KEY_REPEAT_INIT ; SET COUNTER FOR REPEAT TRIGGER LD (MKY_RPTCNT), A POP AF MKY_KEYDOWN_RPT: CALL MKY_RESOLDBIT CALL MKY_SCANADDR LD A, (HL) OR A ; IF NO SCANCODE - IGNORE IT RET Z LD (MKY_SCANBUFF), A LD A, 1 LD (MKY_SCANBUFFLEN), A RET MKY_KEYUP: CALL MKY_SETOLDBIT CALL MKY_SCANADDR LD A, (HL) OR A ; IF NO SCANCODE - IGNORE IT RET Z LD (MKY_SCANBUFF+1), A LD A, $F0 LD (MKY_SCANBUFF), A LD A, 2 LD (MKY_SCANBUFFLEN), A RET MKY_RPTGEN: LD A, (MKY_SCANBUFFLEN) ; IF ALREADY A CODE IN BUFFER OR A ; THEN WE CANT GENERATE A REPEAT RET NZ LD A, (MKY_RPTACTIVE) ; NO KEY IS HELD OR A RET Z LD A, (MKY_RPTCNT) OR A RET NZ ; GENERATE THE KEY DOWN SCAN CODE FOR THE REPEATING KEY LD A, KEY_REPEAT_PERIOD LD (MKY_RPTCNT), A LD A, (MKY_NRPTCOL) LD B, A LD A, (MKY_NRPTROW) EX AF, AF' JR MKY_KEYDOWN_RPT ; ;__________________________________________________________________________________________________ ; ; RETRIEVE ADDRESS AND BIT MASK WITHIN MKY_OLDKEY RRAY ; ; INPUT: ; B = 1 TO 8 - COLUMN COUNT ; A' IS ROW COUNT - 0 TO MATRIX_ROW_COUNT ; OUTPUT: ; HL = BYTE WITHIN MKY_OLDKEY ARRAY ; A = BIT MASK FOR COLUMN COUNT (EG: B = 3, A = 8) ; PROTECTS: ; A' IS UNCHANGED ; B IS UNCHANGED MKY_GETKEYIDX: LD HL, MKY_OLDKEY LD A, $80 LD C, B ; SAVE B (COLUMN COUNT - 1 TO 8) MKY_SETOLDBIT_LP: DEC B JR Z, SKIP RRCA JR MKY_SETOLDBIT_LP SKIP: EX AF, AF' ; RETRIEVE ROW COUNT LD E, A EX AF, AF' LD D, 0 LD B, C ; RETORE B (COLUMN COUNT) ADD HL, DE RET ; ;__________________________________________________________________________________________________ ; ; SET BIT WITHIN THE KEY MATRIX ARRAY ; HL -> ADDRESS WITHIN MKY_OLDKEY ARRAY ; C BIT MASK TO BE OR'ED ; MKY_SETOLDBIT: CALL MKY_GETKEYIDX OR (HL) LD (HL), A RET ; ;__________________________________________________________________________________________________ ; ; RESET BIT WITHIN THE KEY MATRIX ARRAY ; HL -> ADDRESS WITHIN MKY_OLDKEY ARRAY ; C CPL BIT MASK TO BE AND'ED ; MKY_RESOLDBIT: CALL MKY_GETKEYIDX CPL AND (HL) LD (HL), A RET ; ;__________________________________________________________________________________________________ ; ; CALCULATE THE ADDRESS WITHIN THE SCANCODE_TABLE FOR A SPECIFIC KEY ; MKY_SCANADDR: ; ASSUMING SINGLE BYTE CODE CODE EX AF, AF' ; RETRIVE ROW COUNT ; CODE ADDR = SCANCODE_TBL + (A * 8) + B - 1 LD L, A LD H, 0 ADD HL, HL ADD HL, HL ADD HL, HL DEC B LD C, B LD B, 0 ADD HL, BC LD DE, SCANCODE_TBL ADD HL, DE RET ; ;__________________________________________________________________________________________________ ; READ A SINGLE BYTE FROM THE SCANCODE BUFFER ; RETURNED IN A ; MKY_READBYT: LD A, (MKY_SCANBUFFLEN) OR A RET Z LD A, (MKY_SCANBUFF) LD DE, MKY_SCANBUFF LD HL, MKY_SCANBUFF + 1 LD BC, 4 LDIR LD C, A LD A, (MKY_SCANBUFFLEN) DEC A LD (MKY_SCANBUFFLEN), A LD A, C RET ; DYNAMIC DATA STORAGE: ; ; STORAGE OF KEYBOARD MATRIX, USED FOR DETECTING KEY REPETITION MKY_OLDKEY: .FILL MATRIX_ROW_COUNT, $FF ; ; CURRENT STATE OF THE KEYBOARD MATRIX MKY_NEWKEY: .FILL MATRIX_ROW_COUNT, $FF ; ; COPY OF MKY_NEWKEY FOR USE IN GENERATING SCANCODE MKY_SCNKEY: .FILL MATRIX_ROW_COUNT, $FF ; ; SET TO NZ WHEN A SCAN IS COMPLETED ; SET TO ZERO AFTER A SCAN CODE CONVERSION MKY_SCANNED: .DB 0 ; ; F3F6: VDP-INTERRUPT COUNTER THAT COUNTS FROM SCAN_INT_PERIOD TO 0, WHEN IT REACHES ZERO, THE ; KEYBOARD MATRIX IS SCANNED, AND THE COUNTERS IS RESET AT SCAN_INT_PERIOD MKY_SCNCNT: .DB SCAN_INT_PERIOD ; INITIALL SET TO FALSE, AND THUS DISABLING INTERRUPT HANDLER'S SCAN FUNCTION ; AS SOON AT THE KEY REQUEST FUNCTIONS (STATUS, READ), THIS IS SET AND INTERRUPT HANDLER ; IS PERMANETLY ON. ; MKY_SCANON: .DB 0 ; MKY_NRPTCOL: .DB 0 MKY_NRPTROW: .DB 0 MKY_RPTACTIVE: .DB 0 MKY_RPTCNT: .DB KEY_REPEAT_INIT MKY_SCANBUFF: .FILL 5, 0 MKY_SCANBUFFLEN: .DB 0 MKY_SCANCODE: .DB 0 ; RAW SCANCODE MKY_KEYCODE: .DB 0 ; RESULTANT KEYCODE AFTER DECODING MKY_STATE: .DB 0 ; STATE BITS (SEE ABOVE) MKY_LSTATE: .DB 0 ; STATE BITS FOR "LEFT" KEYS MKY_RSTATE: .DB 0 ; STATE BITS FOR "RIGHT" KEYS MKY_STATUS: .DB 0 ; CURRENT STATUS BITS (SEE ABOVE) #IF (MKYKBLOUT == KBD_US) ;__________________________________________________________________________________________________ ; ; MAPPING TABLES US/ENGLISH ;__________________________________________________________________________________________________ MKY_MAPSTD: ; SCANCODE IS INDEX INTO TABLE TO RESULTANT LOOKUP KEYCODE .DB $FF,$E8,$FF,$E4,$E2,$E0,$E1,$EB,$FF,$E9,$E7,$E5,$E3,$09,'`',$FF .DB $FF,$B4,$B0,$FF,$B2,'q','1',$FF,$FF,$FF,'z','s','a','w','2',$FF .DB $FF,'c','x','d','e','4','3',$FF,$FF,' ','v','f','t','r','5',$FF .DB $FF,'n','b','h','g','y','6',$FF,$FF,$FF,'m','j','u','7','8',$FF .DB $FF,',','k','i','o','0','9',$FF,$FF,'.','/','l',';','p','-',$FF .DB $FF,$FF,$27,$FF,'[','=',$FF,$FF,$BC,$B1,$0D,']',$FF,'\',$FF,$FF .DB $FF,$FF,$FF,$FF,$FF,$FF,$08,$FF,$FF,$C0,$FF,$C3,$C6,$FF,$FF,$FF .DB $C9,$CA,$C1,$C4,$C5,$C7,$1B,$BD,$FA,$CE,$C2,$CD,$CC,$C8,$BE,$FF .DB $FF,$FF,$FF,$E6,$EC ; MKY_MAPSIZ .EQU ($ - MKY_MAPSTD) ; MKY_MAPSHIFT: ; SCANCODE IS INDEX INTO TABLE TO RESULTANT LOOKUP KEYCODE WHEN SHIFT ACTIVE .DB $FF,$E8,$FF,$E4,$E2,$E0,$E1,$EB,$FF,$E9,$E7,$E5,$E3,$09,'~',$FF .DB $FF,$B4,$B0,$FF,$B2,'Q','!',$FF,$FF,$FF,'Z','S','A','W','@',$FF .DB $FF,'C','X','D','E','$','#',$FF,$FF,' ','V','F','T','R','%',$FF .DB $FF,'N','B','H','G','Y','^',$FF,$FF,$FF,'M','J','U','&','*',$FF .DB $FF,'<','K','I','O',')','(',$FF,$FF,'>','?','L',':','P','_',$FF .DB $FF,$FF,$22,$FF,'{','+',$FF,$FF,$BC,$B1,$0D,'}',$FF,'|',$FF,$FF .DB $FF,$FF,$FF,$FF,$FF,$FF,$08,$FF,$FF,$D0,$FF,$D3,$D6,$FF,$FF,$FF .DB $D9,$DA,$D1,$D4,$D5,$D7,$1B,$BD,$FA,$DE,$D2,$DD,$DC,$D8,$BE,$FF .DB $FF,$FF,$FF,$E6,$EC ; MKY_MAPEXT: ; PAIRS ARE [SCANCODE,KEYCODE] FOR EXTENDED SCANCODES .DB $11,$B5, $14,$B3, $1F,$B6, $27,$B7 .DB $2F,$EF, $37,$FA, $3F,$FB, $4A,$CB .DB $5A,$CF, $5E,$FC, $69,$F3, $6B,$F8 .DB $6C,$F2, $70,$F0, $71,$F1, $72,$F7 .DB $74,$F9, $75,$F6, $7A,$F5, $7C,$ED .DB $7D,$F4, $7E,$FD, $00,$00 ; #ENDIF #IF (MKYKBLOUT == KBD_DE) ;__________________________________________________________________________________________________ ; ; MAPPING TABLES GERMAN ;__________________________________________________________________________________________________ ; MKY_MAPSTD: ; SCANCODE IS INDEX INTO TABLE TO RESULTANT LOOKUP KEYCODE ROW ; Column 0 1 2 3 4 5 6 7 8 9 A B C D E F ; Special adjustments listed below .DB $FF,$E8,$FF,$E4,$E2,$E0,$E1,$EB,$FF,$E9,$E7,$E5,$E3,$09,'^',$FF ;0 for German keyboard keys that give .DB $FF,$B4,$B0,$FF,$B2,'q','1',$FF,$FF,$FF,'y','s','a','w','2',$FF ;1 different characters than are printed .DB $FF,'c','x','d','e','4','3',$FF,$FF,' ','v','f','t','r','5',$FF ;2 on the keys. .DB $FF,'n','b','h','g','z','6',$FF,$FF,$FF,'m','j','u','7','8',$FF ;3 'german key' --> 'new occupied with' .DB $FF,',','k','i','o','0','9',$FF,$FF,'.','-','l','[','p',$5C,$FF ;4 Assembler ERROR: '\'-->$5C ; 'ö'-->'[' .DB $FF,$FF,'@',$FF,']','|',$FF,$FF,$BC,$B1,$0D,'+',$FF,'#',$FF,$FF ;5 'ä'-->'@' ; 'ü'-->']' .DB $FF,'<',$FF,$FF,$FF,$FF,$08,$FF,$FF,$C0,$FF,$C3,$C6,'<',$FF,$FF ;6 .DB $C9,$CA,$C1,$C4,$C5,$C7,$1B,$BD,$FA,$CE,$C2,$CD,$CC,$C8,$BE,$FF ;7 .DB $FF,$FF,$FF,$E6,$EC ;8 MKY_MAPSIZ .EQU ($ - MKY_MAPSTD) ; MKY_MAPSHIFT: ; SCANCODE IS INDEX INTO TABLE TO RESULTANT LOOKUP KEYCODE WHEN SHIFT ACTIVE .DB $FF,$E8,$FF,$E4,$E2,$E0,$E1,$EB,$FF,$E9,$E7,$E5,$E3,$09,'~',$FF ; '°' --> '~' .DB $FF,$B4,$B0,$FF,$B2,'Q','!',$FF,$FF,$FF,'Y','S','A','W',$22,$FF .DB $FF,'C','X','D','E','$',$20,$FF,$FF,' ','V','F','T','R','%',$FF ; '§'-->$20; '§'=Paragraph not used in CP/M .DB $FF,'N','B','H','G','Z','&',$FF,$FF,$FF,'M','J','U','/','(',$FF .DB $FF,';','K','I','O','=',')',$FF,$FF,':','_','L','{','P','?',$FF ; 'Ö'-->'{' .DB $FF,$FF,'@',$FF,'}','`',$FF,$FF,$BC,$B1,$0D,'*',$FF,$27,$FF,$FF ; 'Ä'-->'@' ; 'Ü'-->'}' .DB $FF,'>',$FF,$FF,$FF,$FF,$08,$FF,$FF,$D0,$FF,$D3,$D6,'>',$FF,$FF .DB $D9,$DA,$D1,$D4,$D5,$D7,$1B,$BD,$FA,$DE,$D2,$DD,$DC,$D8,$BE,$FF .DB $FF,$FF,$FF,$E6,$EC MKY_MAPEXT: ; PAIRS ARE [SCANCODE,KEYCODE] FOR EXTENDED SCANCODES .DB $11,$B5, $14,$B3, $1F,$B6, $27,$B7 .DB $2F,$EF, $37,$FA, $3F,$FB, $4A,$CB ; All keys listed below are customized for Wordstar. .DB $5A,$CF, $5E,$FC, $69,$06, $6B,$13 ; n.a , n.a , word right , n.a. .DB $6C,$01, $70,$16, $71,$07, $72,$18 ; Word left , Toggle Insert/Overwrite , Del Char , Cursor down .DB $74,$04, $75,$05, $7A,$1A, $7C,$ED ; Cursor right , Cursor up , Page down .DB $7D,$17, $7E,$FD, $00,$00 ; Page up , n.a. , END MKY_MAPEXT (Pairs end) ; #ENDIF ; ;__________________________________________________________________________________________________ ; KEYCODE VALUES RETURNED BY THE DECODER ;__________________________________________________________________________________________________ ; ; VALUES 0-127 ARE STANDARD ASCII, SPECIAL KEYS WILL HAVE THE FOLLOWING VALUES: ; ; F1 $E0 ; F2 $E1 ; F3 $E2 ; F4 $E3 ; F5 $E4 ; F6 $E5 ; F7 $E6 ; F8 $E7 ; F9 $E8 ; F10 $E9 ; F11 $EA ; F12 $EB ; SYSRQ $EC ; PRTSC $ED ; PAUSE $EE ; APP $EF ; INS $F0 ; DEL $F1 ; HOME $F2 ; END $F3 ; PGUP $F4 ; PGDN $F5 ; UP $F6 ; DOWN $F7 ; LEFT $F8 ; RIGHT $F9 ; POWER $FA ; SLEEP $FB ; WAKE $FC ; BREAK $FD