1 ; THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
\r
2 ; SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
\r
3 ; END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
\r
4 ; ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
\r
5 ; IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
\r
6 ; SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
\r
7 ; FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
\r
8 ; CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
\r
9 ; AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
\r
10 ; COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
\r
11 ;***************************************************************************
\r
12 ;***************************************************************************
\r
15 ;***** K E Y . A S M *****
\r
17 ;***** Contains routines to get, buffer, and check key presses. *****
\r
20 ;***** PROCEDURES *****
\r
22 ;***** key_init() - Activates the keyboard package. *****
\r
23 ;***** key_close() - Deactivates the keyboard package. *****
\r
24 ;***** key_check() - Returns 1 if a buffered key is waiting. *****
\r
25 ;***** key_getch() - Waits for and returns a buffered keypress. *****
\r
26 ;***** key_flush() - Clears buffers and state array. *****
\r
27 ;***** key_time() - Index by scan code. Contains the time key has been *****
\r
28 ;***** held down. NOT DONE YET. *****
\r
31 ;***** VARIABLES *****
\r
33 ;***** keyd_buffer_type -Set to 0 and key_getch() always returns 0. *****
\r
34 ;***** Set to 1 to so that ASCII codes are returned *****
\r
35 ;***** by key_getch(). Set to 2 and key_getch() returns*****
\r
36 ;***** the buffered keyboard scan codes. *****
\r
37 ;***** keyd_repeat - Set to 0 to not allow repeated keys in the *****
\r
38 ;***** keyboard buffer. Set to 1 to allow repeats. *****
\r
39 ;***** keyd_pressed[] -Index by scan code. Contains 1 if key down else 0*****
\r
42 ;***** CONSTANTS *****
\r
44 ;***** Setting the DEBUG to 1 at compile time passes SysReq through *****
\r
45 ;***** to the debugger, and when the debugger is active, it will give *****
\r
46 ;***** the debugger any keys that are pressed. Note that this only *****
\r
47 ;***** works with the Watcom VIDEO debugger at this time. Setting *****
\r
48 ;***** DEBUG to 0 takes out all the debugging stuff. *****
\r
50 ;***************************************************************************
\r
51 ;***************************************************************************
\r
56 ;************************************************************************
\r
57 ;**************** FLAT MODEL DATA SEGMENT STUFF *************************
\r
58 ;************************************************************************
\r
60 _DATA SEGMENT BYTE PUBLIC USE32 'DATA'
\r
62 rcsid db "$Id: key.asm,v 1.1.1.1 2001-01-19 03:30:14 bradleyb Exp $"
\r
64 PUBLIC _keyd_pressed ; Must start with a _ so C can see the variable.
\r
66 _keyd_pressed db 256 dup (?)
\r
68 keybuffer dw 256 dup (?) ; Use 256 so an inc wraps around
\r
70 TimeKeyWentDown dd 256 dup(0)
\r
71 TimeKeyHeldDown dd 256 dup(0)
\r
72 NumDowns dd 256 dup(0)
\r
73 NumUps dd 256 dup(0)
\r
77 PUBLIC _keyd_last_pressed
\r
78 _keyd_last_pressed db 0
\r
79 PUBLIC _keyd_last_released
\r
80 _keyd_last_released db 0
\r
86 PUBLIC _keyd_buffer_type
\r
88 _keyd_buffer_type db ? ; 0=No buffer, 1=buffer ASCII, 2=buffer scans
\r
103 ;************************************************************************
\r
104 ;**************** FLAT MODEL CODE SEGMENT STUFF *************************
\r
105 ;************************************************************************
\r
107 _TEXT SEGMENT BYTE PUBLIC USE32 'CODE'
\r
113 ;************************************************************************
\r
114 ;************************************************************************
\r
116 ;***** K E Y _ T O _ A S C I I _ *****
\r
118 ;************************************************************************
\r
119 ;************************************************************************
\r
121 PUBLIC key_to_ascii_
\r
136 and ah, 01b ; take away ctrl and alt codes
\r
140 mov al, byte ptr key1[eax]
\r
150 public key_clear_times_,key_clear_counts_
\r
152 ;clear the array of key down times.
\r
153 key_clear_times_: push eax
\r
158 lea edi,TimeKeyHeldDown
\r
159 rep stosd ;clear array
\r
165 ;clear the arrays of key down counts
\r
166 key_clear_counts_: push eax
\r
172 rep stosd ;clear array
\r
175 rep stosd ;clear array
\r
182 PUBLIC key_down_time_
\r
186 EXTERNDEF timer_get_milliseconds_:NEAR
\r
195 cmp _keyd_pressed[ebx], 0
\r
198 call get_modifiers ;shift,alt,ctrl?
\r
205 mov ecx, TimeKeyWentDown[ebx*4]
\r
207 call timer_get_milliseconds_
\r
208 mov TimeKeyWentDown[ebx*4], eax
\r
209 sub eax, ecx ; EAX = time held since last
\r
212 add eax, TimeKeyHeldDown[ebx*4]
\r
213 mov TimeKeyHeldDown[ebx*4], 0
\r
221 PUBLIC key_down_count_
\r
226 mov eax, NumDowns[ebx*4]
\r
227 mov NumDowns[ebx*4], 0
\r
232 PUBLIC key_up_count_
\r
237 mov eax, NumUps[ebx*4]
\r
238 mov NumUps[ebx*4], 0
\r
245 ;************************************************************************
\r
246 ;************************************************************************
\r
248 ;***** K E Y _ F L U S H *****
\r
250 ;************************************************************************
\r
251 ;************************************************************************
\r
265 ; Clear the keyboard array
\r
266 mov edi, offset _keyd_pressed
\r
277 ;************************************************************************
\r
278 ;************************************************************************
\r
280 ;***** K E Y _ I N I T *****
\r
282 ;************************************************************************
\r
283 ;************************************************************************
\r
293 ;**************************************************************
\r
294 ;******************* INITIALIZE key QUEUE **********************
\r
295 ;**************************************************************
\r
298 mov _keyd_buffer_type,1
\r
302 ; Clear the keyboard array
\r
307 jne AlreadyInstalled
\r
309 ;**************************************************************
\r
310 ;******************* SAVE OLD INT9 HANDLER ********************
\r
311 ;**************************************************************
\r
315 mov eax, 03509h ; DOS Get Vector 09h
\r
317 mov org_int_sel, es ; Save old interrupt selector
\r
318 mov org_int_off, ebx ; Save old interrupt offset
\r
321 ;**************************************************************
\r
322 ;***************** INSTALL NEW INT9 HANDLER *******************
\r
323 ;**************************************************************
\r
325 mov eax, 02509h ; DOS Set Vector 09h
\r
326 mov edx, offset key_handler ; Point DS:EDX to new handler
\r
328 mov MyCodeSegment, bx
\r
343 ;************************************************************************
\r
344 ;************************************************************************
\r
346 ;***** K E Y _ C L O S E _ *****
\r
348 ;************************************************************************
\r
349 ;************************************************************************
\r
363 ;**************************************************************
\r
364 ;***************** RESTORE OLD INT9 HANDLER *******************
\r
365 ;**************************************************************
\r
369 ; Clear the BIOS buffer
\r
371 mov al, byte ptr [ebx]
\r
373 mov byte ptr [ebx], al
\r
375 mov eax, 02509h ; DOS Set Vector 09h
\r
376 mov edx, org_int_off
\r
377 mov ds, org_int_sel
\r
387 ;************************************************************************
\r
388 ;************************************************************************
\r
390 ;***** K E Y _ C H E C K _ *****
\r
392 ;************************************************************************
\r
393 ;************************************************************************
\r
395 PUBLIC key_checkch_ ; Must end with a _ so C can see the function.
\r
416 ;************************************************************************
\r
417 ;************************************************************************
\r
419 ;***** K E Y _ D E B U G *****
\r
421 ;************************************************************************
\r
422 ;************************************************************************
\r
430 ;************************************************************************
\r
431 ;************************************************************************
\r
433 ;***** K E Y _ G E T C H _ *****
\r
435 ;************************************************************************
\r
436 ;************************************************************************
\r
438 PUBLIC key_getch_ ; Must end with a _ so C can see the function.
\r
451 cli ; Critical section
\r
458 cli ; Critical section
\r
461 mov ax, word ptr keybuffer[ebx*2]
\r
462 inc BYTE PTR keyhead
\r
469 ;************************************************************************
\r
470 ;************************************************************************
\r
472 ;***** K E Y _ I N K E Y _ *****
\r
474 ;************************************************************************
\r
475 ;************************************************************************
\r
477 PUBLIC key_inkey_ ; Must end with a _ so C can see the function.
\r
488 cli ; Critical section
\r
495 cli ; Critical section
\r
497 mov ax, word ptr keybuffer[ebx*2]
\r
498 inc BYTE PTR keyhead
\r
504 PUBLIC key_peekkey_ ; Must end with a _ so C can see the function.
\r
515 cli ; Critical section
\r
522 cli ; Critical section
\r
524 mov ax, word ptr keybuffer[ebx*2]
\r
532 ;************************************************************************
\r
533 ;************************************************************************
\r
535 ;***** K E Y _ H A N D L E R *****
\r
537 ;************************************************************************
\r
538 ;************************************************************************
\r
540 PUBLIC key_handler ; Must end with a _ so C can see the function.
\r
543 EXTERNDEF timer_get_milliseconds_:NEAR
\r
545 pushfd ; Save flags in case we have to chain to original
\r
552 mov ax, DGROUP ; Point to our data segment, since this is an
\r
553 mov ds, ax ; interrupt and we don't know where we were.
\r
556 call CheckForDebugger
\r
558 mov eax, 0b0000h+78*2
\r
559 mov byte ptr [eax], 'D'
\r
560 jmp SkipBuffer ; If debugger is active, then skip buffer
\r
561 @@: mov eax, 0b0000h+78*2
\r
562 mov byte ptr [eax], 'I'
\r
564 ; Clear the BIOS buffer
\r
566 mov al, byte ptr [ebx]
\r
568 mov byte ptr [ebx], al
\r
571 ;**************************************************************
\r
572 ;****************** READ IN THE SCAN CODE *********************
\r
573 ;**************************************************************
\r
574 ; Reads the scan code from the keyboard and masks off the
\r
575 ; scan code and puts it in EAX.
\r
578 in al, 060h ; Get scan code from keyboard
\r
588 mov bl,al ; Save scan code in BL
\r
592 xor bh,bh ; clear for index use
\r
593 and al,10000000b ; keep break bit, if set
\r
594 xor al,10000000b ; flip bit - 1 means pressed
\r
595 ; - 0 means released
\r
596 rol al,1 ; put it in bit 0
\r
600 ; BX = 1 if pressed, 0 if released.
\r
604 ;**************************************************************
\r
605 ;******************* HANDLE A RELEASED KEY ********************
\r
606 ;**************************************************************
\r
607 ; Unmarks the key press in EAX from the scancode array.
\r
610 mov _keyd_last_released, al
\r
611 mov byte ptr _keyd_pressed[eax], 0
\r
617 or ah,ah ;check modifiers
\r
623 call timer_get_milliseconds_
\r
626 sub edx, TimeKeyWentDown[eax*4]
\r
627 add TimeKeyHeldDown[eax*4], edx
\r
635 ;**************************************************************
\r
636 ;****************** HANDLE A NEWLY PRESSED KEY ****************
\r
637 ;**************************************************************
\r
638 ;Marks the key press in EAX in the scancode array.
\r
641 mov _keyd_last_pressed, al
\r
642 ; Check if the key is repeating or if it just got pressed.
\r
643 cmp byte ptr _keyd_pressed[eax], 1
\r
646 mov byte ptr _keyd_pressed[eax], 1
\r
651 call timer_get_milliseconds_
\r
654 mov TimeKeyWentDown[eax*4], edx
\r
657 inc NumDowns[eax*4]
\r
661 ;**************************************************************
\r
662 ;******************** HANDLE A PRESSED KEY ********************
\r
663 ;**************************************************************
\r
664 ; Adds key scan code in EAX to the keybuffer array.
\r
667 cmp _keyd_repeat, 0
\r
671 cmp _keyd_buffer_type, 0
\r
672 je SkipBuffer ; Buffer = 0 means don't buffer anything.
\r
674 ; Dont buffer shift, ctrl, or alt keys.
\r
675 ;cmp al, 02ah ; Right Shift
\r
677 ;cmp al, 036h ; Left Shift
\r
679 ;cmp al, 038h ; Left Alt
\r
681 ;cmp al, 0b8h ; Right Alt
\r
683 ;cmp al, 01dh ; Left Ctrl
\r
685 ;cmp al, 09dh ' Right Ctrl
\r
688 cmp al, 0AAh ; garbage key
\r
691 call get_modifiers ;returns ah
\r
700 ; If the buffer is full then don't buffer this key
\r
705 mov word ptr keybuffer[ebx*2], ax
\r
713 ;**************************************************************
\r
714 ;*************** FINISH UP THE KEYBOARD INTERRUPT *************
\r
715 ;**************************************************************
\r
717 ; If in debugger, pass control to dos interrupt.
\r
719 pop ds ; Nothing left on stack but flags
\r
725 sub esp, 8 ; Save space for IRETD frame
\r
726 push ds ; Save registers we use.
\r
729 mov ds, ax ; Set DS to our data segment
\r
730 mov eax, org_int_off ; put original handler address
\r
731 mov [esp+8], eax ; in the IRETD frame
\r
732 movzx eax, org_int_sel
\r
734 pop eax ; Restore registers
\r
736 iretd ; Chain to previous handler
\r
739 ; Resets the keyboard, PIC, restores stack, returns.
\r
740 in al, 61h ; Get current port 61h state
\r
741 or al, 10000000b ; Turn on bit 7 to signal clear keybrd
\r
742 out 61h, al ; Send to port
\r
743 and al, 01111111b ; Turn off bit 7 to signal break
\r
744 out 61h, al ; Send to port
\r
745 mov al, 20h ; Reset interrupt controller
\r
747 sti ; Reenable interrupts
\r
749 pop edx ; Restore all of the saved registers.
\r
754 iretd ; Interrupt must return with IRETD
\r
756 ;returns ah=bitmask of shift,ctrl,alt keys
\r
757 get_modifiers: push ecx
\r
761 ; Check the shift keys
\r
762 mov cl, _keyd_pressed[ 036h ]
\r
763 or cl, _keyd_pressed[ 02ah ]
\r
766 ; Check the alt key
\r
767 mov cl, _keyd_pressed[ 038h ]
\r
768 or cl, _keyd_pressed[ 0b8h ]
\r
772 ; Check the ctrl key
\r
773 mov cl, _keyd_pressed[ 01dh ]
\r
774 or cl, _keyd_pressed[ 09dh ]
\r
783 ; Returns CF=0 if debugger isn't active
\r
784 ; CF=1 if debugger is active
\r
786 ;*************************** DEBUG ******************************
\r
787 ; When we're in the VIDEO debugger, we want to pass control to
\r
788 ; the original interrupt. So, to tell if the debugger is active,
\r
789 ; I check if video page 1 is the active page since that is what
\r
790 ; page the debugger uses, and if that works, I check the top of
\r
791 ; the screen to see if the texxt "Control" is there, which should
\r
792 ; only be there when we're in the debugger.
\r
795 ;mov eax, 0462h ; Address 0462 stores BIOS current page
\r
796 ;cmp BYTE PTR [eax], 1
\r
797 ;jne NoDebuggerOnColor
\r
798 ;mov eax, 0b8000h+4096 ; 4096 = offset to 2nd video mem page
\r
799 ;cmp BYTE PTR [eax+2],'C'
\r
800 ;jne NoDebuggerOnColor
\r
801 ;cmp BYTE PTR [eax+4],'o'
\r
802 ;jne NoDebuggerOnColor
\r
803 ;cmp BYTE PTR [eax+6],'n'
\r
804 ;jne NoDebuggerOnColor
\r
805 ;cmp BYTE PTR [eax+8],'t'
\r
806 ;jne NoDebuggerOnColor
\r
807 ;cmp BYTE PTR [eax+10],'r'
\r
808 ;jne NoDebuggerOnColor
\r
809 ;cmp BYTE PTR [eax+12],'o'
\r
810 ;jne NoDebuggerOnColor
\r
811 ;cmp BYTE PTR [eax+14],'l'
\r
812 ;jne NoDebuggerOnColor
\r
813 ;jmp ActiveDebugger
\r
814 ;NoDebuggerOnColor:
\r
815 ; First, see if there is a mono debugger...
\r
817 ;mov eax, 0b0000h ; 4096 = offset to mono video mem
\r
818 ;cmp BYTE PTR [eax+2],'C'
\r
819 ;jne NoActiveDebugger
\r
820 ;cmp BYTE PTR [eax+4],'o'
\r
821 ;jne NoActiveDebugger
\r
822 ;cmp BYTE PTR [eax+6],'n'
\r
823 ;jne NoActiveDebugger
\r
824 ;cmp BYTE PTR [eax+8],'t'
\r
825 ;jne NoActiveDebugger
\r
826 ;cmp BYTE PTR [eax+10],'r'
\r
827 ;jne NoActiveDebugger
\r
828 ;cmp BYTE PTR [eax+12],'o'
\r
829 ;jne NoActiveDebugger
\r
830 ;cmp BYTE PTR [eax+14],'l'
\r
831 ;jne NoActiveDebugger
\r
833 mov eax, 0b0000h ; 4096 = offset to mono video mem
\r
837 cmp BYTE PTR [eax+0],'D'
\r
839 cmp BYTE PTR [eax+2],'B'
\r
841 cmp BYTE PTR [eax+4],'G'
\r
843 cmp BYTE PTR [eax+6],'>'
\r
846 ;Found DBG>, so consider debugger active:
\r
850 cmp BYTE PTR [eax+14],'<'
\r
852 cmp BYTE PTR [eax+16],'i'
\r
854 cmp BYTE PTR [eax+18],'>'
\r
856 cmp BYTE PTR [eax+20],' '
\r
858 cmp BYTE PTR [eax+22],'-'
\r
861 ; Found <i> - , so consider debugger active:
\r
865 cmp BYTE PTR [eax+0], 200
\r
867 cmp BYTE PTR [eax+2], 27
\r
869 cmp BYTE PTR [eax+4], 17
\r
872 ; Found either the help screen or view screen, so consider
\r
877 ; Now we see if its active by looking for the "Executing..."
\r
878 ; text on the bottom of the mono screen
\r
879 ;mov eax, 0b0000h ; 4096 = offset to mono video mem
\r
881 ;cmp BYTE PTR [eax+0],'E'
\r
882 ;je NoActiveDebugger
\r
883 ;cmp BYTE PTR [eax+2],'x'
\r
884 ;je NoActiveDebugger
\r
885 ;cmp BYTE PTR [eax+4],'e'
\r
886 ;je NoActiveDebugger
\r
887 ;cmp BYTE PTR [eax+6],'c'
\r
888 ;je NoActiveDebugger
\r