Skip to content

Commit d7f51d6

Browse files
authored
Merge pull request #13 from arlbibek/dev
Dev
2 parents e5dd032 + 7b9239e commit d7f51d6

File tree

8 files changed

+404
-17
lines changed

8 files changed

+404
-17
lines changed

WINDOWS.ahk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ try {
3333
#Include functions.ahk
3434
#Include hotkeys.ahk
3535
#Include hotstrings.ahk
36+
#Include function_keys_ui.ahk
3637

3738
; splash screen
3839
if FileExist(app_logo) {

assets/keyboardshortcuts.pdf

-737 KB
Binary file not shown.

function_keys_ui.ahk

Lines changed: 352 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,352 @@
1+
; AutoHotkey v2 Script - F-Key Manager GUI (Improved)
2+
; This script creates a GUI for managing F1-F12 key assignments
3+
4+
#SingleInstance Force
5+
#Include globals.ahk
6+
7+
; ============================================================================
8+
; UTILITY FUNCTIONS
9+
; ============================================================================
10+
11+
; Check if an array contains a specific value
12+
array_has_value(haystack, needle) {
13+
for index, value in haystack {
14+
if (value = needle)
15+
return true
16+
}
17+
return false
18+
}
19+
20+
; Read INI file section and return as Map
21+
get_ini_as_map(ini_file_path, ini_section) {
22+
section_records := Map()
23+
24+
if !FileExist(ini_file_path) {
25+
MsgBox("Config file not found: " . ini_file_path, "Error", "Icon!")
26+
return section_records
27+
}
28+
29+
try {
30+
section_data := IniRead(ini_file_path, ini_section)
31+
} catch Error as err {
32+
MsgBox("Failed to read section '" . ini_section . "' from: " . ini_file_path . "`nError: " . err.message, "Error", "Icon!")
33+
return section_records
34+
}
35+
36+
; Parse the section data
37+
loop parse, section_data, "`n", "`r" {
38+
line := Trim(A_LoopField)
39+
if (line = "" || SubStr(line, 1, 1) = ";") ; Skip empty lines and comments
40+
continue
41+
42+
pos := InStr(line, "=")
43+
if (pos > 0) {
44+
key := Trim(SubStr(line, 1, pos - 1))
45+
value := Trim(SubStr(line, pos + 1))
46+
if (key != "")
47+
section_records[key] := value
48+
}
49+
}
50+
51+
return section_records
52+
}
53+
54+
; File chooser dialog
55+
choose_file() {
56+
try {
57+
file_path := FileSelect(3, , "Select an executable file", "Executable Programs (*.exe)")
58+
return file_path ; Returns empty string if cancelled, not 0
59+
} catch Error as err {
60+
MsgBox("Error selecting file: " . err.message, "File Selection Error", "Icon!")
61+
return ""
62+
}
63+
}
64+
65+
; Get description text for function key assignment
66+
get_reference_text(program_path) {
67+
if (program_path = "")
68+
return "Click Browse to choose a program to run"
69+
70+
SplitPath(program_path, &basename)
71+
72+
switch basename {
73+
case "default_browser":
74+
return "Launch / cycle through the default browser window(s)"
75+
case "all_browsers":
76+
return "Launch default browser / cycle through all active browsers"
77+
case "browser_tabs":
78+
return "Launch default/active browser / cycle through active browser tabs"
79+
case "switch_window":
80+
return "Switch between two most recent active windows (Alt+Tab)"
81+
case "switch_tabs":
82+
return "Switch between multiple tabs in the same window (Ctrl+Tab)"
83+
default:
84+
return "Launch / switch to '" . basename . "'"
85+
}
86+
}
87+
88+
; Save configuration to INI file
89+
save_configuration() {
90+
try {
91+
for index, controls in g_FKeyControls {
92+
key := "f" . index
93+
selected_index := controls.dropdown.Value
94+
selected_value := g_FKeyManager.dropdown_values[selected_index]
95+
edit_value := controls.edit.Text
96+
97+
; Determine what to save based on dropdown selection
98+
value_to_save := (selected_value = "add_app_path") ? edit_value : selected_value
99+
100+
IniWrite(value_to_save, config_path, function_keys_section, key)
101+
}
102+
MsgBox("Configuration saved successfully!", "Success", "IconI")
103+
return true
104+
} catch Error as err {
105+
MsgBox("Failed to save configuration: " . err.message, "Error", "Icon!")
106+
return false
107+
}
108+
}
109+
110+
; ============================================================================
111+
; GUI CLASS DEFINITION
112+
; ============================================================================
113+
114+
class fkey_manager_gui {
115+
__New() {
116+
this.gui := ""
117+
this.controls := []
118+
this.function_keys_details := Map()
119+
this.text_labels := ["f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12"]
120+
this.dropdown_options := ["Custom Program", "Default Browser", "All Browsers", "Browser Tabs", "Switch Window", "Switch Tabs"]
121+
this.dropdown_values := ["add_app_path", "default_browser", "all_browsers", "browser_tabs", "switch_window", "switch_tabs"]
122+
}
123+
124+
Create() {
125+
; Load current configuration
126+
this.function_keys_details := get_ini_as_map(config_path, function_keys_section)
127+
128+
; Create main GUI
129+
this.gui := Gui(, "Function Keys Manager - " . A_ScriptName)
130+
this.gui.OnEvent("Close", (*) => this.gui.Hide())
131+
this.gui.OnEvent("Size", (*) => this.OnResize())
132+
133+
; Add header
134+
this.gui.Add("Text", "w420 h30 x10 y10", "Function Key Assignment Manager").SetFont("s12")
135+
this.gui.Add("Text", "w420 h20 x10 y40", "Configure what each Function key (F1 - F12) should do when pressed").SetFont("s9")
136+
137+
; Create controls for each F-key
138+
this.CreateFKeyControls()
139+
140+
; Add action buttons
141+
this.CreateActionButtons()
142+
143+
; Store reference globally for save function
144+
global g_FKeyControls := this.controls
145+
146+
return this.gui
147+
}
148+
149+
CreateFKeyControls() {
150+
y_pos := 70
151+
152+
Loop this.text_labels.Length {
153+
index := A_Index
154+
key := this.text_labels[index]
155+
current_value := this.function_keys_details.Get(key, "")
156+
157+
; Create control group for this F-key
158+
group := {}
159+
160+
; F-key label
161+
group.label := this.gui.Add("Text", "w25 h20 x10 y" . y_pos . " Center", StrUpper(key) . ":")
162+
163+
; Dropdown for action type
164+
group.dropdown := this.gui.Add("DropDownList", "w110 h20 x40 y" . y_pos, this.dropdown_options)
165+
group.dropdown.OnEvent("Change", this.OnDropdownChange.Bind(this, index))
166+
167+
; Edit box for custom path
168+
group.edit := this.gui.Add("Edit", "w270 h20 x155 y" . y_pos, current_value)
169+
group.edit.OnEvent("Change", this.OnEditChange.Bind(this, index))
170+
171+
; Browse button
172+
group.browse_btn := this.gui.Add("Button", "w50 h20 x375 y" . y_pos + 22, "Browse")
173+
group.browse_btn.OnEvent("Click", this.OnBrowseClick.Bind(this, index))
174+
175+
; Description text
176+
group.desc_text := this.gui.Add("Text", "w330 h20 x40 y" . (y_pos + 22), get_reference_text(current_value))
177+
group.desc_text.SetFont("s8 Italic c0x666666")
178+
179+
; Set initial dropdown selection and edit box state
180+
if (array_has_value(this.dropdown_values, current_value) && current_value != "") {
181+
; Find the index of the value and select corresponding option
182+
for i, val in this.dropdown_values {
183+
if (val = current_value) {
184+
group.dropdown.Choose(i)
185+
break
186+
}
187+
}
188+
group.edit.Text := current_value
189+
group.edit.Enabled := false
190+
group.browse_btn.Enabled := false
191+
} else {
192+
group.dropdown.Choose(1) ; "Custom Program"
193+
group.edit.Text := current_value ; Show the custom path
194+
group.edit.Enabled := true
195+
group.browse_btn.Enabled := true
196+
}
197+
198+
this.controls.Push(group)
199+
y_pos += 45
200+
}
201+
}
202+
203+
CreateActionButtons() {
204+
y_pos := 70 + (this.text_labels.Length * 45) + 15
205+
206+
; Save button
207+
save_btn := this.gui.Add("Button", "w70 h30 x10 y" . y_pos, "Save")
208+
save_btn.OnEvent("Click", (*) => save_configuration())
209+
210+
; Restore button
211+
restore_btn := this.gui.Add("Button", "w70 h30 x90 y" . y_pos, "Restore")
212+
restore_btn.OnEvent("Click", (*) => this.RestoreConfig())
213+
214+
; Clear button
215+
clear_btn := this.gui.Add("Button", "w70 h30 x170 y" . y_pos, "Clear All")
216+
clear_btn.OnEvent("Click", (*) => this.ClearAll())
217+
218+
; Close button
219+
close_btn := this.gui.Add("Button", "w70 h30 x355 y" . y_pos, "Close")
220+
close_btn.OnEvent("Click", (*) => this.gui.Hide())
221+
}
222+
223+
OnDropdownChange(index, *) {
224+
group := this.controls[index]
225+
selected_index := group.dropdown.Value
226+
selected_value := this.dropdown_values[selected_index]
227+
228+
if (selected_value = "add_app_path") {
229+
group.edit.Enabled := true
230+
group.browse_btn.Enabled := true
231+
; Keep the current custom path if it exists
232+
current_value := this.function_keys_details.Get(this.text_labels[index], "")
233+
if (!array_has_value(this.dropdown_values, current_value)) {
234+
group.edit.Text := current_value
235+
} else {
236+
group.edit.Text := ""
237+
}
238+
group.edit.Focus()
239+
} else {
240+
group.edit.Enabled := false
241+
group.browse_btn.Enabled := false
242+
group.edit.Text := selected_value
243+
}
244+
245+
this.UpdateDescription(index)
246+
}
247+
248+
OnEditChange(index, *) {
249+
this.UpdateDescription(index)
250+
}
251+
252+
OnBrowseClick(index, *) {
253+
group := this.controls[index]
254+
selected_file := choose_file()
255+
256+
if (selected_file != "" && selected_file != 0) { ; choose_file returns 0 on cancel
257+
group.edit.Text := selected_file
258+
; Ensure dropdown is set to "Custom Program" when browsing for custom file
259+
group.dropdown.Choose(1)
260+
group.edit.Enabled := true
261+
group.browse_btn.Enabled := true
262+
this.UpdateDescription(index)
263+
}
264+
}
265+
266+
UpdateDescription(index) {
267+
group := this.controls[index]
268+
selected_index := group.dropdown.Value
269+
selected_value := this.dropdown_values[selected_index]
270+
current_value := (selected_value = "add_app_path") ? group.edit.Text : selected_value
271+
group.desc_text.Text := get_reference_text(current_value)
272+
}
273+
274+
RestoreConfig() {
275+
result := MsgBox("This will restore all Function keys assignments from the last saved configuration. `n`nAny unsaved changes will be lost. Continue?", "Restore Configuration", "YesNo Icon?")
276+
if (result = "Yes") {
277+
; Reload configuration from file
278+
this.function_keys_details := get_ini_as_map(config_path, function_keys_section)
279+
280+
; Update all controls with restored values
281+
Loop this.controls.Length {
282+
index := A_Index
283+
group := this.controls[index]
284+
key := this.text_labels[index]
285+
restored_value := this.function_keys_details.Get(key, "")
286+
287+
; Set dropdown and edit box based on restored value
288+
if (array_has_value(this.dropdown_values, restored_value) && restored_value != "") {
289+
; Find the index of the value and select corresponding option
290+
for i, val in this.dropdown_values {
291+
if (val = restored_value) {
292+
group.dropdown.Choose(i)
293+
break
294+
}
295+
}
296+
group.edit.Text := restored_value
297+
group.edit.Enabled := false
298+
group.browse_btn.Enabled := false
299+
} else {
300+
group.dropdown.Choose(1) ; "Custom Program"
301+
group.edit.Text := restored_value
302+
group.edit.Enabled := true
303+
group.browse_btn.Enabled := true
304+
}
305+
306+
this.UpdateDescription(index)
307+
}
308+
309+
MsgBox("Configuration restored from file successfully!", "Restore Complete", "Icon!")
310+
}
311+
}
312+
313+
ClearAll() {
314+
Loop this.controls.Length {
315+
group := this.controls[A_Index]
316+
group.dropdown.Choose(1) ; "Custom Program"
317+
group.edit.Text := ""
318+
group.edit.Enabled := true
319+
group.browse_btn.Enabled := true
320+
this.UpdateDescription(A_Index)
321+
}
322+
}
323+
324+
OnResize() {
325+
; Handle window resize if needed
326+
; This could be expanded to make the GUI more responsive
327+
}
328+
329+
Show() {
330+
this.gui.Show()
331+
}
332+
333+
Hide() {
334+
this.gui.Hide()
335+
}
336+
}
337+
338+
; ============================================================================
339+
; MAIN EXECUTION
340+
; ============================================================================
341+
342+
; Create global reference
343+
global g_FKeyManager := ""
344+
global g_FKeyControls := []
345+
346+
; Initialize and show GUI
347+
initialize_fkey_manager(*) {
348+
global g_FKeyManager
349+
g_FKeyManager := fkey_manager_gui()
350+
g_FKeyManager.Create()
351+
g_FKeyManager.Show()
352+
}

functions.ahk

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,4 +415,19 @@ send_alt_tab(*) {
415415
send_ctrl_tab(*) {
416416
; sends Ctrl + tab to switch window
417417
Send("{Ctrl Down}{Tab}{Ctrl UP}")
418+
}
419+
420+
run_wait_one(command, *) {
421+
; command execution
422+
try {
423+
shell := ComObject("WScript.Shell")
424+
exec := shell.Exec(command)
425+
; Wait for completion without timeout
426+
while exec.Status = 0 {
427+
Sleep(50)
428+
}
429+
return exec.StdOut.ReadAll()
430+
} catch Error as e {
431+
throw Error("Command execution failed: " e.Message)
432+
}
418433
}

0 commit comments

Comments
 (0)