Home > front end >  Disable SHIFT Stickykey shortcut
Disable SHIFT Stickykey shortcut

Time:04-14

I'm trying to disable the popout that appears when pressing shift 5 times. Despite setting the HKCU\Control Panel\Accessibility\StickyKeys\Flags key to the 506 value in the registry, the change is not automatically applied.

I tried the code below in powershell, but to no avail:

$SKHA = Add-Type -MemberDefinition '[DllImport("user32.dll", EntryPoint = "SystemParametersInfo")] public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, uint vParam, uint init);' -Name 'Test' -PassThru;
$SKHA::SystemParametersInfo(0x003B, 0, 4, 0)

The documents I used were:

SystemParametersInfoA function (winuser.h)

STICKYKEYS structure (winuser.h)

Is there any way to disable this popout without the user having to manually disable or log off/restart the system after changing the registry?

Thank you in advance.

CodePudding user response:

As explained by mklement0 you need to use the STICKYKEYS structure. Here is a working snippet based on following answer which first, read the current data then apply the parameter

$MethodDefinition = @'
[StructLayout(LayoutKind.Sequential)]
public struct STICKYKEYS
{
    public uint cbSize;
    public int dwFlags;
}

[DllImport("user32.dll")]
public static extern int SystemParametersInfo(int uiAction, int uiParam, out STICKYKEYS pvParam, int fWinIni);
'@
$get = 0x003A
$set = 0x003B
$WinApiVariable = Add-Type -MemberDefinition $MethodDefinition -Name 'Win32' -NameSpace '' -PassThru
$startupStickyKeys = New-Object -TypeName 'Win32 STICKYKEYS'
$startupStickyKeys.cbSize = [System.Runtime.InteropServices.Marshal]::SizeOf($startupStickyKeys)
[Win32]::SystemParametersInfo($get, [System.Runtime.InteropServices.Marshal]::SizeOf($startupStickyKeys), [ref]$startupStickyKeys, 0)
Write-Host "Current:"
$startupStickyKeys.dwFlags
Write-host "Set current flag to disabled (506)"
$startupStickyKeys.dwFlags = 506
[Win32]::SystemParametersInfo($set, [System.Runtime.InteropServices.Marshal]::SizeOf($startupStickyKeys), [ref]$startupStickyKeys, 0)

CodePudding user response:

To complement Brice's helpful and effective solution (his answer deserves the accepted status):

Below is a more fully featured, PowerShell-friendly way to access and manage the sticky-keys feature: The code at the bottom defines type [demo.StickyKeys] with static members that allow you do to do the following:

# Get the active flags as a combination of friendly enum values; e.g.:
#   AVAILABLE, HOTKEYACTIVE, CONFIRMHOTKEY, HOTKEYSOUND, INDICATOR, AUDIBLEFEEDBACK, TRISTATE, TWOKEYSOFF
[demo.StickyKeys]::ActiveFlags

# Query if the hotkey is currently enabled.
[demo.StickyKeys]::IsHotKeyEnabled

# Disable the hotkey *for the current session*
# Afterwards, [demo.StickyKeys]::ActiveFlags output no longer contains HOTKEYACTIVE
[demo.StickyKeys]::IsHotKeyEnabled = $false

# Disable the hotkey *persistently*.
[demo.StickyKeys]::EnableHotKey($false, $true)

# Show the flags in effect by default, on a pristine system.
[demo.StickyKeys]::DefaultFlags

Add-Member-based definition of [demo.StickyKeys]:

