Disable Sticky Keys

Advanced game related topics
coco2
Enthusiast
Enthusiast
Posts: 368
Joined: Mon Nov 25, 2013 5:38 am
Location: Australia

Disable Sticky Keys

Post by coco2 »

Do games disable Sticky Keys when they start? I assume they would. Has anyone figured out how to disable and enable it in PureBasic?
nsstudios
Enthusiast
Enthusiast
Posts: 274
Joined: Wed Aug 28, 2019 1:01 pm
Location: Serbia
Contact:

Re: Disable Sticky Keys

Post by nsstudios »

Good question!
I'm not really sure if it's common behavior.
For Windows, this Microsoft article explains how to use SystemParametersInfo() to do this, although I really don't like it because the function affects the whole system, so if your app/game crashes, the user is gonna be left with everything disabled.

In PB, would look something like this:

Code: Select all

Structure STICKYKEYS
cbSize.l
dwFlags.l
EndStructure
Define.STICKYKEYS sk\cbSize=SizeOf(STICKYKEYS), skOrig=sk
#SKF_STICKYKEYSON=$00000001
#SKF_HOTKEYACTIVE=$00000004
#SKF_CONFIRMHOTKEY=$00000008
SystemParametersInfo_(#SPI_GETSTICKYKEYS, SizeOf(STICKYKEYS), @skOrig, 0); get original settings
sk\dwFlags=skOrig\dwFlags&~(#SKF_STICKYKEYSON|#SKF_HOTKEYACTIVE); turn off the SKF_STICKYKEYSON and SKF_HOTKEYACTIVE flags
SystemParametersInfo_(#SPI_SETSTICKYKEYS, SizeOf(STICKYKEYS), @sk, 0); set new settings
Then when your app/game is about to quit, or your window goes out of focus, call

Code: Select all

SystemParametersInfo_(#SPI_SETSTICKYKEYS, SizeOf(STICKYKEYS), @skOrig, 0); reset settings to original
coco2
Enthusiast
Enthusiast
Posts: 368
Joined: Mon Nov 25, 2013 5:38 am
Location: Australia

Re: Disable Sticky Keys

Post by coco2 »

Thanks for the code it works. I checked and some games disable it but most don't. Reddit believes you should not disable it and let the user work it out.
nsstudios
Enthusiast
Enthusiast
Posts: 274
Joined: Wed Aug 28, 2019 1:01 pm
Location: Serbia
Contact:

Re: Disable Sticky Keys

Post by nsstudios »

You will also probably want to disable/enable toggle and filter keys, too, but yeah. I'm on Reddit's side here. It feels invasive to modify system-wide settings without being 600% sure that you can put things back where you found them.
You know, like what if someone can't use their computer without those features period, so if an app/game disables them, they may not be able to re-enable them without help.
I'd say just put it as a warning in the docs/tutorial, or something. Maybe detect if they're on, and display a warning, even.
coco2
Enthusiast
Enthusiast
Posts: 368
Joined: Mon Nov 25, 2013 5:38 am
Location: Australia

Re: Disable Sticky Keys

Post by coco2 »

That is where I discovered a case where a user is a Sticky Keys user in regular Windows desktop. A certain game they like uses the shift key. That user is going to have to disable Sticky Keys every time they play the game. I would be so annoyed by that. I believe the best option is to allow the game to disable Sticky Keys but only when the user sets the option to do so. That way the user has full control over both Sticky Keys and the game. If you ignore the problem completely you are not causing problems with accessibility, but you are creating frustration.

Edit: how would you go about disabling Filter Keys?
nsstudios
Enthusiast
Enthusiast
Posts: 274
Joined: Wed Aug 28, 2019 1:01 pm
Location: Serbia
Contact:

Re: Disable Sticky Keys

Post by nsstudios »

Oh, I can totally see how that would be frustrating.
Here's a full-fledged include. :)

Code: Select all

; Disable keyboard accessibility
; 2023-08-27 by Enne (NS studios)
; Allows disabling, reverting, and checking the state of the system-wide settings for filter, sticky, and toggle keys
; should be dll-friendly
; InitA11y() must be called before using any of the isX() macros or DisableA11y func
EnableExplicit
;{ consts
#FKF_FILTERKEYSON=$00000001
#FKF_HOTKEYACTIVE=$00000004
#FKF_CONFIRMHOTKEY=$00000008
#SKF_STICKYKEYSON=$00000001
#SKF_HOTKEYACTIVE=$00000004
#SKF_CONFIRMHOTKEY=$00000008
#TKF_TOGGLEKEYSON=$00000001
#TKF_HOTKEYACTIVE=$00000004
#TKF_CONFIRMHOTKEY=$00000008
;} consts
;{ structs
Structure FILTERKEYS
cbSize.l
dwFlags.l
iWaitMSec.l
  iDelayMSec.l
  iRepeatMSec.l
iBounceMSec.l
EndStructure
Structure STICKYKEYS
cbSize.l
dwFlags.l
EndStructure
Structure TOGGLEKEYS
cbSize.l
dwFlags.l
EndStructure
;} structs
Global fkOrig.FILTERKEYS, skOrig.STICKYKEYS, tkOrig.TOGGLEKEYS, a11yInit

; get initial accessibility settings
; return=1 if all features have been read successfully, 0 otherwise
Procedure.i initA11y()
fkOrig\cbSize=SizeOf(FILTERKEYS): skOrig\cbSize=SizeOf(STICKYKEYS): tkOrig\cbSize=SizeOf(TOGGLEKEYS)
Protected fkr=SystemParametersInfo_(#SPI_GETFILTERKEYS, SizeOf(FILTERKEYS), @fkOrig, 0),
skr=SystemParametersInfo_(#SPI_GETSTICKYKEYS, SizeOf(STICKYKEYS), @skOrig, 0),
tkr=SystemParametersInfo_(#SPI_GETTOGGLEKEYS, SizeOf(TOGGLEKEYS), @tkOrig, 0)
a11yInit=Bool(fkr And skr And tkr)
ProcedureReturn a11yInit
EndProcedure

; DisableAccessibility (not exact port of https://learn.microsoft.com/en-us/windows/win32/dxtecharts/disabling-shortcut-keys-in-games)
; state=1 to disable accessibility features (default), 0 to restore them to original settings
; force=whether to disable an accessibility feature even if it's currently active (1=force, 0=don't force (default))
; return=1 if all settings were set successfully, 0 otherwise
; Warning!!! This will affect the accessibility settings system-wide, and the settings will persist after the app exits. It's a must to return the settings to their original state at the very least before exiting, but preferably when the window loses focus, too.
Procedure.i DisableA11y(state=1, force=0)
If Not a11yInit
DebuggerError("initA11y() must be called before calling DisableA11y()!")
EndIf
Protected fk.FILTERKEYS=fkOrig, sk.STICKYKEYS=skOrig, tk.TOGGLEKEYS=tkOrig
If state
If Not fk\dwFlags&#FKF_FILTERKEYSON Or force
fk\dwFlags&~(#FKF_FILTERKEYSON|#FKF_HOTKEYACTIVE|#FKF_CONFIRMHOTKEY)
EndIf
If Not sk\dwFlags&#SKF_STICKYKEYSON Or force
sk\dwFlags&~(#SKF_STICKYKEYSON|#SKF_HOTKEYACTIVE|#SKF_CONFIRMHOTKEY)
EndIf
If Not tk\dwFlags&#TKF_TOGGLEKEYSON Or force
tk\dwFlags&~(#TKF_TOGGLEKEYSON|#TKF_HOTKEYACTIVE|#TKF_CONFIRMHOTKEY)
EndIf
EndIf
Protected fkr=SystemParametersInfo_(#SPI_SETFILTERKEYS, SizeOf(FILTERKEYS), @fk, 0),
skr=SystemParametersInfo_(#SPI_SETSTICKYKEYS, SizeOf(STICKYKEYS), @sk, 0),
tkr=SystemParametersInfo_(#SPI_SETTOGGLEKEYS, SizeOf(TOGGLEKEYS), @tk, 0)
ProcedureReturn Bool(fkr And skr And tkr)
EndProcedure

; checks if filter keys are either active or the hotkey for them is on, meaning they could be triggered
Macro isFilterKeys()
(Bool(fkOrig\dwFlags&(#FKF_FILTERKEYSON|#FKF_HOTKEYACTIVE)))
EndMacro

; checks if sticky keys are either active or the hotkey for them is on, meaning they could be triggered
Macro isStickyKeys()
(Bool(skOrig\dwFlags&(#SKF_STICKYKEYSON|#SKF_HOTKEYACTIVE)))
EndMacro

; checks if toggle keys are either active or the hotkey for them is on, meaning they could be triggered
Macro isToggleKeys()
(Bool(tkOrig\dwFlags&(#TKF_TOGGLEKEYSON|#TKF_HOTKEYACTIVE)))
EndMacro

; checks if at least one accessibility feature is either active or the hotkey for it is on, meaning it can be triggered
Macro isA11y()
(Bool(isFilterKeys() Or isStickyKeys() Or isToggleKeys()))
EndMacro
coco2
Enthusiast
Enthusiast
Posts: 368
Joined: Mon Nov 25, 2013 5:38 am
Location: Australia

Re: Disable Sticky Keys

Post by coco2 »

It works well, except I think I ran it without restoring the original settings now I think I have broken my toggle keys. I tried rebooting and checking the Windows settings but I can't get it to work again. Do you happen to know how to force toggle keys back on? I seem to have broken it. Which goes to show how it can be problematic playing around with these settings and the game crashes. But if Microsoft has documentation saying how to do it then it seems like it is somewhat expected that developers are going to do it.
nsstudios
Enthusiast
Enthusiast
Posts: 274
Joined: Wed Aug 28, 2019 1:01 pm
Location: Serbia
Contact:

Re: Disable Sticky Keys

Post by nsstudios »

:oops:
I think that happened to me once too, and I think just unchecking/checking the allow the shortcut key to start filter/sticky/toggle keys helped, and unchecking/checking the show a warning message, and unchecking/checking the make a sound checkbox in settings/ease of access/keyboard.
coco2 wrote: Mon Aug 28, 2023 12:30 pm It works well, except I think I ran it without restoring the original settings now I think I have broken my toggle keys. I tried rebooting and checking the Windows settings but I can't get it to work again. Do you happen to know how to force toggle keys back on? I seem to have broken it. Which goes to show how it can be problematic playing around with these settings and the game crashes. But if Microsoft has documentation saying how to do it then it seems like it is somewhat expected that developers are going to do it.
coco2
Enthusiast
Enthusiast
Posts: 368
Joined: Mon Nov 25, 2013 5:38 am
Location: Australia

Re: Disable Sticky Keys

Post by coco2 »

The only way I got it to work again was to change the registry:

[HKEY_CURRENT_USER\Control Panel\Accessibility\ToggleKeys]
"Flags"="63"

It seems that ToggleKeys does not have a way for the user to turn the keyboard shortcut back on in the settings of Windows 11. Not sure about Windows 10.
nsstudios
Enthusiast
Enthusiast
Posts: 274
Joined: Wed Aug 28, 2019 1:01 pm
Location: Serbia
Contact:

Re: Disable Sticky Keys

Post by nsstudios »

Yikes!
I'm still using Win10, and I see the
Allow the shortcut key to start Toggle Keys
check box.
That's concerning if you can't change it in Win11.
I really-really wish there was a non-invasive way to do this.
Please let me know if maybe I broke something if you still wish to use/try the include (wouldn't blame you if not).
I will look into alternative ways in the meantime if there are any.
coco2 wrote: Mon Aug 28, 2023 12:50 pm The only way I got it to work again was to change the registry:

[HKEY_CURRENT_USER\Control Panel\Accessibility\ToggleKeys]
"Flags"="63"

It seems that ToggleKeys does not have a way for the user to turn the keyboard shortcut back on in the settings of Windows 11. Not sure about Windows 10.
coco2
Enthusiast
Enthusiast
Posts: 368
Joined: Mon Nov 25, 2013 5:38 am
Location: Australia

Re: Disable Sticky Keys

Post by coco2 »

The include is working well in my game, thanks for you help.

Edit: the mistake I made was that I forgot to reset the original settings when I was playing around with the code, so that meant that the settings were lost. It is implemented correctly now.
nsstudios
Enthusiast
Enthusiast
Posts: 274
Joined: Wed Aug 28, 2019 1:01 pm
Location: Serbia
Contact:

Re: Disable Sticky Keys

Post by nsstudios »

Awesome!
Happy to help. :)
Also happy to fix/add anything if needed anytime.
I'd probably suggest notifying the users somehow or asking them if they want to disable things. Maybe use the isA11y and bring up a prompt or something. In general, things that alter the state of the whole machine shouldn't be done silently IMO, but that's just my opinion.
You could perhaps also have a launcher of sorts that does the disabling and spawns the main process, waits for it to close for any reason, at which point it restores the
settings and exits itself.
That way, even if the game crashes, the watcher/launcher will still restore things.
You could also go a step further and package your main executable inside the launcher and extract it on launch/delete on exit, but that may be considered shady by antiviruses.
coco2
Enthusiast
Enthusiast
Posts: 368
Joined: Mon Nov 25, 2013 5:38 am
Location: Australia

Re: Disable Sticky Keys

Post by coco2 »

You could pop up a message asking if you want to turn off the accessibility features and set a permanent option in the game. The launcher sounds like a good idea, maybe better than what AAA games provide.
Post Reply