Перейти на главную страничку сайта (список статей, файлы для скачивания)

ФОРУМ (здесь можно обсудить эту статью, а также саму программу AutoHotkey и проблемы её использования)

Проект перевода документации AutoHotkey: перечень переведённых статей и статей в работе.

AutoHotkey и русский язык – дружба навеки

Автор статьи - Androgen Belkin


Примечание: материал данной статьи основан на релизах AutoHotkey более ранних, чем 1.0.44.03 - May 29, 2006. Более актуальная информация содержится в новом варианте статьи.


AutoHotkey - очень мощный скриптовый язык. Автоматизировать можно всё что угодно (хоть я и не сторонник таких обобщений, в данном случае – это, похоже, правда). Например, один постоянно загруженный скрипт, заменил мне, по крайней мере, пять постоянно загруженных же программ, и облегчил работу с остальными. Даже и не знаю, как я раньше обходился без AutoHotkey. Одно не хорошо: он не очень "дружит" с русским языком. И если вы с этим пока не сталкивались, то неприятные "сюрпризы" вас еще только ждут. Впрочем, всех этих "сюрпризов" можно с легкостью избежать, достаточно только знать, где можно поскользнуться и посыпать это место песочком. Вот таким "пропесочиванием скользкого" мы и займемся в этой статье.

(Часть здесь написанного уже упоминалась на этом форуме, но The gray Cardinal предложил соединить все в одном месте, расширить описание и осветить темные места).

Прежде, чем мы начнем, замечу, что в статье рассматривается обычная для России ситуация, когда в системе установлены два языка: английский и русский. И большинство случаев неправильной работы горячих клавиш, строк автозамены (Hotstrings и Auto-replace) и команд Send, SendRaw, ControlSend, ControlSendRaw связаны именно с этим двуязычием (кривые руки, конечно, не в счет).

Если у вас установлено не два, а больше языков, то просто делайте соответствующие поправки.

Приступим. Главной и единственной теоретической основой этой темы является то, что в Windows есть так называемый "язык ввода по умолчанию". Это язык, который используется при загрузке компьютера. Назначается он в Панели управления > Язык и региональные стандарты > вкладка Языки > кнопка Подробнее… > вкладка Параметры > раздел Язык ввода по умолчанию.

Примечание: в конце статьи есть скрипт для быстрого переключения языка ввода по умолчанию.

