惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Y
Y Combinator Blog
The GitHub Blog
The GitHub Blog
Vercel News
Vercel News
D
DataBreaches.Net
MongoDB | Blog
MongoDB | Blog
H
Help Net Security
小众软件
小众软件
美团技术团队
T
The Blog of Author Tim Ferriss
爱范儿
爱范儿
D
Docker
Martin Fowler
Martin Fowler
大猫的无限游戏
大猫的无限游戏
博客园 - 聂微东
Blog — PlanetScale
Blog — PlanetScale
H
Hackread – Cybersecurity News, Data Breaches, AI and More
罗磊的独立博客
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
V
V2EX
S
SegmentFault 最新的问题
云风的 BLOG
云风的 BLOG
B
Blog
雷峰网
雷峰网
The Cloudflare Blog

Hacker News

GitHub - SeanFDZ/macmind: Single-layer transformer in HyperTalk for the classic Macintosh Show HN: Agent-cache – Multi-tier LLM/tool/session caching for Valkey and Redis Bonsai 1-bit WebGPU - a Hugging Face Space by webml-community Moving a large-scale metrics pipeline from StatsD to OpenTelemetry / Prometheus GitHub - Nightmare-Eclipse/RedSun: The Red Sun vulnerability repository GitHub - SethPyle376/hiraeth: Local AWS emulator focused on fast integration testing, with SQS support, SQLite-backed state, and a debug-friendly web UI. GitHub - macOS26/Agent: Any AI, replaces Claude Code, Cursor, OpenClaw. Over 18 LLM providers (Claude, OpenAI, Gemini, Ollama, Zai, HF, Qwen) wired into a native Mac app that writes code, builds Xcode projects, bumps versions, manages git, automates Safari, use AppleScript, JS or Accessibility, extend Agent! w/ MCP Servers, run tasks from your iPhone via Messages. YouTube now lets you turn off Shorts I Made a Terminal Pager Burgers | マクドナルド公式 Commands — HackerNews CLI documentation ChatGPT for Excel PiCore - Raspberry Pi Port of Tiny Core Linux Live Nation illegally monopolized ticketing market, jury finds Google Broke Its Promise to Me. Now ICE Has My Data. Founding Engineer at Adaptional | Y Combinator CRISPR takes important step toward silencing Down syndrome’s extra chromosome GitHub - saffron-health/libretto: The AI toolkit for building reliable browser automations US v. Heppner (S.D.N.Y. 2026) no attorney-client privilege for AI chats [pdf] Retrofitting JIT Compilers into C Interpreters IPv6 – Google The Accursèd Alphabetical Clock Cybersecurity Looks Like Proof of Work Now Fragments: April 14 Cal.com Goes Closed Source: Why AI Security Is Forcing Our Decision | Cal.com - Scheduling Software for Online Bookings Laravel raised money and now injects ads directly into your agent When moving fast, talking is the first thing to break Too much Discussion of the XOR swap trick – Heather Cafe Introduction to Spherical Harmonics for Graphics Programmers The Grand Line
Switch between three keyboard languages | mnaoumov.dev
Michael Naumov · 2023-12-17 · via Hacker News

Hi folks.

On the regular basis I use three keyboards: English, Russian and Ukrainian. I need them quite often and I need a quick way to switch between them. Default Alt + Shift and Win + Space are not good enough. Cyclical changes don’t work well sometimes and I have to click more and look in the notification error for the language label.

There are many tools for switching languages such as Punto Switcher but all that I tried work fine with two languages and don’t suggest anything nice for three language users. There are some advices how to use three languages but I didn’t find them practical.

My need is to be able to quickly switch to the desired language regardless of the current language selected.

I came up with the following idea:

  • Left Control to switch to English language
  • Right Control to switch to Russian language
  • Right Alt to switch to Ukrainian language

But also I need to keep the default behavior of those buttons and the shortcuts using those keys.

I would like to share the solution I came up with:

I built a script for AutoHotkey

#Requires AutoHotKey v2.0
#SingleInstance Force
#Warn All, MsgBox
#UseHook

