программирование :: разное

И еще раз о раскладке

Подготавливая статью о раскладке клавиатуры (смотрите КГ N№47 за 1999 год, статья "Раскладка клавиатуры. Даешь сервис!"), никак не мог предположить я, что она вызовет такую бурную дискуссию. Но что сделано, то сделано, и более того, это даже к лучшему. Хочу еще раз вернуться к этой теме. Понимаю, что статья эта значительно запоздала, но, поверьте, это от меня не зависело.

Сначала хочу объяснить то, что вызвало наиболее сильное непонимание читателей - обработка спецсимволов. Вот этот кусок кода:
...
AlphSC$ = "<>{}:'"
ReDim NumSC__(6)
NumSC__(1) = 31
NumSC__(2) = 32
NumSC__(3) = 11
NumSC__(4) = 12
NumSC__(5) = 22
NumSC__(6) = 23
...
For i = 1 To Len(StrZam$)
TecChar$ = Mid(StrZam$, i, 1)
...
NumTecCharSC = InStr(AlphSC$, TecChar$)
If NumTecCharSC <> 0 Then
NumTecCharUp = NumSC__(NumTecCharSC)
NumTecCharDwn = NumSC__(NumTecCharSC)
...
Дорогие мои, все это писалось для того, чтобы корректно обрабатывать не только обычный текст, но и текст, набранный при включенном "Caps Lock", так как раскладка при нажатом "Shift" и при включенном "Caps Lock" все-таки различна. Другое дело, что реализовано это было довольно коряво. Да и, если честно, писался мною этот код, когда я только начинал осваивать Visual Basic. Но, в любом случае спасибо за критику, именно она подвигла меня переписать этот злополучный макрос.
Проанализировав все отклики читателей, решил я объединить все плюсы их предложений, а заодно и добавить (в свете увеличения моих познаний по программированию в Visual Basic) новые возможности. Теперь макрос отслеживает, не нажата ли клавиша "Caps Lock", и если нажата, то совершает перекодировку с учетом этого фактора. После перекодировки макрос также автоматически переключает раскладку клавиатуры. Итак, вот вам универсальный макрос, естественно, с комментариями:

'Объявляем константы для автоматического переключения клавиатуры.
Public Const LANG_RUSSIAN = &H19
Public Const LANG_ENGLISH = &H9
Public Const HKL_PREV = 0
Public Const HKL_NEXT = 1

'Декларируем функции Windows API для переключения клавиатуры.
Declare Function ActivateKeyboardLayout Lib "user32" (ByVal HKL As Long, ByVal flags As Long) As Long
Declare Function GetKeyboardLayout Lib "user32" (ByVal dwLayout As Long) As Byte

'Определяем функцию автоматического переключения раскладки клавиатуры.
Function SetLangKeyb(ByVal btLang As Byte)
Result = GetKeyboardLayout(0)
While Result <> btLang
Result = ActivateKeyboardLayout(HKL_PREV, 0)
Result = GetKeyboardLayout(0)
Wend
End Function

'Определяем функцию перекодировки.
'Переменной btLang определяется результирующая кодировка
'btLang=1 Русский
'btLang=0 Английский
Function ChangeKbrdLayout(ByVal btLang As Byte)

'Определяем действия в случае возникновения ошибки
On Error Resume Next

'Проверяем, если выделение не определено, заканчиваем выполнение функции.
If WordBasic.GetSelStartPos() = WordBasic.GetSelEndPos() Then Exit Function

'Объявляем переменные-списки соответствия перекодируемых символов.
' AlphEng$ — для английской кодировки
' AlphRus$ — для русской кодировки
' AlphEngCL$ — для английской кодировки с включенным "Caps Lock"
AlphEng$ = "QWERTYUIOP{}ASDFGHJKL:""ZXCVBNM<>?/ qwertyuiop[]asdfghjkl;'zxcvbnm,.@#$^&~`"
AlphRus$ = "ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮ,.йцукенгшщзхъфывапролджэячсмитьбю""№;:?Ее"
AlphEngCL$ = "QWERTYUIOP[]ASDFGHJKL;'ZXCVBNM,.?/ qwertyuiop{}asdfghjkl:""zxcvbnm<>@#$^&`~"

' Присваиваем переменной StrZam$-выделенный фрагмент текста
StrZam$ = Selection.Text

' Если последний символ — символ абзаца, отбрасываем его, т.к. при вставке результата Word сам добавляет этот символ.
If Asc(Right(StrZam, 1)) = 13 Then StrZam$ = Left(StrZam$, Len(StrZam$) — 1)
StrRez$ = ""

' Запускаем цикл по всем символам
For i = 1 To Len(StrZam$)
TecChar$ = Mid(StrZam$, i, 1)