Внимание: Язык ввода по умолчанию (или еще говорят "раскладка по умолчанию) - это НЕ текущая раскладка для какого-либо приложения, которую вы переключаете клавишами Alt+Shift (или Ctrl+Shift - это у кого как настроено). Это тот язык (раскладка), с которым запускается Windows, и с которым запускаются (хоть при старте системы, хоть – в любое другое время) все программы, скрипты - все то, что обычно называют "приложения".

Запомним это: ВСЕ ПРИЛОЖЕНИЯ ЗАПУСКАЮТСЯ С ЯЗЫКОМ ПО УМОЛЧАНИЮ.

Я обязательно поясню, что это значит для нас, но сначала…

Горячие клавиши

… напишем и запустим такой крошечный скриптик.

^!z:: ; назначаем горячие клавиши Ctrl+Alt+z
MsgBox, Нажата горячая клавиша. ; показываем сообщение
Return ; конец действий горячей клавиши

Теперь нажмем клавиши Ctrl+Alt+z. Если вы увидели сообщение "Нажата горячая клавиша.", значит в вашей Windows язык ввода по умолчанию – английский. Если это сообщение вы увидели при запуске скрипта, еще до того, как нажали горячие клавиши, значит язык ввода по умолчанию – русский. Иными словами, скрипт не сумел зарегистрировать горячую клавишу и продолжил выполняться так, будто нашей горячей клавиши там и не было. А если бы этим продолжением было не простое сообщение, а что-то более серьезное? У меня, скажем, есть горячая клавиша форсированной перезагрузки, и тогда – конец всему несохраненному?

Отсюда первая проблема.

Если назначаемая вами клавиша может иметь и другую раскладку, то ваш скрипт становится зависимым от раскладки (языка) по умолчанию.

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

Из формулировки проблемы ясно, что она не возникает, если вы назначаете "независимую" клавишу. Например, такое назначение не зависит от раскладки и сработает всегда:

^!F11:: ; назначаем горячие клавиши Ctrl+Alt+F11

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

  1. назначать клавиши и на английском, и её русской "сожительницей" на клавиатуре, или…
  2. назначать горячие клавиши через скан-код. Как определить скан-код клавиши, описано, например, в переведенной Дедом Мазаем статье http://www.script-coding.com/AutoHotkey/KeyList.html, в разделе "Специальные клавиши". Там речь идет о клавишах, отсутствующих в списке стандартных клавиш, но никто не мешает нам поступить, как там написано, и для стандартных клавиш.

В нашем примере, для 1-го варианта, перед первой строкой (или после неё, это не важно), добавьте строку:

^!я:: ; назначаем горячие клавиши Ctrl+Alt+z

А для 2-го варианта вместо первой строки напишите:

^!sc02C:: ; назначаем горячие клавиши Ctrl+Alt+z

Конечно, назначение горячей клавиши через скан-код (sc), гораздо универсальнее. Поэтому именно этот метод я вам и рекомендую.

Примечание: если вы не предполагаете менять язык ввода по умолчанию и не намерены использовать ваши скрипты где-нибудь еще, кроме вашей машины, то, разумеется, можете назначать горячие клавиши только в одной раскладке (для английского языка по умолчанию – на английском, для русского – на русском), но так ли вы уверены, что язык ввода вы никогда не измените, или в том, что не придете со своим скриптом куда-нибудь, где будет другой язык по умолчанию? Может, лучше учесть это сразу?

Идем дальше.

Автозамены (Hotstrings и Auto-replace)

Скан-код – хорошо, однако, с автозаменами этот номер не пройдет. Их придется назначать только по 1-му варианту, т.е. двуязычно.

Хотите – поверьте, хотите – проверьте, но зависимость автозамен от раскладки по умолчанию точно такая же, как и горячих клавиш.

А мы проверим другое. Напишем и запустим такой пример автозамены из справки к AutoHotkey, дополнив его русским текстом:

::btw::by the way. И дополнение на русском. ; назначаем автозамену для английской раскладки
::иец::by the way. И дополнение на русском. ; назначаем автозамену для русской раскладки

Теперь запускаем Блокнот и используем в нем нашу автозамену, напечатав btw (если у вас раскладка по умолчанию – русская, то печататься будет не btw, а иец – русские буквы-соседи на клавиатуре, но мы не обращаем внимание). Жмем enter.

Ура! Что хотели, то и пропечаталось.

А теперь изменим раскладку в Блокноте, нажав Alt+Shift (или что там у вас), и опять печатаем btw, и жмем enter.

Мать моя! Получилась лажа.

Если у вас раскладка по умолчанию русская, то вы увидите: "by the way/ B ljgjkytybt yf heccrjv/".

Т.е. все русские буквы (и даже точка), напечатаны их английскими "сожителями" на клавиатуре.

А если раскладка по умолчанию – английская, то вы увидите: "ин еру цфню И дополнение на русскомю".

Т.е. все английские буквы (и даже точка), напечатаны их русскими "сожителями" на клавиатуре.

Можно даже усмотреть здесь послание разработчиков AutoHotkey русским пользователям: "ин еру цфню" - мол, "на русском будет цфню", но мы изголяться не станем, а лучше разберемся в произошедшем.

А произошло то, о чем мы говорили в начале, и с чем я обещал разобраться. А именно: скрипт был запущен с языком по умолчанию (я просил вас это запомнить), и с этим же языком у нас запустился Блокнот. Поэтому сначала все было ОК, но после того, как мы переключили раскладку для Блокнота, возникло рассогласование раскладок Блокнота и нашего скрипта (для него раскладку мы ведь не переключали).

Отсюда вторая проблема.

Если раскладка скрипта не совпадает с раскладкой того приложения, куда высылается текст, то, скорее всего, текст будет выслан криво.

Это и есть то, о чем написано в FAQ'е, переведенном опять же Дедом Мазаем http://www.script-coding.com/AutoHotkey/FAQ.html, (вопрос "Я использую несколько языковых раскладок на клавиатуре. Почему команда Send и строки автозамены иногда пропечатывают мне не те буквы?").

Решение, предлагаемое там же, в FAQ`е, на мой взгляд, крайне неуклюже.

Тут надо сказать, что Дед Мазай, конечно же, не виноват. Как известно: "Переводчик прозы – раб, переводчик поэзии – соперник". И хотя сам AutoHotkey, безусловно, поэзия, справка к нему все же цинично-англоязычная проза :)

Так вот, предлагается там, обнаружив неверное срабатывание автозамены или команды Send (о ней мы будем говорить позже), удалить-отменить всё, что наделали эти команды (об этом не сказано, но как же иначе?), а дальше либо вызвать горячими клавишами фрагмент скрипта, который откроет своё окно, переключит свою раскладку, закроет своё окно, либо проделать все это "вручную". Мало того, что оба варианта неудобны, так может случиться, что и отменять уже будет поздно. Как говориться: "ОК нажат, к чему теперь рыданья."

Добавлю, что если вы решите попробовать описанный там вариант, автоматически меняющий языковую раскладку для скриптов AutoHotKey, то вам нужно учесть, что клавиши смены раскладки у вас могут отличаться, а главное – уже рассмотренную проблему номер один. Т.е. до переключения раскладки указанным там способом у вас не будет работать какая-то одна из автозамен (в зависимости от раскладки, естественно), а после переключения откажется работать другая, хотя первая – согласится. Поэтому я предлагаю другое…

Решение второй проблемы:

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

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

Поясняю:

::btw::by the way. И дополнение на русском. ; назначаем автозамену для английской раскладки
::иец::by the way. И дополнение на русском. ; назначаем автозамену для русской раскладки

Строки выше – простая автозамена (Auto-replace). А строки ниже – строки автозамены (Hotstrings).

::btw:: ; назначаем автозамену для английской раскладки
::иец:: ; назначаем автозамену для русской раскладки
Send, by the way. И дополнение на русском. ; высылаем текст автозамены
Return ; конец строк автозамены

Примечание: возможно, Hotstrings было бы правильнее перевести как горячие строки (по аналогии с горячими клавишами, как и задумано), ну да как Gourmet перевела http://www.script-coding.com/AutoHotkey/Hotstrings.html, так мы и пишем. За труд ей, конечно, спасибо.

Стало быть, от простых автозамен отказываемся, и вместе со строками автозамены будем использовать команду Send. У этой команды точно такие же сбои, как и у простых автозамен. И сама по себе она дело не поправит, но зато теперь мы можем вставить перед Send что-то такое, что дело поправит. Я написал для этих целей функцию. Вот она:

;*****************************************************************************
; AutoHotkey Version:  1.0.41.01
; Автор:               Androgen Belkin
; Имя скрипта:         Корректировка раскладки скрипта.ahk (v.1.2)
;*****************************************************************************
; Функция корректировки раскладки скрипта для команды Send, SendRaw, и автозамен.
;*****************************************************************************
; создаем функцию изменения раскладки для скрипта на раскладку как в активном окне
PreSend()
{
    ; запоминаем текущий режим определения/нет скрытых окон
    DetectHiddenWindows_Before := A_DetectHiddenWindows
    DetectHiddenWindows, On ; переключаемся на работу со скрытыми окнами
    ; запоминаем текущий режим поиска окон по заголовкам
    TitleMatchMode_Before := A_TitleMatchMode
    ; переключаемся на режим "искать в любой части заголовка окна"
    SetTitleMatchMode, 2
    FormatInteger_Before := A_FormatInteger ; запоминаем текущий числовой формат
    SetFormat, integer, H ; переключаемся на шестнадцатеричный формат
    WinGet, Active_Window_ID, ID, A ; получаем ID активного окна
    Active_Window_Thread := DllCall("GetWindowThreadProcessId"
        , "UInt", Active_Window_ID, "UInt", 0)
    ; получаем для активного окна ID его потока через Win API
    Lang_In_Window := DllCall("GetKeyboardLayout", "UInt", Active_Window_Thread)
    ; получаем текущую раскладку для найденного потока активного окна через Win API
    ; получаем ID окна скрипта
    WinGet, Script_ID, ID, %A_ScriptName% ahk_class AutoHotkey
    ; переключаем раскладку для скрипта на раскладку как в активном окне
    SendMessage, 0x50,, %Lang_In_Window%,, ahk_id %Script_ID%
    ; 0x50 - WM_INPUTLANGCHANGEREQUEST
    ; Об отличиях SendMessage от PostMessage см. ниже отдельное примечание
    ; возвращаем режим определения/нет скрытых окон
    DetectHiddenWindows, %DetectHiddenWindows_Before%
    ; возвращаем режим поиска окон по заголовкам
    SetTitleMatchMode, %TitleMatchMode_Before%
    ; возвращаем числовой формат
    SetFormat, integer, %FormatInteger_Before%
} ; конец функции

Примечание: конечно, можно оформить эту функцию как обычную подпрограмму и просто вставить в наш скрипт. Это тем более верно, что эта функция не возвращает никаких значений. Но я предпочитаю использовать функцию именно как функцию, потому что у меня около 20 разных функций, и вставлять их в каждый скрипт, в котором я намерен ими воспользоваться, конечно, неудобно. Кроме того, представьте: вот написали вы какую-нибудь подпрограмму, вот вставили её в какой-нибудь свой скрипт (один, другой, третий...). А потом как-то раз, оба-на! - отловили глюк этой подпрограммы. Ну, поправили, порадовались. Теперь её надо поправлять везде, куда вы её успели вставить. А если этих скриптов уже под сотню? Вот я наступил на это, и потому - функция. Подключил её директивой #Include и всего делов. Поймал глюк – поправил в одном скрипте, а не в 50-ти, и радуешься жизни дальше.

Итак, мы сохраняем приведенную функцию как отдельный скрипт, а затем в нашем "подопытном" скрипте подключаем ее примерно так (путь, разумеется, указываете свой):

#Include D:\Program_2\AutoHotkey\HScripts\-Проекты\Корректировка раскладки скрипта.ahk

Теперь эту функцию можно использовать, и делается это так:

::btw:: ; назначаем автозамену для английской раскладки
::иец:: ; назначаем автозамену для русской раскладки
PreSend() ; вызываем функцию корректировки раскладки скрипта
Send, by the way. И дополнение на русском. ; высылаем текст автозамены
Return ; конец строк автозамены

И вот теперь вы можете переключать раскладку в целевом приложении (в нашем случае – в Блокноте), как вам заблагорассудится, скрипт будет высылать текст правильно. Ура!

Примечание: команда Send высылает текст чуть медленнее, чем простые автозамены. Если вам это не нравится, вы можете убрать задержку командой SetKeyDelay, -1. Или использовать новый режим высылки "SendMode Input". Для этого просто добавьте в начало вашего скрипта строчку:

SendMode Input ; новый режим высылки без задержки и с повышенной надежностью

Теперь рассмотрим команду Send отдельно от автозамен

Эта команда может использоваться для двух целей–режимов:

  1. для высылки текста, как в предыдущих случаях, и…
  2. для высылки управляющих клавиш.

"Однораскладочные" англичане-американцы используют эту команду одинаково в обоих случаях. Нам же придется сделать упомянутое условное разделение, мы ведь не хотим наступать на "грабли", обходить которые уже научились ранее.

Итак, режим 1-й – высылка текста. Ну, тут все ясно. Я уже говорил, что команда Send "болеет" теми же сбоями, что и простые автозамены, соответственно и "лечится" так же: просто перед ней вызываем рассмотренную функцию корректировки раскладки скрипта и тащимся.

А режим 2-й – еще проще. Если нам нужно выслать управляющие клавиши, то:

Send, ^{sc02E} ; нажать CTRL+С

Ну и т.д.

Я не говорил здесь о команде SendRaw только потому, что она не высылает управляющих клавиш (так и была задумана), поэтому, когда хотим что-то выслать этой командой, то пользуемся ей как для первого режима команды Send.

И, для полноты, так сказать, добавлю, что есть ещё один способ высылать текст командой Send, "не боясь раскладок". Я не нахожу его удобным, но, тем не менее, он есть. Это высылка текста кодами ASCII. Управляющие клавиши "нажать" этим способом не получится, но текст выслать можно. Выглядит это вот так:

Send, {ASC 143}{ASC 224}{ASC 168}{ASC 162}{ASC 165}{ASC 226} {ASC 97}{ASC 98}{ASC 99} ; будет напечатано: Привет abc

Ладно, с этим разобрались, теперь – команда ControlSend (ControlSendRaw)

Плохие новости: команду ControlSend усмирить для работы с "зависимыми" клавишами мне не удалось. Грузить вас разным сочетанием условий, при которых не хотят печататься то английские, то русские буквы, я не буду. Если хотите – поковыряйтесь сами.

Хороших новостей две: первая – независимые клавиши, как всегда, работают нормально, вторая – в большинстве случаев команду ControlSend можно заменить командой Send, с которой мы справились. Удобство команды ControlSend в том, что она позволяет высылать тексты-клавиши контролам (управляющим элементам окна) без активизации окна, которому эти контролы принадлежат. Но почти всегда можно окно безболезненно активизировать, установить фокус на нужный контрол и выслать ему текст Send'ом. Вот, например, так:

WinActivate, ahk_class Notepad; активизировать окно Блокнота
ControlFocus, Edit1, ahk_class Notepad ; ставим фокус на нужный контрол
PreSend() ; вызываем функцию корректировки раскладки скрипта
Send, by the way. И дополнение на русском. ; высылаем текст

А зато теперь, команда – душевный отдых: ControlSetText

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

Она заменяет ВЕСЬ ТЕКСТ контрола на указанный вами. Использовать её можно не только для того, чтобы изменить, например, надпись на кнопке (полезного применения чего я не вижу), а и для того, чтобы заполнять какие-нибудь контролы-поля, или чтобы вставлять какие-нибудь пути к чему-нибудь, например, при автоматизации установки каких-либо программ. Я так "привязался" к этой команде, что, при написании скрипта, всегда ищу, в первую очередь, возможность использовать именно её :)

С проблемными для нашего человека командами AutoHotkey мы разобрались, теперь – факультатив.

Начну с того, что если вы используете какой-нибудь автоматический переключатель раскладок клавиатуры, например, PuntoSwitcher, то проявите осторожность. Хотя обычно проблем не бывает, но учесть не мешало бы. Вот, допустим, захотите вы командой Send выслать английские буквы ghbvth (мало ли зачем, это же я для примера), а PuntoSwitcher распознает их как слово "пример", и обязательно поправит, а это не то, что вам нужно, а скрипт продолжает работу… Это может закончиться нехорошо. Избежать этого можно, либо совсем отключив автокоррекцию раскладки, и корректировать её по горячей клавише, либо назначить в PuntoSwitcher'е горячие клавиши на отключение автокоррекции, и перед "сомнительными" командами нажимать их скриптом (отключив автокоррекцию), а потом опять нажимать (включив автокоррекцию). Например, так:

Send, ^!+= ; нажимаем Ctrl + Alt + Shift + =, для отключения автокоррекции PuntoSwitcher'а
Send, AutoHotkey, ghbvth ; наш странный текст
Send, ^!+= ; нажимаем Ctrl + Alt + Shift + =, для включения автокоррекции PuntoSwitcher'а

Кстати, у PuntoSwitcher'а конвертация неправильно введенных символов жестко прошита на клавишу Break, а в силу особенностей моей клавы и её расположения, мне нажимать Break неудобно. Я написал скрипт, который переназначает конвертацию на двойное нажатие (как двойной клик) клавиши Ctrl:

~Control:: ; Control (ДВОЙНОЕ нажатие) - конвертировать введенные символы в punto switcher
if (A_PriorHotkey <> "~Control" or A_TimeSincePriorHotkey > 300)
; если предыдущая клавиша - не Control,
; или со времени нажатия Control прошло больше 300 миллисекунд, то...
{
    KeyWait, Control
    ;ожидать, пока клавиша не будет отпущена
    ;(чтобы исключить срабатывание от простого удержания нажатой клавиши)
    Return ; закончить обработку горячей клавиши после отжатия клавиши
}
; а вот если предыдущая клавиша - Control,
; и со времени нажатия Control прошло НЕ больше 300 миллисекунд, то...
KeyWait, Control 
; ожидать пока клавиша не будет отпущена
; (чтобы исключить срабатывание от клавиши CTRL + исправляемые punto switcher`ом буквы)
Send, {Break} ; переключить раскладку
Return ; закончить обработку горячей клавиши

