Issue with repeating keys on keyboard

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
Hyphen
Posts: 53
Joined: 24 Jul 2016, 17:57

Issue with repeating keys on keyboard

16 Aug 2016, 13:33

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?
Guest503

Re: Issue with repeating keys on keyboard

16 Aug 2016, 14:13

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"]
}
Guest503

Re: Issue with repeating keys on keyboard

16 Aug 2016, 14:37

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"]
}
Hyphen
Posts: 53
Joined: 24 Jul 2016, 17:57

Re: Issue with repeating keys on keyboard

16 Aug 2016, 16:39

Thank you. The second script seems to be working so far with the delay tuned down to 5ms. Definitely beats replacing an entire keyboard.
Hyphen
Posts: 53
Joined: 24 Jul 2016, 17:57

Re: Issue with repeating keys on keyboard

16 Aug 2016, 18:53

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?
foxhunter
Posts: 72
Joined: 04 Aug 2016, 04:27

Re: Issue with repeating keys on keyboard

16 Aug 2016, 20:00

You can exchange it as follows:
Exchange this code segment (for instance)

Code: Select all

*i::
if Timer("I")
{
	Timer("I", 100)
	Send, i
}
return
with

Code: Select all

*i::
GetKeyState, state, Shift

if Timer("I")
{
	Timer("I", 100)
	if state = D
	{
		Send, I
	} else
	{
		Send, i
	} 
	
}
return
Hyphen
Posts: 53
Joined: 24 Jul 2016, 17:57

Re: Issue with repeating keys on keyboard

16 Aug 2016, 20:27

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?
Guest503

Re: Issue with repeating keys on keyboard

17 Aug 2016, 02:25

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"]
}
Guest503

Re: Issue with repeating keys on keyboard

17 Aug 2016, 02:39

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
foxhunter
Posts: 72
Joined: 04 Aug 2016, 04:27

Re: Issue with repeating keys on keyboard

17 Aug 2016, 04:47

Nice Code, but for me it runs only 1 time. For working for me i had to replace

Code: Select all

HotkeyI:
Hotkey, *i , BlockRepeat, Off
Hotkey, ~*i , , On
return
with

Code: Select all

HotkeyI:
Hotkey, *i , BlockRepeat, Off
Hotkey, ~*i , ~*i, On
return
Probably because the label wasn't defined by a prior Hotkkey command
Ghost503

Re: Issue with repeating keys on keyboard

17 Aug 2016, 05:18

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.
Hyphen
Posts: 53
Joined: 24 Jul 2016, 17:57

Re: Issue with repeating keys on keyboard

17 Aug 2016, 20:24

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
The -5 represents what? I can change that to 3 for 3ms?
Guest503

Re: Issue with repeating keys on keyboard

17 Aug 2016, 23:54

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.

Code: Select all

~*NumLock::
Suspend
Pause,,1
return
Or you can use precise sleep function and tweak the sleep value until it is exactly what you need.

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
}
Guest503

Re: Issue with repeating keys on keyboard

18 Aug 2016, 03:43

foxhunter you were right :D 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 :facepalm:

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
and the one using sleep

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
}
Hyphen
Posts: 53
Joined: 24 Jul 2016, 17:57

Re: Issue with repeating keys on keyboard

18 Aug 2016, 18:15

Guest503 wrote:foxhunter you were right :D 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 :facepalm:

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
and the one using sleep

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
}
Using first code:
Image
Guest503

Re: Issue with repeating keys on keyboard

19 Aug 2016, 01:11

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 -

Code: Select all

Hotkey, IfWinActive, ahk_class Notepad	;replace ahk_class Notepad with your Win Title

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Descolada, OrangeCat and 175 guests