791 lines
20 KiB
NASM
791 lines
20 KiB
NASM
;++
|
|
;
|
|
; WOW v1.0
|
|
;
|
|
; Copyright (c) 1991, Microsoft Corporation
|
|
;
|
|
; WINMISC2.ASM
|
|
; Win16 misc. user services
|
|
;
|
|
; History:
|
|
;
|
|
; Created 28-May-1991 by Jeff Parsons (jeffpar)
|
|
; Copied from WIN31 and edited (as little as possible) for WOW16
|
|
;--
|
|
|
|
;****************************************************************************
|
|
;* *
|
|
;* WINMISC2.ASM - *
|
|
;* *
|
|
;* Random stuff *
|
|
;* *
|
|
;****************************************************************************
|
|
|
|
ifdef WOW
|
|
SEGNAME equ <TEXT>
|
|
endif
|
|
|
|
.xlist
|
|
include user.inc
|
|
include vint.inc
|
|
.list
|
|
|
|
ExternFP <GlobalHandleNorip>
|
|
ExternFP <MessageBox>
|
|
ExternFP <SysErrorBox>
|
|
|
|
|
|
ifndef WOW
|
|
ExternFP <DoBeep>
|
|
ExternFP <XCSTODS>
|
|
ExternNP <rgbKeyState>
|
|
ExternW <hwndCapture>
|
|
ExternW <fBeep>
|
|
ExternW <fMessageBox>
|
|
ExternW <hwndDragIcon>
|
|
|
|
ExternA <__WinFlags>
|
|
|
|
ATOMTABLE STRUC
|
|
at_prime DW ?
|
|
at_hashTable DW ?
|
|
ATOMTABLE ENDS
|
|
|
|
ATOM STRUC
|
|
a_chain DW ?
|
|
a_usage DW ?
|
|
a_len DB ?
|
|
a_name DB ?
|
|
ATOM ENDS
|
|
|
|
LocalArena STRUC
|
|
la_prev DW ? ; previous arena entry (first entry points to self)
|
|
la_next DW ? ; next arena entry (last entry points to self)
|
|
la_handle DW ? ; back link to handle table entry
|
|
LocalArena ENDS
|
|
|
|
sBegin DATA
|
|
|
|
;
|
|
; For GetSysMetrics - don't move this stuff. DS positioning is assumed.
|
|
;
|
|
SM_CMETRICS1 equ 24
|
|
SM_CMETRICS2 equ 16
|
|
|
|
public rgwSysMet
|
|
rgwSysMet dw (SM_CMETRICS1) DUP(0)
|
|
|
|
; These are 'variable metrics', conviently located the system metrics array.
|
|
GlobalW hwndFullScrn, 0
|
|
GlobalW iLevelCursor, 0
|
|
|
|
; These are additions since 2.0
|
|
dw SM_CMETRICS2 DUP(0)
|
|
|
|
|
|
sEnd DATA
|
|
endif ;WOW
|
|
|
|
createSeg _%SEGNAME, %SEGNAME, WORD, PUBLIC, CODE
|
|
|
|
assumes cs,%SEGNAME
|
|
assumes ds,DATA
|
|
|
|
sBegin %SEGNAME
|
|
|
|
ifndef WOW
|
|
;*--------------------------------------------------------------------------*
|
|
;* *
|
|
;* GetSystemMetrics() - *
|
|
;* *
|
|
;*--------------------------------------------------------------------------*
|
|
|
|
; int far GetSystemMetrics(iMetric)
|
|
; int iMetric;
|
|
|
|
LabelFP <PUBLIC, GetSystemMetrics>
|
|
|
|
pop ax ; Pop the FAR return
|
|
pop dx
|
|
pop bx ; BX = iMetric
|
|
push dx ; Restore the FAR return
|
|
push ax
|
|
|
|
xor ax,ax
|
|
cmp bx,SM_CMETRICSMAX ; Bigger than max?
|
|
jge gsmExit ; Yes, exit
|
|
shl bx,1 ; Convert to a byte index
|
|
|
|
ifndef userhimem
|
|
mov es,WORD PTR cs:[cstods]
|
|
else
|
|
push ax
|
|
push ds
|
|
call XCSTODS
|
|
mov es,ax
|
|
pop ds
|
|
pop ax
|
|
endif
|
|
|
|
assumes es,DATA
|
|
mov ax,es:[rgwSysMet+bx] ; Return the SysMetric value
|
|
assumes es,NOTHING
|
|
gsmExit:
|
|
retf
|
|
|
|
|
|
;*--------------------------------------------------------------------------*
|
|
;* *
|
|
;* MessageBeep() - *
|
|
;* *
|
|
;*--------------------------------------------------------------------------*
|
|
|
|
cProc MessageBeep, <FAR, PUBLIC>
|
|
|
|
ParmW beep
|
|
|
|
cBegin
|
|
cmp fBeep,0
|
|
je mbout ; No beeps today....
|
|
mov ax,beep
|
|
cmp fMessageBox,0 ; if we are in an INT24 box, let
|
|
je noint24 ; the sound driver know not to load
|
|
mov ax,-1 ; anything by passing -1.
|
|
noint24:
|
|
push ax
|
|
call DoBeep ; Just call the sound driver guy
|
|
mbout:
|
|
|
|
cEnd
|
|
|
|
|
|
;*--------------------------------------------------------------------------*
|
|
;* *
|
|
;* IsChild() - *
|
|
;* *
|
|
;*--------------------------------------------------------------------------*
|
|
|
|
LabelFP <PUBLIC, IsChild>
|
|
;
|
|
;ParmW hwnd
|
|
;ParmW hwndChild
|
|
;
|
|
pop ax ; pop return address
|
|
pop dx
|
|
pop bx ; bx = hwndChild
|
|
pop cx ; cx = hwnd
|
|
push dx ; push return address
|
|
push ax
|
|
|
|
push ds
|
|
UserDStoDS ; es = USER's DS
|
|
|
|
CheckHwnd cx ; checkhwnd will zero ax if failure
|
|
jz icexit
|
|
ifdef DEBUG
|
|
CheckHwndNull bx ; only do check if debug since
|
|
jz icexit ; we never access anything off this
|
|
; pointer
|
|
endif
|
|
xor ax,ax ; Assume FALSE
|
|
icloop:
|
|
or bx,bx ; while (hwndChild == NULL &&
|
|
jz icexit
|
|
mov dl,byte ptr [bx+WSTATE+WFTYPEMASK/256]
|
|
and dl,LOW(WFTYPEMASK) ; TestwndChild(hwndChild))
|
|
cmp dl,LOW(WFCHILD)
|
|
jne icexit
|
|
mov bx,[bx].wndPwndParent ; hwndChild = hwndChild->hwndParent
|
|
cmp bx,cx ; if (hwnd == hwndChild)
|
|
jne icloop
|
|
inc al ; return(TRUE);
|
|
icexit:
|
|
pop ds
|
|
retf
|
|
|
|
; BOOL IsDescendant(hwndParent, hwndChild);
|
|
;
|
|
; Internal version of IsChild that is a bit faster and ignores the
|
|
; WFCHILD business. MUST be called with DS == USER DS.
|
|
;
|
|
; Returns TRUE if hwndChild == hwndParent (IsChild doesn't)
|
|
;
|
|
; while (hwndChild != NULL)
|
|
; {
|
|
; if (hwndParent == hwndChild)
|
|
; return TRUE;
|
|
; hwndChild = hwndChild->hwndParent;
|
|
; }
|
|
;
|
|
LabelFP <PUBLIC, IsDescendant>
|
|
pop ax ; pop off return address
|
|
pop dx
|
|
pop bx ; bx = hwndChild
|
|
pop cx ; cx = hwndParent
|
|
push dx ; replace return address
|
|
push ax
|
|
|
|
xor ax,ax ; assume FALSE
|
|
idloop:
|
|
or bx,bx ; if at end, return FALSE
|
|
jz idexit
|
|
cmp bx,cx ; hwndChild == hwndParent?
|
|
mov bx,[bx].wndPwndParent ; hwndChild = hwndChild->hwndParent
|
|
jnz idloop ; keep looping if we didn't find it...
|
|
|
|
inc al ; ax = TRUE
|
|
idexit:
|
|
retf
|
|
|
|
;--------------------------------------------------------------------------
|
|
;
|
|
; IsWindowVisible() -
|
|
;
|
|
;--------------------------------------------------------------------------
|
|
;
|
|
; BOOL FAR PASCAL IsWindowVisible(register HWND hwnd)
|
|
; {
|
|
; if (!CheckHwnd(hwnd))
|
|
; return(FALSE);
|
|
;
|
|
; if (hwnd == hwndDragIcon)
|
|
; return(TRUE);
|
|
;
|
|
; for ( ; hwnd != NULL; hwnd = hwnd->hwndParent)
|
|
; {
|
|
; if (!TestWF(hwnd, WFVISIBLE))
|
|
; return FALSE;
|
|
; }
|
|
; return TRUE;
|
|
; }
|
|
;
|
|
LabelFP <PUBLIC, IsWindowVisible>
|
|
;ParmW hwnd
|
|
pop ax ; pop return address
|
|
pop dx
|
|
pop bx ; bx = hwnd
|
|
push dx ; push return address
|
|
push ax
|
|
|
|
push ds
|
|
UserDStoDS ; es = USER's DS
|
|
|
|
CheckHwnd bx ; checkhwnd will zero ax if failure
|
|
jz ivwexit
|
|
|
|
mov ax,TRUE ; assume TRUE
|
|
|
|
; Check if this is the iconic window being moved around with a mouse */
|
|
; If so, return a TRUE, though, strictly speaking, it is hidden. */
|
|
; This helps the Tracer guys from going crazy! */
|
|
; Fix for Bug #57 -- SANKAR -- 08-08-89 -- */
|
|
;
|
|
cmp bx,hwndDragIcon ; hwnd == hwndDragIcon?
|
|
jz ivwexit ; yes: return TRUE.
|
|
ivwloop:
|
|
or bx,bx ; while (hwndChild == NULL &&
|
|
jz ivwexit
|
|
TSTWF bx,WFVISIBLE
|
|
mov bx,[bx].wndPwndParent ; hwndChild = hwndChild->hwndParent
|
|
jnz ivwloop ; if visible bit set, keep looping
|
|
|
|
xor ax,ax ; visible bit clear: return FALSE
|
|
ivwexit:
|
|
pop ds
|
|
retf
|
|
|
|
|
|
;=======================================================================
|
|
;
|
|
; Return whether or not a given window can be drawn in or not.
|
|
;
|
|
; BOOL FAR IsVisible(HWND hwnd, BOOL fClient)
|
|
; {
|
|
; HWND hwndT;
|
|
;
|
|
; for (hwndT = hwnd; hwndT != NULL; hwndT = hwndT->hwndParent)
|
|
; {
|
|
; // Invisible windows are always invisible
|
|
; //
|
|
; if (!TestWF(hwndT, WFVISIBLE))
|
|
; return FALSE;
|
|
;
|
|
; if (TestWF(hwndT, WFICONIC))
|
|
; {
|
|
; // Children of icons are always invisible.
|
|
; //
|
|
; if (hwndT != hwnd)
|
|
; return FALSE;
|
|
;
|
|
; // Client areas with class icons are always invisible.
|
|
; //
|
|
; if (fClient && hwndT->pcls->hIcon)
|
|
; return FALSE;
|
|
; }
|
|
; }
|
|
; return TRUE;
|
|
; }
|
|
;
|
|
LabelFP <PUBLIC, IsVisible>
|
|
pop ax
|
|
pop dx
|
|
pop cx ; cx = fClient
|
|
pop bx ; bx = hwnd
|
|
push dx
|
|
push ax
|
|
|
|
mov dx,bx ; hwnd = dx, bx = hwndT
|
|
xor ax,ax ; assume FALSE return
|
|
jmps iv100 ; fall into loop...
|
|
ivloop:
|
|
mov bx,[bx].wndPwndParent ; hwndChild = hwndChild->hwndParent
|
|
iv100:
|
|
or bx,bx
|
|
jz ivtrue ; Reached the top: return TRUE
|
|
|
|
TSTWF bx,WFVISIBLE ; if not visible, get out of here.
|
|
jz ivfalse
|
|
|
|
TSTWF bx,WFMINIMIZED ; if not minimized, keep looping
|
|
jz ivloop
|
|
|
|
cmp bx,dx ; if (hwnd != hwndT)
|
|
jnz ivfalse ; return FALSE
|
|
|
|
jcxz ivloop ; if fClient == FALSE, keep going.
|
|
|
|
mov bx,[bx].wndPcls
|
|
mov bx,[bx].uclshIcon
|
|
or bx,bx
|
|
jnz ivfalse
|
|
mov bx,dx ; resume enumeration at bx
|
|
jmps ivloop ; keep looping...
|
|
ivtrue:
|
|
inc al ; ax = TRUE
|
|
ivfalse:
|
|
retf
|
|
|
|
;*--------------------------------------------------------------------------*
|
|
;* *
|
|
;* GetMenu() - *
|
|
;* *
|
|
;*--------------------------------------------------------------------------*
|
|
|
|
cProc GetMenu, <FAR, PUBLIC>,<si>
|
|
|
|
ParmW hwnd
|
|
|
|
cBegin
|
|
mov si,hwnd
|
|
CheckHwnd si
|
|
jz gmexit
|
|
mov ax,[si].wndhMenu
|
|
gmexit:
|
|
|
|
cEnd
|
|
endif ;WOW
|
|
|
|
;*--------------------------------------------------------------------------*
|
|
;* *
|
|
;* SwapHandle() - *
|
|
;* *
|
|
;*--------------------------------------------------------------------------*
|
|
|
|
; Takes a far pointer to a word on the stack and converts it from a handle
|
|
; into a segment address or vice-versa. Note that this function is a NO OP
|
|
; in protect mode.
|
|
|
|
ifndef PMODE
|
|
cProc SwapHandle, <PUBLIC, FAR, NODATA, ATOMIC>
|
|
|
|
ParmD lpHandle
|
|
|
|
cBegin
|
|
ifndef WOW
|
|
mov ax,__WinFlags
|
|
test ax,1
|
|
jnz sh200 ; SwapHandle is a no op in pmode.
|
|
endif
|
|
; Save the parameter.
|
|
mov bx,off_lpHandle
|
|
push bx
|
|
|
|
; Get the handle/segment
|
|
mov ax,word ptr ss:[bx]+2
|
|
push ax ; Save it
|
|
|
|
; Call GlobalHandleNorip which puts the proper handle in AX
|
|
; and the corresponding segment address in DX.
|
|
push ax
|
|
call GlobalHandleNorip
|
|
|
|
; Restore the original word.
|
|
pop bx
|
|
|
|
; If DX==CS then we know we've converted a handle into a segment.
|
|
; This prevents problems with the FFFE segment.
|
|
mov cx,cs
|
|
cmp dx,cx
|
|
je sh50
|
|
|
|
; Was the original word a segment address?
|
|
test bl,1
|
|
jnz sh100 ; Yes, AX = handle, DX = segment
|
|
|
|
sh50: xchg ax,dx ; Nope, AX = segment, DX = handle
|
|
|
|
; Restore the pointer to the original word.
|
|
sh100: pop bx
|
|
|
|
; Skip if zero.
|
|
or ax,ax
|
|
jz sh200
|
|
|
|
; Move the result into the original word pointed to.
|
|
mov word ptr ss:[bx]+2,ax
|
|
sh200:
|
|
cEnd
|
|
endif ;PMODE
|
|
|
|
ifndef WOW
|
|
;*--------------------------------------------------------------------------*
|
|
;* *
|
|
;* SwapMouseButton() - *
|
|
;* *
|
|
;*--------------------------------------------------------------------------*
|
|
|
|
; BOOL SwapMouseButton(fSwap)
|
|
; BOOL fSwap;
|
|
|
|
LabelFP <PUBLIC, SwapMouseButton>
|
|
mov ax,_INTDS
|
|
mov es,ax
|
|
assumes es,INTDS
|
|
mov ax,es:fSwapButtons ; Return fSwapButtons' old value
|
|
pop cx ; Pop off the FAR return
|
|
pop dx
|
|
pop es:[fSwapButtons] ; fSwapButtons = fSwap
|
|
|
|
mov bx,es:[fSwapButtons]
|
|
assumes es,NOTHING
|
|
|
|
mov es,WORD PTR cs:[cstods] ; Get user's ds
|
|
assumes es,DATA
|
|
mov es:[rgwSysMet+SM_SWAPBUTTON*2],bx
|
|
assumes es,NOTHING
|
|
|
|
push dx ; Restore the FAR return
|
|
push cx
|
|
retf
|
|
assumes es,NOTHING
|
|
|
|
endif; Not WOW
|
|
|
|
|
|
;*--------------------------------------------------------------------------*
|
|
;* *
|
|
;* SetDivZero() - *
|
|
;* *
|
|
;*--------------------------------------------------------------------------*
|
|
|
|
LabelFP <PUBLIC, SetDivZero>
|
|
push ds
|
|
push cs ; Set DS == CS
|
|
pop ds
|
|
ifndef userhimem
|
|
mov dx,Offset DivideByZero
|
|
else
|
|
push ds
|
|
mov ax, _INTDS
|
|
mov ds,ax
|
|
assumes ds,INTDS
|
|
mov ax,fffedelta
|
|
pop ds
|
|
assumes ds,DATA
|
|
add ax,Offset DivideByZero
|
|
mov dx,ax
|
|
endif
|
|
sdzvector:
|
|
mov ax,2500h ; Use DOS to set interrupt zero
|
|
int 21h
|
|
pop ds
|
|
retf
|
|
|
|
|
|
|
|
;*--------------------------------------------------------------------------*
|
|
;* *
|
|
;* DivideByZero() - *
|
|
;* *
|
|
;*--------------------------------------------------------------------------*
|
|
|
|
LabelFP <PUBLIC, DivideByZero>
|
|
FSTI
|
|
ifdef DEBUG
|
|
pusha
|
|
push es
|
|
endif
|
|
|
|
; Put up the system modal message box.
|
|
mov cx,_INTDS
|
|
ifdef WOW
|
|
; Put up the SysErrorBox Directly
|
|
push cx
|
|
lea ax,szDivZero
|
|
push ax
|
|
|
|
push cx
|
|
lea ax,szSysError
|
|
push ax
|
|
|
|
ifdef DEBUGlater
|
|
|
|
push SEB_CLOSE
|
|
push 0
|
|
push SEB_CANCEL
|
|
call SysErrorBox
|
|
cmp ax,SEB_BTN1
|
|
jz DBZ_Terminate
|
|
|
|
pop es
|
|
popa
|
|
DebugErr DBF_FATAL, "Divide by zero or divide overflow error: break and trace till IRET"
|
|
iret
|
|
|
|
DBZ_Terminate:
|
|
pop es
|
|
popa
|
|
else ; FREE Build
|
|
push 0 ; no button 1
|
|
push SEB_CLOSE ; only allow close
|
|
push 0 ; no button 3
|
|
call SysErrorBox
|
|
endif; FREE Build
|
|
mov ax,4C00h ; Abort the task with a 0
|
|
int 21h
|
|
|
|
else; Not WOW
|
|
xor ax,ax
|
|
push ax ; NULL hwnd
|
|
lea ax,szDivZero
|
|
push cx
|
|
push ax ; Message Text
|
|
lea ax,szSysError
|
|
push cx
|
|
push ax ; Caption Text
|
|
ifdef DEBUG
|
|
mov ax,MB_SYSTEMMODAL OR MB_ICONHAND OR MB_OKCANCEL
|
|
else
|
|
mov ax,MB_SYSTEMMODAL OR MB_ICONHAND
|
|
endif
|
|
push ax
|
|
call MessageBox
|
|
ifdef DEBUG
|
|
cmp ax,1 ; If OK Button clicked, terminate app
|
|
jz DBZ_Terminate
|
|
|
|
pop es
|
|
popa
|
|
DebugErr DBF_FATAL, "Divide by zero or divide overflow error: break and trace till IRET"
|
|
iret
|
|
|
|
DBZ_Terminate:
|
|
pop es
|
|
popa
|
|
endif
|
|
endif; Not WOW
|
|
mov ax,4C00h ; Abort the task with a 0
|
|
int 21h
|
|
|
|
ifndef WOW
|
|
|
|
;-------------------------------------------------------------------------
|
|
;
|
|
; word FAR PASCAL GetUserLocalObjType(pObj)
|
|
; Given a near pointer to an object in USER's local heap, this function
|
|
; determines the type of the object and returns it;
|
|
; It finds out if the given object is a non-tagged belonging to the atom
|
|
; table; If not, it looks at the tag and returns the object type.
|
|
;
|
|
; WARNING: Because this function determines the type of the object by
|
|
; the process of elimination, the results will be unpredictable if the
|
|
; input in incorrect. i.e., no validation is done on the input value;
|
|
; To validate if the input value is indeed an object in USER's heap would
|
|
; warant a walk down the heap; This will be very costly, if done for
|
|
; every call; Apps like HeapWalker are expected to walk down the USER's
|
|
; local heap and make calls to this function for every object thay come
|
|
; accross; So, a validation done here is duplication of effort and affect
|
|
; the performance unnecessarily
|
|
;
|
|
;
|
|
;-------------------------------------------------------------------------
|
|
|
|
ifndef DEBUG
|
|
; The following is in the RETAIL version of USER
|
|
LabelFP <PUBLIC, GetUserLocalObjType>
|
|
xor ax, ax ; Return Unknown struct type
|
|
retf 2 ; Compensate for the WORD parameter
|
|
else
|
|
; The following is in the DEBUG version of USER
|
|
|
|
cProc GetUserLocalObjType, <PUBLIC, FAR>, <si, di>
|
|
|
|
ParmW pObj ; Near pointer to an OBJ in USER's heap
|
|
|
|
cBegin
|
|
; Now DS register is pointing to USER's DS
|
|
;
|
|
; Check if the object is a moveable object
|
|
mov bx, pObj
|
|
mov ax, [bx].la_prev
|
|
test ax, 01 ; is it a free object
|
|
jz FoundFreeObj
|
|
test ax, 02 ; Is it a moveable object
|
|
jz FoundFixedObj
|
|
; Now, it is a moveable obj; So, we have the tags
|
|
mov al, byte ptr [bx + SIZE LocalArena]
|
|
xor ah, ah
|
|
jmps FoundObjType
|
|
|
|
FoundFreeObj:
|
|
mov ax, ST_FREE
|
|
jmps FoundObjType
|
|
|
|
FoundFixedObj:
|
|
; Assume that the object belongs to atom table
|
|
mov ax, ST_ATOMS
|
|
|
|
; Check if this object is the atom table itself
|
|
add bx, SIZE LocalArena - 2
|
|
cmp bx, ds:[8] ; pAtomTable is at this offset.
|
|
je FoundObjType
|
|
|
|
; Check if this is possibly an atom string. If so, the first word
|
|
; stored in this object is a ptr to the next string or NULL;
|
|
; Check if the last two bits are zero; If they are not zero, then
|
|
; this can not be an atom; If they are zero, this may or may not be
|
|
; an atom;
|
|
|
|
mov cx, [bx]
|
|
and cx, 03h
|
|
jnz NotAnAtom
|
|
|
|
; Now walk down the atom table and check each entry against the
|
|
; given object
|
|
|
|
mov dx, bx ; save the near pointer to the object
|
|
mov bx, ds:[8] ; Get the pointer to the atom table pAtomTable
|
|
mov cx, [bx].at_prime ; Get the number of entries
|
|
; Skip to the first entry in the atom table
|
|
errnz <at_hashtable - 2>
|
|
AtomLoop2:
|
|
errnz <SIZE at_hashtable - 2>
|
|
add bx, 2 ;
|
|
errnz <a_chain>
|
|
mov si, [bx] ; Pointer to the next string
|
|
AtomLoop:
|
|
or si, si
|
|
jz NextBucket ; Goto NextBucket
|
|
|
|
;Check the new atom matches the given object
|
|
cmp si, dx
|
|
jz FoundObjType ; AX already has ST_ATOMS in it
|
|
mov si, [si].a_chain
|
|
jmps AtomLoop
|
|
|
|
NextBucket:
|
|
loop AtomLoop2
|
|
mov bx, dx ; Make bx point to the first byte of the object
|
|
|
|
NotAnAtom:
|
|
; bx points to the tag byte of the object
|
|
xor ah, ah
|
|
mov al, byte ptr [bx]
|
|
FoundObjType:
|
|
; ax already contains the proper return value
|
|
cEnd
|
|
endif
|
|
|
|
endif ;WOW
|
|
|
|
|
|
;*--------------------------------------------------------------------------*
|
|
;* *
|
|
;* mouse_event() - *
|
|
;* *
|
|
;*--------------------------------------------------------------------------*
|
|
|
|
; Mouse interrupt event routine
|
|
;
|
|
; Entry: (ax) = flags:
|
|
; 01h = mouse move
|
|
; 02h = left button down
|
|
; 04h = left button up
|
|
; 08h = right button down
|
|
; 10h = right button up
|
|
; 20h = middle button down
|
|
; 40h = middle button up
|
|
; 8000h = absolute move
|
|
; (bx) = dX
|
|
; (cx) = dY
|
|
; (dx) = # of buttons, which is assumed to be 2.
|
|
; (si) = extra info loword (should be null if none)
|
|
; (di) = extra info hiword (should be null if none)
|
|
;
|
|
; Exit: None
|
|
;
|
|
; Uses: All registers
|
|
;
|
|
|
|
ExternFP <MouseEvent> ; Thunk in user4.asm
|
|
|
|
LabelFP <PUBLIC, mouse_event>
|
|
push si ; Preserve the same regs as Win3.1
|
|
regptr disi,di,si
|
|
cCall <FAR PTR MouseEvent>, <ax,bx,cx,dx,disi>
|
|
pop si
|
|
retf
|
|
|
|
LabelFP <PUBLIC, GetMouseEventProc>
|
|
mov dx,cs
|
|
mov ax,offset mouse_event
|
|
retf
|
|
|
|
|
|
;*--------------------------------------------------------------------------*
|
|
;* *
|
|
;* keybd_event() - *
|
|
;* *
|
|
;*--------------------------------------------------------------------------*
|
|
|
|
; Keyboard interrupt handler.
|
|
;
|
|
; ENTRY: AL = Virtual Key Code, AH = 80 (up), 00 (down)
|
|
; BL = Scan Code
|
|
; BH = 0th bit is set if it is an enhanced key(Additional return etc.,).
|
|
; SI = LOWORD of ExtraInfo for the message
|
|
; DI = HIWORD of ExtraInfo for the message
|
|
;
|
|
; NOTES: This routine must preserve all registers.
|
|
|
|
ExternFP <KeybdEvent> ; Thunk in user4.asm
|
|
|
|
LabelFP <PUBLIC, keybd_event>
|
|
push es ; Preserve the registers
|
|
push dx
|
|
push cx
|
|
push bx
|
|
push ax
|
|
regptr disi,di,si
|
|
cCall <FAR PTR KeybdEvent>, <ax,bx,disi>
|
|
pop ax
|
|
pop bx
|
|
pop cx
|
|
pop dx
|
|
pop es
|
|
retf
|
|
|
|
sEnd %SEGNAME
|
|
|
|
end
|