Теперь рассмотрим пару примеров, когда нам скриптом нужно изменить раскладку окна. Вот так активное окно - в английскую раскладку:

SendMessage, 0x50,, 0x4090409,, A ; переключаем в английскую раскладку активное окно

Примечание: отличие команды SendMessage от PostMessage в том, что SendMessage ожидает ответа от того окна, которому высылается сообщение. Ожидание длится 5 секунд. За это время целевое окно обычно успевает обработать посланную команду и сообщить свой ответ. Содержание ответа (во многих случаях) не имеет значения. Важно то, что наш скрипт не продолжится, пока не получит этот ответ (ну, или пока не истекут 5 секунд). А PostMessage не ждет ничего. Поэтому там, где в результате высылки сообщений не возникают диалоговые окна, я рекомендую использовать SendMessage, а не PostMessage. Смена раскладки - как раз такой случай (если, конечно, вы не являетесь обладателем уникальной программы, выбрасывающей диалоговое окно с сообщением "Мне изменили раскладку. Продолжить?").

А в следующем примере - конкретное окно, а хоть бы и Блокнота (будто бы его кто-то использует), переключим в русскую раскладку. Ну, допустим, мы хотим скриптом же, вызвать меню Файл. Мы, конечно, можем Блокноту выслать Alt + Ф, но если он сейчас в английской раскладке, то высланное не словит. Сначала его нужно переключить в русскую раскладку. Поступим так (Блокнот, естественно, должен быть запущен):

