• Dear Guest,

    You're browsing our forum as a Guest meaning you can only see a portion of the forum in read-only mode.
    To view all forum nodes and be able to create threads/posts please register or log-in with your existing account.

    TwinStar team

Lua coding for 1.12 - How can I register shift+click?

hivju

Authorized
Joined
Oct 23, 2014
Hey guys,

I am currently trying to modify an addon for WebDKP. We have earlier used WebDKP version 2.5.1, which seemed to work very well with the 1.12 patch. The problem with this version is, however, not being able to upload the log to the webpage. We had to manually add all items and awards after the raid.
We later learned that the version 2.7 was able to upload to the site.

After going through the lua-code of this addon I discovered how to use the addon (because there were no instructions for the commands). I learned that I had to be whispered !startbid [item] to start a bidding-session, and the old way (WebDKP 2.5.1) of getting a prompt to charge dkp to a player who received item, did not work anymore.

My main concern with this addon is that some of the coding seem like it was maybe for a newer patch than 1.12 (I might be wrong). Now I currently do not have a solution on how to shift+click an item to be the next item to be bid on.

My problem:
I need to be able to shift+left-click on a link from the chat. I will then take the item information and put up for bidding. I am having problem with having a post hook on the shift+left-click, to register when it clicks, so I can actually get the information. The rest should be fine.

I have have tried:
hooksecurefunc() -- seem to not recognize the function. Maybe it is for a newer patch?

HookScript -- seem to not be recognized. Maybe it is for a newer patch?
When I tried the code below it did not recognize the _G[....]. Maybe I can do it another way?

Code:
for i = 1, 4 do
    local lootButton = _G["LootButton"..i]
    lootButton:HookScript("OnClick", WebDKP_myFunction)
end


What I tried, and "kinda" worked was:
Code:
WebDKP_SetItemRef_OnEvent_Original = nil;
if ( SetItemRef ~= WebDKP_myFunction ) then        
    WebDKP_SetItemRef_OnEvent_Original = SetItemRef;
    SetItemRef = WebDKP_myFunction;
end

The problem with this code was that it was overriding the original SetItemRef, and now i.e I couldn´t right-click an item that was linked to get information about it. Maybe it is possible to use SetItemRef in a more secure way? (like hooksecurefunc() should worked :p ).

Maybe there is an eventhandler that could manage my problem better? All I want is to register when a shift+click occurs from the chat and do something with the clicked information!

Hopefully there is someone here with more experience than me :) (first time trying lua)

--
Cheers
Tzui <Agony> - Horde
 
Code:
for i = 1, 4 do
    local f = [FONT=Verdana]getglobal([/FONT][FONT=Verdana]"LootButton"..i):GetScript("OnClick")[/FONT]
    getglobal([FONT=Verdana]"LootButton"..i)[/FONT][FONT=Verdana]:SetScript("OnClick", function(...) if IsShiftKeyDown() then WebDKP_myFunction(...) else f(...) end end)
[/FONT][FONT=Verdana]end[/FONT]
 
Thanks for the fast reply Flynn :)

I am still quite new at lua coding, and didn´t quite get this to work at once.
Does it really matter how many variables I take from the function(..) ? I tried with all three, function(self, button, down), just so I could put else f(self,button,down), in case this would mess up my normal commands. My guess it that it doesn´t really matter as long as I have at least the "self" variable :>

I don´t get the code to run tho.
Here is an example I´ve run.
ex:
Code:
for i = 1, 4 do
    local f = getglobal("LootButton"..i):GetScript("OnClick")
    getglobal("LootButton"..i):SetScript("OnClick", function(self, button, down) if IsShiftKeyDown() then DEFAULT_CHAT_FRAME:AddMessage("testing shiftclick") else f(self, button, down) end end)
end

