-
Notifications
You must be signed in to change notification settings - Fork 41
/
WindowPadX.ahk
519 lines (442 loc) · 16.5 KB
/
WindowPadX.ahk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
/*
Title: _WindowPadX
*Handling windows in general and within a multi-monitor setup in special*
derived from *WindowPad* by *Lexikos* (http://www.autohotkey.com/forum/topic21703.html)
See also the documentation of original *WindowPad* by *Lexikos* (http://www.autohotkey.com/forum/topic21703.html), as *WindowPadX* is just a simple clone of *WindowPad* with reengineering and a few enhancements ....
Documentation:
- <Command-line Usage> - Using *WindowPadX* from the commandline
- <Adding Commands> - Implement your own commands
Requires:
AutoHotkey v1.1.0 or later.
Author:
hoppfrosch
Version History:
1.2.2 - 22.Mar.2012 Hoppfrosch
[+] WPXA.ahk v0.2.0: <wp_RollWindowToggle>: Bugfix for rolling up windows to its titlebar
1.2.1 - 22.Mar.2012 Hoppfrosch
[+] WPXA.ahk v0.1.10: <wp_GetMonitorFromMouse>: Determine monitor where mouse is
[*] WPXA.ahk v0.1.10: <WPXA_MinimizeWindowsOnMonitor>: Minimize windows on screen where mouse is
1.2.0 - 19.Mar.2012 Hoppfrosch
[+] WPXA.ahk v0.1.9: <WPXA_TileLast2Windows>: Tile active and last window (Credits: ipstone today (http://www.autohotkey.com/forum/viewtopic.php?p=521482#521482))
1.1.1 - 26.Jan.2012 Hoppfrosch
[*] WPXA.ahk v0.1.8: <WPXA_MaximizeToggle>: Bugfix to actually toggle Maximization
1.1.0 - 13.Jan.2012 Hoppfrosch
[*] WPXA.ahk v0.1.6: <WPXA_TopToggle()>: Reanimated Notifications
[+] WPXA.ahk v0.1.7: <WPXA_RollToggle>: New action for toggling rolling a window to its captionbar
1.0.1 - 13.Jan.2012 Hoppfrosch
[*] WPXA.ahk v0.1.5: <WPXA_MouseLocator>: Using integer coordinates for Gui Show
1.0.0 - 12.Jan.2012 Hoppfrosch: Initial release of WindowPadX
*/
/*
--------------------------------------------------------------------------------------
Ideensammlung:
* Transparenz f�r Fenster
* Overlay-Icon in Taskbar, um anzuzeigen auf welchem Screen sich das Fenster befindet ... (Funktion aus ITaskBar von maul.esel). Dies sollte bei verlassen des Programmes auch wieder entfernt werden.
Hinweise:
* http://www.autohotkey.com/forum/viewtopic.php?t=74314
* http://www.autohotkey.com/forum/viewtopic.php?t=70978
* "TaskSwitcher" fuer jeden Monitor
Hinweise:
* http://www.autohotkey.com/forum/viewtopic.php?t=71912
--------------------------------------------------------------------------------------
*/
#include %A_ScriptDir%/WPXA.ahk
#SingleInstance force
Version := "1.2.2"
; Custom .ini Path
Param1 = %1%
If (InStr(Param1, ".ini"))
{
WINDOWPADX_INI_PATH := Param1
gosub WindowPadXInit
return
}
if 0 > 0
{
; Command-line mode: interpret each arg as a pseudo-command.
; Suspend all hotkeys which may be created by WindowPadXInit.
Suspend On
; Load options and Gather exclusions.
gosub WindowPadXInit
; Execute command line(s). Each args should be in one of these formats:
; <command>
; <command>,<args_no_spaces>
; "<command>, <args>" ; In this case the initial comma is optional.
Loop %0%
wp_ExecLine(%A_Index%)
ExitApp
}
OnExit, TrayExit
; Load options and Gather exclusions.
WindowPadXInit:
; If this script is #included in another script, this section may not be
; auto-executed. In that case, the following should be called manually:
WindowPadX_Init(WINDOWPADX_INI_PATH)
return
WindowPadX_Init(IniPath="")
{
global WINDOWPADX_INI_PATH
;
; Init icons and tray menu.
;
wp_SetupTray()
;
; Load settings.
;
if IniPath =
Loop, %A_LineFile%\..\WindowPadX.ini
IniPath := A_LoopFileFullPath
ifNotExist %IniPath%
{
IniPath = %A_ScriptDir%\WindowPadX.ini
FileInstall, WindowPadX.Default.ini, %IniPath%
}
WINDOWPADX_INI_PATH := IniPath
WindowPadX_LoadSettings(IniPath)
; Sets Windows Dpi Awareness context for thread so that it uses per-monitor DPI scaling.
; Otherwise there will be issues if using monitors with different scaling for calculating window position, since it will use the scaling of main monitor.
; SetThreadDpiAwarenessContext function description: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setthreaddpiawarenesscontext
; Argument '-3' sets context to 'DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE': https://docs.microsoft.com/en-gb/windows/win32/hidpi/dpi-awareness-context
; Without running the line below, it will use -2 DPI_AWARENESS_CONTEXT_SYSTEM_AWARE
DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr")
}
WindowPadX_LoadSettings(ininame)
{
local v
; Misc Options
IniRead, v, %ininame%, Options, TitleMatchMode, %A_TitleMatchMode%
SetTitleMatchMode, %v%
; allow generic options
IniRead, opts, %ininame%, Options
Loop, Parse, opts, `n, `r
{
StringSplit v, A_LoopField, =
%v1% := v2
}
; Hotkeys: Exclude Windows
v := wp_INI_GetList(ininame, "Exclude Windows", "Window")
Loop, Parse, v, `n
GroupAdd, HotkeyExclude, %A_LoopField%
; Read the Hotkeys section in.
v := wp_INI_ReadSection(ininame, "Hotkeys")
; Replace the first = with ::.
; ('=' is required for WritePrivateProfileSection to work properly.)
v := RegExReplace(v, "m`a)^(.*?)=", "$1::")
Hotkey, IfWinNotActive, ahk_group HotkeyExclude
Hotkey_Params(v)
; Gather: Exclude Windows
v := wp_INI_GetList(ininame, "Gather: Exclude Windows", "Window")
Loop, Parse, v, `n
GroupAdd, GatherExclude, %A_LoopField%
; Gather: Exclude Processes
ProcessGatherExcludeList := wp_INI_GetList(ininame
, "Gather: Exclude Processes", "Process", ",")
}
wp_INI_GetList(ininame, Section, Key, Delim="`n")
{
v := wp_INI_ReadSection(ininame, Section)
Loop, Parse, v, `n
{
pos := InStr(A_LoopField, "=")
if (pos && SubStr(A_LoopField,1,pos-1) = Key)
list .= (list ? Delim : "") . SubStr(A_LoopField, pos+1)
}
return list
}
wp_INI_ReadSection(Filename, Section)
{
char_type := A_IsUnicode ? "UShort" : "UChar"
char_size := A_IsUnicode ? 2 : 1
; Expand relative paths, since GetPrivateProfileSection only searches %A_WinDir%.
Loop, %Filename%, 0
Filename := A_LoopFileLongPath
VarSetCapacity(buf, 0x7FFF*char_size, 0)
len := DllCall("GetPrivateProfileSection"
, "uint", &Section, "uint", &buf, "uint", 0x7FFF, "uint", &Filename)
VarSetCapacity(text, len*char_size), p := &buf
; For each null-terminated substring,
while (s := DllCall("MulDiv", "int", p, "int", 1, "int", 1, "str"))
; append it to the output and advance to the next substring.
text .= s "`n", p += (StrLen(s)+1)*char_size
; Strip the trailing newline
text := SubStr(text, 1, -1)
; Windows Me/98/95:
; The returned string includes comments.
;
; This removes comments. Also, I'm not sure if leading/trailing space is
; automatically removed on Win9x, so the regex removes that too.
if A_OSVersion in WIN_ME,WIN_98,WIN_95
text := RegExReplace(text, "m`n)^[ `t]*(?:;.*`n?|`n)|^[ `t]+|[ `t]+$")
return text
}
; Tray menu subroutines. May also be assigned to hotkeys in WindowPadX.ini.
TrayDebug:
ListHotkeys
return
TrayHelp:
Run, %A_ScriptDir%\WindowPadX.html
return
TrayReload:
Reload
return
TrayEdit:
Edit
return
TrayEditConfig:
RegRead, Editor, HKCR, AutoHotkeyScript\Shell\Edit\Command
StringReplace, Editor, Editor, "`%1",
Editor := RegExReplace(Editor, "(^\s*|\s*$)")
if (Editor = )
Editor = notepad
Run, %Editor% "%A_ScriptDir%\WindowPadX.ini"
return
TraySuspend:
WM_COMMAND(65305,0)
Suspend
Menu, Tray, % A_IsSuspended ? "Check" : "Uncheck", &Suspend
return
TrayExit:
wp_Restore()
ExitApp
;
; Hotkeys: Activate hotkeys defined in INI section [Hotkeys: %section%].
;
Hotkeys(section, options)
{
local this_hotkey, section_var, hotkeys, wait_for_keyup, m, m1, pos, k
static key_regex = "^(?:.* & )?[#!^+&<>*~$]*(.+)"
this_hotkey := A_ThisHotkey
if !section
goto HC_SendThisHotkeyAndReturn
pos := RegExMatch(options, "i)(?<=\bD)\d*\.?\d*", m)
if pos
{
options := SubStr(options, 1, pos-2) . SubStr(options, pos+StrLen(m))
if (m+0 = "")
m := 0.1
Input, k, L1 T%m%
if ErrorLevel != Timeout
{
gosub HC_SendThisHotkey
Send %k%
return
}
}
section_var := RegExReplace(section, "[^\w#@$]", "_")
hotkeys := Hotkeys_%section_var%
if hotkeys =
{
; Load each hotkeys section on first use. Since the ini file may be
; edited between enabling and disabling the hotkeys, loading them
; each and every time would be hazardous.
hotkeys := wp_INI_ReadSection(WINDOWPADX_INI_PATH, "Hotkeys: " section)
if hotkeys =
goto HC_SendThisHotkeyAndReturn
; key=command -> key::command
hotkeys := RegExReplace(hotkeys, "m`a)^(.*?)=", "$1::")
Hotkeys_%section_var% := hotkeys
}
; If Options were omitted and this is a key-down hotkey,
; automatically disable the hotkeys when the key is released.
if (wait_for_keyup := (options="" && SubStr(this_hotkey,-2) != " up"))
options = On ; Explicit "on" in case hotkey exists but is disabled.
Hotkey, IfWinNotActive, ahk_group HotkeyExclude
Hotkey_Params(hotkeys, options)
if (wait_for_keyup)
{
if (!RegExMatch(this_hotkey, key_regex, m) || GetKeyState(m1)="") {
MsgBox, % "Error retrieving primary key of hotkey in Hotkeys().`n"
. "`tHotkey: " this_hotkey "`n"
. "`tResult: " m1
. "`nPlease inform Lexikos. Tip: Press Ctrl+C to copy this message."
return
}
KeyWait, %m1%
Hotkey_Params(hotkeys, "Off")
; A_ThisHotkey: "The key name of the *most recently executed* hotkey"
;if(some other hotkey was executed during KeyWait)
if (this_hotkey = A_ThisHotkey)
goto HC_SendThisHotkeyAndReturn
}
return
HC_SendThisHotkey:
HC_SendThisHotkeyAndReturn:
if ! InStr(this_hotkey, "~")
if (RegExMatch(this_hotkey, key_regex, m) && GetKeyState(m1)!="") {
Hotkey, %this_hotkey%, Off
Send {Blind}{%m1%}
Hotkey, %this_hotkey%, On
}
return
}
;
; Commands implemented as labels for simplicity.
;
Send:
Send, %Params%
return
Minimize:
if wp_WinExist(Params)
PostMessage, 0x112, 0xF020 ; WM_SYSCOMMAND, SC_MINIMIZE
return
Unminimize:
if wp_WinLastMinimized()
WinRestore
return
Restore:
if wp_WinExist(Params)
WinRestore
return
;
; Internal Functions
;
; Execute a pseudo-command with params.
wp_ExecLine(cmdline)
{
if RegExMatch(cmdline, "^\s*(?<Name>\S+?)(?:[, `t]\s*(?<Params>.*?))?\s*$", a)
{
global Params := aParams ; Global for use by label-based pseudo-commands.
if (n := IsFunc(aName)) && n <= 6
{ ; %aName% is a function with up to 5 params.
if n > 2
{ ; Two or more required parameters.
if RegExMatch(aParams, "^(?:[^,]*,){1," n-2 "}\s*", aParams)
StringSplit, p, aParams, `,, %A_Space%%A_Tab%
else ; no comma
p0 := 1
p%p0% := SubStr(Params, StrLen(aParams) + 1)
}
else
; At most one required parameter.
p1 := Params
; Call function with values supplied for only the required params.
; This allows commas to be treated literally in the last param.
return %aName%(p1, p2, p3, p4, p5)
}
else
; aName is a label or invalid.
gosub %aName%
}
}
; Hotkey_Params( line [, Options ] )
; Associates a hotkey with a parameter string.
;
; Expects a newline(`n)-delimited list of hotkeys in the form:
; Hotkey:: LabelName, Params
;
; Note:
; - Spaces are optional.
; - As with hotkey labels, there should be no space between 'Hotkey' and '::'.
; - Unlike the Hotkey command, LabelName MUST NOT be omitted.
; - Params MUST NOT contain a newline character (`n).
; - Params may contain zero or more commas.
; - , (comma) is supported as a hotkey.
; - Unlike the Hotkey command, 'Toggle' should be specified in the Options, not as a label.
;
; Returns the number of hotkeys successfully enabled/disabled.
;
Hotkey_Params(line, Options="")
{
static List ; List of hotkeys and associated labels + parameters.
, sCmdLine ; temp var used by hotkey subroutine.
count = 0
; Note: The parsing loop operates on a temporary copy of 'line',
; so 'line' can be (and is) reused within the loop.
Loop, Parse, line, `n, %A_Space%%A_Tab%
{
; Clear ErrorLevel in case UseErrorLevel is (not) specified.
ErrorLevel =
if ! RegExMatch(A_LoopField, "^\s*(?<Hotkey>.+?)::\s*(?<Name>.+?)(?:[, `t]\s*(?<Params>.*?))?\s*$", line)
continue
if !(IsLabel(lineName) || IsFunc(lineName))
continue
if Options = Toggle ; Not supported as an option (must be Label.)
{
; Toggle hotkey. If it doesn't exist, the next line will enable it.
Hotkey, %lineHotkey%, Toggle, UseErrorLevel
; Ensure the hotkey will execute the correct label.
Hotkey, %lineHotkey%, hp_ExecuteHotkeyWithParams, UseErrorLevel
} else
Hotkey, %lineHotkey%, hp_ExecuteHotkeyWithParams, %Options%
; Check ErrorLevel in case UseErrorLevel was specified.
if ErrorLevel
continue
; Rebuild line to remove whitespace.
line := lineHotkey "::" lineName "," lineParams
; Update an existing hotkey's label + params,
temp := RegExReplace(List, "m`n)^\Q" lineHotkey "\E::.*$", line, repl, 1)
if (repl > 0)
List := temp
else ; or add a new hotkey to the list.
List .= (List ? "`n" : "") . line
count += 1
}
return count
hp_ExecuteHotkeyWithParams:
if RegExMatch(List, "m`n)^\Q" A_ThisHotkey "\E::\K.*", sCmdLine)
wp_ExecLine(sCmdLine)
return
}
;
; Tray Menu
;
;
wp_SetupTray()
{
if A_IsCompiled ; Load icons from my custom WindowPadX.exe.
{
; Default icon is 32x32, so doesn't look good in the tray.
Menu, Tray, Icon, %A_ScriptFullPath%, 2
}
else if (A_LineFile = A_ScriptFullPath)
{ ; Set the tray icon, but only if not included in some other script.
wp_SetTrayIcon(true)
; Use OnMessage to catch "Suspend Hotkeys" or "Pause Script"
; so the "disabled" icon can be used.
OnMessage(0x111, "WM_COMMAND")
}
Menu, Tray, NoStandard
Menu, Tray, MainWindow
Menu, Tray, Add, &Debug, TrayDebug
ifExist, %A_ScriptDir%\WindowPadX.html
{
Menu, Tray, Add, &Help, TrayHelp
Menu, Tray, Add
}
Menu, Tray, Add, &Reload, TrayReload
if !A_IsCompiled
{
Menu, Tray, Add, &Edit Source, TrayEdit
}
Menu, Tray, Add, Edit &Configuration, TrayEditConfig
Menu, Tray, Add
Menu, Tray, Add, &Suspend, TraySuspend
Menu, Tray, Add, E&xit, TrayExit
Menu, Tray, Default, &Debug
}
;
; Tray Icon Override:
; Provides a way to customize the icons without compiling the script.
;
WM_COMMAND(wParam, lParam)
{
static IsPaused, IsSuspended
Critical
id := wParam & 0xFFFF
if id in 65305,65404,65306,65403
{ ; "Suspend Hotkeys" or "Pause Script"
if id in 65306,65403 ; pause
IsPaused := ! IsPaused
else ; at this point, A_IsSuspended has not yet been toggled.
IsSuspended := ! A_IsSuspended
wp_SetTrayIcon(!(IsPaused or IsSuspended))
}
}
wp_SetTrayIcon(is_enabled)
{
icon := is_enabled ? "tray.ico" : "disabled.ico"
icon = %A_ScriptDir%\icons\%icon%
; avoid an error message if the icon doesn't exist
IfExist, %icon%
Menu, TRAY, Icon, %icon%,, 1
}