Why are spacebar events suppressed when running this script? - autohotkey

I made a script to tile windows with my left hand in windows 10, using a dvorak keyboard layout. It works as expected except, it keeps the spacebar events from getting to any program other than the script itself. This is the keyboard log when running the script:
20 039 s d 0.09 Space
20 039 s u 0.08 Space
20 039 s d 0.08 Space
20 039 s u 0.08 Space
20 039 s d 0.08 Space
20 039 s u 0.09 Space
20 039 s d 0.08 Space
20 039 s u 0.09 Space
20 039 s d 31.14 Space
20 039 s u 0.11 Space
20 039 s d 0.09 Space
20 039 s u 0.11 Space
Both space events are detected correctly, but remain suppressed. Terminating the script manually solves the problem.
#MaxThreads 255 ; for the purpose of troubleshooting
#e::return
#.::return
#o::return
#u::return
Space & u::
Space & .::
Space & o::
Space & e::
send {LWin Down}
spcup()
exit
spcup()
{
while GetKeyState("Space", "P") {
rite := GetKeyState("u", "P")
left := GetKeyState("o", "P")
up := GetKeyState(".", "P")
down := GetKeyState("e", "P")
if (rite=1) {
Sleep 75
Send {Right}
Sleep 75
}
else if (left=1) {
Sleep 75
Send {Left}
Sleep 75
}
else if (up=1) {
Sleep 75
Send {Up}
Sleep 75
}
else if (down=1) {
Sleep 75
Send {Down}
Sleep 75
}
else if !GetKeyState("Space", "P") {
sleep 75
Send {LWinUp}
exit
}
}
}
PS, I used space because my left windows key is physically damaged.
Binding Space to itself adding a "Space::Space" line, works partially, only the up event is registered as a hotkey, so it fires only on release of spacebar producing this:
20 039 s d 0.25 Space
20 039 h u 0.16 Space
20 039 i d 0.00 Space
20 039 i u 0.00 Space
s=suppressed
h=hotkey
i=ignored(sent by autohotkey itself)
"Solved", kind of. No way for a prefix key to maintain it's original function without ~, hence sending it to the active window, which is unwanted.
isWindowFullScreen()
{
;checks if the specified window is full screen
;use WinExist of another means to get the Unique ID (HWND) of the desired window
if WinExist("A") {
WinGet, style, Style, A
WinGetPos ,,,winW,winH, A
; 0x800000 is WS_BORDER.
; 0x20000000 is WS_MINIMIZE.
; no border and not minimized
retVal := ((style & 0x20800000) or winH < A_ScreenHeight or winW < A_ScreenWidth) ? 0 : 1
Return, retVal
}
else {
return
}
}
#if isWindowFullScreen() = 0
#e::return
#.::return
#o::return
#u::return
#Space::return
Space::Space
Space & u::
Space & .::
Space & o::
Space & e::
send {LWin Down}
spcup()
exit
spcup()
{
while GetKeyState("Space", "P") {
loop {
rite := GetKeyState("u", "P")
left := GetKeyState("o", "P")
up := GetKeyState(".", "P")
down := GetKeyState("e", "P")
if (left=1) {
Sleep 75
Send {Left}
Sleep 75
}
else if (up=1) {
Sleep 75
Send {Up}
Sleep 75
}
else if (down=1) {
Sleep 75
Send {Down}
Sleep 75
}
else if (rite=1) {
Sleep 75
Send {Right}
Sleep 75
}
} until !GetKeyState("Space", "P")
Sleep 75
Send {LWinUp}
exit
}
}

