Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Wait for Mouse Movement OR Key/MB Up/Down?
#1
Hi Gintaras,
I have several functions where I want to detect if user has moved or has clicked a button - either action will break the "wait state" and trigger different actions.
Is there a wait to test for either.... I think I can figure it out using rep and testing for mouse movement and ifk, but thought there may be a more elegant way.
thanks!!!!
Stuart
#2
GetLastInputInfo - also detects keyboard.
Low level mouse hook - probably isn't more elegant.
Don't know more ways.
#3
With hook.

Function WaitForMouseAction
Code:
Copy      Help
;/
function [^waitMaxS]

;Waits for mouse movement or click or wheel.

;waitMaxS - max number of seconds to wait. Default or 0 is infinite. Error on timeout.


int- __wfma_hook
__wfma_hook=SetWindowsHookEx(WH_MOUSE_LL &__WFMA_MouseProc _hinst 0)
opt waitmsg 1
wait waitMaxS -V __wfma_hook
err
,UnhookWindowsHookEx __wfma_hook
,end _error

Function __WFMA_MouseProc
Code:
Copy      Help
;/
function nCode wParam MSLLHOOKSTRUCT*h

int- __wfma_hook
int r=CallNextHookEx(__wfma_hook nCode wParam h)

UnhookWindowsHookEx __wfma_hook
__wfma_hook=0
ret r
#4
Hi Gintaras, Thanks so much for writing these functions. I said I was looking to wait for user "click button or moved mouse" but I forgot to mention that the button click on my mouse is mapped to a keyboard mapping - i.e. not RMB or LMB or wheel but actually something like 'Aq (.... ifk(Aq), etc).


I don't quite understand the hook structure in your example so I wasn't able to modify it to my needs. I will try again later. I also couldn't find the GetLastInputInfo function in QM though it is referenced elsewhere in the forum...ideally, it would be cool to have a wait statement that could be ended by key UP or Down, mouse click UP or DOWN or mouse movement. Extra amazing if it could return which action tripped it (i.e. which key clicked, etc). Not sure what would be return data on mouse movement other than that mouse movement was the trigger.....

This seems like it would be a big thing to write but any help on understanding GetLastInputInfo would help me get a long way there....
Thanks so much!!!!!

Stuart
#5
GetLastInputInfo is very simple function. It is not QM function. Use Google to find about it. It just gives last input time, and used to detect idle condition. QM function that uses it - ResumeWhenIdle - is in Archive.qml (Forum -> Resources -> first topic).

For what you need, need to also add keyboard hook. Very similar to mouse hook. Hooks also are not QM functions, use Google to find about.
#6
Function WaitForKeyOrMouse
Code:
Copy      Help
;/
function# [^waitMaxS] [KBDLLHOOKSTRUCT&ks] [MSLLHOOKSTRUCT&ms]

;Waits for a key or mouse movement or click or wheel.

;Returns:
;;;on key: virtual key code (value 1-255). The table is in QM help. To get more info, eg key down or up, use ks.
;;;on mouse action: mouse message (WM_MOUSEMOVE etc, value 512-526). Documented in MSDN library. To get more info, use ms.

;waitMaxS - max number of seconds to wait. Default or 0 is infinite. Error on timeout.
;ks - if used, receives last keyboard event info. Documented in MSDN library.
;ms - if used, receives last mouse event info. Documented in MSDN library.

;This function does not work well if this process uses direct input or raw input or keyboard detector.


type WFKMDATA hkey hmouse w r KBDLLHOOKSTRUCT*ks MSLLHOOKSTRUCT*ms
WFKMDATA- __wfkm
__wfkm.w=0
__wfkm.r=0
__wfkm.ks=&ks
__wfkm.ms=&ms
__wfkm.hkey=SetWindowsHookEx(WH_KEYBOARD_LL &__WFKM_KeyProc _hinst 0)
__wfkm.hmouse=SetWindowsHookEx(WH_MOUSE_LL &__WFKM_MouseProc _hinst 0)
opt waitmsg 1
int e
wait waitMaxS V __wfkm.w
err e=1
UnhookWindowsHookEx __wfkm.hkey
UnhookWindowsHookEx __wfkm.hmouse
if(e) end _error
ret __wfkm.r

