Window drag issues using: WM_LBUTTONDOWN & KeyWait Topic is solved

Get help with using AutoHotkey and its commands and hotkeys
padanges
Posts: 17
Joined: 15 Jul 2019, 06:59

Window drag issues using: WM_LBUTTONDOWN & KeyWait

31 Jul 2020, 10:18

Hello, I'm have a simple script which should drag a window once LButton is held down over the window.
The primary issue is that the window reacts only to every second (skips odd) click (&drag). I can't seem to pin down the problem - my only guess is that Hotkey,On/KeyWait lines somehow interrupt WM_LBUTTONDOWN. The secondary issue - it skips double-clicks in the same manner.
Could someone please give me a hint as to what causes this, and can this be resolved?
Thanks in advance.

Code: Select all

#SingleInstance Force
Gui newWnd:New
Gui newWnd: -ToolWindow -SysMenu -Caption -Theme -Resize +AlwaysOnTop
Gui newWnd: Color, FFFFFF
rectCoordStr := % "x" . 100 . " y" . 100 . " w" . 100 . " h" . 100
Gui newWnd:Show, %rectCoordStr% NoActivate, TEST: CLICK&DRAG ME
OnMessage(0x203, "WM_LBUTTONDBLCLK")	;; window message for the mouse left double-click
OnMessage(0x201, "WM_LBUTTONDOWN")		;; window message for the mouse left click
Return

WM_LBUTTONDBLCLK()
{
	MsgBox reserved for other functions
}

WM_LBUTTONDOWN()
{
	Hotkey LButton, _WhileHolding, On ;; hotkey for mouse button hold-down
}

_WhileHolding:
	CoordMode Mouse, Screen ;; set coordinates relative to the screen
	MouseGetPos x1, y1, actWndId
	WinGetPos actWndULx, actWndULy, , , ahk_id %actWndId%
	x1 := x1 - actWndULx, y1 := y1 - actWndULy
	
	SetTimer _MoveWindow, 15
	KeyWait LButton ;; wait for LButton release
	
	SetTimer _MoveWindow, Off
	Hotkey LButton, _WhileHolding, Off
Return

_MoveWindow:
	CoordMode Mouse, Screen ;; set coordinates relative to the screen
	MouseGetPos x2, y2
	WinMove ahk_id %actWndId%, , (x2 - x1), (y2 - y1)
Return

ESC::
	ExitApp
Return

User avatar
boiler
Posts: 5604
Joined: 21 Dec 2014, 02:44

Re: Window drag issues using: WM_LBUTTONDOWN & KeyWait  Topic is solved

31 Jul 2020, 12:20

Here's an easier way to accomplish that:

Code: Select all

#SingleInstance Force
Gui newWnd:New
Gui newWnd: -ToolWindow -SysMenu -Caption -Theme -Resize +AlwaysOnTop
Gui newWnd: Color, FFFFFF
rectCoordStr := % "x" . 100 . " y" . 100 . " w" . 100 . " h" . 100
Gui newWnd:Show, %rectCoordStr% NoActivate, TEST: CLICK&DRAG ME
OnMessage(0x203, "WM_LBUTTONDBLCLK")	;; window message for the mouse left double-click
OnMessage(0x201, "WM_LBUTTONDOWN")		;; window message for the mouse left click
Return

WM_LBUTTONDOWN() {
	PostMessage, 0xA1, 2 ; WM_NCLBUTTONDOWN = 0xA1, HTCAPTION = 2
}

WM_LBUTTONDBLCLK()
{
	MsgBox reserved for other functions
}

ESC::
	ExitApp
Return
padanges
Posts: 17
Joined: 15 Jul 2019, 06:59

Re: Window drag issues using: WM_LBUTTONDOWN & KeyWait

31 Jul 2020, 13:56

Thank you boiler - what a fine trick :)
The task has been solved, but as I have such code constructions (with hotkeys, keywait, timers and messages) used in my other scripts, I prefer to unravel this problem because it's likely I'll encounter it later again -- I'm still puzzled why every second click is being ignored :shock:
I like the solution, but I still would appreciate if some other members could share any ideas about this matter.

