Code:
; pushing registers to stack so they can be restored to their initial value9C PUSHF50 PUSH AX53 PUSH BX51 PUSH CX52 PUSH DX1E PUSH DS56 PUSH SI06 PUSH ES57 PUSH DI; port readingEA 60 IN AL, 60 ; Read port 0x60, store in ALB4 01 MOV AH, 01 ; Assume the key is pressedA8 80 TEST AL, 80 ; Test bit-7 in AL, modifies Sign, Zero and Parity flag register.74 04 JZ 4 ; If Zero flag is SET, skip 4 bytes (2 instructions)B4 00 MOV AH, 00 ; The key was in fact released24 7F AND AL, 7F ; Strip bit-7 from AL (only keep scancode); getting offset from begining of the arrayD0 E0 SHL AL, 1 ; Multiply AL by 2 (target is an INTEGER array of 129 elements)88 C3 MOV BL, AL ; Set BX (lower byte) to ALB7 00 MOV BH, 00 ; Set BX (high byte) to 0B0 00 MOV AL, 00 ; Set AL to 0; going to the array memory address and write key status2E CS: ; Change code segment, set BX (offset)03 1E 12 00 ADD BX, [0012] ; Add BX to the value stored at 0x12 (array memory offset)2E CS: ; Change code segment, set DS (segment)8E 1E 10 00 MOV DS, [0010] ; Set DS to the value stored at 0x10 (array memory segment)86 E0 XCHG AH, AL ; Swap AH and AL (AH contains the key status)89 07 MOV [BX], AX ; Write AX (2 bytes) to [BX] (array memory offset); the rest is the standard:; acknowledge interrupt; restore registers with POP and POPF; terminate interrupt execution with IRET
Code:
; pushing registers like aboveEA 60 IN AL, 60 ; Read port 0x60, store in ALB4 01 MOV AH, 01 ; Assume the key is pressedA8 80 TEST AL, 80 ; Test bit-7 in AL, modifies Sign, Zero and Parity flag register.74 04 JZ 4 ; If Zero flag is SET, skip 4 bytes (2 instructions)B4 00 MOV AH, 00 ; Our bad, key is actually released.24 7F AND AL, 7F ; Only preserve bits 6-0 in AL, discard bit 7.88 C3 MOV BL, AL ; Set BX to scancode: BL = ALB7 00 MOV BH, 0 ; Set BX to scancode: BH = 02E 88 27 MOV CS:[BX], AH ; Copy key status to specified address; the rest is the standard:; acknowledge interrupt; restore registers with POP and POPF; terminate interrupt execution with IRET
Code:
'$INCLUDE: 'QB.BI'DECLARE SUB memFree (segAdr AS INTEGER)DECLARE FUNCTION memAlloc% (numBytes AS LONG)DECLARE FUNCTION keyInit% ()DIM keySegm AS INTEGER, tmr AS DOUBLECLStmr = TIMER + 5keySegm = keyInit%DODEF SEG = keySegmLOCATE 1, 1FOR i% = 0 TO 128PRINT PEEK(i%);NEXT i%LOOP UNTIL (tmr < TIMER)keySegm = keyInit%FUNCTION keyInit%STATIC oldISRSeg AS INTEGER, oldISROfs AS INTEGER, newISRSeg AS INTEGERDIM regs AS RegTypeXIF (newISRSeg = 0) THEN' Reserve memory for buffer & codenewISRSeg = memAlloc%(182) ' key status buffer (129) + code (53)' Clear key strokes (starting at offset 0 of segment [newISRSeg])DEF SEG = newISRSegFOR i% = 0 TO 128POKE i%, 0NEXT i%' Write code (starting at offset 129 of segment [newISRSeg])FOR i% = 0 TO 52POKE i% + 129, VAL("&H" + MID$("FB9C505351521E560657E460B401A8807404B400247F88C3B7002E8827E4610C80E661247FE661B020E6205F075E1F5A595B589DCF", 1 + i% * 2, 2))NEXT i%' Preserve vector interrupt 9 (BIOS keyboard ISR)regs.ax = &H3509CALL INTERRUPTX(&H21, regs, regs)oldISRSeg = regs.esoldISROfs = regs.bx' Clear keyboard bufferDEF SEG = 0POKE (&H41A), PEEK(&H41C)DEF SEG' Hook custom keyboard handlerregs.ax = &H2509regs.ds = newISRSeg ' interrupt code (and buffer) memory segmentregs.dx = 129 ' interrupt code offsetCALL INTERRUPTX(&H21, regs, regs)ELSE' Restore BIOS keyboard ISRregs.ax = &H2509regs.ds = oldISRSegregs.dx = oldISROfsCALL INTERRUPTX(&H21, regs, regs)' Deallocate memory reserved for buffer & codememFree newISRSegEND IFkeyInit% = newISRSeg ' offset to key status bufferEND FUNCTION'''' QuickBASIC always reserves the largest block of memory available for'' the far heap. If we need to allocate memory for our purpose, we must'' first tell QuickBASIC to free part of that memory.''FUNCTION memAlloc% (numBytes AS LONG)DIM memReq AS INTEGER, junk AS LONG, regs AS RegTypeX' Paragraphs are groups of 16 bytesmemReq = (numBytes \ 16) - ((numBytes AND 15) > 0)' Tell QuickBASIC to free some memory (not sure why a margin is needed)junk = SETMEM(-CLNG(memReq + 1) * 16)' Use DOS Interrupt 0x48 to request <memReq> paragraphs of memoryregs.ax = &H4800regs.bx = memReqCALL INTERRUPTX(&H21, regs, regs)' If CF is not clear, something went wrongIF (regs.flags AND &H1) THENjunk = SETMEM(650000)ELSEmemAlloc% = regs.axEND IFEND FUNCTION'''' Free memory reserved via DOS Interrupt 0x21, function 0x48''SUB memFree (segAdr AS INTEGER)DIM junk AS LONG, regs AS RegTypeX' No segment specified, abortIF (segAdr = 0) THEN EXIT SUB' Free allocated memoryregs.ax = &HA900regs.es = segAdrCALL INTERRUPTX(&H21, regs, regs)' Clear segment and offsetsegAdr = 0' Give back memory to QuickBASICjunk = SETMEM(650000)END SUB
Statistics: Posted by MikeHawk — Wed Sep 01, 2021 2:44 pm