'Выбираем способ обработки в зависимости от выбранного направления перекодировки.
Select Case btLang
Case 0
NumTecChar = InStr(AlphRus$, TecChar$)
If NumTecChar <> 0 Then
If Application.CapsLock Then
TecChar$ = Mid(AlphEngCL$, NumTecChar, 1)
Else
TecChar$ = Mid(AlphEng$, NumTecChar, 1)
End If
End If
Case 1
If Application.CapsLock Then
NumTecChar = InStr(AlphEngCL$, TecChar$)
Else
NumTecChar = InStr(AlphEng$, TecChar$)
End If
If NumTecChar <> 0 Then
TecChar$ = Mid(AlphRus$, NumTecChar, 1)
End If
End Select

'Составляем результирующую строку.
StrRez$ = StrRez$ + TecChar$

' Заканчиваем цикл
Next i

'В зависимости от выбранного направления перекодировки выбираем язык проверки орфографии и раскладки клавиатуры. И переключаем в соответствии с выбором.
Select Case btLang
Case 0
Selection.LanguageID = wdEnglishAUS
SetLangKeyb (LANG_ENGLISH)
Case 1
Selection.LanguageID = wdRussian
SetLangKeyb (LANG_RUSSIAN)
End Select

'Вставляем результирующую строку на место исходной.
WordBasic.Insert StrRez$
End Function

'Описываем макрос вызова функции с направлением перекодировки Lat->Рус
Public Sub Кириллица()
ChangeKbrdLayout (1)
End Sub

'Описываем макрос вызова функции с направлением перекодировки Рус->Lat
Public Sub Латиница()
ChangeKbrdLayout (0)
End Sub

Теперь, как видите, имеем два макроса из, практически, одной рабочей функции. Причем общий объем где-то 65 строк, против 75-ти в старом макросе. Хочу сделать маленькое замечание. Если у вас установлено в Windows всего две раскладки клавиатуры, то описание функции SetLangKeyb и описание констант LANG_RUSSIAN и LANG_ENGLISH можете смело удалить, а в тексте функции ChangeKbrdLayout вместо вызова SetLangKeyb вставьте строку:

Result = ActivateKeyboardLayout(HKL_NEXT, 0)
Эта функция Windows API выбирает следующий язык из списка установленных языков. Таким образом, если у вас установлено только два языка — Русский и Английский, то функция будет по очереди переключать их. Но если вы после этого установите еще какой-нибудь язык, например белорусский, то тут вам придется вернуться к изначальному варианту кода. Поэтому советую сохранить его где-нибудь, так, на всякий случай.

Иконки для макросов предлагаю следующие:
Z>Я — для направления Lat -> Рус
Z<Я — для направления Рус -> Lat

Можно, наконец, назначить этим макросам горячие клавиши. Для этого в окошке "Настройка", выпадающем после выбора в меню "Сервис\Настройка...", жмем кнопку "Клавиатура..." (она находится внизу, рядом с кнопкой "Закрыть"). Выпадет еще одно окно с тем же названием, но другим содержанием. В поле "Категории:" выбираем "Макросы". В поле "Макросы:" выбираем макрос, которому хотим назначить горячие клавиши. Переходим в поле "Новое сочетание клавиш:" и жмем те клавиши, по нажатию которых должен будет вызываться макрос. Сочетание нажатых клавиш тут же появляется на экране. Если сочетание уже "занято" каким-либо действием, об этом тут же будет сообщено, и вам придется либо выбрать другое сочетание, либо освободить данное. После выбора свободного сочетания жмем кнопку "Назначить". Все, готово, теперь закрываем окна настройки и пользуемся в удовольствие.
Кстати, хочу порадовать любителей всего нового. В Microsoft Office 2000 (русская локализация) возможность перекодировки текста предусмотрена изначально. Более того, определение необходимости перекодировки происходит автоматически (при определенных настройках) на основе орфографических словарей.
Теперь хочу обсудить вопрос, затронутый в КГ N№51 (за 1999 год) в конце статьи Алексея Ильченко "Пишем прописью". Цитирую:
“...самым главным недостатком этой и подобной ей программ является то, что они "работают" только в рабочем поле Word'а. Так что у вас есть вполне реальная возможность дать какому-нибудь файлу имя "Ltkj dctq vjtq;bpyb" вместо "Дело всей моей жизни", и потерять его безвозвратно.”
В принципе, с ним нельзя не согласиться. Но вся штука в том, что этот макрос изначально предназначался для набора текста в Word и никак не претендовал на универсальную панацею для всей операционной системы. Да, и потом, глупо называть файлы не глядя, что вы набираете.
Но раз уж пошел об этом разговор, то буквально на днях мне пришло письмо с интересной ссылочкой на программу "Опечатка v2.0". Вот адресок, где ее можно скачать, — http://www.ipom.ru/ golomin. Однако, это для тех читателей, у которых имеется доступ к Internet, а таких (к сожалению) отнюдь не большинство. Эта программа как раз и делает то же, что и описанный выше макрос, только в масштабах операционки.
Вот и все. Думаю, теперь тема исчерпана.

Сергей Нематов

© компьютерная газета