OnMessage from existing window

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
Cinemaster
Posts: 32
Joined: 01 Jun 2017, 09:05

OnMessage from existing window

30 Aug 2017, 21:24

I found this OnMessage function (https://www.autohotkey.com/docs/commands/OnMessage.htm) in the documentation, and it gives this example:

Code: Select all

; Example: The following is a working script that monitors mouse clicks in a GUI window.
; Related topic: GuiContextMenu

Gui, Add, Text,, Click anywhere in this window.
Gui, Add, Edit, w200 vMyEdit
Gui, Show
OnMessage(0x201, "WM_LBUTTONDOWN")
return

WM_LBUTTONDOWN(wParam, lParam)
{
    X := lParam & 0xFFFF
    Y := lParam >> 16
    if A_GuiControl
        Control := "`n(in control " . A_GuiControl . ")"
    ToolTip You left-clicked in Gui window #%A_Gui% at client coordinates %X%x%Y%.%Control%
}

GuiClose:
ExitApp
This script receives messages from the gui window it created. How do I receive messages from an existing window, like Chrome or Outlook?
Noesis
Posts: 301
Joined: 26 Apr 2014, 07:57

Re: OnMessage from existing window

30 Aug 2017, 22:17

It completely depends on the actual message you want to receive. It could be the same way, however that is unlikely, as it would have to be the type of message that is broadcast from Chrome or Outlook, and most messages are usually sent to a specific window.

For example, some system messages, like the one in your example (WM_LBUTTONDOWN) are sent by the system (windows) directly to the active window, so you won't be able to pick that particular one up with an external AHK script when the event happens in Chrome/Outlook (but you could use Hotkeys instead in this particular case). There are other messages which are broadcast system wide, so can be acted on with AHK despite the message not being sent to the script. Essentially it completely depends on the message you're interested in. There are methods to receive more messages than normal, like for example using a shell hook to receive system messages you wouldn't normally receive, but again, this is all dependent on what message you're actually interested in trying to receive. FYI, Odds are there is likely a better method to do whatever it is you want to do than trying to do it this way.
Cinemaster
Posts: 32
Joined: 01 Jun 2017, 09:05

Re: OnMessage from existing window

31 Aug 2017, 08:56

Thank you for the reply. The messages I want to receive are mouse movements. AHK can capture mouse clicks and button up/down, but not movements, even though it can control the mouse.

The actual window is the program Camtasia. I want to control mouse behavior within that window to automate some things and control mouse behavior to make it less likely for errors in where the mouse is clicked/moved.

I've investigated, but I haven't found a clean way to do this. I've tried some workarounds, but the behavior is a little wonky, making them unusable. Could I write, say, a C++ program that would capture those messages and send them to AHK, or is there no way to capture mouse movements in another program?
Noesis
Posts: 301
Joined: 26 Apr 2014, 07:57

Re: OnMessage from existing window

01 Sep 2017, 02:04

Since I don't really know what you've tried, I'll suggest a couple of ways you could do this.
You, could use the simpler but kind of clunkier method of using a timer to monitor mouse movements using mousegetpos, (which you may have already tried), or using messages, and the way I'd be more inclined to recommend, is by capturing raw input by using the WM_INPUT message. There is already an ahk library you can use to capture & learn how to capture WM_INPUT messages, called AHKHID.ahk. I recommend you do some searches for AHKHID posts and have look. Basic process is you have to register the script to receive the messages first and then you can capture WM_Input by using OnMessage. This does however mean you will be capturing relative mouse movements, not the pixel screen/window location, so you'll have to code accordingly.
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: OnMessage from existing window

01 Sep 2017, 02:25

I would use a mouse hook for this, here is an example for notepad.

Code: Select all

#Persistent
mh:=new mouseHook("h")
mh.hook()
; you can turn off the hook by calling: mh.unhook()
h(h,x,y){
	; the x and y parameters are in screen coords.
	mouseGetPos,x,y,wum
	if winexist("ahk_class Notepad ahk_id " wum)
		ToolTip, % "Mouse moved at " x " " y " in notepad"
}
class mouseHook{
	; User methods
	hook(){
		if !this.hHook												; WH_MOUSE_LL := 14									  hMod:=0	 dwThreadId:=0
			this.hHook:=DllCall("User32.dll\SetWindowsHookEx", "Int", 14, "Ptr", this.regCallBack:=RegisterCallback(this.LowLevelMouseProc,"",4, &this), "Uint", 0, "Uint", 0, "Ptr")
		return
	}
	unHook(){
		if this.hHook
			DllCall("User32.dll\UnhookWindowsHookEx", "Uint", this.hHook)
		return this.hHook:=""
	}
	; Internal methods.
	__new(callbackFunc){
		(this.callbackFunc:= isObject(callbackFunc)  ? callbackFunc : isFunc(callbackFunc) ? func(callbackFunc) : "")
		if !this.callbackFunc
			throw exception("invalid callbackFunc")
	}
	LowLevelMouseProc(args*) {  
		; (nCode, wParam, lParam)
		Critical
		this:=Object(A_EventInfo),nCode:=NumGet(args-A_PtrSize,"Int"), wParam:=NumGet(args+0,0,"Ptr"), lParam:=NumGet(args+0,A_PtrSize,"UPtr") 
		x:=NumGet(lParam+0,0,"Int"),y:=NumGet(lParam+0,4,"Int"),flags:=NumGet(lParam+0,12,"UInt")
		this.callbackFunc.Call(flags,x,y)
		
		return DllCall("User32.dll\CallNextHookEx","Uint",0, "Int", nCode,"Uptr", wParam,"Ptr",lParam)
	}
	__Delete(){  
		this.unHook()
		if this.regCallBack
			DllCall("GlobalFree", "Ptr", this.regCallBack)
		return 
	}
}
esc::exitapp
Also for rawinput, there is MouseDelta.

Cheers.
Noesis
Posts: 301
Joined: 26 Apr 2014, 07:57

Re: OnMessage from existing window

01 Sep 2017, 08:41

Cinemaster, Helgef's recommendation is the better choice IMO too, considering what you said you needed.
Cinemaster
Posts: 32
Joined: 01 Jun 2017, 09:05

Re: OnMessage from existing window

01 Sep 2017, 15:07

@Helgef,

Thank you very much, this is excellent! I had considered the mouse hook, but the documentation said it worked for mouse clicks/buttons, not moves. But it looks like you didn't even use it, but rather created your own hook through dll calls. I certainly didn't expect it to require as much as you've written. I tried it out and it works great! I don't understand what all the dll calls are doing, as it looks like that requires systems knowledge.

You should really post this code in the scripts/functions forum, as I'm sure others would find this very useful.

So, thank you both for the help, and especially your great code, Helgef!
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: OnMessage from existing window

01 Sep 2017, 15:50

Yes it is a custom hook, rather than ahk's built-in. Same underlying function though (I guess), that is, SetWindowsHookEx (msdn). There are plenty of hook implementations scattered around the forums, if you like it shorter, you can search. I like the class approach for automatic unhooking and memory freeing. Anyways, you might want to take measures to unhook at times you are not working with the specific application you are interested in. Example, although it might not be fit for your actual script,

Code: Select all

#Persistent
mh:=new mouseHook("h")
loop {
	winWaitActive ahk_class Notepad
	mh.hook()
	winWaitNotActive ahk_class Notepad
	mh.unhook()
}
; Rest of script ...
Cheers.

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Lamron750 and 257 guests