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