From the help documentation:
Numpad0 & Numpad1::MsgBox You pressed Numpad1 while holding down Numpad0.
Numpad0 & Numpad2::Run Notepad
The prefix key loses its native function: In the above example,
Numpad0 becomes a prefix key; but this also causes Numpad0 to lose its
original/native function when it is pressed by itself. To avoid this,
a script may configure Numpad0 to perform a new action such as one of
the following:
Numpad0::WinMaximize A ; Maximize the active/foreground window.
Numpad0::Send {Numpad0} ; Make the release of Numpad0 produce a
Numpad0 keystroke. See comment below.
Fire on release: The presence of one of the above custom combination
hotkeys causes the release of Numpad0 to perform the indicated action,
but only if you did not press any other keys while Numpad0 was being
held down. [v1.1.14+]: This behaviour can be avoided by applying the
tilde prefix to either hotkey.
Adding a tilde prefix ~ to each of your Space & hotkeys should make it behave as you expect. Alternatively, you could add ~Space::Return.
Note that this will always send a space, which may have unintended consequences in different applications. For instance, in a browser it will scroll down similar to pressing the
page down key.
Here is a condensed version of your code that I used for testing:
~Space & u::
~Space & .::
~Space & o::
~Space & e::
aReplace := [[ "u" , "Right" ] , [ "o" , "Left" ] , [ "." , "Up" ] , [ "e" , "Down" ]]
Loop , % aReplace.Length()
sReplace := ( SubStr( A_ThisHotkey , 0 , 1 ) = aReplace[ A_Index , 1 ] ) ? aReplace[ A_Index , 2 ] : sReplace
Send , #{%sReplace%}
Return

Related

How do you include a loop with modifiers?

I'm trying to get AHK to continue to press "2" until "2" is pressed a second time. If alt, ctrl, or shift is held it sends ^2, +2, !2 while held and then returns to spamming "2" once the modifier key is released.
This code works so far with modifiers I just need to figure out how to add the loop.
; Disable Alt+Tab
!Tab::Return
; Disable Windows Key + Tab
#Tab::Return
#ifWinActive World of Warcraft
{
$2::
$^2::
$+2::
$!2::
Loop
{
if not GetKeyState("2", "P")
break
if GetKeyState("LCtrl", "P")
Send ^2
else if GetKeyState("LShift", "P")
Send +2
else if GetKeyState("LAlt", "P")
Send !2
else
Send 2
sleep 135
}
return
}
I would recommend using SetTimer for your loop and to be able to toggle it on and off. Please see if the following works for you:
$2::
$<^2::
$<+2::
$<!2::
SetTimer , label_TwoLoop , % ( bT := !bT ) ? "135" : "Off"
Return
label_TwoLoop:
If GetKeyState( "LCtrl" , "P" )
Send , ^2
Else If GetKeyState( "LShift" , "P" )
Send , +2
Else If GetKeyState( "LAlt" , "P" )
Send , !2
Else
Send , 2
Return
https://autohotkey.com/docs/commands/SetTimer.htm
Note that I added the < to the hotkey definitions since the loop-portion is only looking for the left modifier keys. I figured this is the intended behavior.

Autohotkey 3 clicks = volume mute