Function __WFKM_KeyProc
Code:
Copy      Help
;/
function nCode wParam KBDLLHOOKSTRUCT*h

WFKMDATA- __wfkm
if(nCode!=HC_ACTION) goto gr

__wfkm.r=h.vkCode&255

sel __wfkm.r
,case [VK_LCONTROL,VK_RCONTROL] __wfkm.r=VK_CONTROL
,case [VK_LSHIFT,VK_RSHIFT] __wfkm.r=VK_SHIFT
,case [VK_LMENU,VK_RMENU] __wfkm.r=VK_MENU
,case VK_RWIN __wfkm.r=VK_LWIN

if(__wfkm.ks) *__wfkm.ks=*h
__wfkm.w=1
;gr
ret CallNextHookEx(__wfkm.hkey nCode wParam h)

Function __WFKM_MouseProc
Code:
Copy      Help
;/
function nCode wParam MSLLHOOKSTRUCT*h

WFKMDATA- __wfkm
if(nCode!=HC_ACTION) goto gr

__wfkm.r=wParam
if(__wfkm.ms) *__wfkm.ms=*h
__wfkm.w=1
;gr
ret CallNextHookEx(__wfkm.hmouse nCode wParam h)
#7
This is amazing but I don't think I know how to use it to its full potential. I can get out the return of the function as a keycode or mousebutton code but I don't know how to get the ks or ms info out. I have tried something like this:

Macro Macro23
Trigger C' 0x4     Help - how to add the trigger to the macro
Code:
Copy      Help
int h = WaitForKeyOrMouse(10)
out h

for the function value which works but when I try:

Macro Macro23
Trigger C' 0x4     Help - how to add the trigger to the macro
Code:
Copy      Help
KBDLLHOOKSTRUCT ks1
MSLLHOOKSTRUCT ms1
3.0
int h = WaitForKeyOrMouse(10)
out h

out &ks1
out &ms1

I keep on getting the same numbers for ks and ms 53673752 and 53673772. Not sure how to interpret them. I know I am screwing up something with the hookstructures but don't know how to figure it out.

Did find this on msdn but couldn't figure it out:
http://msdn.microsoft.com/en-us/library/ms645616(VS.85).aspx

Thanks for any help or simple code examples using this function (which I know will be awesome once I figure it out!!!)

Stuart
#8
Macro Macro1276
Code:
Copy      Help
KBDLLHOOKSTRUCT ks
MSLLHOOKSTRUCT ms
int k=WaitForKeyOrMouse(0 ks ms)
;out k
str what action
if(k<256) ;;key
,qm.FormatKeyString k 0 &what
,action=iif(ks.flags&LLKHF_UP "released" "pressed")
,
,out "key %s %s" what action
else ;;mouse
,sel k
,,case [WM_LBUTTONDOWN,WM_LBUTTONUP] what="left"
,,case [WM_RBUTTONDOWN,WM_RBUTTONUP] what="right"
,,case [WM_MBUTTONDOWN,WM_MBUTTONUP] what="middle"
,,case [WM_XBUTTONDOWN,WM_XBUTTONUP] sel(ms.mouseData>>16) case XBUTTON1 what="X1"; case XBUTTON2 what="X2"
,,case WM_MOUSEMOVE what="move"
,,case WM_MOUSEWHEEL what="wheel"; action=iif(ms.mouseData>>16&0x8000 "backward" "forward")
,sel k
,,case [WM_LBUTTONDOWN,WM_RBUTTONDOWN,WM_MBUTTONDOWN,WM_XBUTTONDOWN] action="pressed"
,,case [WM_LBUTTONUP,WM_RBUTTONUP,WM_MBUTTONUP,WM_XBUTTONUP] action="released"
,
,out "mouse %s %s at %i %i" what action ms.pt.x ms.pt.y
#9
Unbelievable......this is the "holy grail" anser to all my interface-gesturing issues!!! Plus, I think I understand hooks and how to deal with classes other than just simple str and int much better now!! Hopefully, I will be able to relate things from MSDN to my QM projects more easily now!!
Thanks so very much,
Stuart
#10
fantastic!!