WinActivate, ahk_class Notepad ; активируем окно Блокнота
SendMessage, 0x50,, 0x4190419,, ahk_class Notepad ; переключаем в русскую раскладку Блокнот
PreSend() ; вызываем функцию корректировки раскладки скрипта
;(т.е. теперь и скрипт переключаем в русскую раскладку)
Send, !ф ; нажимаем Alt + Ф (вызвать меню Файл)

Пример выше – только для иллюстрации. Вызывать пункты всяческих меню "Файл", "Правка" и т.д. (на любом языке), лучше командой WinMenuSelectItem. И причина, по которой я об этом рассказываю здесь, такая: если у проги, в которой вы хотите вызвать пункты меню, есть многоязычный интерфейс, то, чтобы быть уверенным, что переключившись в другой язык (не раскладку, а интерфейс программы), вы все равно сможете вызвать нужный вам пункт меню, нужно использовать не имена пунктов меню, а их номера.

WinMenuSelectItem, ahk_class Notepad,, Справка, О программе
; вызвать в Блокноте меню о программе, используя имена пунктов
WinMenuSelectItem, ahk_class Notepad,, 5&, 3&
; вызвать в Блокноте меню о программе, используя номера пунктов

Хотя пункт "О программе" выглядит вторым в меню, но в меню "Справка" есть разделитель, а он тоже считается за пункт меню, поэтому "О программе" - третий пункт меню.

