How could I recreate this script using only WinAPI functions?

106 Views Asked by At

Like the title states, I'm attempting to recreate a script I made using only standard WinAPI functions such as IsMouseButtonPressed() PressMouseButton() ReleaseMouseButton() in hopes of making it work using a non-logitech mouse. The script is a simple one that detects when mb5/mb4 is pressed together with right mouse button to simulate keypresses, in this case pressing respectively the key O and P. So if mb5 is pressed together with right mb, it would press O, if mb4 is pressed together with right mb, it would press P. Here is the script:

local mouseButton5Pressed = false
local mouseButton4Pressed = false
local rightMouseButtonPressed = false

function OnEvent(event, arg)
    if event == "MOUSE_BUTTON_PRESSED" then
        if arg == 5 then
            mouseButton5Pressed = true
        elseif arg == 4 then
            mouseButton4Pressed = true
        elseif arg == 2 then
            rightMouseButtonPressed = true
        end
    elseif event == "MOUSE_BUTTON_RELEASED" then
        if arg == 5 then
            mouseButton5Pressed = false
        elseif arg == 4 then
            mouseButton4Pressed = false
        elseif arg == 2 then
            rightMouseButtonPressed = false
        end
    end
    if rightMouseButtonPressed and (mouseButton5Pressed or mouseButton4Pressed) then
        if mouseButton5Pressed then
            PressKey("o")
        else
            ReleaseKey("o")
        end
        if mouseButton4Pressed then
            PressKey("p")
        else
            ReleaseKey("p")
        end
    else
        ReleaseKeys()
    end
end

function ReleaseKeys()
    ReleaseKey("o")
    ReleaseKey("p")
end

So far I've tried a few other versions of the script along these lines:

function OnEvent(event, arg)
    if IsMouseButtonPressed(3) and (IsMouseButtonPressed(5) or IsMouseButtonPressed(4)) then
        if IsMouseButtonPressed(5) then
            PressKey("o")
        else
            ReleaseKey("o")
        end
        
        if IsMouseButtonPressed(4) then
            PressKey("p")
        else
            ReleaseKey("p")
        end
    else
        ReleaseKeys()
    end
end

function ReleaseKeys()
    ReleaseKey("o")
    ReleaseKey("p")
end

However they all feel way less responsive, they stop working when you press the mouse buttons too quickly and fail to release the keys reliably once either mouse button is released, which isn't optimal considering what I intend to use the script for.

Also, since I mentionned how I would like to make it work using a non-logitech mice, I was also curious as to whether or not it was possible to implement (event == "PROFILE_ACTIVATED") in the script so you can invoke the OnEvent function without the logitech mouse. A bit like this script that can be used with any mouse:

EnablePrimaryMouseButtonEvents(true);

function OnEvent(event, arg)
    if (event == "PROFILE_ACTIVATED") then
        repeat  
            if IsMouseButtonPressed(5) then
                repeat
                    PressMouseButton(1)
                    Sleep(15) 
                    ReleaseMouseButton(1)
                    Sleep(15) 
                until not IsMouseButtonPressed(5)
            end             
        until not (event == "PROFILE_ACTIVATED")
    end         
end

I know the formating is different since this a loop and it might not be feasible but I don't really know what else I could do. I'm a bit out of options here so any help would be greatly appreciated.

1

There are 1 best solutions below

1
ESkri On BEST ANSWER
------ outputs

local simulated_by_you = {}

local orig_PressKey = PressKey
local orig_ReleaseKey = ReleaseKey
local orig_PressMouseButton = PressMouseButton
local orig_ReleaseMouseButton = ReleaseMouseButton

function PressKey(key)
   key = tostring(key)
   simulated_by_you[key] = true
   orig_PressKey(key)
end

function ReleaseKey(key)
   key = tostring(key)
   simulated_by_you[key] = false
   orig_ReleaseKey(key)
end

function PressMouseButton(button)
   button = tonumber(button)
   simulated_by_you[button] = true
   orig_PressMouseButton(button)
end

function ReleaseMouseButton(button)
   button = tonumber(button)
   simulated_by_you[button] = false
   orig_ReleaseMouseButton(button)
end

local function release_keys_on_exit()
   for key, status in pairs(simulated_by_you) do
      if status then
         if type(key) == "number" then
            ReleaseMouseButton(key)
         else
            ReleaseKey(key)
         end
      end
   end
end

------ inputs

local input = {}                   -- current value of input
local input_has_changed = {}       -- changed just now in either direction
local input_has_turned_on = {}     -- changed just now from OFF to ON
local input_has_turned_off = {}    -- changed just now from ON to OFF

local input_functions = {
   [IsMouseButtonPressed] = {1, 2, 3, 4, 5},
   [IsModifierPressed]    = {"lalt", "ralt", "alt", "lshift", "rshift", "shift", "lctrl", "rctrl", "ctrl"},
   [IsKeyLockOn]          = {"numlock", "capslock", "scrolllock"},
}

local function refresh_input(ms)
   local tm = GetRunningTime() + (ms or 0)
   repeat
      Sleep(10)
      local something_has_changed
      for func, args in pairs(input_functions) do
         for _, arg in ipairs(args) do
            local old = input[arg]
            local new = func(arg)
            input[arg]                = new
            input_has_changed[arg]    = old ~= new
            input_has_turned_on[arg]  = new and not old
            input_has_turned_off[arg] = not new and old
            something_has_changed = something_has_changed or old ~= new
         end
      end
   until GetRunningTime() >= tm or something_has_changed
end

------ main loop

function OnEvent(event, arg)
   if event == "PROFILE_ACTIVATED" then
      refresh_input()
      repeat
         refresh_input()
         ------------------------------------------------
         -- Your code is here
         -- Read from tables: input, input_has_changed, input_has_turned_on, input_has_turned_off
         --    to obtain inputs: mouse buttons ([1]...[5]), modifier keys (".shift",...), lock key LEDs (".numlock",...)
         -- Invoke functions: PressKey, ReleaseKey, PressAndReleaseKey, PressMouseButton, ReleaseMouseButton, PressAndReleaseMouseButton
         --    to simulate outputs
         -- Read from table simulated_by_you
         --    to determine which keyboard keys (".o",...) and mouse buttons ([1]...[5]) press you have previously simulated and not released them yet
         ------------------------------------------------

         -- if (RMB is currently down) and (button#5 has been pressed just now) or vice versa
         if input[3] and input_has_turned_on[5] or input_has_turned_on[3] and input[5] then
            PressKey("o")
         end
         -- if (you previously simulated key "o" pressed) and (RMB or button#5 has been released just now)
         if simulated_by_you.o and (input_has_turned_off[3] or input_has_turned_off[5]) then
            ReleaseKey("o")
         end

         -- if (RMB is currently down) and (button#4 has been pressed just now) or vice versa
         if input[3] and input_has_turned_on[4] or input_has_turned_on[3] and input[4] then
            PressKey("p")
         end
         -- if (you previously simulated key "p" pressed) and (RMB or button#4 has been released just now)
         if simulated_by_you.p and (input_has_turned_off[3] or input_has_turned_off[4]) then
            ReleaseKey("p")
         end

         ------------------------------------------------
      until input_has_changed.numlock
      release_keys_on_exit()
   end
end

This script works without touching Logitech mouse.
When LGS/GHub profile is switched (when starting another application or when making another application window foreground), OnEvent function is starting.
You must press NumLock (to exit OnEvent function) before every switch to another profile, otherwise LGS/GHub will crash.