Configure debounce time in Windows for mouse
My mouse is broken and I am too lazy to buy a new one. The problem is with the left click button. A simple physical click will result in several clicks in Windows. There is already a debouncing circuit in the mouse to prevent this type of behavior, but it is no longer effective. How can I increase the debounce time in software? Or another to put it is how can I tell to Windows to ignore multiple mouse clicks if the time between them is less than 0.1 sec.
The free (and open source) tool AutoHotkey allows users to write custom scripts that interact with the keyboard and mouse. In particular, one user has written a script called "Buggy Mouse" which "sets your mouse's minimum double-click speed (preventing single-clicks from being seen as double-clicks)". It does this by ignoring multiple clicks that occur too close to each other.
After installing AutoHotkey and loading the script, my own debouncing issues appear to have been solved.
You may need to adjust the DoubleClick_Min
parameter at the top of the script which determines the minimum amount of time between mouse events to be considered as two independent clicks: I found that the default value caused legitimate double-clicks to be considered a bounce. The value of 75
seems to work well for me, however.
Edit 2021-02-18:
The Buggy Mouse link has rotted. However, another user as posted a new link to what appears to be equivalent code although the DoubleClick_Min
variable was renamed DoubleClickMin_ms
. It is copied here in its entirety to prevent future rot.
/*
** Buggy-Mouse.ahk - Fix a buggy mouse. Stop it from double-clicking when you try to single-click.
**
** NOTE: Please use this URL when linking to Buggy Mouse: r.secsrv.net/AutoHotkey/Scripts/Buggy-Mouse
**
** Updated: Thu, Nov 1, 2012 --- 11/1/12, 10:19:19am EDT
** Location: r.secsrv.net/AutoHotkey/Scripts/Buggy-Mouse
**
** Keywords: mouse double clicks when I click once
** Keywords: mouse double clicks when I single click
** Keywords: mouse double clicks on its own
** Keywords: mouse double clicks with one click
** Keywords: mouse double clicks on single click
** Keywords: mouse double clicks on one click
** Keywords: mouse double-clicking when you single-click
** Keywords: set mouse minimum double click speed
** Keywords: debounce mouse
**
** Author: JSLover - r.secsrv.net/JSLover - r.secsrv.net/JSLoverAHK
**
** NOTE: Please use AutoHotkey 1.1+ (AutoHotkey_L) for this script!
** AutoHotkey.com
** L.AutoHotkey.net
**
** NOTE: Compiled version available here: r.secsrv.net/AutoHotkey/Scripts/Buggy-Mouse.exe
**
*/
#SingleInstance force
OnExit, OnExit
;// **************************** Settings ****************************
;// Minimum double-click time. Any lower & it will be blocked (as being inhumanly fast).
DoubleClickMin_ms:=90
;// *** DISABLED *** ;// Minimum click after mouse-up time. Any lower & it will be blocked (as being inhumanly fast).
;// *** DISABLED *** ClickAfterMouseUpMin_ms:=100
;// **************************** /Settings ****************************
;// **************************** Advanded Settings ****************************
;// Enable logging if you need to report a bug.
;// Default (Disabled): Log=0
Log=0
;// Enable debugging if you want to see blocked/allowed clicks.
;// Default (Disabled): Debug=0
Debug=0
;// Enable this if you only want to see blocked clicks (when debugging is enabled).
;// Default (Enabled): Debug_OnlyBlocked=1
;// Note: Requires Debug (above) to be enabled (or no debugging will happen at all)
Debug_OnlyBlocked=1
;// **************************** /Advanded Settings ****************************
Gosub, OnStartup
;// *** Build Tray Menu ***
Text_ClicksBlocked=Clicks Blocked
Text_Debug=Debug
Text_Debug_OnlyBlocked=Debug (only blocked)
Menu, Tray, Add, %Text_ClicksBlocked%, BuggyMouse_MenuSelect_ClicksBlocked
Text_ClicksBlocked_MenuCurrent:=Text_ClicksBlocked
Menu, Tray, Default, %Text_ClicksBlocked%
Menu, Tray, Add, %Text_Debug%, BuggyMouse_MenuSelect_Debug
Menu, Tray, Add, %Text_Debug_OnlyBlocked%, BuggyMouse_MenuSelect_Debug_OnlyBlocked
Menu, Tray, Disable, %Text_Debug_OnlyBlocked%
Menu, Tray, MainWindow
Menu, Tray, NoStandard
Menu, Tray, Add
Menu, Tray, Standard
;// *** /Build Tray Menu ***
;// BuggyMouse_Debug:=1
;// BuggyMouse_Debug_OnlyBlocked:=1
if (Debug) {
Gosub, BuggyMouse_MenuSelect_Debug
}
if (Debug_OnlyBlocked) {
Gosub, BuggyMouse_MenuSelect_Debug_OnlyBlocked
}
return
OnStartup:
logdir=%A_ScriptDir%
logfilename=%A_ScriptName%.log
logfile=%logdir%\%logfilename%
time:=time()
logmsg=
(LTrim
%A_ScriptName% Started`t`t%time%
` Status`t`tUpDn`t Key`t`t`tReason`t`t`t`tWindow`n
)
log(logmsg)
return
OnExit:
time:=time()
logmsg=
(LTrim
%A_ScriptName% Exited`t`t%time%`n`n
)
log(logmsg)
ExitApp
*LButton::
*MButton::
*RButton::
A_ThisHotkey_VarSafe:=Hotkey_MakeVarSafe(A_ThisHotkey, "*")
A_ThisHotkey_NoModifiers:=Hotkey_RemoveModifiers(A_ThisHotkey)
;// A_ThisHotkey_Modifiers:=Hotkey_GetModifiers(A_ThisHotkey)
A_ThisHotkey_KeyName:=Hotkey_GetKeyName(A_ThisHotkey)
log_key:="Down`t" A_ThisHotkey "`t"
Critical
di++
TimeSinceLastMouseDown:=A_TickCount-LastMouseDown_ts
;// TimeSinceLastMouseUp:=A_TickCount-LastMouseUp_ts
DoubleClickTooFast:=TimeSinceLastMouseDown<=DoubleClickMin_ms
;// *** DISABLED *** ClickAfterMouseUpTooSoon:=(ClickAfterMouseUpMin_ms!="" && TimeSinceLastMouseUp<=ClickAfterMouseUpMin_ms)
;// if ((A_ThisHotkey==LastMouseDown && DoubleClickTooFast) || ClickAfterMouseUpTooSoon) {
if (A_ThisHotkey==LastMouseDown && (DoubleClickTooFast || ClickAfterMouseUpTooSoon)) {
;// if (A_TimeSincePriorHotkey<=DoubleClickMin_ms) {
reason:=DoubleClickTooFast ? "DoubleClickTooFast" "(" TimeSinceLastMouseDown ")" "(" DoubleClickMin_ms ")"
: ClickAfterMouseUpTooSoon ? "ClickAfterMouseUpTooSoon" "(" TimeSinceLastMouseUp ")" "(" ClickAfterMouseUpMin_ms ")"
: "Unknown"
msg=`nblocked (%reason%)
blockeddown:=1
BlockedCount_Down++
BlockedCount_%A_ThisHotkey_VarSafe%++
Gosub, BuggyMouse_UpdateStatus_ClicksBlocked
log_action:="BLOCKED`t"
} else {
reason:=""
Send, {Blind}{%A_ThisHotkey_KeyName% DownTemp}
msg=`nSent, {Blind}{%A_ThisHotkey_KeyName% DownTemp}`n`n
(LTrim C
if (%A_ThisHotkey%==%LastMouseDown% && (%DoubleClickTooFast% || %ClickAfterMouseUpTooSoon%))
)
log_action:="`tallowed"
}
BuggyMouse_DebugMsg_down=%di%: %A_ThisHotkey%(%TimeSinceLastMouseDown%)%LastMouseDown%%msg%
msg=
Gosub, BuggyMouse_Debug
LastMouseDown:=A_ThisHotkey
LastMouseDown_ts:=A_TickCount
wininfo:=WinGetInfo("a")
log(log_action "`t`t" log_key "`t`t" reason "`t`t`t`t`t" wininfo "`n")
return
*LButton up::
*MButton up::
*RButton up::
A_ThisHotkey_VarSafe:=Hotkey_MakeVarSafe(A_ThisHotkey, "*")
A_ThisHotkey_NoModifiers:=Hotkey_RemoveModifiers(A_ThisHotkey)
;// A_ThisHotkey_Modifiers:=Hotkey_GetModifiers(A_ThisHotkey)
A_ThisHotkey_KeyName:=Hotkey_GetKeyName(A_ThisHotkey)
log_key:=" Up `t" A_ThisHotkey
Critical
ui++
TimeSinceLastMouseUp:=A_TickCount-LastMouseUp_ts
;// if (A_ThisHotkey=A_PriorHotkey && A_TimeSincePriorHotkey<=DoubleClickMin_ms) {
;// if (A_ThisHotkey=LastMouseUp && A_TimeSincePriorHotkey<=DoubleClickMin_ms) {
if (blockeddown) {
msg=`nblocked
blockedup:=1
BlockedCount_Up++
BlockedCount_%A_ThisHotkey_VarSafe%++
Gosub, BuggyMouse_UpdateStatus_ClicksBlocked
log_action:="BLOCKED`t"
} else {
Send, {Blind}{%A_ThisHotkey_KeyName% up}
msg=`nSent, {Blind}{%A_ThisHotkey_KeyName% up}
log_action:="`tallowed"
}
;// if (BuggyMouse_Debug) {
BuggyMouse_DebugMsg_up=%ui%: %A_ThisHotkey%(%TimeSinceLastMouseUp%)%LastMouseUp%%msg%
msg=
Gosub, BuggyMouse_Debug
;// }
blockeddown=
blockedup=
LastMouseUp:=A_ThisHotkey
LastMouseUp_ts:=A_TickCount
wininfo:=WinGetInfo("a")
log(log_action "`t`t" log_key "`t`t" reason "`t`t`t`t`t" wininfo "`n")
return
BuggyMouse_Debug_ShowLastMsg:
;// BuggyMouse_Debug_ShowLastMsg=1
BuggyMouse_Debug:
CoordMode, Tooltip
if (A_ThisLabel="BuggyMouse_Debug_ShowLastMsg"
|| (BuggyMouse_Debug && (!BuggyMouse_Debug_OnlyBlocked
|| (BuggyMouse_Debug_OnlyBlocked && (blockeddown||blockedup))))) {
Tooltip, %BuggyMouse_DebugMsg_down%`n`n%BuggyMouse_DebugMsg_up%, 819, 619
} else {
Tooltip
}
return
BuggyMouse_UpdateStatus_ClicksBlocked:
BlockedCount_Total:=BlockedCount_Down+BlockedCount_Up
Text_ClicksBlocked_MenuNew=%Text_ClicksBlocked%: %BlockedCount_Total%
Menu, Tray, Rename, %Text_ClicksBlocked_MenuCurrent%, %Text_ClicksBlocked_MenuNew%
Text_ClicksBlocked_MenuCurrent:=Text_ClicksBlocked_MenuNew
Menu, Tray, Tip, %Text_ClicksBlocked_MenuCurrent% - %A_ScriptName%
return
BuggyMouse_MenuSelect_ClicksBlocked:
msgbox, 64, ,
(LTrim C
%Text_ClicksBlocked_MenuCurrent%
Down(%BlockedCount_Down%)
Up(%BlockedCount_Up%)
LButton(%BlockedCount_LButton%)
MButton(%BlockedCount_MButton%)
RButton(%BlockedCount_RButton%)
LButton up(%BlockedCount_LButton_up%)
MButton up(%BlockedCount_MButton_up%)
RButton up(%BlockedCount_RButton_up%)
)
return
BuggyMouse_MenuSelect_Debug:
BuggyMouse_Debug:=!BuggyMouse_Debug
Menu, Tray, ToggleCheck, %Text_Debug%
Menu, Tray, ToggleEnable, %Text_Debug_OnlyBlocked%
Tooltip
return
BuggyMouse_MenuSelect_Debug_OnlyBlocked:
BuggyMouse_Debug_OnlyBlocked:=!BuggyMouse_Debug_OnlyBlocked
Menu, Tray, ToggleCheck, %Text_Debug_OnlyBlocked%
Tooltip
return
Hotkey_MakeVarSafe(p_hotkey, p_ignorechars="") {
replace:=p_hotkey
StringReplace, replace, replace, $, % !InStr(p_ignorechars, "$") ? "KH_":""
StringReplace, replace, replace, ~, % !InStr(p_ignorechars, "~") ? "PT_":""
StringReplace, replace, replace, *, % !InStr(p_ignorechars, "*") ? "WC_":""
StringReplace, replace, replace, <^>!, AltGr_
StringReplace, replace, replace, <, L, a
StringReplace, replace, replace, >, R, a
StringReplace, replace, replace, &, and
StringReplace, replace, replace, ^, Ctrl_, a
StringReplace, replace, replace, +, Shift_, a
StringReplace, replace, replace, #, Win_, a
StringReplace, replace, replace, !, Alt_, a
replace:=RegExReplace(replace, "i)[^a-z0-9_]", "_")
p_hotkey:=replace
return p_hotkey
}
Hotkey_GetModifiers(p_hotkey) {
return RegExReplace(p_hotkey, "i)[\w\s]+$")
}
Hotkey_RemoveModifiers(p_hotkey) {
return RegExReplace(p_hotkey, "i)^[^a-z0-9_]+")
}
Hotkey_GetKeyName(p_hotkey) {
p_hotkey:=Hotkey_RemoveModifiers(p_hotkey)
;// Get string before 1st space...(removes "up" or "down" from name of key)
Loop, Parse, p_hotkey, " "
{
p_hotkey:=A_LoopField
break
}
return p_hotkey
}
log(p_msg, p_file="") {
Global Log, logfile
if (!Log) {
return
}
if (p_file="") {
p_file:=logfile
}
FileAppend, %p_msg%, %p_file%
}
time() {
FormatTime, time, L1033, ddd, MMM d, yyyy --- M/d/yy h:mm:sstt
return time
}
WinGetInfo(p_win, ByRef r_win_title="", ByRef r_win_class="") {
WinGetTitle, win_title, %p_win%
WinGetClass, win_class, %p_win%
r_win_title:=(win_title ? win_title:"<no-title-info>")
r_win_class:=(win_class ? win_class:"<no-class-info>")
;// wininfo:=(win_title ? win_title:"<no-title-info>") " - " (win_class ? win_class:"<no-class-info>")
wininfo:=(win_class ? win_class:"<no-class-info>") ": " (win_title ? win_title:"<no-title-info>")
return wininfo
}
;// #ScrollLock::log("*** PROBLEM ***`n")
^+#!F8::Gosub, BuggyMouse_Debug_ShowLastMsg
^+#!F9::Suspend
^+#!F12::ExitApp
/* ;// **************************** Changelog / Version History ****************************
**
** Created: Fri, Apr 11, 2008 --- 4/11/08, 11:19:19am
** Modified: Sat, Apr 12, 2008 --- 4/12/08, 5:38:19am
** Modified: Sun, Jul 10, 2011 --- 7/10/11, 3:19:19am EDT
** * Added blocking of "mouse down too soon after last mouse up"
** Modified: Wed, Jul 20, 2011 --- 7/20/11, 1:19:19pm EDT
** Modified: Thu, Aug 25, 2011 --- 8/25/11, 1:19:19am EDT
** * Temporarily disabled "mouse down too soon after last mouse up" blocking, until I get it working.
** Modified: Thu, Aug 25, 2011 --- 8/25/11, 2:38:19am EDT
** * Updated Keywords for search engines
** Modified: Sat, Aug 27, 2011 --- 8/27/11, 7:19:19am EDT
** * Added Logging
** Modified: Sat, Aug 27, 2011 --- 8/27/11, 2:38:19pm EDT
** * Added Window Info to log
** Modified: Sun, May 13, 2012 --- 5/13/12, 7:19:19pm EDT
** * Added support for blocking mouse clicks while holding down keyboard keys
** Modified: Mon, May 14, 2012 --- 5/14/12, 10:19:19am EDT
** * Updated Hotkey_MakeVarSafe()
** Modified: Tue, May 15, 2012 --- 5/15/12, 7:19:19am EDT
** * Hotkey_MakeVarSafe(): Fixed error msg/incompatibility with AutoHotkey < 1.1
** Modified: Thu, Nov 1, 2012 --- 11/1/12, 10:19:19am EDT
** * Made Debugging default to Off
** * Added "Debug" & "Debug_OnlyBlocked" to Settings section, for easier toggling of the default state
**
*/ ;// **************************** /Changelog / Version History ****************************
Sorry I can't post comments, but I wanted to add to daviddg's answer. Searching the scripts section of the AutoHotkey web site did not find anything for "Buggy Mouse". However, I did find a script on this post: http://www.autohotkey.com/board/topic/82509-software-fix-for-double-clicking-mouse
And the script source is:
LButton::
If (A_TimeSincePriorHotkey < 100) ;hyperclick
Return
sendinput {LButton down}
KeyWait, LButton
sendinput {LButton up}
Return