Advanced mouse thumb buttons

Advanced mouse thumb buttons

Discuss Lua based Spring scripts (LuaUI widgets, mission scripts, gaia scripts, mod-rules scripts, scripted keybindings, etc...)

Moderator: Moderators

Post Reply
DrHash
Posts: 18
Joined: 07 Sep 2011, 00:30

Advanced mouse thumb buttons

Post by DrHash »

Hi folks,

I've been playing around with widget Mouse Reclaim (http://widgets.springrts.de/springinfo/index.php#187). This widget assigns actions to mouse thumb buttons (buttons 4 and 5). I finally ended with a completely different widget which is supposed to do the following things:

- pressing and releasing button 4 issues command "repair" if the selected unit can repair, or command "fight" otherwise
- pressing and releasing button 5 issues command "reclaim" if the selected unit can reclaim, or "attack" otherwise
- pressing and releasing both buttons 4 & 5 issues command "resurrect" if the selected unit can resurrect, or "patrol" otherwise

The source code is as follows:

Code: Select all

function widget:GetInfo()
    return {
        name      = "Mouse thumbs",
        desc      = "Assign actions to thumb mouse buttons, either when pressed alone or together",
        author    = "DrHash",
        version   = "v1",
        date      = "Sep 15, 2010",
        license   = "GNU GPL, v3 or later",
        layer     = 0,
        enabled   = true,
   }
end

--------------------------------------
--Configuration: modify at your will--
--------------------------------------

local thumbButton1 = 4
local thumbButton2 = 5

local thumb1Command = "Repair"
local thumb1AlternativeCommand = "Fight"
local thumb2Command = "Reclaim"
local thumb2AlternativeCommand = "Attack"
local thumbComboCommand = "Resurrect"
local thumbComboAlternativeCommand = "Patrol"

---------
--Flags--
---------

local thumb1Pressed = false
local thumb2Pressed = false
local bothThumbsHaveBeenPressed = false

------------
--Speedups--
------------

local SetActiveCommand = Spring.SetActiveCommand
local GetActiveCommand = Spring.GetActiveCommand

-------------
--Functions--
-------------

--Issue command, if possible; if not, try alternative command
function issueCommand(command, alternativeCommand)
  SetActiveCommand(command)
  local _, _, _, currentActiveCommand = GetActiveCommand() 
  if (currentActiveCommand == command) then
    Spring.Echo(command)
  else
    SetActiveCommand(alternativeCommand)
    Spring.Echo(alternativeCommand)
  end
end

-- Just register thumb button presses
function widget:MousePress(x, y, button)
  Spring.Echo("Press " .. button)
  if (button == thumbButton1) then
    thumb1Pressed = true
    bothThumbsHaveBeenPressed = thumb2Pressed
    Spring.Echo(thumb1Pressed, thumb2Pressed, bothThumbsHaveBeenPressed)
    return true
  end
  if (button == thumbButton2) then
    thumb2Pressed = true
    bothThumbsHaveBeenPressed = thumb1Pressed
    Spring.Echo(thumb1Pressed, thumb2Pressed, bothThumbsHaveBeenPressed)
    return true
  end
  return false
end

-- Execute actions upon releasing thumb buttons
function widget:MouseRelease(x, y, button)
  Spring.Echo("Release " .. button)
  if (button ~= thumbButton1 and button ~= thumbButton2) then -- No thumb buttons released; do nothing here
    Spring.Echo("Nothing to do")
    return false
  end

--  local alt,ctrl,meta,shift = Spring.GetModKeyState()

-- if thumb2 has not been released, then it has been thumb1: thumb1Pressed = false
-- otherwise thumb2 has been released instead of thumb1: thumb1 continues to be pressed if it was already pressed
  thumb1Pressed = (thumb1Pressed and button == thumbButton2)
-- same logic applies here but for the other thumb button (exchange numbers 1 and 2)
  thumb2Pressed = (thumb2Pressed and button == thumbButton1)
  Spring.Echo(thumb1Pressed, thumb2Pressed, bothThumbsHaveBeenPressed)

  if (bothThumbsHaveBeenPressed) then -- Both thumb buttons have been pressed...
    if (not(thumb1Pressed or thumb2Pressed)) then -- ...and now both have been released: execute thumb-combo action
      issueCommand(thumbComboCommand, thumbComboAlternativeCommand)
      bothThumbsHaveBeenPressed = false
      Spring.Echo(thumb1Pressed, thumb2Pressed, bothThumbsHaveBeenPressed)
    end
-- In case there is one button to release yet, do nothing until then
    return true
  end
 
-- Just one thumb button has been pressed and released; execute corresponding action
  if (button == thumbButton1) then -- Releasing thumb1
    issueCommand(thumb1Command, thumb1AlternativeCommand)
  else -- Releasing thumb2
    issueCommand(thumb2Command, thumb2AlternativeCommand)
  end
  return true
end
The bottom line: the previous code doesn't work!! It seems Spring has a weird way of informing about mouse button presses and releases, or I didn't understand how functions MousePress and MouseRelease work. I'm sure the mouse buttons are working since presses and releases are properly reported by tool "xev" (under Ubuntu). I've read that within the same widget there must be a couple of functions MousePress and MouseRelease working together, and that MousePress must return true upon a mouse button press so that MouseRelease is called upon releasing that mouse button. Well, I wrote this small code in order to test this behavior:

Code: Select all

