'=========================================================================== ' Subject: NEW ASSEMBLY MULTIKEY FUNCTION Date: 12-20-97 (10:33) ' Author: Joe Huber, Jr. Code: QB, QBasic, PDS ' Origin: Milo Sedlacek Packet: KEYBOARD.ABC '=========================================================================== DECLARE SUB KEYTEST () DECLARE FUNCTION MULTIKEY (T) 'New and Improved MULTIKEY function!! 'This version eliminates the key lock-up problem from 'previous verions. And is MUCH, MUCH faster!! 'ASM Interrupt & support code by Milo Sedlacek 'Everything else by 'MULTIKEY - main routine ' Usage: ' X = MULTIKEY(T) ' where t can equal -1,-2, and 1-128 ' t = -1: IMPORTANT!!! Make sure you pass this value to ' the function before -2 and 1-128! It turns the ' interrupt on so you can start reading keys. ' Returns: nothing ' t = -2: EXTREMELY IMPORTANT!!!!!!!! ' ALWAYS pass this before you end your program! ' If you don't, your computer won't be able to ' read your keyboard & you'll have to reset! ' i.e., CTRL-ALT-DEL won't work!! ' Returns: nothing ' t = keycode (1-128): Returns status of a key. ' Returns: 1 or 0 where ' 1 = pressed ' 0 = unpressed ' 'KEYTEST - helps you find new keycodes ' Usage: ' CALL KEYTEST or KEYTEST ' This will show all 128 keycodes & their statuses. ' Press & hold a key & a 1 will appear somewhere. ' The number that the 1 is by will be the keycode ' for that key. Simple! ' Send any qustions, comments, etc. to: huberjjr@nicom.com 'Demo code: 'Use arrows to turn & accelerate 'Press space to come to a total stop 'Hit ESC to exit Z = MULTIKEY(-1) ' Initalize ASM & hook interrupt SCREEN 12 CLS X = 320 Y = 240 cPI = (3.141592654# / 180) ANGLE = 0 RADIUS = 5 SPEED = .2 DO IF MULTIKEY(77) THEN ANGLE = ANGLE - 7 ' Left IF MULTIKEY(75) THEN ANGLE = ANGLE + 7 ' Right IF MULTIKEY(72) THEN ' Up VX = VX + (SIN(cPI * ANGLE) * SPEED) VY = VY + (COS(cPI * ANGLE) * SPEED) END IF IF MULTIKEY(80) THEN ' Down VX = VX - (SIN(cPI * ANGLE) * SPEED) VY = VY - (COS(cPI * ANGLE) * SPEED) END IF IF MULTIKEY(57) THEN ' Space VX = 0 VY = 0 END IF IF ANGLE > 360 THEN ' Wrap-around angle ANGLE = 0 + (ANGLE - 360) END IF IF ANGLE < 0 THEN ANGLE = 360 - (0 + ANGLE) END IF IF X < 0 + RADIUS THEN VX = -VX ' Bounce limits IF X > 640 - RADIUS THEN VX = -VX IF Y < 0 + RADIUS THEN VY = -VY IF Y > 480 - RADIUS THEN VY = -VY X = X + VX ' Move it Y = Y + VY X2 = X + SIN(cPI * ANGLE) * RADIUS ' White dot calc Y2 = Y + COS(cPI * ANGLE) * RADIUS ' ditto VX = VX * .998 ' Friction VY = VY * .998 ' ditto CIRCLE (XX, YY), RADIUS, 0 ' Erase PSET (XX2, YY2), 0 PSET (XX, YY), 0 CIRCLE (X, Y), RADIUS, 4 ' Draw PSET (X2, Y2), 15 PSET (X, Y), 4 XX = X: YY = Y: YY2 = Y2: XX2 = X2 WAIT &H3DA, 8 ' Wait to vert. retarce WAIT &H3DA, 8, 8 LOOP UNTIL MULTIKEY(1) = 1 ' Hit ESC to exit Z = MULTIKEY(-2) 'Unhook interrupt END 'KB Interrrupt source ' &HE9,&H1D,&H00 : '0000 JMP 0020 ;Jump to INSTALL INTERRUPT ' &HE9,&H3C,&H00 : '0003 JMP 0042 ;Jump to UNINSTALL INTERRUPT ' &H00,&H00 : '0006 ADD [BX+SI],AL ;\ ' &H00,&H00 : '0008 ADD [BX+SI],AL ; \ ' &H00,&H00 : '000A ADD [BX+SI],AL ; } Unused space ' &H00,&H00 : '000C ADD [BX+SI],AL ; / ' &H00,&H00 : '000E ADD [BX+SI],AL ;/ ' &H00,&H00 : '0010 ADD [BX+SI],AL ;variable: keyboard_matrix_segment ' &H00,&H00 : '0012 ADD [BX+SI],AL ;variable: keyboard_matrix_offset ' &H00,&H00 : '0014 ADD [BX+SI],AL ;variable: dos_isr_handler_offset ' &H00,&H00 : '0016 ADD [BX+SI],AL ;variable: dos_isr_handler_segment ' &H00,&H00 : '0018 ADD [BX+SI],AL ;\ ' &H00,&H00 : '001A ADD [BX+SI],AL ; \ ' &H00,&H00 : '001C ADD [BX+SI],AL ; / Unused space ' &H00,&H00 : '001E ADD [BX+SI],AL ;/ ' &H1E : '0020 PUSH DS ;INSTALL INTERRUPT save DS for QBASIC ' &H31,&HC0 : '0021 XOR AX,AX ;\ ' &H8E,&HD8 : '0023 MOV DS,AX ; } DS:SI -> interrupt vector 9 ' &HBE,&H24,&H00 : '0025 MOV SI,0024 ;/ ' &H0E : '0028 PUSH CS ; ' &H07 : '0029 POP ES ;ES = CS ' &HBF,&H14,&H00 : '002A MOV DI,0014 ;ES:DI -> dos_isr_handler_offset ' &HFC : '002D CLD ;Increment SI, DI on string moves ' &HA5 : '002E MOVSW ;\ ' &HA5 : '002F MOVSW ;/ Read address of old handler ' &H8C,&HC3 : '0030 MOV BX,ES ;BX = CS ' &H8E,&HC0 : '0032 MOV ES,AX ;ES = 0 ' &HBF,&H24,&H00 : '0034 MOV DI,0024 ;ES:DI -> keyboard interrupt vector ' &HB8,&H56,&H00 : '0037 MOV AX,0056 ;AX = Offset of new handler from CS ' &HFA : '003A CLI ;Disable interrupts ' &HAB : '003B STOSW ;\ ' &H89,&HD8 : '003C MOV AX,BX ; } Change keyboard interrupt vector ' &HAB : '003E STOSW ;/ to point to new handler ' &HFB : '003F STI ;Enable interrupts ' &H1F : '0040 POP DS ;Restore DS for QBASIC ' &HCB : '0041 RETF ; ' &H1E : '0042 PUSH DS ;UNINSTALL INTERRUPT save DS for QBASIC ' &H31,&HC0 : '0043 XOR AX,AX ;\ ' &H8E,&HC0 : '0045 MOV ES,AX ; } ES:DI -> keyboard interrupt vector ' &HBF,&H24,&H00 : '0047 MOV DI,0024 ;/ ' &HBE,&H14,&H00 : '004A MOV SI,0014 ;\ ' &H0E : '004D PUSH CS ; } DS:SI -> address of old handler ' &H1F : '004E POP DS ;/ ' &HFC : '004F CLD ;Increment SI, DI on string moves ' &HFA : '0050 CLI ;Disable interrupts ' &HA5 : '0051 MOVSW ;\ ' &HA5 : '0052 MOVSW ;/ Change interrupt vector ' &HFB : '0053 STI ;Enable interrupts ' &H1F : '0054 POP DS ;Restore DS for QBASIC ' &HCB : '0055 RETF ; ' &HFB : '0056 STI ;INTERRUPT HANDLER enable interrupts ' &H9C : '0057 PUSHF ;Save flags ' &H50 : '0058 PUSH AX ;Save registers ' &H53 : '0059 PUSH BX ; ' &H51 : '005A PUSH CX ; ' &H52 : '005B PUSH DX ; ' &H1E : '005C PUSH DS ; ' &H56 : '005D PUSH SI ; ' &H06 : '005E PUSH ES ; ' &H57 : '005F PUSH DI ; ' &HE4,&H60 : '0060 IN AL,60 ;AL = Scan code ' &HB4,&H01 : '0062 MOV AH,01 ;Assume it's a make code ' &HA8,&H80 : '0064 TEST AL,80 ; ' &H74,&H04 : '0066 JZ 006C ÚÄÄÄ;If it's not a break code then jump ' &HB4,&H00 : '0068 MOV AH,00 ³ ; It's a break code ' &H24,&H7F : '006A AND AL,7F ³ ; key index = code AND 127 ' &HD0,&HE0 : '006C SHL AL,1 ÀÄÄ>;\ ' &H88,&HC3 : '006E MOV BL,AL ; } BX = key index * 2 ' &HB7,&H00 : '0070 MOV BH,00 ;/ ' &HB0,&H00 : '0072 MOV AL,00 ; ' &H2E : '0074 CS: ; ' &H03,&H1E,&H12,&H00 : '0075 ADD BX,[0012] ;BX = BX + offset of matrix ' &H2E : '0079 CS: ; ' &H8E,&H1E,&H10,&H00 : '007A MOV DS,[0010] ;DS = segment of matrix ' &H86,&HE0 : '007E XCHG AH,AL ; ' &H89,&H07 : '0080 MOV [BX],AX ;Store key state ' &HE4,&H61 : '0082 IN AL,61 ;Interrupt Clean up ' &H0C,&H82 : '0084 OR AL,82 ; ' &HE6,&H61 : '0086 OUT 61,AL ; ' &H24,&H7F : '0088 AND AL,7F ; ' &HE6,&H61 : '008A OUT 61,AL ; ' &HB0,&H20 : '008C MOV AL,20 ; ' &HE6,&H20 : '008E OUT 20,AL ; ' &H5F : '0090 POP DI ;Restore registers ' &H07 : '0091 POP ES ; ' &H5E : '0092 POP SI ; ' &H1F : '0093 POP DS ; ' &H5A : '0094 POP DX ; ' &H59 : '0095 POP CX ; ' &H5B : '0096 POP BX ; ' &H58 : '0097 POP AX ; ' &H9D : '0098 POPF ;Restore flags ' &HCF : '0099 IRET ;Exit interrupt SUB KEYTEST SCREEN 0 CLS Z = MULTIKEY(-1) DO X = 1 Y = 1 FOR I = 1 TO 128 TEST = MULTIKEY(I) LOCATE Y, X PRINT USING "## =###"; TEST; I IF Y < 23 THEN Y = Y + 1 ELSE Y = 1 X = X + 9 END IF NEXT I LOOP WHILE MULTIKEY(1) = 0 Z = MULTIKEY(-2) END END SUB FUNCTION MULTIKEY (T) STATIC kbcontrol%(), kbmatrix%(), Firsttime, StatusFlag IF Firsttime = 0 THEN 'Initalize DIM kbcontrol%(128) DIM kbmatrix%(128) code$ = "" code$ = code$ + "E91D00E93C00000000000000000000000000000000000000000000000000" code$ = code$ + "00001E31C08ED8BE24000E07BF1400FCA5A58CC38EC0BF2400B85600FAAB" code$ = code$ + "89D8ABFB1FCB1E31C08EC0BF2400BE14000E1FFCFAA5A5FB1FCBFB9C5053" code$ = code$ + "51521E560657E460B401A8807404B400247FD0E088C3B700B0002E031E12" code$ = code$ + "002E8E1E100086E08907E4610C82E661247FE661B020E6205F075E1F5A59" code$ = code$ + "5B589DCF" DEF SEG = VARSEG(kbcontrol%(0)) FOR I% = 0 TO 155 ' Load ASM d% = VAL("&h" + MID$(code$, I% * 2 + 1, 2)) POKE VARPTR(kbcontrol%(0)) + I%, d% NEXT I% I& = 16 ' I think this stuff connects the interrupt with kbmatrix%() N& = VARSEG(kbmatrix%(0)): l& = N& AND 255: h& = ((N& AND &HFF00) \ 256): POKE I&, l&: POKE I& + 1, h&: I& = I& + 2 N& = VARPTR(kbmatrix%(0)): l& = N& AND 255: h& = ((N& AND &HFF00) \ 256): POKE I&, l&: POKE I& + 1, h&: I& = I& + 2 DEF SEG Firsttime = 1 END IF SELECT CASE T CASE -1 IF StatusFlag = 0 THEN DEF SEG = VARSEG(kbcontrol%(0)) CALL ABSOLUTE(0) ' Run interrupt DEF SEG StatusFlag = 1 END IF CASE -2 IF StatusFlag = 1 THEN DEF SEG = VARSEG(kbcontrol%(0)) ' Turn off interrupt CALL ABSOLUTE(3) DEF SEG StatusFlag = 0 END IF CASE 1 TO 128 MULTIKEY = kbmatrix%(T) ' Return status CASE ELSE MULTIKEY = 0 ' User Supidity Error END SELECT END FUNCTION