Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

WindowPad - window-moving tool


  • Please log in to reply
377 replies to this topic
Lexikos
  • Administrators
  • 9449 posts
  • Last active:
  • Joined: 17 Oct 2006
WindowPad

Uses a virtual "pad" to arrange windows. Original concept based on HiRes Screen Splitter by JOnGliko. Use the Numpad or your own custom layout to move and resize a window to fill the appropriate section of the screen.

Features include:
  • Move windows within the current monitor or between monitors (in multi-monitor setups).
  • Customize hotkeys via WindowPad.ini with AutoHotkey-like command syntax.
  • Define custom commands as labels or functions in WindowPad.ahk.
  • Execute WindowPad commands specified on the command-line.
Note: WindowPad hasn't been updated in over two years.

hoppfrosch's WindowPadX is an enhancement of WindowPad, providing additional functionality useful for multi-monitor setups.


WindowPad is public domain or closest equivalent; see CC0.

Attached Files



bobbo
  • Members
  • 15 posts
  • Last active: Oct 10 2010 01:08 AM
  • Joined: 19 Mar 2007
Absolutely love this tool, it is fast and effective at what it does. Instantly earned a place in my startup script.

One suggestion: please add using the NumpadDot key to move the window to the next monitor without resizing the window. It's often nice to just throw a window to another screen without resizing first. Otherwise, great job!

Lexikos
  • Administrators
  • 9449 posts
  • Last active:
  • Joined: 17 Oct 2006
Updated to v1.1:
[*:3bhlzhj3]Added "Gather windows" hotkeys (NumpadDiv and NumpadMult)
[*:3bhlzhj3]Added Win+NumpadDot to move window to next monitor
[*:3bhlzhj3]Added more EasyKey combos (for symmetry)
[*:3bhlzhj3]Original functionality of EasyKey is now retained (on key-release)
[*:3bhlzhj3]Added SetWinDelay, -1 to reduce lag when making multiple moves (quickly):)

Charon the Hand
  • Members
  • 8 posts
  • Last active: Feb 24 2010 02:16 AM
  • Joined: 07 Aug 2007
This is a splendid tool, thank you very much.

lukemh
  • Guests
  • Last active:
  • Joined: --
This is AWESOME! Keep up the great work.

bobbo
  • Members
  • 15 posts
  • Last active: Oct 10 2010 01:08 AM
  • Joined: 19 Mar 2007
Again, great work, and thanks for the quick inclusion of my suggestion! I made a couple of minor edits for myself:

This allows the NumpadDot to work for maximized windows:
MoveWindowToNextScreen:
    gosub WP_SetLastFoundWindowByHotkey
    WinGet, state, MinMax
    if state
	{
        WinRestore
		MoveWindowToNextScreen()
        WinMaximize
	}
    else
		MoveWindowToNextScreen()
return

