|
|
|
|
local _, addon = ...
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
local SetOverrideBindingClick = SetOverrideBindingClick;
|
|
|
|
|
local ClearOverrideBindings = ClearOverrideBindings;
|
|
|
|
|
local IsKeyDown = IsKeyDown;
|
|
|
|
|
|
|
|
|
|
local GamePadButtonPool = addon.GamePadButtonPool;
|
|
|
|
|
local ACTION_GOUPS = addon.actionGroups;
|
|
|
|
|
|
|
|
|
|
local ActiveGroup = {};
|
|
|
|
|
|
|
|
|
|
local KeyListener, Repeater;
|
|
|
|
|
local Loader = CreateFrame("Frame");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
local ModuleManager = Narci.ModuleManager;
|
|
|
|
|
|
|
|
|
|
local function SignalGamePadActive()
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if ModuleManager then
|
|
|
|
|
function SignalGamePadActive()
|
|
|
|
|
ModuleManager:OnGamePadActiveChanged(true);
|
|
|
|
|
end
|
|
|
|
|
ModuleManager:AddGamePadCallbackWidget(Loader);
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
local function SelectActionGroup(name, mode)
|
|
|
|
|
if ACTION_GOUPS[name] then
|
|
|
|
|
if ActiveGroup.currentObj and ActiveGroup.currentObj.OnLeave then
|
|
|
|
|
ActiveGroup.currentObj:OnLeave();
|
|
|
|
|
end
|
|
|
|
|
GamePadButtonPool:HideAllButtons();
|
|
|
|
|
ActiveGroup = ACTION_GOUPS[name];
|
|
|
|
|
ActiveGroup:Activate(mode);
|
|
|
|
|
Repeater:SetInterval(ActiveGroup.repeatInterval);
|
|
|
|
|
|
|
|
|
|
--print("Action Group: "..name);
|
|
|
|
|
else
|
|
|
|
|
print("Failed to find: "..name);
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
addon.SelectActionGroup = SelectActionGroup;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
--courtesy of Munk (dev of ConsolePort and Immersion)
|
|
|
|
|
local Proxy = CreateFrame("Button", "NarciPadClickProxy", nil, "InsecureActionButtonTemplate");
|
|
|
|
|
addon.ClickProxy = Proxy;
|
|
|
|
|
Proxy:SetAttribute("type", "click");
|
|
|
|
|
|
|
|
|
|
function Proxy:SetClickTarget(object)
|
|
|
|
|
SetOverrideBindingClick(Proxy, true, "PAD3", "NarciPadClickProxy");
|
|
|
|
|
self:SetAttribute("type", "click");
|
|
|
|
|
self:SetAttribute("clickbutton", object);
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function Proxy:SetUseItem(slotID)
|
|
|
|
|
SetOverrideBindingClick(Proxy, true, "PAD3", "NarciPadClickProxy");
|
|
|
|
|
self:SetAttribute("type", "item");
|
|
|
|
|
self:SetAttribute("item", slotID);
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function Proxy:SetRunMacro(macroText)
|
|
|
|
|
if macroText then
|
|
|
|
|
SetOverrideBindingClick(Proxy, true, "PAD3", "NarciPadClickProxy");
|
|
|
|
|
self:SetAttribute("type", "macro");
|
|
|
|
|
self:SetAttribute("macrotext", macroText);
|
|
|
|
|
else
|
|
|
|
|
self:Remove();
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function Proxy:SetCancelCast()
|
|
|
|
|
ClearOverrideBindings(self)
|
|
|
|
|
SetOverrideBindingClick(Proxy, true, "PAD2", "NarciPadClickProxy");
|
|
|
|
|
self:SetAttribute("type", "macro");
|
|
|
|
|
self:SetAttribute("macrotext", "/stopcasting");
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function Proxy:Remove()
|
|
|
|
|
ClearOverrideBindings(self)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
local IsNavigationKeys = {
|
|
|
|
|
["PADRSHOULDER"] = true,
|
|
|
|
|
["PADLSHOULDER"] = true,
|
|
|
|
|
["PADDLEFT"] = true,
|
|
|
|
|
["PADDRIGHT"] = true,
|
|
|
|
|
["PADDUP"] = true,
|
|
|
|
|
["PADDDOWN"] = true,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
local SIGNAL_PRESS = {
|
|
|
|
|
["PAD1"] = true,
|
|
|
|
|
["PAD2"] = true,
|
|
|
|
|
["PAD3"] = true,
|
|
|
|
|
["PAD4"] = true,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
--Process hardware input
|
|
|
|
|
KeyListener = CreateFrame("Frame");
|
|
|
|
|
KeyListener.isButtonDown = {};
|
|
|
|
|
KeyListener:Hide();
|
|
|
|
|
KeyListener:SetPropagateKeyboardInput(false);
|
|
|
|
|
|
|
|
|
|
Repeater = CreateFrame("Frame", nil, KeyListener);
|
|
|
|
|
Repeater:Hide();
|
|
|
|
|
|
|
|
|
|
KeyListener:RegisterEvent("PLAYER_REGEN_DISABLED");
|
|
|
|
|
KeyListener:RegisterEvent("MODIFIER_STATE_CHANGED");
|
|
|
|
|
|
|
|
|
|
KeyListener:SetScript("OnEvent", function(self, event, ...)
|
|
|
|
|
if event == "PLAYER_REGEN_DISABLED" then
|
|
|
|
|
self:Deactivate();
|
|
|
|
|
else
|
|
|
|
|
self:SetModifierState(...)
|
|
|
|
|
end
|
|
|
|
|
end);
|
|
|
|
|
|
|
|
|
|
function KeyListener:SetModifierState(key, down)
|
|
|
|
|
self.isButtonDown[key] = down == 1;
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function KeyListener:IsButtonDown(key)
|
|
|
|
|
return self.isButtonDown[key]
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function KeyListener:ResetButtonStates()
|
|
|
|
|
self.isButtonDown = {};
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
KeyListener:SetScript("OnKeyDown", function(self, key, down)
|
|
|
|
|
--print("|cFF8cd964"..key);
|
|
|
|
|
self:SetPropagateKeyboardInput(true);
|
|
|
|
|
end);
|
|
|
|
|
|
|
|
|
|
KeyListener:SetScript("OnKeyUp", function(self, key, down)
|
|
|
|
|
--print("|cFFff8000"..key);
|
|
|
|
|
self:SetPropagateKeyboardInput(true);
|
|
|
|
|
end);
|
|
|
|
|
|
|
|
|
|
KeyListener:SetScript("OnGamePadStick", function(self, ...)
|
|
|
|
|
if self:IsButtonDown("PADRTRIGGER") or self:IsButtonDown("RCTRL") then
|
|
|
|
|
local stick, x, y, a = ...
|
|
|
|
|
if stick == "Right" then
|
|
|
|
|
y = 0.1 * y;
|
|
|
|
|
if y > 0 then
|
|
|
|
|
CameraZoomIn(y);
|
|
|
|
|
elseif y < 0 then
|
|
|
|
|
CameraZoomOut(-y);
|
|
|
|
|
else
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
self:SetPropagateKeyboardInput(false);
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
local stick, x, y, a = ...
|
|
|
|
|
if stick == "Right" then
|
|
|
|
|
addon.CameraRotater:Yaw(x);
|
|
|
|
|
self:SetPropagateKeyboardInput(false);
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end)
|
|
|
|
|
|
|
|
|
|
KeyListener:SetScript("OnGamePadButtonDown", function(self, key)
|
|
|
|
|
--print("|cFF8cd964"..key);
|
|
|
|
|
if key == "PADBACK" or key == "PADSYSTEM" then
|
|
|
|
|
Narci:CloseCharacterUI();
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
self.isButtonDown[key] = true;
|
|
|
|
|
SignalGamePadActive();
|
|
|
|
|
local hold, propagate = self:ProcessKeyDown(key);
|
|
|
|
|
if hold and IsNavigationKeys[key] then
|
|
|
|
|
self:HoldKey(key);
|
|
|
|
|
else
|
|
|
|
|
Repeater:Stop();
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
self:SetPropagateKeyboardInput(propagate);
|
|
|
|
|
if SIGNAL_PRESS[key] then
|
|
|
|
|
GamePadButtonPool:SignalPress(key);
|
|
|
|
|
end
|
|
|
|
|
end)
|
|
|
|
|
|
|
|
|
|
KeyListener:SetScript("OnGamePadButtonUp", function(self, key)
|
|
|
|
|
--print("|cFFff8000"..key);
|
|
|
|
|
self.isButtonDown[key] = false;
|
|
|
|
|
Repeater:Stop();
|
|
|
|
|
self:ProcessKeyUp(key);
|
|
|
|
|
end)
|
|
|
|
|
|
|
|
|
|
function KeyListener:ProcessKeyDown(key, isRepeated)
|
|
|
|
|
local hold, propagate;
|
|
|
|
|
if IsNavigationKeys[key] then
|
|
|
|
|
if key == "PADDLEFT" then
|
|
|
|
|
hold, propagate = ActiveGroup:Navigate(-1, 0);
|
|
|
|
|
elseif key == "PADDRIGHT" then
|
|
|
|
|
hold, propagate = ActiveGroup:Navigate(1, 0);
|
|
|
|
|
elseif key == "PADDUP" then
|
|
|
|
|
hold, propagate = ActiveGroup:Navigate(0, 1);
|
|
|
|
|
elseif key == "PADDDOWN" then
|
|
|
|
|
hold, propagate = ActiveGroup:Navigate(0, -1);
|
|
|
|
|
elseif key == "PADLSHOULDER" then
|
|
|
|
|
hold, propagate = ActiveGroup:Switch(-1);
|
|
|
|
|
elseif key == "PADRSHOULDER" then
|
|
|
|
|
hold, propagate = ActiveGroup:Switch(1);
|
|
|
|
|
else
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
hold, propagate = ActiveGroup:KeyDown(key);
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if propagate == nil then
|
|
|
|
|
propagate = false;
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
return hold, propagate
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function KeyListener:ProcessKeyUp(key)
|
|
|
|
|
ActiveGroup:KeyUp(key);
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function KeyListener:HoldKey(key)
|
|
|
|
|
Repeater:SetKeyAndStart(key);
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function KeyListener:Activate()
|
|
|
|
|
self:Show();
|
|
|
|
|
self:EnableGamePadButton(true);
|
|
|
|
|
self:EnableKeyboard(true);
|
|
|
|
|
self:SetFrameStrata("FULLSCREEN_DIALOG");
|
|
|
|
|
self:SetFrameLevel(1208);
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function KeyListener:Deactivate()
|
|
|
|
|
self:Hide();
|
|
|
|
|
self:SetPropagateKeyboardInput(true);
|
|
|
|
|
Proxy:Remove();
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
--Hold to Repeat Aey Actions
|
|
|
|
|
Repeater.t = 0;
|
|
|
|
|
Repeater.interval = 0.25;
|
|
|
|
|
Repeater:SetScript("OnUpdate", function(self, elapsed)
|
|
|
|
|
self.t = self.t + elapsed;
|
|
|
|
|
if self.t > self.interval then
|
|
|
|
|
self.t = 0;
|
|
|
|
|
if self.key and KeyListener:IsButtonDown(self.key) then
|
|
|
|
|
local isValid = KeyListener:ProcessKeyDown(self.key, true);
|
|
|
|
|
if not isValid then
|
|
|
|
|
self:Hide();
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
self:Hide();
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end);
|
|
|
|
|
|
|
|
|
|
Repeater:SetScript("OnHide", function(self)
|
|
|
|
|
self.callBack = nil;
|
|
|
|
|
self.t = 0;
|
|
|
|
|
end);
|
|
|
|
|
|
|
|
|
|
function Repeater:SetInterval(interval)
|
|
|
|
|
self.interval = interval or 0.25;
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function Repeater:SetKeyAndStart(key)
|
|
|
|
|
if key then
|
|
|
|
|
self:Hide();
|
|
|
|
|
self.key = key;
|
|
|
|
|
self:Start();
|
|
|
|
|
else
|
|
|
|
|
self:Stop();
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function Repeater:Start()
|
|
|
|
|
self.t = -0.25; --initial delay
|
|
|
|
|
self:Show();
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function Repeater:Stop()
|
|
|
|
|
self:Hide();
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
------------------------------------------------------
|
|
|
|
|
Loader:RegisterEvent("ADDON_LOADED");
|
|
|
|
|
--[[
|
|
|
|
|
Loader:RegisterEvent("GAME_PAD_ACTIVE_CHANGED");
|
|
|
|
|
Loader:RegisterEvent("GAME_PAD_CONFIGS_CHANGED");
|
|
|
|
|
Loader:RegisterEvent("GAME_PAD_CONNECTED");
|
|
|
|
|
Loader:RegisterEvent("GAME_PAD_DISCONNECTED");
|
|
|
|
|
|
|
|
|
|
function Loader:OnActiveChanged(isActive)
|
|
|
|
|
if isActive then
|
|
|
|
|
print("Game pad is active");
|
|
|
|
|
else
|
|
|
|
|
print("Game pad is inactive");
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function Loader:OnConfigChanged()
|
|
|
|
|
print("Game pad config changed");
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function Loader:OnConnected()
|
|
|
|
|
print("Game pad connected");
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function Loader:OnDisconnected()
|
|
|
|
|
print("Game pad disconnected");
|
|
|
|
|
end
|
|
|
|
|
--]]
|
|
|
|
|
|
|
|
|
|
function Loader:Init()
|
|
|
|
|
print("Narcissus GamePad enabled");
|
|
|
|
|
|
|
|
|
|
hooksecurefunc("Narci_Open", function()
|
|
|
|
|
if Narci.isActive then
|
|
|
|
|
KeyListener:Activate();
|
|
|
|
|
SelectActionGroup("EquipmentSlot"); --CharacterFrame
|
|
|
|
|
else
|
|
|
|
|
self:ExitGamePadMode();
|
|
|
|
|
end
|
|
|
|
|
end)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
local EquipmentOption = Narci_EquipmentOption;
|
|
|
|
|
hooksecurefunc(EquipmentOption, "SetFromSlotButton", function(f, slotButton, returnHome)
|
|
|
|
|
SelectActionGroup("EquipmentOption", true);
|
|
|
|
|
end);
|
|
|
|
|
|
|
|
|
|
hooksecurefunc(EquipmentOption, "CloseUI", function()
|
|
|
|
|
SelectActionGroup("EquipmentSlot");
|
|
|
|
|
end);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
local EquipmentFlyout = Narci_EquipmentFlyoutFrame;
|
|
|
|
|
|
|
|
|
|
hooksecurefunc(EquipmentFlyout, "DisplayItemsBySlotID", function(f, slotButton, slotChanged)
|
|
|
|
|
SelectActionGroup("SwapItem", slotChanged);
|
|
|
|
|
end);
|
|
|
|
|
|
|
|
|
|
EquipmentFlyout:HookScript("OnHide", function(frame)
|
|
|
|
|
SelectActionGroup("EquipmentSlot");
|
|
|
|
|
end);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
hooksecurefunc(Narci_NavBar, "SelectTab", function(f, tabID)
|
|
|
|
|
if tabID == 1 then
|
|
|
|
|
SelectActionGroup("CharacterFrame", 1);
|
|
|
|
|
elseif tabID == 2 then
|
|
|
|
|
SelectActionGroup("SetManager");
|
|
|
|
|
elseif tabID == 3 then
|
|
|
|
|
SelectActionGroup("MythicPlus");
|
|
|
|
|
elseif tabID == 4 then
|
|
|
|
|
--SelectActionGroup("Soulbind");
|
|
|
|
|
end
|
|
|
|
|
end);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
EquipmentOption.ItemList:HookScript("OnShow", function(frame)
|
|
|
|
|
SelectActionGroup("EnhancementList");
|
|
|
|
|
end);
|
|
|
|
|
|
|
|
|
|
EquipmentOption.ItemList:HookScript("OnHide", function(frame)
|
|
|
|
|
SelectActionGroup("EquipmentOption");
|
|
|
|
|
end);
|
|
|
|
|
|
|
|
|
|
Narci_TitleFrame:HookScript("OnShow", function(frame)
|
|
|
|
|
SelectActionGroup("TitleManager");
|
|
|
|
|
end);
|
|
|
|
|
Narci_TitleFrame:HookScript("OnHide", function(frame)
|
|
|
|
|
SelectActionGroup("CharacterFrame");
|
|
|
|
|
end);
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function Loader:ExitGamePadMode()
|
|
|
|
|
KeyListener:Deactivate();
|
|
|
|
|
self:ResetNavigation();
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function Loader:ResetNavigation()
|
|
|
|
|
addon.CameraRotater:Stop();
|
|
|
|
|
for name, actionGroup in pairs(ACTION_GOUPS) do
|
|
|
|
|
actionGroup:ResetNavigation();
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function Loader:OnGamePadActiveChanged(isActive)
|
|
|
|
|
if isActive then
|
|
|
|
|
addon.GamePadNavBar:Show();
|
|
|
|
|
else
|
|
|
|
|
addon.GamePadNavBar:Hide();
|
|
|
|
|
if ActiveGroup.currentObj and ActiveGroup.currentObj.OnLeave and not ActiveGroup.currentObj:IsMouseOver() then
|
|
|
|
|
ActiveGroup.currentObj:OnLeave();
|
|
|
|
|
end
|
|
|
|
|
self:ResetNavigation();
|
|
|
|
|
end
|
|
|
|
|
GamePadButtonPool:OnGamePadActiveChanged(isActive);
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
Loader:SetScript("OnEvent", function(self, event, ...)
|
|
|
|
|
if event == "ADDON_LOADED" then
|
|
|
|
|
local name = ...
|
|
|
|
|
if name == "Narcissus_GamePad" then
|
|
|
|
|
self:UnregisterEvent(event);
|
|
|
|
|
self:Init();
|
|
|
|
|
end
|
|
|
|
|
elseif event == "GAME_PAD_ACTIVE_CHANGED" then
|
|
|
|
|
self:OnActiveChanged(...);
|
|
|
|
|
elseif event == "GAME_PAD_CONFIGS_CHANGED" then
|
|
|
|
|
self:OnConfigChanged(...);
|
|
|
|
|
elseif event == "GAME_PAD_CONNECTED" then
|
|
|
|
|
self:OnConnected(...);
|
|
|
|
|
elseif event == "GAME_PAD_DISCONNECTED" then
|
|
|
|
|
self:OnDisconnected(...);
|
|
|
|
|
end
|
|
|
|
|
end)
|