Disable a gui from resetting the the Y position to 0 when released Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
Hellbent
Posts: 2102
Joined: 23 Sep 2017, 13:34

Disable a gui from resetting the the Y position to 0 when released

21 Jun 2021, 07:44

Does anyone know of a simple method that will prevent a GUI from setting the Y position to 0 when is moved and released?

I know that I can use OnMessage( 0x3 ) to detect when the window is moving
and then watch for a LButton Up event to set the gui in the position I want. Is that the best I can do or does someone have a better way to do this.

The goal is simple. When I move the window, have it stay where it is moved (even with a negative value for the y axis ).

Example:
Temp (1).gif
Temp (1).gif (149.43 KiB) Viewed 861 times
Before the question comes up. There is a reason for what is seen, and having what is shown above in the placement it is in is required for other elements that come later. So no I can't just place it at the top of the gui.

HB.
teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

Re: Disable a gui from resetting the the Y position to 0 when released

21 Jun 2021, 15:34

Consider this way:

Code: Select all

global EVENT_SYSTEM_MOVESIZESTART := 0xA
     , EVENT_SYSTEM_MOVESIZEEND   := 0xB

Gui, New, +hwndhGui
Gui, Show, w300 h300
Hook := new WinEventHook(EVENT_SYSTEM_MOVESIZESTART, EVENT_SYSTEM_MOVESIZEEND, "HookProc", hGui)
Return

GuiClose:
   ExitApp

HookProc(hHook, event, hwnd) {
   static start := {}
   if (hwnd != A_EventInfo)
      Return
   
   if (event = EVENT_SYSTEM_MOVESIZESTART) {
      WinGetPos, X, Y,,, ahk_id %hwnd%
      start.x := X, start.y := Y
   }
   if (event = EVENT_SYSTEM_MOVESIZEEND) {
      WinGetPos,, Y,,, ahk_id %hwnd%
      if (Y <= 0)
         WinMove, ahk_id %hwnd%,, start.x, start.y
   }
}

class WinEventHook
{
   ; Event Constants: https://is.gd/tRT5Wr
   __New(eventMin, eventMax, hookProc, eventInfo := 0, idProcess := 0, idThread := 0, dwFlags := 0) {
      this.pCallback := RegisterCallback(hookProc, "F",, eventInfo)
      this.hHook := DllCall("SetWinEventHook", "UInt", eventMin, "UInt", eventMax, "Ptr", 0, "Ptr", this.pCallback
                                             , "UInt", idProcess, "UInt", idThread, "UInt", dwFlags, "Ptr")
   }
   __Delete() {
      DllCall("UnhookWinEvent", "Ptr", this.hHook)
      DllCall("GlobalFree", "Ptr", this.pCallback, "Ptr")
   }
}
doubledave22
Posts: 343
Joined: 08 Jun 2019, 17:36

Re: Disable a gui from resetting the the Y position to 0 when released

21 Jun 2021, 15:45

wineventhook is good for this or you could use a simple drag from anywhere script.

https://www.autohotkey.com/boards/viewtopic.php?t=80352
User avatar
Hellbent
Posts: 2102
Joined: 23 Sep 2017, 13:34

Re: Disable a gui from resetting the the Y position to 0 when released

21 Jun 2021, 15:51

@teadrinker

Thank you for the reply.
I think that my example may have given the wrong impression about what is happening and what I'm looking for (sorry about that).

Here is a little demo that shows more or less what can't be seen.

Code: Select all

#SingleInstance, Force

