Nenue@0: -------------------------------------------- Nenue@5: -- SkeletonKey Nenue@5: -- Krakyn-Mal'Ganis Nenue@0: -- @project-revision@ @project-hash@ Nenue@0: -- @file-revision@ @file-hash@ Nenue@0: -- Created: 6/16/2016 3:47 AM Nenue@0: -------------------------------------------- Nenue@0: -- kb Nenue@5: -- .StoreBinding(button, key) bind current keystroke to command Nenue@5: -- .GetSlot(index) return display slot Nenue@5: -- .SetSlot(button, command, name, icon) assign display slot Nenue@5: -- .ReleaseSlot(button) clear button command Nenue@5: -- .UpdateSlot(button) update button contents Nenue@5: -- .SelectProfile(name) set profile character Nenue@5: -- .ApplyBindings(bindings) walk table with SetBinding() Nenue@0: Nenue@5: local _ Nenue@5: local kb, print = LibStub("LibKraken").register(KeyBinder) Nenue@5: local cprint = DEVIAN_WORKSPACE and function(...) _G.print('Cfg', ...) end or function() end Nenue@14: kb.L = setmetatable({}, { Nenue@14: __call = function(t, k, ...) return format(t[k] or '', ...) end Nenue@14: }) Nenue@14: local L = kb.L Nenue@7: Nenue@5: --- Caps Lock literals Nenue@5: local CLICK_KEYBINDER_MACRO = "CLICK KeyBinderMacro:" Nenue@6: local CLICK_KEYBINDER_KEY = "CLICK KeyBinderKey:" Nenue@5: local CLASS_ICON_TEXTURE = "Interface\\GLUES\\CHARACTERCREATE\\UI-CHARACTERCREATE-CLASSES" Nenue@5: local FOOTER_OFFSET Nenue@5: local HEADER_OFFSET Nenue@14: L.BINDING_ASSIGNED = '|cFF00FF00%s|r assigned to |cFFFFFF00%s|r (%s).' Nenue@14: L.BINDING_REMOVED = '|cFFFFFF00%s|r (|cFF00FFFF%s|r) unbound.' Nenue@14: L.BINDING_FAILED_PROTECTED = '|cFFFF4400Unable to use |r|cFF00FF00%s|r|cFFFF4400 (currently |cFFFFFF00%s|r|cFFFF4400)|r' Nenue@14: Nenue@14: Nenue@5: local BINDING_TYPE_SPECIALIZATION = 3 Nenue@5: local BINDING_TYPE_CHARACTER = 2 Nenue@5: local BINDING_TYPE_GLOBAL = 1 Nenue@5: Nenue@5: Nenue@5: --- Caps Lock derivatives Nenue@5: local ACTION_SCRIPT = { Nenue@5: ['mount'] = "/script C_MountJournal.SummonByID(%d)", Nenue@5: ['macro'] = "%s", Nenue@5: ['equipset'] = "/script UseEquipmentSet(%d)", Nenue@5: ['spell'] = "/cast %s", Nenue@5: ['petaction'] = "/cast %s", Nenue@5: ['battlepet'] = SLASH_SUMMON_BATTLE_PET1 .. " %s", Nenue@5: ['item'] = "/use %s" Nenue@5: } Nenue@5: Nenue@5: local professionMappings = { Nenue@5: [5] = 3, Nenue@5: [7] = 4, Nenue@5: [9] = 5, Nenue@5: [10] = 6 Nenue@5: } Nenue@6: kb.configTitle = { Nenue@5: [BINDING_TYPE_GLOBAL] = 'Global Binds', Nenue@0: [BINDING_TYPE_CHARACTER] = 'Character: %s', Nenue@5: [BINDING_TYPE_SPECIALIZATION] = 'Specialization: %s' Nenue@0: } Nenue@6: kb.configDescription = { Nenue@5: [BINDING_TYPE_GLOBAL] = 'The bindings are applied globally.', Nenue@5: [BINDING_TYPE_CHARACTER] = 'Applied when you log onto this character.', Nenue@5: [BINDING_TYPE_SPECIALIZATION] = 'Applied when you log onto this character and are that specialization.', Nenue@5: } Nenue@5: Nenue@0: Nenue@0: Nenue@14: kb.inactiveTalentBindings = {} Nenue@6: kb.configHeaders = {} Nenue@6: kb.loadedProfiles = {} Nenue@6: kb.orderedProfiles = {} Nenue@6: kb.buttons = {} Nenue@6: kb.macros = {} Nenue@0: Nenue@14: -- these are sent to plugin Nenue@14: Nenue@14: local bindings = {} Nenue@5: local macros = {} Nenue@5: local talentBindings = {} Nenue@0: Nenue@0: local protected = { Nenue@0: ['OPENCHATSLASH'] = true, Nenue@0: ['OPENCHAT'] = true, Nenue@0: } Nenue@5: Nenue@14: Nenue@14: local db Nenue@5: local bindHeader, currentHeader = '', '' Nenue@5: local specID, specGlobalID, specName, specDesc, specTexture, characterHeader = 0, 0, 'SPEC_NAME', 'SPEC_DESCRIPTION', 'Interface\\ICONS\\INV_Misc_QuestionMark', 'PLAYER_NAME' Nenue@5: local classHeader, className, classID = '', '', 0 Nenue@5: local bindsCommitted = true Nenue@5: local forceButtonUpdate = false Nenue@5: Nenue@5: --- Control handles Nenue@0: local saveButton, restoreButton, clearButton Nenue@0: Nenue@5: --- Returns conflicting assignment and binding profiles for use in displaying confirmations Nenue@6: kb.IsCommandBound = function(self, command) Nenue@6: local isAssigned, assignedBy = false, db.bindMode Nenue@6: local isBound, boundBy = false, db.bindMode Nenue@5: Nenue@5: Nenue@5: command = command or self.command Nenue@6: for i = 1, #kb.orderedProfiles do Nenue@6: local tier = kb.orderedProfiles[i] Nenue@6: if i ~= db.bindMode then Nenue@5: Nenue@5: if tier.commands[command] then Nenue@5: isAssigned = true Nenue@5: assignedBy = i Nenue@5: end Nenue@5: if tier.bound[command] then Nenue@5: isBound = true Nenue@5: boundBy = i Nenue@5: end Nenue@5: Nenue@5: Nenue@5: --print(' *', configHeaders[i], tier.commands[command], tier.bound[command]) Nenue@5: Nenue@5: if isAssigned and isBound then Nenue@0: break Nenue@0: end Nenue@0: end Nenue@5: Nenue@0: end Nenue@5: Nenue@6: print('|cFFFFFF00IsCommandBound:|r', command:gsub(CLICK_KEYBINDER_MACRO, ''),'|r [profile:', db.bindMode .. ']', isAssigned, isBound, assignedBy, boundBy) Nenue@5: return isAssigned, isBound, assignedBy, boundBy Nenue@0: end Nenue@0: Nenue@5: local talentSpellHardCodes = { Nenue@5: [109248] = 'Binding Shot', Nenue@5: } Nenue@5: Nenue@0: --- Returns a value for use with Texture:SetDesaturated() Nenue@6: kb.BindingIsLocked = function(key) Nenue@0: local success = false Nenue@6: for i = 1, db.bindMode-1 do Nenue@6: local tier = kb.orderedProfiles[i] Nenue@0: if tier.bindings[key] then Nenue@0: success = true Nenue@0: break Nenue@0: end Nenue@0: end Nenue@0: return success Nenue@0: end Nenue@0: Nenue@0: --- Translates GetBindingKey() results into a printable string. Nenue@6: kb.BindingString = function(...) Nenue@0: local stack = {} Nenue@0: for i = 1, select('#', ...) do Nenue@0: local key = select(i, ...) Nenue@5: stack[i] = key:gsub('SHIFT', 's'):gsub('ALT', 'a'):gsub('CTRL', 'c'):gsub('SPACE', 'Sp'):gsub('BUTTON', 'M '):gsub('NUMPAD', '# ') Nenue@0: end Nenue@0: Nenue@0: if #stack >= 1 then Nenue@0: return table.concat(stack, ',') Nenue@0: else Nenue@0: return nil Nenue@0: end Nenue@0: end Nenue@0: Nenue@5: Nenue@6: --- Resolve the appropriate command and macroText for the given action parameters Nenue@13: kb.RegisterAction = function(type, id, name) Nenue@6: local macroText, macroName, command = '', '', '' Nenue@5: Nenue@5: if type == 'spell' then Nenue@6: if kb.ProfessionCache[id] then Nenue@6: command = CLICK_KEYBINDER_KEY .. "profession_".. kb.ProfessionCache[id].profOffset .. '_' .. kb.ProfessionCache[id].spellNum Nenue@6: else Nenue@13: command = CLICK_KEYBINDER_KEY ..name Nenue@6: end Nenue@6: else Nenue@13: macroName = type .. ' ' .. name Nenue@13: macroText = ACTION_SCRIPT[type]:format(name) Nenue@6: local baseName, iterative = macroName, 1 Nenue@6: while (macros[macroName] and macros[macroName][1] ~= macroText) do Nenue@6: print(' * cannot use|cFF00FF00', macroName, '|r"'.. (macros[macroName][1] or '') .. '"') Nenue@6: macroName = baseName .. '_' .. iterative Nenue@6: iterative = iterative + 1 Nenue@6: end Nenue@6: if macroName ~= baseName then Nenue@6: print(' * Creating|cFF00FF00', macroName) Nenue@6: else Nenue@6: print(' * Re-using|cFF00FF00', macroName) Nenue@6: end Nenue@6: command = 'CLICK KeyBinderMacro:'.. macroName Nenue@6: macros[macroName] = {macroText, command } Nenue@5: end Nenue@5: Nenue@6: print('RegisterAction', type, id, '->', command , macroText) Nenue@5: return macroName, macroText, command Nenue@0: end Nenue@0: Nenue@0: --- Updates the current KeyBinding for the button's command Nenue@5: kb.StoreBinding = function(self, key) Nenue@0: Nenue@0: if not self.command then Nenue@0: return Nenue@0: end Nenue@0: Nenue@0: if key:match('[RL]SHIFT') or key:match('[RL]ALT') or key:match('[RL]CTRL') then Nenue@0: return Nenue@0: end Nenue@5: print('|cFFFFFF00received|cFFFFFF00', self:GetID(), '|cFF00FFFF', key) Nenue@0: Nenue@5: if key == 'ESCAPE' then Nenue@5: local keys = {GetBindingKey(self.command) } Nenue@5: --print('detected', #keys, 'bindings') Nenue@5: for i, key in pairs(keys) do Nenue@5: --print('clearing', key) Nenue@5: SetBinding(key, nil) Nenue@5: SaveBindings(GetCurrentBindingSet()) Nenue@6: if kb.currentProfile.bindings[key] then Nenue@14: kb:print(L('BINDING_REMOVED', self.actionName, kb.configHeaders[db.bindMode])) Nenue@6: kb.currentProfile.bindings[key] = nil Nenue@5: end Nenue@6: if kb.currentProfile.talents[self.actionName] then Nenue@6: kb.currentProfile.talents[self.actionName] = nil Nenue@5: end Nenue@5: bindings[self.actionType][self.actionID] = nil Nenue@5: end Nenue@6: if kb.currentProfile.bound[self.command] then Nenue@6: kb.currentProfile.bound[self.command] = nil Nenue@6: --kb:print(BINDING_REMOVED:format(self.actionName, configHeaders[db.bindMode])) Nenue@5: end Nenue@5: Nenue@5: bindsCommitted = false Nenue@5: self.active = false Nenue@5: else Nenue@5: Nenue@5: local modifier = '' Nenue@5: if IsAltKeyDown() then Nenue@5: modifier = 'ALT-' Nenue@5: end Nenue@5: if IsControlKeyDown() then Nenue@5: modifier = modifier.. 'CTRL-' Nenue@5: end Nenue@5: if IsShiftKeyDown() then Nenue@5: modifier = modifier..'SHIFT-' Nenue@5: end Nenue@5: Nenue@5: Nenue@5: if self.command then Nenue@5: self.binding = modifier..key Nenue@5: Nenue@5: local previousKeys Nenue@5: local previousAction = GetBindingAction(self.binding) Nenue@5: local binding1, binding2, new1, new2 Nenue@5: print(type(previousAction), previousAction) Nenue@5: if previousAction ~= "" and previousAction ~= self.command then Nenue@5: if protected[previousAction] then Nenue@5: -- bounce out if trying to use a protected key Nenue@14: kb.statustext:SetText(L('BINDING_FAILED_PROTECTED', key, GetBindingAction(previousAction))) Nenue@5: kb.bindingstext:SetText(nil) Nenue@5: return Nenue@5: else Nenue@5: kb:print('Discarding keybind for', previousAction) Nenue@5: -- todo: sort out retcon'd talent spells Nenue@5: end Nenue@5: end Nenue@5: Nenue@5: self.pending = true Nenue@5: Nenue@5: bindsCommitted = false Nenue@5: SetBinding(self.binding, self.command) Nenue@5: SaveBindings(GetCurrentBindingSet()) Nenue@5: Nenue@5: local talentInfo Nenue@5: if self.actionType == 'spell' and kb.TalentCache[self.actionID] then Nenue@5: print('conditional binding (talent = "'..self.actionName..'")') Nenue@5: talentInfo = {self.macroName, self.actionName, self.actionType, self.actionID} Nenue@5: local bindings = {GetBindingKey(self.command) } Nenue@5: for i, key in ipairs(bindings) do Nenue@5: tinsert(talentInfo, key) Nenue@5: end Nenue@5: end Nenue@5: Nenue@6: for level, profile in ipairs(kb.orderedProfiles) do Nenue@6: if (level == db.bindMode) then Nenue@6: profile.bound[self.command] = true Nenue@5: if talentInfo then Nenue@6: profile.bindings[self.binding] = nil Nenue@5: else Nenue@6: profile.bindings[self.binding] = self.command Nenue@5: end Nenue@6: profile.talents[self.actionName] = talentInfo Nenue@5: else Nenue@6: profile.bindings[self.binding] = nil Nenue@6: profile.bound[self.command] = nil Nenue@6: kb.currentProfile.talents[self.actionName] = nil Nenue@5: end Nenue@6: if kb.currentProfile.talents[self.actionID] then Nenue@6: kb.currentProfile.talents[self.actionID] = nil Nenue@5: end Nenue@5: end Nenue@5: Nenue@14: kb:print(L('BINDING_ASSIGNED', self.binding, self.actionName, kb.configHeaders[db.bindMode])) Nenue@5: end Nenue@0: end Nenue@5: kb.UpdateSlot(self, true) Nenue@5: KeyBinderSaveButton:Enable() Nenue@0: end Nenue@0: Nenue@5: Nenue@6: kb.inactiveTalentBindings = {} Nenue@5: kb.ApplyTalentBinding = function(talentInfo, cache) Nenue@5: for i = 5, #talentInfo do Nenue@6: local command = CLICK_KEYBINDER_KEY.. talentInfo[2] Nenue@6: SetBinding(talentInfo[i], command) Nenue@6: cprint(' **', talentInfo[i], '->', command) Nenue@5: tinsert(cache, talentInfo[i]) Nenue@0: end Nenue@0: end Nenue@5: kb.CacheTalentBinding = function(talentInfo, cache) Nenue@6: Nenue@5: local spellID = talentInfo[4] Nenue@5: kb.inactiveTalentBindings[spellID] = kb.inactiveTalentBindings[spellID] or {} Nenue@5: kb.inactiveTalentBindings[spellID] = {select(5,unpack(talentInfo)) } Nenue@6: --cprint(spellID, unpack(kb.inactiveTalentBindings[spellID])) Nenue@0: end Nenue@0: Nenue@6: kb.LoadBinding = function(command, name, icon, actionType, actionID, macroName, macroText ) Nenue@5: Nenue@6: if actionType == 'spell' then Nenue@6: KeyBinderKey:SetAttribute("*type-"..name, actionType) Nenue@6: KeyBinderKey:SetAttribute("*"..actionType.."-"..name, name) Nenue@13: Nenue@6: elseif actionType == 'item' then Nenue@6: KeyBinderKey:SetAttribute("*type-"..name, actionType) Nenue@6: KeyBinderKey:SetAttribute("*"..actionType.."-"..name, name) Nenue@6: elseif actionType == 'macro' then Nenue@5: KeyBinderMacro:SetAttribute("*macro-"..macroName, actionID) Nenue@5: else Nenue@5: KeyBinderMacro:SetAttribute("*macrotext-"..macroName, macroText) Nenue@5: end Nenue@13: Nenue@13: cprint('Loading binding', actionType, actionID) Nenue@5: bindings[actionType] = bindings[actionType] or {} Nenue@5: bindings[actionType][actionID] = bindings[actionType][actionID] or {} Nenue@5: bindings[command] = bindings[actionType][actionID] Nenue@5: return bindings[actionType], actionID Nenue@5: end Nenue@5: Nenue@5: kb.ApplyBindings = function (profile) Nenue@5: cprint('binding profile', profile) Nenue@5: for slot, data in pairs(profile.buttons) do Nenue@6: kb.LoadBinding(unpack(data)) Nenue@5: end Nenue@5: Nenue@5: for key, command in pairs(profile.bindings) do Nenue@5: Nenue@6: cprint(' *', key, '->', command) Nenue@5: Nenue@5: --_G.print('HotKey','loading', key, command) Nenue@5: SetBinding(key, command) Nenue@5: if bindings[command] and not tContains(bindings[command], key) then Nenue@5: tinsert(bindings[command], key) Nenue@5: end Nenue@5: end Nenue@5: Nenue@5: for spellName, talentInfo in pairs(profile.talents) do Nenue@5: local dummy = GetSpellInfo(spellName) Nenue@5: local func = kb.CacheTalentBinding Nenue@5: local dest = kb.inactiveTalentBindings Nenue@5: if dummy then Nenue@5: cprint('|cFFBBFF00Active:|r', dummy) Nenue@5: local macroName, spellName, actionType, actionID = unpack(talentInfo) Nenue@5: bindings[actionType] = bindings[actionType] or {} Nenue@5: bindings[actionType][actionID] = {} Nenue@5: func = kb.ApplyTalentBinding Nenue@5: dest = bindings[actionType][actionID] Nenue@5: else Nenue@5: Nenue@5: cprint('|cFFFF4400Inactive:|r', talentInfo[2]) Nenue@5: end Nenue@5: func(talentInfo, dest) Nenue@5: end Nenue@5: Nenue@5: SaveBindings(GetCurrentBindingSet()) Nenue@5: end Nenue@5: Nenue@5: kb.ApplyAllBindings =function () Nenue@5: table.wipe(kb.inactiveTalentBindings) Nenue@5: Nenue@6: -- reflect action key settings Nenue@6: if GetCVarBool("ActionButtonUseKeyDown") then Nenue@6: KeyBinderMacro:RegisterForClicks("AnyDown") Nenue@6: KeyBinderKey:RegisterForClicks("AnyDown") Nenue@6: else Nenue@6: KeyBinderMacro:RegisterForClicks("AnyUp") Nenue@6: KeyBinderKey:RegisterForClicks("AnyUp") Nenue@6: end Nenue@6: Nenue@6: for i, profile in ipairs(kb.orderedProfiles) do Nenue@5: kb.ApplyBindings(profile) Nenue@5: end Nenue@5: -- do this after to ensure that profession binds are properly overridden Nenue@5: kb.UpdateProfessionInfo() Nenue@6: Nenue@6: Nenue@5: end Nenue@5: Nenue@5: kb.Command = function(args, editor) Nenue@5: if args:match("import") then Nenue@5: kb.ImportCommmit(args) Nenue@5: return Nenue@5: elseif args:match("scan") then Nenue@5: kb.ImportScan(args) Nenue@5: kb.ui() Nenue@5: return Nenue@5: elseif args:match("load") then Nenue@5: kb:ApplyAllBindings() Nenue@0: return Nenue@0: end Nenue@0: Nenue@5: if db.showUI then Nenue@5: db.showUI = false Nenue@5: kb:print('|cFFFFFF00KeyBinds|r trace, |cFFFF0000OFF|r.') Nenue@5: kb:Hide() Nenue@5: else Nenue@1: db.showUI = true Nenue@5: kb:print('|cFFFFFF00KeyBinds|r trace, |cFF00FF00ON|r.') Nenue@5: end Nenue@5: kb.ui(true) Nenue@5: end Nenue@5: Nenue@5: kb.InitProfile = function(profile, prototype) Nenue@5: if not profile then Nenue@5: profile = {} Nenue@5: end Nenue@5: if prototype then Nenue@5: print('appplying prototype', prototype) Nenue@5: for k,v in pairs(prototype) do Nenue@5: if not profile[k] then Nenue@5: profile[k] = v Nenue@5: end Nenue@5: end Nenue@0: end Nenue@0: Nenue@5: profile.bound = profile.bound or {} Nenue@5: profile.buttons = profile.buttons or {} Nenue@5: profile.commands = profile.commands or {} Nenue@5: profile.bindings = profile.bindings or {} Nenue@5: profile.macros = profile.macros or {} Nenue@5: profile.talents = profile.talents or {} Nenue@5: return profile Nenue@5: end Nenue@5: Nenue@5: kb.ResetProfile = function(profile, prototype) Nenue@6: if profile == kb.currentProfile then Nenue@5: for i, button in pairs(buttons) do Nenue@5: kb.ReleaseSlot(button) Nenue@5: end Nenue@5: end Nenue@5: table.wipe(profile) Nenue@5: kb.InitProfile(profile, prototype) Nenue@5: end Nenue@5: Nenue@5: Nenue@5: Nenue@5: --- Handles constructing spec profiles as they are selected Nenue@5: Nenue@5: Nenue@5: --- Obtains profile data or creates the necessary tables Nenue@5: kb.SelectProfileSet = function(name) Nenue@5: Nenue@6: local defaultMode Nenue@5: --- General info Nenue@5: classHeader, className, classID = UnitClass('player') Nenue@5: print('|cFF00FF00profile:|r', name) Nenue@5: print('|cFF00FF00class:|r', UnitClass('player')) Nenue@5: Nenue@5: --- Global Nenue@6: defaultMode = BINDING_TYPE_GLOBAL Nenue@5: kb.InitProfile(db) Nenue@6: kb.loadedProfiles[BINDING_TYPE_GLOBAL] = db Nenue@5: Nenue@5: --- Character Nenue@5: if name then Nenue@5: db[name] = kb.InitProfile(db[name], Nenue@5: {classHeader = classHeader, className = className, classID = classID}) Nenue@6: kb.loadedProfiles[BINDING_TYPE_CHARACTER] = db[name] Nenue@6: defaultMode = BINDING_TYPE_CHARACTER Nenue@5: end Nenue@5: Nenue@5: --- Mutable skills data Nenue@5: kb.UpdateSpecInfo() Nenue@5: kb.UpdateTalentInfo() Nenue@5: Nenue@6: kb.orderedProfiles = {kb.loadedProfiles[BINDING_TYPE_GLOBAL], kb.loadedProfiles[BINDING_TYPE_CHARACTER], kb.loadedProfiles[BINDING_TYPE_SPECIALIZATION]} Nenue@6: if db.bindMode and (not kb.configTitle[db.bindMode]) then Nenue@6: print('fixing bad bindMode value, was', db.bindMode) Nenue@6: db.bindMode = defaultMode Nenue@5: end Nenue@5: Nenue@5: Nenue@5: print(BINDING_TYPE_GLOBAL) Nenue@6: kb.configHeaders[BINDING_TYPE_GLOBAL] = kb.configTitle[BINDING_TYPE_GLOBAL] Nenue@6: kb.configHeaders[BINDING_TYPE_CHARACTER] = kb.configTitle[BINDING_TYPE_CHARACTER]:format(UnitName('player', true)) Nenue@10: kb.configHeaders[BINDING_TYPE_SPECIALIZATION] = kb.configTitle[BINDING_TYPE_SPECIALIZATION]:format(kb.specInfo.name) Nenue@5: Nenue@5: Nenue@6: setmetatable(kb.loadedProfiles[BINDING_TYPE_GLOBAL], {__tostring =function() return kb.configHeaders[BINDING_TYPE_GLOBAL] end}) Nenue@6: setmetatable(kb.loadedProfiles[BINDING_TYPE_CHARACTER], {__tostring =function() return kb.configHeaders[BINDING_TYPE_CHARACTER] end}) Nenue@6: setmetatable(kb.loadedProfiles[BINDING_TYPE_SPECIALIZATION], {__tostring =function() return kb.configHeaders[BINDING_TYPE_SPECIALIZATION] end}) Nenue@5: Nenue@6: print('|cFF00FF00bindMode:|r', db.bindMode) Nenue@6: kb.currentProfile = kb.loadedProfiles[db.bindMode] Nenue@5: end Nenue@5: Nenue@5: local scrollCache = {} Nenue@5: kb.SelectTab = function(self) Nenue@6: scrollCache[db.bindMode] = kb.scrollOffset Nenue@5: db.bindMode = self:GetID() Nenue@6: kb.currentProfile = kb.loadedProfiles[self:GetID()] Nenue@6: kb.scrollOffset = scrollCache[db.bindMode] or 0 Nenue@5: kb.ui(true) Nenue@5: end Nenue@5: Nenue@5: kb.RevertBindings = function() Nenue@5: -- todo: reversion code Nenue@5: end Nenue@5: Nenue@5: kb.ConfirmBindings = function() Nenue@5: SaveBindings(GetCurrentBindingSet()) Nenue@5: bindsCommitted = true Nenue@5: for i, button in ipairs(buttons) do Nenue@5: button.pending = false Nenue@5: end Nenue@5: kb.ApplyAllBindings() Nenue@5: Nenue@5: kb.ui() Nenue@5: kb:print('Keybinds saved.') Nenue@5: end Nenue@5: Nenue@5: Nenue@5: Nenue@5: Nenue@5: --- post ADDON_LOADED Nenue@5: kb.variables = function() Nenue@5: SkeletonKeyDB = SkeletonKeyDB or {spec = {}} Nenue@5: kb.db = SkeletonKeyDB Nenue@5: kb.playerName = UnitName('player') Nenue@5: kb.playerRealm = SelectedRealmName() Nenue@5: kb.profileName = kb.playerRealm .. '_' .. kb.playerName Nenue@5: db = kb.db Nenue@5: Nenue@5: kb.SelectProfileSet(kb.profileName) Nenue@6: -- todo: redo import checking Nenue@6: Nenue@6: Nenue@6: Nenue@5: kb.ApplyAllBindings() Nenue@5: Nenue@5: kb.ui(true) Nenue@0: end Nenue@0: Nenue@1: Nenue@5: kb.wrap = function(module) Nenue@5: kb.modules = kb.modules or {} Nenue@5: tinsert(kb.modules, module) Nenue@0: end Nenue@0: Nenue@5: -- Volatiles Access Nenue@5: kb.GetBindings = function() return bindings end Nenue@5: kb.GetButtons = function() return buttons end Nenue@6: kb.GetCharacterProfile = function () return kb.loadedProfiles[BINDING_TYPE_CHARACTER] end Nenue@6: kb.GetGlobalProfile = function () return kb.loadedProfiles[BINDING_TYPE_GLOBAL] end Nenue@5: kb.GetLooseTalents = function() return talentBindings end Nenue@5: kb.GetReverts = function() return reverts end Nenue@6: kb.GetSpecProfile = function () return kb.loadedProfiles[BINDING_TYPE_SPECIALIZATION] end Nenue@0: Nenue@0: Nenue@5: SLASH_SKB1 = "/skb" Nenue@5: SLASH_SKB2 = "/skeletonkey" Nenue@5: SlashCmdList.SKB = kb.Command