if Binder then return end Binder = {} local Binder = Binder -- Localize builtin functions we use local ipairs = ipairs local next = next local pairs = pairs local tinsert = table.insert -- Localize ESO API functions we use local d = d local strjoin = zo_strjoin local strsplit = zo_strsplit local GetNumActionLayers = GetNumActionLayers local GetActionLayerInfo = GetActionLayerInfo local GetActionLayerCategoryInfo = GetActionLayerCategoryInfo local GetActionInfo = GetActionInfo local GetActionIndicesFromName = GetActionIndicesFromName local function print(...) d(strjoin("", ...)) end function Binder.BuildActionTables() local actionHierarchy = {} local actionNames = {} local layers = GetNumActionLayers() for layerIndex=1, layers do local layerName, categories = GetActionLayerInfo(layerIndex) local layer = {} for categoryIndex=1, categories do local category = {} local categoryName, actions = GetActionLayerCategoryInfo(layerIndex, categoryIndex) for actionIndex=1, actions do local actionName, isRebindable, isHidden = GetActionInfo(layerIndex, categoryIndex, actionIndex) if isRebindable then local action = { ["name"] = actionName, ["rebind"] = isRebindable, ["hidden"] = isHidden, } category[actionIndex] = action tinsert(actionNames, actionName) end end if next(category) ~= nil then category["name"] = categoryName layer[categoryIndex] = category end end if next(layer) ~= nil then layer["name"] = layerName actionHierarchy[layerIndex] = layer end end Binder.actionHierarchy = actionHierarchy Binder.actionNames = actionNames end function Binder.BuildBindingsTable() if not Binder.actionNames then Binder.BuildActionTables() end local bindings = {} local bindCount = 0 local maxBindings = GetMaxBindingsPerAction() for index, actionName in ipairs(Binder.actionNames) do local layerIndex, categoryIndex, actionIndex = GetActionIndicesFromName(actionName) local actionBindings = {} for bindIndex=1, maxBindings do local keyCode, mod1, mod2, mod3, mod4 = GetActionBindingInfo(layerIndex, categoryIndex, actionIndex, bindIndex) if keyCode ~= 0 then local bind = { ["keyCode"] = keyCode, ["mod1"] = mod1, ["mod2"] = mod2, ["mod3"] = mod3, ["mod4"] = mod4, } tinsert(actionBindings, bind) bindCount = bindCount + 1 end end bindings[actionName] = actionBindings end Binder.bindings = bindings Binder.bindCount = bindCount end function Binder.RestoreBindingsFromTable() local bindCount = 0 local skippedBindCount = 0 local maxBindings = GetMaxBindingsPerAction() for actionName, actionBindings in pairs(Binder.bindings) do local layerIndex, categoryIndex, actionIndex = GetActionIndicesFromName(actionName) CallSecureProtected("UnbindAllKeysFromAction", layerIndex, categoryIndex, actionIndex) for bindingIndex, bind in ipairs(actionBindings) do if bindingIndex <= maxBindings then CallSecureProtected("BindKeyToAction", layerIndex, categoryIndex, actionIndex, bindingIndex, bind["keyCode"], bind["mod1"], bind["mod2"], bind["mod3"], bind["mod4"]) bindCount = bindCount + 1 else skippedBindCount = skippedBindCount + 1 end end end end function Binder.SaveBindings(bindSetName) if bindSetName == nil or bindSetName == "" then print("Usage: /binder save <set name>") return end Binder.BuildBindingsTable() Binder.savedVariables.bindings[bindSetName] = Binder.bindings print("Saved ", Binder.bindCount, " bindings to bind set '", bindSetName, "'.") end function Binder.LoadBindings(bindSetName) if bindSetName == nil or bindSetName == "" then print("Usage: /binder load <set name>") return end if Binder.savedVariables.bindings[bindSetName] == nil then print("Bind set '", bindSetName, "' does not exist.") return end Binder.bindings = Binder.savedVariables.bindings[bindSetName] Binder.RestoreBindingsFromTable() print("Loaded ", Binder.bindCount, " bindings from bind set '", bindSetName, "'.") end function Binder.ListBindings() local sets = {} for setName in pairs(Binder.savedVariables.bindings) do table.insert(sets, setName) end table.sort(sets) print("Bind sets saved:") for i,setName in ipairs(sets) do print("- ", setName) end end Binder.commands = { ["build"] = Binder.BuildBindingsTable, ["save"] = Binder.SaveBindings, ["load"] = Binder.LoadBindings, ["list"] = Binder.ListBindings, } function Binder.SlashCommandHelp() print("Binder usage:") print("- /binder save <set name> (saves current keybindings)") print("- /binder load <set name> (loads specified keybindings)") print("- /binder list (lists all saved bind sets)") end function Binder.SlashCommand(argtext) local args = {strsplit(" ", argtext)} if next(args) == nil then Binder.SlashCommandHelp() return end local command = Binder.commands[args[1]] if not command then print("Binder: unknown command '", args[1], "'.") Binder.SlashCommandHelp() return end -- Call the selected function with everything except the original command command(unpack(args, 2)) end function Binder.OnAddOnLoaded(event, addonName) if addonName ~= "Binder" then return end Binder.savedVariables = ZO_SavedVars:NewAccountWide("Binder_SavedVariables", 1, "default", {["bindings"]={}}) end EVENT_MANAGER:RegisterForEvent("Binder", EVENT_ADD_ON_LOADED, Binder.OnAddOnLoaded) if FW_SlashCommand ~= nil then -- Register via Wykkyd's framework for those who use it, to allow macroing FW_SlashCommand("binder", Binder.SlashCommand) else -- But don't require the framework. SLASH_COMMANDS["/binder"] = Binder.SlashCommand end