; ; Command & Conquer Red Alert(tm) ; Copyright 2025 Electronic Arts Inc. ; ; This program is free software: you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation, either version 3 of the License, or ; (at your option) any later version. ; ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with this program. If not, see . ; ;*************************************************************************** ;** C O N F I D E N T I A L --- W E S T W O O D A S S O C I A T E S ** ;*************************************************************************** ;* * ;* Project Name : Westwood 32 bit Library * ;* (Mouse Routines) ;* * ;* File Name : KEYIREAL.ASM * ;* * ;* Programmer : Philip W. Gorrow * ;* * ;* Start Date : May 21, 1992 * ;* * ;* Last Update : July 13, 1994 [PWG] * ;* * ;* This file sort of breaks the standard of keeping all of the keyboard * ;* and mouse routines isolated. This is done because the mouse and * ;* the keyboard share data, and the best way to do this is to put * ;* them in the same segment. This should probably be split into several * ;* include files to help make the code clearer once it is finally put * ;* together. * ;* * ;*-------------------------------------------------------------------------* ;* Functions: * ;* KeyNum_Translate -- Translates extended keynums to normal keynums * ;* Stuff_Key_Word -- Stuffs a word of data into keyboard buffer * ;* Stuff_Key_Num -- Stuffs a key num code into the circular buffer * ;* Keystroke_Interrupt -- Real mode handler of input from the keyboard * ;* Break_Interrupt -- Handles the break key interrupt * ;* Call_Interrupt_Chain -- Function PM calls to call RM interrupt chain * ;* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * ;* * ;* Keyboard driver -- 8086 Assembly portion; * ;* updated by: Phil Gorrow for 32 bit Protected Mode * ;*************************************************************************** ;--------------------------------------------------------------------------- ; Set the assembly directives ;--------------------------------------------------------------------------- IDEAL ; the product runs in ideal mode P386N ; use 386 real mode instructions MODEL TINY ; code must be tiny so it fits LOCALS ?? ; ?? is the symbol for a local WARN ; generate all warnings we can JUMPS ; optimize jumps if possible ;--------------------------------------------------------------------------- ; Include all of the keyboard specific defines ;--------------------------------------------------------------------------- INCLUDE "keyboard.inc" CONDHIDE EQU 08000H ; bit for testing conditional region CONDHIDDEN EQU 04000H ; bit for testing conditional hidden RESTORE_VISIBLE_PAGE EQU 0 STORE_VISIBLE_PAGE EQU 1 GLOBAL set_vesa_page :near GLOBAL set_vesa_window :near GLOBAL get_vesa_window :near GLOBAL next_vesa_page :near ECHOON equ 0 ;--------------------------------------------------------------------------- ; WARNING!!!! All of the following code segment variables are shared by ; the protected mode interrupt. Do not change these unless you make the ; proper changes to KEYSTRUC.INC. If you do not know what you are doing, ; find someone who does!!! ;--------------------------------------------------------------------------- CODESEG ;--------------------------------------------------------------------------- ; Begin definition of Keyboard specific variables ;--------------------------------------------------------------------------- SoundOn DW 1 ; toggled by alt S MusicOn DW 1 ; toggled by alt M KeyFlags DD REPEATON+CTRLALTTURBO ; all but repeat for now Break DW 0 KeyMouseMove DB -1,0,1 DB -16,0,16 ScreenEdge DW 320/2,0 ; North DW 319,0 ; North-East DW 319,138/2 ; East DW 319,137 ; South-East DW 320/2,137 ; South DW 0,137 ; South-West DW 0,138/2 ; West DW 0,0 ; North-West DW 320/2,138/2 ; Center Bits DB 01H,02H,04H,08H,10H,20H,40H,80H CondPassKey DW 0220H, 0320H, 060CH, 070DH, 066AH DW 0669H, 0230H, 0330H, 007DH, 017DH DW 025AH, 035AH, 0200H, 0410H, 046EH DW 026EH, 007CH CondPassCond DW CTRLSON, CTRLSON, CTRLALTTURBO, CTRLALTTURBO, CTRLALTTURBO DW CTRLALTTURBO, CTRLCON, CTRLCON, SCROLLLOCKON, SCROLLLOCKON DW PAUSEON, PAUSEON, BREAKON, TASKSWITCHABLE, TASKSWITCHABLE DW TASKSWITCHABLE, BREAKON EscRoutine DD 0 ; vector to execute on esc key press (0=none) ; Extended raw keycodes to be converted to Westwood keycodes. ExtCodes DB 038H,01DH,052H,053H,04BH,047H,04FH,048H,050H,049H DB 051H,04DH,035H,01CH,037H DB 046H ; The matching Westwood keycodes. ExtNums DB 62, 64, 75, 76, 79, 80, 81, 83, 84, 85 DB 86, 89, 95, 108, 124, 0 ; If extended mapping is disabled, then these codes really are... ExtRemap DB 60, 58, 99, 104, 92, 91, 93, 96, 98, 101 DB 103, 102, 55, 43, 124, 0 ExtRemapEnd DB 0 ExtKeyboard DB 0 ; flag for 101/102-key keyboard KeyBuffer DW 128 DUP(0) ; set to empty KeyBufferHead DD 0 ; set to first entry KeyBufferTail DD 0 ; set to head for empty buffer KeyLock DW 0 ; num and caps lock bits KeyNums DB 127,110,002,003,004,005,006,007,008,009,010,011,012,013,015,016 DB 017,018,019,020,021,022,023,024,025,026,027,028,043,058,031,032 DB 033,034,035,036,037,038,039,040,041,001,044,029,046,047,048,049 DB 050,051,052,053,054,055,057,100,060,061,030,112,113,114,115,116 DB 117,118,119,120,121,090,125,091,096,101,105,092,097,102,106,093 DB 098,103,099,104,127,127,127,122,123 KeysCapsLock DB 0,0,0FEH,087H,0FFH,0C0H,01FH,0,0,0,0,0,0,0,0,0 KeysNumLock DB 0,0,0,0,0,0,0,0,0,0,0,038H,0EFH,1,0,0 KeysUpDown DB 16 DUP(0) ; set to all keys up KeyStream DB 16 DUP(0) ; set to all keys up PassCount DW 0 KeyStreamIndex DW 0 LastKeyE0 DB 0 LastKeyE1 DB 0 ; ; Westwood key number values of keys to pass through ; ; CAPS, LEFT_SHIFT, RIGHT_SHIFT, LEFT_CTRL, LEFT_ALT, ; RIGHT_ALT, RIGHT_CTRL, NUM_LOCK, UNKNOWN PassAlways DB 30, 44, 57, 58, 60, 62, 64, 90, 128, 128 PassAlwaysEnd DB 128 ; invalid code to END PassAlways CtrlFlags DB 0 Buffer DW ? Time DW ? ADJUST = 1 ; do not modify DRD XYAdjust DB -ADJUST, -ADJUST ; 91 -> upleft DB -ADJUST, 0 ; 92 -> left DB -ADJUST, ADJUST ; 93 -> downleft DB 0, 0 ; 94 illegal DB 0, 0 ; 95 illegal DB 0, -ADJUST ; 96 -> up DB 0, 0 ; 97 illegal (center) DB 0, ADJUST ; 98 -> down DB 0, 0 ; 99 illegal DB 0, 0 ; 100 illegal DB ADJUST, -ADJUST ; 101 -> upright DB ADJUST, 0 ; 102 -> right DB ADJUST, ADJUST ; 103 -> downright EdgeConv DW 8,2,8,6,4,3,8,5,8,8,8,8,0,1,8,7 MouseUpdate DW 0 MouseX DW 0,0 LocalMouseX DW 0 MouseY DW 0,0 LocalMouseY DW 0 IsExtKey DB 0 ExtIndex DW 0 KeyOldRMI DD 0 ; The origianl RM interrupt seg:off. KeyOldPMIOffset DD 0 ; The origianl PM interrupt offset KeyOldPMISelector DD 0 ; The original PM interrupt segment. KeyCodeOffset DW RM_Keystroke_Interrupt ; Offset of the code in the RM stuff. CallKeyRMIntOffset DW Call_Interrupt_Chain ; Offset of function to call DOS timer interrupt. CallKeyRMIntAddr DD 0 ; PM address of CallRealIntOffset for speed. PMIssuedKeyInt DD 0 BrkOldRMI DD 0 ; The origianl RM interrupt seg:off. BrkOldPMIOffset DD 0 ; The origianl PM interrupt offset BrkOldPMISelector DD 0 ; The original PM interrupt segment. BrkCodeOffset DW RM_Break_Interrupt ; Offset of the code in the RM stuff. CallBrkRMIntOffset DW 0 CallBrkRMIntAddr DD 0 ; PM address of CallRealIntOffset for speed. PMIssuedBrkInt DD 0 KeyIntDisabled DD 0 DbgOldPMIOffset DD 0 ; The origianl PM interrupt offset DbgOldPMISelector DD 0 ; The original PM interrupt segment. ;--------------------------------------------------------------------------- ; Begin definition of Mouse Specific Variables for real mode ;--------------------------------------------------------------------------- Button DB 0 ; current value of the mouse button MDisabled DB 0 ; Is the mouse driver disabled MInput DB 1 ; Defaults to mouse input allowed. Adjust DW 0 ; flag to adjust coordinates if necessary MouseStepX DW 0 ; step values if the mouse moves at MouseStepY DW 0 ; more than one pixel at a time MouseOffsetX DW 0 ; Fractional step values used if a mouse MouseOffsetY DW 0 ; moves at less than one pixel at a time MState DW 0,0 ; Tracks if mouse is hidden (TRUE) or not (FALSE) MouseXOld DW 0 ; Holds last MouseX and MouseY to determine if MouseYOld DW 0 ; mouse needs to be redrawn MCState DW 0 ; Tracks if mouse conditional hidden (TRUE) or not MouseCXLeft DW 0,0 ; Conditional hide mouse left x position MouseCYUpper DW 0,0 ; Conditional hide mouse top y position MouseCXRight DW 0,0 ; Conditional hide mouse right x position MouseCYLower DW 0,0 ; Conditional hide mouse lower y position MouseCursor DD 0 ; Pointer to the mouse cursor to draw MouseCursorSize DW 0 ; Pointer to buffer mouse is saved in MouseBuffer DD 0 ; Pointer to buffer mouse is saved in MouseXHot DW 0,0 ; Offset to mouse's x hot spot MouseYHot DW 0,0 ; Offset to mouse's y hot spot MouseBuffX DW 0,0 ; X position background was saved at MouseBuffY DW 0,0 ; Y position background was saved at MouseBuffW DW 0,0 ; Width of the region saved for mouse MouseBuffH DW 0,0 ; Height of the region saved for mouse MouseWidth DW 0,0 ; Mouse cursor theoretical width MouseHeight DW 0,0 ; Mouse cursor theoretical height MouseCodeOffset DW RM_Mouse_Interrupt ; Offset of the code in the RM stuff. MouseRight DW 0,0 MouseBottom DW 0,0 ShadowPtr dw 0 DrawMousePtr dw 0 VGAMouseDraw dw VGA_Draw_Mouse VGAMouseShadow dw VGA_Mouse_Shadow_Buffer VESAMouseDraw dw VESA_Draw_Mouse VESAMouseShadow dw VESA_Mouse_Shadow_Buffer VesaPtr dd 0 banktable dd 8 dup ( 0 ) Adjust_XPos dw 0 , 0 Adjust_YPos dw 0 , 0 align 2 Keyboard_App_Stack_ES dw 0 ; This the System Stack Offsset Keyboard_App_Stack_SS dw 0 ; This the System Stack Selector Keyboard_StackPointer dw 0DEADh ; We Create a Local Application Keyboard_Stack dw 512 dup (0) Keyboard_StackStart dw 0 Mouse_State dw 0 ; Mouse Temp Variable Mouse_Cond dw 0 ; Mouse Temp Variable Mouse_App_Stack_ES dw 0 ; This the System Stack Offsset Mouse_App_Stack_SS dw 0 ; This the System Stack Selector Mouse_StackPointer dw 0DEADh ; We Create a Local Application Mouse_Stack dw 512 dup (0) Mouse_StackStart dw 0 current_page dw 0 ;*************************************************************************** ;* KEYNUM_TRANSLATE -- Translates extended keynums to normal keynums * ;* * ;* INPUT: UWORD the keynum to translate * ;* * ;* OUTPUT: WORD the translated keynum * ;* * ;* PROTO: UWORD KeyNum_Translate(UWORD keynum); * ;* * ;* HISTORY: * ;* 07/11/1994 PWG : Created. * ;*=========================================================================* GLOBAL KeyNum_Translate:FAR PROC KeyNum_Translate C FAR USES cx,di,es,ds ARG keycode:WORD mov ax,cs ; since we are in tiny model mov ds,ax ; set cs = ds mov es,ax ; set es up for scansb mov ax,[keycode] test [WORD PTR KeyFlags],TRACKEXT jne short ??fini mov cx,ExtRemap-ExtNums mov di,OFFSET ExtNums repne scasb jcxz short ??fini ; No match found. mov di,OFFSET ExtRemapEnd dec di sub di,cx mov al,[es:di] ??fini: ret ENDP KeyNum_Translate ;*************************************************************************** ;* STUFF_KEY_WORD -- Stuffs a word of data into keyboard buffer * ;* * ;* INPUT: WORD the code to stick into the circular buffer * ;* * ;* OUTPUT: WORD !=0 is sucessful, ==0 is not enough room * ;* * ;* PROTO: VOID Stuff_Key_WORD(WORD code); * ;* * ;* HISTORY: * ;* 07/11/1994 PWG : Created. * ;*=========================================================================* GLOBAL C Stuff_Key_WORD:FAR PROC Stuff_Key_WORD C FAR USES si,bx,ds ARG code:WORD mov ax,cs ; since we are in tiny model mov ds,ax ; set cs = ds mov ax,[WORD PTR KeyBufferTail] mov si,ax add ax,2 and ax,0FFh ; New KeyBufferTail value. cmp [WORD PTR KeyBufferHead],ax je short ??noroom mov bx,[code] mov [KeyBuffer+si],bx ; Record the keystroke. mov [WORD PTR KeyBufferTail],ax xor ax,ax ret ??noroom: mov ax,1 ret ENDP Stuff_Key_WORD ;*************************************************************************** ;* STUFF_KEY_NUM -- Stuffs a key num code into the circular buffer * ;* * ;* INPUT: WORD the keycode to stuff * ;* * ;* OUTPUT: WORD !=0 is sucessful, ==0 is not enough room * ;* * ;* PROTO: VOID Stuff_Key_Num(WORD keynum); * ;* * ;* HISTORY: * ;* 07/11/1994 PWG : Created. * ;*=========================================================================* GLOBAL C Stuff_Key_Num:FAR PROC Stuff_Key_Num C FAR USES bx,cx,dx,di,si,ds ARG keycode:WORD LOCAL tail:WORD ; Original keybuffer tail (safety copy). LOCAL size:WORD ; Size of write. pushf cli ; disable interrupts ; Abort key recognition if in record mode and unable ; to output key due to simultaneous DOS operation. mov ax,cs ; since we are in tiny model mov ds,ax ; set cs = ds ; Record the mouse position to be stuffed into buffer. mov ax,[MouseX] mov [LocalMouseX],ax mov ax,[MouseY] mov [LocalMouseY],ax ??cando: mov ax,[keycode] ; get the code or ax,ax ; Null keycodes are not recorded. jne short ??validkey jmp ??exit ??validkey: test [WORD PTR KeyFlags],KEYMOUSE ; is the numeric keypad moving the mouse? je ??no_pad_move ; ALT-cursor keys are undefined. Pass them on to the program. test ah,ALTPRESS ; is either alt key down? jne ??no_pad_move test [WORD PTR KeyFlags],SIMLBUTTON ; are we simulating left mouse presses je short ??chkinsert cmp al,KN_RETURN je short ??forceleft cmp al,KN_SPACE je short ??forceleft cmp al,KN_KEYPAD_RETURN je short ??forceleft ??chkinsert: cmp al,KN_INSERT jne short ??regular ??forceleft: mov al,KN_LMOUSE or [Button],1 ; Left mouse bit. test ah,KEYRELEASE je ??mousefake and [Button],NOT 1 jmp ??mousefake ??regular: cmp al,KN_DELETE jne short ??regular2 mov al,KN_RMOUSE or [Button],2 ; Right mouse bit. test ah,KEYRELEASE je ??mousefake and [Button],NOT 2 jmp ??mousefake ??regular2: ; DRD correction to ignore key releases for key mouse movement test ah,KEYRELEASE jne ??no_pad_move cmp al,KN_CENTER je short ??pad_move cmp al,KN_UPLEFT ; less than upleft? jb ??no_pad_move ; yes, then it isn't a keypad key cmp al,KN_DOWNRIGHT ; greater than downright? ja ??no_pad_move ; yes, then it isn't a keypad key cmp al,KN_DOWNLEFT ; is it UPLEFT, LEFT, or DOWNLEFT? jbe short ??pad_move cmp al,KN_UPRIGHT ; is it UPRIGHT, RIGHT, or DOWNRIGHT? jae short ??pad_move cmp al,KN_UP ; up? je short ??pad_move cmp al,KN_DOWN ; down? jne ??no_pad_move ??pad_move: ; DRD correction to use ch for ah mov ch,ah ; save shift-ctrl-alt-rlse status xor ah,ah ; get rid of any bits sub al,KN_UPLEFT ; get a number between 0 and 12 mov bx,ax shl bx,1 ; double for WORD index add bx,OFFSET XYAdjust mov ax,[bx] ; get x,y add value mov bl,ah cbw xchg ax,bx cbw xchg ax,bx ; AX = mouse x delta, BX = mouse y delta ; DRD correction to use ch ; The CTRL key moves the mouse to the edge of the screen. test ch,CTRLPRESS ; is either ctrl key down? jne short ??ctrlon ; if so, ctrl is on ; DRD correction to use ch ; use fast speed of the mouse move if the shift key is held down. mov dx,1 ; for slow speed test ch,SHIFTPRESS ; is either shift key down? je short ??normspeed ; if not then neither shift is down ??doublespeed: add dx,3 ; for fast speed ??normspeed: add bx,dx ; add speed for y index mov bl,[KeyMouseMove+bx] ; get speed for y delta xchg ax,bx ; swap with ax to extend sign cbw xchg ax,bx xchg bx,dx ; save mouse y delta add bx,ax ; add speed for x index mov al,[KeyMouseMove+bx] ; get speed for x delta cbw xchg bx,dx ; restore mouse y delta jmp short ??ctrloff ??ctrlon: ; Table lookup method for determining hotkey positions for CTRL ; cursor combination. This algorithm is hard coded for an ADJUST ; value of 3. If this value changed, then this section will also ; have to be modified. and bx,011b ; Y = 1, 0, 3 and ax,011b ; X = 1, 0, 3 ; Table lookup method for determining hotkey positions for CTRL ; cursor combination. This algorithm is hard coded. ; -1, 0, 1 and bx,011b ; Y = 3, 0, 1 and ax,011b ; X = 3, 0, 1 shl bx,1 shl bx,1 or bx,ax ; Lookup index. ; Convert raw index into logical (clockwise) index. shl bx,1 mov bx,[EdgeConv+bx] shl bx,1 shl bx,1 mov ax,[ScreenEdge+bx] ; New absolute X mov bx,[ScreenEdge+bx+2] ; New absolute Y mov [LocalMouseX],ax mov [LocalMouseY],bx ??set_xyz: mov ax,[LocalMouseX] ; get new mouse x,y mov bx,[LocalMouseY] jmp short ??set_xy ; Process a normal faked mouse move. ??ctrloff: ; DRD change add [LocalMouseX],ax ; save it in our local jns short ??not_negative_x xor ax,ax mov [LocalMouseX],ax ; clear our local ??not_negative_x: ; DRD change add [LocalMouseY],bx ; save it in our local jns short ??not_negative_y xor bx,bx mov [LocalMouseY],bx ; clear our local ??not_negative_y: mov ax,[LocalMouseX] ; get new mouse x,y mov bx,[LocalMouseY] cmp ax,MAX_X_PIXEL ; bigger than jle short ??check_y mov ax,MAX_X_PIXEL ??check_y: cmp bx,MAX_Y_PIXEL ; bigger than jle short ??set_xy mov bx,MAX_Y_PIXEL ??set_xy: mov [LocalMouseX],ax mov [LocalMouseY],bx mov [MouseX],ax mov [MouseY],bx cmp [MouseUpdate],0 ; wait until mouse interrupt is done jne short ??noshow call Low_Hide_Mouse call Low_Show_Mouse ??noshow: mov ax,KN_MOUSE_MOVE ??mousefake: mov [keycode],ax ; Fake a MOUSE_MOVE event. ??no_pad_move: ; Fetch working pointers to the keyboard ends. mov si,[WORD KeyBufferTail] mov [tail],si ; Safety record. mov di,[WORD PTR KeyBufferHead] ; Record the base keycode (if there is room). push ax call Stuff_Key_WORD add sp,2 or ax,ax jne short ??jmpnoroom ; Also record the mouse coordinates if necessary. mov ax,[keycode] ; get key code cmp al,KN_MOUSE_MOVE ; mouse move? je short ??recordmouse ; yes? then record the mouse cooordinates cmp al,KN_LMOUSE je short ??recordmouse cmp al,KN_RMOUSE je short ??recordmouse jmp short ??ok ??jmpnoroom: jmp ??noroom ; Record mouse coordinate X. ??recordmouse: push [LocalMouseX] call Stuff_Key_WORD add sp,2 or ax,ax jne ??jmpnoroom add [size],2 ; Record mouse coordinate Y. push [LocalMouseY] call Stuff_Key_WORD add sp,2 or ax,ax jne ??jmpnoroom add [size],2 ??ok: ; If PASSBREAKS is not active and this is a keyboard ; break AND it is not a mouse event, then don't put ; it into the buffer. mov bx,0101h ; Bit control tools. mov ax,[keycode] cmp al,KN_MOUSE_MOVE je short ??notreal cmp al,127 je short ??notreal test ah,KEYRELEASE je short ??real xor bl,bl test [WORD PTR KeyFlags],PASSBREAKS jne short ??real cmp al,KN_LMOUSE je short ??real cmp al,KN_RMOUSE je short ??real ??notreal: mov [WORD PTR KeyBufferTail],si ; Nullify any KeyBufferTail changes. ??real: ; Update the KeysUpDown bit array. mov di,ax and di,07Fh mov cl,3 shr di,cl ; DI = Byte offset into bit table. mov cl,al and cl,0111b ; CL = Bit offset into bit table byte. shl bx,cl not bh ; If this is a reapeat key and the key is already being held ; down, then don't stuff it into the keyboard buffer. test bl,[KeysUpDown+di] je short ??notalready test [WORD PTR KeyFlags],REPEATON jne short ??notalready mov [WORD PTR KeyBufferTail],si ; Nullify any KeyBufferTail changes. ??notalready: and [KeysUpDown+di],bh ; Force key bit to zero. or [KeysUpDown+di],bl ; Insert key bit as appropriate. ;??notreal: ; Successful keybuffer stuff could result in a ??norecord: mov ax,1 jmp short ??exit ; Unsuccessful keybuffer stuff. ??noroom: mov ax,[tail] mov [WORD PTR KeyBufferTail],ax xor ax,ax ; Signal an error. ??exit: popf ret ENDP Stuff_Key_Num ;*********************************************************** ;*************************************************************************** ;* KEYSTROKE_INTERRUPT -- Handles input that comes from the keyboard * ;* * ;* This routine intercepts the key codes on their way to the * ;* BIOS. With the adjustment of the Flags described above * ;* you can get a wide variety of effects. * ;* * ;* INPUT: none * ;* * ;* OUTPUT: none * ;* * ;* WARNINGS: This is an interrupt function * ;* * ;* HISTORY: * ;* 07/13/1994 PWG : Created. * ;*=========================================================================* label RM_Keystroke_Interrupt GLOBAL C Keystroke_Interrupt:FAR PROC Keystroke_Interrupt C FAR IF 0 push ax inc ax pop ax iret ELSE push ax push bx push cx push di push ds push dx push es push si cld mov ax,cs ; set ds to cs to avoid cs overide mov ds,ax ; At this point we do not know if the SS selector is a ; System Stack or the Application Stack pointer. ; Soo to be in the safe side we create our own local ; Stack Pointer Selector Relative to DS ; Note Do not try this trick in a reentrant interrupt mov cx, ss ; get SS mov [Keyboard_App_Stack_ES], sp ; Protect ES mov [Keyboard_App_Stack_SS], cx ; Protect SS lea dx, [Keyboard_StackStart ] ; Compute Local Stack size and dx, -2; cli ; Disable All interrupts mov ss, ax ; Set new SS Selector mov sp, dx ; Set new Stack Offset sti ; Enable Interrupts cmp [WORD PTR PMIssuedKeyInt],0; Check to see if PM made Int call. mov [WORD PTR PMIssuedKeyInt],0; Make it false. jne ??passcode ; if so, just call Int Chain. mov dx,[WORD PTR KeyFlags] ;*** The following fix allows proper caps and num lock tracking on Tandy ; 10-6-89 LJC, DRD and [KeyLock],NOT (NUMLOCK OR CAPSLOCK); assume caps and num inactive mov ax,040H ; BIOS segment mov es,ax ; put in es test [BYTE PTR es:017H],040H ; test Caps lock bit in BIOS je short ??bioscapsoff ; skip activate code or [KeyLock],CAPSLOCK ; Caps Lock active ??bioscapsoff: test [BYTE PTR es:017H],020H ; test Num lock bit in BIOS je short ??biosnumoff ; skip activate code or [KeyLock],NUMLOCK ; Num Lock active ??biosnumoff: mov [ExtKeyboard],TRUE ; assume 101/102-key keyboard test [BYTE PTR es:096H],010H ; test for 101/102-key keyboard jne short ??extkeyboard ; skip deactivate code mov [ExtKeyboard],FALSE ; no 101/102-key keyboard ??extkeyboard: mov ax,cs ; set ds to cs to avoid cs overide mov es,ax cld ; clear direction flag for strings xor ah,ah ; clear ctrl flags to 0 mov bx,0101H ; set key to a make by default in al,KEYDATA ; get a code from the keyboard ; ; New CODE to montior key stream ; mov bx,[KeyStreamIndex] mov [KeyStream+bx],al inc bx and bx,15 mov [KeyStreamIndex],bx mov bx,0101H ; set key to a make by default ; ; END OF SEQUENCE ; ; ; Handle the PAUSE key being pressed. If it is pressed, then ; signal that the next two input codes are to be thrown out. ; cmp al,0E1H ; see if this is a pause/break jne short ??notpcode ; not a pause/break start code mov [LastKeyE1],3 ; absorb this and next two codes ??notpcode: cmp [LastKeyE1],0 ; are we in a pause/break code je short ??notpause ; no, just keep going dec [LastKeyE1] ; yes, dec the count test dx,PAUSEON ; should it pass these codes jne ??passcode ; pass the code jmp ??absorbcode ; don't pass code ??notpause: ; ; Record any extended key codes that arrive. They will be ; taken into account with the next code. ; cmp al,0E0H ; is it an extended code jne short ??notextcode ; if not skip to handle key mov [LastKeyE0],TRUE ; set the extended code to 1 ??jmppasscode: jmp ??passcode ; always pass E0s ??notextcode: ; ; Check and acknowledge if the key is a make or a break. ; test al,080H ; test for high bit je short ??make ; if off its a make xor bl,bl ; set make/break to break and al,07FH ; clear high bit or ah,KEYRELEASE ; CDY NEW -- ABSENT IN OLD CODE ??make: ; ; Translate the raw keycode into the Westwood keycode. ; cmp [LastKeyE0],FALSE ; was the prev byte an E0? je short ??normal ; if not it is a normal key mov [LastKeyE0],FALSE ; if so clear for next read mov [IsExtKey],TRUE ; it is an extended key mov di,OFFSET ExtCodes ; get offset of extended codes table mov cx,(ExtNums-ExtCodes) ; get number of entrys in ext table repne scasb ; look for a match jcxz ??absorbcode ; Not recognized, so throw it away. mov al,[(ExtNums - ExtCodes) - 1 + di] ; get the match mov [IsExtKey],FALSE ; it is not an extended key jmp short ??notext ??normal: cmp al,07Ah jne short ??normok mov al,128 jmp short ??notext ??normok: mov di,ax ; use code as an index and di,007Fh ; Mask off any release bit. mov al,[KeyNums+di] ; get the key number of this key ??notext: ; ; Test and set the CTRL bit. ; test [KeysUpDown+8],001H ; is the right ctrl down? jne short ??ctrlon ; if so, ctrl is on test [KeysUpDown+7],004H ; is the left ctrl down? je short ??ctrloff ; if not, neither are down, no ctrl ; DRD ; check for CTRL-NUMLOCK for pause on some keyboards cmp al,KN_NUMLOCK ; check for CTRL-NUMLOCK jne short ??ctrlon cmp [ExtKeyboard],TRUE ; if 101/102-key keyboard it is ok je short ??ctrlon test dx,PAUSEON ; should it pass these codes jne short ??ctrlon ; pass the code jmp ??absorbcode ; don't pass code ??ctrlon: or ah,CTRLPRESS ; or on the ctrl bit in flags ??ctrloff: ; ; Test and set the ALT bit. ; test [KeysUpDown + 7],050H ; is either alt key down? je short ??altoff or ah,ALTPRESS ; or on the alt bit in flags ??altoff: ; ; Remap the keyboard keys if this is requested. (Do not set DGROUP ; as it is unecessary) push ax call KeyNum_Translate add sp,2 ;------ Set the shift bit if necessary. test [KeysUpDown+5],010H ; is the left shift down? jne short ??shifton ; if so the shift is on test [KeysUpDown+7],002H ; is the right shift down? je short ??shiftoff ; if not then neither shift is down ??shifton: or ah,SHIFTPRESS ; or on the shift bit in flags ??shiftoff: ; ;------ Toggle the shift state if the caps lock key is on (if necessary). ; mov di,ax and di,07Fh shr di,1 shr di,1 shr di,1 mov bx,ax and bx,07Fh and bl,0111b mov ch,[Bits+bx] ; get the bit to test test [KeyLock],CAPSLOCK ; is the caps lock on? je short ??capsoff ; if not don't worry about it test ch,[KeysCapsLock+di] ; get code for keycaps je short ??capsoff ; its not effected xor ah,SHIFTPRESS ; toggle the shift flag ??capsoff: ; ;------ Toggle the shift state if the num-lock key is on (if necessary). ; test [KeyLock],NUMLOCK ; is the num lock key on? je short ??numlockoff ; if not don't worry about it test ch,[KeysNumLock+di] ; get code for numlock je short ??numlockoff ; if not effected skip toggle xor ah,SHIFTPRESS ; toggle the shift flag if effected ??numlockoff: ;------ Remember the current control/shift/alt bit settings for later use. ;??noshiftever: mov [CtrlFlags],ah ; save off shift-ctrl-alt flags ; for the mouse and joystick routines ; to use in stuffing key into the ; keyboard buffer. test dx,DEBUGINT jz ??not_toggle IF DEBUG cmp [KeyIntDisabled],1 jne ??not_currently_disabled cmp ax,115 ; is it the F4 key je ??disable cmp ax,118 ; is it less then F7 key jb ??justpass cmp ax,120 ; is it greater than F9 key ja ??justpass ??disable: mov [KeyIntDisabled],0 ??justpass: jmp ??passcode ??not_currently_disabled: cmp ax,125 jne ??not_toggle mov [KeyIntDisabled],1 jmp ??absorbcode ENDIF ??not_toggle: ;------ The CTRL-ALT-DEL key combination always gets passed to the system. cmp ax,0668H ; is it ctrl alt del? je ??passcode cmp ax,064CH ; is it ctrl alt ext del? je ??passcode ; if so don't add it to the buffer ;------ Special Ctrl-C check. cmp ax,0230h je short ??breaker cmp ax,027Eh jne short ??nobreak ??breaker: mov [Break],1 ??nobreak: ;------ Check for Music and Sound control keys. cmp ax,0420H ; is this an alt s jne short ??checkmusic ; toggle the Sound variable push ax mov ax,[SoundOn] xor ax,01H push ax add sp,2 pop ax ??checkmusic: cmp ax,0434H ; is this an alt m jne short ??esc ; toggle the Music variable push ax mov ax,[MusicOn] xor ax,01H push ax add sp,2 pop ax ??esc: push ax call Stuff_Key_Num pop ax ??skipstuff: ;------ Do the special ESC routine if necessary. cmp al,110 ; is this the esc key? jne short ??noroutine ; if not goto the pass always cmp [WORD PTR EscRoutine+2],0 ;if vector is 0 don't jump je short ??noroutine push ax call [EscRoutine] pop ax ??noroutine: ;------ Check to see if the key is to be passed to the system or not. mov di,OFFSET PassAlways ; get offset to table mov cx,(PassAlwaysEnd - PassAlways) ; get number of pass always CDY JLB MOD 7/11 was +1 repne scasb ; look for a match or cx,cx ; see if there was no match jne ??passcode ; CDY JLB 7/11 optimization ??passalways: ; now check for conditional passes mov di,OFFSET CondPassKey ; get offset to cond key table mov cx,(CondPassCond-CondPassKey) ; get number of entries shr cx,1 ; cut in half for words repne scasw ; look for a match jcxz short ??notcondpass ; OPTIMIZATION CDY JLB mov bx,[(CondPassCond - CondPassKey) - 2 + di] and bx,dx ; are the conditions met? je short ??notcondpass ; NO... check normally. jmp short ??passcode ; YES... pass back to system. ; ;------ Last check before passing keycode back to the system. ; ??notcondpass: test dx,FILTERONLY ; is the filter only flag on? je short ??absorbcode ; if not, absorb the code. ??passcode: inc [cs:PassCount] ;mov ax , 0B000h ;mov es, ax ;inc [BYTE PTR es : 40h] ; Now it is time to set up for the call to the System Keyboard ; interrupt handler. ; 1 -Restore System Stack Pointer Selector before exit Interrupt ; 2- We Create a Returning Point from Interrupt by Push A ; Interupt Stack Frame into the Stack Pointer ; 3- We make a Far jump to the interuupt handler cmp [Keyboard_StackPointer],0DEADh je ??stackok push cx push di push ax push es mov ax,0A000h mov es,ax xor di,di mov cx,64000 mov ax,1 rep stosb pop es pop ax pop di pop cx ??stackok: cli ; disable Interrupts mov dx, [Keyboard_App_Stack_SS] mov ss, dx ; Get System Stack Selector mov sp, [Keyboard_App_Stack_ES] ; Get System Stack offset sti ; Enable Interrupts lea dx, [??Call_Back_Keyboard] ; Get Return address offset pushf ; push flags push cs ; push Code segment push dx ; push Offset ; Now we need to simulate an interrup call by using ired ; because we still want to come back here from the ; Old Keyboard interrupt handle. pushf push [word ptr KeyOldRMI + 2] ; push orig segment. push [word ptr KeyOldRMI] ; push orig offset. iret ; call interrupt ??absorbcode: ;mov ax , 0B000h ;mov es, ax ;inc [BYTE PTR es : 0h] in al,KEYCTRL ; get the control port mov ah,al or al,080H ; reset bit for keyboard out KEYCTRL,al xchg ah,al ; get orig control data out KEYCTRL,al ; restore control data mov ax,040h ; BIOS paragraph is always @ 040h mov es,ax ; put in es as BIOS paragraph mov al,[es:96h] ; get extended keys and al,0FDh ; turn off last key e0 flag mov [es:96h],al ; set extended keys mov al,CLEARISR ; value to clear In Service Register out INTCHIP0,al ; 8259 interrupt chip controller 0 cmp [Keyboard_StackPointer],0DEADh je ??stackok2 push cx push di push ax push es mov ax,0A000h mov es,ax xor di,di mov cx,64000 mov ax,1 rep stosb pop es pop ax pop di pop cx ??stackok2: ; Restore System Stack Pointer Selector before exit Interrupt mov dx, [Keyboard_App_Stack_SS] cli ; disable Interrupts mov ss, dx ; Get Syatem Stack Selector mov sp, [Keyboard_App_Stack_ES] ; Get Syatem Stack offset sti ; Enable Interrupts ??Call_Back_Keyboard: pop si pop es pop dx pop ds pop di pop cx pop bx pop ax iret ENDIF ENDP Keystroke_Interrupt ;*************************************************************************** ;* Break interrupt routines begin here! ;*************************************************************************** ;*************************************************************************** ;* BREAK_INTERRUPT -- Handles the break key interrupt * ;* * ;* INPUT: none * ;* * ;* OUTPUT: none * ;* * ;* WARNINGS: This is an interrupt routine. * ;* * ;* HISTORY: * ;* 07/13/1994 PWG : Created. * ;*=========================================================================* label RM_Break_Interrupt GLOBAL C Break_Interrupt:FAR PROC Break_Interrupt C FAR pushf push ax push es mov ax,0B000h ; ES:DI = Mono RAM address. mov es,ax inc [BYTE PTR es:0] pop es pop ax popf iret ENDP Break_Interrupt ;************************************************************************** ;* CALL_INTERRUPT_CHAIN -- Function PM calls to call the RM interrupt chain* ;* * ;* * ;* INPUT: none * ;* * ;* OUTPUT: none * ;* * ;* HISTORY: * ;* 07/08/1994 SKB : Created. * ;*=========================================================================* Call_Interrupt_Chain: pushf call Keystroke_Interrupt ;[KeyOldRMI] retf ;---------------------------------------------------------------------------- ; LOW_HIDE_MOUSE: ; ; This function hides the mouse cursor on the screen if it was shown. It ; will not hide the mouse if it is already hidden. ; ; PROTOTYPE: ; ; VOID Low_Hide_Mouse(VOID); ; ; NOTE: does not check if mouse is currently being updated. ; ;---------------------------------------------------------------------------- GLOBAL C Low_Hide_Mouse:FAR PROC Low_Hide_Mouse C FAR USES ax,bx,cx,dx,ds mov ax,cs ; since we are in tiny model mov ds,ax ; set cs = ds cmp [MDisabled],0 ; check if mouse is disabled jne short ??end cmp [MState],0 ; check if it was hidden before jne short ??endnodraw ; no need to hide again ;------ Move the saved graphic buffer to the seenpage to hide the mouse. ; call Buffer_To_Page C,[buffx],[buffy],[buffw],[buffh],[MouseBuffer],SEENPAGE mov ax,RESTORE_VISIBLE_PAGE push ax push cs call [ ShadowPtr ] add sp,2 ;------ Record that the mouse has been hidden. ??endnodraw: add [MState],1 adc [MState],0 ??end: ret ENDP Low_Hide_Mouse ;---------------------------------------------------------------------------- ;---------------------------------------------------------------------------- ; LOW_SHOW_MOUSE: ; ; This function displays the mouse cursor on the screen if it was hidden. ; ; PROTOTYPE: ; VOID Low_Show_Mouse(VOID); ; ; NOTE: does not check if mouse is currently being updated. ;---------------------------------------------------------------------------- GLOBAL C Low_Show_Mouse:FAR PROC Low_Show_Mouse C FAR USES ax,bx,cx,dx,si,di,ds,es LOCAL mousex:WORD ; Draw X position. LOCAL mousey:WORD ; Draw Y position. mov ax,cs ; since we are in tiny model mov ds,ax ; set cs = ds ;----- Don't show the mouse if it is not hidden, disabled. cmp [MDisabled],0 ; is the mouse disabled jne ??exit ; if so then exit cmp [MState],0 ; is the mouse already visible je ??exit ; if so then exit dec [MState] cmp [MState],0 ; can the mouse be shown jne short ??exit ;------ Determine the drawing position of the mouse. mov cx,[MouseWidth] ; Theoretical buffer width (pixel). mov dx,[MouseHeight] ; Theoretical buffer height (pixel). mov ax,[MouseX] ; sub ax,[MouseXHot] mov [mousex],ax ; Draw X pixel. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; IF 0 ; jns short ??xnotneg ; add cx,ax ; Reduce width accordingly. ; mov ax,0 ??xnotneg: ENDIF ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; mov bx,[MouseY] ; sub bx,[MouseYHot] mov [mousey],bx ; Draw Y pixel. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; IF 0 ; jns short ??ynotneg ; add dx,bx ; Reduce height of mouse accordingly. ; mov bx,0 ??ynotneg: ENDIF ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;------ Determine the theoretical coordinates and dimensions of the ; area the mouse shape will be rendered upon. mov [MouseBuffX],ax mov [MouseBuffY],bx mov [MouseBuffW],cx mov [MouseBuffH],dx ;------ Move the area that will be drawn upon, to the graphic buffer. mov ax,STORE_VISIBLE_PAGE push ax push cs call [ ShadowPtr ] add sp,2 ;------ Draw the mouse shape to the seenpage. push [mousey] push [mousex] push cs call [ DrawMousePtr ] add sp,4 ??exit: ret ENDP Low_Show_Mouse ;---------------------------------------------------------------------------- ;---------------------------------------------------------------------------- GLOBAL C Mouse_KeyNum:FAR PROC Mouse_KeyNum C FAR USES bx ARG state:WORD ; Current mouse state. LOCAL keynum:WORD ; Determined keynum. mov ax,cs ; since we are in tiny model mov ds,ax ; set cs = ds mov [keynum],KN_MOUSE_MOVE ; Presume just a mouse move. mov bx,[state] mov ax,bx xor bl,[Button] ; Bits of state change. je short ??fini mov [Button],al ; Record new mouse state. test bl,0010b je short ??notright mov [keynum],KN_RMOUSE test al,0010b jne short ??notright or [keynum],0800h ; Release bit on. ??notright: ; DRD ; note: the left mouse button has priority over the right mouse button ; this should be changed at a later date to process them independently test bl,0001b je short ??notleft mov [keynum],KN_LMOUSE test al,0001b jne short ??notleft or [keynum],0800h ; Release bit on. ??notleft: ??fini: mov ax,[keynum] ret ENDP Mouse_KeyNum ;---------------------------------------------------------------------------- ;---------------------------------------------------------------------------- ; MOUSE_INT: ; ; This routine is called automatically when the Mouse_Int is installed. It ; automatically updates the global variables stored in the code segment so ; that the mouse information is automatically known at all times. ; ; INPUTS (from int): AX = condition mask ( bit 0 == cursor position chg, ; bit 1 == left button press, ; bit 2 == left button release, ; bit 3 == right button press, ; bit 4 == right button release, ; 5-15 == not used ) ; BX = button state ( bit 0 == left button down, ; bit 1 == right button down, ; bit 2 == middle button down. ; 3-15 == not used ) ; CX = cursor coordinate (horizontal axis) ; DX = cursor coordinate (vertical axis) ; DI = horizontal mouse count (mickeys) ; SI = vertical mouse count (mickeys) ; ; RETURNS: none ; ; MODIFIES: modifies the variables _Button, _ButtonChange, ; _MouseX,_MouseY,_ButtonLatch ; ; PROTOTYPE: ; This routine is called from an interrupt. ;---------------------------------------------------------------------------- label RM_Mouse_Interrupt PROC Mouse_Int C FAR USES ax,bx,cx,dx,ds,si,es,di LOCAL cond:WORD ; Local copy of mouse event. LOCAL state:WORD ; Local copy of button state. mov [cs:Mouse_State],bx mov [cs:Mouse_Cond],ax mov ax,cs ; since we are in tiny model mov ds,ax ; set cs = ds ; At this point we do not know if the SS selector is a ; System Stack or the Application Stack pointer. ; Soo to be in the safe side we create our own local ; Stack Pointer Selector Relative to DS ; Note Do not try this trick in a reentrant interrupt mov bx, ss ; get SS mov [Mouse_App_Stack_ES], sp ; Protect ES mov [Mouse_App_Stack_SS], bx ; Protect SS lea bx, [Mouse_StackStart ] ; Compute Local Stack size and bx, -2; cli ; Disable All interrupts mov ss, ax ; Set new SS Selector mov sp, bx ; Set new Stack Offset sti ; Enable Interrupts push ax push dx mov dx,3c8h xor al,al out dx,al inc dx out dx,al mov dx,3c9h mov ax,cx shr ax,3 out dx,al jmp ??j1 ??j1: xor al,al out dx,al jmp ??j2 ??j2: out dx,al jmp ??j3 ??j3: pop dx pop ax ;------ Process the mouse interrupt only if the mouse is enabled (whether ; present or not). cmp [MDisabled],0 jne ??exit cmp [MInput],0 je ??exit ;------ This was added because of missing mouse presses and ; releases during a mouse update. mov ax,[Mouse_Cond] and ax,0001EH ; bits for left and right press and release jne short ??dopress_release cmp [MouseUpdate],0 ; if mouse move and mouse updating exit jne ??exit ??dopress_release: ;------ In EEGA mode mouse X coordinates as 0..639. Make adjustment ; to keep within 0..319 range. cmp [Adjust],1 ; if the x coordinate is returned jne short ??noadjust ; incorrectly then shr cx,1 ; adjust x coord from 640 pixel screen ??noadjust: ; scale mouse posX and PosY ; cmp [Adjust_XPos] , 0 ; jz short ??no_scaleX ; push dx ; mov ax , [MouseRight] ; imul cx ; idiv [Adjust_XPos] ; mov cx , ax ; pop dx ??no_scaleX: ; cmp [Adjust_YPos] , 0 ; jz short ??no_scaleY ; mov ax , [MouseBottom] ; imul dx ; idiv [Adjust_YPos] ; mov dx , ax ??no_scaleY: ;------ Keep mouse within screen bounds. cmp cx,[MouseRight] ; in EGAMODE, the mouse may go to 320 jb short ??boundX_ok ; force it to stay at least one pixel mov cx,[MouseRight] ; on the screen dec cx ??boundX_ok: cmp dx,[MouseBottom] ; in EGAMODE, the mouse may go to 320 jb short ??boundY_ok ; force it to stay at least one pixel mov dx,[MouseBottom] ; on the screen dec dx ??boundY_ok: IF 0 ;------ Remap the middle button to equal the right button. test bx,04h je ??noremap or bx,0010b ; Set the right button bit. ??noremap: ENDIF mov [MouseX],cx ; and store in mouse x mov [MouseY],dx ; store y coord in mouse y test [KeyFlags],KEYMOUSE jne short ??nostuffit call Mouse_KeyNum C,[Mouse_State] ; Convert mouse state to key number code. call Stuff_Key_Num C,ax ; Record mouse keynumber code. ??nostuffit: ;------ The check for Mouse in the middle of updating CAN NOT BE MOVED ; any farther up because mouse presses and releases will be LOST!! cmp [MouseUpdate],0 jne ??exit ;??jexit: ; jmp ??exit christopher: ??chkxy: ;------ Signal that no mouse updating can occur at this time. ; cmp [_MouseUpdate],0 ; jne ??exit ; mov [_MouseUpdate],1 ;------ Perform any X movement grid adjustment. cmp [MouseStepX],0 ; are we stepping on the X? je short ??no_x_step ; no x mov ax,cx ; get current x_pixel mov cx,dx ; save dx - it is trashed by idiv sub ax,[MouseOffsetX] ; get offset difference mov bx,[MouseStepX] ; get step in bx for idiv cwd ; extend ax -> dx:ax idiv bx ; divide by Step X imul bx ; ax = div * Step X add ax,[MouseOffsetX] ; normalize to region offset mov dx,cx ; restore dx (new MouseY) mov cx,ax ; set cx (new MouseX) ??no_x_step: ;------ Perform any Y movement grid adjustment. cmp [MouseStepY],0 ; are we stepping on the Y je short ??no_step ; no y mov ax,dx ; get current y_pixel sub ax,[MouseOffsetY] ; get offset difference mov bx,[MouseStepY] ; get step in bx for idiv cwd ; extend ax -> dx:ax idiv bx ; divide by Step Y imul bx ; ax = div * Step Y add ax,[MouseOffsetY] ; normalize to region offset mov dx,ax ; set dx (new MouseY) ??no_step: ;------ Here is where we store the new MouseX and MouseY values ; mov [MouseX],cx ; and store in mouse x ; mov [MouseY],dx ; store y coord in mouse y ;------ If the mouse is hidden or its position hasn't changed, then ; perform no action. cmp [MState],0 jne short ??updateend cmp [MouseXOld],cx jne short ??doit cmp [MouseYOld],dx je short ??updateend ??doit: ;------ At this point we KNOW the mouse has moved. mov ax,[MCState] and ax,CONDHIDE+CONDHIDDEN cmp ax,CONDHIDE+CONDHIDDEN je short ??condcheck ; If already hidden. ;------ We know that the mouse is visible, we must hide it ; before we update its position. call Low_Hide_Mouse ;------ Conditional region check goes here. If the mouse falls within the ; conditional region, it gets marked as hidden and no other processing ; occurs. test [MCState],CONDHIDE je short ??condok ??condcheck: cmp cx,[MouseCXLeft] ; check adjusted x region jb short ??condok cmp cx,[MouseCXRight] ja short ??condok cmp dx,[MouseCYUpper] ; check adjusted y region jb short ??condok cmp dx,[MouseCYLower] ja short ??condok or [MCState],CONDHIDDEN ; flag as conditional hidden jmp short ??updateend ;------ The mouse coordinates and flags pass all of the tests, proceed ; with rendering the mouse. ??condok: call Low_Show_Mouse ;------ Final clean up and exit. ??updateend: mov [MouseXOld],cx mov [MouseYOld],dx ??exit: cmp [Mouse_StackPointer],0DEADh je ??mouse_stk_ok push cx push di push ax push es mov ax,0A000h mov es,ax xor di,di mov cx,64000 mov ax,1 rep stosb pop es pop ax pop di pop cx ??mouse_stk_ok: ; Restore System Stack Pointer Selector before exit Interrupt mov ax, [Mouse_App_Stack_SS] cli ; disable Interrupts mov ss, ax ; Get Syatem Stack Selector mov sp, [Mouse_App_Stack_ES] ; Get Syatem Stack offset sti ; Enable Interrupts ret ENDP Mouse_Int ;*************************************************************************** ;*************************************************************************** ;*************************************************************************** ;* MOUSE_SHADOW_BUFFER -- Handles storing and restoring the mouse buffer * ;* * ;* INPUT: int store - indicates whether we are storing the buffer or * ;* not. * ;* * ;* OUTPUT: none * ;* * ;* PROTO: Asm callable only! * ;* * ;* HISTORY: * ;* 10/27/1994 PWG : Created. * ;*=========================================================================* GLOBAL C VGA_Mouse_Shadow_Buffer:FAR PROC VGA_Mouse_Shadow_Buffer C FAR USES ax,bx,cx,dx,di,si,ds,es ARG store:WORD local x0 : word local y0 : word local x1 : word local y1 : word local buffx0 : word local buffy0 : word ;*=========================================================================* ;* Since we are in tiny model point ds to cs ;*=========================================================================* mov ax,cs ; since we are in tiny model mov ds,ax ; set cs = ds ;*=========================================================================* ; Direction flag must be forward in this routine. ;*=========================================================================* cld ;*=================================================================== ;* Copy of X, Y, Width and Height into local registers ;*=================================================================== mov ax,[MouseBuffX] mov bx,[MouseBuffY] sub ax , [ MouseXHot ] sub bx , [ MouseYHot ] mov [ x0 ] , ax mov [ y0 ] , bx add ax , [MouseBuffW] add bx , [MouseBuffH] mov [ x1 ] , ax mov [ y1 ] , bx mov [ buffx0 ] , 0 mov ax , [ word ptr MouseBuffer ] mov [ buffy0 ] , ax ;*=================================================================== ;* Bounds check source X. Y. ;*=================================================================== xor ax , ax xor dx , dx mov cx , [ x0 ] mov bx , [ x1 ] add cx , cx adc ax , ax add bx , bx adc dx , dx mov cx , [ x0 ] mov bx , [ x1 ] sub cx , [ MouseRight ] sub bx , [ MouseRight ] dec cx dec bx add cx , cx adc ax , ax add bx , bx adc dx , dx mov cx , [ y0 ] mov bx , [ y1 ] add cx , cx adc ax , ax add bx , bx adc dx , dx mov cx , [ y0 ] mov bx , [ y1 ] sub cx , [MouseBottom] sub bx , [MouseBottom] dec cx dec bx add cx , cx adc ax , ax add bx , bx adc dx , dx xor al , 5 xor dl , 5 mov ah , al test dl , al jnz ??out or al , dl jz ??acepted test ah , 1000b jz ??scr_left_ok mov bx , [ x0 ] neg bx mov [ buffx0 ] , bx mov [ x0 ] , 0 ??scr_left_ok: test ah , 0010b jz ??scr_bottom_ok push dx mov ax , [ y0 ] neg ax mul [MouseBuffW] add [ buffy0 ] , ax mov [ y0 ] , 0 pop dx ??scr_bottom_ok: test dl , 0100b jz ??scr_right_ok mov ax , [MouseRight] ; get width into register mov [ x1 ] , ax ??scr_right_ok: test dl , 0001b jz ??acepted mov ax , [MouseBottom] ; get width into register mov [ y1 ] , ax ??acepted: ;*=================================================================== ;* Get the offset into the screen. ;*=================================================================== mov ax,0A000h mov es,ax mov ax , [ y0 ] mul [ MouseRight ] mov dx , [MouseRight] mov di , ax add di , [ x0 ] ;*=================================================================== ;* Adjust the source for the top clip. ;*=================================================================== mov bx , [ MouseWidth ] ; turn this into an offset lds si , [ MouseBuffer ] mov si , [ buffy0 ] ; edx points to source add si , [ buffx0 ] ; plus clipped lines ;*=================================================================== ;* Calculate the bytes per row add value ;*=================================================================== mov ax , [ x1 ] mov cx , [ y1 ] sub ax , [ x0 ] jle ??out sub cx , [ y0 ] jle ??out sub dx , ax sub bx , ax push bp cmp [store],RESTORE_VISIBLE_PAGE ; are we restoring page? jne ??store_entry ; if not the go to store ;*=================================================================== ;* Handle restoring the buffer to the visible page ;*=================================================================== mov bp , cx ??restore_loop: mov cx,ax ; get number to really write rep movsb ; store them into the buffer add si,bx ; move past right clipped pixels add di,dx ; adjust dest to next line dec bp ; decrement number of rows to do jnz ??restore_loop ; if more to do, do it pop bp IF ECHOON mov ax , 0b000h mov di , 12 * 80 + 10 mov es, ax mov al , 'V' mov [es:di],al mov al,2 mov [es:di+1],al ENDIF ret ;*=================================================================== ;* Handle soting the visible page into the Mouse Shadow Buffer ;*=================================================================== ??store_entry: xchg si,di ; xchg the source and the dest mov bp , cx push es ; need to swap es and ds but push ds ; cant xchg so pop them on the pop es ; stack and pop them off the pop ds ; wrong way intentionally. ??store_loop: mov cx,ax ; get number to really write rep movsb ; store them into the buffer add si,dx ; move past right clipped pixels add di,bx ; adjust dest to next line dec bp ; decrement number of rows to do jnz ??store_loop ; if more to do, do it pop bp ??out: IF ECHOON mov ax , 0b000h mov di , 12 * 80 + 12 mov es, ax mov al , 'G' mov [es:di],al mov al,2 mov [es:di+1],al ENDIF ret ENDP VGA_Mouse_Shadow_Buffer ;*************************************************************************** GLOBAL C VGA_Draw_Mouse:FAR PROC VGA_Draw_Mouse C FAR USES ax,bx,cx,dx,di,si,ds,es ARG mousex:WORD ARG mousey:WORD local x0 : word local y0 : word local x1 : word local y1 : word local buffx0 : word local buffy0 : word ;*=========================================================================* ;* Since we are in tiny model point ds to cs ;*=========================================================================* mov ax,cs ; since we are in tiny model mov ds,ax ; set cs = ds ;*=================================================================== ;* Pre-initialize the left, right and topclip values to zero. ;*=================================================================== mov ax, [ mousex ] mov bx , [ mousey ] sub ax , [ MouseXHot ] sub bx , [ MouseYHot ] mov [ x0 ] , ax mov [ y0 ] , bx add ax, [ MouseWidth ] add bx, [ MouseHeight ] mov [ x1 ] , ax mov [ y1 ] , bx mov [ buffx0 ] , 0 les ax , [ MouseCursor ] mov [ buffy0 ] , ax ;*=================================================================== ;* Bounds check source X. Y. ;*=================================================================== xor ax , ax xor dx , dx mov cx , [ x0 ] mov bx , [ x1 ] add cx , cx adc ax , ax add bx , bx adc dx , dx mov cx , [ x0 ] mov bx , [ x1 ] sub cx , [ MouseRight ] sub bx , [ MouseRight ] dec cx dec bx add cx , cx adc ax , ax add bx , bx adc dx , dx mov cx , [ y0 ] mov bx , [ y1 ] add cx , cx adc ax , ax add bx , bx adc dx , dx mov cx , [ y0 ] mov bx , [ y1 ] sub cx , [MouseBottom] sub bx , [MouseBottom] dec cx dec bx add cx , cx adc ax , ax add bx , bx adc dx , dx xor al , 5 xor dl , 5 mov ah , al test dl , al jnz ??out or al , dl jz ??acepted test ah , 1000b jz ??scr_left_ok mov bx , [ x0 ] neg bx mov [ buffx0 ] , bx mov [ x0 ] , 0 ??scr_left_ok: test ah , 0010b jz ??scr_bottom_ok push dx mov ax , [ y0 ] neg ax mul [MouseWidth] add [ buffy0 ] , ax mov [ y0 ] , 0 pop dx ??scr_bottom_ok: test dl , 0100b jz ??scr_right_ok mov bx , [MouseRight] ; get width into register mov [ x1 ] , bx ??scr_right_ok: test dl , 0001b jz ??acepted mov bx , [MouseBottom] ; get width into register mov [ y1 ] , bx ??acepted: mov ax , [ y0 ] mul [ MouseRight ] mov dx , [MouseRight] mov di , ax add di , [ x0 ] ;*=================================================================== ;* Adjust the source for the top clip. ;*=================================================================== mov bx , [MouseWidth] ; turn this into an offset mov si , [ buffy0 ] ; edx points to source add si , [ buffx0 ] ; plus clipped lines ;*=================================================================== ;* Calculate the bytes per row add value ;*=================================================================== mov ax , 0a000h mov ds , ax mov ax , [ x1 ] mov cx , [ y1 ] sub ax , [ x0 ] jle ??out sub cx , [ y0 ] jle ??out sub dx , ax sub bx , ax ;*=================================================================== ;* Handle restoring the buffer to the visible page ;*=================================================================== ??top_loop: mov ah,al ??inner_loop: mov ch , [es:si] inc esi or ch,ch jz ??inc_edi mov [di],ch ??inc_edi: inc di dec ah jnz ??inner_loop add si,bx ; move past right clipped pixels add di,dx ; adjust dest to next line dec cl ; decrement number of rows to do jnz ??top_loop ; if more to do, do it ??out: IF ECHOON mov ax , 0b000h mov di , 12 * 80 + 14 mov es, ax mov al , 'A' mov [es:di],al mov al,2 mov [es:di+1],al ENDIF ret ENDP VGA_Draw_Mouse ;*************************************************************************** ;*************************************************************************** ;*************************************************************************** ;* MOUSE_SHADOW_BUFFER -- Handles storing and restoring the mouse buffer * ;* * ;* INPUT: int store - indicates whether we are storing the buffer or * ;* not. * ;* * ;* OUTPUT: none * ;* * ;* PROTO: Asm callable only! * ;* * ;* HISTORY: * ;* 10/27/1994 PWG : Created. * ;*=========================================================================* GLOBAL C VESA_Mouse_Shadow_Buffer:FAR PROC VESA_Mouse_Shadow_Buffer C FAR USES ax,bx,cx,dx,di,si,ds,es ARG store:WORD local x0 : word local y0 : word local x1 : word local y1 : word local buffx0 : word local buffy0 : word ;*=========================================================================* ;* Since we are in tiny model point ds to cs ;*=========================================================================* mov ax,cs ; since we are in tiny model mov ds,ax ; set cs = ds call get_vesa_window mov [ app_vesa_window ] , dx ;*=========================================================================* ; Direction flag must be forward in this routine. ;*=========================================================================* cld ;*=================================================================== ;* Copy of X, Y, Width and Height into local registers ;*=================================================================== mov ax,[MouseBuffX] mov bx,[MouseBuffY] sub ax , [ MouseXHot ] sub bx , [ MouseYHot ] mov [ x0 ] , ax mov [ y0 ] , bx add ax , [MouseBuffW] add bx , [MouseBuffH] mov [ x1 ] , ax mov [ y1 ] , bx mov [ buffx0 ] , 0 mov ax , [ word ptr MouseBuffer ] mov [ buffy0 ] , ax ;*=================================================================== ;* Bounds check source X. Y. ;*=================================================================== xor ax , ax xor dx , dx mov cx , [ x0 ] mov bx , [ x1 ] add cx , cx adc ax , ax add bx , bx adc dx , dx mov cx , [ x0 ] mov bx , [ x1 ] sub cx , [ MouseRight ] sub bx , [ MouseRight ] dec cx dec bx add cx , cx adc ax , ax add bx , bx adc dx , dx mov cx , [ y0 ] mov bx , [ y1 ] add cx , cx adc ax , ax add bx , bx adc dx , dx mov cx , [ y0 ] mov bx , [ y1 ] sub cx , [MouseBottom] sub bx , [MouseBottom] dec cx dec bx add cx , cx adc ax , ax add bx , bx adc dx , dx xor al , 5 xor dl , 5 mov ah , al test dl , al jnz ??out or al , dl jz ??acepted test ah , 1000b jz ??scr_left_ok mov bx , [ x0 ] neg bx mov [ buffx0 ] , bx mov [ x0 ] , 0 ??scr_left_ok: test ah , 0010b jz ??scr_bottom_ok push dx mov ax , [ y0 ] neg ax mul [MouseBuffW] add [ buffy0 ] , ax mov [ y0 ] , 0 pop dx ??scr_bottom_ok: test dl , 0100b jz ??scr_right_ok mov ax , [MouseRight] ; get width into register mov [ x1 ] , ax ??scr_right_ok: test dl , 0001b jz ??acepted mov ax , [MouseBottom] ; get width into register mov [ y1 ] , ax ??acepted: ;*=================================================================== ;* Get the offset into the screen. ;*=================================================================== mov ax,0A000h mov es,ax mov ax , [ y0 ] mul [ MouseRight ] add ax , [ x0 ] adc dx , 0 mov di , ax call set_vesa_page mov dx , [MouseRight] ;*=================================================================== ;* Adjust the source for the top clip. ;*=================================================================== mov bx , [ MouseWidth ] ; turn this into an offset lds si , [ MouseBuffer ] mov si , [ buffy0 ] ; edx points to source add si , [ buffx0 ] ; plus clipped lines ;*=================================================================== ;* Calculate the bytes per row add value ;*=================================================================== mov ax , [ x1 ] mov cx , [ y1 ] sub ax , [ x0 ] jle ??out sub cx , [ y0 ] jle ??out sub dx , ax sub bx , ax cmp [store],RESTORE_VISIBLE_PAGE ; are we restoring page? jne ??store_entry ; if not the go to store ;*=================================================================== ;* Handle restoring the buffer to the visible page ;*=================================================================== ??restore_loop: mov ah,al ??res_inner_loop: mov ch , [si] mov [es:di],ch inc si inc di jnz ??res_same_page call next_vesa_page ??res_same_page: dec ah jnz ??res_inner_loop add si,bx ; move past right clipped pixels add di,dx ; adjust dest to next line jnc ??res_same_page1 call next_vesa_page ??res_same_page1: dec cl ; decrement number of rows to do jnz ??restore_loop IF ECHOON mov ax , 0b000h mov di , 10 * 80 + 10 mov es,ax mov al ,'v' mov [es:di],al mov al,2 mov [es:di+1],al ENDIF jmp ??out ;*=================================================================== ;* Handle soting the visible page into the Mouse Shadow Buffer ;*=================================================================== ??store_entry: mov ah,al ??store_inner_loop: mov ch , [es:di] mov [si],ch inc si inc di jnz ??store_same_page call next_vesa_page ??store_same_page: dec ah jnz ??store_inner_loop add si,bx ; move past right clipped pixels add di,dx ; adjust dest to next line jnc ??store_same_page1 call next_vesa_page ??store_same_page1: dec cl ; decrement number of rows to do jnz ??store_entry ??out: IF ECHOON mov ax , 0b000h mov di , 10 * 80 + 14 mov es,ax mov al ,'e' mov [es:di],al mov al,2 mov [es:di+1],al ENDIF mov dx , [ app_vesa_window ] call set_vesa_window ret ENDP VESA_Mouse_Shadow_Buffer ;*************************************************************************** GLOBAL C VESA_Draw_Mouse:FAR PROC VESA_Draw_Mouse C FAR USES ax,bx,cx,dx,di,si,ds,es ARG mousex:WORD ARG mousey:WORD local x0 : word local y0 : word local x1 : word local y1 : word local buffx0 : word local buffy0 : word local app_vesa_window : word ;*=========================================================================* ;* Since we are in tiny model point ds to cs ;*=========================================================================* mov ax,cs ; since we are in tiny model mov ds,ax ; set cs = ds call get_vesa_window mov [ app_vesa_window ] , dx ;*=================================================================== ;* Pre-initialize the left, right and topclip values to zero. ;*=================================================================== mov ax, [ mousex ] mov bx , [ mousey ] sub ax , [ MouseXHot ] sub bx , [ MouseYHot ] mov [ x0 ] , ax mov [ y0 ] , bx add ax, [ MouseWidth ] add bx, [ MouseHeight ] mov [ x1 ] , ax mov [ y1 ] , bx mov [ buffx0 ] , 0 les ax , [ MouseCursor ] mov [ buffy0 ] , ax ;*=================================================================== ;* Bounds check source X. Y. ;*=================================================================== xor ax , ax xor dx , dx mov cx , [ x0 ] mov bx , [ x1 ] add cx , cx adc ax , ax add bx , bx adc dx , dx mov cx , [ x0 ] mov bx , [ x1 ] sub cx , [ MouseRight ] sub bx , [ MouseRight ] dec cx dec bx add cx , cx adc ax , ax add bx , bx adc dx , dx mov cx , [ y0 ] mov bx , [ y1 ] add cx , cx adc ax , ax add bx , bx adc dx , dx mov cx , [ y0 ] mov bx , [ y1 ] sub cx , [MouseBottom] sub bx , [MouseBottom] dec cx dec bx add cx , cx adc ax , ax add bx , bx adc dx , dx xor al , 5 xor dl , 5 mov ah , al test dl , al jnz ??out or al , dl jz ??acepted test ah , 1000b jz ??scr_left_ok mov bx , [ x0 ] neg bx mov [ buffx0 ] , bx mov [ x0 ] , 0 ??scr_left_ok: test ah , 0010b jz ??scr_bottom_ok push dx mov ax , [ y0 ] neg ax mul [MouseWidth] add [ buffy0 ] , ax mov [ y0 ] , 0 pop dx ??scr_bottom_ok: test dl , 0100b jz ??scr_right_ok mov ax , [MouseRight] ; get width into register mov [ x1 ] , ax ??scr_right_ok: test dl , 0001b jz ??acepted mov ax , [MouseBottom] ; get width into register mov [ y1 ] , ax ??acepted: mov ax , [ y0 ] mul [ MouseRight ] add ax , [ x0 ] adc dx , 0 mov di , ax call set_vesa_page mov dx , [MouseRight] ;*=================================================================== ;* Adjust the source for the top clip. ;*=================================================================== mov bx , [MouseWidth] ; turn this into an offset mov si , [ buffy0 ] ; edx points to source add si , [ buffx0 ] ; plus clipped lines ;*=================================================================== ;* Calculate the bytes per row add value ;*=================================================================== mov ax , 0a000h mov ds , ax mov ax , [ x1 ] mov cx , [ y1 ] sub ax , [ x0 ] jle ??out sub cx , [ y0 ] jle ??out sub dx , ax sub bx , ax ;*=================================================================== ;* Handle restoring the buffer to the visible page ;*=================================================================== ??top_loop: mov ah,al ??inner_loop: mov ch , [es:si] inc si or ch,ch jz ??inc_edi mov [di],ch ??inc_edi: inc di jnz ??same_page call next_vesa_page ??same_page: dec ah jnz ??inner_loop add si,bx ; move past right clipped pixels add di,dx ; adjust dest to next line jnc ??same_page1 call next_vesa_page ??same_page1: dec cl ; decrement number of rows to do jnz ??top_loop ; if more to do, do it ??out: IF ECHOON mov ax , 0b000h mov di , 10 * 80 + 14 mov es, ax mov al , 's' mov [es:di],al mov al,2 mov [es:di+1],al mov di , 10 * 80 + 16 mov al , 'a' mov [es:di],al mov al,2 mov [es:di+1],al ENDIF mov dx , [ app_vesa_window ] call set_vesa_window ret ENDP VESA_Draw_Mouse ;************************************************************************ PROC get_vesa_window C near uses ax,bx mov ax , 04f05h mov bh , 1 mov bl , 0 call [ dword ptr cs: VesaPtr ] ret ENDP ;************************************************************************ PROC set_vesa_window C near uses ax,bx,dx mov ax , 04f05h mov bh , 0 mov bl , 0 call [ dword ptr cs: VesaPtr ] ret ENDP ;*************************************************************************** PROC set_vesa_page C near USES ax,bx,dx mov bx , dx shl bx , 2 mov [ cs: current_page ] , bx mov dx , [ word ptr cs:banktable + bx ] mov ax , 04f05h mov bh , 0 mov bl , 0 call [ dword ptr cs: VesaPtr ] ret ENDP set_vesa_page PROC next_vesa_page C near USES ax,bx,dx mov bx , [ cs: current_page ] add bx , 4 mov [ cs:current_page ] , bx mov dx , [ word ptr cs:banktable + bx ] mov ax , 04f05h mov bh , 0 mov bl , 0 call [ dword ptr cs: VesaPtr ] ret ENDP next_vesa_page ;*********************************************************** END