I'm posting some info I've gathered about the solution:
WM_NCLBUTTONDOWN (0xA1) is the message posted by LButton when it is pressed down on a window Titlebar -- activates (native) window dragging
https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-nclbuttondown
https://autohotkey.com/board/topic/80594-how-to-enable-drag-for-a-gui-without-a-titlebar/
https://stackoverflow.com/questions/8781862/what-does-wm-nclbuttondown-do
padanges
Posts: 17
Joined: 15 Jul 2019, 06:59

Re: Window drag issues using: WM_LBUTTONDOWN & KeyWait

02 Aug 2020, 03:28

After trying out various combinations I came to conclusion that OnMessage() with, for example, WM_LBUTTONDOWN or WM_LBUTTONDBLCLK, "steals" a click and resends it back, because:
1) every mouse right d-click on a window, which closes that window, is sent further, that is, once the window (above the desktop) is closed, the right click menu pops up on the desktop, even if unwanted; using something like this:

Code: Select all

WM_RBUTTONDBLCLK()
{
	Gui %A_Gui%:Destroy
	;; how to suppress btn d-click sending down once the gui is closed?
}
2) it's not possible to create a Hotkey in a received message event and have this hotkey activated on the first (when message is being receive) click, like this:

Code: Select all

WM_LBUTTONDOWN()
{
	Hotkey LButton, _WhileDragging, On ;; hotkey for mouse button hold-down
	;; even additional line "SendInput {LButton down}" does not help here
}

_WhileDragging:
	KeyWait LButton ;; wait for LButton release
	MsgBox LButton is up now
	Hotkey LButton, _WhileDragging, Off
Return
Full test case (for the click&drag):

Code: Select all

#SingleInstance Force
Gui newWnd:New
Gui newWnd: -ToolWindow -SysMenu -Caption -Theme -Resize +AlwaysOnTop
Gui newWnd: Color, FFFFFF
rectCoordStr := % "x" . 100 . " y" . 100 . " w" . 100 . " h" . 100
Gui newWnd:Show, %rectCoordStr% NoActivate, TEST: CLICK&DRAG ME
OnMessage(0x203, "WM_LBUTTONDBLCLK")	;; window message for the mouse left double-click
OnMessage(0x201, "WM_LBUTTONDOWN")		;; window message for the mouse left click
Return

WM_LBUTTONDBLCLK()
{
	MsgBox reserved for other functions
}

WM_LBUTTONDOWN()
{
	Hotkey LButton, _WhileDragging, On ;; hotkey for mouse button hold-down
	;; even additional line "SendInput {LButton down}" does not help here
}

_WhileDragging:
	KeyWait LButton ;; wait for LButton release
	MsgBox LButton is up now
	Hotkey LButton, _WhileDragging, Off
Return


ESC::
	ExitApp
Return
Could anyone, please, clarify this matter a bit further? Am I right?
User avatar
boiler
Posts: 5604
Joined: 21 Dec 2014, 02:44

Re: Window drag issues using: WM_LBUTTONDOWN & KeyWait

02 Aug 2020, 06:07

padanges wrote: After trying out various combinations I came to conclusion that OnMessage() with, for example, WM_LBUTTONDOWN or WM_LBUTTONDBLCLK, "steals" a click and resends it back
I don't know the answer to this one, but I wouldn't have guessed that it re-sends the click back. I would have just said it just acts on the message and doesn't steal the click.

