Script goes into loop - logitech-gaming-software

I can't solve the problem, when my script goes into infinite loop, and have no idea how to solve it.
I'm using G600 Mouse with LGS, and i want send "9" when mouse button 6 pressed, and send "1" When mouse button 6 released.
The mouse button 6 is also assigned to G-Shift function in LGS
what i've try:
function OnEvent(event, arg,family)
if event == "MOUSE_BUTTON_PRESSED" and arg == 6 then
PressKey("9")
Sleep(100)
end
if event == "MOUSE_BUTTON_RELEASED" and arg == 6 then
PressKey("1")
Sleep(100)
end

You should invoke both pressing and releasing of keys being simulated.
The most simple way is to use PressAndReleaseKey("9") instead of PressKey("9")
The mouse button 6 is also assigned to G-Shift function in LGS
It does not matter.

Related

AUTOHOTKEY: Problem with code which suspend script after clicking key and unsuspend it after clicking 2 another keys. Doing 2 things at the same time

In game chat start with t key and I want that after pressing t on keyboard my script will be suspend and I will can normally write on chat but if I press enter or esc my script will be unsuspended (esc - close chat, enter - send message on chat).
I have problem with this code:
t::
Suspend On
Loop
{
GetKeyState, state, Enter, P
GetKeyState, state2, Escape, P
if (state = Enter){
Suspend Off
break
}
else if (state2 = Escape){
Suspend Off
break
}
}
return
Main problem with this code is loop which not work, and I don't know how to repair it or replace it something more useful or better solution.
Another problem is t key which work but I must click it 2 times, why? First click suspends script, second click runs chat. I want after clicking 1 time t key chat will run and script will suspend. I want the same with enter and esc, to make 2 functions at the same time (enter - unsuspends script and send message on chat, esc - close chat and unsuspends script)
The problem is with the usage of the (deprecated legacy) GetKeyState command, but I must say, the whole solution could be implemented a lot better.
The output value of the command doesn't contain key names, it contains D for down, or U for up, as stated in the documentation. And also you'd need to "quote" your strings.
And the problem with your T key not working on the first press, is of course because you have a hotkey that is capturing the press of the T key.
To not consume the T key press when the hotkey runs, you want to use the ~ modifier(docs).
But anyway, I think a better implementation would be just that a press of the keys simply suspends/unsuspends.
Like so:
~t::Suspend, On
~Enter::
~Esc::Suspend, Off
As a bonus:
The usage of #IfWinActive(docs) might be desirable so the hotkeys only work when your game is active.
#IfWinActive, ahk_exe ExeOfMyGame.exe
~t::Suspend, On
~Enter::
~Esc::Suspend, Off
#IfWinActive
I change code to this:
~t::
Suspend On
Loop
if (GetKeyState("Enter", "P") || GetKeyState("Escape", "P"))
break
Suspend Off
return
Why? Because in #0x464e code was that problem when I suspended script manually and click enter / esc it unsuspended it, I needed after click T it suspend and only enter / esc will unsuspend it. When I manually suspend it in code which is above enter / esc do not unsuspend it.

How can I toggle SetTimer off with a hotkey in AutoHotKey?

I am trying to write a script toggling a function.
This is an AutoHotkey 2 Script.
j::
SetTimer "NewTimer", 1000
return
k::
SetTimer "NewTimer", Off
return
NewTimer() {
SendInput "NewInput"
}
Pressing J should start the timer, pressing K should stop it.
Currently, pressing K only stops it as long as I hold the key down.
How can I stop the timer with the key press?
k::
SetTimer "NewTimer" , "Off"
Return
Off must be in quotes, otherwise it will try to pass the contents of the varaible "Off". The reason holding K seems to pause it is because it's rapidly updating the period to the value contained in Off which is null and an error, so it reverts to the previous period of 1000.
Alternatively, if this is the only timer, using just SetTimer , "Off" also works.
You can consider that excerpt from the official docs for SetTimer:
If hotkey response time is crucial (such as in games) and the script contains any timers whose subroutines take longer than about 5 ms to execute, use the following command to avoid any chance of a 15 ms delay. Such a delay would otherwise happen if a hotkey is pressed at the exact moment a timer thread is in its period of uninterruptibility:
Thread, interrupt, 0 ;//Make all threads always-interruptible.

