Thread View: comp.lang.modula2
7 messages
7 total messages
Started by Martin Harvey
Wed, 27 Mar 1996 16:03
Interrupt Handlers in Topspeed Modula 2 V1.17
Author: Martin Harvey
Date: Wed, 27 Mar 1996 16:03
Date: Wed, 27 Mar 1996 16:03
94 lines
3047 bytes
3047 bytes
-- Hi,
I'm trying to write an interrupt handler that intercepts the keyboard
interrupt. I've looked in the documentation that I have, and two
alternative approaches seem to appear:
1. Write the handler as a procedure.
eg.
MODULE Int
VAR KbdInt [??:??] :ADDRESS;
(*seg ofs address for keyboard interrupt vector *)
OldInt:ADDRESS;
(*$J+,C FF*) (*Save all regs, and have IRET *)
PROCEDURE Handler;
BEGIN
.....
END Handler;
(*$J-,C F0*) (*Normal procedure return conventions *)
BEGIN
OldInt:=KbdInt;
KbdInt:=ADR(Handler);
..... (*Bit of code where we want handler to work *)
KbdInt:=OldInt;
END Int.
However, there seems to be a possible way of doing it, by using the
system procedures TRANSFER and IOTRANSFER Perhaps something like this??
(excuse the likely errors here!)
MODULE Int;
VAR
Main,Handler:SYSTEM.Process;
HandlerSpace:ARRAY[0..4096] OF BYTE;
CONST
IntNo=16H;
PROCEDURE Handler;
VAR
ExRegs:SYSTEM.ExtendedRegisters;
BEGIN;
LOOP
IOTRANSFER(Handler,Main,IntNo);
ExRegs:=(SYSTEM.InterruptRegisters(Handler))^;
(* Handling Gunk down here *)
END;
END Handler;
BEGIN;
SYSTEM.NEWPROCESS(Handler,ADR(HandlerSpace),SIZE(HandlerSpace),Handler);
SYSTEM.TRANSFER(Main,Handler);
(*Code where we want all this to take effect *)
END Int.
There are several things that I can't seem to find explained very well:
If I want to write a keyboard interrupt handler, I will want to make it
so that when my procedure returns, the registers are modified as if a
call to the original handler had occured (at least most of the time,
until the right keystroke(s) are entered) how do I do this??
The First example modifies the interrupt vector table directly. If i
want to use this method, how do I calculate the address for any given
interrupt??
And lastly: which of the above is the most practical/workable?? I would
greatly appreciate a quick pointer in the right direction from someone
who has tried this before :-)
Sincerely
-------------------------------------------------------------
| Martin Harvey |
| Term Time: mch24@cam.ac.uk |
| Holidays: mch24@harvey27.demon.co.uk |
| |
| Home page: http://www.pem.cam.ac.uk:81/mch24/home.html |
-------------------------------------------------------------
Re: Interrupt Handlers in Topspeed Modula 2 V1.17
Author: "Mark Morgan Lloyd "
Date: Thu, 28 Mar 1996 13:41
Date: Thu, 28 Mar 1996 13:41
28 lines
1519 bytes
1519 bytes
> There are several things that I can't seem to find explained very well: > > If I want to write a keyboard interrupt handler, I will want to make it > so that when my procedure returns, the registers are modified as if a > call to the original handler had occured (at least most of the time, > until the right keystroke(s) are entered) how do I do this?? I've done it by inline code to modify the stack. > The First example modifies the interrupt vector table directly. If i > want to use this method, how do I calculate the address for any given > interrupt?? You don't. There's a DOS call to do this. > And lastly: which of the above is the most practical/workable?? I would > greatly appreciate a quick pointer in the right direction from someone > who has tried this before :-) I've done it in the past by hooking in a mixture of high-level and assembler, but it was not nice. I don't suggest trying IOTRANSFER or anything like that- it's not really designed for it. Mark Morgan Lloyd mark_tbu@cix.compulink.co.uk [Opinions above are the author's, not those of his employers or colleagues]
Re: Interrupt Handlers in Topspeed Modula 2 V1.17
Author: "David Collier"
Date: Thu, 28 Mar 1996 19:09
Date: Thu, 28 Mar 1996 19:09
4 lines
500 bytes
500 bytes
I've got a thing which intercepts keyboard stuff, and fiddles with it. Now set up for V3.1 though. Let me know if you want it. David.
Re: Interrupt Handlers in Topspeed Modula 2 V1.17
Author: Andrejs Jansons
Date: Sat, 30 Mar 1996 19:07
Date: Sat, 30 Mar 1996 19:07
12 lines
1002 bytes
1002 bytes
The first approach is the best in the case when you must handle interrupts
as fast as possible (e.q. some 1000-3000 int. per sec. from high-speed data
link). The second one is a "classic" way to handle interrupts in Modula-2, but
it is *MUCH SLOWER* and well suited only for no more than 100-200 int. per
sec. The amount of code executed for each interrupt in this case is almost 100
machine commands for TopSpeed Modula-2 v1.17. Of course, all mentioned above
depends from how fast CPU you use.
Andrejs.
Re: Interrupt Handlers in Topspeed Modula 2 V1.17
Author: Michel De Rosa
Date: Sat, 30 Mar 1996 22:15
Date: Sat, 30 Mar 1996 22:15
50 lines
2452 bytes
2452 bytes
Martin Harvey (mch24@harvey27.demon.co.uk) wrote: : : -- Hi, : : I'm trying to write an interrupt handler that intercepts the keyboard : interrupt. I've looked in the documentation that I have, and two : alternative approaches seem to appear: hmmm from the rest of the post, i gather you're trying to replace the BIOS call that passes information back to your program (INT 16H), and not the actual kbd handler (INT 9H, the one that interprets each key as their entered, and stores them in a buffer).. There's a big difference, one is a software interrupt, while the latter is a hardware interrupt.. And each one involves different steps, to implement... : VAR KbdInt [??:??] :ADDRESS; : (*seg ofs address for keyboard interrupt vector *) : OldInt:ADDRESS; Later you ask how to figure out the value of [??:??]... The first 1k of the x86 'real' mode memory map, is a list of interrupt addresses... each is 32-bits (seg+ofs) wide, i.e. 4bytes wide.. You therefore multiply the interrupt number by 4... for Int16H (22 Decimal), that's [0000:0058H] (or segment 0, offset 88decimal).. Like Mark Morgan Lloyd points out, tho... you'd usually use a DOS call instead (recommended for so called well-behaved programs).. Of course that won't work with the above declaration ( KbdInt [????:????] ...). : (*$J+,C FF*) (*Save all regs, and have IRET *) That line also 'partly' answers your question about setting up registers, for your return... I'm using TopSpeed v3.01, and the pragmas have changed, but i suspect you'd use a set of pragmas to define 'how/where' your results are returned.. : And lastly: which of the above is the most practical/workable?? I would : greatly appreciate a quick pointer in the right direction from someone : who has tried this before :-) For replacing Int16H i wouldn't use IOTRANSFER.. this is a completely different beast... It (iotransfer) would be more usefull for Int9H, tho.. Ciao! Michel De Rosa. aliath@nyongwa.montreal.qc.ca
Re: Interrupt Handlers in Topspeed Modula 2 V1.17
Author: Peter Moylan
Date: Sun, 31 Mar 1996 22:44
Date: Sun, 31 Mar 1996 22:44
16 lines
1056 bytes
1056 bytes
Martin Harvey (mch24@harvey27.demon.co.uk) wrote:
>-- Hi,
>I'm trying to write an interrupt handler that intercepts the keyboard
>interrupt. I've looked in the documentation that I have, and two
>alternative approaches seem to appear:
You'll find some sample code at
http://www.eng.newcastle.edu.au/ee/Moylan/m2/PMOS/PMOS.html
--
Peter Moylan peter@ee.newcastle.edu.au
http://www.eng.newcastle.edu.au/ee/Moylan.html
OS/2 freeware list at
http://www.eng.newcastle.edu.au/ee/Moylan/os2/os2info.html
Re: Interrupt Handlers in Topspeed Modula 2 V1.17
Author: Stefan Ericsson
Date: Mon, 08 Apr 1996 12:42
Date: Mon, 08 Apr 1996 12:42
510 lines
15688 bytes
15688 bytes
Martin Harvey wrote:
>
> -- Hi,
>
> I'm trying to write an interrupt handler that intercepts the keyboard
> interrupt. I've looked in the documentation that I have, and two
> alternative approaches seem to appear:
>
Hi Martin,
I wrote something that is based on some example TSR code from Topspeed and some C code that
I found some (long) time ago. Hopefully you can use something out of it.
The example code also includes a very simple test program.
The SetIntrrupt and ResetIntrrupt routines should use the DOS eqvalient instead of the
array of pointers, but this works.
Note, this code seems to fail working under Win95 (if I remember it correctly...or
maybe it was the key interrupt routine that is included in the RS232 toolkit?).
The code is however for V3.x.
Sorry for this long posting.
/Stefan
MODULE TestKey;
IMPORT IO,Lib,SYSTEM,Keyb,KeyInt;
CONST
UseKeyInt = FALSE;
VAR
r :SYSTEM.Registers;
key :CHAR;
keyrec :KeyInt.KeyRec;
key2 :Keyb.KeyRec;
stop:BOOLEAN;
ch :CHAR;
i,
sc :CARDINAL;
BEGIN
(*%F UseKeyInt *)
Keyb.Install;
(*%E *)
(*%T UseKeyInt *)
KeyInt.InstallKeyHandler;
(*%E *)
LOOP
IO.WrStr('Enter key:');
(*%F UseKeyInt *)
key2 := Keyb.RdKeyR();
IO.WrLn;
IO.WrStr('Char:');IO.WrChar( key2.char );
IO.WrStr(' ,Scan:'); IO.WrCard( key2.scan,0 );
IO.WrStr(' ,Code:'); IO.WrCard( key2.code,0 );
key := key2.char;
(*%E *)
(*%T UseKeyInt *)
WHILE NOT KeyInt.KeyPressed() DO END;
keyrec := KeyInt.RdKeyRec();
key := keyrec.char;
sc := keyrec.code;
IO.WrLn;
IO.WrStr('Char:');IO.WrChar( key ); IO.WrLn;
IO.WrStr('Scan:'); IO.WrCard( sc,0 );
(*%E *)
IO.WrLn;
IF key = CHR(27) THEN
EXIT;
END;
END;
(*%F UseKeyInt *)
Keyb.Uninstall;
(*%E *)
(*%T UseKeyInt *)
KeyInt.DeinstallKeyHandler;
(*%E *)
END TestKey.
DEFINITION MODULE KeyInt;
(*# check(stack=>off,index=>off,range=>off,overflow=>off,nil_ptr=>off) *)
(*# debug(vid=>off)*)
IMPORT Key;
(*
This module contains a replacement for the system
keyboard handler.
*)
CONST
QueueLength = 32;
TYPE
KeyFlagSet = SET OF ( RShift,LShift,Ctrl,Alt,Scroll,Num,Caps,Ins,Shift ) ;
KeyRec = RECORD
char : CHAR;
code : CARDINAL;
flags: KeyFlagSet;
END;
VAR
(*# save, data(volatile=>on) *)
isInstalled : BOOLEAN;
useOldKeyIntr : BOOLEAN; (* FALSE on setup *)
SysRequest : BOOLEAN; (* If SysReq has benn pressed *)
CtrlAltDel : BOOLEAN; (* If CtrlAltDel has been pressed *)
CtrlBreak : BOOLEAN; (* If CtrlBreak has been pressed *)
CtrlC : BOOLEAN; (* If CtrlC has been pressed *)
CtrlAltPressed : BOOLEAN; (* If CtrlAlt has been pressed *)
FuncKeyPressed : BOOLEAN; (* If some function key has been pressed *)
MoveKeyPressed : BOOLEAN; (* If Left/Right/Down or Up is pressed *)
KeyFlags : KeyFlagSet; (* Usefully key flags *)
lastKeyPress : CARDINAL; (* the last key pressed, use Key.Def *)
lastKey : KeyRec; (* the last key pressed *)
currKey : KeyRec; (* the current pressed key *)
(*# restore *)
PROCEDURE InstallKeyHandler;
PROCEDURE DeinstallKeyHandler;
PROCEDURE ClearKey( scan:CARDINAL ); (* If key is pressed *)
PROCEDURE SetKey( scan :CARDINAL ); (* Set key as pressed *)
PROCEDURE TestKey( scan :CARDINAL ):BOOLEAN; (* Test if key pressed *)
PROCEDURE ResetKey( scan :CARDINAL ); (* Set pressed := pressing *)
PROCEDURE GetLastKey():CARDINAL;
PROCEDURE ClearLastKey;
PROCEDURE ClrKeyBuff;
PROCEDURE RdKey():CHAR;
PROCEDURE RdKeyRec():KeyRec;
PROCEDURE RdKeyFlags():KeyFlagSet;
PROCEDURE KeyPressed():BOOLEAN;
PROCEDURE WaitEsc;
END KeyInt.
IMPLEMENTATION MODULE KeyInt;
(*# check(stack=>off,index=>off,range=>off,overflow=>off,nil_ptr=>off) *)
(*# debug(vid=>off)*)
(*# debug(line_num=>on) *)
IMPORT SYSTEM, Lib;
CONST
(*KBFuseful = KBFlagSet { RShift, LShift, Ctrl, Alt } ;*)
NumKeys = 128;
NumChars = 128;
(*QueueLength = 32;*)
TYPE
CharType = ARRAY [0..NumChars-1] OF CHAR;
(*KeyFlagSet = SET OF ( RShift,LShift,Ctrl,Alt,Scroll,Num,Caps,Ins,Shift ) ;*)
KeySetRec = RECORD
pressed : BOOLEAN;
pressing : BOOLEAN;
END;
KeySet = ARRAY [0..NumKeys-1] OF KeySetRec;
(*
KeyRec = RECORD
char : CHAR;
code : CARDINAL;
flags: KeyFlagSet;
END;
*)
QueueType = ARRAY [0..QueueLength-1] OF KeyRec;
VAR
Continue : PROC;
CapitalKeys : CharType;
(*# save, data(volatile=>on) *)
(*
isInstalled : BOOLEAN;
useOldKeyIntr : BOOLEAN; (* FALSE on setup *)
SysRequest : BOOLEAN; (* If SysReq has benn pressed *)
CtrlAltDel : BOOLEAN; (* If CtrlAltDel has been pressed *)
CtrlBreak : BOOLEAN; (* If CtrlBreak has been pressed *)
CtrlC : BOOLEAN; (* If CtrlC has been pressed *)
CtrlAltPressed : BOOLEAN; (* If CtrlAlt has been pressed *)
FuncKeyPressed : BOOLEAN; (* If some function key has been pressed *)
MoveKeyPressed : BOOLEAN; (* If Left/Right/Down or Up is pressed *)
KeyFlags : KeyFlagSet; (* Usefully key flags *)
lastKeyPress : CARDINAL; (* the last key pressed, use Key.Def *)
lastKey : KeyRec; (* the last key pressed *)
currKey : KeyRec; (* the current pressed key *)
count : CARDINAL; (* debug *)
*)
scanCode : CARDINAL; (* the key scan code *)
keys : KeySet; (* the key array, faster access *)
queueCount : CARDINAL; (* count of keys in queue *)
queue : QueueType; (* the circular key queue *)
head : CARDINAL; (* head queue pointer *)
tail : CARDINAL; (* tail queue pointer *)
(*# restore *)
PROCEDURE ConvertToChar( scan :CARDINAL ):KeyRec;
VAR key :KeyRec;
BEGIN
key.char := 0C;
key.flags := KeyFlags;
CASE scan OF
| 1 : key.code := 27; key.char := CHR(27);
| 15 : key.code := 9; key.char := CHR(9);
| 57 : key.code := 32; key.char := ' ';
| 28 : key.code := 13; key.char := CHR(13);
| 114 : SysRequest := TRUE;
key.code := scan + Key.Extended;
| 58..68,
87..88 : FuncKeyPressed := TRUE;
key.code := scan + Key.Extended;
| 72,75,
77,80 : MoveKeyPressed := TRUE;
key.code := scan + Key.Extended;
| 71,73,74,78,82,83,
79,81 : key.code := scan + Key.Extended;
ELSE
key.char := CapitalKeys[scan];
key.code := scan;
END;
RETURN key;
END ConvertToChar;
(* Interrupt Handlers *)
(* ================== *)
(* pragmas for interrupt handler *)
(*# save,
call(interrupt => on,
reg_param => (),
same_ds => off
)
*)
TYPE
IPROC = PROCEDURE();
VAR
Irpt[0:0], (* Interrupt table *)
SaveIrpt : ARRAY [0..255] OF IPROC ;
PROCEDURE Int9 (); (* Keyboard H/W interrupt *)
VAR
scan,status : SHORTCARD ;
key : CHAR;
BEGIN
IF useOldKeyIntr THEN
SaveIrpt[09H](); (* Call old key interrupt instead *)
ELSE
scan := SYSTEM.In(60H) ; (* Read scan code *)
status := SYSTEM.In(61H) ; (* Read status *)
SYSTEM.Out(61H,SHORTCARD(BITSET(status)+{7})); (* Send acknowledge *)
SYSTEM.Out(61H,status); (* Restore status *)
IF scan >= 128
THEN scanCode := CARDINAL(scan) - 128;
ELSE scanCode := CARDINAL(scan);
END;
(* Set the key flags *)
IF scan < 128 THEN (* key pressed *)
lastKeyPress := scanCode;
keys[scanCode].pressed := TRUE;
keys[scanCode].pressing := TRUE;
IF scanCode = 42 THEN (* left shift *)
KeyFlags := KeyFlags + KeyFlagSet{LShift};
KeyFlags := KeyFlags + KeyFlagSet{Shift};
ELSIF scanCode = 54 THEN (* right shift *)
KeyFlags := KeyFlags + KeyFlagSet{RShift};
KeyFlags := KeyFlags + KeyFlagSet{Shift};
ELSIF scanCode = 58 THEN KeyFlags := KeyFlags + KeyFlagSet{Caps};
ELSIF scanCode = 29 THEN KeyFlags := KeyFlags + KeyFlagSet{Ctrl};
ELSIF scanCode = 56 THEN KeyFlags := KeyFlags + KeyFlagSet{Alt};
ELSIF scanCode = 69 THEN (* num lock *)
IF Num IN KeyFlags
THEN KeyFlags := KeyFlags - KeyFlagSet{Num};
ELSE KeyFlags := KeyFlags + KeyFlagSet{Num};
END;
ELSIF scanCode = 70 THEN (* scroll lock *)
IF Scroll IN KeyFlags
THEN KeyFlags := KeyFlags - KeyFlagSet{Scroll};
ELSE KeyFlags := KeyFlags + KeyFlagSet{Scroll};
END;
ELSIF scanCode = 82 THEN (* insert key *)
IF Ins IN KeyFlags
THEN KeyFlags := KeyFlags - KeyFlagSet{Ins};
ELSE KeyFlags := KeyFlags + KeyFlagSet{Ins};
END;
END;
(* Check for important keys *)
IF Ctrl IN KeyFlags THEN
IF Alt IN KeyFlags THEN
CtrlAltPressed := TRUE;
IF scanCode=83 THEN CtrlAltDel := TRUE END; (* restart keys *)
ELSIF scanCode=46 THEN
CtrlC := TRUE;
END;
END;
(* Convert the scan code *)
lastKey := currKey;
currKey := ConvertToChar( scanCode );
IF queueCount < QueueLength THEN
queue[tail].char := currKey.char;
queue[tail].code := currKey.code;
queue[tail].flags := currKey.flags;
tail := (tail+1) MOD QueueLength;
INC(queueCount);
END;
ELSE (* key is released *)
keys[scanCode].pressing := FALSE;
IF scanCode = 42 THEN
KeyFlags := KeyFlags - KeyFlagSet{LShift};
ELSIF scanCode = 54 THEN
KeyFlags := KeyFlags - KeyFlagSet{RShift};
ELSIF scanCode = 29 THEN KeyFlags := KeyFlags - KeyFlagSet{Ctrl};
ELSIF scanCode = 56 THEN KeyFlags := KeyFlags - KeyFlagSet{Alt};
END;
IF NOT (RShift IN KeyFlags) AND NOT (LShift IN KeyFlags) THEN
KeyFlags := KeyFlags - KeyFlagSet{Shift};
END;
END;
SYSTEM.Out(20H,20H); (* Send EOI to timer *)
END; (* use old key interrupt *)
END Int9;
PROCEDURE Int1C () ; (* Timer Interrupt *)
VAR
base : CARDINAL ;
BEGIN
SaveIrpt[1CH]() ; (* Chain Int 1C *)
END Int1C ;
PROCEDURE Int24 () : CARDINAL ; (* Critical Error Interrupt *)
BEGIN
RETURN 0 ;
END Int24;
(*# restore *)
PROCEDURE SetIntr ( N : CARDINAL ; P : IPROC ) ;
VAR
fl : CARDINAL ;
BEGIN
fl := SYSTEM.GetFlags();
SYSTEM.DI;
SaveIrpt[N] := Irpt[N];
Irpt[N] := P;
SYSTEM.SetFlags(fl);
SYSTEM.EI;
END SetIntr ;
PROCEDURE ResetIntr ( N : CARDINAL ) ;
VAR
fl : CARDINAL;
BEGIN
fl := SYSTEM.GetFlags();
SYSTEM.DI;
Irpt[N] := SaveIrpt[N];
SYSTEM.SetFlags(fl);
SYSTEM.EI;
END ResetIntr ;
PROCEDURE ClrKeyBuff;
VAR
i :CARDINAL;
BEGIN
SYSTEM.DI;
head := 0;
tail := 0;
queueCount := 0;
FuncKeyPressed := FALSE;
MoveKeyPressed := FALSE;
CtrlC := FALSE;
CtrlBreak := FALSE;
CtrlAltDel := FALSE;
CtrlAltPressed := FALSE;
lastKey.char := 0C;
lastKey.code := 0;
lastKey.flags := KeyFlagSet{};
currKey.char := 0C;
currKey.code := 0;
currKey.flags := KeyFlagSet{};
FOR i:=0 TO NumKeys-1 DO
keys[i].pressed := FALSE;
keys[i].pressing := FALSE;
END;
SYSTEM.EI;
END ClrKeyBuff;
PROCEDURE ClearKey( scan:CARDINAL ); (* If key is pressed *)
BEGIN
IF scan < NumKeys-1 THEN
SYSTEM.DI;
keys[scan].pressed := FALSE;
SYSTEM.EI;
END;
END ClearKey;
PROCEDURE SetKey( scan :CARDINAL ); (* Set key as pressed *)
BEGIN
IF scan < NumKeys-1 THEN
SYSTEM.DI;
keys[scan].pressed := TRUE;
SYSTEM.EI;
END;
END SetKey;
PROCEDURE TestKey( scan :CARDINAL ):BOOLEAN; (* Test if key pressed *)
BEGIN
IF scan < NumKeys-1 THEN
RETURN (keys[scan].pressed = TRUE);
END;
END TestKey;
PROCEDURE ResetKey( scan :CARDINAL ); (* Set pressed := pressing *)
BEGIN
IF scan < NumKeys-1 THEN
SYSTEM.DI;
keys[scan].pressed := keys[scan].pressing;
SYSTEM.EI;
END;
END ResetKey;
PROCEDURE GetLastKey():CARDINAL;
BEGIN
RETURN lastKeyPress;
END GetLastKey;
PROCEDURE ClearLastKey;
BEGIN
lastKeyPress := 0;
END ClearLastKey;
PROCEDURE RdKeyRec():KeyRec;
VAR key :KeyRec;
BEGIN
IF queueCount > 0 THEN
key := queue[head];
head := (head+1) MOD QueueLength;
DEC(queueCount);
ELSE
key.char := 0C;
key.code := 0;
key.flags := KeyFlags;
END;
RETURN key;
END RdKeyRec;
PROCEDURE RdKey():CHAR;
VAR key :KeyRec;
BEGIN
key := RdKeyRec();
RETURN key.char;
END RdKey;
PROCEDURE RdKeyFlags():KeyFlagSet;
BEGIN
RETURN KeyFlags;
END RdKeyFlags;
PROCEDURE WaitEsc;
VAR key :KeyRec;
BEGIN
ClrKeyBuff;
LOOP
key := RdKeyRec();
IF key.code = Key.Escape THEN EXIT END;
END;
END WaitEsc;
PROCEDURE KeyPressed():BOOLEAN;
BEGIN
RETURN (queueCount # 0);
END KeyPressed;
PROCEDURE TermProc;
BEGIN
IF isInstalled THEN
ResetIntr( 09H );
END;
Continue();
END TermProc;
PROCEDURE InstallKeyHandler;
BEGIN
ClrKeyBuff;
useOldKeyIntr := FALSE;
isInstalled := TRUE;
SetIntr( 09H, Int9 );
Lib.Terminate(TermProc,Continue);
END InstallKeyHandler;
PROCEDURE DeinstallKeyHandler;
BEGIN
ResetIntr( 09H );
ClrKeyBuff;
useOldKeyIntr := TRUE;
isInstalled := FALSE;
END DeinstallKeyHandler;
VAR
i :CARDINAL;
BEGIN
isInstalled := FALSE;
useOldKeyIntr := TRUE;
lastKeyPress := 0;
FOR i:=0 TO NumChars-1 DO CapitalKeys[i]:=' ' END;
CapitalKeys :=
' 1234567890+ QWERTYUIOP ASDFGHJKL ZXCVBNM,.- 789 456+1230';
ClrKeyBuff;
END KeyInt.
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads