Puppeteer/core/OverrideBindings.lua
2025-08-15 08:43:59 -07:00

207 lines
6.3 KiB
Lua

-- Handles mouse wheel and key bindings
PTUtil.SetEnvironment(Puppeteer)
local _G = getfenv(0)
local util = PTUtil
_G.BINDING_HEADER_PUPPETEER = "Puppeteer (Don't Touch These)"
local bindingsNames = {}
local MAX_BINDINGS = 24
for i = 1, MAX_BINDINGS do
bindingsNames[i] = "PUPPETEERBINDING"..i
_G["BINDING_NAME_"..bindingsNames[i]] = "Dynamic Binding "..i
end
local bindingsNamesSet = util.ToSet(bindingsNames)
local BindingPrefixes = {
"",
"SHIFT-",
"CTRL-",
"ALT-",
"ALT-CTRL-SHIFT-",
"ALT-CTRL-",
"ALT-SHIFT-",
"CTRL-SHIFT-"
}
StoredBindings = {} -- Key: Baked keybind key(like "ALT-SHIFT-R") | Value: The stored value of the binding
IndexButtonMap = {} -- Key: Index corresponding to the binding | Value: Button name
KeybindIndexMap = {} -- Key: Baked keybind key | Value: Index corresponding to the binding
function InitOverrideBindingsMapping()
util.ClearTable(IndexButtonMap)
util.ClearTable(KeybindIndexMap)
local index = 1
for _, button in ipairs(PTOptions.Buttons) do
if not util.GetAllButtonsSet()[button] then
for _, prefix in ipairs(BindingPrefixes) do
KeybindIndexMap[prefix..button] = index
end
IndexButtonMap[index] = button
index = index + 1
end
end
for _, bindingName in ipairs(bindingsNames) do
local k1, k2, k3, k4, k5, k6, k7, k8 = GetBindingKey(bindingName)
for _, key in ipairs({k1, k2, k3, k4, k5, k6, k7, k8}) do
if key then
SetBinding(key, nil)
end
end
end
end
-- Stuff to stop expensive UPDATE_BINDINGS events as much as possible
local noOp = function() end
local updateBindingsFunctions = {}
local updateBindingsFrames = {}
local holdingFunctionsHostage = false
function AddUpdateBindingsFunction(funcName)
table.insert(updateBindingsFunctions, {
funcName = funcName
})
end
function AddUpdateBindingsFrame(frameName)
if _G[frameName] then
table.insert(updateBindingsFrames, {
frame = _G[frameName]
})
end
end
-- Alternative method
function HookUpdateBindingsFrame(frameName)
local frame = _G[frameName]
local realScript = frame:GetScript("OnEvent")
frame:SetScript("OnEvent", function()
if holdingFunctionsHostage then
return
end
realScript()
end)
end
AddUpdateBindingsFunction("ActionButton_OnEvent")
AddUpdateBindingsFunction("BonusActionButton_OnEvent")
AddUpdateBindingsFunction("PetActionButton_OnEvent")
AddUpdateBindingsFunction("CharacterMicroButton_OnEvent")
AddUpdateBindingsFunction("TalentMicroButton_OnEvent")
AddUpdateBindingsFrame("MainMenuMicroButton")
AddUpdateBindingsFrame("QuestLogMicroButton")
AddUpdateBindingsFrame("SocialsMicroButton")
AddUpdateBindingsFrame("WorldMapMicroButton")
util.RunLater(function()
AddUpdateBindingsFrame("pfActionBar") -- pfUI
AddUpdateBindingsFrame("DFRL_HotkeyBinding") -- Dragonflight Reloaded
end)
local function StopUpdateBindingsUpdates()
if holdingFunctionsHostage then
return
end
holdingFunctionsHostage = true
for _, entry in ipairs(updateBindingsFunctions) do
entry.func = _G[entry.funcName]
_G[entry.funcName] = noOp
end
for _, entry in ipairs(updateBindingsFrames) do
entry.func = entry.frame:GetScript("OnEvent")
entry.frame:SetScript("OnEvent", nil)
end
end
local function StartUpdateBindingsUpdates()
if not holdingFunctionsHostage then
return
end
for _, entry in ipairs(updateBindingsFunctions) do
_G[entry.funcName] = entry.func
end
for _, entry in ipairs(updateBindingsFrames) do
entry.frame:SetScript("OnEvent", entry.func)
end
holdingFunctionsHostage = false
end
-- End of UPDATE_BINDINGS mitigation
function ApplyOverrideBindings()
RemoveOverrideBindings()
StopUpdateBindingsUpdates()
for fullButton, index in pairs(KeybindIndexMap) do
local binding = GetBindingAction(fullButton)
if binding == "" then -- Lazy set the binding to our binding and don't touch until setting up again
SetBinding(fullButton, bindingsNames[index])
elseif not bindingsNamesSet[binding] then -- If it's not our binding, it must be stored and replaced
StoredBindings[fullButton] = binding
SetBinding(fullButton, bindingsNames[index])
end
end
StartUpdateBindingsUpdates()
end
function RemoveOverrideBindings()
if util.IsTableEmpty(StoredBindings) then
return
end
StopUpdateBindingsUpdates()
for button, binding in pairs(StoredBindings) do
SetBinding(button, binding)
end
StartUpdateBindingsUpdates()
util.ClearTable(StoredBindings)
end
function HandleKeyPress(index)
if not Mouseover then
return
end
local button = IndexButtonMap[index]
if keystate == "down" then
CurrentlyHeldButton = button
MouseoverFrame.pressed = true
MouseoverFrame:AdjustHealthPosition()
if button == "MOUSEWHEELUP" or button == "MOUSEWHEELDOWN" then
FakeMouseWheelHold(button)
end
ReapplySpellsTooltip()
if PTOptions.CastWhenKey == "Key Down" then
UnitFrame_OnClick(button, Mouseover, MouseoverFrame)
end
else
if button ~= "MOUSEWHEELUP" and button ~= "MOUSEWHEELDOWN" then
CurrentlyHeldButton = nil
MouseoverFrame.pressed = false
MouseoverFrame:AdjustHealthPosition()
ReapplySpellsTooltip()
end
if PTOptions.CastWhenKey == "Key Up" then
UnitFrame_OnClick(button, Mouseover, MouseoverFrame)
end
end
end
MouseWheelHeldFaker = CreateFrame("Frame", "PTMouseWheelHeldFaker")
local unholdAt
local unholdButton
local MouseWheelHeldFaker_OnUpdate = function()
if GetTime() >= unholdAt then
MouseWheelHeldFaker:SetScript("OnUpdate", nil)
if CurrentlyHeldButton == unholdButton then
CurrentlyHeldButton = nil
if MouseoverFrame then
MouseoverFrame.pressed = false
MouseoverFrame:AdjustHealthPosition()
end
ReapplySpellsTooltip()
end
end
end
function FakeMouseWheelHold(button)
unholdAt = GetTime() + 0.08
unholdButton = button
MouseWheelHeldFaker:SetScript("OnUpdate", MouseWheelHeldFaker_OnUpdate)
end