1 ; THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
2 ; SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
3 ; END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
4 ; ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
5 ; IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
6 ; SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
7 ; FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
8 ; CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
9 ; AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
10 ; COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
11 ; $Log: not supported by cvs2svn $
12 ; Revision 1.2 1994/02/17 15:55:59 john
15 ; Revision 1.20 1994/01/18 10:58:55 john
16 ; *** empty log message ***
18 ; Revision 1.19 1993/12/22 13:28:40 john
19 ; Added back changes Matt made in r1.14
21 ; Revision 1.18 1993/12/22 13:18:32 john
22 ; *** empty log message ***
24 ; Revision 1.17 1993/12/20 16:48:47 john
25 ; Put cli/sti around clear keybuffer in key_close
27 ; Revision 1.16 1993/12/20 15:39:13 john
28 ; Tried to neaten handler code... also, moved some cli's and sti's around
29 ; trying to find bug. Made the code call key_get_milliseconds instead
30 ; of timer_get_milliseconds, because we don't want the cli and sti
31 ; stuff in the interrupt handler.
33 ; Revision 1.15 1993/12/02 10:54:48 john
34 ; Made the Ctrl,Shift,Alt keys buffer like all the other keys.
36 ; Revision 1.14 1993/10/29 11:25:18 matt
37 ; Made key_down_time() not accumulate time if shift,alt,ctrl down
39 ; Revision 1.13 1993/10/29 10:47:00 john
40 ; *** empty log message ***
42 ; Revision 1.12 1993/10/16 19:24:16 matt
43 ; Added new function key_clear_times() & key_clear_counts()
45 ; Revision 1.11 1993/10/15 10:16:49 john
46 ; bunch of stuff, mainly with detecting debugger.
48 ; Revision 1.10 1993/10/04 13:25:57 john
49 ; Changed the way extended keys are processed.
51 ; Revision 1.9 1993/09/28 11:35:32 john
54 ; Revision 1.8 1993/09/23 18:09:23 john
55 ; fixed bug checking for DBG
57 ; Revision 1.7 1993/09/23 17:28:01 john
58 ; made debug check look for DBG> instead of CONTROL
60 ; Revision 1.6 1993/09/20 17:08:19 john
61 ; Made so that keys pressed in debugger don't get passed through to
62 ; the keyboard handler. I also discovered, but didn't fix a error
63 ; (page fault) caused by jumping back and forth between the debugger
66 ; Revision 1.5 1993/09/17 09:58:12 john
67 ; Added checks for already installed, not installed, etc.
69 ; Revision 1.4 1993/09/15 17:28:00 john
70 ; Fixed bug in FlushBuffer that used CX before a REP instead of ECX.
72 ; Revision 1.3 1993/09/08 14:48:00 john
73 ; made getch() return an int instead of a char that has shift states, etc.
75 ; Revision 1.2 1993/07/22 13:12:23 john
79 ; Revision 1.1 1993/07/10 13:10:42 matt
85 ;***************************************************************************
86 ;***************************************************************************
89 ;***** K E Y . A S M *****
91 ;***** Contains routines to get, buffer, and check key presses. *****
94 ;***** PROCEDURES *****
96 ;***** key_init() - Activates the keyboard package. *****
97 ;***** key_close() - Deactivates the keyboard package. *****
98 ;***** key_check() - Returns 1 if a buffered key is waiting. *****
99 ;***** key_getch() - Waits for and returns a buffered keypress. *****
100 ;***** key_flush() - Clears buffers and state array. *****
101 ;***** key_time() - Index by scan code. Contains the time key has been *****
102 ;***** held down. NOT DONE YET. *****
105 ;***** VARIABLES *****
107 ;***** keyd_buffer_type -Set to 0 and key_getch() always returns 0. *****
108 ;***** Set to 1 to so that ASCII codes are returned *****
109 ;***** by key_getch(). Set to 2 and key_getch() returns*****
110 ;***** the buffered keyboard scan codes. *****
111 ;***** keyd_repeat - Set to 0 to not allow repeated keys in the *****
112 ;***** keyboard buffer. Set to 1 to allow repeats. *****
113 ;***** keyd_pressed[] -Index by scan code. Contains 1 if key down else 0*****
116 ;***** CONSTANTS *****
118 ;***** Setting the DEBUG to 1 at compile time passes SysReq through *****
119 ;***** to the debugger, and when the debugger is active, it will give *****
120 ;***** the debugger any keys that are pressed. Note that this only *****
121 ;***** works with the Watcom VIDEO debugger at this time. Setting *****
122 ;***** DEBUG to 0 takes out all the debugging stuff. *****
124 ;***************************************************************************
125 ;***************************************************************************
130 ;************************************************************************
131 ;**************** FLAT MODEL DATA SEGMENT STUFF *************************
132 ;************************************************************************
134 _DATA SEGMENT BYTE PUBLIC USE32 'DATA'
136 rcsid db "$Id: oldkey.asm,v 1.1.1.2 2001-01-19 03:33:50 bradleyb Exp $"
138 PUBLIC _keyd_pressed ; Must start with a _ so C can see the variable.
140 _keyd_pressed db 256 dup (?)
142 keybuffer dw 256 dup (?) ; Use 256 so an inc wraps around
144 TimeKeyWentDown dd 256 dup(0)
145 TimeKeyHeldDown dd 256 dup(0)
146 NumDowns dd 256 dup(0)
151 PUBLIC _keyd_editor_mode
153 _keyd_editor_mode db 0
155 PUBLIC _keyd_use_bios
159 PUBLIC _keyd_last_pressed
160 _keyd_last_pressed db 0
161 PUBLIC _keyd_last_released
162 _keyd_last_released db 0
164 PUBLIC _keyd_dump_key_array
165 _keyd_dump_key_array db 0
174 PUBLIC _keyd_buffer_type
176 _keyd_buffer_type db ? ; 0=No buffer, 1=buffer ASCII, 2=buffer scans
191 ;************************************************************************
192 ;**************** FLAT MODEL CODE SEGMENT STUFF *************************
193 ;************************************************************************
195 _TEXT SEGMENT BYTE PUBLIC USE32 'CODE'
200 key_get_milliseconds:
201 EXTERNDEF timer_get_stamp64:NEAR
206 call timer_get_stamp64
208 ; Timing in milliseconds
209 ; Can be used for up to 1000 hours
210 shld edx, eax, 21 ; Keep 32+11 bits
212 mov ebx, 2502279823 ; 2^21*1193180/1000
220 ;************************************************************************
221 ;************************************************************************
223 ;***** K E Y _ T O _ A S C I I _ *****
225 ;************************************************************************
226 ;************************************************************************
243 and ah, 01b ; take away ctrl and alt codes
247 mov al, byte ptr key1[eax]
257 public key_clear_times_,key_clear_counts_
259 ;clear the array of key down times.
267 lea edi,TimeKeyHeldDown
268 rep stosd ;clear array
275 ;clear the arrays of key down counts
284 rep stosd ;clear array
287 rep stosd ;clear array
295 PUBLIC key_down_time_
308 cmp _keyd_pressed[ebx], 0
312 cmp _keyd_editor_mode, 0
315 call get_modifiers ;shift,alt,ctrl?
321 read_time: mov ecx, TimeKeyWentDown[ebx*4]
322 call key_get_milliseconds
323 mov TimeKeyWentDown[ebx*4], eax
324 sub eax, ecx ; EAX = time held since last
327 add eax, TimeKeyHeldDown[ebx*4]
328 mov TimeKeyHeldDown[ebx*4], 0
336 PUBLIC key_down_count_
341 mov eax, NumDowns[ebx*4]
342 mov NumDowns[ebx*4], 0
352 mov eax, NumUps[ebx*4]
360 ;************************************************************************
361 ;************************************************************************
363 ;***** K E Y _ F L U S H *****
365 ;************************************************************************
366 ;************************************************************************
381 ; Clear the keyboard array
382 mov edi, offset _keyd_pressed
393 ;************************************************************************
394 ;************************************************************************
396 ;***** K E Y _ I N I T *****
398 ;************************************************************************
399 ;************************************************************************
409 ;**************************************************************
410 ;******************* INITIALIZE key QUEUE **********************
411 ;**************************************************************
413 mov _keyd_buffer_type,1
417 ; Clear the keyboard array
423 ;**************************************************************
424 ;******************* SAVE OLD INT9 HANDLER ********************
425 ;**************************************************************
429 mov eax, 03509h ; DOS Get Vector 09h
431 mov org_int_sel, es ; Save old interrupt selector
432 mov org_int_off, ebx ; Save old interrupt offset
435 ;**************************************************************
436 ;***************** INSTALL NEW INT9 HANDLER *******************
437 ;**************************************************************
439 mov eax, 02509h ; DOS Set Vector 09h
440 mov edx, offset key_handler ; Point DS:EDX to new handler
442 mov MyCodeSegment, bx
457 ;************************************************************************
458 ;************************************************************************
460 ;***** K E Y _ C L O S E _ *****
462 ;************************************************************************
463 ;************************************************************************
477 ;**************************************************************
478 ;***************** RESTORE OLD INT9 HANDLER *******************
479 ;**************************************************************
483 ; Clear the BIOS buffer
486 mov al, byte ptr [ebx]
488 mov byte ptr [ebx], al
491 mov eax, 02509h ; DOS Set Vector 09h
503 ;************************************************************************
504 ;************************************************************************
506 ;***** K E Y _ C H E C K _ *****
508 ;************************************************************************
509 ;************************************************************************
511 PUBLIC key_checkch_ ; Must end with a _ so C can see the function.
531 ;************************************************************************
532 ;************************************************************************
534 ;***** K E Y _ D E B U G *****
536 ;************************************************************************
537 ;************************************************************************
545 ;************************************************************************
546 ;************************************************************************
548 ;***** K E Y _ G E T C H _ *****
550 ;************************************************************************
551 ;************************************************************************
553 PUBLIC key_getch_ ; Must end with a _ so C can see the function.
566 cli ; Critical section
573 cli ; Critical section
576 mov ax, word ptr keybuffer[ebx*2]
584 ;************************************************************************
585 ;************************************************************************
587 ;***** K E Y _ I N K E Y _ *****
589 ;************************************************************************
590 ;************************************************************************
592 PUBLIC key_inkey_ ; Must end with a _ so C can see the function.
603 cli ; Critical section
610 cli ; Critical section
612 mov ax, word ptr keybuffer[ebx*2]
619 PUBLIC key_peekkey_ ; Must end with a _ so C can see the function.
627 cli ; Critical section
636 mov ax, word ptr keybuffer[ebx*2]
644 ;************************************************************************
645 ;************************************************************************
647 ;***** K E Y _ H A N D L E R *****
649 ;************************************************************************
650 ;************************************************************************
652 PUBLIC key_handler ; Must end with a _ so C can see the function.
656 pushfd ; Save flags in case we have to chain to original
663 mov ax, DGROUP ; Point to our data segment, since this is an
664 mov ds, ax ; interrupt and we don't know where we were.
666 mov eax, (0b0000h+76*2)
667 mov byte ptr [eax], '1'
670 call CheckForDebugger
672 mov eax, 0b0000h+78*2
673 mov byte ptr [eax], 'D'
674 jmp PassToBios ; If debugger is active, then skip buffer
676 @@: mov eax, 0b0000h+78*2
677 mov byte ptr [eax], 'I'
679 ; Clear the BIOS buffer
681 ;**mov al, byte ptr [ebx]
683 ;**mov byte ptr [ebx], al
689 in al, 060h ; Get scan code from keyboard
694 E0Code: mov E0Flag, 010000000b
695 jmp LeaveHandler ; If garbage key, then don't buffer it
697 NotE0Code: mov bl, al ; Put break bit into bl ; 0 = pressed, 1=released
698 and al, 01111111b ; AL = scancode
699 or al, E0Flag ; AL = extended scancode
700 mov E0Flag,0 ; clear E0 flag
703 shl bl, 1 ; put upper bit into carry flag
704 jc key_mark_released ; if upper bit of bl was set, then it was a release code
706 ;**************************************************************
707 ;****************** HANDLE A NEWLY PRESSED KEY ****************
708 ;**************************************************************
709 ;Marks the key press in EAX in the scancode array.
712 ;cmp al, 0eh ; backspace
715 mov _keyd_last_pressed, al
716 ; Check if the key is repeating or if it just got pressed.
717 cmp byte ptr _keyd_pressed[eax], 1
720 ;------------------------------- Code for a key pressed for the first time ------------------------
721 mov byte ptr _keyd_pressed[eax], 1
726 call key_get_milliseconds
729 mov TimeKeyWentDown[eax*4], edx
736 ;------------------------------- Code for a key that is already pressed ------------------------
739 je DoneMarkingPressed
742 cmp _keyd_buffer_type, 0
743 je SkipBuffer ; Buffer = 0 means don't buffer anything.
745 cmp al, 0AAh ; garbage key
748 call get_modifiers ;returns ah
755 ; If the buffer is full then don't buffer this key
760 mov word ptr keybuffer[ebx*2], ax
765 ;---------------------------------- Exit function -----------------------------
769 ;**************************************************************
770 ;******************* HANDLE A RELEASED KEY ********************
771 ;**************************************************************
772 ; Unmarks the key press in EAX from the scancode array.
775 mov _keyd_last_released, al
776 mov byte ptr _keyd_pressed[eax], 0
779 cmp _keyd_editor_mode, 0
784 or ah,ah ;check modifiers
791 call timer_get_stamp64
793 ; Timing in milliseconds
794 ; Can be used for up to 1000 hours
795 shld edx, eax, 21 ; Keep 32+11 bits
797 mov ebx, 2502279823 ; 2^21*1193180/1000
802 sub edx, TimeKeyWentDown[eax*4]
803 add TimeKeyHeldDown[eax*4], edx
805 skip_time: ;**jmp LeaveHandler
807 ;**************************************************************
808 ;*************** FINISH UP THE KEYBOARD INTERRUPT *************
809 ;**************************************************************
811 mov eax, (0b0000h+76*2)
812 mov byte ptr [eax], '2'
814 ;; cmp _keyd_dump_key_array, 0
821 showdown: mov al, _keyd_pressed[ebx]
823 mov [ebx*2+ 0b0000h], al
828 mov byte ptr [ eax+(036h*2+1) ], 070h
829 mov byte ptr [ eax+(02Ah*2+1) ], 070h
830 mov byte ptr [ eax+(038h*2+1) ], 070h
831 mov byte ptr [ eax+(0B8h*2+1) ], 070h
832 mov byte ptr [ eax+(01Dh*2+1) ], 070h
833 mov byte ptr [ eax+(09dh*2+1) ], 070h
835 mov byte ptr [ eax+(0AAh*2+1) ], 07Fh
836 mov byte ptr [ eax+(0E0h*2+1) ], 07Fh
841 ; If in debugger, pass control to dos interrupt.
843 PassToBios: pop ds ; Nothing left on stack but flags
849 sub esp, 8 ; Save space for IRETD frame
850 push ds ; Save registers we use.
853 mov ds, ax ; Set DS to our data segment
854 mov eax, org_int_off ; put original handler address
855 mov [esp+8], eax ; in the IRETD frame
856 movzx eax, org_int_sel
858 pop eax ; Restore registers
860 iretd ; Chain to previous handler
863 in al, 61h ; Get current port 61h state
864 or al, 10000000b ; Turn on bit 7 to signal clear keybrd
865 out 61h, al ; Send to port
866 and al, 01111111b ; Turn off bit 7 to signal break
867 out 61h, al ; Send to port
868 mov al, 20h ; Reset interrupt controller
870 sti ; Reenable interrupts
872 pop edx ; Restore all of the saved registers.
877 sub esp, 8 ; Save space for IRETD frame
878 push ds ; Save registers we use.
881 mov ds, ax ; Set DS to our data segment
882 mov eax, org_int_off ; put original handler address
883 mov [esp+8], eax ; in the IRETD frame
884 movzx eax, org_int_sel
886 pop eax ; Restore registers
889 iretd ; Interrupt must return with IRETD
893 ; Resets the keyboard, PIC, restores stack, returns.
894 in al, 61h ; Get current port 61h state
895 or al, 10000000b ; Turn on bit 7 to signal clear keybrd
896 out 61h, al ; Send to port
897 and al, 01111111b ; Turn off bit 7 to signal break
898 out 61h, al ; Send to port
899 mov al, 20h ; Reset interrupt controller
901 sti ; Reenable interrupts
903 pop edx ; Restore all of the saved registers.
908 iretd ; Interrupt must return with IRETD
910 ;returns ah=bitmask of shift,ctrl,alt keys
911 get_modifiers: push ecx
915 ; Check the shift keys
916 mov cl, _keyd_pressed[ 036h ]
917 or cl, _keyd_pressed[ 02ah ]
921 mov cl, _keyd_pressed[ 038h ]
922 or cl, _keyd_pressed[ 0b8h ]
927 mov cl, _keyd_pressed[ 01dh ]
928 or cl, _keyd_pressed[ 09dh ]
937 ; Returns CF=0 if debugger isn't active
938 ; CF=1 if debugger is active
940 ;*************************** DEBUG ******************************
941 ; When we're in the VIDEO debugger, we want to pass control to
942 ; the original interrupt. So, to tell if the debugger is active,
943 ; I check if video page 1 is the active page since that is what
944 ; page the debugger uses, and if that works, I check the top of
945 ; the screen to see if the texxt "Control" is there, which should
946 ; only be there when we're in the debugger.
951 ;mov eax, 0462h ; Address 0462 stores BIOS current page
952 ;cmp BYTE PTR [eax], 1
953 ;jne NoDebuggerOnColor
954 ;mov eax, 0b8000h+4096 ; 4096 = offset to 2nd video mem page
955 ;cmp BYTE PTR [eax+2],'C'
956 ;jne NoDebuggerOnColor
957 ;cmp BYTE PTR [eax+4],'o'
958 ;jne NoDebuggerOnColor
959 ;cmp BYTE PTR [eax+6],'n'
960 ;jne NoDebuggerOnColor
961 ;cmp BYTE PTR [eax+8],'t'
962 ;jne NoDebuggerOnColor
963 ;cmp BYTE PTR [eax+10],'r'
964 ;jne NoDebuggerOnColor
965 ;cmp BYTE PTR [eax+12],'o'
966 ;jne NoDebuggerOnColor
967 ;cmp BYTE PTR [eax+14],'l'
968 ;jne NoDebuggerOnColor
971 ; First, see if there is a mono debugger...
973 ;mov eax, 0b0000h ; 4096 = offset to mono video mem
974 ;cmp BYTE PTR [eax+2],'C'
975 ;jne NoActiveDebugger
976 ;cmp BYTE PTR [eax+4],'o'
977 ;jne NoActiveDebugger
978 ;cmp BYTE PTR [eax+6],'n'
979 ;jne NoActiveDebugger
980 ;cmp BYTE PTR [eax+8],'t'
981 ;jne NoActiveDebugger
982 ;cmp BYTE PTR [eax+10],'r'
983 ;jne NoActiveDebugger
984 ;cmp BYTE PTR [eax+12],'o'
985 ;jne NoActiveDebugger
986 ;cmp BYTE PTR [eax+14],'l'
987 ;jne NoActiveDebugger
989 mov eax, 0b0000h ; 4096 = offset to mono video mem
993 cmp BYTE PTR [eax+0],'D'
995 cmp BYTE PTR [eax+2],'B'
997 cmp BYTE PTR [eax+4],'G'
999 cmp BYTE PTR [eax+6],'>'
1002 ;Found DBG>, so consider debugger active:
1006 cmp BYTE PTR [eax+14],'<'
1008 cmp BYTE PTR [eax+16],'i'
1010 cmp BYTE PTR [eax+18],'>'
1012 cmp BYTE PTR [eax+20],' '
1014 cmp BYTE PTR [eax+22],'-'
1017 ; Found <i> - , so consider debugger active:
1021 cmp BYTE PTR [eax+0], 200
1023 cmp BYTE PTR [eax+2], 27
1025 cmp BYTE PTR [eax+4], 17
1028 ; Found either the help screen or view screen, so consider
1033 ; Now we see if its active by looking for the "Executing..."
1034 ; text on the bottom of the mono screen
1035 ;mov eax, 0b0000h ; 4096 = offset to mono video mem
1037 ;cmp BYTE PTR [eax+0],'E'
1038 ;je NoActiveDebugger
1039 ;cmp BYTE PTR [eax+2],'x'
1040 ;je NoActiveDebugger
1041 ;cmp BYTE PTR [eax+4],'e'
1042 ;je NoActiveDebugger
1043 ;cmp BYTE PTR [eax+6],'c'
1044 ;je NoActiveDebugger