НейроАгент

Исправление AHK-скрипта для переключения раскладки Windows

Решение проблемы с AHK-скриптом переключения раскладки клавиатуры, который не работает в системных окнах Windows. Узнайте, как исправить скрипт с помощью DllCall и WinAPI вызовов.

Вопрос

Как исправить AHK-скрипт для переключения раскладки клавиатуры в системных окнах Windows?

Я использую Windows 10 и впервые работаю с AutoHotkey. Я создал скрипт для переключения раскладки клавиатуры: русский язык на правый Ctrl и английский на левый Ctrl. Вот мой скрипт:

autohotkey
~LCtrl up::
    If (A_PriorKey = "LControl") {
        SendMessage, 0x50,, 0x4090409,, A ; английский
    }
    
~RCtrl up::
    If (A_PriorKey = "RControl") {
        SendMessage, 0x50,, 0x4190419,, A ; русский
    }

Скрипт работает корректно в обычных окнах, но не срабатывает в системных окнах Windows, например, в стандартном диалоговом окне сохранения файла.

В чем заключается ошибка в моем скрипте и как ее исправить?

Примечание: Я знаю, что PuntoSwitcher решает эту задачу, но я не хочу использовать эту программу.

Дополнительно: Я хочу оставить в системе единственный способ переключения языков через этот скрипт, без добавления дополнительных комбинаций клавиш в системных настройках и без эмуляции их нажатий.

НейроАгент

Проблема с вашим AHK-скриптом заключается в том, что системные окна Windows (такие как диалоги сохранения файлов) имеют особый механизм обработки ввода и не всегда реагируют на стандартные сообщения AutoHotkey. В системных окнах часто требуется прямой вызов системных API через DllCall вместо использования SendMessage.

Содержание

Основная причина проблемы

Системные окна Windows используют собственный механизм обработки ввода, который игнорирует стандартные сообщения AutoHotkey. Ваш метод SendMessage, 0x50 работает в обычных приложениях, но не в системных диалогах, потому что:

  • Системные окна имеют ограниченный доступ к внешним сообщениям
  • Они используют собственный обработчик ввода
  • Требуются более низкоуровневые вызовы API Windows

Решение 1: Использование DllCall с LoadKeyboardLayout

Наиболее надежный метод - прямой вызов системных функций через DllCall:

autohotkey
~LCtrl up::
    If (A_PriorKey = "LControl") {
        SetKeyboardLayout(0x0409) ; английский (US)
    }
    return

~RCtrl up::
    If (A_PriorKey = "RControl") {
        SetKeyboardLayout(0x0419) ; русский
    }
    return

SetKeyboardLayout(LocaleID) {
    ; Загружаем раскладку клавиатуры
    hKL := DllCall("LoadKeyboardLayout", "Str", Format("{:08X}", LocaleID), "UInt", 0x00000001)
    
    ; Устанавливаем раскладку для текущего потока
    DllCall("ActivateKeyboardLayout", "UInt", hKL, "UInt", 0x00000000)
    
    ; Обновляем системные параметры
    VarSetCapacity(LAN, 8, 0)
    NumPut(LocaleID, LAN, 0, "UInt")
    NumPut(LocaleID, LAN, 4, "UInt")
    DllCall("SystemParametersInfo", "UInt", 0x005A, "UInt", 0, "Ptr", &LAN, "UInt", 0x0002)
}

Этот метод работает в большинства системных окон, так как использует прямой вызов системных функций Windows.

Решение 2: Полная замена системных горячих клавиш

Чтобы полностью заменить системные горячие клавиши, необходимо:

  1. Отключить стандартное переключение в настройках Windows
  2. Создать собственный обработчик, который будет работать везде
autohotkey
; Полная замена системных горячих клавиш
#NoEnv
#SingleInstance Force
SetBatchLines, -1

; Отключаем стандартное переключение (запускать от имени администратора)
OnExit, ExitSub
ExitSub:
    DllCall("SystemParametersInfo", "UInt", 0x005A, "UInt", 0, "Ptr", &OldLAN, "UInt", 0x0002)
    ExitApp

; Сохраняем текущие настройки
VarSetCapacity(OldLAN, 8, 0)
DllCall("SystemParametersInfo", "UInt", 0x005A, "UInt", 0, "Ptr", &OldLAN, "UInt", 0x0002)

; Горячие клавиши для переключения
~LCtrl up::
    If (A_PriorKey = "LControl") {
        SetKeyboardLayout(0x0409) ; английский
    }
    return

~RCtrl up::
    If (A_PriorKey = "RControl") {
        SetKeyboardLayout(0x0419) ; русский
    }
    return

Решение 3: Запуск скрипта от имени администратора