function widget:GetInfo()
    return {
        name      = "Mouse thumb test",
        desc      = "Test press/release events of mouse thumb buttons",
        author    = "DrHash",
        version   = "v1",
        date      = "Sep 15, 2010",
        license   = "GNU GPL, v3 or later",
        layer     = 0,
        enabled   = true,
   }
end

---------------------------------
--Configuration: modify at will--
---------------------------------

local thumbButton1 = 4
local thumbButton2 = 5

-------------
--Functions--
-------------

-- Register thumb button presses
function widget:MousePress(x, y, button)
  Spring.Echo("Press " .. button)
  if (button == thumbButton1) then
    return true
  end
  if (button == thumbButton2) then
    return true
  end
  return false
end

function widget:MouseRelease(x, y, button)
  Spring.Echo("Release " .. button)
  if (button == thumbButton1) then
    return true
  end
  if (button == thumbButton2) then
    return true
  end
  return false
end
So, pressing and releasing one thumb button produces the corresponding press/release events. However, when I do the following:

press4, press5, release5, release4

the last release is not reported. If I do the following:

press4, press5, release4, release5

again, the last release is not reported. It seems that, whenever pressing several mouse buttons and then releasing them, only the first release is reported and the others act like they never existed. Am I right? Can someone tell me exactly when and what should I return from functions MousePress and MouseRelease? Does MouseRelease even have to return something?

Thanks.
Last edited by DrHash on 15 Sep 2011, 23:23, edited 2 times in total.
User avatar
Jools
XTA Developer
Posts: 2816
Joined: 23 Feb 2009, 16:29

Re: Advanced mouse thumb buttons

Post by Jools »

Mouserelease has to return true if you don't want any other events to process the action, otherwise, if you want other events to process the action you must return false.

Sometimes other events can interfere, check that no other events in any other widget returns true for the release of mousebutton 5.

Edit: it seems the release event of button 5 never gets called because the release of button 4 already returns true.
DrHash
Posts: 18
Joined: 07 Sep 2011, 00:30

Re: Advanced mouse thumb buttons

Post by DrHash »

Well, assuming that the first button release deletes the second button release, I've written this other version, which seems to work:

Code: Select all

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--
--  file:    gui_mouse_thumbs.lua
--  brief:   Assign up to 6 actions to thumb mouse buttons, either when pressed alone or together
--  author:  DrHash
--  version: 1.0
--
--  Copyright (C) 2011.
--  Licensed under the terms of the GNU GPL, v3 or later.
--
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

function widget:GetInfo()
    return {
        name      = "Mouse thumbs",
        desc      = "Assign up to 6 actions to thumb mouse buttons, either when pressed alone or together",
        author    = "DrHash",
        version   = "v1",
        date      = "Sep 15, 2010",
        license   = "GNU GPL, v3 or later",
        layer     = 0,
        enabled   = true,
   }
end

---------------------------------
--Configuration: modify at will--
---------------------------------

local thumbButton1 = 4
local thumbButton2 = 5
local thumbCommand1 = "Repair"
local thumbAlternativeCommand1 = "Fight"
local thumbCommand2 = "Reclaim"
local thumbAlternativeCommand2 = "Attack"
local thumbComboCommand = "Resurrect"
local thumbComboAlternativeCommand = "Patrol"

---------
--Flags--
---------

local thumbPressed1 = false
local thumbPressed2 = false

------------
--Speedups--
------------

local SetActiveCommand = Spring.SetActiveCommand
local GetActiveCommand = Spring.GetActiveCommand

-------------
--Functions--
-------------

--Issue command, if possible; if not, try alternative command
function issueCommand(command, alternativeCommand)
  SetActiveCommand(command)
  local _, _, _, currentActiveCommand = GetActiveCommand() 
  if (currentActiveCommand ~= command) then
    SetActiveCommand(alternativeCommand)
  end
end

-- Just register thumb button presses
function widget:MousePress(x, y, button)
  if (button == thumbButton1) then
    thumbPressed1 = true
    return true
  end
  if (button == thumbButton2) then
    thumbPressed2 = true
    return true
  end
  return false
end

function widget:MouseRelease(x, y, button)
  if (button == thumbButton1) then
    thumbPressed1 = false
    if (thumbPressed2) then
      thumbPressed2 = false -- Second button release is not reported by Spring; assume it takes place
      issueCommand(thumbComboCommand, thumbComboAlternativeCommand)
    else
      issueCommand(thumbCommand1, thumbAlternativeCommand1)
    end      
    return true
  elseif (button == thumbButton2) then
    thumbPressed2 = false
    if (thumbPressed1) then
      thumbPressed1 = false -- Second button release is not reported by Spring; assume it takes place
      issueCommand(thumbComboCommand, thumbComboAlternativeCommand)
    else
      issueCommand(thumbCommand2, thumbAlternativeCommand2)
    end
    return true
  else
    return false
  end
end
Note that you must press and release the buttons in order to send the command; the widget must wait for a possible "dual" press in order to know if it must trigger a single button action or a dual button action.

Cheers,

DrHash
DrHash
Posts: 18
Joined: 07 Sep 2011, 00:30

Re: Advanced mouse thumb buttons

Post by DrHash »

A cool feature would be to be able to use thumb buttons without having to later press mouse button 1; for instance, just keep pressed one thumb button in order to extend the reclaim, repair or attack circle. When pressing both buttons at once, the reclaim/repair/attack circle would then be replaced by a resurrect circle, and upon releasing the buttons the command would be executed/enqueued. Anyone taking the challenge?
Post Reply

Return to “Lua Scripts”