;************************************************************************
; *
; Copyright (C) 1991 by Trace Center (just kidding) *
; *
; MOUSEKEY.ASM *
; *
;************************************************************************
TITLE MouseKeys
INCLUDE keyboard.inc
EXTRN real_states:byte
EXTRN shift_flg:byte
EXTRN lock_flg:byte
EXTRN ToggleKeys:PROC ; in ToggleKeys.asm
EXTRN beep_high:PROC ; in Handicap.asm
EXTRN beep_low:PROC
EXTRN no_beep:PROC
EXTRN beep_turn_on:PROC
EXTRN beep_turn_off:PROC
EXTRN click:PROC
EXTRN fmouse_driver:byte
EXTRN _fmouse_id:byte
EXTRN btn_1:byte
EXTRN btn_2:byte
EXTRN Current_Button:byte
EXTRN fmouse_button:byte
EXTRN _comp_id:byte
EXTRN comp_flag:byte
EXTRN Get_Mouse_Data:PROC
EXTRN ExtendedSeg:word
EXTRN fpause_being_sent:byte
EXTRN fswitching_video:byte
EXTRN faccess_sound:byte
EXTRN fbios_called_timing:byte
EXTRN fsecond_cue:byte
EXTRN Put_Key_Data:PROC
EXTRN ftimer_1C_active:byte
EXTRN fserial_key_recieved:byte
EXTRN fmousetrapping:byte
; EXTRN fwindows_enh:byte ; DEBUGGING
EXTRN fMouseKeysOn:byte ; from Param.asm
EXTRN fMK_On_Off_Feedback:byte
EXTRN Max_Speed:word
EXTRN Time_To_Max_Speed:word
EXTRN fDialog_Mouse_off:byte
EXTRN fRecovery_On:byte
EXTRN fspace_saver:byte
EXTRN fToggleKeysOn:byte
EXTRN fSticKeysOn:byte
EXTRN TimeOut_Reset:PROC ; in TimeOut.asm
EXTRN fUser_SetUp_Option1:byte ; in FilterKeys.asm
EXTRN fUser_SetUp_Option2:byte
EXTRN on_repeat_ticks:word
PUBLIC MouseKeys ; in MouseKeys.asm
PUBLIC MouseKeys_timer
PUBLIC MouseKeys_TurnOff
PUBLIC InjectMouse
PUBLIC button_click,Status
PUBLIC fMoving,fbutton_up,Last_Direction,fbutton_down
PUBLIC Delta_X,Delta_Y,Mouse_Status
PUBLIC mouse_data
PUBLIC mouse_data_head
PUBLIC mouse_data_tail
PUBLIC mouse_data_end
PUBLIC Put_Mouse_Data
PUBLIC MouseKeys_dialog
PUBLIC Button_Status
PUBLIC mouse_cnt
PUBLIC fnum_lock_was_off
PUBLIC fserial_stop
IFDEF BUG
EXTRN portid:byte
EXTRN portout:byte
EXTRN HexCharsOut:PROC
ENDIF; BUG
;----------------------------------------------------------------------------
_TEXT segment word public 'CODE'
assume CS:_TEXT
assume DS:NOTHING
assume ES:NOTHING
assume SS:NOTHING
;----------------------------------------------------------------------------
; R E S I D E N T D A T A A R E A
;
; The below area defines the resident data area.
fMoving DB false ; flag for accelerated Moving
fSteady DB false ; flag for if at constant speed
fJust_Manually_On DB false ; flag to prevent turn off right after turn on
fJust_Manually_Off DB false ; flag to prevent turn on right after turn off
fbutton DB false ; flag to indicate a mousekey mouse button was pressed
fbutton_up DB false ; flag to tell code after the mouse driver that MouseKeys button up was sent
fbutton_down DB false ; flag to tell code that mouse button down has been pressed once already
foff_mousekeys DB false ; flag that MouseKeys is turning off after we get numlock break code
fpass_mousekeys DB true ; flag that turns numeric pad on/off to mousekeys with numlock key only
fnum_lock_was_off db false ; flag used with space saver kybd, should on num lock be passed or not ?
fpass_numlock_spsav db false ; flag used with space saver kybd to block typematic numlock makes from
fserial_stop db false ; flag used to tell timer when to stop sending serial mouse mvmnts to driver
; toggling MouseKeys on/off/on/off/on.......
Accel_Ptr DB 0 ; pointer into table
Constant_Ptr DB 0
Last_Direction label word
Y_Direction DB 0 ; direction
X_Direction DB 0 ; direction
Status DB 0 ; byte to hold the mouse status as built
Button_Status DB 0 ; holds button_status info for the mouse
Temp_Button DB 0 ; holds al register while I check if kybd supports 3rd button
Mouse_Packet label word ; next four words
Delta_Z DW 0 ; added for our matching in AccesDos
Delta_Y DW 0
Delta_X DW 0
Mouse_Status DW 0 ; only changes in states
mouse_cnt DB 0 ; mouse data packet buffer counter
mouse_data_tail DW ? ; pointer into mouse_data
mouse_data_head DW ? ; pointer into mouse_data
mouse_data DW 120 DUP (?) ; array of (120 words) for circular buffer of mouse button data
mouse_data_end label word
;----------------------------------------------------------------------------
; MouseKeys_Param
Accel_Table_Len DB 73 ; just storage initially
; 73 bytes gives alittle more 4 seconds maximum if choosen
; to complete the accel. table ( 73 tics / 18.2 ticks/sec)
Accel_Table db 0, 0, 1, 0, 0, 1, 0, 1
db 0, 1, 0, 1, 0, 1, 0, 1
db 0, 1, 0, 1, 0, 1, 0, 1
db 1, 0, 1, 0, 1, 0, 1, 0
db 1, 0, 1, 0, 1, 0, 1, 1
db 0, 1, 0, 1, 0, 1, 0, 1
db 0, 1, 0, 1, 1, 1, 1, 1
db 1, 1, 1, 1, 1, 1, 1, 1
db 1, 1, 1, 1, 1, 1, 1, 1
db 1
Constant_Table_Len DB 21 ; just storage
Constant_Table db 1, 1, 1, 1, 1, 1, 1, 1
db 1, 1, 1, 1, 1, 1, 1, 1
db 1, 1, 1, 1, 1
;----------------------------------------------------------------------------
; search table for a shift key.
mouse_tbl label word
dw NumLock
dw NumPad_Divide
dw NumPad_Times
dw NumPad_Minus
dw NumPad_Plus
dw NumPad_Enter
dw NumPad_Period
dw NumPad_9
dw NumPad_8
dw NumPad_7
dw NumPad_6
dw NumPad_5
dw NumPad_4
dw NumPad_3
dw NumPad_2
dw NumPad_1
dw NumPad_0
mouse_tbl_len equ 17
MK_call_table label word
dw button_delta ; button down
dw move_proc
dw move_proc
dw move_proc
dw move_proc
dw button_click ; button click
dw move_proc
dw move_proc
dw move_proc
dw move_proc
dw button_click ; button up, changed to accomadate MouseKeys and real mouse together
dw dummy_proc
dw dbl_click_proc ; double click
dw btn_sel_proc
dw btn_sel_proc
dw btn_sel_proc
dw off_proc
MK_data_table label word
dw 1 ; numpad 0 button down
dw 0ffffh ; numpad 1 -x,-y
dw 000ffh ; numpad 2 0,-y
dw 001ffh ; numpad 3 +x,-y
dw 0ff00h ; numpad 4 -x, 0
dw 0 ; numpad +, click
dw 00100h ; numpad 6 +x, 0
dw 0ff01h ; numpad 7 -x,+y
dw 00001h ; numpad 8 0,+y
dw 00101h ; numpad 9 +x,+y
dw 1 ; numpad . button up
dw 0 ; numpad "Enter"
dw 0 ; numpad + double click
dw 01002h ; high=10,serial right button, low=2 AUX right button
dw 03003h ; high=30,serial both buttons, low=3 AUX both buttons
dw 02001h ; high=20,serial left button, low=1 AUX left button
dw 0 ; numpad "Num Lock" key for On/Off
;----------------------------------------------------------------------------
;
; The mouseKeys routine allows everyone who has difficulty controlling a standard mouse input
; device, the ability to alternately control the standard mouse from the keyboard. Mousekeys
; remaps the numeric keypad into a mouse control pad, with all the same functionality of the
; standard input mouse available to the user from the keyboard.
;----------------------------------------------------------------------------
MouseKeys proc
assume DS:_TEXT
jmp mouse_begin
;----------------------------------------------------------------------------
; Put_Mouse_Data
;
; This procedure loads mouse button info into a buffer where the timer will later
; retrieve it and send it to the appropriate mouse input mechanism. All serial
; mouse info ends up in this buffer, but only the ps/2 mouse button info needs
; to be buffered, the rest of the PS/2 mouse information can be injected directly.
;
; Expects Ax= mouse data to be stored, order is
;
; 1st Mouse_Status
; 2nd Delta_X
; 3rd Delta_Y
Put_Mouse_Data proc
assume DS:_TEXT
push bx ; temp store of bx register
push si ; temp store of si register
mov bx,mouse_data_tail ; get tail pointer of mouse_data buffer
mov si,bx ; save pointer value
add bx,2 ; move to next word address in buffer
cmp bx,OFFSET mouse_data_end ; are we at the end of the buffer ?
jne PMD_5 ; no
mov bx,OFFSET mouse_data ; yes we are, so reset to the buffer beginning
PMD_5:
cmp bx,mouse_data_head ; has the buffer wrapped around ?
jne PMD_10
; if equal, buffer is full, exit
jmp Put_Mouse_Data_End ; if full, leave routine
PMD_10:
mov [si],ax ; move whats in ax into address pointed to by si
inc mouse_cnt ; increase counter by 1, since we put a word into the buffer
mov mouse_data_tail,bx ; update tail pointer
Put_Mouse_Data_End:
pop si
pop bx
ret
Put_Mouse_Data endp
;----------------------------------------------------------------------------
; MouseKeys_timer
;
; Expects: Nothing
;
; Changes: ax,bx
MouseKeys_timer proc
assume DS:_TEXT
cmp fMouseKeysOn,true ; is mouse key on?
jne mt_10 ; no, skip routine -->
cmp fMoving,true ; are we in motion?
je mt_20 ; yes -->
mt_10:
jmp MouseKeys_timer_end ; don't do anything
mt_20:
xor ax,ax ; clear motion value
xor bx,bx ; clear pointer
cmp fSteady,false ; are we in a steady motion?
jne mt_40 ; yes -->
mov bl,Accel_Ptr ; motion is accelerating
cmp Time_To_Max_Speed,1 ; do we accel. for 1 sec. ?
jne mt_22 ; not a 1
mov al,18 ; 1 sec <=> 18 ticks
mov Accel_Table_Len,al
jmp mt_28
mt_22:
cmp Time_To_Max_Speed,2 ; do we accel. for 2 sec. ?
jne mt_24
mov al,36 ; 2 sec <=> 36 ticks
mov Accel_Table_Len,al
jmp mt_28
mt_24:
cmp Time_To_Max_Speed,3 ; do we accel. for 3 sec. ?
jne mt_26
mov al,54 ; 3 sec <=> 54 ticks
mov Accel_Table_Len,al
jmp mt_28
mt_26:
mov al,73 ; 4 sec <=> 73 ticks Default back to
mov Accel_Table_Len,al
mt_28:
cmp bl,Accel_Table_Len ; are we at end of accel?
jb mt_30 ; no -->
mov fSteady,true ; yes, start using constant table
xor bx,bx
jmp short mt_50 ; -->
mt_30:
mov al,Accel_Table[bx]
cbw
inc bx ; increment pointer
mov Accel_Ptr,bl
jmp short mt_60
mt_40:
mov bl,Constant_Ptr ; yes, get next movement
cmp bl,Constant_Table_Len ; are we at end of table?
jb mt_50 ; no -->
xor bx,bx ; yes, reset to beginning
mt_50:
mov al,Constant_Table[bx]
cbw
inc bx ; increment pointer
mov Constant_Ptr,bl
mt_60:
or ax,ax ; motion on this interrupt?, based on "..."table value
jnz mt_62 ; we have a non zero, so cont. to do motion
jmp MouseKeys_timer_end ; no motion this time,end
mt_62:
cmp fSteady,false ; catches here and below (x and y direction)
jne mt_65
cmp Max_Speed,8 ; don't adjust speed unless above Max_Speed 8
jle mt_65
mov ax,Max_Speed
cmp ax,36 ; if Max_Sped is 36, shr twice
jne mt_64
shr ax,1
mt_64:
shr ax,1
;------------------
; acceleration speed adjustments
xor bx,bx ; clear x direction
cmp X_Direction,bl ; is direction 0?
je mt_70A ; yes -->
mov bx,ax ; get current acceleration variable, doesn't change flag bits
jg mt_70A ; is it positive? yes --> from above compare YET !!!
neg bx
mt_70A:
xor cx,cx ; clear y direction
cmp Y_Direction,cl ; is direction 0?
je mt_80 ; yes -->
mov cx,ax ; get accel. variable***
jg mt_80 ; is it positive?, yes -->from above compare YET !!!
neg cx
jmp short mt_80
;------------------
; standard acceleration and constant speed
mt_65:
xor bx,bx ; clear x direction
cmp X_Direction,bl ; is direction 0?
je mt_70 ; yes -->
mov bx,Max_Speed ; get current acceleration variable, doesn't change flag bits
jg mt_70 ; is it positive? yes --> from above compare YET !!!
neg bx
mt_70:
xor cx,cx ; clear y direction
cmp Y_Direction,cl ; is direction 0?
je mt_80 ; yes -->
mov cx,Max_Speed ; get accel. variable***
jg mt_80 ; is it positive?, yes -->from above compare YET !!!
neg cx
mt_80:
cmp _fmouse_id,4 ; is the PS/2 mouse driver loaded
jne mt_90
mov Delta_Y,cx ; preload Delta_X before calling Inject Mouse
mov Delta_X,bx ; preload Delta_Y before calling Inject Mouse
xor ax,ax
mov al,Status ; now have direction status in al register
or al,Button_Status ; get button status info. into al register
mov Mouse_Status,ax
call InjectMouse
jmp short MouseKeys_timer_end
mt_90:
; cx register has Delta_y, and bx register has Delta_X data
cmp _fmouse_id,2 ; do we have a serial mouse ?
jne MouseKeys_timer_end
cmp cl,00h ; if y is zero, leave alone
je mt_95
test cl,80h ; if y is neg, for serial mouse must switch
jnz mt_92
or Status,0Ch ; build Status for neg. Y dir.
mt_92:
neg cl ; 2's compl. Y,
mt_95:
mov Delta_Y,cx ; load Delta_Y
and Delta_Y,03fh ; flag not the first byte
mov Delta_X,bx ; load Delta_X
test bl,80h ; is x neg?
jz mt_97
or Status,03h ; build Status for neg X dir.
mt_97:
and Delta_X,03fh ; flag not the first byte
xor ax,ax ; make sure ax is 0
mov al,Status
or al,Button_Status
or al,40h ; need to always set this bit for serial mouse button byte
mov Mouse_Status,ax
cmp mouse_cnt,100 ; are there 100 nouse data wors in buffer already ?
jge MouseKeys_timer_end
call Put_Mouse_Data ; store info on serial mouse in buffer
mov ax,Delta_X
call Put_Mouse_Data ; store info on serial mouse in buffer
mov ax,Delta_Y
call Put_Mouse_Data ; store info on serial mouse in buffer
mov fmouse_button,true ; is a mousekeys mouse button data
MouseKeys_timer_end:
ret
MouseKeys_timer endp
;------------------------------------------------------------------------
; the following routines provide the sound feedback.
mk_turn_on_fb proc
assume DS:_TEXT
cmp fMK_On_Off_Feedback,false
je MouseKeys_TurnOn
call beep_turn_on
MouseKeys_TurnOn:
cmp fswitching_video,false
jne MouseKeys_TurnOn_3
mov faccess_sound,true
mov fsecond_cue,24
MouseKeys_TurnOn_3:
mov fJust_Manually_On,true
MouseKeys_TurnOn_5:
mov fpass_numlock_spsav,false
mov fpass_mousekeys,true ; trap numeric pad keys as MouseKeys
call stop_moving
mov fbutton,false ; reset mousekey mouse button to false
mov fbutton_up,false
mov fbutton_down,false
mov fmouse_button,false
; reset mouse_data buffer to empty, i.e. point head and tail to the start of the buffer
push bx ; temp save of bx register
mov bx,OFFSET mouse_data ; get address of mouse_data buffer
mov mouse_data_head,bx ; reset head pointer to start of buffer
mov mouse_data_tail,bx ; reset tail pointer to start of buffer
mov mouse_cnt,false ;
mov fserial_stop,false
pop bx
call TimeOut_Reset
mov fMouseKeysOn,true
cmp _fmouse_id,4 ; do we have a PS/2 mouse ?
jne mk_turn_on_5
mov Current_Button,01h
mov Temp_Button,false
jmp short mk_turn_on_10
mk_turn_on_5:
cmp _fmouse_id,2 ; do we have a serial mouse ?
jne short mk_turn_on_10
mov Current_Button,20h
mk_turn_on_10:
mov Button_Status,0 ; buttons default up at turn on
ret
mk_turn_on_fb endp
;----------------------------------------------------------------------------
mk_turn_off_fb proc
assume DS:_TEXT
cmp fMK_On_Off_Feedback,false
je MouseKeys_TurnOff
call beep_turn_off
MouseKeys_TurnOff:
cmp fswitching_video,false
jne MouseKeys_TurnOff_5
mov faccess_sound,true
mov fsecond_cue,25
MouseKeys_TurnOff_5:
mov fJust_Manually_Off,true ; flag that we just turned off
mov fserial_stop,false
call stop_moving
cmp Button_Status,0 ; check to see if MouseButton's are up?
je MKTOff_20 ; yes, ignore and jump around resetting of button code
push ax ; temp save
push cx ; temp save
mov cx,0053h ; button up key code
mov ax,1 ; same as if called from table for a button up
mov fbutton_up,true ; ""
mov fbutton_down,false ; ""
call button_click ;
pop cx ; restore register
pop ax ; restore register
MKTOff_20:
mov fMouseKeysOn,false ; no, then turn off
mov fnum_lock_was_off,false ; reset to false
ret
mk_turn_off_fb endp
;----------------------------------------------------------------------------
; MouseKeys_dialog
;
; Checks a single flag from Dialog box to see if MouseKeys was turned
; on/off. If it was, this routine makes a call to MouseKeys_TurnOn/Off so the realstates
; can be updated to match the computer. Upon exit the flag that was set by
; Dialog box is cleared.(returned to false)
MouseKeys_dialog proc
assume DS:_TEXT
cmp fMouseKeysOn,true ; was Stickeys turned on
jne Md_25
cmp fmouse_driver,false ; if fmouse_driver false, don't turn mousekeys on
je Md_50 ; no, just pass on -->
call MouseKeys_TurnOn_5 ; yes it was true, so turn on
cmp fspace_saver,true
jne Md_50
mov fpass_mousekeys,false ; start space_saver kybd in off position if turned on via menu
jmp short Md_50
Md_25:
call MouseKeys_TurnOff_5 ; fMouseKeyOn was false, so turn off
Md_50:
mov fDialog_Mouse_off,false ; reset flag to false
ret
MouseKeys_dialog endp
;----------------------------------------------------------------------------
; INJECT MOUSE
;
;expects:
; AX Mouse Status Word
; BX X Data Word
; CX Y Data Word
; DX Z Data Word
;
;returns: nothing
;
;calls: Pointing Device Driver at segment [40:0E], offset [22h]
; Int 74h (80286 or higher CPUs) or 71h (8086 CPUs)
;
;----------------------------------------------------------------------------
InjectMouse proc
assume DS:_TEXT
;-DEBUGGING---------------------------------------------------------------------
;
;;; cmp fwindows_enh,true
;;; jne IM_10
;;; call click
; push ax
; mov ax,Mouse_Status
; call Put_Mouse_Data
; mov ax,Delta_X
; call Put_Mouse_Data
; mov ax,Delta_Y
; call Put_Mouse_Data
; pop ax
; jmp IM_150 ; ADDED LABEL
;----------------------------------------------------------------------
;
;IM_10:
cli ; disable int
push es
push ax
push bx
push cx
push dx
xor ax,ax ; make sure the registers are zero
xor bx,bx
xor cx,cx
xor dx,dx
mov fmouse_button,true ; is a mousekeys mouse button data
mov ax,Mouse_Status
push ax ;first status goes on stack
mov bx,Delta_X
push bx ;now X data
mov cx,Delta_Y
push cx ;now Y
mov dx,Delta_Z
push dx ;now Z, always equal to 0
;now call device driver pointer routine to store values in its data area
assume ES:NOTHING
mov ax,ExtendedSeg ;get extended BIOS segment
mov es,ax
call dword ptr es:[22h] ;call user pointer routine
; Since the device driver does most of its processing in the hardware interrupt routine rather than the pointer
; routine, we have to call it. This is done by simulating an interrupt. The device driver calls the
; normal bios interrupt routine, checks to see if it got any data, and then processes the data. We stuffed data
; in already, (i.e. simulated the normal bios interrupt routine). When the normal bios interrupt routine is
; called, it will see no data at the hardware port so it should just return. We assume this will always happen
; but we may have to disable the mouse to make sure it will always happen. Also, since no data was found, the
; normal bios interrupt routine will not call the pointer routine. This is great since we called the pointer
; routine with our data. The device driver will now process our data.
;
; Now call interrupt routine to process the new data
cmp _comp_id,8 ; which computer model do we have ?
jne IM_40
int 74h ; works for high end PS/2 Models (55SX,70,80)
jmp IM_100
IM_40:
cmp _comp_id,7 ; which computer model do we have ?
jne IM_50
int 74h ; works for high end PS/2 Models ("25/286","30/286",50,60)
jmp IM_100
IM_50:
cmp _comp_id,6
jne IM_120
int 71h ; works for low end PS/2 Models (25,30,.../86)
IM_100:
add sp,+8 ; get our stuff off stack after the interrupt
IM_120:
pop dx
pop cx
pop bx
pop ax
pop es
sti ; re-enable int.'s
;;IM_150:
ret
InjectMouse endp
;----------------------------------------------------------------------------
; stops smooth motion moving of the PS/2 and Serial mouse
stop_moving proc
assume DS:_TEXT
mov Last_Direction,0
mov fMoving,false
mov fSteady,false
mov Accel_Ptr,0
mov Delta_X,0
mov Delta_Y,0
mov Status,0
; don't reset mouse_data buffer on a mouse button (i.e. button down/up, click, dblclick)
cmp fbutton,true
je stop_moving_end
; don't reset mouse data buffer unless it's a serial mouse
cmp _fmouse_id,2
jne stop_moving_end
mov fserial_stop,true ; flag that we want to stop sending serial mouse novmnts
; push bx ; temp save of bx register
; mov bx,OFFSET mouse_data ; get address of mouse_data buffer
; mov mouse_data_head,bx ; reset head pointer to start of buffer
; mov mouse_data_tail,bx ; reset tail pointer to start of buffer
; mov mouse_cnt,false ;
; pop bx
stop_moving_end:
ret
stop_moving endp
;----------------------------------------------------------------------------
; dummy_proc
;
; Expects: Nothing
dummy_proc proc
assume DS:_TEXT
; When this procedure is called, the actual scan code still resides in "cx" register
; so if we mov "cx" back to "ax" and then call ToggleKeys, then everything is back to normal.
mov ax,cx ; restore scan code to "ax" register
mov fbutton,false ; move mousekey mouse button to false
call ToggleKeys ; pass ENTER key on, actually the "E0" part of scan code
; was passed by handicap.asm
cmp ftimer_1C_active,true ; if space_saver kybd, and we called ToggleKeys,
; must undo previous clearing of fbios_called_timing if fFilterKeys is On
jne dummy_proc_end
mov fbios_called_timing,true ; reset flag so int. 15 will pass the key and exit
dummy_proc_end:
ret
dummy_proc endp
;----------------------------------------------------------------------------
; off_proc
;
; Expects: cx = extended scan code
;
; This routine only gets the break codes of numlock when turned on, the make/break
; code of the numlock if the operator wants to toggle MouseKeys on/off, or the make num lock
; scan code when the operator wants to turn off MouseKeys. It is set up for laptops especially,
; and all other computers that toggling the numlock key by itself whilc MouseKeys is on, will
; toggle the Numeric KeyPad On/Off (i.e. MouseKeys will toggle On/Off but not tottaly off)
; which requires three key left shift left alt and numlock keys
off_proc proc
assume DS:_TEXT
cmp fJust_Manually_On,true ; is this the break of turn On numlock ?
jne off_25
test cl,break_bit ; is it a make numlock, if so pass
jnz off_10 ; wait for numlock break to turn on
jmp off_112 ; typematic makes of num lock turn on, eat
off_10:
cmp fspace_saver,true ; if space saver keyboard, must pass on break
jne off_20 ; if we passed on the num lock make originally
cmp fSticKeysOn,true ; is StickeyKeys On ???
jne off_20
cmp fnum_lock_was_off,true ; see if we originally passed num lock make code ?
jne off_20 ; if not, do not pass on the break as well
jmp off_107
off_20:
jmp off_110 ; if not, exit at 110 by not passing key on
off_25:
; if gets here, it could be numlock make/break and we don't know if the user waants to turn MouseKeys Off
; unless we check if the left shift and the left alt keys are depressed
; NOTE: If StickeyKeys is On, the modifier flags will only be set on the make of the num lock key.
cmp dh,fLshift + fAlt ; are the left shift and alt down?
jne off_100 ; no, so just a numlock make by itself, pass on
; if yes, left alt + left shift + numlock so shut off
call mk_turn_off_fb
mov fbutton,false ; move mousekey mouse button to false
mov fpass_numlock_spsav,false ; clear flag
jmp off_110 ; jump to here so we eat the numlock make code
off_100:
; if gets here, it is just a numlock make/break without any modifier keys
test cl,break_bit ; is it a make numlock, if yes, change status
jz off_101
jmp off_106 ; it was a break, pass on for all KYBDS
off_101:
cmp fpass_numlock_spsav,true ; flag to stop typematic on/off/on/off... of MouseKeys
jne off_102
jmp off_110
off_102:
mov fpass_numlock_spsav,true
cmp fpass_mousekeys,true ; are MouseKeys currently being trapped ???
je off_105
mov fpass_mousekeys,true ; trap numeric keys (i.e MouseKeys is On)
cmp fspace_saver,true ; it was a make, do we have the space saver ?
jne off_103D
cmp fSticKeysOn,true ; is StickeyKeys On ???
jne off_103D ; if StickeyKeys isn't On, don't mess with Num Lock
off_103A:
cmp fToggleKeysOn,true
jne off_103D
jmp off_107 ; passing num lock on by space saver will do beeps
off_103D:
cmp fMK_On_Off_Feedback,false
je off_103E
call beep_high ; beep high if toggle Mousekeys back on
off_103E:
cmp fswitching_video,false
jne off_104
mov faccess_sound,true
mov fsecond_cue,7
off_104:
cmp fspace_saver,true ; is it space saver ?
je off_107
jmp short off_110
;--------------------------------------------
off_105:
mov fpass_mousekeys,false ; untrap or pass numeric keys (i.e MouseKeys is Off)
cmp fspace_saver,true ; it was a make, do we have the space saver ?
jne off_105C
cmp fSticKeysOn,true ; is StickeyKeys On ???
jne off_105C ; if StickeyKeys isn't On, don't mess with Num Lock
off_105A:
cmp fToggleKeysOn,true
jne off_105C
jmp short off_107 ; passing num lock on by space saver will do beeps
off_105C:
cmp fMK_On_Off_Feedback,false
je off_105D
call beep_low ; beep low if toggle Mousekeys back off
off_105D:
cmp fswitching_video,false
jne off_105E
mov faccess_sound,true
mov fsecond_cue,9
off_105E:
; if we toggle off, we must be sure that mousekeys mouse buttons are released
push ax ; temp save
push cx ; temp save
mov cx,0053h ; button up key code
mov ax,1 ; same as if called from table for a button up
mov fbutton_up,true ; ""
mov fbutton_down,false ; ""
call button_click ; ""
pop cx ; restore register
pop ax ; restore register
cmp fspace_saver,true ; it was a make, do we have the space saver ?
je off_107
jmp short off_110
off_106:
mov fpass_numlock_spsav,false ; we got a break of the num lock, clear flag
off_107:
cmp fSticKeysOn,true ; is StickeyKeys On ???
jne off_110 ; if StickeyKeys isn't On, don't mess with Num Lock
mov ax,cx ; ToggleKeys expects scan code in ax register
call ToggleKeys ; pass num lock key on, regardless if Mkeys On/Off
cmp ftimer_1C_active,true ; if space_saver kybd, and we called ToggleKeys,
; must undo previous clearing of fbios_called_timing if fFilterKeys is On
jne off_110
mov fbios_called_timing,true ; reset flag so int. 15 will pass the key and exit
off_110:
mov fnum_lock_was_off,false
mov fJust_Manually_On,false
off_112:
ret
off_proc endp
;----------------------------------------------------------------------------
; btn_sel_proc
;
; Expects: ax = button value, where ah=button if serial mouse and al=button if AUX. port mouse
;
; Must check here for which type of keyboard we have. If we have the 101/102
; key beyboard, then we can emulate a 3 button mouse because we have "/,*, and-"
; on the numeric keypad. If we do not have the 101/102 keyboard, then we
; probably only have the 84 key keyboard, which only has the "* and -" key,
; so we can only emulate a 2 button mouse. If ax="btn_1 + btn_2", or "03h",(AUX) mouse,
; then, we must check to keyboard type and either leave ax alone for the
; 101/102 key keyboard, or reset to only "btn_1" for an 84 key keyboard.
btn_sel_proc proc
assume DS:_TEXT
push ax
mov fbutton,false ; move mousekey mouse button to false
cmp _fmouse_id,4 ; do we have a AUX. port PS/2 mouse ?
jne btn_sel_10
mov Temp_Button,al ; set to which ever button(s)
cmp Temp_Button,03h ; is it a "btn_1 + btn_2" ?
je btn_sel_20 ; yes, so check if we support it
mov Current_Button,al ; no, select what ever button, and quit
jmp short btn_sel_60 ; process both buttons pushed together
btn_sel_10:
cmp _fmouse_id,2 ; do we have a serial port mouse ?
jne btn_sel_50 ; no, somethings wrong !!! this should never execute !
mov Temp_Button,ah ; set to which ever button(s)
cmp Temp_Button,030h ; is it a "btn_1 + btn_2" ?
je btn_sel_20 ; yes, so check if we support it
mov Current_Button,ah ; no, select what ever button, and quit
jmp short btn_sel_60 ; process both buttons pushed together
btn_sel_20:
; if we get here, we have a "btn_1 + btn_2" push, and need to verify the keyboard type
; we can now check comp_id, and if we don't have a 2(New XT), 6(25..30/86), 7(New XT
; New AT, 25..30..50..60/286) or 8(55SX..70..80), then we don't have a kb_flag_3 to check !!!
; Could also be true for new 5A or 1A....see new keyboard.inc
cmp comp_flag,true ; do we have a comp_id of #2,#5A,#5B,#6,#7, or #8 ?
jne btn_sel_25
mov Current_Button,al ; let btn1+btn2 through
jmp short btn_sel_60
btn_sel_25:
; if comp_flag is not set, we have a comp_id of 1=PC, 5=Orig. AT
; 3= Jr. or 4=Conv. We do not support selections 3 and 4, and if it is either
; 1 or 5, the mouse must be a serial mouse, so reset the mouse button to the left
; button for either of these two, or beep error for Jr./Conv. and then set button
cmp _comp_id,1
je btn_sel_55
cmp _comp_id,5
je btn_sel_55
btn_sel_50:
call beep_high ; beep high for button error selection
cmp fswitching_video,false
jne btn_sel_55
mov faccess_sound,true
mov fsecond_cue,7
btn_sel_55:
; there is really no reason why a PS/2 should have an 84 key keyboard and a serial mouse !!!
cmp _fmouse_id,4 ; do we have a AUX. port PS/2 mouse ?
jne btn_sel_56
mov Current_Button,01h ; left button AUX
jmp short btn_sel_60
btn_sel_56:
cmp _fmouse_id,2 ; do we have a serial port mouse ?
jne btn_sel_60 ; no, somethings wrong !!! this should never execute !
mov Current_Button,020h ; left button serial
btn_sel_60:
pop ax
ret
btn_sel_proc endp
;----------------------------------------------------------------------------
; button_delta
;
; Expects: ax = 0 - buttons up
; = non 0 - buttons down
; cx = extended scan code
;
; Changes: bx,dx
button_delta proc
assume DS:_TEXT
push ax
push bx
push cx
push dx
mov fbutton,true ; mousekeys mouse button
test cl,break_bit ; is this the break key?
jz bd_5 ; no, so cont. on
jmp button_delta_end ; was a break key, so quit
bd_5:
call stop_moving ; yes, so stop any motion
mov bl,Button_Status ; current status
mov cl,Current_Button ; current button(s) to press
or ax,ax ; do a button(s) down?
jz bd_10 ; no -->
; Button down
or dl,cl ; get new status
mov Button_Status,dl ; keep Button_Status for next time thru
jmp bd_100
; Button up
bd_10:
or bl,bl ; any buttons down to let up
jnz bd_15
jmp button_delta_end ; no, was zero, so quit
bd_15:
not cl ; get mask to clear state
and dl,cl ; get new status
mov Button_Status,dl ; keep Button_Status for next time thru
; Now do delta
bd_100:
cmp _fmouse_id,4 ; is the PS/2 mouse driver loaded
jne bd_140
cmp Current_Button,1 ; left button ?
jne bd_110
cmp dl,0 ; button up ?
jne bd_105
mov dx,0008h ; release button 1
jmp bd_130
bd_105:
mov dx,0009h ; press button 1
jmp bd_130
bd_110:
cmp Current_Button,2 ; right button ?
jne bd_120
cmp dl,0 ; button up ?
jne bd_115
mov dx,0008h ; release button 2
jmp bd_130
bd_115:
mov dx,000ah ; press button 2
jmp bd_130
bd_120: ; if gets here, both buttons must be down/up
cmp dl,0 ; button up ?
jne bd_125
mov dx,0008h ; release both buttons
jmp bd_130
bd_125:
mov dx,000bh ; press both buttons
bd_130:
mov Mouse_Status,dx
jmp bd_200
;-----------------------------------------------------------------------------
; serial mouse buttons
bd_140:
cmp _fmouse_id,2 ; do we have a serial mouse ?
jne button_delta_end
; process serial mouse data
cmp Current_Button,20h ; left button ?
jne bd_150
cmp dl,0h ; button up ?
jne bd_145
mov dx,0040h ; release button 1
jmp bd_190
bd_145:
mov dx,0060h ; press button 1
jmp bd_190
bd_150:
cmp Current_Button,10h ; right button ?
jne bd_160
cmp dl,0h ; button up ?
jne bd_155
mov dx,0040h ; release button 2
jmp bd_190
bd_155:
mov dx,0050h ; press button 2
jmp bd_190
bd_160: ; if gets here, both buttons must be down/up
cmp dl,00h ; button up ?
jne bd_165
mov dx,0040h ; release both buttons
jmp bd_190
bd_165:
mov dx,0070h ; press both buttons
bd_190:
mov Mouse_Status,dx
bd_200:
cmp mouse_cnt,100 ; are there 100 mouse data words in buffer already ?
jge button_delta_end
push ax
mov ax,Mouse_Status
call Put_Mouse_Data ; store info on serial mouse or PS/2 mouse in buffer
mov ax,Delta_X
call Put_Mouse_Data ; store info on serial mouse or PS/2 mouse in buffer
mov ax,Delta_Y
call Put_Mouse_Data ; store info on serial mouse or PS/2 mouse in buffer
pop ax
mov fmouse_button,true ; is a mousekeys mouse button data
button_delta_end:
pop dx
pop cx
pop bx
pop ax
ret
button_delta endp
;----------------------------------------------------------------------------
; button_click
;
; Expects: nothing
;
; Changes: ax,bx,cx,dx
button_click proc
assume DS:_TEXT
mov fbutton,true ; mousekeys mouse button to true
cmp fbutton_up,true ; if we got a MouseKeys button_up, jump to do a button down/up only
jne button_click_5
cmp fmousetrapping,true ; is mouse int. hook off?
jne button_click_10
mov fbutton_up,false ; reset here if mouse int. trapping is off
jmp short button_click_15
button_click_5:
xor ax,ax
call button_delta ; make sure they are all up
not ax
button_click_10:
call button_delta ; then do click
button_click_15:
xor ax,ax
call button_delta
ret
button_click endp
;----------------------------------------------------------------------------
; dbl_click_proc
;
; Expects: Nothing
dbl_click_proc proc
assume DS:_TEXT
call button_click
call button_click
ret
dbl_click_proc endp
;----------------------------------------------------------------------------
; move_proc
;
; Expects: ax = direction ah = x dir
; al = y dir
; cx = extended code
;
; Changes: ax,cx
move_proc proc
assume DS:_TEXT
push cx
push ax
; check for break of key
mov fbutton,false ; move mousekey mouse button to false
test cl,break_bit ; is it a break key?
jz move_10 ; no -->
; deal with break of key
move_proc_5:
call stop_moving ; yes, stop moving mouse
move_7:
jmp move_proc_end
; deal with the make of a mousekey
move_10:
cmp Last_Direction,ax ; is this the same as last direction?
jne move_20 ; no -->
mov fMoving,true
jmp move_proc_end
move_20:
call stop_moving ; stop any other current motion
mov Last_Direction,ax ; save direction
; added code to allow the mouse cursor to move using mousekeys even if RepeatKeys is off
cmp fUser_SetUp_Option1,true ; if set, reallow fmoving
je MK_10
cmp fUser_SetUp_Option2,true ; if set, reallow fmoving
je MK_10
cmp on_repeat_ticks,32760 ; if set, repeat keys is off, reallow fmoving
je MK_10
cmp fRecovery_On,true ; if RecoveryKeys is on, reallow fmoving
je MK_10
cmp fserial_key_recieved,true ; if serial_key input, reallow fmoving
je MK_10
cmp _fmouse_id,2 ; do we have a serial mouse ?
jne MK_20 ; if we have a serial mouse, allow each key tap to get sent
MK_10:
mov fMoving,true ; allow mousekeys to work even if RepeatKeys is off
MK_20:
mov cx,ax ; get copy into cx
cmp _fmouse_id,4 ; is the PS/2 mouse driver loaded
jne MK_60
and ax,00ffh ; mask off ah, so al = y data
mov Delta_Y,ax ; Set delta Y
test al,80h ; is the high bit set (i.e. neg ?)
jz MK_30
or Status,20h ; if was neg, set bit 5 for negative Y
MK_30:
mov ax,cx ; restore ax with ah = x data, and al = y data
mov al,ah
and ax,00ffh ; mask off ah, so al now = x data
mov Delta_X,ax ; Set delta X
test al,80h ; is the high bit set (i.e. neg ?)
jz MK_50
or Status,10h ; if was neg, set bit 4 for negative X
MK_50:
mov al,Status ; now have direction in al register
or al,Button_Status ; get button status info. into al register
mov Mouse_Status,ax ; store into mouse_status for prep. to call inject proc.
call InjectMouse
jmp move_proc_end
;-------------------------------------------------------------------------------------
; serial mouse
MK_60:
cmp _fmouse_id,2 ; do we have a serial mouse ?
jne move_proc_end
; process serial mouse data
MK_70:
and ax,00ffh ; mask off ah, so al = y data
cmp al,00h ; if zero y movement, cont. on
je MK_80
test al,80h ; is the high bit set (i.e. neg ?)
jnz MK_75
or Status,0Ch ; if was pos, set bit 3 and 2 for negative Y
MK_75:
neg al ; serial mouse neg Y is up !
MK_80:
mov Delta_Y,ax ; Set delta Y
and Delta_Y,03fh ; flag not the first byte
mov ax,cx ; restore ax with ah = x data, and al = y data
mov al,ah
and ax,00ffh ; mask off ah, so al now = x data
mov Delta_X,ax ; Set delta X
test al,80h ; is the high bit set (i.e. neg ?)
jz MK_85
or Status,03h ; if was neg, set bit 1 and 0 for negative X
MK_85:
and Delta_X,03fh ; flag not the first byte
mov al,Status ; now have direction in al register
or al,Button_Status ; get button status info. into al register
or al,40h ; set the bit which always needs to be set for serial mouse
mov Mouse_Status,ax ; store into mouse_status for prep. to call inject proc.
cmp mouse_cnt,100 ; are there 100 nouse data wors in buffer already ?
jge move_proc_end
call Put_Mouse_Data ; store info on serial mouse in buffer
mov ax,Delta_X
call Put_Mouse_Data ; store info on serial mouse in buffer
mov ax,Delta_Y
call Put_Mouse_Data ; store info on serial mouse in buffer
mov fmouse_button,true ; is a mousekeys mouse button data
move_proc_end:
pop ax
pop cx
ret
move_proc endp
;---------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------
; MouseKeys
;
; This is the beginning of the routine to emulate a mouse with the keypad
; of the keyboard. It expects the extended scan code to be in AX.
;---------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------
mouse_begin:
assume DS:_TEXT
push es
push cs
pop es
assume ES:_TEXT
mov dh,shift_flg ; get assumed current states
or dh,real_states
or dh,lock_flg
cmp fMouseKeysOn,true ; is mouse key on?
je mouse_100 ; yes, do routines -->
;----------------------------------------------------------------------------
; We are off so only check to see if turned on
;
cmp ax,NumLock ; make of numlock?
jne mouse_108 ; no, just pass on
cmp dh,fLshift + fAlt ; only the left shift and alt down?
jne mouse_110 ; no, pass on -->
; must check if turned on by 3 key sequence, if mouse driver is not loaded,
; then don't allow mousekeys to turn on
cmp fmouse_driver,false ; if fmouse_driver false, don't turn mousekeys on
je mouse_112 ; no, just pass on -->
cmp fJust_Manually_Off,true ; did we just turn off
je mouse_112
call mk_turn_on_fb
cmp fspace_saver,true
jne mouse_55
cmp fSticKeysOn,true ; is StickeyKeys On ???
jne mouse_55 ; if StickeyKeys isn't On, don't mess with Num Lock
push es
push bx
push ax
assume es:NOTHING
mov bx,RAMBIOS
mov es,bx
assume es:RAMBIOS
mov al,es:[kb_flag]
test al,fNum ; is the num lock key already down ?
jnz mouse_50 ; if not zero, then it is already down and we don't want to pass it again
mov fnum_lock_was_off,true ; flag ourselves that we are going to pass the make
pop ax
pop bx
pop es
assume es:_TEXT
jmp short mouse_110 ; if space saver keyboard, pass num lock make on, as it will
; set up mousekeys correctly as num lock will be on
mouse_50:
pop ax
pop bx
pop es
assume es:_TEXT
mov fnum_lock_was_off,false ; flag ourselves that we did not pass the make, so we don't have to
; pass the break in off_proc
mouse_55:
jmp MouseKeys_end ; inhibit key stroke -->
;----------------------------------------------------------------------------
; we are on, so check for pertainent keys of mousekeys
;
mouse_100:
; must check if turned on by Dialog Box, if mouse driver is not loaded,
; then don't allow mousekeys to call Inject Mouse
mouse_102:
cmp fmouse_driver,false ; if fmouse_driver false, don't turn mousekeys on
je mouse_110 ; no, just pass on -->
mov si,ax ; save extended scan code in bx
and al,not break_bit ; get make scan code in al
mov cx,mouse_tbl_len ; search for a mouse key
mov di,offset mouse_tbl ; when done, cl will hold shift
cld ; count to get flag for mouse key
repne scasw ; ne=not found e=found
je mouse_10 ; yes, a key we are interested in -->
;
; Does not assume ToggleKeys saves any registers
;
call stop_moving ; no
mov ax,si ; restore original extended scan
push es
push ax
assume ES:NOTHING
mov ax, RAMBIOS ; BIOS RAM segment at 40h
mov es,ax ; .. point ES to that!
assume ES:RAMBIOS
mov al,es:kb_flag ; take a quick look at the flags
and al,03h ; mask off eveything except bits 1 and 0, left and right shift
jnz mouse_105 ; if either bit is set, then don't reset fmouse_button flag (i.e. shift click in progress)
mov fmouse_button,false ; not a mousekeys mouse button
mouse_105:
pop ax
pop es
assume ES:_TEXT
mouse_108:
mov fJust_Manually_Off,false ; reset to false upon non mousekey
mouse_110:
call ToggleKeys ; pass key on
mouse_112:
jmp MouseKeys_end
;
; We expect cx to hold the count of the key we found. We will now use it
; as an index into tables and jump to the appropriate routine to handle the
; key.
mouse_10:
shl cx,1 ; multiply by 2 to get offset to words
mov bx,cx ; put in bx
mov cx,si ; put scan in cx
cmp cx,052h ; is it mouse button down ?
jne mouse_12
mov fbutton_down,true ; yes it was, flag for later processing
mov fbutton_up,false ; reset other button flag
jmp short mouse_20
mouse_12:
cmp cx,053h ; button_up make code only, break falls thru per norm
jne mouse_20
mov fbutton_up,true ; if it is button_up, flag for later processing
mov fbutton_down,false ; reset other button flag
; since it is the period key, or "DEL", check to see if "CTRL and ALT" keys are down,
; i.e. the user wants to reboot, so don't make them have to turn off MouseKeys to do so
; for those users who do not have a seperate "DEL" cursor pad key
push es
push ax
assume ES:NOTHING
mov ax, RAMBIOS ; BIOS RAM segment at 40h
mov es,ax ; .. point ES to that!
assume ES:RAMBIOS
mov al,es:kb_flag ; take a quick look at the flags
and al,0ch ; mask off eveything except bits 2 and 3(ctrl and alt)
cmp al,0ch ; are both bits set
jne mouse_18 ; if no flags are set, cont. on as normal
pop ax
pop es
mov fmouse_button,false ; not a mousekeys mouse button
mov ax,si ; restore original extended scan
call ToggleKeys ; pass key on, which will cause a reboot !!!
jmp short MouseKeys_end
mouse_18:
pop ax
pop es
assume ES:_TEXT
mouse_20:
cmp cx,045h ; numlock make key ???
jne mouse_21
jmp short mouse_22
mouse_21:
cmp cx,0c5h ; numlock break key ???
jne mouse_25
mouse_22:
; was a numlock make/break code, so check if it is really the nulock, or part of the PAUSE key?
cmp fpause_being_sent,true ; is PAUSE key being sent ??
jne mouse_25 ; if not a PAUSE, send on as normal MouseKey
; if part of PAUSE key, pass on to ToggleKeys
mov ax,si ; restore original extended scan
call ToggleKeys ; pass key on
; when we retrun from ToggleKeys
mov fpause_being_sent,false ; reset this flag after we pass the PAUSE key parts along
jmp short MouseKeys_end
mouse_25:
; check first if we've been silently toggled off due to num lock key (used for laptops)
cmp fpass_mousekeys,true ; allow numeric keys to be trapped
je mouse_40 ; yes, cont on
; fpass_mousekeys is false, we are not trapping mousekeys, so only trap numlock key
cmp cx,045h ; numlock make key ???
je mouse_40
cmp cx,0c5h ; numlock break key ??
je mouse_40
mov ax,si ; restore original extended scan
call ToggleKeys ; pass key on
jmp short MouseKeys_end
mouse_40:
mov fbios_called_timing,false ; reset flag if it was a mousekey and we are not calling ToggleKeys
mov ax,MK_data_table[bx] ; get data to pass to routine
call MK_call_table[bx] ; now do it
MouseKeys_end:
pop es
assume ES:NOTHING
ret
MouseKeys endp
_TEXT ends
end