Некоторые системные окна требуют повышенных привилегий:

  1. Создайте ярлык для вашего скрипта
  2. Откройте свойства ярлыка
  3. Перейдите на вкладку “Совместимость”
  4. Установите галочку “Выполнить программу от имени администратора”
  5. Примените изменения

Полный рабочий скрипт

autohotkey
#NoEnv
#SingleInstance Force
SetBatchLines, -1

; Устанавливаем скрипт для работы со всеми окнами
#InstallKeybdHook
#UseHook On

; Функция установки раскладки клавиатуры
SetKeyboardLayout(LocaleID) {
    try {
        ; Пробуем сначала через ActivateKeyboardLayout
        hKL := DllCall("LoadKeyboardLayout", "Str", Format("{:08X}", LocaleID), "UInt", 0x00000001)
        DllCall("ActivateKeyboardLayout", "UInt", hKL, "UInt", 0x00000000)
        
        ; Обновляем системные параметры
        VarSetCapacity(LAN, 8, 0)
        NumPut(LocaleID, LAN, 0, "UInt")
        NumPut(LocaleID, LAN, 4, "UInt")
        DllCall("SystemParametersInfo", "UInt", 0x005A, "UInt", 0, "Ptr", &LAN, "UInt", 0x0002)
        
        ; Дополнительная попытка для stubborn окон
        PostMessage, 0x50, 0, % (LocaleID << 16) | LocaleID, , A
    }
    return
}

; Горячие клавиши
~LCtrl up::
    If (A_PriorKey = "LControl") {
        SetKeyboardLayout(0x0409) ; английский (US)
        ToolTip, English Layout, 1000
    }
    return

~RCtrl up::
    If (A_PriorKey = "RControl") {
        SetKeyboardLayout(0x0419) ; русский
        ToolTip, Русская раскладка, 1000
    }
    return

; Убираем подсказку через 1 секунду
SetTimer, RemoveToolTip, -1000
RemoveToolTip:
    ToolTip
    return

Настройка системы для единственного способа переключения

Чтобы оставить в системе только ваш способ переключения:

  1. Откройте Параметры → Время и язык → Язык
  2. Нажмите на Языковые параметры
  3. В разделе Сочетания клавиш для языков ввода нажмите Сочетания клавиш для языков ввода
  4. В окне Текст服务和输入语言 выберите вкладку Переключение языков ввода
  5. Установите Нет для “Переключать язык ввода”
  6. Примените изменения и перезагрузите компьютер

Рекомендации по устранению неполадок

Если скрипт все еще не работает:

  1. Проверьте коды языков: Убедитесь, что 0x0409 и 0x0419 соответствуют вашим языкам
  2. Добавьте отладочную информацию:
    autohotkey
    ~LCtrl up::
        If (A_PriorKey = "LControl") {
            MsgBox, Переключение на английский
            SetKeyboardLayout(0x0409)
        }
        return
    
  3. Используйте альтернативные коды языков:
    • Английский: 0x0409 (US), 0x0809 (UK)
    • Русский: 0x0419, 0x0422 (Украина)
  4. Попробуйте использовать WinAPI напрямую:
    autohotkey
    SetKeyboardLayout(LocaleID) {
        static hKL := {}
        if !hKL.HasKey(LocaleID) {
            hKL[LocaleID] := DllCall("LoadKeyboardLayout", "Str", Format("{:08X}", LocaleID), "UInt", 1)
        }
        return DllCall("ActivateKeyboardLayout", "UInt", hKL[LocaleID], "UInt", 0)
    }
    

Важно: Некоторые системные окна могут требовать перезапуска после изменения настроек языка. Также убедитесь, что ваш скрипт запущен от имени администратора для максимальной совместимости.

Источники

  1. AutoHotkey Community - Switch keyboard layout
  2. AutoHotkey Community - How to change keyboard language layout
  3. Stack Overflow - AutoHotkey: Disable Ctrl+Shift
  4. Super User - Setting different keys for switching between keyboard layouts
  5. AutoHotkey Community - Keyboard layout switcher for many layouts

Заключение

Основные проблемы с переключением раскладки в системных окнах Windows решаются использованием прямых вызовов WinAPI через DllCall вместо стандартных сообщений AutoHotkey. Ключевые моменты:

  • Используйте DllCall("LoadKeyboardLayout") и DllCall("ActivateKeyboardLayout") для надежной работы
  • Запускайте скрипт от имени администратора для доступа ко всем системным окнам
  • Отключите стандартные сочетания клавиш в настройках Windows
  • Для максимальной совместимости используйте комбинацию разных методов

Представленный скрипт должен работать во всех типах окон, включая системные диалоги, и позволит вам оставить единственный способ переключения языков без использования внешних программ.