🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

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
#3427
Author: Martin Harvey
Date: Wed, 27 Mar 1996 16:03
94 lines
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
#3431
Author: "Mark Morgan Lloyd "
Date: Thu, 28 Mar 1996 13:41
28 lines
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
#3433
Author: "David Collier"
Date: Thu, 28 Mar 1996 19:09
4 lines
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
#3439
Author: Andrejs Jansons
Date: Sat, 30 Mar 1996 19:07
12 lines
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
#3442
Author: Michel De Rosa
Date: Sat, 30 Mar 1996 22:15
50 lines
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
#3443
Author: Peter Moylan
Date: Sun, 31 Mar 1996 22:44
16 lines
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
#3460
Author: Stefan Ericsson
Date: Mon, 08 Apr 1996 12:42
510 lines
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