View Single Post
08-09-15, 07:44 AM   #1
MunkDev
A Scalebane Royal Guard
 
MunkDev's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2015
Posts: 431
Redirecting keybinds mid combat

I'm trying to figure out whether the following scenario is possible:
  • A key is bound to an in-game button, which inherits the SecureActionButtonTemplate.
  • When no extra frames are visible, the button casts an arbitrary spell or performs a protected action.
  • When a frame is visible (e.g. WorldMapFrame, QuestFrame) the keybinding is redirected to perform operations on that frame. Think of it as frame hotkeys.
  • When the player enters combat, the button is NOT immediately reverted to cast spells, but rather stick to handling whatever frame is overlaying the UI until the player decides to close that frame.
  • When in combat, and all frames are hidden, whether they are closed mid combat or not, the secure button goes back to casting spells.
  • The definition of an overlaying frame is set by the code author.

My current approach is just reverting instantly upon PLAYER_REGEN_DISABLED, since this will not taint or cause any issues. The problem is that if I'm trying to manage a frame using keyboard input, it will instantly stop working if I happen to grab aggro from a nearby mob. This is obviously not favorable, since there are more than a few scenarios in which you need to interact with the interface mid combat. Since action bar swapping is something I handle with a SecureStateHandler, maybe it's possible to also make decisions depending on which frames are visible?

Example of what I'm currently using:
Lua Code:
  1. local btn   = CreateFrame("Button", name..modifier, UIParent, "SecureActionButtonTemplate");
  2. --
  3. -- Bunch of irrelevant shit missing here
  4. --
  5. btn.reset   = function()
  6.     btn.default = {
  7.         type = "click",
  8.         attr = "clickbutton",
  9.         val  = btn.action
  10.     }
  11. end
  12. -- MainBarAction is a function that determines whether the action exists on the standard action bar
  13. btn.revert  = function()
  14.     if  MainBarAction(btn.default.val) then
  15.         btn.default.type = "action";
  16.         btn.default.attr = "action";
  17.         btn.default.val  = MainBarAction(btn.default.val);
  18.         btn:SetID(btn.default.val);
  19.     end
  20.     btn:SetAttribute("type", btn.default.type);
  21.     btn:SetAttribute(btn.default.attr, btn.default.val);
  22.     btn:SetAttribute("clickbutton", btn.action);
  23. end
  24.  
  25. -- This works because of the grace period between the event and secure state lockdown
  26. btn:RegisterEvent("PLAYER_REGEN_DISABLED");
  27. btn:SetScript("OnEvent", btn.revert);
  28.  
  29. -- Register to handler
  30. Handler:SetFrameRef("NewButton", btn);
  31. SecureHandlerExecute(Handler, [[
  32.     BUTTONS[self:GetFrameRef("NewButton")] = true
  33. ]]);

Handler code for bar and stance swapping:
Lua Code:
  1. local m = CreateFrame("Frame", "Handler", UIParent, "SecureHandlerStateTemplate");
  2. SecureHandlerExecute(m, [[
  3.     BUTTONS = newtable();
  4.     UpdateMainActionBar = [=[
  5.         local page = ...;
  6.         if page == "tempshapeshift" then
  7.             if HasTempShapeshiftActionBar() then
  8.                 page = GetTempShapeshiftBarIndex();
  9.             else
  10.                 page = 1;
  11.             end
  12.         elseif page == "possess" then
  13.             page = self:GetFrameRef("MainMenuBarArtFrame"):GetAttribute("actionpage");
  14.             if page <= 10 then
  15.                 page = self:GetFrameRef("OverrideActionBar"):GetAttribute("actionpage");
  16.             end
  17.             if page <= 10 then
  18.                 page = 12;
  19.             end
  20.         end
  21.         self:SetAttribute("actionpage", page);
  22.         for btn in pairs(BUTTONS) do
  23.             btn:SetAttribute("actionpage", page);
  24.         end
  25.     ]=]
  26. ]]);
  27. m:SetFrameRef("MainMenuBarArtFrame", MainMenuBarArtFrame)
  28. m:SetFrameRef("OverrideActionBar", OverrideActionBar)
  29. local state = {};
  30. tinsert(state, "[overridebar][possessbar]possess");
  31. for i = 2, 6 do
  32.     tinsert(state, ("[bar:%d]%d"):format(i, i));
  33. end
  34. local _, playerClass = UnitClass("player");
  35. if playerClass == "DRUID" then
  36.     tinsert(state, "[bonusbar:1,stealth]7");
  37. elseif playerClass == "WARRIOR" then
  38.     tinsert(state, "[stance:2]7");
  39.     tinsert(state, "[stance:3]8");
  40. end
  41. for i = 1, 4 do
  42.     tinsert(state, ("[bonusbar:%d]%d"):format(i, i+6));
  43. end
  44. tinsert(state, "[stance:1]tempshapeshift");
  45. tinsert(state, "1");
  46. state = table.concat(state, ";");
  47. local now = SecureCmdOptionParse(state);
  48. m:SetAttribute("actionpage", now);
  49. RegisterStateDriver(m, "page", state);
  50. m:SetAttribute("_onstate-page", [=[
  51.     self:Run(UpdateMainActionBar, newstate);
  52. ]=]);
__________________

Last edited by MunkDev : 08-09-15 at 07:51 AM.
  Reply With Quote