This script is the literal imlementation of "to run, you have to walk first".
When learning to touch-type, or when learning a new keyboard layout (such as Colemak), I sometimes hit the wrong key. Instead of slowing down and correcting myself (and consciuosly learning from my mistake), I tend to quickly try all surrounding keys one after the other until I happen to hit the right one. And then I go and make the same typo again a few minutes later.
So, what this script does is slow you down every time you hit Backspace (or Caps Lock, on Colemak). It forces you to carefully choose the next key to hit, making you think about it in the process.
All intervals are configurable. Not all features are implemented yet (most notably, locale is completely missing - it forces you to type in English).
What do you think about it?
MakeFasterBy := 50 ; how much to reduce from the delay of the keys, in ms
MakeFasterEvery := 250 ; interval between each time the delay is reduced, in ms
MakeSlowerBy := 500 ; how much slower to make key entry every time there is a mistake, in ms
MaxDelay := 1000 ; maximum delay between keys
KeyDelay := 0 ; initial key delay, in ms
GraceKeys := 4 ; how many keys have to be typed correctly in a row, before the delay is cancelled
CorrectlyTyped := 0
#MaxThreadsPerHotkey 1
;Register all keys as hotkeys.
k_ASCII = 42
Loop {
Transform k_char, Chr, %k_ASCII%
;StringUpper k_char, k_char
if k_char not in <,>,^,~, ,`,
Hotkey $%k_char%, k_KeyPress
Hotkey $+%k_char%, k_KeyPress
if k_ASCII = 93
break
k_ASCII++
}
Hotkey,~Backspace,MakeSlower
Hotkey,~CapsLock,MakeSlower
~^2::Suspend, off
~^3::Suspend, on
k_KeyPress: ; This is the main key capture routine
StringTrimLeft k_ThisHotkey, A_ThisHotkey, 1 ; Remove ~*
TypeAndSleep(k_ThisHotkey)
Return
k_deadkey: ; What to do when no keypresses should be processed.
Return
MakeFaster:
Tooltip %KeyDelay%
If (KeyDelay <= 0) {
ToolTip
KeyDelay:=0
SetTimer,MakeFaster,off
}
KeyDelay := KeyDelay-MakeFasterBy
Return
MakeSlower:
If (KeyDelay+MakeSlowerBy <= MaxDelay) {
KeyDelay := KeyDelay+MakeSlowerBy
} Else {
KeyDelay := 1000+MakeFasterBy
}
CorrectlyTyped := 0
SetTimer,MakeFaster,%MakeFasterEvery%
Return
/*
CheckToActivate:
ThreadID:=DllCall("GetWindowThreadProcessId", "Int", WinID, "Int", 0)
InputLocaleID:=DllCall("GetKeyboardLayout", "Int", ThreadID)
If (InputLocaleID = InputLocaleCode) {
Suspend,off
} Else {
Suspend, on
}
ToolTip %InputLocaleID%
return
*/
TypeAndSleep(KeyToType)
{
Global
CorrectlyTyped +=1
If (GetKeyState("Shift", "P") or GetKeyState("Capslock", "T")){
StringUpper KeyToType, KeyToType
}
Else {
StringLower KeyToType, KeyToType
}
if (CorrectlyTyped=Gracekeys) {
KeyDelay = 0
}
if (KeyDelay > 0)
{
Blockinput,on
k_ASCII = 42
Loop {
Transform k_char, Chr, %k_ASCII%
;StringUpper k_char, k_char
if k_char not in <,>,^,~, ,`,
Hotkey $%k_char%, k_deadkey
Hotkey $+%k_char%, k_deadkey
if k_ASCII = 93
break
k_ASCII++
}
Send, ?
sleep KeyDelay
Send {backspace}
k_ASCII = 42
Loop {
Transform k_char, Chr, %k_ASCII%
;StringUpper k_char, k_char
if k_char not in <,>,^,~, ,`,
Hotkey $%k_char%, k_KeyPress
Hotkey $+%k_char%, k_KeyPress
if k_ASCII = 93
break
k_ASCII++
}
Blockinput,off
}
Send %KeyToType%
return
}