Gui, 1:+AlwaysOnTop -Caption -DPIScale
Gui, 1:Color, 22262A
Gui, 1:Add, Text,cWhite x0 y335 w100 h70 Border Center gMoveWindow, Move `n Window
Gui, 1:Show, x200 y100 w2000 h700


return
GuiContextMenu:
*ESC::ExitApp

MoveWindow:
	PostMessage, 0xA1, 2
	return

As you will see with that demo if you were to try to move the "Move Window" text control up to the top of a monitor that doesn't have another monitor above it, it will snap the guis y position to be the top of the monitor rather than just staying where it is when you release it (which is what I want to do). I want to disable that "Snapping to Top" feature.
User avatar
Hellbent
Posts: 2102
Joined: 23 Sep 2017, 13:34

Re: Disable a gui from resetting the the Y position to 0 when released

21 Jun 2021, 15:56

doubledave22 wrote:
21 Jun 2021, 15:45
wineventhook is good for this or you could use a simple drag from anywhere script.

https://www.autohotkey.com/boards/viewtopic.php?t=80352
Thank you for the link Dave, but it looks like that is about another issue. I have just posted something that hopefully fills any gaps that I may have missed in my first post.
doubledave22
Posts: 343
Joined: 08 Jun 2019, 17:36

Re: Disable a gui from resetting the the Y position to 0 when released

21 Jun 2021, 16:25

Hellbent wrote:
21 Jun 2021, 15:56
Thank you for the link Dave, but it looks like that is about another issue. I have just posted something that hopefully fills any gaps that I may have missed in my first post.
Tried your example... its certainly acting strangely. That said... have you tried teadrinkers or a drag+drop script to move the window instead of PostMessage, 0xA1, 2?

In your example the window itself is actually getting chopped down. I tried dragging it above the monitor and back into view and the GUI seems to cut itself down. I'm guessing it gets redraw and the "move window" box resets its coordinates based on the new window height. Maybe winmove wont do this (both our options used winmove instead)
teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

Re: Disable a gui from resetting the the Y position to 0 when released

21 Jun 2021, 16:27

Hellbent wrote: Here is a little demo that shows more or less what can't be seen.
Got it. In this case you can realise an algorythm like @doubledave22 provided.
My try:

Code: Select all

#SingleInstance, Force
SetBatchLines, -1
SetWinDelay, 0

Gui, 1:+AlwaysOnTop -Caption -DPIScale +hwndhGui
obj := {hwnd: hGui}
pObj := Object(obj)

Gui, 1:Color, 22262A
Gui, 1:Add, Text,cWhite x0 y335 w100 h70 Border Center gMoveWindow, Move `n Window
Gui, 1:Show, x200 y100 w2000 h700
return

GuiContextMenu:
*ESC::ExitApp

MoveWindow:
   CoordMode, Mouse
   MouseGetPos, X_Mouse, Y_Mouse
   WinGetPos, X_Gui, Y_Gui,,, % "ahk_id " . obj.hwnd
   obj.dX := X_Gui - X_Mouse, obj.dY := Y_Gui - Y_Mouse
   Hook := new WindowsHook(WH_MOUSE_LL := 14, "LowLevelMouseProc", pObj)
   KeyWait, LButton
   Hook := ""
   return

LowLevelMouseProc(nCode, wParam, lParam) {
   static WM_MOUSEMOVE := 0x200, obj
   (!obj && obj := Object(A_EventInfo))
   msg := wParam
   if (msg = WM_MOUSEMOVE) {
      mouse_x := NumGet(lParam + 0, "Int")
      mouse_y := NumGet(lParam + 4, "Int")
      timer := Func("EventHandler").Bind(obj, mouse_x, mouse_y)
      SetTimer, % timer, -10
   }
   Return DllCall("CallNextHookEx", "Ptr", 0, "Int", nCode, "UInt", wParam, "Ptr", lParam)
}

EventHandler(obj, x, y) {
   WinMove, % "ahk_id" . obj.hwnd,, x + obj.dX, y + obj.dY
}

class WindowsHook {
   __New(type, callback, eventInfo := "", isGlobal := true) {
      this.pCallback := RegisterCallback(callback, "Fast", 3, eventInfo)
      this.hHook := DllCall("SetWindowsHookEx", "Int", type, "Ptr", this.pCallback
                                              , "Ptr", !isGlobal ? 0 : DllCall("GetModuleHandle", "UInt", 0, "Ptr")
                                              , "UInt", isGlobal ? 0 : DllCall("GetCurrentThreadId"), "Ptr")
   }
   __Delete() {
      DllCall("UnhookWindowsHookEx", "Ptr", this.hHook)
      DllCall("GlobalFree", "Ptr", this.pCallback, "Ptr")
   }
}
User avatar
Hellbent
Posts: 2102
Joined: 23 Sep 2017, 13:34

Re: Disable a gui from resetting the the Y position to 0 when released

21 Jun 2021, 16:31

@doubledave22

This approximates the effect that I'm going for.

Code: Select all

#SingleInstance, Force

