whkd icon indicating copy to clipboard operation
whkd copied to clipboard

[FEAT]: Tie some key binds to a keyboard layout

Open claudio4 opened this issue 6 months ago • 0 comments

Is your feature request related to a problem? Please describe. When switching between different keyboard layouts (e.g., US and Spanish) on Windows, whkd keybindings break because the physical key assigned to a virtual key code changes its reported name.

For example, the key that's Oem4 (left square bracket [) in the US layout becomes Oem1 in the Spanish layout. Similarly, Oem6 (right square bracket ]) in US becomes OemPlus in Spanish. This makes it difficult to maintain consistent keybinds when frequently switching layouts for different tasks like programming and writing.

Describe the solution you'd like It would be ideal to be able to tie some key combination to a keyboard layout, so it is only enabled when the associated layout is the currently active layout in Windows.

Describe alternatives you've considered The key binds can be duplicated for those keys that are different between layouts but no are not conflicting. Meanwhile, for those that do conflict, as whkd can run pwsh commands, this monstrosity can be used to determine the active layout and perform a different action.

Add-Type @"
using System;
using System.Runtime.InteropServices;
public class WinKB {
  [DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow();
  [DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr p);
  [DllImport("user32.dll")] public static extern IntPtr GetKeyboardLayout(uint idThread);
  [DllImport("user32.dll", CharSet = CharSet.Unicode)]
  public static extern bool GetKeyboardLayoutName(System.Text.StringBuilder sb);
}
"@

# get HKL for the thread owning the foreground window
$hkl = [WinKB]::GetKeyboardLayout(
        [WinKB]::GetWindowThreadProcessId([WinKB]::GetForegroundWindow(), [IntPtr]::Zero))

$sb  = New-Object System.Text.StringBuilder 9
[WinKB]::GetKeyboardLayoutName($sb) | Out-Null
$klid = $sb.ToString()            # 

# all Spanish KLIDs ends with 0A
if ($klid.Substring(6,2) -eq "0A") {
  Write-Output "Spanish layout detected – running command A"
  # komorebic A
} else {
  Write-Output "Non-Spanish layout detected – running command B"
  # komorebic B
}

claudio4 avatar Jun 18 '25 15:06 claudio4