Ä Fido Pascal Conference ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ PASCAL Ä Msg : 425 of 474 From : Lou Duchez 1:157/200.0 21 Jun 93 21:16 To : Ian Lin Subj : Using esc key ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Since you seem to be talking about multiple key presses, let me repost: HOW TO RESET YOUR KEYBOARD INTERRUPT TO READ MULTIPLE KEYS - by Lou DuChez When you press/release a key on the keyboard, the "scan code" of the key is sent to port 60h of your machine (bit 0-6 specify the key; bit 7 indicates a "press" with a "0" and a release with a "1"). This triggers hardware interrupt 09h, which triggers other software interrupts and puts the appropriate keystrokes into your keyboard buffer. Ideally, you'd like to be able to read port 60h directly to get keyboard status, but unfortunately the port is reinitialized to "0" in the course of all those interrupts. So what you need to do is modify the hardware interrupt to record which keys are up/down before any of the "housekeeping" can occur. To do this, the steps you'll need to do are: 1) Store the location of the "normal" interrupt 09h routine. Declare a pointer variable called "OLDKBDINT", and execute this command: getintvec($09, oldkbdint); { make sure you've got "Uses DOS"! } 2) Write a simple interrupt handler. Just something to keep track of what keys are down. We'll keep track of them all with an "array [0..127] of boolean" called "KeyDown". Declare this array, and be sure to initialize it to all "false" before using it. (At the end of this message, I'll list the various "scan codes" for the various keys. Be patient.) Here's the new keyboard handler: procedure newkbdint; interrupt; begin keydown[port[$60] mod 128] := (port[$60] < 128); runproc(oldkbdint); mem[$0040:$001a] := mem[$0040:$001c]; inline($fb); end; Explanations: - The directive "Interrupt" is necessary so that the compiler processes this procedure properly. - The "KeyDown" line: whichever key is specified in the keyboard port, is "pressed" if the high bit is "0" and "released" if the high bit is "1". - RunProc: After reading the port, we want to process the keystroke in the "normal" way. So we "run" the "normal" keyboard interrupt routine via "RunProc". RunProc is a procedure that I cribbed from "Turbo Pascal 6.0: The Complete Reference" by Stephen O'Brien, and you really need it. Anyway, it goes like this: procedure runproc(proctorun: pointer); begin inline($9c/ { PUSHF } $ff/$5e/$06); { CALL DWORD PTR [BP+6] } end; - The "Mem" line clears the keyboard buffer. The one memory location points to the first unread character in the buffer, and the other points to the very last one. By setting them equal, the computer is fooled into thinking that the keystroke has been read. (This way, your computer won't beep incessantly after 16 keystrokes.) - InLine: I'm calling the STI instruction ("Set Interrupt Flag") to make sure the system will be able to read hardware interrupts. (Not that I turned it "off" anywhere, but a little paranoia never hurt anyone ...) Notice that I don't do much in my interrupt handler except play with memory. That makes it a pretty "crash-proof" animal. Notice also that "my" routine executes first, reading the port before that info can be lost; then, after the "normal" interrupt has had its fun, I do the "postprocessing" of clearing the keyboard buffer. 3) To invoke this new interrupt handler: setintvec($09, addr(newkbdint)); inline($fb); { another STI for good luck } 4) To reset the old interrupt handler when you end your program: setintvec($09, oldkbdint); inline($fb); { yet another STI: couldn't hurt, right? } * * * C O N T I N U E D T O N E X T M E S S A G E * * * --- * KingQWK 1.00 * As-Easy-As - the ONLY spreadsheet - download it today! --- FidoPCB v1.4 beta * Origin: PC-OHIO - The Best BBS in America (pcohio.com) (1:157/200) Ä Fido Pascal Conference ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ PASCAL Ä Msg : 426 of 474 From : Lou Duchez 1:157/200.0 21 Jun 93 21:16 To : Ian Lin Subj : Using esc key {2} ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ * * * C O N T I N U E D F R O M L A S T M E S S A G E * * * Congratulations, you now have a new keyboard handler. The whole animal should look something like this: Program FlamingCarrotRules; uses Dos; var keydown: array [0..127] of boolean; oldkbdint: pointer; cnter: byte; { just a dumb "counter" variable } {$F+} { Far calls for this "interrupt" stuff! } procedure runproc(); . . procedure newkbdint; interrupt; . . begin { main program } for cnter := 0 to 127 do keydown[cnter] := false; getintvec($09, oldkbdint); setintvec($09, addr(newkbdint)); inline($fb); . . { Your code goes here; instead of reading the keyboard buffer, } . { you check what keys are down via "KeyDown". } . setintvec($09, oldkbdint); inline($fb); end. All of this makes a very nice unit, by the way. (Just don't try to install the "new" interrupt in the initialization part of the unit: the system doesn't like that.) Another point to consider: a "Ctrl-Break" could cause your program to pop to DOS before you have a chance to restore the "normal" keyboard handler. Bad juju all around. Two approaches: 1) use CRT and set "CheckBreak" to false; or 2) write an interrupt handler for "Ctrl-Break" (interrupt 1bh). I leave it up to you to set it up. (Hint: it's very much like the above, except that your new handler should contain NO instructions -- so the system does NOTHING on a "Ctrl-Break" -- except maybe another STI ...) Finally, the scan codes (so you can actually make heads or tails of "KeyDown"). First some constants for "special" keys. const escscan: byte = $01; backscan: byte = $0e; ctrlscan: byte = $1d; lshscan: byte = $2a; capscan: byte = $3a; f1scan: byte = $3b; f2scan: byte = $3c; f3scan: byte = $3d; f4scan: byte = $3e; f5scan: byte = $3f; f6scan: byte = $40; f7scan: byte = $41; f8scan: byte = $42; f9scan: byte = $43; f10scan: byte = $44; f11scan: byte = $d9; f12scan: byte = $da; scrlscan: byte = $46; tabscan: byte = $0f; entscan: byte = $1c; rshscan: byte = $36; prtscan: byte = $37; altscan: byte = $38; homescan: byte = $47; upscan: byte = $48; pgupscan: byte = $49; minscan: byte = $4a; leftscan: byte = $4b; midscan: byte = $4c; rightscan: byte = $4d; plusscan: byte = $4e; endscan: byte = $4f; downscan: byte = $50; pgdnscan: byte = $51; insscan: byte = $52; delscan: byte = $53; numscan: byte = $45; Is the "middle key" (the "5") on the keyboard being pressed? Only if KeyDown[midscan] is "True". A couple mnemonics that might not be clear: minscan = "the minus sign on the keypad" midscan = "the middle ('5') key on the keypad" plusscan = "the plus sign on the keypad" lshscan = "the left shift key" rshscan = "the right shift key" entscan = "the enter key" In my programs, I set up an array called "ScanOf": it's an "array[' '..'~'] of byte" that returns the scan code of a key. ("What's the scan code of 'P'?" ScanOf['P']. "Is '3' currently being pressed?" Only if KeyDown[ScanOf['3']] is "True".) Here are the values: * * * C O N T I N U E D T O N E X T M E S S A G E * * * --- * KingQWK 1.00 * As-Easy-As - the ONLY spreadsheet - download it today! --- FidoPCB v1.4 beta * Origin: PC-OHIO - The Best BBS in America (pcohio.com) (1:157/200) Ä Fido Pascal Conference ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ PASCAL Ä Msg : 429 of 474 From : Lou Duchez 1:157/200.0 21 Jun 93 21:50 To : Ian Lin Subj : Using esc key {3} ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ** CONTINUED FROM A COUPLE MESSAGES AGO -- SCAN CODES!! scanof['!'] := $02; scanof['1'] := $02; scanof['@'] := $03; scanof['2'] := $03; scanof['#'] := $04; scanof['3'] := $04; scanof['$'] := $05; scanof['4'] := $05; scanof['%'] := $06; scanof['5'] := $06; scanof['^'] := $07; scanof['6'] := $07; scanof['&'] := $08; scanof['7'] := $08; scanof['*'] := $09; scanof['8'] := $09; scanof['('] := $0a; scanof['9'] := $0a; scanof[')'] := $0b; scanof['0'] := $0b; scanof['_'] := $0c; scanof['-'] := $0c; scanof['+'] := $0d; scanof['='] := $0d; scanof['Q'] := $10; scanof['q'] := $10; scanof['W'] := $11; scanof['w'] := $11; scanof['E'] := $12; scanof['e'] := $12; scanof['R'] := $13; scanof['r'] := $13; scanof['T'] := $14; scanof['t'] := $14; scanof['Y'] := $15; scanof['y'] := $15; scanof['U'] := $16; scanof['u'] := $16; scanof['I'] := $17; scanof['i'] := $17; scanof['O'] := $18; scanof['o'] := $18; scanof['P'] := $19; scanof['p'] := $19; scanof['{'] := $1a; scanof['['] := $1a; scanof['}'] := $1b; scanof[']'] := $1b; scanof['A'] := $1e; scanof['a'] := $1e; scanof['S'] := $1f; scanof['s'] := $1f; scanof['D'] := $20; scanof['d'] := $20; scanof['F'] := $21; scanof['f'] := $21; scanof['G'] := $22; scanof['g'] := $22; scanof['H'] := $23; scanof['h'] := $23; scanof['J'] := $24; scanof['j'] := $24; scanof['K'] := $25; scanof['k'] := $25; scanof['L'] := $26; scanof['l'] := $26; scanof[':'] := $27; scanof[';'] := $27; scanof['"'] := $28; scanof[''''] := $28; scanof['~'] := $29; scanof['`'] := $29; scanof['|'] := $2b; scanof['\'] := $2b; scanof['Z'] := $2c; scanof['z'] := $2c; scanof['X'] := $2d; scanof['x'] := $2d; scanof['C'] := $2e; scanof['c'] := $2e; scanof['V'] := $2f; scanof['v'] := $2f; scanof['B'] := $30; scanof['b'] := $30; scanof['N'] := $31; scanof['n'] := $31; scanof['M'] := $32; scanof['m'] := $32; scanof['<'] := $33; scanof[','] := $33; scanof['>'] := $34; scanof['.'] := $34; scanof['?'] := $35; scanof['/'] := $35; scanof[' '] := $39; I hope I have managed to explain this well -- I never can tell. But it does work, and I hope you enjoy it. I'd be eager for feedback; I intend to keep posting this whenever anyone has questions about the keyboard, and I want it to be as clear as possible. (And all of you out there: if you think this message will help someone else, feel free to repost it at will!) --- * KingQWK 1.00 * As-Easy-As - the ONLY spreadsheet - download it today! --- FidoPCB v1.4 beta * Origin: PC-OHIO - The Best BBS in America (pcohio.com) (1:157/200)