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.
15 ;***************************************************************************
16 ;***************************************************************************
19 ;***** K E Y . A S M *****
21 ;***** Contains routines to get, buffer, and check key presses. *****
24 ;***** PROCEDURES *****
26 ;***** key_init() - Activates the keyboard package. *****
27 ;***** key_close() - Deactivates the keyboard package. *****
28 ;***** key_check() - Returns 1 if a buffered key is waiting. *****
29 ;***** key_getch() - Waits for and returns a buffered keypress. *****
30 ;***** key_flush() - Clears buffers and state array. *****
31 ;***** key_time() - Index by scan code. Contains the time key has been *****
32 ;***** held down. NOT DONE YET. *****
35 ;***** VARIABLES *****
37 ;***** keyd_buffer_type -Set to 0 and key_getch() always returns 0. *****
38 ;***** Set to 1 to so that ASCII codes are returned *****
39 ;***** by key_getch(). Set to 2 and key_getch() returns*****
40 ;***** the buffered keyboard scan codes. *****
41 ;***** keyd_repeat - Set to 0 to not allow repeated keys in the *****
42 ;***** keyboard buffer. Set to 1 to allow repeats. *****
43 ;***** keyd_pressed[] -Index by scan code. Contains 1 if key down else 0*****
46 ;***** CONSTANTS *****
48 ;***** Setting the DEBUG to 1 at compile time passes SysReq through *****
49 ;***** to the debugger, and when the debugger is active, it will give *****
50 ;***** the debugger any keys that are pressed. Note that this only *****
51 ;***** works with the Watcom VIDEO debugger at this time. Setting *****
52 ;***** DEBUG to 0 takes out all the debugging stuff. *****
54 ;***************************************************************************
55 ;***************************************************************************
60 ;************************************************************************
61 ;**************** FLAT MODEL DATA SEGMENT STUFF *************************
62 ;************************************************************************
64 _DATA SEGMENT BYTE PUBLIC USE32 'DATA'
66 PUBLIC _keyd_pressed ; Must start with a _ so C can see the variable.
68 _keyd_pressed db 256 dup (?)
70 keybuffer dw 256 dup (?) ; Use 256 so an inc wraps around
72 TimeKeyWentDown dd 256 dup(0)
73 TimeKeyHeldDown dd 256 dup(0)
74 NumDowns dd 256 dup(0)
79 PUBLIC _keyd_editor_mode
81 _keyd_editor_mode db 0
87 PUBLIC _keyd_last_pressed
88 _keyd_last_pressed db 0
89 PUBLIC _keyd_last_released
90 _keyd_last_released db 0
92 PUBLIC _keyd_dump_key_array
93 _keyd_dump_key_array db 0
102 PUBLIC _keyd_buffer_type
104 _keyd_buffer_type db ? ; 0=No buffer, 1=buffer ASCII, 2=buffer scans
119 ;************************************************************************
120 ;**************** FLAT MODEL CODE SEGMENT STUFF *************************
121 ;************************************************************************
123 _TEXT SEGMENT BYTE PUBLIC USE32 'CODE'
128 key_get_milliseconds:
129 EXTERNDEF timer_get_stamp64:NEAR
134 call timer_get_stamp64
136 ; Timing in milliseconds
137 ; Can be used for up to 1000 hours
138 shld edx, eax, 21 ; Keep 32+11 bits
140 mov ebx, 2502279823 ; 2^21*1193180/1000
148 ;************************************************************************
149 ;************************************************************************
151 ;***** K E Y _ T O _ A S C I I _ *****
153 ;************************************************************************
154 ;************************************************************************
171 and ah, 01b ; take away ctrl and alt codes
175 mov al, byte ptr key1[eax]
185 public key_clear_times_,key_clear_counts_
187 ;clear the array of key down times.
195 lea edi,TimeKeyHeldDown
196 rep stosd ;clear array
203 ;clear the arrays of key down counts
212 rep stosd ;clear array
215 rep stosd ;clear array
223 PUBLIC key_down_time_
236 cmp _keyd_pressed[ebx], 0
240 cmp _keyd_editor_mode, 0
243 call get_modifiers ;shift,alt,ctrl?
249 read_time: mov ecx, TimeKeyWentDown[ebx*4]
250 call key_get_milliseconds
251 mov TimeKeyWentDown[ebx*4], eax
252 sub eax, ecx ; EAX = time held since last
255 add eax, TimeKeyHeldDown[ebx*4]
256 mov TimeKeyHeldDown[ebx*4], 0
264 PUBLIC key_down_count_
269 mov eax, NumDowns[ebx*4]
270 mov NumDowns[ebx*4], 0
280 mov eax, NumUps[ebx*4]
288 ;************************************************************************
289 ;************************************************************************
291 ;***** K E Y _ F L U S H *****
293 ;************************************************************************
294 ;************************************************************************
309 ; Clear the keyboard array
310 mov edi, offset _keyd_pressed
321 ;************************************************************************
322 ;************************************************************************
324 ;***** K E Y _ I N I T *****
326 ;************************************************************************
327 ;************************************************************************
337 ;**************************************************************
338 ;******************* INITIALIZE key QUEUE **********************
339 ;**************************************************************
341 mov _keyd_buffer_type,1
345 ; Clear the keyboard array
351 ;**************************************************************
352 ;******************* SAVE OLD INT9 HANDLER ********************
353 ;**************************************************************
357 mov eax, 03509h ; DOS Get Vector 09h
359 mov org_int_sel, es ; Save old interrupt selector
360 mov org_int_off, ebx ; Save old interrupt offset
363 ;**************************************************************
364 ;***************** INSTALL NEW INT9 HANDLER *******************
365 ;**************************************************************
367 mov eax, 02509h ; DOS Set Vector 09h
368 mov edx, offset key_handler ; Point DS:EDX to new handler
370 mov MyCodeSegment, bx
385 ;************************************************************************
386 ;************************************************************************
388 ;***** K E Y _ C L O S E _ *****
390 ;************************************************************************
391 ;************************************************************************
405 ;**************************************************************
406 ;***************** RESTORE OLD INT9 HANDLER *******************
407 ;**************************************************************
411 ; Clear the BIOS buffer
414 mov al, byte ptr [ebx]
416 mov byte ptr [ebx], al
419 mov eax, 02509h ; DOS Set Vector 09h
431 ;************************************************************************
432 ;************************************************************************
434 ;***** K E Y _ C H E C K _ *****
436 ;************************************************************************
437 ;************************************************************************
439 PUBLIC key_checkch_ ; Must end with a _ so C can see the function.
459 ;************************************************************************
460 ;************************************************************************
462 ;***** K E Y _ D E B U G *****
464 ;************************************************************************
465 ;************************************************************************
473 ;************************************************************************
474 ;************************************************************************
476 ;***** K E Y _ G E T C H _ *****
478 ;************************************************************************
479 ;************************************************************************
481 PUBLIC key_getch_ ; Must end with a _ so C can see the function.
494 cli ; Critical section
501 cli ; Critical section
504 mov ax, word ptr keybuffer[ebx*2]
512 ;************************************************************************
513 ;************************************************************************
515 ;***** K E Y _ I N K E Y _ *****
517 ;************************************************************************
518 ;************************************************************************
520 PUBLIC key_inkey_ ; Must end with a _ so C can see the function.
531 cli ; Critical section
538 cli ; Critical section
540 mov ax, word ptr keybuffer[ebx*2]
547 PUBLIC key_peekkey_ ; Must end with a _ so C can see the function.
555 cli ; Critical section
564 mov ax, word ptr keybuffer[ebx*2]
572 ;************************************************************************
573 ;************************************************************************
575 ;***** K E Y _ H A N D L E R *****
577 ;************************************************************************
578 ;************************************************************************
580 PUBLIC key_handler ; Must end with a _ so C can see the function.
584 pushfd ; Save flags in case we have to chain to original
591 mov ax, DGROUP ; Point to our data segment, since this is an
592 mov ds, ax ; interrupt and we don't know where we were.
594 mov eax, (0b0000h+76*2)
595 mov byte ptr [eax], '1'
598 call CheckForDebugger
600 mov eax, 0b0000h+78*2
601 mov byte ptr [eax], 'D'
602 jmp PassToBios ; If debugger is active, then skip buffer
604 @@: mov eax, 0b0000h+78*2
605 mov byte ptr [eax], 'I'
607 ; Clear the BIOS buffer
609 ;**mov al, byte ptr [ebx]
611 ;**mov byte ptr [ebx], al
617 in al, 060h ; Get scan code from keyboard
622 E0Code: mov E0Flag, 010000000b
623 jmp LeaveHandler ; If garbage key, then don't buffer it
625 NotE0Code: mov bl, al ; Put break bit into bl ; 0 = pressed, 1=released
626 and al, 01111111b ; AL = scancode
627 or al, E0Flag ; AL = extended scancode
628 mov E0Flag,0 ; clear E0 flag
631 shl bl, 1 ; put upper bit into carry flag
632 jc key_mark_released ; if upper bit of bl was set, then it was a release code
634 ;**************************************************************
635 ;****************** HANDLE A NEWLY PRESSED KEY ****************
636 ;**************************************************************
637 ;Marks the key press in EAX in the scancode array.
640 ;cmp al, 0eh ; backspace
643 mov _keyd_last_pressed, al
644 ; Check if the key is repeating or if it just got pressed.
645 cmp byte ptr _keyd_pressed[eax], 1
648 ;------------------------------- Code for a key pressed for the first time ------------------------
649 mov byte ptr _keyd_pressed[eax], 1
654 call key_get_milliseconds
657 mov TimeKeyWentDown[eax*4], edx
664 ;------------------------------- Code for a key that is already pressed ------------------------
667 je DoneMarkingPressed
670 cmp _keyd_buffer_type, 0
671 je SkipBuffer ; Buffer = 0 means don't buffer anything.
673 cmp al, 0AAh ; garbage key
676 call get_modifiers ;returns ah
683 ; If the buffer is full then don't buffer this key
688 mov word ptr keybuffer[ebx*2], ax
693 ;---------------------------------- Exit function -----------------------------
697 ;**************************************************************
698 ;******************* HANDLE A RELEASED KEY ********************
699 ;**************************************************************
700 ; Unmarks the key press in EAX from the scancode array.
703 mov _keyd_last_released, al
704 mov byte ptr _keyd_pressed[eax], 0
707 cmp _keyd_editor_mode, 0
712 or ah,ah ;check modifiers
719 call timer_get_stamp64
721 ; Timing in milliseconds
722 ; Can be used for up to 1000 hours
723 shld edx, eax, 21 ; Keep 32+11 bits
725 mov ebx, 2502279823 ; 2^21*1193180/1000
730 sub edx, TimeKeyWentDown[eax*4]
731 add TimeKeyHeldDown[eax*4], edx
733 skip_time: ;**jmp LeaveHandler
735 ;**************************************************************
736 ;*************** FINISH UP THE KEYBOARD INTERRUPT *************
737 ;**************************************************************
739 mov eax, (0b0000h+76*2)
740 mov byte ptr [eax], '2'
742 ;; cmp _keyd_dump_key_array, 0
749 showdown: mov al, _keyd_pressed[ebx]
751 mov [ebx*2+ 0b0000h], al
756 mov byte ptr [ eax+(036h*2+1) ], 070h
757 mov byte ptr [ eax+(02Ah*2+1) ], 070h
758 mov byte ptr [ eax+(038h*2+1) ], 070h
759 mov byte ptr [ eax+(0B8h*2+1) ], 070h
760 mov byte ptr [ eax+(01Dh*2+1) ], 070h
761 mov byte ptr [ eax+(09dh*2+1) ], 070h
763 mov byte ptr [ eax+(0AAh*2+1) ], 07Fh
764 mov byte ptr [ eax+(0E0h*2+1) ], 07Fh
769 ; If in debugger, pass control to dos interrupt.
771 PassToBios: pop ds ; Nothing left on stack but flags
777 sub esp, 8 ; Save space for IRETD frame
778 push ds ; Save registers we use.
781 mov ds, ax ; Set DS to our data segment
782 mov eax, org_int_off ; put original handler address
783 mov [esp+8], eax ; in the IRETD frame
784 movzx eax, org_int_sel
786 pop eax ; Restore registers
788 iretd ; Chain to previous handler
791 in al, 61h ; Get current port 61h state
792 or al, 10000000b ; Turn on bit 7 to signal clear keybrd
793 out 61h, al ; Send to port
794 and al, 01111111b ; Turn off bit 7 to signal break
795 out 61h, al ; Send to port
796 mov al, 20h ; Reset interrupt controller
798 sti ; Reenable interrupts
800 pop edx ; Restore all of the saved registers.
805 sub esp, 8 ; Save space for IRETD frame
806 push ds ; Save registers we use.
809 mov ds, ax ; Set DS to our data segment
810 mov eax, org_int_off ; put original handler address
811 mov [esp+8], eax ; in the IRETD frame
812 movzx eax, org_int_sel
814 pop eax ; Restore registers
817 iretd ; Interrupt must return with IRETD
821 ; Resets the keyboard, PIC, restores stack, returns.
822 in al, 61h ; Get current port 61h state
823 or al, 10000000b ; Turn on bit 7 to signal clear keybrd
824 out 61h, al ; Send to port
825 and al, 01111111b ; Turn off bit 7 to signal break
826 out 61h, al ; Send to port
827 mov al, 20h ; Reset interrupt controller
829 sti ; Reenable interrupts
831 pop edx ; Restore all of the saved registers.
836 iretd ; Interrupt must return with IRETD
838 ;returns ah=bitmask of shift,ctrl,alt keys
839 get_modifiers: push ecx
843 ; Check the shift keys
844 mov cl, _keyd_pressed[ 036h ]
845 or cl, _keyd_pressed[ 02ah ]
849 mov cl, _keyd_pressed[ 038h ]
850 or cl, _keyd_pressed[ 0b8h ]
855 mov cl, _keyd_pressed[ 01dh ]
856 or cl, _keyd_pressed[ 09dh ]
865 ; Returns CF=0 if debugger isn't active
866 ; CF=1 if debugger is active
868 ;*************************** DEBUG ******************************
869 ; When we're in the VIDEO debugger, we want to pass control to
870 ; the original interrupt. So, to tell if the debugger is active,
871 ; I check if video page 1 is the active page since that is what
872 ; page the debugger uses, and if that works, I check the top of
873 ; the screen to see if the texxt "Control" is there, which should
874 ; only be there when we're in the debugger.
879 ;mov eax, 0462h ; Address 0462 stores BIOS current page
880 ;cmp BYTE PTR [eax], 1
881 ;jne NoDebuggerOnColor
882 ;mov eax, 0b8000h+4096 ; 4096 = offset to 2nd video mem page
883 ;cmp BYTE PTR [eax+2],'C'
884 ;jne NoDebuggerOnColor
885 ;cmp BYTE PTR [eax+4],'o'
886 ;jne NoDebuggerOnColor
887 ;cmp BYTE PTR [eax+6],'n'
888 ;jne NoDebuggerOnColor
889 ;cmp BYTE PTR [eax+8],'t'
890 ;jne NoDebuggerOnColor
891 ;cmp BYTE PTR [eax+10],'r'
892 ;jne NoDebuggerOnColor
893 ;cmp BYTE PTR [eax+12],'o'
894 ;jne NoDebuggerOnColor
895 ;cmp BYTE PTR [eax+14],'l'
896 ;jne NoDebuggerOnColor
899 ; First, see if there is a mono debugger...
901 ;mov eax, 0b0000h ; 4096 = offset to mono video mem
902 ;cmp BYTE PTR [eax+2],'C'
903 ;jne NoActiveDebugger
904 ;cmp BYTE PTR [eax+4],'o'
905 ;jne NoActiveDebugger
906 ;cmp BYTE PTR [eax+6],'n'
907 ;jne NoActiveDebugger
908 ;cmp BYTE PTR [eax+8],'t'
909 ;jne NoActiveDebugger
910 ;cmp BYTE PTR [eax+10],'r'
911 ;jne NoActiveDebugger
912 ;cmp BYTE PTR [eax+12],'o'
913 ;jne NoActiveDebugger
914 ;cmp BYTE PTR [eax+14],'l'
915 ;jne NoActiveDebugger
917 mov eax, 0b0000h ; 4096 = offset to mono video mem
921 cmp BYTE PTR [eax+0],'D'
923 cmp BYTE PTR [eax+2],'B'
925 cmp BYTE PTR [eax+4],'G'
927 cmp BYTE PTR [eax+6],'>'
930 ;Found DBG>, so consider debugger active:
934 cmp BYTE PTR [eax+14],'<'
936 cmp BYTE PTR [eax+16],'i'
938 cmp BYTE PTR [eax+18],'>'
940 cmp BYTE PTR [eax+20],' '
942 cmp BYTE PTR [eax+22],'-'
945 ; Found <i> - , so consider debugger active:
949 cmp BYTE PTR [eax+0], 200
951 cmp BYTE PTR [eax+2], 27
953 cmp BYTE PTR [eax+4], 17
956 ; Found either the help screen or view screen, so consider
961 ; Now we see if its active by looking for the "Executing..."
962 ; text on the bottom of the mono screen
963 ;mov eax, 0b0000h ; 4096 = offset to mono video mem
965 ;cmp BYTE PTR [eax+0],'E'
967 ;cmp BYTE PTR [eax+2],'x'
969 ;cmp BYTE PTR [eax+4],'e'
971 ;cmp BYTE PTR [eax+6],'c'