I also tried:
Code:
for i = 1, 4 do
    	local f = getglobal("LootButton"..i):GetScript("OnClick");
    	getglobal("LootButton"..i):SetScript("OnClick", function(self, button) 
    		if IsShiftKeyDown() then 
			DEFAULT_CHAT_FRAME:AddMessage("test 1");
    			WebDKP_ItemChatClick(self);  --- This is the function I want to run.
    		else
			DEFAULT_CHAT_FRAME:AddMessage("test 2");
    			f(self, button);
    		end
    	end);
end

As we can see from the last code-snippet above WebDKP_ItemChatClick(self, button) is the function I want to run.
It takes in (link, text, button), but it only uses the first variable which is the link information. However I can´t even get the test messages to pop in-game when I run this.

I´ve put this code in the WebDKP_OnEnable(), so this will load when the addon loads. Hopefully this is the correct place.


--
Cheers
Tzui <Agony> - Horde
 
Cut the self shit. That doesn't work in Lua 5.0 with the Vanilla client. You have to use this inside the function but no explicitly pass it as a parameter.

So remove the self parameter from your hooked function. MOST likely, you will have to remove ALL parameters, because WoW does some weird shit where variables like "this", "button" and other things are global. So using them as a function parameter makes them inaccessible within the actual function (as you're overwriting the globals in the current "namespace").

Also yes, hooksecurefunc wasn't implement (at least not properly) in Vanilla. You can't get the original parameters, not even in TBC. So you hook the original function by saving it in a local variable, then overwriting it (e.g. button.onClick = function() end)
 
Last edited:
Thanks for the feedback Schaka.
I am still pretty new with this lua coding, so I got some more question.

Cut the self shit. That doesn't work in Lua 5.0 with the Vanilla client. You have to use this inside the function but no explicitly pass it as a parameter.

Considering the code Flynn suggested, shall I just write:
Code:
[FONT=monospace]for i = 1, 4 do    local f = [/FONT][FONT=Verdana]getglobal([/FONT][FONT=Verdana]"LootButton"..i):GetScript("OnClick")[/FONT][FONT=monospace]    getglobal([/FONT][FONT=Verdana]"LootButton"..i)[/FONT][FONT=Verdana]:SetScript("OnClick", function() if IsShiftKeyDown() then [/FONT][FONT=monospace]WebDKP_ItemChatClick()[/FONT][FONT=Verdana] else f() end end)[/FONT][FONT=Verdana]end
The WebDKP_ItemChatClick() function I want to active is like this (it was already like this in the code I received from the addon):
Code:
[/FONT][FONT=monospace]function WebDKP_ItemChatClick(link, text, button)[/FONT]
[FONT=monospace]	-- do a search for 'player'. If it can be found... this is a player link, not an item link. It can be ignored[/FONT]
[FONT=monospace]	local idx = strfind(text, "player");[/FONT]
[FONT=monospace]	[/FONT]
[FONT=monospace]	if( idx == nil ) then[/FONT]
[FONT=monospace]		-- check to see if the bidding frame wants to do anything with the information[/FONT]
[FONT=monospace]		WebDKP_Bid_ItemChatClick(link, text, button);[/FONT]
[FONT=monospace]		[/FONT]
[FONT=monospace]		-- put the item text into the award editbox as long as the table frame is visible[/FONT]
[FONT=monospace]		if ( IsShiftKeyDown()) then[/FONT]
[FONT=monospace]			local _,itemName,_ = WebDKP_GetItemInfo(link); [/FONT]
[FONT=monospace]			WebDKP_AwardItem_FrameItemName:SetText(itemName);[/FONT]
[FONT=monospace]		end[/FONT]
[FONT=monospace]	end[/FONT]
[FONT=monospace]end
[/FONT]

Is this what you mean by not explicitly passing the parameters, when the function is just saying which parameters it like to receive?

The first code for the hook still doesn´t work. I have tired to put DEFAULT_CHAT_FRAME:AddMessage("test") in several places in the code, but it seem to not be running at all.

Maybe there is a way I can do what you suggest when you say: "So you hook the original function by saving it in a local variable, then overwriting it (e.g. button.onClick = function() end)"

Can you give me a code example of that so I can understand it better?
Sorry for not understanding it more easily. I appriciate all the help!

--
Cheers
Tzui <Agony> - Horde
 
Hivju:

Code:
for i = 1, 4 do
    getglobal("LootButton"..i):SetScript("OnClick", function() 
        if IsShiftKeyDown() then 
            DEFAULT_CHAT_FRAME:AddMessage("Test Shift is pressed and you clicked on "..this:GetName())
        else
            DEFAULT_CHAT_FRAME:AddMessage("Test Shift is not pressed and you clicked on "..this:GetName())
        end
    end)
end
 
Last edited:
I tested it, but I still don´t get either of the test messages.

I even tried with putting
DEFAULT_CHAT_FRAME:AddMessage("Loading the code...")
just before the for-loop.

I can see the "Loading the code..."-message, but I can not see anything else when I try to shift-click a linked item.
Maybe there is something that overrides this shift+click function?
 
You need to click on item in loot window not in chat. If you want chat item, try this instead:

oldClick = ChatFrame1:GetScript("OnHyperlinkClick")
ChatFrame1:SetScript("OnHyperlinkClick", function() ChatFrame1:AddMessage("TEST"); oldClick() end)

--
 
This worked perfectly! The click from the loot window seem to not work yet, but I havn´t tested it 100%. For now I am happy with the click from link.
Thanks for the help so far.

However, my next problem is:
How can I save the information / pass the parameters from the linked item that I clicked?
 
function() ChatFrame1:AddMessage(arg1, arg2 --[[itemString, itemLink]]); oldClick() end)
 
