diff --git a/src/Main_Class.ahk b/src/Main_Class.ahk index 2ebb31b..4f4a917 100644 --- a/src/Main_Class.ahk +++ b/src/Main_Class.ahk @@ -40,6 +40,11 @@ Class Main_Class extends ThumbWindow { EventHooks := Map() ThumbWindows := {} ThumbHwnd_EvEHwnd := Map() + AutoForwardGroups := [] + AutoForwardEnabled := Map() ; Map of group index => enabled state + AutoForwardVisited := Map() ; Map of group index => array of visited window names + AutoForwardToggleMode := Map() ; Map of group index => toggle mode setting + AutoForwardProcessedWindow := 0 ; Track which window hwnd already got its input processed __New() { @@ -207,12 +212,13 @@ Class Main_Class extends ThumbWindow { static registerGroups := 0 ;if the user has set Hotkeys in Options if (This._Hotkeys[title]) { + hk := This._Hotkeys[title] ;if the user has selected Global Hotkey. This means the Hotkey will alsways trigger as long at least 1 EVE Window exist. ;if a Window does not Exist which was assigned to the hotkey the hotkey will be dissabled until the Window exist again if(This.Global_Hotkeys) { - HotIf (*) => WinExist(This.EVEExe) && WinExist("EVE - " title ) && !WinActive("EVE-X-Preview - Settings") + HotIf (*) => WinExist(This.EVEExe) && WinExist("EVE - " title ) && !WinActive("EVE-X-Preview - Settings") && !This.HasExtraModifiers(hk) try { - Hotkey This._Hotkeys[title], (*) => This.ActivateEVEWindow(,,title), "P1" + Hotkey hk, (*) => This.ActivateEVEWindow(,,title), "P1" } catch ValueError as e { MsgBox(e.Message ": --> " e.Extra " <-- in Profile Settings - " This.LastUsedProfile " Hotkeys" ) @@ -221,15 +227,35 @@ Class Main_Class extends ThumbWindow { ;if the user has selected (Win Active) the hotkeys will only trigger if at least 1 EVE Window is Active and in Focus ;This makes it possible to still use all keys outside from EVE else { - HotIf (*) => WinExist("EVE - " title ) && WinActive(This.EVEExe) + HotIf (*) => WinExist("EVE - " title ) && WinActive(This.EVEExe) && !This.HasExtraModifiers(hk) try { - Hotkey This._Hotkeys[title], (*) => This.ActivateEVEWindow(,,title),"P1" + Hotkey hk, (*) => This.ActivateEVEWindow(,,title),"P1" } catch ValueError as e { MsgBox(e.Message ": --> " e.Extra " <-- in Profile Settings - " This.LastUsedProfile " Hotkeys" ) } } } + } + + ; Check if extra modifiers are pressed beyond what's in the hotkey string + HasExtraModifiers(hk) { + ; Check which modifiers are in the hotkey + hasCtrl := InStr(hk, "^") || InStr(hk, "ctrl", false) + hasAlt := InStr(hk, "!") || InStr(hk, "alt", false) + hasShift := InStr(hk, "+") || InStr(hk, "shift", false) + hasWin := InStr(hk, "#") || InStr(hk, "win", false) + + ; Return true if any modifier is pressed that's NOT in the hotkey + if (!hasCtrl && GetKeyState("Ctrl", "P")) + return true + if (!hasAlt && GetKeyState("Alt", "P")) + return true + if (!hasShift && GetKeyState("Shift", "P")) + return true + if (!hasWin && (GetKeyState("LWin", "P") || GetKeyState("RWin", "P"))) + return true + return false } Register_CharSelectionScreen_Hotkeys(){ @@ -283,9 +309,13 @@ Class Main_Class extends ThumbWindow { static Fkey := "", BKey := "", Arr := [] if (IsObject(This.Hotkey_Groups) && This.Hotkey_Groups.Count != 0) { for k, v in This.Hotkey_Groups { + ; Check if auto-forward is enabled for this group + hasAutoForward := v.Has("AutoForwardOnKeypress") && v["AutoForwardOnKeypress"] + ;If any EVE Window Exist and at least 1 character matches the the list from the group windows if(This.Global_Hotkeys) { - if( v["ForwardsHotkey"] != "" ) { + ; Only register normal forwards hotkey if auto-forward is NOT enabled + if( v["ForwardsHotkey"] != "" && !hasAutoForward) { Fkey := v["ForwardsHotkey"], Arr := v["Characters"] HotIf ObjBindMethod(This, "OnWinExist", Arr) try { @@ -308,7 +338,8 @@ Class Main_Class extends ThumbWindow { } ;If any EVE Window is Active else { - if( v["ForwardsHotkey"] != "" ) { + ; Only register normal forwards hotkey if auto-forward is NOT enabled + if( v["ForwardsHotkey"] != "" && !hasAutoForward) { Fkey := v["ForwardsHotkey"], Arr := v["Characters"] HotIf ObjBindMethod(This, "OnWinActive", Arr) try { @@ -328,7 +359,176 @@ Class Main_Class extends ThumbWindow { MsgBox(e.Message ": --> " e.Extra " <-- in Profile Settings - " This.LastUsedProfile " Hotkey Groups - " k " - Backwards Hotkey" ) } } - } + } + ; Store auto-forward groups and register toggle hotkey + if (hasAutoForward) { + groupIdx := This.AutoForwardGroups.Length + 1 + This.AutoForwardGroups.Push(v["Characters"]) + This.AutoForwardEnabled[groupIdx] := false + This.AutoForwardVisited[groupIdx] := [] + This.AutoForwardToggleMode[groupIdx] := v.Has("AutoForwardToggle") ? v["AutoForwardToggle"] : true + + ; Register the forwards hotkey as toggle + if (v["ForwardsHotkey"] != "") { + if(This.Global_Hotkeys) { + HotIf ObjBindMethod(This, "OnWinExist", v["Characters"]) + } else { + HotIf ObjBindMethod(This, "OnWinActive", v["Characters"]) + } + try { + Hotkey(v["ForwardsHotkey"], ObjBindMethod(This, "ToggleAutoForward", groupIdx, v["Characters"]), "P1") + } + catch ValueError as e { + MsgBox(e.Message ": --> " e.Extra " <-- in Profile Settings - " This.LastUsedProfile " - Hotkey Groups - " k " - Forwards Hotkey (Toggle)" ) + } + } + } + } + } + ; Register keyboard/mouse hook if any auto-forward groups exist + if (This.AutoForwardGroups.Length > 0) { + This.RegisterAutoForwardHook() + } + } + + ; Toggle auto-forward for a group + ToggleAutoForward(groupIdx, Arr, *) { + if (This.AutoForwardEnabled[groupIdx]) { + ; Disable + This.AutoForwardEnabled[groupIdx] := false + This.AutoForwardVisited[groupIdx] := [] + } else { + ; Enable and mark current window as first visited + This.AutoForwardEnabled[groupIdx] := true + This.AutoForwardVisited[groupIdx] := [] + This.AutoForwardProcessedWindow := 0 ; Reset so current window can receive input + try { + ActiveTitle := This.CleanTitle(WinGetTitle("A")) + This.AutoForwardVisited[groupIdx].Push(ActiveTitle) + } + } + } + + ; Register a low-level input hook for auto-forward + RegisterAutoForwardHook() { + ; Use low-level keyboard hook to catch ALL keys including with modifiers + This.KeyboardHook := DllCall("SetWindowsHookEx", "Int", 13, "Ptr", CallbackCreate(ObjBindMethod(This, "LowLevelKeyboardProc"), "Fast", 3), "Ptr", 0, "UInt", 0, "Ptr") + ; Use low-level mouse hook + This.MouseHook := DllCall("SetWindowsHookEx", "Int", 14, "Ptr", CallbackCreate(ObjBindMethod(This, "LowLevelMouseProc"), "Fast", 3), "Ptr", 0, "UInt", 0, "Ptr") + } + + ; Low-level mouse hook callback + LowLevelMouseProc(nCode, wParam, lParam) { + static WM_LBUTTONDOWN := 0x201, WM_RBUTTONDOWN := 0x204, WM_MBUTTONDOWN := 0x207 + + if (nCode >= 0 && (wParam = WM_LBUTTONDOWN || wParam = WM_RBUTTONDOWN || wParam = WM_MBUTTONDOWN)) { + if (This.IsAutoForwardActive()) { + try { + currentWindow := WinGetID("A") + ; Only process if this window hasn't been processed yet + if (currentWindow != This.AutoForwardProcessedWindow) { + This.AutoForwardProcessedWindow := currentWindow + ; Must defer out of hook context + SetTimer(ObjBindMethod(This, "TriggerAutoForward"), -1) + } + } + } + } + return DllCall("CallNextHookEx", "Ptr", 0, "Int", nCode, "Ptr", wParam, "Ptr", lParam) + } + + ; Low-level keyboard hook callback + LowLevelKeyboardProc(nCode, wParam, lParam) { + static WM_KEYDOWN := 0x100, WM_SYSKEYDOWN := 0x104 + + if (nCode >= 0 && (wParam = WM_KEYDOWN || wParam = WM_SYSKEYDOWN)) { + vkCode := NumGet(lParam, 0, "UInt") + ; Ignore modifier keys themselves + if (vkCode = 0x10 || vkCode = 0x11 || vkCode = 0x12 + || vkCode = 0x5B || vkCode = 0x5C + || vkCode = 0xA0 || vkCode = 0xA1 || vkCode = 0xA2 + || vkCode = 0xA3 || vkCode = 0xA4 || vkCode = 0xA5) { + return DllCall("CallNextHookEx", "Ptr", 0, "Int", nCode, "Ptr", wParam, "Ptr", lParam) + } + + if (This.IsAutoForwardActive()) { + try { + currentWindow := WinGetID("A") + ; Only process if this window hasn't been processed yet + if (currentWindow != This.AutoForwardProcessedWindow) { + This.AutoForwardProcessedWindow := currentWindow + ; Must defer out of hook context - SetTimer -1 runs immediately after hook returns + SetTimer(ObjBindMethod(This, "TriggerAutoForward"), -1) + } + } + } + } + ; Always pass to next hook + return DllCall("CallNextHookEx", "Ptr", 0, "Int", nCode, "Ptr", wParam, "Ptr", lParam) + } + + ; Check if any auto-forward group window is active AND enabled + IsAutoForwardActive() { + try { + ActiveTitle := This.CleanTitle(WinGetTitle("A")) + for groupIdx, Arr in This.AutoForwardGroups { + if (This.AutoForwardEnabled[groupIdx] && This.OnWinActive(Arr)) { + for index, name in Arr { + if (name = ActiveTitle) + return true + } + } + } + } + return false + } + + ; Check if current window should auto-forward and trigger it + TriggerAutoForward() { + try { + ActiveTitle := This.CleanTitle(WinGetTitle("A")) + for groupIdx, Arr in This.AutoForwardGroups { + if (!This.AutoForwardEnabled[groupIdx]) + continue + if (This.OnWinActive(Arr)) { + for index, name in Arr { + if (name = ActiveTitle) { + This.Cycle_Hotkey_Groups(Arr, "ForwardsHotkey") + + ; Update processed window to the NEW window after cycling + try This.AutoForwardProcessedWindow := WinGetID("A") + + ; Track visited window + try { + newTitle := This.CleanTitle(WinGetTitle("A")) + alreadyVisited := false + for visited in This.AutoForwardVisited[groupIdx] { + if (visited = newTitle) { + alreadyVisited := true + break + } + } + if (!alreadyVisited) { + This.AutoForwardVisited[groupIdx].Push(newTitle) + } + + ; If not toggle mode, check if all windows visited + if (!This.AutoForwardToggleMode[groupIdx]) { + existingCount := 0 + for n in Arr { + if (WinExist("EVE - " n " Ahk_Exe exefile.exe")) + existingCount++ + } + if (This.AutoForwardVisited[groupIdx].Length >= existingCount) { + This.AutoForwardEnabled[groupIdx] := false + This.AutoForwardVisited[groupIdx] := [] + } + } + } + return + } + } + } } } } @@ -810,4 +1010,3 @@ Class Main_Class extends ThumbWindow { FileAppend(JSON.Dump(This._JSON, , " "), "EVE-X-Preview.json") } } - diff --git a/src/Propertys.ahk b/src/Propertys.ahk index 27ccfc2..58f147b 100644 --- a/src/Propertys.ahk +++ b/src/Propertys.ahk @@ -415,7 +415,7 @@ class Propertys extends TrayMenu { return This._JSON["_Profiles"][This.LastUsedProfile]["Hotkey Groups"] } set { - This._JSON["_Profiles"][This.LastUsedProfile]["Hotkey Groups"][Key] := Map("Characters", value, "ForwardsHotkey", "", "BackwardsHotkey", "") + This._JSON["_Profiles"][This.LastUsedProfile]["Hotkey Groups"][Key] := Map("Characters", value, "ForwardsHotkey", "", "BackwardsHotkey", "", "AutoForwardOnKeypress", 0, "AutoForwardToggle", 1) } } ; Hotkey_Groups_Hotkeys[Name?, Hotkey?] { diff --git a/src/Settings_Gui.ahk b/src/Settings_Gui.ahk index 975bbf0..35e9688 100644 --- a/src/Settings_Gui.ahk +++ b/src/Settings_Gui.ahk @@ -412,6 +412,15 @@ Hotkey_Groups.Push HKBackwards This.S_Gui["BackwardsdKey"].OnEvent("Change", (obj, *) => SaveHKGroupList(obj)) + Hotkey_Groups.Push This.S_Gui.Add("Text", "xp yp50", "Auto-Forward:") + AutoForwardCB := This.S_Gui.Add("Checkbox", "xp yp+20 Disabled vAutoForwardOnKeypress", "Forward on any keypress") + Hotkey_Groups.Push AutoForwardCB + This.S_Gui["AutoForwardOnKeypress"].OnEvent("Click", (obj, *) => SaveAutoForward(obj)) + + AutoForwardToggleCB := This.S_Gui.Add("Checkbox", "xp yp+20 Disabled vAutoForwardToggle", "Toggle mode (else: disable after full cycle)") + Hotkey_Groups.Push AutoForwardToggleCB + This.S_Gui["AutoForwardToggle"].OnEvent("Click", (obj, *) => SaveAutoForwardToggle(obj)) + This.S_Gui.Controls.Profile_Settings.PsDDL["Hotkey Groups"] := Hotkey_Groups for k, v in This.S_Gui.Controls.Profile_Settings.PsDDL["Hotkey Groups"] v.Visible := 0 @@ -433,6 +442,8 @@ } EditObj.value := "", ForwardHKObj.value := "", BackwardHKObj.value := "" ForwardHKObj.Enabled := 1, BackwardHKObj.Enabled := 1, EditObj.Enabled := 1 + AutoForwardCB.value := 0, AutoForwardCB.Enabled := 1 + AutoForwardToggleCB.value := 1, AutoForwardToggleCB.Enabled := 1 ddlObj.Choose(ArrayIndex) This.NeedRestart := 1 SetTimer(This.Save_Settings_Delay_Timer, -200) @@ -446,6 +457,8 @@ ddlObj.Add(This.GetGroupList()) ForwardHKObj.value := "", BackwardHKObj.value := "", EditObj.value := "" ForwardHKObj.Enabled := 0, BackwardHKObj.Enabled := 0, EditObj.Enabled := 0 + AutoForwardCB.value := 0, AutoForwardCB.Enabled := 0 + AutoForwardToggleCB.value := 0, AutoForwardToggleCB.Enabled := 0 This.NeedRestart := 1 SetTimer(This.Save_Settings_Delay_Timer, -200) @@ -460,6 +473,10 @@ EditObj.value := text, EditObj.Enabled := 1 ForwardHKObj.value := This.Hotkey_Groups[ddlObj.Text]["ForwardsHotkey"], ForwardHKObj.Enabled := 1 BackwardHKObj.value := This.Hotkey_Groups[ddlObj.Text]["BackwardsHotkey"], BackwardHKObj.Enabled := 1 + AutoForwardCB.value := This.Hotkey_Groups[ddlObj.Text].Has("AutoForwardOnKeypress") ? This.Hotkey_Groups[ddlObj.Text]["AutoForwardOnKeypress"] : 0 + AutoForwardCB.Enabled := 1 + AutoForwardToggleCB.value := This.Hotkey_Groups[ddlObj.Text].Has("AutoForwardToggle") ? This.Hotkey_Groups[ddlObj.Text]["AutoForwardToggle"] : 1 + AutoForwardToggleCB.Enabled := 1 } } @@ -483,6 +500,22 @@ This.NeedRestart := 1 SetTimer(This.Save_Settings_Delay_Timer, -200) } + + SaveAutoForward(obj) { + if (ddl.Text != "") { + This.Hotkey_Groups[ddl.Text]["AutoForwardOnKeypress"] := obj.value + This.NeedRestart := 1 + SetTimer(This.Save_Settings_Delay_Timer, -200) + } + } + + SaveAutoForwardToggle(obj) { + if (ddl.Text != "") { + This.Hotkey_Groups[ddl.Text]["AutoForwardToggle"] := obj.value + This.NeedRestart := 1 + SetTimer(This.Save_Settings_Delay_Timer, -200) + } + } }