In autohotkey im trying to make it so that when I press the left mouse button 3 times with a delay of +/- 10 ms it becomes a volume mute
LButton::
if (?)
{
Send, Volume_Mute
}
else
{
Send, LButton
}
Return
Use A_TickCount to read current time in milliseconds and then calculate the delay between clicks. See Date and Time
ms := A_TickCount
N := 3 ; number of clicks
T := 500 ; max delay between clicks, ms
clicks := 0
~lbutton::
msx := A_TickCount ; get current time
d := msx - ms ; get time past
ms := msx ; remember current time
if (d < T)
clicks += 1
else
clicks := 1
if (clicks >= N)
{
; tooltip %N%-click detected
send {Volume_Mute}
clicks := 0
}
return
Each Autohotkey Script (example.Ahk) that you will run in a loop (running in the background), these loops will repeating in a count off frequence ?...ms (milliseconds)
If you want to use a delay from +- 10ms you will need to change the Timer. (Default = +-250ms)
With the Autohotkey Command (SetTimer) you can change that.
(ps- +-10 ms is very fast i recommend to use a lower Time frequence)
In the Line (SetTimer, CountClicks, 100) you can change(optimize) the number 100. (so that it works fine on your system.)
Note: you can remove the line (msgbox) this is only to show visual how many times you did click.
Try this code:
#NoEnv
#SingleInstance force
;#NoTrayIcon
a1 := -1
b1 := 0
esc::exitapp ;You can click the (esc) key to stop the script.
;if you use ~ it will also use the default function Left-Button-Click.
;and if you Click the Left Mouse Button 3x times, it will Execute Ahk Code Part 3
~LButton::
if(a1 = -1)
{
a1 := 4
#Persistent
SetTimer, CountClicks, 100
}
else
{
a1 := 3
}
return
CountClicks:
if(a1 = 3)
{
b1 := b1 + 1
}
if(a1 = 0)
{
msgbox you did Click <LButton> Key > %b1%x times
if (b1=1)
{
;if Click 1x - Then Execute Ahk Code Part 1
;Here you can put any code for Part 1
}
if (b1=2)
{
;if Click 2x - Then Execute Ahk Code Part 2
;Here you can put any code for Part 2
}
if (b1=3)
{
;if Click 3x - Then Execute Ahk Code Part 3
;Here you can put any code for Part 3
Send {Volume_Mute} ;Send, Volume_Mute
}
if (b1=4)
{
;if Click 4x - Then Execute Ahk Code Part 4
;Here you can put any code for Part 4
}
b1 := 0
SetTimer, CountClicks , off
reload ; restart script
}
a1 := a1 - 1
return
I did test it out on a Windows 10 System and it works.

Layer based Keyboard using AutoHotKey: Change modifiers single press, hold, and double press behavior

folks,
I want to create a layer based keyboard using AutoHotkey. Basicly, I want to achieve what shift already does: modify each key when a modifier is used.
I want to improve regular shift in the following:
press modifier once: only change layer for next character
hold modifier: change layer as long as modifier is down
press modifier twice: enter layer mode, like capslock. (end by another press)
Modifiers: LAlt, RAlt, LControl, RControl (CapsLock, Shift)
How cas I accomplish this?
what I found so far on stackoverflow:
This code allows for shift to be pressed and released for the next character
$*LShift::
SendInput, {LShift Down} ; press shift
Input, Key, L1 M V ; wait for input character
If GetKeyState("LShift", "P") ; if shift still pressed, wait for release
KeyWait, LShift
SendInput, {LShift Up} ; send input with shift down, the shift up
Return
this code turns a double shift press into CapsLock
LShift::
KeyWait, CapsLock ; wait to be released
KeyWait, CapsLock, D T0.2 ; and pressed again within 0.2 seconds
if ErrorLevel
return
else if (A_PriorKey = "CapsLock")
SetCapsLockState, % GetKeyState("CapsLock","T") ? "Off" : "On"
return
#If, GetKeyState("CapsLock", "P") ; hotkeys go below
a::b
#If
But I am not experienced enough with AHK to bring this together. My goal is to have something like
Modifier::
; code that makes the modifier behave like expected: single press, hold, double press
Return
#If, GetKeyState("Modifier", "P") ; List of key remaps in specific layer
#If
I hope this is specific enough and that you can help me out here.
thanks!
Assign the corresponding Booleam values (true or false) to the variables "Double_LAlt" and "Double_LAlt_holding" in order to create context-sensitive hotkeys depended on their values:
LAlt::
ToolTip,,,, 3
ToolTip,,,, 4
Double_LAlt := false
; Press twice or press twice and hold LAlt within 0,2 seconds
If (A_PriorHotKey = "~LAlt Up" AND A_TimeSincePriorHotkey < 200)
{
Sleep, 200
If GetKeyState("LAlt","P")
{
ToolTip,,,, 4
ToolTip, Double_LAlt_holding,,, 2
Double_LAlt_holding := true
}
else
{
ToolTip,,,, 4
ToolTip, Double_LAlt,,, 3
Double_LAlt := true
}
}
If !((Double_LAlt_holding) || (Double_LAlt)) ; "!" means "NOT" and "||" means "OR"
ToolTip, LAlt_holding,,, 1
return
~LAlt Up::
ToolTip,,,, 1
ToolTip,,,, 2
Double_LAlt_holding := false
Sleep, 100
If (A_TimeIdlePhysical > 100)
Tooltip, PriorHotKey = LAlt Up,,, 4
SetTimer, RemoveTooltip, 1000
return
#If (Double_LAlt_holding) ; If this variable has the value "true"
<!a:: MsgBox, a while Double_LAlt_holding ; "<!" means "LAlt"
<!1:: MsgBox, 1 while Double_LAlt_holding
#If (Double_LAlt)
a:: MsgBox, a after Double_LAlt
1:: MsgBox, 1 after Double_LAlt
; Press a key within 2 seconds after releasing LAlt:
#If (A_PriorHotKey = "~LAlt Up" AND A_TimeSincePriorHotkey < 2000)
a:: MsgBox, a after LAlt Up
1:: MsgBox, 1 after LAlt Up
#If GetKeyState("LAlt","P")
a:: MsgBox, a while LAlt_holding
1:: MsgBox, 1 while LAlt_holding
#If
RemoveTooltip:
If (A_TimeSincePriorHotkey > 2000) ; 2 seconds
ToolTip,,,, 4
return

