home *** CD-ROM | disk | FTP | other *** search
- UNIT MoreKeyU; {More_Keys UNIT}
- (* ==================================== *)
- (* Demonstrates a method for enabling *)
- (* handy key combinations that the BIOS *)
- (* normally throws away. *)
- (* ==================================== *)
- Interface
- USES Crt,Dos;
- (* ======================================== *)
- (* There's nothing at all in the INTERFACE *)
- (* portion of this unit. It's completely *)
- (* self-contained. The initialization *)
- (* code at the end loads the new Interrupt *)
- (* Service Routine and the ExitProc puts *)
- (* back the old interrupt. *)
- (* ======================================== *)
- Implementation
-
- VAR
- Kbd_Vec, Exit_Vec : Pointer;
-
- CONST
- ROM_Data = $0040; {Segment for ROM data about keyboard }
- KB_Flag = $0017; {Offset for shift states }
- Head = $001A; {Offset for Kbd. buffer HEAD pointer }
- Tail = $001C; {Offset for Kbd. buffer TAIL pointer }
- KeyBuf = $001E; {Offset for Keyboard buffer itself }
- BufEnd = $003E; {Offset for end of keyboard buffer }
- Kbd_Int = 9;
-
- {$I error.inc}
-
- PROCEDURE INT9_ISR(_Flags, _CS, _IP, _AX, _BX, _CX, _DX,
- _SI, _DI, _DS, _ES, _BP:word);
- INTERRUPT;
- (* ======================================= *)
- (* This ISR first checks if the <Alt> key *)
- (* is pressed and the <LeftShift> is NOT *)
- (* pressed. IF so, it grabs the scan code *)
- (* waiting in the keyboard and checks if *)
- (* it is a KEYPAD key. IF so, it clears *)
- (* the keyboard and stuffs the keyboard *)
- (* buffer with the value corresponding *)
- (* to that key combination as listed in *)
- (* Appendix K of the TURBO 3.0 manual. *)
- (* *)
- (* If none of the special cases apply, it *)
- (* is a normal key, to be given to the *)
- (* normal keyboard interrupt. *)
- (* *)
- (* Sounds complicated, but the end result *)
- (* is that you can use the <Alt>+Keypad *)
- (* combinations in a program. If you want *)
- (* <Alt><Number> combinations (e.g., to *)
- (* get char 219), you use <Alt><LeftShift> *)
- (* <Number>, just as with SuperKey. *)
- (* ======================================= *)
- BEGIN
- INLINE(
- $FB/ {STI ;Allow interrupts}
- $9C/ {PUSHF ;Save the flags}
- $1E/ {PUSH DS ;Save the Turbo DSeg}
- $E4/$60/ {IN AL,$60 ;Read the keyboard port}
- $88/$C1/ {MOV CL,AL}
- $B8/>ROM_DATA/ {MOV AX,ROM_DATA}
- $8E/$D8/ {MOV DS,AX ;Set DS to ROM_DATA segment}
- $A0/>KB_FLAG/ {MOV AL,[>KB_FLAG]}
- $A8/$08/ {TEST AL,$08 ;The 8 bit is ALT}
- $74/$14/ {JZ Norm_Key ;IF not alt, normal}
- $A8/$02/ {TEST AL,$02 ;The 2 bit is L-Shift}
- $75/$10/ {JNZ Norm_Key ;If L-shifted, normal}
- $88/$C8/ {MOV AL,CL}
- $3C/$80/ {CMP AL,$80 ;Is it a key-release?}
- $73/$0A/ {JNB Norm_Key ;If so, treat as normal}
- $3C/$47/ {CMP AL,$47 ;Below Home is normal}
- $72/$06/ {JB Norm_Key}
- $3C/$53/ {CMP AL,$53 ;Above Del is normal}
- $7F/$02/ {JG Norm_Key}
- $EB/$19/ {JMP SHORT Special_Key}
- {Norm_Key:}
- {IF it's not a special key, just CHAIN to the old interrupt}
- $1F/ {POP DS ;Restore TURBO DSeg}
- $9D/ {POPF ;Restore the flags}
- $A1/>KBD_VEC+2/ {MOV AX,[>KBD_VEC+2] ;Old vector seg to AX}
- $8B/$1E/>KBD_VEC/ {MOV BX,[>KBD_VEC] ;Old vector ofs to BX}
- $87/$5E/$0E/ {XCHG BX,[BP+$0E] ;Swap ofs w/ return address}
- $87/$46/$10/ {XCHG AX,[BP+$10] ;Swap seg w/ return address}
- $89/$EC/ {MOV SP,BP ;UNDO procedure's entry code}
- $5D/ {POP BP}
- $07/ {POP ES}
- $1F/ {POP DS}
- $5F/ {POP DI}
- $5E/ {POP SI}
- $5A/ {POP DX}
- $59/ {POP CX}
- $CB/ {RETF ;in effect, JMP to old vector}
- {Special_Key:}
- $50/ {PUSH AX ;Save the key we got}
- $E4/$61/ {IN AL,$61 ;Read Kbd controller port}
- $88/$C4/ {MOV AH,AL}
- $0C/$80/ {OR AL,$80 ;Set the "reset" bit and}
- $E6/$61/ {OUT $61,AL ; send it back to control}
- $86/$C4/ {XCHG AH,AL ;Get back control value}
- $E6/$61/ {OUT $61,AL ; and send it too}
- $58/ {POP AX}
- $04/$67/ {ADD AL,$67 ;+67h makes it SuperKey code}
- $B4/$00/ {MOV AH,+$00 ;0 for Scan Code}
- $86/$C4/ {XCHG AH,AL}
- $8B/$1E/>TAIL/ {MOV BX,[>TAIL]}
- $89/$07/ {MOV [BX],AX ;Put key in buffer}
- $81/$C3/$02/$00/ {ADD BX,+$02 ;Advance tail pointer}
- $81/$FB/>BUFEND/ {CMP BX,>BUFEND ;IF at end of buffer}
- $7C/$03/ {JL BufOK}
- $BB/>KEYBUF/ {MOV BX,>KEYBUF ; set back to beginning}
- {BufOK:}
- $89/$1E/>TAIL/ {MOV [>TAIL],BX}
- $80/$26/>KB_FLAG/$F7/ {AND BYTE PTR [>KB_FLAG],$F7}
- {Turn off ALT flag }
- $1F/ {POP DS ;Restore TURBO DSeg}
- $9D/ {POPF ;Restore the flags}
- $FA/ {CLI ;No interrupts }
- $B0/$20/ {MOV AL,+$20 ;Send an EOI to the}
- $E6/$20); {OUT $20,AL ; interrupt controller }
- END;
-
- (* ========================================== *)
- (* You _can_ end a UNIT with just an "END." *)
- (* statement, but if you end it with a *)
- (* "BEGIN..END." pair, the code between *)
- (* that pair will be executed automatically *)
- (* at the beginning of any program that *)
- (* USES the UNIT. *)
- (* ========================================== *)
- BEGIN
- CheckBreak := TRUE;
- GetIntVec(Kbd_Int, Kbd_Vec); {save "old" INT9}
- SetIntVec(Kbd_Int, @INT9_ISR); {install new}
- Exit_Vec := ExitProc; {save old ExitProc}
- ExitProc := @My_Error; {install new}
- END.