; Based on https://www.autohotkey.com/boards/viewtopic.php?f=6&t=18519

setDefaultKeyboard(localeId) {
    ; https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfoa
    static SPI_SETDEFAULTINPUTLANG := 0x005A

    ; https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfoa
    static SPIF_SENDWININICHANGE := 2

    ; https://learn.microsoft.com/en-us/windows/win32/winmsg/wm-inputlangchangerequest
    static WM_INPUTLANGCHANGEREQUEST := 0x0050

    ; https://learn.microsoft.com/en-us/windows/win32/winmsg/wm-inputlangchange
    static WM_INPUTLANGCHANGE := 0x0051

    ; https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-loadkeyboardlayouta
    static KLF_ACTIVATE := 0x00000001

    ; https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-loadkeyboardlayouta
    pwszKLID := Format("{:08x}", localeId)
    Flags := KLF_ACTIVATE
    keyboardLayout := DllCall("LoadKeyboardLayout", "Str", pwszKLID, "Int", Flags)

    ; https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfoa
    uiAction := SPI_SETDEFAULTINPUTLANG
    uiParam := 0
    pvParam := keyboardLayout
    fWinIni := SPIF_SENDWININICHANGE
    DllCall("SystemParametersInfo", "UInt", uiAction, "UInt", uiParam, "UPtr", pvParam, "UInt", fWinIni)

    windowIds := WinGetList()

    for windowId in windowIds {
        try {
            PostMessage(WM_INPUTLANGCHANGEREQUEST, 0, keyboardLayout, , "ahk_id" . windowId)
            PostMessage(WM_INPUTLANGCHANGE, 0, keyboardLayout, , "ahk_id" . windowId)
        } catch {
            ; Skip access denied windows
        }
    }
}

; https://stackoverflow.com/questions/14701095/how-to-get-keyboard-layout-name-from-a-keyboard-layout-identifier
; https://learn.microsoft.com/en-us/globalization/windows-keyboard-layouts

localeId_English_USA := 0x0409
localeId_Russian_Russia := 0x0419
localeId_Ukrainian_Ehnanced := 0x20422

~LControl: {
    global isAltGr := false
    Sleep 100
    if (isAltGr) {
        return
    }

    SetDefaultKeyboard(localeId_English_USA)
}

~RControl: SetDefaultKeyboard(localeId_Russian_Russia)

~RAlt: SetDefaultKeyboard(localeId_Ukrainian_Ehnanced)

~LControl & RAlt: {
    global isAltGr := true
    SetDefaultKeyboard(localeId_Ukrainian_Ehnanced)
}

Gotchas here:

  1. I’ve added links to every WinAPI function and constant for better maintainability. Surprisingly most of WinAPI examples I see on the Internet are written very poorly.
  2. Tilde prefix ~ (https://www.autohotkey.com/docs/v2/Hotkeys.htm)

    When the hotkey fires, its key’s native function will not be blocked (hidden from the system).

  3. Physical Right Alt button in some keyboard layouts (in my case, both Russian and Ukrainian) act as AltGr, which is an equivalent of LControl & RAlt. Therefore it requires special check to distinguish LControl & RAlt (as a physical button of Right Alt) from fair Left Control. As I figured out, it triggers LControl handler first and then LControl & RAlt, that’s why I had to add a global variable isAltGr and a small delay to handle this difference.

Stay tuned!

UPD: After some time, I found the selected shortcuts not so pleasant to use, then I realized, there is a key that I used only a few time in my life: Caps Lock, so I decided to utilize it. Now Caps Lock + 1 – English, Caps Lock + 2 – Russian, Caps Lock + 3 – Ukrainian. It’s a bit unusual to have Caps Lock as a modifier, so it took my muscle memory a bit of time to kick in, but now I am happily using it.

The changes in the script I put before

CapsLock & 1:: SetDefaultKeyboard(localeId_English_USA)
CapsLock & 2:: SetDefaultKeyboard(localeId_Russian_Russia)
CapsLock & 3:: SetDefaultKeyboard(localeId_Ukrainian_Ehnanced)