;; ==================================================================== ;; Macros ;; ==================================================================== ;; Jump if key pressed JKEYP MACRO key,label cmp byte ptr cs:_keyFlags[key+1],1 je label ENDM ;; Jump if key not pressed JKEYNP MACRO key,label cmp byte ptr cs:_keyFlags[key+1],1 jne label ENDM ;; Note that JNKEY and JKEY both modify _flKeyChanged, so you cannot ;; use one after the other! In other words, ;; JKEYNP no_key ;; JKEYP yes_key ;<-- this will fail ;; will not work like you'd think it would. The second call (JKEYP) ;; will not know that a key has been pressed! ;; Jump if no key pressed: JNKEY MACRO label cmp cs:_flKeyChanged,0 je label mov cs:_flKeyChanged,0 ; <--- important! ENDM ;; Jump if key pressed: JKEY MACRO label cmp cs:_flKeyChanged,0 mov cs:_flKeyChanged,0 jne label ENDM ;; Start keyboard interrupts KEYB_START MACRO call SwapInt9 mov cs:_flKeyChanged,0 ENDM ;; Clear keyboard interrupts KEYB_END MACRO call SwapInt9 ENDM ;; Credit for these routines: Steve Dollins, Brown Computer Group. ;; I didn't write any of the code below -- just heisted it from some ;; stuff that he wrote and released! Very useful keyboard routines. ;; Any comments prefixed SDE were added by me. _keyFlags dw 256 dup (0) ; SDE: since they only use 2 bits ; per word, this is a tradeoff, ; space for time oldint9_offset dw offset newint9 oldint9_segment dw seg newint9 _flKeyChanged dw 0 ;----------------------------------------------------------------------- ; void SwapInt9( void ) ; ; SwapInt9() exchanges the vector in oldint9_segment:oldint9_offset ; with the vector in the interrupt table for INT 9h. ;----------------------------------------------------------------------- SwapInt9 PROC far mov ax,cs mov ds,ax mov ax,03509h ; Get interrupt 09h int 21h ; return in ES:BX mov ax,oldint9_segment mov dx,oldint9_offset push ds mov ds,ax mov ax,02509h ; Set new interrupt int 21h ; to address in DS:DX pop ds mov oldint9_segment,es ; Save the old interrupt mov oldint9_offset,bx ret SwapInt9 ENDP ;----------------------------------------------------------------------- ; newint9 is the new keyboard interrupt (INT 9h). ; ; Reads the scan code from the keyboard and modifies the key ; flags table. The high byte is set to the position of the key, ; pressed=1, release=0. The low byte is set to 1 when the key ; is pressed and left unmodified when the key is released. ;----------------------------------------------------------------------- newint9 PROC far push ax push bx push ds mov ax,cs mov ds,ax JKEYNP kCTRL,not_ctrlaltdel ; SDE code JKEYNP kALT,not_ctrlaltdel ; To still allow ctrl- JKEYNP kDELETE,not_ctrlaltdel ; alt-delete. Nothing jmp ctrlaltdel ; worse than a total lockup! not_ctrlaltdel: in ax,60h ; get scan code in AL, control byte in AH mov bx,ax ; save a copy in BX xchg ah,al ; swap to get control byte in AL or al,80h ; clear keyboard out 61h,al ; of interrupt and al,7Fh out 61h,al mov al,20h ; send generic EOI to out 20h,al ; PIC and bx,0007fh ; strip all but the scan code shl bx,1 ; multiply by two to get our offset ; if the key was released, the high bit is set in the scan code bt ax,15 ; move this high bit into the carry flag setnc byte ptr [_keyFlags+bx+1] ; set "Is being pressed" flag jc short int09done ; if the key was released, we're done mov byte ptr [_keyFlags+bx],1 ; set "Has been pressed" flag mov _flKeyChanged,1 ; state of keyboard has changed int09done: mov _flKeyChanged,1 ; state of keyboard has changed pop ds pop bx pop ax iret ctrlaltdel: int 19h ; SDE -- added this. ; Allows a reboot. newint9 ENDP ;; Defines the current key procedure (used as a jump-through) kprocCur dw KprocDirect ;; This is a keyboard procedure. Normally, this would control some ;; sprite, or something, and the screen would follow the sprite. For ;; the purposes of this code, though (namely, sprite-less scrolling) ;; it just directly affects ScrollDX and ScrollDY. ;; This keyproc is inertialess, use + and - to increase speed and ;; the up/down/left/right keys to move directions. ;; Pressing K will switch to the other keyprocedure on the fly. ;; P pauses the screen -- note that this is just for completely ;; freezing the screen... it doesn't return until you let go! EVEN scroll_speed_x dw SCROLL_SPEED ; (defaults) scroll_speed_y dw SCROLL_SPEED * VIRTUAL_WIDTH ; (defaults) KprocDirect PROC near chk_leftright: mov ax,0 JKEYNP kRIGHT,not_right mov ax,scroll_speed_x mov ScrollDX,ax jmp chk_updown not_right: JKEYNP kLEFT,not_left sub ax,scroll_speed_x mov ScrollDX,ax jmp chk_updown not_left: mov ScrollDX,ax chk_updown: mov ax,0 JKEYNP kUP,not_up sub ax,scroll_speed_y mov ScrollDY,ax jmp chk_other not_up: JKEYNP kDOWN,not_down mov ax,scroll_speed_y mov ScrollDY,ax jmp chk_other not_down: mov ScrollDY,ax chk_other: JKEYNP kK,not_k mov kprocCur,KprocInertia not_k: JKEYNP kM,not_m mov bDoTransition,1 not_m: JKEYNP kGREY_MINUS,not_minus cmp scroll_speed_x,1 jle not_minus dec scroll_speed_x sub scroll_speed_y,VIRTUAL_WIDTH not_minus: JKEYNP kGREY_PLUS,not_plus cmp scroll_speed_x,16 jge not_plus inc scroll_speed_x add scroll_speed_y,VIRTUAL_WIDTH not_plus: pause_key: JKEYP kP,pause_key ret KprocDirect ENDP ;; This keyproc has inertia, so + and - don't work. ;; Use up/down/left/right keys to increase speed in those directions. ;; Pressing K will switch to the other keyprocedure on the fly. ;; P pauses the screen -- note that this is just for completely ;; freezing the screen... it doesn't return until you let go! KprocInertia PROC near chk2_leftright: JKEYNP kRIGHT,not2_right cmp ScrollDX,16 je not2_right inc ScrollDX jmp chk2_updown not2_right: JKEYNP kLEFT,not2_left cmp ScrollDX,-16 je not2_left dec ScrollDX jmp chk2_updown not2_left: chk2_updown: JKEYNP kUP,not2_up cmp ScrollDY,-VIRTUAL_WIDTH * 16 je not2_up add ScrollDY,-VIRTUAL_WIDTH jmp chk2_other not2_up: JKEYNP kDOWN,not2_down cmp ScrollDY,VIRTUAL_WIDTH * 16 je not2_down add ScrollDY,VIRTUAL_WIDTH jmp chk2_other not2_down: chk2_other: JKEYNP kK,not2_k mov kprocCur,KprocDirect not2_k: JKEYNP kM,not2_m mov bDoTransition,1 not2_m: pause2_key: JKEYP kP,pause2_key ret KprocInertia ENDP