It works!
Thanks for the help. It was truly appreciated! :)

--
Cheers
Tzui <Agony> - Horde
 
While we´re at it, I have two more questions.
I think the solutions should be fairly easy, but with my less than average experience with this programming, I need to ask to learn more:

I learned that the clicking from loot window did not work because I have an additional addon, called XLoot.
Question one:

When I use this code:
Code:
for i = 1, 4 do
    	getglobal("LootButton"..i):SetScript("OnClick", function() 
	        if ( IsShiftKeyDown() ) then 
	            DEFAULT_CHAT_FRAME:AddMessage("Test Shift is pressed and you clicked on "..this:GetName())
	            WebDKP_Bid_ShowUI() 
	            WebDKP_ItemChatClick() -- I want parameters sent here with info about clicked item
	            return 1 --> continues with a normal function to loot an item
	        else
	            DEFAULT_CHAT_FRAME:AddMessage("Test Shift is not pressed and you clicked on "..this:GetName())
	            return nil --> do nothing else on click
	        end
    	end)
end

The argument I get here is only arg1, which is a variable for the button I clicked on my mouse. I only need the information about the item I clicked on, to send as parameters.


Question two:
Is it hard to do a similar function for the loot window that the XLoot addon uses?
Can we maybe just do it like this? (if the xloot window is among the globals...):
" getglobal("XLoot"..i):SetScript("OnClick", function() "

Perhaps the XLoot window has a different name I can refer to, or maybe this is not possible?
I tried to read some of the XLoot code, but since im not that experienced, it not easy to know what to look for.

--
Cheers
Tzui <Agony> - Horde
 
As a general rule, you can hook any Lua function that is global. If XLoot is not using globals or for some reason doesn't name its frames (which makes them globally available), it won't be possible. You should just have a look into XLoot and find out for yourself.

Also, you're missing a keypart of what Flynn told you, you're forgetting to call the original function in your code here.