Замечу, что команда WinMenuSelectItem работает не со всеми окнами, и тогда можно попробовать использовать вызов меню так, как мы делали это для Блокнота двумя абзацами выше. А если и это не поможет, тогда, увы, - мышкой (скриптовой, конечно).

А что, если мы хотим, чтобы какое-либо окно автоматически переключалось в нужную раскладку? Например, у меня раскладка по умолчанию – русская, поэтому Total Commander запускается в русской раскладке. Меня это устраивает, но я часто пользуюсь быстрым поиском в ТС, и окошко быстрого поиска открывается тоже, разумеется, в русской раскладке, а вот это меня не устраивает (обычно я ищу по английским буквам). Можно, конечно, переключить раскладку и "вручную", но ведь есть AutoHotkey! Вот и попросим его. Создаем таймер, по которому будут выполняться всяческие автоматизации окон, и вписываем его где-нибудь в автовыполняющуюся секцию скрипта.

#Persistent ; скрипт будет запущен постоянно
;(если после автовыполняющейся секции у вас есть горячие клавиши или автозамены,
;то эта директива - лишняя)
SetTimer, Auto_Window, 200 ; переходить к указанной подпрограмме через каждые 0.2 секунды
Return ; закончить автовыполняющуюся часть

А теперь сама подпрограмма автоматизации окон.

