Hey guys. I have a Razer BlackWidow keyboard that I'm in love with and can't afford to replace right now. I've got an issue on the hardware end of it, and I thought that maybe AHK could help as a temporary fix.
I'm experiencing an issue where some of my keys (namely I, J, K, and L) are sometimes "double tapping" upon a single press. For example, just as I type this, "single" actually typed out as "siingle," with both Is coming out instantaneously. I assume this comes from two years of gaming on these keys.
Is it possible, with AHK, to prevent this? For example, something like where if the IJKL keys are repeated (independently, not together like IK, IJ, so just II") within a milisecond of each other, to instead prevent the second press and only send one?
Issue with repeating keys on keyboard
Re: Issue with repeating keys on keyboard
Hello, you can use Timer Function by Fnatic Guru for this.
Code: Select all
;insert your usual autoexec
*i::
if Timer("DoubleTap")
{
Timer("DoubleTap", 100)
Send, i
}
return
*j::
if Timer("DoubleTap")
{
Timer("DoubleTap", 100)
Send, j
}
return
*k::
if Timer("DoubleTap")
{
Timer("DoubleTap", 100)
Send, k
}
return
*l::
if Timer("DoubleTap")
{
Timer("DoubleTap", 100)
Send, l
}
return
Timer(Timer_Name := "", Timer_Opt := "D")
{
static
global Timer, Timer_Count
if !Timer
Timer := {}
if (Timer_Opt = "U" or Timer_Opt = "Unset")
if IsObject(Timer[Timer_Name])
{
Timer.Remove(Timer_Name)
Timer_Count --=
return true
}
else
return false
if RegExMatch(Timer_Opt,"(\d+)",Timer_Match)
{
if !(Timer[Timer_Name,"Start"])
Timer_Count += 1
Timer[Timer_Name,"Start"] := A_TickCount
Timer[Timer_Name,"Finish"] := A_TickCount + Timer_Match1
Timer[Timer_Name,"Period"] := Timer_Match1
}
if RegExMatch(Timer_Opt,"(\D+)",Timer_Match)
Timer_Opt := Timer_Match1
else
Timer_Opt := "D"
if (Timer_Name = "")
{
for index, element in Timer
Timer(index)
return
}
if (Timer_Opt = "R" or Timer_Opt = "Reset")
{
Timer[Timer_Name,"Start"] := A_TickCount
Timer[Timer_Name,"Finish"] := A_TickCount + Timer[Timer_Name,"Period"]
}
Timer[Timer_Name,"Now"] := A_TickCount
Timer[Timer_Name,"Left"] := Timer[Timer_Name,"Finish"] - Timer[Timer_Name,"Now"]
Timer[Timer_Name,"Elapse"] := Timer[Timer_Name,"Now"] - Timer[Timer_Name,"Start"]
Timer[Timer_Name,"Done"] := true
if (Timer[Timer_Name,"Left"] > 0)
Timer[Timer_Name,"Done"] := false
if (Timer_Opt = "D" or Timer_Opt = "Done")
return Timer[Timer_Name,"Done"]
if (Timer_Opt = "S" or Timer_Opt = "Start")
return Timer[Timer_Name,"Start"]
if (Timer_Opt = "F" or Timer_Opt = "Finish")
return Timer[Timer_Name,"Finish"]
if (Timer_Opt = "L" or Timer_Opt = "Left")
return Timer[Timer_Name,"Left"]
if (Timer_Opt = "N" or Timer_Opt = "Now")
return Timer[Timer_Name,"Now"]
if (Timer_Opt = "P" or Timer_Opt = "Period")
return Timer[Timer_Name,"Period"]
if (Timer_Opt = "E" or Timer_Opt = "Elapse")
return Timer[Timer_Name,"Elapse"]
}
Re: Issue with repeating keys on keyboard
I think i may have misunderstood your intention. The above code works well if you have keys repeating off of each other like j appearing when you press i etc. if you just want to stop single key repeating you can edit "DoubleTap" and change it to the hotkey like this. 100 is the amount of time (in ms) the key cant be repeated once pressed btw.
Code: Select all
;insert your usual autoexec
*i::
if Timer("I")
{
Timer("I", 100)
Send, i
}
return
*j::
if Timer("J")
{
Timer("J", 100)
Send, j
}
return
*k::
if Timer("K")
{
Timer("K", 100)
Send, k
}
return
*l::
if Timer("L")
{
Timer("L", 100)
Send, l
}
return
Timer(Timer_Name := "", Timer_Opt := "D")
{
static
global Timer, Timer_Count
if !Timer
Timer := {}
if (Timer_Opt = "U" or Timer_Opt = "Unset")
if IsObject(Timer[Timer_Name])
{
Timer.Remove(Timer_Name)
Timer_Count --=
return true
}
else
return false
if RegExMatch(Timer_Opt,"(\d+)",Timer_Match)
{
if !(Timer[Timer_Name,"Start"])
Timer_Count += 1
Timer[Timer_Name,"Start"] := A_TickCount
Timer[Timer_Name,"Finish"] := A_TickCount + Timer_Match1
Timer[Timer_Name,"Period"] := Timer_Match1
}
if RegExMatch(Timer_Opt,"(\D+)",Timer_Match)
Timer_Opt := Timer_Match1
else
Timer_Opt := "D"
if (Timer_Name = "")
{
for index, element in Timer
Timer(index)
return
}
if (Timer_Opt = "R" or Timer_Opt = "Reset")
{
Timer[Timer_Name,"Start"] := A_TickCount
Timer[Timer_Name,"Finish"] := A_TickCount + Timer[Timer_Name,"Period"]
}
Timer[Timer_Name,"Now"] := A_TickCount
Timer[Timer_Name,"Left"] := Timer[Timer_Name,"Finish"] - Timer[Timer_Name,"Now"]
Timer[Timer_Name,"Elapse"] := Timer[Timer_Name,"Now"] - Timer[Timer_Name,"Start"]
Timer[Timer_Name,"Done"] := true
if (Timer[Timer_Name,"Left"] > 0)
Timer[Timer_Name,"Done"] := false
if (Timer_Opt = "D" or Timer_Opt = "Done")
return Timer[Timer_Name,"Done"]
if (Timer_Opt = "S" or Timer_Opt = "Start")
return Timer[Timer_Name,"Start"]
if (Timer_Opt = "F" or Timer_Opt = "Finish")
return Timer[Timer_Name,"Finish"]
if (Timer_Opt = "L" or Timer_Opt = "Left")
return Timer[Timer_Name,"Left"]
if (Timer_Opt = "N" or Timer_Opt = "Now")
return Timer[Timer_Name,"Now"]
if (Timer_Opt = "P" or Timer_Opt = "Period")
return Timer[Timer_Name,"Period"]
if (Timer_Opt = "E" or Timer_Opt = "Elapse")
return Timer[Timer_Name,"Elapse"]
}
Re: Issue with repeating keys on keyboard
Thank you. The second script seems to be working so far with the delay tuned down to 5ms. Definitely beats replacing an entire keyboard.
Re: Issue with repeating keys on keyboard
One issue I'm encountering is that I can't send capital versions of those letters now. I've searched on Google for multiple forms of "AHK send matching case" but can't find the solution, I'm sure it's as simple as adding a symbol?
Re: Issue with repeating keys on keyboard
You can exchange it as follows:
Exchange this code segment (for instance)
with
Exchange this code segment (for instance)
Code: Select all
*i::
if Timer("I")
{
Timer("I", 100)
Send, i
}
return
Code: Select all
*i::
GetKeyState, state, Shift
if Timer("I")
{
Timer("I", 100)
if state = D
{
Send, I
} else
{
Send, i
}
}
return
Re: Issue with repeating keys on keyboard
Worked, thanks. Running into more issues now as it doesn't work with modifier keys, like Shift+L, Ctrl+L, etc. Is there any clean way to get all of this stuff working?
Re: Issue with repeating keys on keyboard
You will have to forgive me as I was severely intoxicated when I posted that code. This should work, I dont have ahk where I am right now, but I have proof read it. Let me know if it works
Code: Select all
;insert your usual autoexec
#UseHook
~*i::
if !Timer("I")
{
Hotkey, ~*i , , Off
Hotkey, *i , BlockRepeat, On
SetTimer, HotkeyI, -5
}
Timer("I", 5)
return
~*j::
if !Timer("J")
{
Hotkey, ~*j , , Off
Hotkey, *j , BlockRepeat, On
SetTimer, HotkeyJ, -5
}
Timer("J", 5)
return
*k::
if !Timer("K")
{
Hotkey, ~*k , , Off
Hotkey, *k, BlockRepeat, On
SetTimer, HotkeyK, -5
}
Timer("K", 5)
return
*l::
if !Timer("L")
{
Hotkey, ~*l , , Off
Hotkey, *l , BlockRepeat, On
SetTimer, HotkeyL, -5
}
Timer("L", 5)
return
BlockRepeat:
return
HotkeyI:
Hotkey, *i , BlockRepeat, Off
Hotkey, ~*i , , On
return
HotkeyJ:
Hotkey, *j , BlockRepeat, Off
Hotkey, ~*j , , On
return
HotkeyK:
Hotkey, *k , BlockRepeat, Off
Hotkey, ~*k , , On
return
HotkeyL:
Hotkey, *l , BlockRepeat, Off
Hotkey, ~*l , , On
return
Timer(Timer_Name := "", Timer_Opt := "D")
{
static
global Timer, Timer_Count
if !Timer
Timer := {}
if (Timer_Opt = "U" or Timer_Opt = "Unset")
if IsObject(Timer[Timer_Name])
{
Timer.Remove(Timer_Name)
Timer_Count --=
return true
}
else
return false
if RegExMatch(Timer_Opt,"(\d+)",Timer_Match)
{
if !(Timer[Timer_Name,"Start"])
Timer_Count += 1
Timer[Timer_Name,"Start"] := A_TickCount
Timer[Timer_Name,"Finish"] := A_TickCount + Timer_Match1
Timer[Timer_Name,"Period"] := Timer_Match1
}
if RegExMatch(Timer_Opt,"(\D+)",Timer_Match)
Timer_Opt := Timer_Match1
else
Timer_Opt := "D"
if (Timer_Name = "")
{
for index, element in Timer
Timer(index)
return
}
if (Timer_Opt = "R" or Timer_Opt = "Reset")
{
Timer[Timer_Name,"Start"] := A_TickCount
Timer[Timer_Name,"Finish"] := A_TickCount + Timer[Timer_Name,"Period"]
}
Timer[Timer_Name,"Now"] := A_TickCount
Timer[Timer_Name,"Left"] := Timer[Timer_Name,"Finish"] - Timer[Timer_Name,"Now"]
Timer[Timer_Name,"Elapse"] := Timer[Timer_Name,"Now"] - Timer[Timer_Name,"Start"]
Timer[Timer_Name,"Done"] := true
if (Timer[Timer_Name,"Left"] > 0)
Timer[Timer_Name,"Done"] := false
if (Timer_Opt = "D" or Timer_Opt = "Done")
return Timer[Timer_Name,"Done"]
if (Timer_Opt = "S" or Timer_Opt = "Start")
return Timer[Timer_Name,"Start"]
if (Timer_Opt = "F" or Timer_Opt = "Finish")
return Timer[Timer_Name,"Finish"]
if (Timer_Opt = "L" or Timer_Opt = "Left")
return Timer[Timer_Name,"Left"]
if (Timer_Opt = "N" or Timer_Opt = "Now")
return Timer[Timer_Name,"Now"]
if (Timer_Opt = "P" or Timer_Opt = "Period")
return Timer[Timer_Name,"Period"]
if (Timer_Opt = "E" or Timer_Opt = "Elapse")
return Timer[Timer_Name,"Elapse"]
}
Re: Issue with repeating keys on keyboard
oh boy, I messed up. Things are a bit hectic where I am at right now, that code wont work. Try this, it should be enough
Code: Select all
;insert your usual autoexec
#UseHook
~*i::
Hotkey, ~*i , , Off
Hotkey, *i , BlockRepeat, On
SetTimer, HotkeyI, -5
return
~*j::
Hotkey, ~*j , , Off
Hotkey, *j , BlockRepeat, On
SetTimer, HotkeyJ, -5
return
~*k::
Hotkey, ~*k , , Off
Hotkey, *k, BlockRepeat, On
SetTimer, HotkeyK, -5
return
~*l::
Hotkey, ~*l , , Off
Hotkey, *l , BlockRepeat, On
SetTimer, HotkeyL, -5
return
BlockRepeat:
return
HotkeyI:
Hotkey, *i , BlockRepeat, Off
Hotkey, ~*i , , On
return
HotkeyJ:
Hotkey, *j , BlockRepeat, Off
Hotkey, ~*j , , On
return
HotkeyK:
Hotkey, *k , BlockRepeat, Off
Hotkey, ~*k , , On
return
HotkeyL:
Hotkey, *l , BlockRepeat, Off
Hotkey, ~*l , , On
return
Re: Issue with repeating keys on keyboard
Nice Code, but for me it runs only 1 time. For working for me i had to replace
with
Probably because the label wasn't defined by a prior Hotkkey command
Code: Select all
HotkeyI:
Hotkey, *i , BlockRepeat, Off
Hotkey, ~*i , , On
return
Code: Select all
HotkeyI:
Hotkey, *i , BlockRepeat, Off
Hotkey, ~*i , ~*i, On
return
Re: Issue with repeating keys on keyboard
Ah you must be on an older version of AHK. My code should work above v1.1.19 Hotkey is now updated when Label is omitted.
Re: Issue with repeating keys on keyboard
The -5 represents what? I can change that to 3 for 3ms?Guest503 wrote:oh boy, I messed up. Things are a bit hectic where I am at right now, that code wont work. Try this, it should be enough
Code: Select all
;insert your usual autoexec #UseHook ~*i:: Hotkey, ~*i , , Off Hotkey, *i , BlockRepeat, On SetTimer, HotkeyI, -5 return ~*j:: Hotkey, ~*j , , Off Hotkey, *j , BlockRepeat, On SetTimer, HotkeyJ, -5 return ~*k:: Hotkey, ~*k , , Off Hotkey, *k, BlockRepeat, On SetTimer, HotkeyK, -5 return ~*l:: Hotkey, ~*l , , Off Hotkey, *l , BlockRepeat, On SetTimer, HotkeyL, -5 return BlockRepeat: return HotkeyI: Hotkey, *i , BlockRepeat, Off Hotkey, ~*i , , On return HotkeyJ: Hotkey, *j , BlockRepeat, Off Hotkey, ~*j , , On return HotkeyK: Hotkey, *k , BlockRepeat, Off Hotkey, ~*k , , On return HotkeyL: Hotkey, *l , BlockRepeat, Off Hotkey, ~*l , , On return
Re: Issue with repeating keys on keyboard
Yes, it is the delay between repeats. But -1 to -10 (or upto -15.6) should be the same based on your OS granularity. if you want to spam those keys without limits then you can add a suspend and pause toggle in the script.
Or you can use precise sleep function and tweak the sleep value until it is exactly what you need.
Code: Select all
~*NumLock::
Suspend
Pause,,1
return
Code: Select all
;insert your usual autoexec
#UseHook
~*i::
Hotkey, ~*i , , Off
Hotkey, *i , BlockRepeat, On
sleep(3)
GoSub, HotkeyI
return
~*j::
Hotkey, ~*j , , Off
Hotkey, *j , BlockRepeat, On
sleep(3)
GoSub, HotkeyJ
return
~*k::
Hotkey, ~*k , , Off
Hotkey, *k, BlockRepeat, On
sleep(3)
GoSub, HotkeyK
return
~*l::
Hotkey, ~*l , , Off
Hotkey, *l , BlockRepeat, On
sleep(3)
GoSub, HotkeyL
return
BlockRepeat:
return
HotkeyI:
Hotkey, *i , BlockRepeat, Off
Hotkey, ~*i , , On
return
HotkeyJ:
Hotkey, *j , BlockRepeat, Off
Hotkey, ~*j , , On
return
HotkeyK:
Hotkey, *k , BlockRepeat, Off
Hotkey, ~*k , , On
return
HotkeyL:
Hotkey, *l , BlockRepeat, Off
Hotkey, ~*l , , On
return
sleep(period := 1, Mode := "")
{
static Frequency, MinSetResolution, PID ; frequency can't change while computer is on
if (Mode = "P") ; Precise, but the loop will eat CPU cycles! - use for short time periods
{
pBatchLines := A_BatchLines
SetBatchLines, -1 ; increase the precision
; if !PID
; PID := DllCall("GetCurrentProcessId")
; pPiority := DllCall("GetPriorityClass","UInt", hProc := DllCall("OpenProcess","Uint",0x400,"Int",0,"UInt", PID)) ; have to use 0x400 (PROCESS_QUERY_INFORMATION)
; , DllCall("CloseHandle","Uint",hProc)
; if (pPiority != 0x20) ; Normal - I figure if priortiy less than normal increase it to normal for accuracy else if its above normal decrease it, so it doesn't affect other programs as much
; DllCall("SetPriorityClass","UInt", hProc := DllCall("OpenProcess","Uint",0x200,"Int",0,"UInt",PID), "Uint", 0x20) ; set priority to normal ;have to open a new process handle with 0x200 (PROCESS_SET_INFORMATION)
; , PriorityAltered := True
if !Frequency
DllCall("QueryPerformanceFrequency", "Int64*", Frequency) ; e.g. 3222744 (/s)
DllCall("QueryPerformanceCounter", "Int64*", Start)
Finish := Start + ( Frequency * (period/1000))
loop
DllCall("QueryPerformanceCounter", "Int64*", Current) ; eats the cpu
until (Current >= Finish)
SetBatchLines, %pBatchLines%
; if PriorityAltered ; restore original priority
; DllCall("SetPriorityClass","UInt", hProc := DllCall("OpenProcess","Uint",0x200,"Int",0,"UInt",PID), "Uint", pPiority) ; reset priority
; , DllCall("CloseHandle","Uint",hProc)
}
else if (Mode = "HP" || Mode = "HS" ) ; hybrid Precise or hybrid suspend
{ ; will sleep the majority of the time using AHKs sleep
if !Frequency ; and sleep the remainder using Precise or suspend
DllCall("QueryPerformanceFrequency", "Int64*", Frequency)
DllCall("QueryPerformanceCounter", "Int64*", Start)
Finish := Start + ( Frequency * (period/1000))
if (A_BatchLines = -1)
sleep % period - 15 ; if period is < 15 this will be a nagative number which will simply make AHK check its message queue
else sleep, % period - 25 ; I picked 25 ms, as AHK sleep is usually accurate to 15 ms, and then added an extra 10 ms in case there was an AHK internal 10ms sleep
DllCall("QueryPerformanceCounter", "Int64*", Current)
if (Current < Finish) ; so there is still a small amount of sleep time left, lets use the precise methods for the remainder
{
period := (Finish - Current)*1000 / Frequency ; convert remainder to ms
if (Mode = "HP")
sleep(period, "P")
else sleep(period, "S")
}
}
else if (Mode = "S") ; suspend/sleep (sleeps entire script so will delay timers/hotkeys)
{
if !MinSetResolution
{
error := DllCall("winmm\timeGetDevCaps", Int64P, TimeCaps, UInt,8)
if ( error || Errorlevel)
{
DLLcallErrorlevel := Errorlevel
sleep, %period% ;fall back to AHKs own sleep
return error ? error : DLLcallErrorlevel
}
MinSetResolution := TimeCaps & 0xFFFFFFFF
;MaxResolution := TimeCaps >> 32
DllCall("Winmm.dll\timeBeginPeriod", UInt, MinSetResolution)
}
DllCall("Sleep", UInt, period)
}
else if (Mode = "Off" && MinSetResolution) ; this should be called once at the end of the script
{ ; if mode "s" has been used somewhere
DllCall("Winmm.dll\timeEndPeriod", UInt, MinSetResolution)
MinSetResolution := False
}
else ; When no mode is specified, the function will use the precise method when the period
{ ; is 20 ms or less (i have a number of sleep calls which contain a variable period)
if (period > 20) ; otherwise it just uses AHKs sleep
sleep, %period%
else sleep(period, "P")
}
return
}
Re: Issue with repeating keys on keyboard
foxhunter you were right need to include Label, even though the Hotkey was defined before, which should automatically declare a Label. I guess it is disabling the Label aswell when you disable Hotkey with Hotkey command. I just tested it out. Serves me right for not testing before posting code
Heres the updated code
and the one using sleep
Heres the updated code
Code: Select all
;insert your usual autoexec
#UseHook
~*i::
Hotkey, ~*i , , Off
Hotkey, *i , BlockRepeat, On
SetTimer, HotkeyI, -5
return
~*j::
Hotkey, ~*j , , Off
Hotkey, *j , BlockRepeat, On
SetTimer, HotkeyJ, -5
return
~*k::
Hotkey, ~*k , , Off
Hotkey, *k, BlockRepeat, On
SetTimer, HotkeyK, -5
return
~*l::
Hotkey, ~*l , , Off
Hotkey, *l , BlockRepeat, On
SetTimer, HotkeyL, -5
return
BlockRepeat:
return
HotkeyI:
Hotkey, *i , BlockRepeat, Off
Hotkey, ~*i , ~*i, On
return
HotkeyJ:
Hotkey, *j , BlockRepeat, Off
Hotkey, ~*j , ~*j, On
return
HotkeyK:
Hotkey, *k , BlockRepeat, Off
Hotkey, ~*k , ~*k, On
return
HotkeyL:
Hotkey, *l , BlockRepeat, Off
Hotkey, ~*l , ~*l, On
return
Code: Select all
;insert your usual autoexec
#UseHook
~*i::
Hotkey, ~*i , , Off
Hotkey, *i , BlockRepeat, On
sleep(3)
GoSub, HotkeyI
return
~*j::
Hotkey, ~*j , , Off
Hotkey, *j , BlockRepeat, On
sleep(3)
GoSub, HotkeyJ
return
~*k::
Hotkey, ~*k , , Off
Hotkey, *k, BlockRepeat, On
sleep(3)
GoSub, HotkeyK
return
~*l::
Hotkey, ~*l , , Off
Hotkey, *l , BlockRepeat, On
sleep(3)
GoSub, HotkeyL
return
BlockRepeat:
return
HotkeyI:
Hotkey, *i , BlockRepeat, Off
Hotkey, ~*i , ~*i, On
return
HotkeyJ:
Hotkey, *j , BlockRepeat, Off
Hotkey, ~*j , ~*j, On
return
HotkeyK:
Hotkey, *k , BlockRepeat, Off
Hotkey, ~*k , ~*k, On
return
HotkeyL:
Hotkey, *l , BlockRepeat, Off
Hotkey, ~*l , ~*l, On
return
sleep(period := 1, Mode := "")
{
static Frequency, MinSetResolution, PID ; frequency can't change while computer is on
if (Mode = "P") ; Precise, but the loop will eat CPU cycles! - use for short time periods
{
pBatchLines := A_BatchLines
SetBatchLines, -1 ; increase the precision
; if !PID
; PID := DllCall("GetCurrentProcessId")
; pPiority := DllCall("GetPriorityClass","UInt", hProc := DllCall("OpenProcess","Uint",0x400,"Int",0,"UInt", PID)) ; have to use 0x400 (PROCESS_QUERY_INFORMATION)
; , DllCall("CloseHandle","Uint",hProc)
; if (pPiority != 0x20) ; Normal - I figure if priortiy less than normal increase it to normal for accuracy else if its above normal decrease it, so it doesn't affect other programs as much
; DllCall("SetPriorityClass","UInt", hProc := DllCall("OpenProcess","Uint",0x200,"Int",0,"UInt",PID), "Uint", 0x20) ; set priority to normal ;have to open a new process handle with 0x200 (PROCESS_SET_INFORMATION)
; , PriorityAltered := True
if !Frequency
DllCall("QueryPerformanceFrequency", "Int64*", Frequency) ; e.g. 3222744 (/s)
DllCall("QueryPerformanceCounter", "Int64*", Start)
Finish := Start + ( Frequency * (period/1000))
loop
DllCall("QueryPerformanceCounter", "Int64*", Current) ; eats the cpu
until (Current >= Finish)
SetBatchLines, %pBatchLines%
; if PriorityAltered ; restore original priority
; DllCall("SetPriorityClass","UInt", hProc := DllCall("OpenProcess","Uint",0x200,"Int",0,"UInt",PID), "Uint", pPiority) ; reset priority
; , DllCall("CloseHandle","Uint",hProc)
}
else if (Mode = "HP" || Mode = "HS" ) ; hybrid Precise or hybrid suspend
{ ; will sleep the majority of the time using AHKs sleep
if !Frequency ; and sleep the remainder using Precise or suspend
DllCall("QueryPerformanceFrequency", "Int64*", Frequency)
DllCall("QueryPerformanceCounter", "Int64*", Start)
Finish := Start + ( Frequency * (period/1000))
if (A_BatchLines = -1)
sleep % period - 15 ; if period is < 15 this will be a nagative number which will simply make AHK check its message queue
else sleep, % period - 25 ; I picked 25 ms, as AHK sleep is usually accurate to 15 ms, and then added an extra 10 ms in case there was an AHK internal 10ms sleep
DllCall("QueryPerformanceCounter", "Int64*", Current)
if (Current < Finish) ; so there is still a small amount of sleep time left, lets use the precise methods for the remainder
{
period := (Finish - Current)*1000 / Frequency ; convert remainder to ms
if (Mode = "HP")
sleep(period, "P")
else sleep(period, "S")
}
}
else if (Mode = "S") ; suspend/sleep (sleeps entire script so will delay timers/hotkeys)
{
if !MinSetResolution
{
error := DllCall("winmm\timeGetDevCaps", Int64P, TimeCaps, UInt,8)
if ( error || Errorlevel)
{
DLLcallErrorlevel := Errorlevel
sleep, %period% ;fall back to AHKs own sleep
return error ? error : DLLcallErrorlevel
}
MinSetResolution := TimeCaps & 0xFFFFFFFF
;MaxResolution := TimeCaps >> 32
DllCall("Winmm.dll\timeBeginPeriod", UInt, MinSetResolution)
}
DllCall("Sleep", UInt, period)
}
else if (Mode = "Off" && MinSetResolution) ; this should be called once at the end of the script
{ ; if mode "s" has been used somewhere
DllCall("Winmm.dll\timeEndPeriod", UInt, MinSetResolution)
MinSetResolution := False
}
else ; When no mode is specified, the function will use the precise method when the period
{ ; is 20 ms or less (i have a number of sleep calls which contain a variable period)
if (period > 20) ; otherwise it just uses AHKs sleep
sleep, %period%
else sleep(period, "P")
}
return
}
Re: Issue with repeating keys on keyboard
Using first code:Guest503 wrote:foxhunter you were right need to include Label, even though the Hotkey was defined before, which should automatically declare a Label. I guess it is disabling the Label aswell when you disable Hotkey with Hotkey command. I just tested it out. Serves me right for not testing before posting code
Heres the updated code
and the one using sleepCode: Select all
;insert your usual autoexec #UseHook ~*i:: Hotkey, ~*i , , Off Hotkey, *i , BlockRepeat, On SetTimer, HotkeyI, -5 return ~*j:: Hotkey, ~*j , , Off Hotkey, *j , BlockRepeat, On SetTimer, HotkeyJ, -5 return ~*k:: Hotkey, ~*k , , Off Hotkey, *k, BlockRepeat, On SetTimer, HotkeyK, -5 return ~*l:: Hotkey, ~*l , , Off Hotkey, *l , BlockRepeat, On SetTimer, HotkeyL, -5 return BlockRepeat: return HotkeyI: Hotkey, *i , BlockRepeat, Off Hotkey, ~*i , ~*i, On return HotkeyJ: Hotkey, *j , BlockRepeat, Off Hotkey, ~*j , ~*j, On return HotkeyK: Hotkey, *k , BlockRepeat, Off Hotkey, ~*k , ~*k, On return HotkeyL: Hotkey, *l , BlockRepeat, Off Hotkey, ~*l , ~*l, On return
Code: Select all
;insert your usual autoexec #UseHook ~*i:: Hotkey, ~*i , , Off Hotkey, *i , BlockRepeat, On sleep(3) GoSub, HotkeyI return ~*j:: Hotkey, ~*j , , Off Hotkey, *j , BlockRepeat, On sleep(3) GoSub, HotkeyJ return ~*k:: Hotkey, ~*k , , Off Hotkey, *k, BlockRepeat, On sleep(3) GoSub, HotkeyK return ~*l:: Hotkey, ~*l , , Off Hotkey, *l , BlockRepeat, On sleep(3) GoSub, HotkeyL return BlockRepeat: return HotkeyI: Hotkey, *i , BlockRepeat, Off Hotkey, ~*i , ~*i, On return HotkeyJ: Hotkey, *j , BlockRepeat, Off Hotkey, ~*j , ~*j, On return HotkeyK: Hotkey, *k , BlockRepeat, Off Hotkey, ~*k , ~*k, On return HotkeyL: Hotkey, *l , BlockRepeat, Off Hotkey, ~*l , ~*l, On return sleep(period := 1, Mode := "") { static Frequency, MinSetResolution, PID ; frequency can't change while computer is on if (Mode = "P") ; Precise, but the loop will eat CPU cycles! - use for short time periods { pBatchLines := A_BatchLines SetBatchLines, -1 ; increase the precision ; if !PID ; PID := DllCall("GetCurrentProcessId") ; pPiority := DllCall("GetPriorityClass","UInt", hProc := DllCall("OpenProcess","Uint",0x400,"Int",0,"UInt", PID)) ; have to use 0x400 (PROCESS_QUERY_INFORMATION) ; , DllCall("CloseHandle","Uint",hProc) ; if (pPiority != 0x20) ; Normal - I figure if priortiy less than normal increase it to normal for accuracy else if its above normal decrease it, so it doesn't affect other programs as much ; DllCall("SetPriorityClass","UInt", hProc := DllCall("OpenProcess","Uint",0x200,"Int",0,"UInt",PID), "Uint", 0x20) ; set priority to normal ;have to open a new process handle with 0x200 (PROCESS_SET_INFORMATION) ; , PriorityAltered := True if !Frequency DllCall("QueryPerformanceFrequency", "Int64*", Frequency) ; e.g. 3222744 (/s) DllCall("QueryPerformanceCounter", "Int64*", Start) Finish := Start + ( Frequency * (period/1000)) loop DllCall("QueryPerformanceCounter", "Int64*", Current) ; eats the cpu until (Current >= Finish) SetBatchLines, %pBatchLines% ; if PriorityAltered ; restore original priority ; DllCall("SetPriorityClass","UInt", hProc := DllCall("OpenProcess","Uint",0x200,"Int",0,"UInt",PID), "Uint", pPiority) ; reset priority ; , DllCall("CloseHandle","Uint",hProc) } else if (Mode = "HP" || Mode = "HS" ) ; hybrid Precise or hybrid suspend { ; will sleep the majority of the time using AHKs sleep if !Frequency ; and sleep the remainder using Precise or suspend DllCall("QueryPerformanceFrequency", "Int64*", Frequency) DllCall("QueryPerformanceCounter", "Int64*", Start) Finish := Start + ( Frequency * (period/1000)) if (A_BatchLines = -1) sleep % period - 15 ; if period is < 15 this will be a nagative number which will simply make AHK check its message queue else sleep, % period - 25 ; I picked 25 ms, as AHK sleep is usually accurate to 15 ms, and then added an extra 10 ms in case there was an AHK internal 10ms sleep DllCall("QueryPerformanceCounter", "Int64*", Current) if (Current < Finish) ; so there is still a small amount of sleep time left, lets use the precise methods for the remainder { period := (Finish - Current)*1000 / Frequency ; convert remainder to ms if (Mode = "HP") sleep(period, "P") else sleep(period, "S") } } else if (Mode = "S") ; suspend/sleep (sleeps entire script so will delay timers/hotkeys) { if !MinSetResolution { error := DllCall("winmm\timeGetDevCaps", Int64P, TimeCaps, UInt,8) if ( error || Errorlevel) { DLLcallErrorlevel := Errorlevel sleep, %period% ;fall back to AHKs own sleep return error ? error : DLLcallErrorlevel } MinSetResolution := TimeCaps & 0xFFFFFFFF ;MaxResolution := TimeCaps >> 32 DllCall("Winmm.dll\timeBeginPeriod", UInt, MinSetResolution) } DllCall("Sleep", UInt, period) } else if (Mode = "Off" && MinSetResolution) ; this should be called once at the end of the script { ; if mode "s" has been used somewhere DllCall("Winmm.dll\timeEndPeriod", UInt, MinSetResolution) MinSetResolution := False } else ; When no mode is specified, the function will use the precise method when the period { ; is 20 ms or less (i have a number of sleep calls which contain a variable period) if (period > 20) ; otherwise it just uses AHKs sleep sleep, %period% else sleep(period, "P") } return }
Re: Issue with repeating keys on keyboard
The code on its own wont create that error, you are adding one of the #IfWin commands. Try placing the #IfWin command at the bottom of the script or place a Hotkey IfWin command at the top.
example -
example -
Code: Select all
Hotkey, IfWinActive, ahk_class Notepad ;replace ahk_class Notepad with your Win Title