Similarly, this allows the "Gather Windows" to work with maximized windows (I only the changed last line of the original function, but I'm posting the whole function for completeness):
GatherWindows(md=1)
{
    ;SetWinDelay, -1 ; Makes a BIG difference to perceived performance.
    
    ; List all visible windows.
    WinGet, win, List
    
    ; Copy bounds of all monitors to an array.
    SysGet, mc, MonitorCount
    Loop, %mc%
        SysGet, mon%A_Index%, MonitorWorkArea, %A_Index%
    
    ; Destination monitor
    mdx := mon%md%Left
    mdy := mon%md%Top
    mdw := mon%md%Right - mdx
    mdh := mon%md%Bottom - mdy
    
    Loop, %win%
    {
        ; Set Last Found Window.
        if (!WinExist("ahk_id " . win%A_Index%))
            continue
        
        WinGetPos, x, y, w, h
        
        ; Determine which monitor this window is on.
        xc := x+w/2, yc := y+h/2
        ms := 1
        Loop, %mc%
            if (xc >= mon%A_Index%Left && xc <= mon%A_Index%Right
                && yc >= mon%A_Index%Top && yc <= mon%A_Index%Bottom)
            {
                ms := A_Index
                break
            }
        ; If already on destination monitor, skip this window.
        if (ms = md)
            continue
        
        ; Source monitor
        msx := mon%ms%Left
        msy := mon%ms%Top
        msw := mon%ms%Right - msx
        msh := mon%ms%Bottom - msy
        
        ; If the window is resizable, scale it by the monitors' resolution difference.
        if (IsResizable()) {
            w *= (mdw/msw)
            h *= (mdh/msh)
        }
        
        ; Move window, using resolution difference to scale co-ordinates.
	    WinGet, state, MinMax
	    if state
		{
	        WinRestore
			WinMove,,, mdx + (x-msx)*(mdw/msw), mdy + (y-msy)*(mdh/msh), w, h
	        WinMaximize
		}
	    else
			WinMove,,, mdx + (x-msx)*(mdw/msw), mdy + (y-msy)*(mdh/msh), w, h
    }
}

And finally, I removed the "SetWinDelay, -1" because of its AHK Command Reference entry:

Although a delay of -1 (no delay at all) is allowed, it is recommended that at least 0 be used, to increase confidence that the script will run correctly even when the CPU is under load.



Lexikos
  • Administrators
  • 9449 posts
  • Last active:
  • Joined: 17 Oct 2006

This allows the NumpadDot to work for maximized windows:

It already worked for maximized windows (for me?; it resizes based on screen size difference.) :? Restoring then maximizing again just adds a delay. The same applies to gather windows.

[Edit] Heh, I just realised maximized windows go back to their original screen when you restore them. I guess using WinRestore before and WinMaximize after moving the window (like bobbo suggests) would fix this. For now, I'd rather omit it so the window moves "instantly." [/Edit]

And finally, I removed the "SetWinDelay, -1" because of its AHK Command Reference entry:

I ignored that because...

This is done to improve the reliability of scripts because a window sometimes needs a period of "rest" after being created, activated, minimized, etc. so that it has a chance to update itself and respond to the next command that the script may attempt to send to it.

...if you're only sending one command to each window, there is no "next command." And it seemed to work reliably (and faster) with SetWinDelay,-1.

Oh well, whatever works for you.

silkcom
  • Guests
  • Last active:
  • Joined: --
First, let me tell you, awesome script. This is exactly what I've been looking for.

I found a small problem though:

When I use the 6 to move to the right side, then to the next monitors left side, etc, it works, but when I use the 4 to try and do the same thing the opposite way it doesn't work.

My setup: I have my secondary monitor on the right side of my main monitor. I did switch the variables in the GatherWindowsLeft and RIght, but I'm not sure if there is another place that I'm suppose to change it?

Lexikos
  • Administrators
  • 9449 posts
  • Last active:
  • Joined: 17 Oct 2006
GatherWindows uses absolute monitor index, so it should be the only part you'd need to change.

So you can move to the secondary, which is on the right, but not back to the primary? It seems to work fine for me (after moving my secondary to the right of my primary.) What's the exact setup of your monitors? (Easiest answer is to run this script and copy-paste the mon* variables.)
SysGet, m, MonitorCount
Loop, %m%
    SysGet, mon%A_Index%, Monitor, %A_Index%
ListVars
Pause


silkcom
  • Guests
  • Last active:
  • Joined: --
Global Variables (alphabetical)
--------------------------------------------------
0[1 of 3]: 0
dir[0 of 0]:
dir0[0 of 0]:
dir1[0 of 0]:
dir2[0 of 0]:
Directions0[0 of 0]:
Directions1[0 of 0]:
EasyKey[0 of 0]:
ErrorLevel[1 of 3]: 0
heightFactor[0 of 0]:
m[1 of 3]: 2
mon1[0 of 0]:
mon1Bottom[3 of 3]: 800
mon1Left[1 of 3]: 0
mon1Right[4 of 7]: 1280
mon1Top[1 of 3]: 0
mon2[0 of 0]:
mon2Bottom[3 of 3]: 658
mon2Left[4 of 7]: 1280
mon2Right[4 of 7]: 2960
mon2Top[4 of 7]: -392
Prefix_Active[0 of 0]:
Prefix_Other[0 of 0]:
state[0 of 0]:
widthFactor[0 of 0]:


2nd question:
I'm interested in changing the hotkeys. I know that I would have to change them in the Loop at the beginning but I'm not exactly sure how DoMoveWindowInDirection works, so I'm not sure if that would need to be changed too. The problem is that I'm on a laptop, so the numpad is a bit annoying to work with :). I'd prefer to be able to do the move with one hand (I want to do Alt+Win+a to move left, and Alt+Win+d to move right, etc).

