;MOUSECURsor for Microsoft Mouse drivers - 9/87, upgraded 9/89 ;Based on Jeff Prosise's MOUSEKEY. ;------------------------------------------------------------ ; Microsoft MOUSE.COM or MOUSE.SYS, or a compatible driver must be installed. ; Works with the Mouse Systems MSMOUSE driver, but takes less total RAM. ; MOUSER works with ANY PROGRAM that accepts the cursor keys. ; Mouse speed and buttons can be programmed. ; The cursor keys continue to work as usual. Programs with mouse drivers work ; independently of MOUSER. ; -------------------------------------------------------------------------- ; PARAMETERS ; MOUSER Hn Vn Lnn Mnn Rnn ? ; ? = help (also appears if invalid command line params are entered) ; Hn, Vn n=1 to 9 - sets Horizontal or Vertical cursor speed ; Lx, Mx, Rx - x=character or 2-digit decimal ASCII value: ; Left, Middle, or Right button values ; Digit values above 31 are treated as 'extended' keys. ; Params are all optional, in any order, with any delimiters. ; -------------------------------------------------------------------------- ; ABOUT TSR AND RELOADING ; Only one copy of MOUSER ever loads; after that, only the parameters ; are updated whenever the program is run. ; Some programs disable MOUSER; you can put MOUSER in the application's ; .BAT startup file, after the application program, to turn the mouse back on. ; Programs (like ACAD) with internal mouse drivers are commonly guilty of this. ; -------------------------------------------------------------------------- cr equ 0Dh lf equ 0Ah code segment byte public 'code' assume cs:code, ds:code, es:code org 100h Start: jmp Install ResFinder db 'MOUSER CODE' ;Used to determine if MOUSER is resident vdelay db 8 ;vertical divider (set by Vn) hdelay db 8 ;horizontal divider (set by Hn) lkey dw 0Dh ;keycode for left button (set by Lnn) rkey dw 1Bh ;keycode for right button (set by Rnn) mkey dw 5200h ;keycode for middle button (set by Mnn) vcount dw 0 ;vertical mickeys since last update hcount dw 0 ;horizontal UpDnPointer dw 0 LeRiPointer dw 0 ;keycode below is at 011Eh in code keycode db 4Dh,4Bh,50h,48h ;codes for rt/left/dn/up cursor keys ;------------------------------------------------------------------------------ ;This routine gets a FAR CALL from the Microsoft driver when the mouse is ; moved or a button is pressed. mouse: push ds mov dx,cs mov ds,dx mov dx,lkey test ax,2 ;bit 1, left button pressed ? jnz PutAndRet ;yes, jump mov dx,rkey test ax,8 ;bit 3, right button ? jnz PutAndRet mov dx,mkey test ax,32 ;bit 5, middle button ? jz Move ;no, must be mouse move PutAndRet: mov ax,dx call PutCode MouseRet: pop ds retf ; - - - - - - - - - - - - - - - - - - - - - - - - ;Move the cursor. ;hdelay & vdelay are input as Hn Vn params, 1-slow to 8-fast, and converted ;for decrementing to divide by 128-slow to 1-fast. It skips that number of ; mickeys (mouse increments) before responding. Move: mov ax,0Bh ;read mouse motion counters int 33h ; CX=hor, DX=vert count mov LeRiPointer,0 ;point to Right keycode mov UpDnPointer,2 ;point to Down keycode ;accumulate motion, use totals. No total exceeds +/- 32K. add hcount,cx jno NoHorOflo jns HorPos mov hcount,-32768 HorPos: mov hcount,32767 NoHorOflo: add vcount,dx jno NoVertOflo jns VertPos mov vcount,-32768 VertPos: mov vcount,32767 NoVertOflo: cmp vcount,0 ;vertical count positive? jge VDirSet inc UpDnPointer ;point to Up code VDirSet: cmp hcount,0 ;horizontal count positive? jge DivideEm inc LeRiPointer ;point to Left code ; Now the pointers point to the proper key code for the accumulated motion. ; The counts still are signed. ;Ideally, this would alternate hor & vert codes for diagonal moves. DivideEm: mov ax,vcount cwd ;extend AX to DX:AX mov cl,vdelay xor ch,ch idiv cx mov vcount,dx ;signed remainder mov cx,ax ;CX has no. of codes to insert, signed or cx,cx jz DoHor jns VertNotNeg neg cx VertNotNeg: mov bx,UpDnPointer mov ah,ds:[bx+keycode] call MovePut ;now do the same for horiz motion DoHor: mov ax,hcount cwd mov cl,hdelay xor ch,ch idiv cx mov hcount,dx ;signed remainder mov cx,ax or cx,cx ;filter out zero to insert jnz HorSome jmp MouseRet HorSome: jns HorNotNeg neg cx HorNotNeg: mov bx,LeRiPointer mov ah,ds:[bx+keycode] ;get keycode from table call MovePut jmp MouseRet MovePut: xor al,al ;zero AL for extended keycode PutLoop: call PutCode loop PutLoop ;sets CX=1 if buffer full, so will exit ret ; - - - - - - - - - - - - - - - - - - - - - - - - ;Put the keycode in AX into the keyboard buffer. PutCode: push ds push bx mov bx,40h ;point DS to BIOS data area mov ds,bx cli ;disable interrupts mov bx,ds:[1Ch] ;buffer tail mov dx,bx add dx,2 ;calculate next buffer position cmp dx,ds:[82h] ;did we overshoot the buffer end? jnz insert1 ;no, continue mov dx,ds:[80h] ;yes, wrap around to buffer start insert1: cmp dx,ds:[1Ah] ;buffer head - is the buffer full? jnz DoInsert ;no, do it mov cx,1 ;to exit calling loop jmp InsDone DoInsert: mov ds:[bx],ax mov bx,dx ;advance & mov ds:[1Ch],bx ; store new pointer InsDone: sti pop bx pop ds ret ;- - - - - - - end of resident portion - - - - - - - Banner db cr,lf,'MOUSECUR 10/87 by Paul Noeldner, Madison, WI' db ' - - - hacked by J. E. Arkay 9/89' db cr,lf,'$' helpmsg db 'Cursor enabler for Microsoft Mouse drivers.' db cr,lf,lf db 'You can set the speed for easy pointing and the buttons for common keys.' db cr,lf db ' Put it in .BAT files, to set it up for your applications.' jnkhelp db cr,lf,lf db 'Example:',cr,lf db ' MOUSECUR H5 V5 L13 R27 M82 shows default parameters.',cr,lf db ' MOUSECUR H1 V2 M/ Slower cursor (for 123-style menus)' db cr,lf db ' MOUSECUR V7 L73 M81 R27 Faster with PGUP/PGDN (for browsing)' db cr,lf,lf db ' Hn, Vn Horizontal, Vertical speed 1-8 (default 5 if not entered)' db cr,lf db ' Lx, Mx, Rx Button characters or decimal ASCII key codes' db cr,lf db ' All params are optional, in any order, with any delimiter.' db cr,lf db ' ASCII values over 31 decimal are taken to be extended keys.' db cr,lf,lf db ' Commonly used keys (see a BASIC manual for more):' db cr,lf db '03 - CTRL-C 09 - TAB 13 - RETURN 27 - ESC' db cr,lf db '71 - HOME 73 - PGUP 78 - GRAY + 79 - END 81 - PGDN' db cr,lf db '82 - INSERT 83 - DELETE 59 THRU 68 - F1 THRU F10' db cr,lf,lf,'$' NoDriverMsg db cr,lf,' DRIVER MISSING: Install MOUSE.SYS, MOUSE.COM,' db ' MSMOUSE.COM, etc.',cr,lf,lf,'$' junkmsg db cr,lf,' INVALID PARAMETER - CHECK THIS SCREEN',7,'$' loadmsg db 'Mouse Cursor Installed',cr,lf,lf,'$' AdjustedMsg db 'Mouse Parameters Adjusted ',cr,lf,lf,'$' endparm dw 81h ;offset of end of params posted db 'N' ;is MOUSER already loaded ? DigitFlag db 'N' ;found a digit in command line Install: mov dx,OFFSET Banner mov ah,9 int 21h mov ax,0 ;check Microsoft driver is installed and reset. int 33h or ax,ax jnz DrvrOK ;AX=0FFFFh if installed OK mov dx,OFFSET NoDriverMsg jmp MsgExit DrvrOK: call parms ;process command line params call Find ;if MOUSECUR is resident, update params cmp posted,'Y' jnz TSR ;if not, install this copy mov dx,OFFSET AdjustedMsg jmp MsgExit TSR: mov ah,9 mov dx,OFFSET loadmsg int 21h mov ax,0Ch ;activate Microsoft driver mov cx,101011b ;'call mask'- call if mouse moved, or button press mov dx,OFFSET mouse ;point ES:DX to our routine int 33h ;pass address to mouse driver ;de-allocate the Environment Block, we don't need it ; NOTE: This sometimes leaves a uselessly small unused Block push es xor ax,ax xchg ax,word ptr CS:2Ch ;Environment Block addr in the PSP or ax,ax jz GoRes ;skip it if there is no Env mov es,ax mov ah,49h ;free allocated RAM int 21h GoRes: pop es mov dx,offset Banner ;bytes to stay resident add dx,15 ;allow for fractional para mov cl,4 shr dx,cl ;paras to stay resident mov ax,3100h ;go TSR int 21h ; - - - - - - - - - - - - - - - - - - - ;Process command line params (if any) parms: mov si,80h ;point at input param length in PSP mov ah,0 mov al,[si] ;length of params add ax,80h ;compute end of params mov endparm,ax ;remember it inc si ;skip initial space in input params parmloop: inc si cmp si,endparm ;at end of params ? jle parse ;if not, process it ret ;if so, done with setup parse: mov al,[si] ;get next character cmp al,' ' ;skip blanks jz parmloop cmp al,'/' ;skip slashes jz parmloop cmp al,',' ;skip commas jz parmloop help: cmp al,'?' ;show help? jnz case mov dx,OFFSET helpmsg MsgExit: mov ah,9 int 21h mov ax,4C01h ;exit w/Errorlevel = 1 int 21h case: cmp al,91 ;upper case? jl upper sub al,32 ;convert lower to upper case upper: call parmcheck ;see if H, V, L, R jmp parmloop ;continue parsing ;Check for Horizontal and Vertical Speed, Left/Right/Both button control values parmcheck: cmp al,'H' ;horizontal speed param ? jnz parmv call digedit ;next byte to AL cmp DigitFlag,'Y' jnz junk ;error if not cmp al,8 ja junk call CvtSpeed mov hdelay,ah ret ;back to parsing params parmv: cmp al,'V' ;vertical speed param ? jnz parml call digedit ;next byte to AL cmp DigitFlag,'Y' jnz junk ;error if not cmp al,8 ja junk call CvtSpeed mov vdelay,ah ret CvtSpeed: mov ah,80h sub al,1 ;DEC AL will not set the C flag !! jc CvtRet ;if speed input was 0, use speed 1 mov cl,al shr ah,cl ;each number is a factor of 2 CvtRet: ret parml: cmp al,'L' ;left button param ? jnz parmr call dighex ;get 2 ASCII bytes to AX mov lkey,ax ;left button key code ret parmr: cmp al,'R' ;right button param ? jnz parmb call dighex ;get 2 ASCII bytes to AX mov rkey,ax ;right button key code ret parmb: cmp al,'M' ;middle button param ? jnz junk ;error if not call dighex ;get 2 ASCII bytes to AX mov mkey,ax ;both buttons key code ret junk: mov dx,OFFSET junkmsg mov ah,9 int 21h mov dx,OFFSET jnkhelp ;help, error message for invalid parms jmp MsgExit ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;Check for other copies of this program in memory by walking MCB's. ;See HOTBOOT3 for how to avoid the copy in the disk buffer with shorter code. ;If MOUSER is already resident, params are updated in that copy of the program. Find: push ax push bx push cx push dx push es cld ;compare UPward mov ah,52h ;get DOS list of lists int 21h mov bx,es:[bx-2] ;starting MCB seg address inc bx ;for first DEC below FindLoop: dec bx mov es,bx ;point to the MCB add bx,es:[3] inc bx ;length + 1 points next MCB inc bx ;and 1 more points next block mov es,bx mov ax,cs cmp bx,ax ;BX and ES up to present CS ? jae NoCopies mov si,offset ResFinder ;point DS:SI to our signature mov di,si ;look the same place in both segs mov cx,11 ;length of 'MOUSER CODE' repz cmpsb ;DS:[SI] - ES:[DI] and inc SI & DI jnz FindLoop ;if not same, check next block ;Post params in current resident MOUSER mov posted,'Y' ;flag we've done this mov al,vdelay ;copy from this loaded copy mov es:vdelay,al ; to resident copy mov al,hdelay mov es:hdelay,al mov ax,lkey mov es:lkey,ax mov ax,rkey mov es:rkey,ax mov ax,mkey mov es:mkey,ax ;Re-activate the Microsoft driver mov ax,0Ch ;set driver active mov cx,00101011b ;'call mask', move or button press (not release) mov dx,offset mouse ;ES:DX points installed Mouse routine int 33h NoCopies: pop es pop dx pop cx pop bx pop ax ret ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;ASCII digits to hex routine dighex: call digedit ;get next byte into AL cmp DigitFlag,'Y' jz digcon ret ;otherwise got literal in AX digcon: mov bx,ax ;save hi digit call digedit ;get next byte cmp DigitFlag,'Y' jz ItsOK jmp junk ;error if not ItsOK: xchg ax,bx ;hi byte to AX, lo byte to BX mov cx,10 mul cx ;AX=hi byte times 10 add ax,bx ;now AX=value cmp al,' ' ;is number < 20h ? jl setok ;yes, set as is mov ah,al ;make higher nos the high byte, and xor al,al ; null the low byte for extended keycode setok: ret ;Get value of ASCII digit or literal into AL with AH=0 digedit: mov DigitFlag,'N' ;assume literal, not digit inc si mov al,[si] ;get next byte mov ah,al ;save literal value sub al,30h ;convert digit to hex jl liter ;if < 0, is literal cmp al,9 jg liter ;if not digit, is literal mov DigitFlag,'Y' xor ah,ah ret liter: mov al,ah ;use literal character xor ah,ah ret ;back to param scan code ends end Start