Auto_Window:
;метка входа таймера автоматизации окон (эту подпрограмму можно размещать
;в любом месте скрипта, мне удобно размещать подпрограммы в конце, но это не обязательно)

; TOTAL COMMANDER: ПЕРЕКЛЮЧИТЬ РАСКЛАДКУ В БЫСТРОМ ПОИСКЕ
IfWinActive, ahk_class TQUICKSEARCH ; если активно окно Быстрого поиска в ТС, то...
{
    if Win_QS = ; если окно только что активизировалось, то...
    {
        SendMessage, 0x50,, 0x4090409,, ahk_class TQUICKSEARCH
        ; переключить раскладку на английскую в окне Быстрого поиска
        Win_QS = 1 ; выставить указатель, что окно уже активно
    }
}
Else ; если окно НЕ активно, то...
    Win_QS = ; выставить указатель, что окно НЕ активно

; TOTAL COMMANDER: ЗАКРЫТИЕ ОКНА "ДИСК НЕ НАЙДЕН"
IfWinExist, ahk_class TDRIVEDLG ; если существует окно "Диск не найден" в Тотале, то...
WinClose, ahk_class TDRIVEDLG ; закрыть окно "Диск не найден"

Return ; конец подпрограммы по таймеру

Как, надеюсь, понятно – скрипт проверяет, активизировалось окно Быстрого поиска только что, или оно уже тут давно (давнее, чем прошел предыдущий цикл по таймеру). Это нужно для того, что если я захочу поискать в этом окне на русском, то я переключу раскладку "руками" и скрипт мне не будет мешать. Само собой, что так можно поступать с любыми окнами.

Я для примера, добавил ещё одну автоматизацию - закрытие окна "Диск не найден" в Тотале. Оно возникает, когда кликаешь, например по сидюку, а его там нет. Тогда Тотал и говорит, что, мол, не могу найти диск, выберите другой. Нефига мне смотреть на это окно.

А вот еще на тему русского языка (не совсем про AutoHotkey, но может кому-то будет полезно). Иногда, при копировании в буфер из некоторых англоязычных (хоть, иногда, и русифицированных) программ, и последующей вставки куда-нибудь, вдруг оказывается что вставляемый текст весь в вопросах или кракозябрах. Если у вас так бывает, то скопируйте текст ниже, вставьте его в блокнот, и сохраните с любым именем и расширением reg. Получится файл реестра, который нужно запустить-подтвердить, и перезагрузиться. Помогает решить проблему с кракозябрами в 99,8 % случаев.

REGEDIT4
; Файл реестра для исправления возможных проблем с отображением русских шрифтов в Windows 2k/XP/2k3

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CodePage]
"1250"="c_1251.nls"
"1251"="c_1251.nls"
"1252"="c_1251.nls"
"1253"="c_1251.nls"
"1254"="c_1251.nls"
"1255"="c_1251.nls"

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontMapper]
"ARIAL"=dword:000000cc

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes]
"Arial,0"="Arial,204"
"Comic Sans MS,0"="Comic Sans MS,204"
"Courier,0"="Courier New,204"
"Courier,204"="Courier New,204"
"MS Sans Serif,0"="MS Sans Serif,204"
"Tahoma,0"="Tahoma,204"
"Times New Roman,0"="Times New Roman,204"
"Verdana,0"="Verdana,204"

Обратите внимание, что если у вас 9x, Me или NT4, то вам нужен другой файл, вот он:

REGEDIT4
; Файл реестра для исправления возможных проблем с отображением русских шрифтов в Windows 9x/Me/NT4
; Может также потребоваться добавить в файл Win.ini следующие строки (не забудьте убрать точки с запятой):
;
; [FontSubstitutes] 
; Arial,0=Arial,204
; Comic Sans MS,0=Comic Sans MS,204
; Courier,0=Courier New,204
; Microsoft Sans Serif,0=Microsoft Sans Serif,204
; Tahoma,0=Tahoma,204
; Times New Roman,0=Times New Roman,204
; Verdana,0=Verdana,204