padanges wrote: it's not possible to create a Hotkey in a received message event and have this hotkey activated on the first (when message is being receive) click
There is no reason I would think this would have been possible since the click event already occurred (and I don't think the click is being re-sent). It would be possible for the function to create a hotkey to capture a button release since that wouldn't have happened yet if the button were held sufficiently long, as demonstrated here:

Code: Select all

Gui, Add, Text,, Release mouse button for message
Gui, Show, w200 h150
OnMessage(0x201, "WM_LBUTTONDOWN")
return

WM_LBUTTONDOWN() {
	Hotkey, LButton up, Message, On
}

Message:
	Send, {LButton up}
	Hotkey, LButton up,, Off
	MsgBox, Mouse button has been released
return
padanges
Posts: 17
Joined: 15 Jul 2019, 06:59

Re: Window drag issues using: WM_LBUTTONDOWN & KeyWait

02 Aug 2020, 12:41

Perhaps I should paraphrase "steals and resends": receives a message but does not stop the click itself?
The idea about "resending" came from a situation like this:

Code: Select all

Gui, Add, Text,, Right-click me
Gui, Show, w200 h150
OnMessage(0x204, "WM_RBUTTONDOWN")
Return

WM_RBUTTONDOWN() {
	Gui Destroy
}
In such situation the right click gets sent after the gui is destroy to the window below (for example, over the Desktop, we get an "additional" right-click menu) -- the click event has occurred and the button down was still active. Here we see that the click event has not stopped the click itself.

There's one more question: if OnMessage() captures the click event that already occurred then why on this event it's not possible to send a click input?

Code: Select all

#SingleInstance Force
Global clickCt := 0
Gui, Add, Text,, Release mouse button for message
Gui, Show, w200 h150
OnMessage(0x201, "WM_LBUTTONDOWN")
Return

WM_LBUTTONDOWN() {
	Tooltip % ++clickCt
	Hotkey LButton, Message, On
	Send {LButton} ;; should activate previously set Hotkey? it doesn't.
}

Message:
	KeyWait LButton
	Hotkey, LButton, Message, Off
	MsgBox, Mouse button has been released
Return

ESC::ExitApp
On the other hand, we see here that the click event has stopped the click itself. :wtf:

Anyway, your sample clears things a bit up. Thank you.
User avatar
boiler
Posts: 5604
Joined: 21 Dec 2014, 02:44

Re: Window drag issues using: WM_LBUTTONDOWN & KeyWait

02 Aug 2020, 12:52

padanges wrote:
02 Aug 2020, 12:41
if OnMessage() captures the click event that already occurred then why on this event it's not possible to send a click input?
It has nothing to do with OnMessage(). Virtual mouse clicks never trigger hotkeys as other keys do. Using $ as a hotkey modifier prevents sending keyboard key strokes from triggering hotkeys, but it is not needed for mouse clicks because they don't trigger hotkeys, as described in the hotkey documentation on modifier symbols. This following script demonstrates it. You cannot trigger the MsgBox by pressing the F1 key.

Code: Select all

F1::Send, {LButton}

LButton::MsgBox, Hello

Esc::ExitApp
padanges
Posts: 17
Joined: 15 Jul 2019, 06:59

Re: Window drag issues using: WM_LBUTTONDOWN & KeyWait

02 Aug 2020, 14:48

Thanks boiler for the idea about the hotkey modifiers and input levels. Here's your code updated, where you can trigger the MsgBox by pressing the F1 key.

Code: Select all

LButton::MsgBox, Hello

#InputLevel 1
F1::Send, {LButton}

Esc::ExitApp
Now regarding my original question - I'm still convinced that it's all about OnMessage() messing with clicks. Since I can send mouse button hotkey triggers, I also should be able to change their states, for example, to set {LButton down} for KeyWait LButton to wait for, but - that's not what happens,- it seems that OnMessage() somehow modifies LButton state when gets the message WM_LBUTTONDOWN(). Here's the code:

Code: Select all

#SingleInstance Force
Gui, Add, Text,, Release mouse button for message
Gui, Show, w200 h150
OnMessage(0x201, "WM_LBUTTONDOWN")
Return

WM_LBUTTONDOWN() {
	Hotkey LButton, Message, On	;; InputLevel 0
	SendLevel 1					;; InputLevel 1
	Send {Blind}{LButton down}
	;; should send button DOWN for KeyWait to wait for, but...
}

Message:
	KeyWait LButton
	Hotkey, LButton, Message, Off
	MsgBox, Mouse button has been released
Return

ESC::ExitApp

padanges
Posts: 17
Joined: 15 Jul 2019, 06:59

Re: Window drag issues using: WM_LBUTTONDOWN & KeyWait

04 Aug 2020, 05:13

The first answer by boiler is of most help in current situation. So I'm marking this topic as Solved and posting a simplified question as another topic.
padanges
Posts: 17
Joined: 15 Jul 2019, 06:59

Re: Window drag issues using: WM_LBUTTONDOWN & KeyWait

07 Aug 2020, 05:00

I've finally managed to find out how to move a window, without using a "PostMessage, 0xA1, 2" trick. The answer is simple... here's the final code:

Code: Select all

#SingleInstance Force
Gui newWnd:New
Gui newWnd: -ToolWindow -SysMenu -Caption -Theme -Resize +AlwaysOnTop
Gui newWnd: Color, FFFFFF
rectCoordStr := % "x" . 100 . " y" . 100 . " w" . 100 . " h" . 100
Gui newWnd:Show, %rectCoordStr% NoActivate, TEST: CLICK&DRAG ME
OnMessage(0x203, "WM_LBUTTONDBLCLK")	;; window message for the mouse left double-click
OnMessage(0x201, "WM_LBUTTONDOWN")		;; window message for the mouse left click
Return

WM_LBUTTONDBLCLK()
{
	MsgBox reserved for other functions
}

WM_LBUTTONDOWN()
{
	GoSub _WhileHolding
}

_WhileHolding:
	CoordMode Mouse, Screen ;; set coordinates relative to the screen
	MouseGetPos x1, y1, actWndId
	WinGetPos actWndULx, actWndULy, , , ahk_id %actWndId%
	x1 := x1 - actWndULx, y1 := y1 - actWndULy
	
	SetTimer _MoveWindow, 15
	KeyWait LButton ;; wait for LButton release
	
	SetTimer _MoveWindow, Off
	Hotkey LButton, _WhileHolding, Off
Return

_MoveWindow:
	CoordMode Mouse, Screen ;; set coordinates relative to the screen
	MouseGetPos x2, y2
	WinMove ahk_id %actWndId%, , (x2 - x1), (y2 - y1)
Return

ESC::
	ExitApp
Return
But I still have no idea why you must use GoSub. Apparently "WM_LBUTTONDOWN()" and "KeyWait LButton" just can't be combined together.
User avatar
boiler
Posts: 5604
Joined: 21 Dec 2014, 02:44

Re: Window drag issues using: WM_LBUTTONDOWN & KeyWait

07 Aug 2020, 06:53

padanges wrote:
07 Aug 2020, 05:00
But I still have no idea why you must use GoSub. Apparently "WM_LBUTTONDOWN()" and "KeyWait LButton" just can't be combined together.
No, that’s not it. You don’t have to use Gosub, and KeyWait LButton can be in the WM_LBUTTONDOWN() function. You probably just didn’t account for the scope of the variables in the function that are used by _MoveWindow. This works:

Code: Select all

#SingleInstance Force
Gui newWnd:New
Gui newWnd: -ToolWindow -SysMenu -Caption -Theme -Resize +AlwaysOnTop
Gui newWnd: Color, FFFFFF
rectCoordStr := % "x" . 100 . " y" . 100 . " w" . 100 . " h" . 100
Gui newWnd:Show, %rectCoordStr% NoActivate, TEST: CLICK&DRAG ME
OnMessage(0x203, "WM_LBUTTONDBLCLK")	;; window message for the mouse left double-click
OnMessage(0x201, "WM_LBUTTONDOWN")		;; window message for the mouse left click
Return

WM_LBUTTONDBLCLK()
{
	MsgBox reserved for other functions
}

WM_LBUTTONDOWN()
{
	global actWndId, x1, y1
	CoordMode Mouse, Screen ;; set coordinates relative to the screen
	MouseGetPos x1, y1, actWndId
	WinGetPos actWndULx, actWndULy, , , ahk_id %actWndId%
	x1 := x1 - actWndULx, y1 := y1 - actWndULy
	
	SetTimer _MoveWindow, 15
	KeyWait LButton ;; wait for LButton release
	
	SetTimer _MoveWindow, Off
}

_MoveWindow:
	CoordMode Mouse, Screen ;; set coordinates relative to the screen
	MouseGetPos x2, y2
	WinMove ahk_id %actWndId%, , (x2 - x1), (y2 - y1)
Return

ESC::
	ExitApp
Return
padanges
Posts: 17
Joined: 15 Jul 2019, 06:59

Re: Window drag issues using: WM_LBUTTONDOWN & KeyWait

07 Aug 2020, 12:03

You're right! :D thank you boiler - the mystery has been solved

Return to “Ask For Help”

Who is online

Users browsing this forum: Google [Bot], hd0202 and 45 guests