You store the old click function in a local variable, by using GetScript on whatever button. You then need to call that function (oldClick() in Flynn's code) after or before your own, INSIDE your new click function. Otherwise you are just overwriting whatever original function was bound to a click on that button and NOT hooking it. By overwriting it, you are getting rid of the original functionality, which is bound to break at least 5 other addons and the default interface.
 
I finally got a working solution for everything I wanted.

If anyone is interested, here is how I did it:

Code to shift+click from the chat:
Code:
local oldClick = ChatFrame1:GetScript("OnHyperlinkClick")
ChatFrame1:SetScript("OnHyperlinkClick", function() 
    if ( IsShiftKeyDown() and WebDKP_BidFrame:IsShown() ) then
        WebDKP_ItemChatClick(arg1, arg2) --[[itemString, itemLink]]
    end
    oldClick() 
end)

Code to shift+click from normal blizzard loot window:
Code:
for i = 1, 4 do
    getglobal("LootButton"..i):SetScript("OnClick", function() 
        if ( IsShiftKeyDown() ) then 
            WebDKP_Bid_ShowUI()
            for i = 1, 4 do
                if string.find(this:GetName(), i) then
                    _, itemName, _, _, _ = GetLootSlotInfo(i)
                    itemLink = GetLootSlotLink(i)
                     WebDKP_ItemChatClick(itemName, itemLink);
                 end
             end
            return 1 --> continues with a normal function to loot an item
        else
            return nil --> do nothing else on click
        end
    end)
end

For last, the maybe hardest challenge (which seemed easy when I found the solution, ofc), is how I manage to fix it with the XLoot addon. After trying a lot of different solutions on how to hook it from webdkp.lua, I gave up and came with the solution to add the onClick inside xloot.lua like this:
Code:
button:SetScript("onClick", WebDKP_Register_ShiftClickLootWindowHook_xloot)

The WebDKP_Register_ShiftClickLootWindowHook_xloot function is pretty similar to the blizzard loot window, except it isn´t limited to 4 items for each window:
Code:
if ( IsShiftKeyDown() ) then 
    WebDKP_Bid_ShowUI()
    for i = 1, GetNumLootItems() do
        if string.find(this:GetName(), i) then
            _, itemName, _, _, _ = GetLootSlotInfo(i)
            itemLink = GetLootSlotLink(i)
             WebDKP_ItemChatClick(itemName, itemLink);
         end
    end
    return 1 --> continues with a normal function to loot an item
else
    return nil --> do nothing else on click
end

For now the code seem to work very well. Something might be somewhat inefficient, but I just hope there is nothing here now that will ruin other addon for me.

--
Cheers
Tzui <Agony> - Horde
 
Last edited:
I need to update this post!
A lot of my code was working, but as I was afraid of and as Schaka warned me about, the oldClick() function was not preserved correctly.

I have recently made some small fixes that should fix this problem. However, I still have a "small" issue still, but will address that after the code.

Fixes:
The bid-window shows "name (rank)" when a bid is set (very helpful to separate the members from the trials). I did, however, not change this info back, so when I tried to award them an item, it couldn´t be added.
I now change the info back to just the name before actually awarding them an item.

For the onClick function of the loot-window (blizzard loot window), I had to also use the oldClick() inside the function. Here is how it is now:
Code:
function WebDKP_Register_ShiftClickLootWindowHook()
    --== For blizzard loot window ==--
    for i = 1, 4 do 
        local oldClick = getglobal("LootButton"..i):GetScript("OnClick")
        getglobal("LootButton"..i):SetScript("OnClick", function() 
            if ( IsShiftKeyDown() ) then 
                WebDKP_Bid_ShowUI()
                for i = 1, 4 do
                    if string.find(this:GetName(), i) then
                        _, itemName, _, _, _ = GetLootSlotInfo(i)
                        itemLink = GetLootSlotLink(i)
                         WebDKP_ItemChatClick(itemName, itemLink);
                     end
                 end
             end
             oldClick()
        end)
    end
end

It is a similar solution for the xloot function. Here is from xloot.lua:555 ish:
Code:
    xLootOldClick = button:GetScript("onClick")
    button:SetScript("onClick", WebDKP_Register_ShiftClickLootWindowHook_xloot)

Which is then again use in webdkp.lua:
Code:
function WebDKP_Register_ShiftClickLootWindowHook_xloot()
    --== This function is run from XLoot.lua:555 when button is onClick ==--
    if ( IsShiftKeyDown() ) then     
        xLootOldClick()
        WebDKP_Bid_ShowUI()
        for i = 1, GetNumLootItems() do
            if string.find(this:GetName(), i) then
                _, itemName, _, _, _ = GetLootSlotInfo(i)
                itemLink = GetLootSlotLink(i)
                 WebDKP_ItemChatClick(itemName, itemLink);
             end
        end
    end
    xLootOldClick()
end

After this fix, I really feel that the code is starting to look good, and should for most parts work.
I had, however, a problem last night at Onyxia. I was ML and using the xloot addon. For those who doesnt know, xloot showns all loot in one list, instead of max 4 at a time. I have never had a problem with this. And after these fixes I have mentioned above (after sunday where problems occured, because oldClick() wasnt looked after), I really thought I was good.
When we killed Onyxia I opened the loot, shift-clicked an item which opened the bid-window with the item and I could start bidding. After that I went for the last item on the list (sack of gems) and wanted to give it to an officer. I found him on the list, everything seemed fine. When I gave it to him I saw: "<name> receives: Onyxia Hide Backpack. The bag was the first item on the list, and I didnt click anywhere near it.

At this point I am not sure if this bug was from the xloot addon, or my coding (most likely). Do I need to run oldClick() before if ( IsShiftKeyDown() ) ? Do I need to return 1, which was proposed earlier? Maybe the function needs to return true to avoid these problems?

I was a bit unlucky since the first item on the list was green, and not purple, which actually gives me a warning: "are you sure you want to give ..item.. to ..player..". I will most likely not have this problem on any other boss than Onyxia, but it would be very nice if I could get solution for this problem and not be afraid to make a new, and maybe bigger mistake in the future.


I was proposed to share my code, so if anyone is interested on how my webdkp code works, want something similar, or just want to steal some code snippets, I´d be happy to help.
One small fix I have added is automatically giving 5dkp to all in raid if a boss dies (and yes, domo dies at raggy event) :)
Other than that I have a /bosskill cmd to prompt me for a reason to give 5dkp to all in raid.
And I have /bid to show bid-window.
Also.. all the raid-chat spam is in norwegian, so you just have to live with that xD
Hopefully someone will find this helpful. Here is a link to the code:
https://www.dropbox.com/s/b3d2joaivrg67e6/WebDKP_and_XLoot_v4.zip?dl=0