[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Nls\Codepage]
"1250"="cp_1251.nls"
"1251"="cp_1251.nls"
"1252"="cp_1251.nls"
"1253"="cp_1251.nls"
"1254"="cp_1251.nls"
"1255"="cp_1251.nls"

Ну и напоследок пара скриптиков для русско-английских пользователей (для нас то есть).

Сначала скрипт для облегчения переводческой работы (например, для тех, кто самоотверженно переводит справку AutoHotkey).

;*****************************************************************************
; AutoHotkey Version:  1.0.33.0
; Автор:               Androgen
; Имя скрипта:         Перевести в PromtX.ahk (v.1.1)
;*****************************************************************************
; Перевести в PromtX или в X-Translator PLATINUM
;*****************************************************************************
; Пользуемся так: выделяем что-то, что хотим перевести,
; нажимаем горячие клавиши вызова скрипта, и - получаем перевод.
; Горячие клавиши можно назначить на скрипт обычными средствами Windows,
; а можно - вставить содержимое этого скрипта
; в скрипт, запущенный у вас постоянно (если таковой имеется), и назначить их в нем.
; ПРИМЕЧАНИЕ: PromtX может автоматически переводить изменившийся буфер обмена,
; но мне вовсе не нужно, чтобы его окно
; выскакивало всякий раз, когда я что-нибудь скопирую в буфер.
; Кроме того, для этой его фишки нужно, чтобы он был уже запущен, а для этого скрипта - это не обязательно.
; И PromtX не чистит форматирование скопированного текста (см. комментарии ниже)

; ========== НАСТРОЙКИ ПОЛЬЗОВАТЕЛЯ ==========
PrmtX_Path = %A_ProgramFiles%\X-Translator PLATINUM\XTRAPL\PrmtXP.exe ; укажите здесь путь к PromtX
;~ PrmtX_Path = %A_ProgramFiles%\PRMT6\PRMTX\PrmtX.exe ; укажите здесь путь к PromtX
PrmtX_Window =  - X-Translator PLATINUM ; фрагмент имени окна PromtX
;~ PrmtX_Window =  - PromtX ; фрагмент имени окна PromtX
; ========== КОНЕЦ НАСТРОЕК ПОЛЬЗОВАТЕЛЯ ==========

IfNotExist, %PrmtX_Path% ; проверяем правильность пути к PromtX
{
    MsgBox, Неверно указан путь: "%PrmtX_Path%". ; показать сообщение
    ExitApp ; закончить скрипт
}

Translate_String = Чтобы прервать
;фрагмент текста строки состояния "Чтобы прервать процесс перевода, нажмите ESC."
SetTitleMatchMode, 2 ; сравнивать с любой частью заголовка окна
DetectHiddenWindows, On ; искать в скрытых окнах, чтобы "поднимать" свернутый в трей PromtX
Menu, Tray, Icon, %PrmtX_Path%, 1 ; установить иконку скрипта в трее как у PromtX
Clipboard = ; очищаем буфер
Loop ; скопировать выделенное в буфер (в цикле, если одного раза будет почему-то недостаточно)
{
    Send, ^{sc02E} ; нажать CTRL + С (копировать в буфер)
    ClipWait, 1 ; подождать появления содержимого в буфере максимум 1 секунды
    if ErrorLevel = 0 ; если ДОЖДАЛИСЬ содержимого в буфере, то...
        Break ; закончить цикл
    ; если содержимого в буфере не дождались, то продолжаем
    if A_Index = 3 ; если цикл уже выполнился 3 раза, то...
    {
        MsgBox, Не удается скопировать текст в буфер обмена. ; показать сообщение
        ExitApp ; закончить скрипт
    }
}