thanks.
An old blog on QM coding and automation.

The Macro Hook
#11
Note use blockinput to eat the keyboard
Macro Macro
Code:
Copy      Help
BlockInput 1
An old blog on QM coding and automation.

The Macro Hook
#12
Hi Gintaras,

quick question about the amazing function above: what is the temporal resolution and/or what controls it.
What I am trying to do is create stream of what user is doing at the console all time for UI evaluation in my field: keyboard btn up/down, mouse click/press/drag, win/child controlID/acc from mouse-over or click/drag, mouse mileage/trace (hot spot), etc

Macro1276 with WaitForKeyOrMouse gives most of that (and easy for me to code other info).

Question is, is a wait statement best way to "open up the stream" so to speak - or is there a more general way to get all this low level keyboard, mouse hook info?

If indeed this is best way (good filter of idle time), then what controls the sampling rate e.g. for continuous mouse motion?

Would spe affect things?
Does the out statements slow the sampling down?
Would it be faster to write directly to console or file structure rather than QM output console?

Much appreciated all you do for QM and this help me understand it better!!!
Thanks so much!
S
#13
WaitForKeyOrMouse is to wait for a single event.
To receive keyboard and mouse events all the time, use hooks directly:

Macro keyboard_and_mouse_hooks
Code:
Copy      Help
int hkey=SetWindowsHookEx(WH_KEYBOARD_LL &sub.KeyProc _hinst 0)
int hmouse=SetWindowsHookEx(WH_MOUSE_LL &sub.MouseProc _hinst 0)
opt waitmsg 1
wait -1
UnhookWindowsHookEx hkey
UnhookWindowsHookEx hmouse


#sub KeyProc
function nCode wParam KBDLLHOOKSTRUCT*x

if(nCode!=HC_ACTION) goto gr

int k=x.vkCode&255
str what action

sel k
,case [VK_LCONTROL,VK_RCONTROL] k=VK_CONTROL
,case [VK_LSHIFT,VK_RSHIFT] k=VK_SHIFT
,case [VK_LMENU,VK_RMENU] k=VK_MENU
,case VK_RWIN k=VK_LWIN

qm.FormatKeyString k 0 &what
action=iif(x.flags&LLKHF_UP "released" "pressed")

out "key %s %s" what action

;gr
ret CallNextHookEx(0 nCode wParam x)


#sub MouseProc
function nCode wParam MSLLHOOKSTRUCT*x

if(nCode!=HC_ACTION) goto gr

int k=wParam
str what action

sel k
,case [WM_LBUTTONDOWN,WM_LBUTTONUP] what="left"
,case [WM_RBUTTONDOWN,WM_RBUTTONUP] what="right"
,case [WM_MBUTTONDOWN,WM_MBUTTONUP] what="middle"
,case [WM_XBUTTONDOWN,WM_XBUTTONUP] sel(x.mouseData>>16) case XBUTTON1 what="X1"; case XBUTTON2 what="X2"
,case WM_MOUSEMOVE what="move"
,case WM_MOUSEWHEEL what="wheel"; action=iif(x.mouseData>>16&0x8000 "backward" "forward")
sel k
,case [WM_LBUTTONDOWN,WM_RBUTTONDOWN,WM_MBUTTONDOWN,WM_XBUTTONDOWN] action="pressed"
,case [WM_LBUTTONUP,WM_RBUTTONUP,WM_MBUTTONUP,WM_XBUTTONUP] action="released"

out "mouse %s %s at %i %i" what action x.pt.x x.pt.y

;gr
ret CallNextHookEx(0 nCode wParam x)
out uses some CPU, as well as other output methods, eg writing to a file.
#14
Yes, this is the kind of stream I was envisioning!
Perfect!

How does it feel to be a magical wizard, Jedi Master, and Santa Claus all rolled up into one person!

Thanks so much, as always!!!
S


Forum Jump:


Users browsing this thread: 1 Guest(s)