Modify value in array?

So, I have a number of buttons that adds 1 to a counter. When a button is pressed the first time, it should add 1 to a array. When the button is pushed again, it should modify it to 2 and so on. Every button should modify its own number. Whats the best way to do this? I have tried to remove and insert with new value every time the button is pressed, but that don't seem like a good way to do it.
First create Empty array
var arr = [Int](repeating:0,count:btnsCount)
then connect the buttons to same action
#IBAction func btnClicked(_ sender:UIButton) {
arr[sender.tag] = arr[sender.tag] + 1
}

Non-blocking ReadConsoleInput

I'm writing a Win32 console application that interacts with the mouse. I'm using ReadConsoleInput to get the window-relative mouse movements like so. Here's a simplified version of my problem:
int main(void)
{
HANDLE hStdin;
DWORD cNumRead;
INPUT_RECORD irInBuf[128];
hStdin = GetStdHandle(STD_INPUT_HANDLE);
SetConsoleMode(hStdin, ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT | ENABLE_PROCESSED_INPUT);
while (1)
{
mouse_position_changed = 0;
ReadConsoleInput(hStdin, irInBuf, 128, &cNumRead);
/* input handler here: changes the cursor position if the mouse position changed;
clears screen if mouse position changed;
sets mouse_position_changed (self-explanatory).
(this part of the code is irrelevant to the quesiton at hand) */
if (!mouse_position_changed)
putchar('0');
}
}
(I've removed most of the code including error checks. This is a simple, watered-down version of what I'm doing; it's much larger-scale than making 0's run away from the cursor.)
I want the screen to be cleared and the cursor set to the mouse coordinates whenever the mouse is moved. This part is working.
I want 0 to be printed the screen whenever the mouse is not moved. This will have the effect of 0's running away from the mouse cursor. This is not working, because ReadConsoleInput will block until it receives input.
The 0 is not printed until more input is received. Unless the user continually hits the keyboard, nothing is printed because whenever the mouse is moved, the screen is cleared.
The problem
I would like the loop to continue even when no input is present. ReadConsoleInput waits for input to be read, which means that the loop will pause until the keyboard is hit, or the mouse is moved.
I'm looking for an alternative to ReadConsoleInput, or a way to make it non-blocking.
This is all documented in ReadConsoleInput. You can determine if there is a console input with GetNumberOfConsoleInputEvents. And you are able to to determine the type of console input events with PeekConsoleInput.
So GetNumberOfConsoleInputEvents is all you need.
You can also use WaitForSingleObject with the console handle to wait for a next available input. This is also documented in ReadConsoleInput

Binding to multiple button clicks

