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.
- package/.editorconfig +9 -0
- package/.eslintignore +3 -0
- package/.eslintrc.js +55 -0
- package/.jsdoc +25 -0
- package/AutoHotkey_2.0.19/AutoHotkey.chm +0 -0
- package/AutoHotkey_2.0.19/AutoHotkey32.exe +0 -0
- package/AutoHotkey_2.0.19/AutoHotkey64.exe +0 -0
- package/AutoHotkey_2.0.19/Install.cmd +2 -0
- package/AutoHotkey_2.0.19/UX/Templates/Minimal for v2.ahk +6 -0
- package/AutoHotkey_2.0.19/UX/WindowSpy.ahk +246 -0
- package/AutoHotkey_2.0.19/UX/inc/CommandLineToArgs.ahk +12 -0
- package/AutoHotkey_2.0.19/UX/inc/CreateAppShortcut.ahk +37 -0
- package/AutoHotkey_2.0.19/UX/inc/EnableUIAccess.ahk +246 -0
- package/AutoHotkey_2.0.19/UX/inc/GetGitHubReleaseAssetURL.ahk +26 -0
- package/AutoHotkey_2.0.19/UX/inc/HashFile.ahk +96 -0
- package/AutoHotkey_2.0.19/UX/inc/README.txt +3 -0
- package/AutoHotkey_2.0.19/UX/inc/ShellRun.ahk +7 -0
- package/AutoHotkey_2.0.19/UX/inc/bounce-v1.ahk +3 -0
- package/AutoHotkey_2.0.19/UX/inc/common.ahk +21 -0
- package/AutoHotkey_2.0.19/UX/inc/config.ahk +13 -0
- package/AutoHotkey_2.0.19/UX/inc/identify.ahk +29 -0
- package/AutoHotkey_2.0.19/UX/inc/identify_regex.ahk +4 -0
- package/AutoHotkey_2.0.19/UX/inc/launcher-common.ahk +78 -0
- package/AutoHotkey_2.0.19/UX/inc/spy.ico +0 -0
- package/AutoHotkey_2.0.19/UX/inc/ui-base.ahk +129 -0
- package/AutoHotkey_2.0.19/UX/install-ahk2exe.ahk +53 -0
- package/AutoHotkey_2.0.19/UX/install-version.ahk +109 -0
- package/AutoHotkey_2.0.19/UX/install.ahk +1056 -0
- package/AutoHotkey_2.0.19/UX/launcher.ahk +430 -0
- package/AutoHotkey_2.0.19/UX/reload-v1.ahk +22 -0
- package/AutoHotkey_2.0.19/UX/reset-assoc.ahk +38 -0
- package/AutoHotkey_2.0.19/UX/ui-dash.ahk +200 -0
- package/AutoHotkey_2.0.19/UX/ui-editor.ahk +238 -0
- package/AutoHotkey_2.0.19/UX/ui-launcherconfig.ahk +195 -0
- package/AutoHotkey_2.0.19/UX/ui-newscript.ahk +296 -0
- package/AutoHotkey_2.0.19/UX/ui-setup.ahk +175 -0
- package/AutoHotkey_2.0.19/UX/ui-uninstall.ahk +68 -0
- package/AutoHotkey_2.0.19/WindowSpy.ahk +2 -0
- package/AutoHotkey_2.0.19/license.txt +351 -0
- package/AutoHotkey_2.0.19/zclick.ahk +5 -0
- package/AutoHotkey_2.0.19/zrun_click.bat +2 -0
- package/AutoHotkey_2.0.19/zrun_send.bat +2 -0
- package/AutoHotkey_2.0.19/zsend.ahk +4 -0
- package/LICENSE +21 -0
- package/README.md +23 -0
- package/SECURITY.md +5 -0
- package/_tmp/view.all.png +0 -0
- package/_tmp/view.det.png +0 -0
- package/babel.config.js +16 -0
- package/dist/action.umd.js +32 -0
- package/dist/action.umd.js.map +1 -0
- package/dist/ck-pic.umd.js +7 -0
- package/dist/ck-pic.umd.js.map +1 -0
- package/dist/compare.umd.js +7 -0
- package/dist/compare.umd.js.map +1 -0
- package/dist/get-settings.umd.js +7 -0
- package/dist/get-settings.umd.js.map +1 -0
- package/dist/mousekey.umd.js +7 -0
- package/dist/mousekey.umd.js.map +1 -0
- package/dist/screen.umd.js +7 -0
- package/dist/screen.umd.js.map +1 -0
- package/docs/fonts/Montserrat/Montserrat-Bold.eot +0 -0
- package/docs/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
- package/docs/fonts/Montserrat/Montserrat-Bold.woff +0 -0
- package/docs/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
- package/docs/fonts/Montserrat/Montserrat-Regular.eot +0 -0
- package/docs/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
- package/docs/fonts/Montserrat/Montserrat-Regular.woff +0 -0
- package/docs/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +978 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +1049 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
- package/docs/index.html +84 -0
- package/docs/scripts/collapse.js +39 -0
- package/docs/scripts/commonNav.js +28 -0
- package/docs/scripts/linenumber.js +25 -0
- package/docs/scripts/nav.js +12 -0
- package/docs/scripts/polyfill.js +4 -0
- package/docs/scripts/prettify/Apache-License-2.0.txt +202 -0
- package/docs/scripts/prettify/lang-css.js +2 -0
- package/docs/scripts/prettify/prettify.js +28 -0
- package/docs/scripts/search.js +99 -0
- package/docs/styles/jsdoc.css +776 -0
- package/docs/styles/prettify.css +80 -0
- package/g.mjs +46 -0
- package/g.test_opencv.mjs +36 -0
- package/package.json +41 -0
- package/pic/view.png +0 -0
- package/script.txt +17 -0
- package/src/action.mjs +132 -0
- package/src/ckPic.mjs +95 -0
- package/src/compare.mjs +201 -0
- package/src/getSettings.mjs +17 -0
- package/src/mousekey.mjs +95 -0
- package/src/screen.mjs +62 -0
- package/test/WMousekey.test.mjs +11 -0
- package/toolg/addVersion.mjs +4 -0
- package/toolg/cleanFolder.mjs +4 -0
- package/toolg/gDistRollup.mjs +33 -0
- 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!"
|