Gui, 1:+AlwaysOnTop -Caption -DPIScale
Gui, 1:Color, 22262A
Gui, 1:Add, Text,cWhite x0 y335 w100 h70 Border Center gMoveWindow, Move `n Window
Gui, 1:Show, x200 y100 w2000 h700

return
GuiContextMenu:
*ESC::ExitApp

MoveWindow:
	CoordMode, Mouse, Screen
	PostMessage, 0xA1, 2
	While(GetKeyState("LButton"))
		sleep, 10
	MouseGetPos,,Y
	Gui, Show, % "y" Y - 335 
	return

doubledave22 wrote:
21 Jun 2021, 16:25
In your example the window itself is actually getting chopped down. I tried dragging it above the monitor and back into view and the GUI seems to cut itself down.
I'm not sure if I'm reading that correct, but it sounds like a windows setting or version thing. I'm on windows 8.1
Either way that sounds like it is only a graphical thing. (kind of like how you can set windows to only draw a border when moving a window)
doubledave22
Posts: 343
Joined: 08 Jun 2019, 17:36

Re: Disable a gui from resetting the the Y position to 0 when released

21 Jun 2021, 16:37

haha i just wrote up a near similar example:

Code: Select all

#SingleInstance, Force

Gui, 1:+AlwaysOnTop -Caption -DPIScale +HWNDTest123
Gui, 1:Color, 22262A
Gui, 1:Add, Text,cWhite x0 y335 w100 h70 Border Center gMoveWindow, Move `n Window
Gui, 1:Show, x200 y100 w2000 h700


return
GuiContextMenu:
*ESC::ExitApp

MoveWindow:
	;~ PostMessage, 0xA1, 2,,, A

	while (GetKeystate("LButton","P"))
	{
		coordmode, mouse, screen
		mousegetpos, mX, mY
		winmove, % "ahk_id " Test123, ,mX, mY-400

	}
	
return
but make sure to comment out postmessage
User avatar
Hellbent
Posts: 2102
Joined: 23 Sep 2017, 13:34

Re: Disable a gui from resetting the the Y position to 0 when released

21 Jun 2021, 16:37

@teadrinker

That works quiet well. I think that I can adapt that to suit my needs.
doubledave22
Posts: 343
Joined: 08 Jun 2019, 17:36

Re: Disable a gui from resetting the the Y position to 0 when released

21 Jun 2021, 16:39

I'm on windows 10. yes use teadrinkers solution. It seems that winmove doesn't have the same issue you are having
teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

Re: Disable a gui from resetting the the Y position to 0 when released

21 Jun 2021, 16:41

@doubledave22
It works more smoothly with a mouse hook.
doubledave22
Posts: 343
Joined: 08 Jun 2019, 17:36

Re: Disable a gui from resetting the the Y position to 0 when released

21 Jun 2021, 16:43

teadrinker wrote:
21 Jun 2021, 16:41
@doubledave22
It works more smoothly with a mouse hook.
yeah I should switch my stuff over... thanks!
User avatar
Hellbent
Posts: 2102
Joined: 23 Sep 2017, 13:34

Re: Disable a gui from resetting the the Y position to 0 when released

21 Jun 2021, 16:51

Thank you @teadrinker and @doubledave22

I had hoped for something like this.

Code: Select all

Gui, New, -E0x0FF0F ;Disable "Snap-To-Top"
But I knew it was a long shot at best. That window hooking should prove useful.
teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

Re: Disable a gui from resetting the the Y position to 0 when released

21 Jun 2021, 17:01

Hellbent wrote: -E0x0FF0F
I now on Windows 7, for me this doesn't work. Do you know, what the ExStyle is 0x0FF0F? I haven't found.
User avatar
Hellbent
Posts: 2102
Joined: 23 Sep 2017, 13:34

Re: Disable a gui from resetting the the Y position to 0 when released

21 Jun 2021, 17:11

teadrinker wrote:
21 Jun 2021, 17:01
Hellbent wrote: -E0x0FF0F
I now on Windows 7, for me this doesn't work. Do you know, what the ExStyle is 0x0FF0F? I haven't found.
No lol. I have no idea if 0x0FF0F does anything at all, I just made that up as an example of what I was really hoping for. Something super simple that takes up 0 lines of code. (0 lines because Gui, New, +AlwaysOnTop ... etc)

Like I said, I knew it was a long shot that something like it exists but it kind of feels like there should be something that interrupts the process of checking if a window is outside the top of the screen and resets the position.
teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

Re: Disable a gui from resetting the the Y position to 0 when released

21 Jun 2021, 17:31

Hm, just tried on Windows 10:

Code: Select all

#SingleInstance, Force

