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