Сию статью я решил представить как описание моей проги для работы с
клавой. Признаюсь, меня долго интересовал вопрос о смене состояния таких клваиш
как NumLock, CapsLock, ScrollLock (следовательно и о моргании лампочек :), и только
сегодня я созрел для написания этой статьи.
Суть моего исходника, который мы будем разбирать - это показать на двух
примерах как работают функции GetKeyBoardState, SetKeyboardState и ActivateKeyboardLayout.
Для начала рассмотрим первые две.
Должен тебя немножко обломать... Лампочки мигают только Win9x, в WinNT только
меняется состояние клавиш.Перед рассмотром куска кода моего исходника,
произведу короткое описание имущества:
Command1, Command2, Command3, cmdDoSymfony, cmdStopSymfony, cmdsym2,
cmdstopsym2, cmdRus, cmdLat - Кнопки.
symfony, num, caps, scroll - таймеры.
Попытайся
сбацать дизайн так, как показано на картинке справа. Теперь задай всем таймерам
значение False для свойства Enabled; таймеру с именем symfony
задай интервал, равный 100, а остальным задай интервал 200
Теперь о кнопках. Кнопкам cmdStopSymfony и cmdstopsym2 задай
значение False для свойства Enabled (для чего это, ты узнаешь
позднее).
Теперь перейдём к кодингу (наконец-то!). Для начала, забомби
это
в
раздел Declarations модуля формы:
Private Declare Function GetKeyboardState Lib "user32" (pbKeyState As
Byte) As Long
Private Declare Function SetKeyboardState Lib "user32" (lppbKeyState
As Byte) As Long
Private Declare Function ActivateKeyboardLayout Lib "user32" _
(ByVal HKL As Long, ByVal flags As Long) As Long
Private Const kb_lay_ru As Long = 68748313
Private Const kb_lay_en As Long = 67699721
Dim KeyState(0 To 255) As Byte
Здесь
я
объявляю
API
функции для работы с клавой. Разжуем их поподробнее.
Функция GetKeyBoardState служит для получения текущего состояния
клавиатуры. Причём она должна обращатся к массиву KeyState типа данных Byte.
В массиве храняться состояния клавиш.
Функция SetKeyboardState служит для изменения состояния клавиатуры.
Обращается к тому же массиву.
Функция ActivateKeyboardLayout меняет раскладку клавиатуры.
Насчёт массива KeyState - он (этоя объясняю для особо одарённых :))
должен сказать только то, что его нет, среди API семейства VB, поэтому его надо
создать самому (что мы и сделали)
Всё, больше в этом разделе, на протяжении всего кодинга, ничего объявляться не
будет.
Перейдём к программированию кнопок Command1 ("Нажать Num"),
Command2 ("Нажать Caps") и Command3 ("Нажать
Scroll"):
Private Sub Command1_Click()
'Получаю
текущее состояние клавиатуры (т.е. получаю значение всего массива KeyState)
GetKeyboardState KeyState(Index)
'Изменяю
сосотояние клавиши в массиве с нумером 144 (NumLock)
KeyState(144) = KeyState(144) Xor 1
'Устанавливаю
новое состояние клавиатуры
SetKeyboardState KeyState(Index)
End Sub
Private Sub Command2_Click()
'Получаю
текущее состояние клавиатуры (т.е. получаю значение всего массива KeyState)
GetKeyboardState KeyState(Index)
'Изменяю
сосотояние клавиши в массиве с нумером 20 (CapsLock)
KeyState(20) = KeyState(20) Xor 1
'Устанавливаю
новое состояние клавиатуры
SetKeyboardState KeyState(Index)
End Sub
Private Sub Command3_Click()
'Получаю
текущее состояние клавиатуры (т.е. получаю значение всего массива KeyState)
GetKeyboardState KeyState(Index)
'Изменяю
сосотояние клавиши в массиве с нумером 145 (ScrollLock)
KeyState(145) = KeyState(145) Xor 1
'Устанавливаю
новое состояние клавиатуры
SetKeyboardState KeyState(Index)
End Sub
Тут почти
всё одинаково, поэтому разберём только обработчик нажатия на кнопку Command1.
Ты уже знаешь для чего служит функция GetKeyboardState, так вот, я получаю
состояние клавиатуры из всех значений массива KeyState; чтобы это
сделать, я вместо какого-то конкретного индекса массива указываю значение Index,
чтобы проверился весь массив.
Как только яполучил текущее состояние клавиатуры, я изменил состояние клавши в
массиве с номером 144 (т.е. состояние NumLock).Как я это сделал мы рассмотрим
чуть ниже.Как только массив принял новое значение, я тут же заставляю функцию SetKeyboardState
установить это значение.
Теперь подробнее разберём вторую строчку. Как ты знаешь состояние клавши может
быть только в двух значениях - нажата/ненажата.Следовательно, нам надо, чтобы
состояние клавши менялось в зависимости от ситуации. Для этого то я и взял
логический оператор Xor.Прежде чем разбираться дальше, глянь-ка на енту
таблицу:
И (And) |
Или (Or) |
Исключающее или (Xor) |
Отрицание (Not) |
0 And 0 = 0 |
0 Or 0 = 0 |
0 Xor 0 = 0 |
Not 0 = 1 |
Так вот, самые
распространённые варианты значений, которые может принимать один бит, - это
значения "правда" и "ложь" (1 и 0, True и False),
используемые в логике, откуда происходят так называемые "логические
операции" над битами.Если ты напрягёшь свою логику, то ты поймёшь, почему
же я взял оператор Xor, а не And.Ладно, объясню :) Допустим, NumLock у тебя
включен, т.е. его состояние в массиве KeyState равно 1. Если ты смотрел
таблицу, то ты должен был заметить это: 1 Xor 1 = 1 (ведь я во второй строчке
писал Xor 1).Это значит, что после этой логической операции, знчение NumLock
изменится на пртивоположное, и так до бесконечности...
Ту же шнягу я вытворял с другими значениями массивов.
Как выглядит код таймеров и кнопок cmdDoSymfony, cmdStopSymfony, cmdsym2
и cmdstopsym2 я писать не стану, т.к. ты если захочешь, всё увидмшь в
исходнике, но вот принцип их работы я объясню. После того, как ты нажал на
кнопку cmdDoSymfony, активизируется таймер symfony, который
поочереди вызывает процедуры-обработчики нажатия на кнопки Command1, Command2 и
Command3, так же становиться доступной кнопка отключения этого таймера (cmdStopSymfony),
а сама эта кнопка (cmdDoSymfony) отключается (блокируется).После нажатия
на cmdStopSymfony происходит обратный процесс.
После нажатия на cmdsym2 происходит активация таймера num,
который в свою очередь, после необходимых операций включает таймер caps
и отключает себя, а тот в свою очередь, после заданных операций, активизирует
таймер scroll, а себя отрубает :))) .Таймер scroll делает
аналогичную операцию.Вообщем как-то запущено, поэтому я решил всё-таки показать
обработчики вышеописанных таймеров:
Private Sub num_Timer()
'Меняю состояние ScrollLock:
GetKeyboardState KeyState(Index)
KeyState(145) = KeyState(145) Xor 1
SetKeyboardState KeyState(Index)
GetKeyboardState KeyState(Index)
KeyState(144) = KeyState(144) Xor 1
SetKeyboardState KeyState(Index)
caps.Enabled = True
num.Enabled = False
End Sub
Private Sub caps_Timer()
GetKeyboardState KeyState(Index)
KeyState(20) = KeyState(20) Xor 1
SetKeyboardState KeyState(Index)
'При этом значение NumLock
опять меняется:
GetKeyboardState KeyState(Index)
KeyState(144) = KeyState(144) Xor 1
SetKeyboardState KeyState(Index)
scroll.Enabled = True
caps.Enabled = False
End Sub
Private Sub scroll_Timer()
GetKeyboardState KeyState(Index)
KeyState(145) = KeyState(145) Xor 1
SetKeyboardState KeyState(Index)
'Но при этом меняются прошлые
значения CapsLock и NumLock:
GetKeyboardState KeyState(Index)
KeyState(20) = KeyState(20) Xor 1
SetKeyboardState KeyState(Index)
GetKeyboardState KeyState(Index)
KeyState(144) = KeyState(144) Xor 1
SetKeyboardState KeyState(Index)
num.Enabled = True
scroll.Enabled = False
End Sub
Ну всё, с лампочками окончили.
И напоследок я
покажу как сменить раскладку.Для этго нам понадобятся всего две кнопки - cmdRus
и cmdLat. Обработчик нажатия на cmdRus выглядит так:
Private Sub cmdRus_Click()
'Ставлю русскую раскладку
ActivateKeyboardLayout& kb_lay_ru, 0
End Sub
А обработчик нажатия на cmdLat:
Private Sub cmdLat_Click()
'Ставлю латинскую раскладку
ActivateKeyboardLayout& kb_lay_en, 0
End Sub