AHK: remap numeric keypad with Numlock On so it behaves like numeric keypad with Numlock Off

I'd like to remap the numeric keypad with Numlock On to behave like the numeric keypad with Numlock Off, including being able to extend the selection with Shift/Ctrl held down.
The problem I have is the following
Numpad8::Up
Doesn't have correct behaviour when shift+numpad8 is pressed, the cursor moves up, but no text is selected. The following also don't work as I'd like (same behaviour as Numpad::8).
+Numpad8::Up
+Numpad8::+Up
If I remap a normal key, the selection behaviour is correct when shift is pressed:
w::Up
Any hints?
The reason I'm doing this is to make a CoolerMaster QuickFire TK's numeric keypad behave like it has a standard numeric keypad layout (I've some registry keyboard remapping happening as well, which is why I want the navigation behaviour with Numlock On).
It's possible, but it's a pain in the ass... compared to normal remapping.
Here is the normal behaviour of the Numpad8-key:
With numpad on:
num8: up
shift+num8: mark up
With numpad off:
num8: 8
shift+num8:up
So if you want to reverse that, what we want is this:
With numpad on:
num8: 8
shift+num8:up
With numpad off:
num8: up
shift+num8: mark up
This is how it could be achived:
*NumpadUp::
If GetKeyState("NumLock", "T")
SendInput, {Shift Down}{Up}
Else If GetKeyState("Shift")
SendInput, {Shift Up}{NumpadUp}
Else
SendInput, {Shift Up}{Numpad8}
Return
*Numpad8::
If GetKeyState("Shift")
SendInput, {Shift Down}{NumpadUp}
Else
SendInput, {NumpadUp}
Return
Now you just need to do the same thing for the other numpad keys that you want to reverse.
Here is a different approach that uses a little hack to make it look like the Numpad toggles when pressing the numlock key. But it ensures that the numlock actually is always off and only the numlock light is changed.
SetNumLockState, Off
fakeNumlockOn := False
Return
NumLock::
SetNumLockState, Off
fakeNumlockOn := !fakeNumlockOn
SetNumLockLEDs(fakeNumlockOn ? "on" : "off")
Sleep, 100
SetNumLockLEDs(fakeNumlockOn ? "on" : "off")
Return
SetNumLockLEDs(state) {
Loop, 11
KeyboardLED(2,state,A_Index-1)
}
/*
Keyboard LED control for AutoHotkey_L
http://www.autohotkey.com/forum/viewtopic.php?p=468000#468000
KeyboardLED(LEDvalue, "Cmd", Kbd)
LEDvalue - ScrollLock=1, NumLock=2, CapsLock=4
Cmd - on/off/switch
Kbd - index of keyboard (probably 0 or 2)
*/
KeyboardLED(LEDvalue, Cmd, Kbd=0) {
SetUnicodeStr(fn,"\Device\KeyBoardClass" Kbd)
h_device := NtCreateFile(fn,0+0x00000100+0x00000080+0x00100000,1,1,0x00000040+0x00000020,0)
If (Cmd = "switch") ;switches every LED according to LEDvalue
KeyLED:= LEDvalue
If (Cmd = "on") ;forces all choosen LED's to ON (LEDvalue= 0 ->LED's according to keystate)
KeyLED:= LEDvalue | (GetKeyState("ScrollLock", "T") + 2*GetKeyState("NumLock", "T") + 4*GetKeyState("CapsLock", "T"))
If (Cmd = "off") { ;forces all choosen LED's to OFF (LEDvalue= 0 ->LED's according to keystate)
LEDvalue := LEDvalue ^ 7
KeyLED := LEDvalue & (GetKeyState("ScrollLock", "T") + 2*GetKeyState("NumLock", "T") + 4*GetKeyState("CapsLock", "T"))
}
success := DllCall( "DeviceIoControl" , "ptr", h_device , "uint", CTL_CODE( 0x0000000b , 2 , 0 , 0 ) , "int*", KeyLED << 16 , "uint", 4 , "ptr", 0 , "uint", 0 , "ptr*", output_actual , "ptr", 0 )
NtCloseFile(h_device)
return success
}
CTL_CODE( p_device_type, p_function, p_method, p_access ) {
return, ( p_device_type << 16 ) | ( p_access << 14 ) | ( p_function << 2 ) | p_method
}
NtCreateFile(ByRef wfilename,desiredaccess,sharemode,createdist,flags,fattribs) {
VarSetCapacity(objattrib,6*A_PtrSize,0)
VarSetCapacity(io,2*A_PtrSize,0)
VarSetCapacity(pus,2*A_PtrSize)
DllCall("ntdll\RtlInitUnicodeString","ptr",&pus,"ptr",&wfilename)
NumPut(6*A_PtrSize,objattrib,0)
NumPut(&pus,objattrib,2*A_PtrSize)
status:=DllCall("ntdll\ZwCreateFile","ptr*",fh,"UInt",desiredaccess,"ptr",&objattrib ,"ptr",&io,"ptr",0,"UInt",fattribs,"UInt",sharemode,"UInt",createdist ,"UInt",flags,"ptr",0,"UInt",0, "UInt")
return % fh
}
NtCloseFile(handle) {
return DllCall("ntdll\ZwClose","ptr",handle)
}
SetUnicodeStr(ByRef out, str_) {
VarSetCapacity(out,2*StrPut(str_,"utf-16"))
StrPut(str_,&out,"utf-16")
}

