Работа с клавиатурой

 

Сию статью я решил представить как описание моей проги для работы с клавой. Признаюсь, меня долго интересовал вопрос о смене состояния таких клваиш как 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 And 1 = 0
1 And 0 = 0
1 And 1 = 1

0 Or 0 = 0
0 Or 1 = 1
1 Or 0 = 1
1 Or 1 = 1

0 Xor 0 = 0
0 Xor 1 = 1
1 Xor 0 = 1
1 Xor 1 = 0

Not 0 = 1
Not 1 = 0

Так вот, самые распространённые варианты значений, которые может принимать один бит, - это значения "правда" и "ложь" (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

Hosted by uCoz