The XLoot addon is also there. I have only added those 2 lines, and if you don´t want to use it, the rest will still work.

--
Cheers
Tzui <Agony> - Horde
 
Could it perhaps be a solution to do it like this:
Code:
function WebDKP_Register_ShiftClickLootWindowHook_xloot()
	--== This function is run from XLoot.lua:555 when button is onClick ==--
	if ( IsShiftKeyDown() ) then 	
		xLootOldClick()
	    WebDKP_Bid_ShowUI()
	    for i = 1, GetNumLootItems() do
	    	if string.find(this:GetName(), i) then
	    		_, itemName, _, _, _ = GetLootSlotInfo(i)
	    		itemLink = GetLootSlotLink(i)
	 			WebDKP_ItemChatClick(itemName, itemLink);
	 		end
		end
	end
	return xLootOldClick()
end

I know very little about the oldClick() function, but since you earlier suggested to return 1, else return nil, then perhaps it fails because I don´t return the outcome from oldClick()? The shiftclick should return 1 either time I think, but returning the outcome of xLootOldClick() instead of just running it is the only thing that seems logical for me atm.

Please let me know if I am horribly wrong :D

--
Cheers
Tzui <Agony> - Horde
 
It is a similar solution for the xloot function. Here is from xloot.lua:555 ish:
Code:
    xLootOldClick = button:GetScript("onClick")
    button:SetScript("onClick", WebDKP_Register_ShiftClickLootWindowHook_xloot)

"onClick" ≠ "OnClick"
 
"onClick" ≠ "OnClick"

Wow, well spotted :p

Hopefully this is the problem. But then again I don´t understand what I got from button:GetScript("onClick"), because it definitely helped something.

I will test this as soon as possible and let you guys know if everything works!
 
Top Bottom