Add-Type -Namespace demo -Name StickyKeys -MemberDefinition '

  // The WinAPI P/Invoke declaration for SystemParametersInfo()
  [DllImport("user32.dll", SetLastError = true)]
  [return: MarshalAs(UnmanagedType.Bool)]
  static extern bool SystemParametersInfo(uint uiAction, uint uiParam, ref STICKYKEYS pvParam, uint fWinIni);

  // The data structure used by SystemParametersInfo() to get and set StickyKey-related flags.
  [StructLayout(LayoutKind.Sequential)]
  struct STICKYKEYS {
    public uint  cbSize;
    public UInt32 dwFlags;
  }

  // A helper enum that represents a given combination of flags as a list of friendly symbolic identifiers.
  [Flags]
  public enum StickyKeyFlags : uint { // Prefix SKF_ omitted from the value names.
    AUDIBLEFEEDBACK = 0x00000040,
    AVAILABLE = 0x00000002,
    CONFIRMHOTKEY = 0x00000008,
    HOTKEYACTIVE = 0x00000004,
    HOTKEYSOUND = 0x00000010,
    INDICATOR = 0x00000020,
    STICKYKEYSON = 0x00000001,
    TRISTATE = 0x00000080,
    TWOKEYSOFF = 0x00000100,
    LALTLATCHED = 0x10000000,
    LCTLLATCHED = 0x04000000,
    LSHIFTLATCHED = 0x01000000,
    RALTLATCHED = 0x20000000,
    RCTLLATCHED = 0x08000000,
    RSHIFTLATCHED = 0x02000000,
    LALTLOCKED = 0x00100000,
    LCTLLOCKED = 0x00040000,
    LSHIFTLOCKED = 0x00010000,
    RALTLOCKED = 0x00200000,
    RCTLLOCKED = 0x00080000,
    RSHIFTLOCKED = 0x00020000,
    LWINLATCHED = 0x40000000,
    RWINLATCHED = 0x80000000,
    LWINLOCKED = 0x00400000,
    RWINLOCKED = 0x00800000
  }

  // Gets or set the enabled status of the sticky-keys hotkey.
  // Note: Setting is invariably *non-persistent*.
  //       Use the .EnableHotKey() method for optional persistence.
  public static bool IsHotKeyEnabled { 
    get { return (GetFlags() & StickyKeyFlags.HOTKEYACTIVE) != 0u; }
    set { EnableHotKey(value, false); }
  }

  // Gets or set the active sticky-keys flags.
  // Note: Setting is invariably *non-persistent*.
  //       Use the .SetFlags() method for optional persistence.
  public static StickyKeyFlags ActiveFlags { 
    get { return GetFlags(); }
    set { SetFlags(value, false); }
  }

  // The flags in effect on a pristine system.
  public static StickyKeyFlags DefaultFlags {
    get { return StickyKeyFlags.AVAILABLE | StickyKeyFlags.HOTKEYACTIVE | StickyKeyFlags.CONFIRMHOTKEY | StickyKeyFlags.HOTKEYSOUND | StickyKeyFlags.INDICATOR | StickyKeyFlags.AUDIBLEFEEDBACK | StickyKeyFlags.TRISTATE | StickyKeyFlags.TWOKEYSOFF; } // 510u
  }

  // Enable or disable the stick-keys hotkey, optionally persistently.
  public static void EnableHotKey(bool enable = true, bool persist = false) {
    var skInfo = new STICKYKEYS();
    skInfo.cbSize = (uint)Marshal.SizeOf(skInfo);
    var flags = GetFlags();
    SetFlags((enable ? flags | StickyKeyFlags.HOTKEYACTIVE : flags & ~StickyKeyFlags.HOTKEYACTIVE), persist);
  }

  // Get the currently active flags; exposed via the static .ActiveFlags property only.
  private static StickyKeyFlags GetFlags() {
    var skInfo = new STICKYKEYS();
    skInfo.cbSize = (uint)Marshal.SizeOf(skInfo);
    if (!SystemParametersInfo(0x003a /* SPI_GETSTICKYKEYS */, 0, ref skInfo, 0))
      throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
    return (StickyKeyFlags)skInfo.dwFlags;
  }

  // Set the active flags *in full*, i.e. the value must combine all flags that should be set.
  // Best to start from the current combination of flags reported by .ActiveFlags.
  public static void SetFlags(StickyKeyFlags flags, bool persist = false) {
    var skInfo = new STICKYKEYS();
    skInfo.cbSize = (uint)Marshal.SizeOf(skInfo);
    skInfo.dwFlags = (UInt32)flags;
    if (!SystemParametersInfo(0x003b /* SPI_SETSTICKYKEYS */, 0, ref skInfo, persist ? 1u : 0u))
      throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
  }

'
  • Related