; Если текст скопирован из, например, справки или браузера, то он, вероятно,
; содержит форматирование, и тогда
; скопированный текст, и перевод, будут начинаться примерно так:
; ОбычныйТерминСписокопределенийАдресЦитатыФорматированный
; Избавляемся от форматирования следующей командой:
Clipboard = %Clipboard% ; преобразуем форматированный текст в гладкий
IfWinNotExist, %PrmtX_Window% ; если окно PromtX`а НЕ существует, то...
        Run, %PrmtX_Path% ; запустить PromtX
WinWait, %PrmtX_Window%,, 5 ; ожидать появления окна PromtX не более 5 секунд
if ErrorLevel <> 0 ; если так и не дождались окна, то...
{
    MsgBox, Не дождались окна %PrmtX_Window%
        ExitApp ; конец скрипта
}
WinActivate, %PrmtX_Window% ; активизировать окно
WinWaitActive, %PrmtX_Window% ; пождать активизации окна
Loop ; в цикле ожидается начало перевода в окне PromtX
{
        ControlSend,, {F11}, %PrmtX_Window% ; нажать "перевести содержимое буфера обмена"
        ; (используется ControlSend, а не Send,
        ; чтобы гарантировать нажатие клавиши именно для окна PromtX)
        StatusBarGetText, StatusBar_Text, 1, %PrmtX_Window%
        ; получить текст строки состояния (сама строка сост. может быть и скрытой)
        IfInString, StatusBar_Text , %Translate_String% ; если перевод начался, то...
            Break ; закончить цикл
}
ExitApp ; конец скрипта

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

;*****************************************************************************
; AutoHotkey Version:  1.0.41.01
; Автор:               Androgen
; Имя скрипта:         Переключить язык по умолчанию.ahk (v.1.3)
;*****************************************************************************
; Проверить и, если нужно - переключить, язык ввода по умолчанию (тот, что при загрузке Windows).
;*****************************************************************************

; ========== НАСТРОЙКИ ПОЛЬЗОВАТЕЛЯ ==========
Name_Lang_Serv_Win = Языки и службы текстового ввода
; как у вас называется это окно (я встречал и другие названия)
; ========== КОНЕЦ НАСТРОЕК ПОЛЬЗОВАТЕЛЯ ==========

#NoTrayIcon ; не показывать иконку скрипта в трее
RegRead, Load_Lang, HKEY_CURRENT_USER, Keyboard Layout\Preload, 1
; прочитать, какая раскладка по умолчанию
if Load_Lang = 00000419 ; если русская, то...
{
        MsgBox, 1, Внимание., Текущий язык ввода по умолчанию - русский.`n`nИзменить на АНГЛИЙСКИЙ ?
        ; оформляем сообщение
    IfMsgBox, OK ; если "OK", то...
        Key_Action = {Up} ; эта клавиша будет высылаться контролу
        ; для смены раскладки на английскую (если нужно - поправьте)
    else ; если кнопка подтверждения не нажата, то...
        Exit ; завершить скрипт
}
if Load_Lang = 00000409 ; если английская, то...
{
        MsgBox, 1, Внимание., Текущий язык ввода по умолчанию - английский.`n`nИзменить на РУССКИЙ ?
        ; оформляем сообщение
    IfMsgBox, OK ; если "OK", то...
        Key_Action = {Down} ; эта клавиша будет высылаться контролу
        ; для смены раскладки на русскую (если нужно - поправьте)
    else ; если кнопка подтверждения не нажата, то...
        Exit ; завершить скрипт
}
if (Load_Lang <> 00000419 AND Load_Lang <> 00000409)
; если раскладки по умолчанию не русская и не английская, то...
{
        MsgBox, 0, Внимание!, %A_Space%Текущий язык НЕ АНГЛИЙСКИЙ и НЕ РУССКИЙ.`n`n
        , Скрипт рассчитан на работу с этими раскладками.`n`n
        , Измените настройки скрипта. ; оформляем сообщение
        Exit ; завершить скрипт
}

Run, RunDll32.exe shell32.dll`,Control_RunDLL input.dll
; запустить апплет "Языки и службы текстового ввода"
WinWait, %Name_Lang_Serv_Win%,, 5
; подождать окно "Языки и службы текстового ввода" не более 5 секунд
If ErrorLevel <> 0 ; если окна так и не дождались, то...
{
    MsgBox, Не дождались окна: "%Name_Lang_Serv_Win%"`n`n
    , Проверьте в скрипте "НАСТРОЙКИ ПОЛЬЗОВАТЕЛЯ" ; оформляем сообщение
        Exit ; завершить скрипт
}
; если окно появилось, то...
ControlSend, ComboBox1, %Key_Action%, %Name_Lang_Serv_Win% ; выбрать язык
Sleep, 100 ; пауза для надежности переключения раскладки
;~ pause ; для проверки переключения раскладки, раскомментируйте эту строку,
; а директиву #NoTrayIcon (в начале скрипта) - закомментируйте
metka0: ; метка для повторного клика, если понадобится
ControlClick, Button10 ; кликнуть "OK"
if ErrorLevel <> 0 ; если контрол не был готов (а такое случается), то...
    goto, metka0 ; повторить клик
Exit ; завершить скрипт

Здесь я вынужден с вами попрощаться. Я старался быть кратким, поэтому "за бортом" осталось множество нюансов. Однако, главные проблемы AutoHotkey и русского языка мы рассмотрели. Надеюсь, что что-то из написанного окажется вам полезным. И надеюсь, что когда-нибудь, разработчики AutoHotkey учтут, что их замечательным продуктом пользуются не только "однораскладочники". И тогда нам не придется прибегать ко всем тем ухищрениям, прибегать к которым мы пока вынуждены.

Удачи вам!

Перейти на главную страничку сайта (список статей, файлы для скачивания)

© 2007 http://www.script-coding.com При любом использовании материалов сайта обязательна ссылка на него как на источник информации, а также сохранение целостности и авторства материалов.