SendEvent ^{ins} isn't copying content to the clipboard

!c::
file_name = footnote.ini
restore_original_clipBoard := clipboard
clipboard =
KeyWait, Alt
KeyWait, c ;small c
BlockInput, on
SendEvent, ^{ins} ;^c doesn't work
ClipWait, 2 ; Wait for the clipboard to contain text.
if ErrorLevel
{
MsgBox Failed to save the selection: %clipboard%
exit
}
BlockInput, off
save_selection := clipboard
Problem: Despite a selection being made, Sendevent ^{ins} does not save it to the clipboard. Sometimes I have to repeat my hotkey, alt + c several times before the selection is being copied to the clipboard. The KeyWait should ensure me that only ^{ins} is being processed without any additional keys. What am I doing wrong here?
UPDATE
One of the ways I tried to force copy a selection to the clipboard was by using a while loop. I got it to work through the post: Looping clipboard and errorlevel evaluation not working as expected
PROBLEM
When I make a selection and press alt + c it sometimes gets stuck in the infinite loop that I implemented. But as you can see from that code:
clipboard := ""
while( StrLen(clipboard) < 1 )
{
Send, ^{ins}
Sleep, 50
}
MsgBox % ClipBoard
The infinite loop incorporates within itself a continues resending of ^{ins}. For some reason, my selection is not being recognized as a selection. Whilst it is in that infinite loop, I try to reselect the text. It then recognizes it instantly and copies my selection to the clipboard. But alas! The selection is incomplete because it goes so quick.
This problem is not always like that. Sometimes it recognizes the selection first spot on! So sometimes it copies my selection to my clipboard sometimes not. When it does not, then a resending of a ^{ins} does not seem to work. I do not want to the user to reselect his selection. Is that possible to do?
Send {Ctrl Down}{c}{Ctrl Up}
That presses Ctrl+C, you must do it instantly as one command apposed to pressing Ctrl waiting then pressing C.
Never seen Insert key used for copying text.
Also found this sends Ctrl+C as well.
Send, ^c
To send insert key use
{Insert}
This way works for me:
!vk43:: ; alt+c
clipContent:=ClipboardAll
Clipboard:=""
SendEvent, ^{Ins}
ClipWait, .75
MsgBox, % 262 . (ErrorLevel ? 160:208)
, % ErrorLevel ? "Period expired:":"Result:"
, % ErrorLevel ? "Failed to save the selection.":Clipboard
, % (ErrorLevel ? 0:2) . .5
Clipboard:=clipContent
KeyWait, vk43
Return
!vk43:: ; alt+c
clipContent:=ClipboardAll ; backup clipboard content (if needed)
Clipboard:="" ; no comment :)
Loop
{
SendEvent, ^{Ins}
ClipWait, .75 ; means 750ms, same if write 0.75
; assign value of "ErrorLevel" an variable for further usage
errLvl:=ErrorLevel
; monitoring current action (for debugging purpose only)
TrayTip, % "attempt: #"A_Index
, % """ErrorLevel"" of ""ClipWait"" command is: "errLvl
}
; here you can set the condition of ending the cycle: either...
; ...variable errLvl has not a true value,...
; ...or the number of attempts is equal 5
Until, Not errLvl Or A_Index=5
; value of each field of the command "MsgBox"...
; ...are set depending on the value of errLvl variable...
; ...using a ternary expression
; means if errLvl is a true, "options" field is 262160
MsgBox, % 262 . (errLvl ? 160:208)
; means that "title" has a couple variants
, % errLvl ? "Period expired:":"Result:"
; means that "text" has a couple variants
, % errLvl ? "Failed to save the selection.":Clipboard
; means if errLvl is a true, "timeout" field is 0.5 (500ms)
, % (errLvl ? 0:2) . .5
/* same that and above:
IfEqual, errLvl, % True, MsgBox, 262160
, % "Period expired:"
, % "Failed to save the selection."
, 0.5
Else MsgBox, 262208, % "Result:", % Clipboard, 2.5
*/
TrayTip ; remove "TrayTip" (for debugging purpose only)
; save an positive result (if needed)
IfEqual, errLvl, 0, Sleep, -1, someVar:=Clipboard
; return a temporarily saved data into clipboard (if needed)
Clipboard:=clipContent
KeyWait, % "vk43"
Return
From my experience whenever keystrokes are not recognized reliably it's due to either the system or the targeted program not keeping up with the speed at which those keys are sent.
For SendEvent you could try something like SetKeyDelay, 1000, 1000 and see if this improves things. The other option would be to send explicit down and up keys with intermittent sleep calls as outlined in this answer.