w-mousekey 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/.editorconfig +9 -0
  2. package/.eslintignore +3 -0
  3. package/.eslintrc.js +55 -0
  4. package/.jsdoc +25 -0
  5. package/AutoHotkey_2.0.19/AutoHotkey.chm +0 -0
  6. package/AutoHotkey_2.0.19/AutoHotkey32.exe +0 -0
  7. package/AutoHotkey_2.0.19/AutoHotkey64.exe +0 -0
  8. package/AutoHotkey_2.0.19/Install.cmd +2 -0
  9. package/AutoHotkey_2.0.19/UX/Templates/Minimal for v2.ahk +6 -0
  10. package/AutoHotkey_2.0.19/UX/WindowSpy.ahk +246 -0
  11. package/AutoHotkey_2.0.19/UX/inc/CommandLineToArgs.ahk +12 -0
  12. package/AutoHotkey_2.0.19/UX/inc/CreateAppShortcut.ahk +37 -0
  13. package/AutoHotkey_2.0.19/UX/inc/EnableUIAccess.ahk +246 -0
  14. package/AutoHotkey_2.0.19/UX/inc/GetGitHubReleaseAssetURL.ahk +26 -0
  15. package/AutoHotkey_2.0.19/UX/inc/HashFile.ahk +96 -0
  16. package/AutoHotkey_2.0.19/UX/inc/README.txt +3 -0
  17. package/AutoHotkey_2.0.19/UX/inc/ShellRun.ahk +7 -0
  18. package/AutoHotkey_2.0.19/UX/inc/bounce-v1.ahk +3 -0
  19. package/AutoHotkey_2.0.19/UX/inc/common.ahk +21 -0
  20. package/AutoHotkey_2.0.19/UX/inc/config.ahk +13 -0
  21. package/AutoHotkey_2.0.19/UX/inc/identify.ahk +29 -0
  22. package/AutoHotkey_2.0.19/UX/inc/identify_regex.ahk +4 -0
  23. package/AutoHotkey_2.0.19/UX/inc/launcher-common.ahk +78 -0
  24. package/AutoHotkey_2.0.19/UX/inc/spy.ico +0 -0
  25. package/AutoHotkey_2.0.19/UX/inc/ui-base.ahk +129 -0
  26. package/AutoHotkey_2.0.19/UX/install-ahk2exe.ahk +53 -0
  27. package/AutoHotkey_2.0.19/UX/install-version.ahk +109 -0
  28. package/AutoHotkey_2.0.19/UX/install.ahk +1056 -0
  29. package/AutoHotkey_2.0.19/UX/launcher.ahk +430 -0
  30. package/AutoHotkey_2.0.19/UX/reload-v1.ahk +22 -0
  31. package/AutoHotkey_2.0.19/UX/reset-assoc.ahk +38 -0
  32. package/AutoHotkey_2.0.19/UX/ui-dash.ahk +200 -0
  33. package/AutoHotkey_2.0.19/UX/ui-editor.ahk +238 -0
  34. package/AutoHotkey_2.0.19/UX/ui-launcherconfig.ahk +195 -0
  35. package/AutoHotkey_2.0.19/UX/ui-newscript.ahk +296 -0
  36. package/AutoHotkey_2.0.19/UX/ui-setup.ahk +175 -0
  37. package/AutoHotkey_2.0.19/UX/ui-uninstall.ahk +68 -0
  38. package/AutoHotkey_2.0.19/WindowSpy.ahk +2 -0
  39. package/AutoHotkey_2.0.19/license.txt +351 -0
  40. package/AutoHotkey_2.0.19/zclick.ahk +5 -0
  41. package/AutoHotkey_2.0.19/zrun_click.bat +2 -0
  42. package/AutoHotkey_2.0.19/zrun_send.bat +2 -0
  43. package/AutoHotkey_2.0.19/zsend.ahk +4 -0
  44. package/LICENSE +21 -0
  45. package/README.md +23 -0
  46. package/SECURITY.md +5 -0
  47. package/_tmp/view.all.png +0 -0
  48. package/_tmp/view.det.png +0 -0
  49. package/babel.config.js +16 -0
  50. package/dist/action.umd.js +32 -0
  51. package/dist/action.umd.js.map +1 -0
  52. package/dist/ck-pic.umd.js +7 -0
  53. package/dist/ck-pic.umd.js.map +1 -0
  54. package/dist/compare.umd.js +7 -0
  55. package/dist/compare.umd.js.map +1 -0
  56. package/dist/get-settings.umd.js +7 -0
  57. package/dist/get-settings.umd.js.map +1 -0
  58. package/dist/mousekey.umd.js +7 -0
  59. package/dist/mousekey.umd.js.map +1 -0
  60. package/dist/screen.umd.js +7 -0
  61. package/dist/screen.umd.js.map +1 -0
  62. package/docs/fonts/Montserrat/Montserrat-Bold.eot +0 -0
  63. package/docs/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
  64. package/docs/fonts/Montserrat/Montserrat-Bold.woff +0 -0
  65. package/docs/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
  66. package/docs/fonts/Montserrat/Montserrat-Regular.eot +0 -0
  67. package/docs/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
  68. package/docs/fonts/Montserrat/Montserrat-Regular.woff +0 -0
  69. package/docs/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
  70. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
  71. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +978 -0
  72. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
  73. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
  74. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
  75. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
  76. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +1049 -0
  77. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
  78. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
  79. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
  80. package/docs/index.html +84 -0
  81. package/docs/scripts/collapse.js +39 -0
  82. package/docs/scripts/commonNav.js +28 -0
  83. package/docs/scripts/linenumber.js +25 -0
  84. package/docs/scripts/nav.js +12 -0
  85. package/docs/scripts/polyfill.js +4 -0
  86. package/docs/scripts/prettify/Apache-License-2.0.txt +202 -0
  87. package/docs/scripts/prettify/lang-css.js +2 -0
  88. package/docs/scripts/prettify/prettify.js +28 -0
  89. package/docs/scripts/search.js +99 -0
  90. package/docs/styles/jsdoc.css +776 -0
  91. package/docs/styles/prettify.css +80 -0
  92. package/g.mjs +46 -0
  93. package/g.test_opencv.mjs +36 -0
  94. package/package.json +41 -0
  95. package/pic/view.png +0 -0
  96. package/script.txt +17 -0
  97. package/src/action.mjs +132 -0
  98. package/src/ckPic.mjs +95 -0
  99. package/src/compare.mjs +201 -0
  100. package/src/getSettings.mjs +17 -0
  101. package/src/mousekey.mjs +95 -0
  102. package/src/screen.mjs +62 -0
  103. package/test/WMousekey.test.mjs +11 -0
  104. package/toolg/addVersion.mjs +4 -0
  105. package/toolg/cleanFolder.mjs +4 -0
  106. package/toolg/gDistRollup.mjs +33 -0
  107. package/toolg/modifyReadme.mjs +4 -0
