Skip to content

Commit

Permalink
hoverbind: add support for mouse button & mouse wheel bindings
Browse files Browse the repository at this point in the history
- add support for mouse button & mouse wheel bindings
- remove need_save logic and just always save bindings immediately
- block left & right mouse buttons without modifier
  • Loading branch information
Pizzahawaiii authored Mar 22, 2024
1 parent 0439610 commit ba5e0ab
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 28 deletions.
2 changes: 2 additions & 0 deletions modules/actionbar.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1464,6 +1464,8 @@ pfUI:RegisterModule("actionbar", "vanilla:tbc", function ()
pfUI.bars.update = updatecache
pfUI.bars.buttons = buttoncache
pfUI.bars.ButtonFullUpdate = ButtonFullUpdate
pfUI.bars.ButtonEnter = ButtonEnter
pfUI.bars.ButtonLeave = ButtonLeave

pfUI.bars.UpdateGrid = function(self, state, typ)
if not typ then
Expand Down
154 changes: 126 additions & 28 deletions modules/hoverbind.lua
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,31 @@ pfUI:RegisterModule("hoverbind", "vanilla:tbc", function ()
["pfActionBarStanceBar4Button"] = "PFSTANCEFOUR",
}

local mousebuttonmap = {
["LeftButton"] = "BUTTON1",
["RightButton"] = "BUTTON2",
["MiddleButton"] = "BUTTON3",
["Button4"] = "BUTTON4",
["Button5"] = "BUTTON5",
}

local mousewheelmap = {
[1] = "MOUSEWHEELUP",
[-1] = "MOUSEWHEELDOWN",
}

local modifiers = {
["ALT"] = "ALT-",
["CTRL"] = "CTRL-",
["SHIFT"] = "SHIFT-"
}

-- We don't allow binding these keys without any modifiers
local blockedKeys = {
"LeftButton",
"RightButton",
}

pfUI.hoverbind = CreateFrame("Frame","pfKeyBindingFrame",UIParent)
pfUI.hoverbind:Hide()
pfUI.hoverbind:RegisterEvent("PLAYER_REGEN_DISABLED")
Expand All @@ -46,8 +65,16 @@ pfUI:RegisterModule("hoverbind", "vanilla:tbc", function ()
pfUI.bars:UpdateGrid(1)
pfUI.bars:UpdateGrid(1, "PET")
end

-- Initialize hoverbind frames on first show. We can't do this before because the action
-- bars might not exist yet when this module is loaded.
if not pfUI.hoverbind.frames then
pfUI.hoverbind.frames = pfUI.hoverbind:CreateHoverbindFrames()
end

pfUI.gui:Hide()
pfUI.hoverbind.edit:Show()
pfUI.hoverbind:ShowHoverbindFrames()

local txt = T["|cff33ffccKeybind Mode|r\nThis mode allows you to bind keyboard shortcuts to your actionbars.\nBy hovering a button with your cursor and pressing a key, the key will be assigned to that button.\nHit Escape on a button to remove bindings.\n\nPress Escape or click on an empty area to leave the keybind mode."]
CreateInfoBox(txt, 30, pfUI.hoverbind.edit)
Expand All @@ -58,38 +85,11 @@ pfUI:RegisterModule("hoverbind", "vanilla:tbc", function ()
pfUI.bars:UpdateGrid(0)
pfUI.bars:UpdateGrid(0, "PET")
end
pfUI.hoverbind:HideHoverbindFrames()
pfUI.hoverbind.edit:Hide()
pfUI.gui:Show()
end)

pfUI.hoverbind:EnableKeyboard(true)
pfUI.hoverbind:SetScript("OnKeyUp",function(...)
if modifiers[arg1] then return end -- ignore single modifier keyup
local need_save = false
local frame = GetMouseFocus()
local hovername = (frame and frame.GetName) and (frame:GetName()) or ""
local binding = pfUI.hoverbind:GetBinding(hovername)
if arg1 == "ESCAPE" and not binding then pfUI.hoverbind:Hide() return end
if binding then
if arg1 == "ESCAPE" then
local key = (GetBindingKey(binding))
if (key) then
SetBinding(key)
need_save = true
end
else
if (SetBinding(pfUI.hoverbind:GetPrefix()..arg1,binding)) then
need_save = true
end
end
end
-- if we set or cleared a binding save to the selected set
if need_save then
need_save = false
SaveBindings(GetCurrentBindingSet())
end
end)

function pfUI.hoverbind:GetBinding(button_name)
local found,_,buttontype,buttonindex = string.find(button_name,"^(.-)(%d+)$")
if found then
Expand All @@ -112,6 +112,104 @@ pfUI:RegisterModule("hoverbind", "vanilla:tbc", function ()
(IsShiftKeyDown() and modifiers.SHIFT or ""))
end

-- Loops over all actionbar buttons and creates an invisible overlapping hoverbind frame
-- for each of them. These hoverbind frames receive all key, mouse and mouse wheel events
-- so we can bind the respective key, mouse button or mouse wheel direction to the underlying
-- actionbar button. They should only be shown when hoverbind is active, otherwise the
-- underlying actionbar buttons can't be clicked anymore.
function pfUI.hoverbind:CreateHoverbindFrames()
if not pfUI.bars then return end

local frames = {}

for i=1,12 do
for j=1,12 do
local button = pfUI.bars[i][j]
if button then
local frame = CreateFrame("Frame", button:GetName() .. "HoverbindFrame", button)
frame:SetAllPoints(button)
frame:EnableKeyboard(true)
frame:EnableMouse(true)
frame:EnableMouseWheel(true)
frame:Hide()

-- Store the actionbar button on the overlaying hoverbind frame so we can reference
-- them in the hoverbind handler to create the key/mouse binding. We need this
-- because the hoverbind frames "steal" the mouse focus from the actual buttons.
frame.button = button

local function GetHoverbindHandler(map)
return function()
if modifiers[arg1] then return end -- ignore single modifier keyup

local prefix = pfUI.hoverbind:GetPrefix()

-- Don't allow binding certain buttons without modifiers
if not prefix or prefix == "" then
for _, blockedKey in ipairs(blockedKeys) do
if arg1 == blockedKey then return end
end
end

local frame = GetMouseFocus()
local hovername = (frame and frame.button and frame.button.GetName) and frame.button:GetName() or ""
local binding = pfUI.hoverbind:GetBinding(hovername)
if arg1 == "ESCAPE" and not binding then pfUI.hoverbind:Hide() return end
if binding then
if arg1 == "ESCAPE" then
-- Remove existing binding
local key = (GetBindingKey(binding))
if (key) then
SetBinding(key)
SaveBindings(GetCurrentBindingSet())
end
else
-- Create new binding
local key = map and map[arg1] or arg1
if (SetBinding(prefix..key, binding)) then
SaveBindings(GetCurrentBindingSet())
end
end
end
end
end
frame:SetScript("OnKeyUp", GetHoverbindHandler())
frame:SetScript("OnMouseUp", GetHoverbindHandler(mousebuttonmap))
frame:SetScript("OnMouseWheel", GetHoverbindHandler(mousewheelmap))

-- Explicitly call the corresponding button's onEnter/onLeave handlers to show/hide
-- its highlight and tooltip. This is necessary because the actual buttons don't
-- receive any mouse events in hoverbind mode since those are swallowed by the
-- overlapping hoverbind frames.
frame:SetScript("OnEnter", function()
pfUI.bars.ButtonEnter(button)
end)
frame:SetScript("OnLeave", function()
pfUI.bars.ButtonLeave(button)
end)

table.insert(frames, frame)
end
end
end

return frames
end

function pfUI.hoverbind:ShowHoverbindFrames()
if not pfUI.hoverbind.frames then return end
for _, frame in ipairs(pfUI.hoverbind.frames) do
frame:Show()
end
end

function pfUI.hoverbind:HideHoverbindFrames()
if not pfUI.hoverbind.frames then return end
for _, frame in ipairs(pfUI.hoverbind.frames) do
frame:Hide()
end
end

pfUI.hoverbind:SetScript("OnEvent",function()
-- disable hoverbind so player gets back control of their keyboard to fight
pfUI.hoverbind:Hide()
Expand Down

0 comments on commit ba5e0ab

Please sign in to comment.