Thanks again.

silkcom
  • Guests
  • Last active:
  • Joined: --
Ok, so I'm pretty sure that the problem is that my monitors are setup such that the tops don't line up (when I lined them up, in display properties, so that the tops were at the same level the script moved back and forth perfectly).

Not sure how to fix it, but it's definately trying to get a monitor possition where the top is negative (which it is on my big monitor, but would return a bad number otherwise I would think).

silkcom
  • Guests
  • Last active:
  • Joined: --
A quick fix that I put in is:

In GetMonitorAt() as the first line I put:
y := 100

Not a bad answer, but if u positioned ur monitors such that 100 is below or above one of the monitors, then it would break again.

Lexikos
  • Administrators
  • 9449 posts
  • Last active:
  • Joined: 17 Oct 2006
I see the problem. It works by getting some point that is probably in the right monitor:
x := (sideX>0 ? monBRight : monBLeft) + sideX
y := (sideY>0 ? monBBottom : monBTop) + sideY
This needs to be fixed so that if sideX|Y = 0, the current window position on that axis is used. At the moment it would use the top/left of the monitor.

Edit: done. (It now uses the center of the window when sideX|Y=0.)

kmccoy
  • Members
  • 1 posts
  • Last active: Aug 17 2007 09:35 AM
  • Joined: 17 Aug 2007
This is really great. One thing I noticed is that when I gather windows, it gathers things that really shouldn't move, like the Vista Sidebar and desktop. It'd be great to be able to rule those things out, but I can't find anything in common to these items so that I can conveniently make it ignore them...

Lexikos
  • Administrators
  • 9449 posts
  • Last active:
  • Joined: 17 Oct 2006
My original need for gather windows was to move all windows to my secondary monitor when my primary isn't "hooked up"* to my PC - so I didn't have much need for an exclusion list. (Also, I find the Vista sidebar next to useless. :p)

* for lack of a better term; it has dual inputs, so I use it with my Xbox360 occasionally.

I can see how it might be useful to exclude some windows, so I've added two methods of exclusion:[*:2kgsycec]Exclude by title, class, etc. (GroupAdd, GatherExclude, ...)
[*:2kgsycec]Exclude by process name (ProcessGatherExcludeList; comma-delimited.)By default it excludes the sidebar and its gadgets. Simply uncomment ProcessGatherExcludeList and add process.exe to the list to exclude entire applications. (e.g. ...List = sidebar.exe,firefox.exe)

I'm interested in changing the hotkeys. I know that I would have to change them in the Loop at the beginning but I'm not exactly sure how DoMoveWindowInDirection works, so I'm not sure if that would need to be changed too.

I forgot to reply to this. :oops: After using WindowPad for a while, I think I'd also like to change the keys. The main issue at the moment is the way DoMoveWindowInDirection maps keys (specifically, the numbers at the end of the key names) to directions - via the Directions array (which is initialized at the top of DoMoveWindowInDirection.) I realised when I wrote it that it wouldn't allow for proper customization, but I was in a hurry. :roll: When I get time, I'll rewrite it to allow keys to be customized; probably similar to:
key_list =
( C
#Numpad4=-1,0  ; left
#Numpad5=0,0  ; middle
#Numpad6=1,0  ; right
...
!#Numpad1=2:-1,1  ; second window down-left
#NumpadMult=all:2  ; gather at monitor 2
#NumpadDot=+1 ; next monitor
)
One possible complication (with the "n:..." convention) is determining the true order for always-on-top windows. For instance, on Vista, windows 1 and 2 are the start button orb and taskbar (which are always-on-top.)

I think the most accurate way would be to track window activation, and maintain a list of the last %n% active windows...