@@ -0,0 +1,430 @@
1
+ ; This script is intended for indirect use via commands registered by install.ahk.
2
+ ; It can also be compiled as a replacement for AutoHotkey.exe, so tools which run
3
+ ; scripts by executing AutoHotkey.exe can benefit from automatic version selection.
4
+ #requires AutoHotkey v2.0
5
+
6
+ ;@Ahk2Exe-SetDescription AutoHotkey Launcher
7
+ #SingleInstance Off
8
+ #NoTrayIcon
9
+
10
+ #include inc\identify.ahk
11
+ #include inc\launcher-common.ahk
12
+ #include inc\ui-base.ahk
13
+
14
+ if A_ScriptFullPath == A_LineFile || A_LineFile == '*#1' {
15
+ SetWorkingDir A_InitialWorkingDir
16
+ Main
17
+ }
18
+
19
+ Main() {
20
+ switches := []
21
+ while A_Args.length {
22
+ arg := A_Args.RemoveAt(1)
23
+ if SubStr(arg,1,1) != '/' {
24
+ ScriptPath := arg
25
+ break
26
+ }
27
+ nextArgValue() {
28
+ if !A_Args.Length {
29
+ MsgBox "Invalid command line switches; missing value for " arg ".", "AutoHotkey Launcher", "icon!"
30
+ ExitApp 1
31
+ }
32
+ return A_Args.RemoveAt(1)
33
+ }
34
+ switch arg, false {
35
+ case '/RunWith': ; Launcher-specific
36
+ A_Args.runwith := nextArgValue()
37
+ case '/Launch': ; Launcher-specific
38
+ A_Args.launch := true
39
+ case '/Which':
40
+ A_Args.which := true
41
+ if trace.Enabled
42
+ trace.DefineProp 'call', {call: (this, s) => OutputDebug(s "`n")} ; Don't use stdout.
43
+ case '/iLib', '/include':
44
+ switches.push(arg)
45
+ switches.push(nextArgValue())
46
+ default:
47
+ switches.push(arg)
48
+ }
49
+
50
+ }
51
+ if !IsSet(ScriptPath)
52
+ && !FileExist(ScriptPath := A_ScriptDir "\AutoHotkey.ahk")
53
+ && !FileExist(ScriptPath := A_MyDocuments "\AutoHotkey.ahk")
54
+ && !FileExist(ScriptPath := A_ScriptDir "\ui-dash.ahk") {
55
+ ExitApp
56
+ }
57
+ if ScriptPath = '*'
58
+ ExitApp 2 ; FIXME: code would need to be read in and then passed to the real AutoHotkey
59
+ IdentifyAndLaunch ScriptPath, A_Args, switches
60
+ }
61
+
62
+ GetLaunchParameters(ScriptPath, interactive:=false) {
63
+ code := FileRead(ScriptPath, 'UTF-8')
64
+ require := prefer := rule := exe := ""
65
+ if RegExMatch(code, 'im)^[ `t]*#Requires[ `t]+AutoHotkey[ `t]+([^;`r`n]*?)[ `t]*(?:;[ `t]*prefer[ `t]+([^;`r`n\.]+))?(?:$|;)', &m) {
66
+ trace "![Launcher] " m.0
67
+ require := RegExReplace(m.1, '[^\s,]\K\s+(?!$)', ",")
68
+ prefer := RegExReplace(m.2, '[^\s,]\K\s+(?!$)', ",")
69
+ rule := "#Requires"
70
+ }
71
+ else if ConfigRead('Launcher', 'Identify', true) {
72
+ i := IdentifyBySyntax(code)
73
+ trace "![Launcher] syntax says version " (i.v || "unknown") " -- " i.r
74
+ if i.v
75
+ require := String(i.v)
76
+ rule := i.r
77
+ if rule = "error"
78
+ MsgBox "Syntax detection has failed due to an error in the launcher.`n`n" Type(i.err) ": " i.err.Message " " i.err.Extra "`n`n"
79
+ . "Character index " i.pos "`n" SubStr(code, i.pos, 50) "`n...`n`n"
80
+ . "Please report this on the forums, with sample code that triggers the error.", "AutoHotkey Launcher", "icon!"
81
+ }
82
+ else {
83
+ trace "![Launcher] version unknown - syntax-checking is disabled"
84
+ }
85
+ if !(hasv := RegExMatch(require, '(^|,)\s*(?!(32|64)-bit)[<>=]*v?\d')) {
86
+ ; No version specified or detected
87
+ if hasv := v := ConfigRead('Launcher', 'Fallback', "") {
88
+ require .= (require=''?'':',') v
89
+ trace "![Launcher] using fallback version " v
90
+ }
91
+ }
92
+ v := GetVersionToInstall(require) ; Currently used for multiple purposes
93
+ if !hasv
94
+ exe := interactive ? PromptMajorVersion(ScriptPath, require, prefer) : ""
95
+ else
96
+ if !exe := GetRequiredOrPreferredExe(require, prefer)
97
+ if interactive {
98
+ if v && !LocateExeByVersion(v, '')
99
+ exe := TryToInstallVersion(v, rule, ScriptPath, require, prefer)
100
+ else
101
+ RequirementNotMetMsgBox require, ScriptPath
102
+ }
103
+ lp := {exe: exe, id: exe ? GetMajor(exe.Version) : GetLikelyMajor(require), v: v, switches: []}
104
+ if exe {
105
+ if GetMajor(exe.Version) = 1 && ConfigRead('Launcher\v1', 'UTF8', false)
106
+ lp.switches.Push('/CP65001')
107
+ }
108
+ return lp
109
+ }
110
+
111
+ ParseRequiresVersion(s) {
112
+ return RegExMatch(s, 'i)^(?!(?:32|64)-bit$)(?<op>[<>=]*)v?(?<version>(?<major>\d+)\b\S*)', &m) ? m : 0
113
+ }
114
+
115
+ GetLikelyMajor(r) {
116
+ if IsNumber(r)
117
+ return Integer(r)
118
+ ; Usually there would be either a version number with no operator
119
+ ; or a range where the lower and upper bound have the same major.
120
+ Loop Parse r, ",", " `t"
121
+ if (m := ParseRequiresVersion(A_LoopField)) && m.op != '<'
122
+ return m.major
123
+ return ''
124
+ }
125
+
126
+ GetVersionToInstall(r) {
127
+ ; TryToInstallVersion currently only supports the latest bug-fix release,
128
+ ; so don't try to install if there's a complex version requirement.
129
+ if IsNumber(r)
130
+ return r
131
+ v := ""
132
+ Loop Parse r, ",", " `t" {
133
+ if (m := ParseRequiresVersion(A_LoopField)) {
134
+ if m.op
135
+ return ''
136
+ v := m.version
137
+ }
138
+ }
139
+ return v
140
+ }
141
+
142
+ IdentifyAndLaunch(ScriptPath, args, switches) {
143
+ lp := GetLaunchParameters(ScriptPath, !(whichMode := args.HasProp('which')))
144
+ if whichMode {
145
+ try FileAppend(lp.v "`n"
146
+ (lp.exe ? lp.exe.Path : "") "`n"
147
+ (lp.switches.Length ? lp.switches[1] : "") "`n", '*', 'UTF-8-RAW')
148
+ ExitApp lp.id
149
+ }
150
+ if !lp.exe
151
+ ExitApp 2
152
+ switches.Push(lp.switches*)
153
+ ExitApp LaunchScript(lp.exe.Path, ScriptPath, args, switches)
154
+ }
155
+
156
+ TryToInstallVersion(v, r, ScriptPath, require, prefer) {
157
+ ; This is currently designed only for downloading the latest bug-fix of a given minor version.
158
+ SplitPath ScriptPath, &name
159
+ m := ' script you are trying to run requires AutoHotkey v' v ', which is not installed.'
160
+ m := !(r && r != '#Requires') ? 'The' m '`n`nScript:`t' name : 'It looks like the' m '`nIf the version has been misidentified, please add a #Requires directive to your script file.`n`nScript:`t' name '`nRule:`t' r
161
+ if downloadable := IsNumber(v) || VerCompare(v, '1.1.24.02') >= 0 {
162
+ ; Get current version compatible with v.
163
+ bv := v = 1 ? '1.1' : IsInteger(v) ? v '.0' : RegExReplace(v, '^\d+(?:\.\d+)?\b\K.*')
164
+ req := ComObject('Msxml2.XMLHTTP')
165
+ req.open('GET', Format('https://www.autohotkey.com/download/{}/version.txt', bv), false)
166
+ try req.send()
167
+ if req.status = 200 && RegExMatch(cv := req.responseText, '^\d+\.[\w\+\-\.]+$') && VerCompare(cv, v) >= 0
168
+ m .= '`n`nWe can try to download and install AutoHotkey v' cv ' for you, while retaining the ability to use the versions already installed.`n`nDownload and install AutoHotkey v' cv '?'
169
+ else
170
+ downloadable := false
171
+ }
172
+ if downloadable && !A_IsAdmin && RegRead('HKLM\SOFTWARE\AutoHotkey', 'InstallDir', "") = ROOT_DIR
173
+ SetTimer(() => (
174
+ WinExist('ahk_class #32770 ahk_pid ' ProcessExist()) &&
175
+ SendMessage(0x160C,, true, 'Button1') ; BCM_SETSHIELD := 0x160C
176
+ ), -25)
177
+ if MsgBox(m, 'AutoHotkey', downloadable ? 'Iconi y/n' : 'Icon!') != 'yes'
178
+ return false
179
+ if RunWait(Format('"{}" /script "{}\install-version.ahk" "{}"', A_AhkPath, A_ScriptDir, cv)) != 0
180
+ return false
181
+ return exe := GetRequiredOrPreferredExe(require, prefer)
182
+ }
183
+
184
+ RequirementNotMetMsgBox(require, ScriptPath) {
185
+ SplitPath ScriptPath, &name
186
+ MsgBox 'Unable to locate the appropriate interpreter to run this script.`n`nScript:`t' name '`nRequires: ' StrReplace(require, ',', ' '), 'AutoHotkey', 'Icon!'
187
+ }
188
+
189
+ GetRequiredOrPreferredExe(require, prefer:='') {
190
+ if A_Args.HasProp('runwith')
191
+ prefer := A_Args.runwith ',' prefer
192
+ return LocateExeByVersion(require, Trim(prefer, ','))
193
+ }
194
+
195
+ LocateExeByVersion(require, prefer:='!UIA, 64, !ANSI') {
196
+ trace '![Launcher] locating exe: require ' require (prefer='' ? '' : '; prefer ' prefer)
197
+ best := '', bestscore := 0, cPrefMap := Map()
198
+ for ,f in GetUsableAutoHotkeyExes() {
199
+ try {
200
+ ; Check requirements first
201
+ fMajor := GetMajor(f.Version)
202
+ Loop Parse require, ",", " " {
203
+ if A_LoopField = ""
204
+ continue
205
+ if m := ParseRequiresVersion(A_LoopField) {
206
+ if !VerCompare(f.Version, (m.op ? '' : '>=') A_LoopField) {
207
+ ; trace '![Launcher] ' f.Version ' ' (m.op ? '' : '>=') A_LoopField ' = false'
208
+ continue 2
209
+ }
210
+ if !m.op && fMajor > m.major { ; No operator implies it must be same major version
211
+ ; trace '![Launcher] major ' f.Version ' > ' m.version
212
+ continue 2
213
+ }
214
+ }
215
+ else if !matchPref(f.Description, A_LoopField) {
216
+ ; trace '![Launcher] no match for "' A_LoopField '" in ' f.Description
217
+ continue 2
218
+ }
219
+ }
220
+ ; Determine additional user preferences based on major version
221
+ if !(cPref := cPrefMap.Get(fMajor, 0)) {
222
+ section := 'Launcher\v' fMajor
223
+ cPref := ConfigRead(section, 'Version', "")
224
+ cPref := {
225
+ V: cPref ? '=' cPref ',' : '<0,',
226
+ D: ',' (ConfigRead(section, 'Build', (A_Is64bitOS ? "64," : "") "!ANSI"))
227
+ . ',' (ConfigRead(section, 'UIA', false) ? 'UIA' : '!UIA')
228
+ }
229
+ cPrefMap.Set(fMajor, cPref)
230
+ }
231
+ ; Calculate preference score
232
+ fscore := 0
233
+ Loop Parse cPref.V prefer cPref.D, ",", " " {
234
+ if A_LoopField = ""
235
+ continue
236
+ fscore <<= 1
237
+ if !(A_LoopField ~= '^[<>=]' ? VerCompare(f.Version, A_LoopField)
238
+ : matchPref(f.Description, A_LoopField))
239
+ continue
240
+ fscore |= 1
241
+ }
242
+ ; trace '![Launcher] ' fscore ' v' f.Version ' ' f.Path
243
+ ; Prefer later version if all else matches. If version also matches, prefer later files,
244
+ ; as enumeration order is generally AutoHotkey.exe, ..A32.exe, ..U32.exe, ..U64.exe.
245
+ if bestscore < fscore
246
+ || bestscore = fscore && VerCompare(f.Version, best.Version) >= 0
247
+ bestscore := fscore, best := f
248
+ }
249
+ catch as e {
250
+ trace "-[Launcher] " type(e) " checking file " A_LoopFileName ": " e.message
251
+ trace "-[Launcher] " e.file ":" e.line
252
+ }
253
+ }
254
+ return best
255
+ matchPref(desc, pref) => SubStr(pref,1,1) != "!" ? InStr(desc, pref) : !InStr(desc, SubStr(pref,2))
256
+ }
257
+
258
+ PromptMajorVersion(ScriptPath, require:='', prefer:='') {
259
+ majors := Map()
260
+ Loop 2
261
+ if f := GetRequiredOrPreferredExe(A_Index ',' require, prefer)
262
+ majors[A_Index] := f
263
+ switch majors.Count {
264
+ case 1:
265
+ for , f in majors
266
+ return f
267
+ case 0:
268
+ trace '-[Launcher] Failed to locate any interpreters; fallback to launcher'
269
+ return {Path: A_AhkPath, Version: A_AhkVersion}
270
+ }
271
+ files := []
272
+ for , f in majors
273
+ files.Push(f)
274
+ prompt := VersionSelectGui(ScriptPath, files)
275
+ prompt.Show
276
+ WinWaitClose prompt
277
+ if !prompt.HasProp('selection') {
278
+ trace '[Launcher] No version selected from menu'
279
+ ExitApp
280
+ }
281
+ return prompt.selection
282
+ }
283
+
284
+ class Handle {
285
+ __new(ptr:=0) => this.ptr := ptr
286
+ __delete() => DllCall("CloseHandle", "ptr", this)
287
+ }
288
+
289
+ LaunchScript(exe, ahk, args:="", switches:="", encoding:="UTF-8") {
290
+ ; Pass our own stdin/stdout handles (if any) to the child process.
291
+ hStdIn := DllCall("GetStdHandle", "uint", -10, "ptr")
292
+ hStdOut := DllCall("GetStdHandle", "uint", -11, "ptr")
293
+ hStdErr := DllCall("GetStdHandle", "uint", -12, "ptr")
294
+
295
+ ; Build command line to execute.
296
+ makeArgs(args) {
297
+ r := ''
298
+ for arg in args is object ? args : [args]
299
+ r .= ' ' (arg ~= '\s' ? '"' arg '"' : arg)
300
+ return r
301
+ }
302
+ switches := makeArgs(switches)
303
+ cmd := Format('"{1}"{2} "{3}"{4}', exe, switches, ahk, makeArgs(args))
304
+ trace '>[Launcher] ' cmd
305
+
306
+ ; For RunWait, stdout redirection, /validate, etc. to have the best chance of working,
307
+ ; let the launcher exit early only if it can detect that it was executed from Explorer
308
+ ; or the parent process appears to have exited already (or if the caller passed /launch).
309
+ waitClose := !args.HasProp('launch')
310
+ hParent := 0
311
+ if IsSet(ProcessGetParent) {
312
+ try {
313
+ ; (PROCESS_QUERY_LIMITED_INFORMATION := 0x1000) | (SYNCHRONIZE := 0x100000)
314
+ if hParent := DllCall("OpenProcess", "uint", 0x101000, "int", false
315
+ , "uint", parentPid := ProcessGetParent(), "ptr")
316
+ hParent := Handle(hParent)
317
+ if !hParent || (parentName := ProcessGetName(parentPid)) = "explorer.exe"
318
+ waitClose := false
319
+ }
320
+ catch as e
321
+ trace '![Launcher] Failure checking parent process: ' e.Message
322
+ }
323
+
324
+ try {
325
+ proc := RunWithHandles(cmd, {in: hStdIn, out: hStdOut, err: hStdErr})
326
+ }
327
+ catch OSError as e {
328
+ if e.Number != 740 ; ERROR_ELEVATION_REQUIRED
329
+ throw
330
+ trace '![Launcher] elevation required; handles will not be redirected'
331
+ cmd := RegExReplace(cmd, ' /ErrorStdOut(?:=\S*)?')
332
+ Run cmd
333
+ ExitApp
334
+ }
335
+
336
+ ; When the /launch switch is used, return the process ID as the launcher's exit code.
337
+ if args.HasProp('launch')
338
+ return proc.pid
339
+
340
+ if waitClose {
341
+ ; Wait for either the child process or our parent process (if determined) to terminate.
342
+ NumPut 'ptr', proc.hProcess.ptr, 'ptr', hParent ? hParent.ptr : 0, waitHandles := Buffer(A_PtrSize*2)
343
+ loop {
344
+ Sleep -1
345
+ waitResult := DllCall("MsgWaitForMultipleObjects", "uint", 1 + (hParent != 0), "ptr", waitHandles, "int", 0, "uint", -1, "uint", 0x04FF)
346
+ } until waitResult = 0 || waitResult = 1
347
+ }
348
+
349
+ DllCall("GetExitCodeProcess", "ptr", proc.hProcess, "uint*", &exitCode:=0)
350
+ if trace.Enabled {
351
+ ; We have to return something numeric for ExitApp, so currently exitCode is left as 259
352
+ ; if the process is still running.
353
+ if exitCode = 259 && DllCall("WaitForSingleObject", "ptr", proc.hProcess, "uint", 0) = 258 { ; STILL_ACTIVE = 259, WAIT_TIMEOUT = 258
354
+ if !(hParent ?? 1) || (waitResult ?? -1) = 1
355
+ trace '>[Launcher] Process launched; now exiting because parent process has terminated.'
356
+ else if (parentName ?? "") = "explorer.exe"
357
+ trace '>[Launcher] Process launched; now exiting because parent is explorer.exe.'
358
+ else
359
+ trace '>[Launcher] Process launched; launcher exiting early.'
360
+ }
361
+ else
362
+ trace '>[Launcher] Exit code: ' exitCode
363
+ }
364
+
365
+ return exitCode
366
+ }
367
+
368
+ RunWithHandles(cmd, handles, workingDir:="") {
369
+ static STARTUPINFO_SIZE := A_PtrSize=8 ? 104 : 68
370
+ , STARTUPINFO_dwFlags := A_PtrSize=8 ? 60 : 44
371
+ , STARTUPINFO_hStdInput := A_PtrSize=8 ? 80 : 56
372
+ , STARTF_USESTDHANDLES := 0x100
373
+ , PROCESS_INFORMATION_SIZE := A_PtrSize=8 ? 24 : 16
374
+ HandleValue(p) => HasProp(handles, p) && (IsInteger(h := handles.%p%) ? h : h.Ptr)
375
+ si := Buffer(STARTUPINFO_SIZE, 0)
376
+ NumPut("uint", STARTUPINFO_SIZE, si)
377
+ NumPut("uint", STARTF_USESTDHANDLES, si, STARTUPINFO_dwFlags)
378
+ NumPut("ptr", HandleValue("in")
379
+ , "ptr", HandleValue("out")
380
+ , "ptr", HandleValue("err")
381
+ , si, STARTUPINFO_hStdInput)
382
+ pi := Buffer(PROCESS_INFORMATION_SIZE)
383
+ if !DllCall("CreateProcess", "ptr", 0, "str", cmd, "ptr", 0, "int", 0, "int", true
384
+ , "int", 0x08000000, "int", 0, "ptr", workingDir ? StrPtr(workingDir) : 0
385
+ , "ptr", si, "ptr", pi)
386
+ throw OSError(, -1, cmd)
387
+ return { hProcess: Handle(NumGet(pi, 0, "ptr"))
388
+ , hThread: Handle(NumGet(pi, A_PtrSize, "ptr"))
389
+ , pid: NumGet(pi, A_PtrSize*2, "uint") }
390
+ }
391
+
392
+ class VersionSelectGui extends AutoHotkeyUxGui {
393
+ __new(script, files) {
394
+ SplitPath script, &scriptName
395
+ super.__new("Run " scriptName " with", '-MinimizeBox')
396
+ DllCall('uxtheme\SetWindowThemeAttribute', 'ptr', this.hwnd, 'int', 1 ; WTA_NONCLIENT
397
+ , 'int64*', 2 | (2<<32), 'int', 8) ; WTNCA_NODRAWICON=2
398
+ lv := this.AddListMenu('vList LV0x40 w200', ["Version"])
399
+ lv.OnEvent('Focus', 'Focused')
400
+ lv.OnEvent('LoseFocus', 'Focused')
401
+ lv.OnEvent('Click', 'Confirm')
402
+ il := IL_Create(,, false)
403
+ lv.SetImageList(il, 0)
404
+ for f in this.files := files {
405
+ lv.Add('Icon' IL_Add(il, f.Path), f.Version " " StrReplace(f.Description, "AutoHotkey "))
406
+ }
407
+ lv.AutoSize(8)
408
+ lv.GetPos(&x, &y, &w, &h)
409
+ this.Show('AutoSize Hide')
410
+ this.AddButton('Default Hidden', "Confirm").OnEvent('Click', 'Confirm')
411
+ }
412
+
413
+ Confirm(*) {
414
+ if !(i := this['List'].GetNext())
415
+ return
416
+ this.selection := this.files[i]
417
+ this.Hide()
418
+ }
419
+
420
+ Focused(ctrl, *) {
421
+ OnMessage(0x101, keyup, ctrl.Focused)
422
+ static keyup(wParam, lParam, nmsg, hwnd) {
423
+ local this := GuiFromHwnd(hwnd, true)
424
+ if IsDigit(GetKeyName(Format("vk{:x}", wParam))) && this['List'].GetNext() {
425
+ this.Confirm()
426
+ return true
427
+ }
428
+ }
429
+ }
430
+ }
@@ -0,0 +1,22 @@
1
+ ; This file is part of a trick for allowing a v2 script to relaunch itself with
2
+ ; v2 when the user attempts to execute it with v1. See inc\bounce-v1.ahk.
3
+
4
+ #NoTrayIcon
5
+
6
+ if (A_ScriptFullPath = A_LineFile)
7
+ {
8
+ MsgBox 16,, This script is not meant to be executed.
9
+ ExitApp 2
10
+ }
11
+
12
+ if (!A_Args.Length())
13
+ {
14
+ Loop Files, %A_ScriptDir%\..\AutoHotkey32.exe, FR
15
+ {
16
+ Run "%A_LoopFileLongPath%" /force "%A_ScriptFullPath%"
17
+ ExitApp
18
+ }
19
+ }
20
+
21
+ MsgBox 16,, This script requires AutoHotkey v2, but was launched with v1.
22
+ ExitApp 2
@@ -0,0 +1,38 @@
1
+ ; This script clears any file type assocation made via the "open with" dialog,
2
+ ; so that the standard registration under HKCR\.ahk can take effect.
3
+ #include inc\bounce-v1.ahk
4
+ /* v1 stops here */
5
+ #requires AutoHotkey v2.0
6
+
7
+ keyname := "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.ahk\UserChoice"
8
+ initial_progid := RegRead(keyname, "ProgId", "")
9
+ legacy_key := "HKCU\Software\Classes\.ahk"
10
+ legacy_assoc := RegRead(legacy_key,, "AutoHotkeyScript")
11
+ if A_Args.Length && A_Args[1] = '/check' {
12
+ if (initial_progid = "" || initial_progid = "AutoHotkeyScript") && legacy_assoc = "AutoHotkeyScript"
13
+ || MsgBox("It looks like you've used an unsupported method to set the default program for .ahk files. "
14
+ . "This will prevent the standard context menu and launcher (version auto-detect) functionality "
15
+ . "from working. Would you like this setting to be reset for you?", "AutoHotkey", "Icon! y/n") != "yes"
16
+ ExitApp
17
+ }
18
+ reg_file_path := A_Temp "\reset-ahk-file-association.reg"
19
+ FileOpen(reg_file_path, "w").Write("Windows Registry Editor Version 5.00`n"
20
+ . "[-" keyname "]`n")
21
+ EnvSet "__COMPAT_LAYER", "RunAsInvoker"
22
+ RunWait 'regedit.exe /S "' reg_file_path '"'
23
+ EnvSet "__COMPAT_LAYER", ""
24
+ if legacy_assoc != "AutoHotkeyScript"
25
+ RegWrite "AutoHotkeyScript", "REG_SZ", legacy_key
26
+ DllCall("shell32\SHChangeNotify", "uint", 0x08000000, "uint", 0, "int", 0, "int", 0) ; SHCNE_ASSOCCHANGED
27
+ FileDelete reg_file_path
28
+ new_progid := RegRead(keyname, "ProgId", "")
29
+ if (new_progid != "" || A_LastError != 2)
30
+ MsgBox "Something went wrong and the reset probably "
31
+ . "didn't work.`n`nCurrent association: "
32
+ . (new_progid = "" ? "(unknown)" : new_progid), "AutoHotkey", "Icon!"
33
+ else if (initial_progid != "" || legacy_assoc != "AutoHotkeyScript")
34
+ MsgBox "Association of .ahk files for the current user has been reset.", "AutoHotkey", "Iconi"
35
+ else
36
+ MsgBox "It looks as though the current user's settings "
37
+ . "weren't overriding the default .ahk file options. A reset was "
38
+ . "attempted anyway, but it probably had no effect.", "AutoHotkey", "Icon!"