Gui, 1: +AlwaysOnTop -Caption -DPIScale -E0x0FF0F
Gui, 1:Color, 22262A
Gui, 1:Add, Text,cWhite x0 y335 w100 h70 Border Center gMoveWindow, Move `n Window
Gui, 1:Show, x200 y100 w2000 h700


return
GuiContextMenu:
*ESC::ExitApp

MoveWindow:
   PostMessage, 0xA1, 2
   return
Doesn't work either.
User avatar
Hellbent
Posts: 2102
Joined: 23 Sep 2017, 13:34

Re: Disable a gui from resetting the the Y position to 0 when released

21 Jun 2021, 17:42

@teadrinker
Yeah, I just made that number up :lol:

When I started out I had a sense that there must be some process that once a window has been moved and released a bit of code checks to see if the window is in the bounds of all monitors and if it is outside the bounds it sets the position to be the top of the best fit monitor. I was hoping that there was something that would tell it to not do that check and just leave the window where it was moved to. (Disable snap-to-top kind of thing)
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: Disable a gui from resetting the the Y position to 0 when released  Topic is solved

21 Jun 2021, 18:57

http://web.archive.org/web/20131112230756/http://stackoverflow.com/questions/6645085/move-a-window-partially-off-the-top-of-the-screen

Code: Select all

#SingleInstance, Force

global hwndGui
Gui, 1:+AlwaysOnTop -Caption -DPIScale +HwndhwndGui
Gui, 1:Color, 22262A

global hwndButton
Gui, 1:Add, Text,cWhite x0 y335 w100 h70 Border Center gMoveWindow HwndhwndButton, Move `n Window
Gui, 1:Show, x200 y100 w200 h700

global in_movesize_loop := false
global inhibit_movesize_loop := false

OnMessage(0x0231, "WM_ENTERSIZEMOVE")
WM_ENTERSIZEMOVE(wParam, lParam, msg, hwnd) {
	if (hwnd = hwndGui)
	{
		in_movesize_loop := true
		inhibit_movesize_loop := false
		return 0
	}
}

OnMessage(0x0232, "WM_EXITSIZEMOVE")
WM_EXITSIZEMOVE(wParam, lParam, msg, hwnd) {
	if (hwnd = hwndGui)
	{
		in_movesize_loop := false
		inhibit_movesize_loop := false
		return 0
	}
}

OnMessage(0x0215, "WM_CAPTURECHANGED")
WM_CAPTURECHANGED(wParam, lParam, msg, hwnd) {
	if (hwnd = hwndGui)
	{
		inhibit_movesize_loop := in_movesize_loop
		return 0
	}
}

OnMessage(0x0046, "WM_WINDOWPOSCHANGING")
WM_WINDOWPOSCHANGING(wParam, lParam, msg, hwnd) {
	if (hwnd = hwndGui)
	{
		if inhibit_movesize_loop
		{
			flags := NumGet(lParam + 32, "UInt")
			NumPut(flags | 0x0002, lParam + 32, "UInt") ; |= SWP_NOMOVE
			return 0
		}
	}
}

GuiContextMenu:
*ESC::ExitApp

MoveWindow:
	PostMessage, 0xA1, 2
return
teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

Re: Disable a gui from resetting the the Y position to 0 when released

21 Jun 2021, 20:05

@swagfag
Thanks, interesting. Looks like the code can be simplified like this:

Code: Select all

global hwndGui, WM_CAPTURECHANGED := 0x0215, WM_WINDOWPOSCHANGING := 0x0046
Gui, 1:+AlwaysOnTop -Caption -DPIScale +HwndhwndGui
Gui, 1:Color, 22262A

Gui, 1:Add, Text,cWhite x0 y335 w100 h70 Border Center gMoveWindow, Move `n Window
Gui, 1:Show, x200 y100 w200 h700
OnMessage(WM_CAPTURECHANGED, "MessageHandler")
OnMessage(WM_WINDOWPOSCHANGING, "MessageHandler")
Return

MessageHandler(wParam, lParam, msg, hwnd) {
   static inhibit_movesize_loop := true
   if (hwnd = hwndGui) {
      Switch msg {
         Case WM_CAPTURECHANGED: inhibit_movesize_loop := !inhibit_movesize_loop
         Case WM_WINDOWPOSCHANGING:
         if inhibit_movesize_loop {
            flags := NumGet(lParam + A_PtrSize*2 + 16, "UInt")
            NumPut(flags | 0x0002, lParam + A_PtrSize*2 + 16, "UInt") ; |= SWP_NOMOVE
         }
      }
   }
}

GuiContextMenu:
*ESC::ExitApp

MoveWindow:
   PostMessage, 0xA1, 2
return

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: iamMG and 118 guests