To bind to the 1 key I use:
hs.hotkey.bind(hyper, '1'
How to bind to multiple presses of 1 key? Something like:
hs.hotkey.bind(hyper, '1+1'
Reading the documentation, this functionality is not mentioned.
By multiple presses I mean press 1 twice to run some code and press 1 three times to run a separate piece of code.
You're going to have to implement this yourself. Here's a basic summary of how to accomplish this:
Start a timer from zero, and set a flag for the first press initially to false, which indicates the first press has not happened yet
Observe and watch keypresses with hs.eventtap, specifically hs.eventtap.event.types.keyPress
When the event (keyPress) happens, check if the key pressed was the correct key
If it was the right key, check if it's the second press and if it was in time, if it wasn't in time or was not the second press then set the timer to the current time and first flag to true
If it was the second press and was in time, then execute our handler and reset timer and first flag
If it wasn't the right key then reset the timer and first flag
Translated into code, this is what is could look like (I'm not a Lua expert). Note that the flags could be implemented as booleans here, or as an internal table holding keypresses so far which you could check:
local timer = require("hs.timer")
local eventtap = require("hs.eventtap")
local keycodes = require("hs.keycodes")
local events = eventtap.event.types --all the event types
timeFrame = 1 --this is the timeframe in which the second press should occur, in seconds
key = 50 --the specific keycode we're detecting, in this case, 50
--print(keycodes.map["`"]) you can look up the certain keycode by accessing the map
function twoHandler()
hs.alert("Pressed ` twice!") --the handler for the double press
end
function correctKeyChecker(event) --keypress validator, checks if the keycode matches the key we're trying to detect
local keyCode = event:getKeyCode()
return keyCode == key --return if keyCode is key
end
function inTime(time) --checks if the second press was in time
return timer.secondsSinceEpoch() - time < timeFrame --if the time passed from the first press to the second was less than the timeframe, then it was in time
end
local pressTime, firstDown = 0, false --pressTime was the time the first press occurred which is set to 0, and firstDown indicates if the first press has occurred or not
eventtap.new({ events.keyDown }, function(event) --watch the keyDown event, trigger the function every time there is a keydown
if correctKeyChecker(event) then --if correct key
if firstDown and inTime(pressTime) then --if first press already happened and the second was in time
twoHandler() --execute the handler
elseif not firstDown or inTime(pressTime) then --if the first press has not happened or the second wasn't in time
pressTime, firstDown = timer.secondsSinceEpoch(), true --set first press time to now and first press to true
return false --stop prematurely
end
end
pressTime, firstDown = 0, false --if it reaches here that means the double tap was successful or the key was incorrect, thus reset timer and flag
return false --keeps the event propogating
end):start() --start our watcher
I've commented the code line-by-line for a better understanding. If you want to detect 3 or 4 or some other arbitrary N number of presses, just set flags for N - 1 presses and add a few checks, but it's unusual to have key combinations that take more than 2 successive presses. It does seem a little verbose, but AFAIK this is how you do it. To avoid duplicate code and boilerplate, try putting this in a class-like structure or a module so that you can reuse code.
As for executing a different handler for 2 successive presses, or 3 successive presses, that would be a little more hacky since you would have to wait the whole timeframe before knowing if the user will press again to know which handler to execute. That would cause a slight delay and a bad user experience, I would suggest against that, though you could probably implement that by refactoring the code and doing some more checks such as if it's the timeframe and the first flag was triggered, then execute the handler for one press.
You can not bind all keys or multiple keys with bind. Instead you can use this function: http://www.hammerspoon.org/docs/hs.eventtap.html#keyStroke
So the most straight forward programming language agnostic approach is as follows:
Call your function for any key stroke.
Within the function keep a static instance variable that will keep previous key strokes.
As the first task of your function append the new coming character to that variable.
Check the last 3 characters if they are the desired "11" string.
Extra for extreme conditions:
If the variable length pass a certain point reduce it to length 1 so that it does not keep unnecessary place in memory.
A solution for n keypresses
Very late to the party but there's little to no info on this, so I thought I should really put this here considering this is one of the only search results for this.
My solution is a bit more elegant then some others (in my opinion); there are definitely some things that could be improved about it but I'm not really familiar enough with Lua or Hammerspoon to fix them.
It should work to assign a shortcut to as many consecutive keypresses as you want.
Read the code comments for an explanation of how it works. I've tried to be as detailed as possible, in an effort to make it more beginner friendly for those that don't know much about coding and those that aren't that familiar with Lua or Hammerspoon (like me).
require("hs.timer") -- Load timer module, used for timing
keyDownCount = 0 -- Keypress counter, used later in the program to store the number of times the key has been pressed
keyMultipressGapTime = 0.3 -- Max time between consecutive keypresses, used to determine when the user has stopped pressing the key
keyMaxPressCount = 3 -- Max number of key presses
testKeyCode = 18 -- Key code to bind shortcut to (in this case the 1 key)
-- READ CheckKeyDownCount FUNCTION CODE (BELOW) FIRST
-- Function to press a key with code
-- This isn't completely intuitive so I'm including it
-- Im sure there's a better way of doing this but this is what I figured out
function PressKey(keyCode)
keyDown = hs.eventtap.event.newKeyEvent(keyCode, true) -- Create new keydown event using the keycode passed in the keycode argument
keyDown:setProperty(hs.eventtap.event.properties.eventSourceUserData, 1) -- Sets user data byte of keydown event to 1, used later to prevent keydown event handler from self triggering
keyDown:post() -- Fire keydown event
hs.eventtap.event.newKeyEvent(keyCode, false):post() -- Create and fire keyup event using the keycode passed in the keycode argument
end
-- READ EVENT HANDLER CODE (BELOW) FIRST
-- Function to check the number of times the key was pressed and act accordingly
-- Pretty self explanatory
function CheckKeyDownCount()
CheckKeyDownCountTimer:stop() -- Stops keydown timer so it doesn't repeat
-- There may be a better way of doing this but I can't find a way to creating and restarting a non repeating timer without creating a whole new timer object every time
if keyDownCount == 1 then -- Perform action based on number of keypresses
hs.alert("Pressed once")
PressKey(testKeyCode)
elseif keyDownCount == 2 then
hs.alert("Pressed twice")
elseif keyDownCount == 3 then
hs.alert("Pressed thrice")
end
keyDownCount = 0 -- Reset keypress counter
end
CheckKeyDownCountTimer = hs.timer.new(keyMultipressGapTime, CheckKeyDownCount) -- Creates timer for determining when the user has stopped pressing the key
-- Time interval is set to the max time between consecutive keypresses
-- Runs the CheckKeyDownCount function at end of time interval
-- IMPORTANT: Time interval automatically resets when timer is stopped and started
-- Creates keydown event handler
-- FOR BEGINNERS: An event handler is a routine that runs when triggered by an event (kind of like an interrupt if you know what that is), normally they call a function, like below
-- FOR BEGINNERS CONTINUED: The timer above is also an event handler of sorts, with the event being the end of the time interval, event handlers are very useful because they allow asynchronous code execution
-- FOR BEGINNERS CONTINUED: In this case asynchronous code execution means that the program will continue executing until an event needs to be handled, the program will then stop where it is, handel the event, and then jump back to where it left off
multipressBtnShortcuts = hs.eventtap.new({hs.eventtap.event.types.keyDown}, function(event)
-- FOR BEGINNERS: "function(event)" creates anonymous function containing the below code and passes it the keydown event as an object called "event" (Just makes the code neater, you could use a separate function if you want)
-- FOR BEGINNERS CONTINUED: An anonymous function is just a function without an identifier (name), instead they're objects and often behave kinda like variables (look this up, it's kinda hard to explain and not relevant here)
-- RANDOM NOTE: Also turns out all functions in lua are anonymous which is pretty interesting, the interpreter just converts the structure "function foo(x) return 2*x end" into "foo = function (x) return 2*x end"
if event:getKeyCode() == testKeyCode and event:getProperty(hs.eventtap.event.properties.eventSourceUserData) == 0 then -- Check if keycode is the shortcut keycode and check if the user data byte is set to 0 (default)
-- The user data byte check is to prevent the event handler from triggering itself (SEE PressKey FUNCTION ABOVE)
-- I'm sure there's a better way to do this but I cant find it
event:setType(hs.eventtap.event.types.nullEvent) -- Null the keypress event
-- Overrides the keypress, remove if you don't want the original keypresses to be overridden
-- I'm sure there's a better way to do this but I cant find it
keyDownCount = keyDownCount + 1 -- Add one to keypress counter
if CheckKeyDownCountTimer:running() then -- If the max key press gap timer is running stop it (NOTE: Stopping and starting it also resets it)
CheckKeyDownCountTimer:stop()
end
if keyDownCount < keyMaxPressCount then -- If keypress counter is less then the max number of keypresses restart the max key press gap timer (NOTE: Stopping and starting it also resets it)
CheckKeyDownCountTimer:start()
else -- Alternativly, if the keypress counter is greater than or equal to the max number of keypresses run the CheckKeyDownCount function
CheckKeyDownCount()
end
end
return false -- Ends the anonymous function by returning false, not sure if this is really necessary but it's what other people seem to do
end)
multipressBtnShortcuts:start() -- Starts the keydown event handler

Resources