платформа Win32 - Туториалы Iczelion'a на русском, адаптированные для FreeBasic. Урок 6 - клавиатура

Предыдущая тема Следующая тема Перейти вниз

платформа Win32 - Туториалы Iczelion'a на русском, адаптированные для FreeBasic. Урок 6 - клавиатура

Сообщение  electrik в Вс Июн 28, 2009 8:23 pm

Win32 API. Урок 6. Клавиатура

Мы изучим, как Windows программа получает сообщения от клавиатуры.

Теория:

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

Хотя на экране может быть сразу несколько окон, только одно из них имеет фокус ввода, и только оно может получать сообщения от клавиатуры. Вы можете отличить окно, которое имеет фокус ввода от окна, которое его не имеет, посмотрев на его title bar - он будет подсвечен, в отличии от других.

В действительности, есть два типа сообщений от клавиатуры, зависящих от того, чем вы считаете клавиатуру. Вы можете считать ее набором кнопок. В этом случае, если вы нажмете кнопку, Windows пошлет сообщение WM_KEYDOWN активному окну, уведомляя о нажатии клавиши. Когда вы отпустите клавишу, Windows пошлет сообщение WM_KEYUP. Вы думаете о клавише как о кнопке. Другой взгляд на клавиатуру предполагает, что это устройство ввода символов. Тогда, Windows шлет сообщения WM_KEYDOWN или WM_KEYUP окну, в котором есть фокус ввода, и эти сообщения будут транслированы в сообщение WM_CHAR функцией TranslateMessage. Процедура окна может обрабатывать все три сообщения или только то, в котором оно заинтересованно. Большую часть времени вы можете игнорировать WM_KEYDOWN и WM_KEYUP, так как вызов функции TranslateMessage в цикле обработки сообщений транслирует сообщения WM_KEYDOWN и WM_KEYUP в WM_CHAR. Мы будем опираться именно на это сообщение в данном Уроке.

Пример:

Код:

' клавиатура
#include "windows.bi"

declare function WinMain ( byval hInst as HINSTANCE, _
byval hPrevInst as HINSTANCE, _
  byval szCmdLine as LPSTR, _
  byval iCmdShow as integer ) as integer

' начало программы
#define ClassName "SimpleWinClass" ' класс окна
#define AppName "Our First Window" ' имя программы
dim shared char as WPARAM = &h20 ' символ, который программа получает от клавиатуры
end WinMain( GetModuleHandle( NULL ) ,NULL,GetCommandLine() , SW_SHOWNORMAL ) ' вызвать основную функцию
' здесь заканчивается программа

' процедура окна
function  WndProc _
(byval hwnd as HWND, _ ' хэндл окна
byval uMsg as UINT, _ ' сообщение
byval wParam as WPARAM, _ ' дополнительный  параметр сообщений
byval lParam as LPARAM) as LRESULT ' дополнительный параметр сообщений

dim hDc as HDC ' хэндл контекста устройства
dim ps as PAINTSTRUCT ' структура PAINTSTRUCT

function = 0
select case uMsg  'начинаем обработку сообщений
case WM_DESTROY ' если пользователь закрывает окно
PostQuitMessage(0) ' выходим из программы
exit function
case WM_CHAR ' если получено сообщение WM_CHAR
char=wParam ' копируем символ из wParam в нашу переменную char
InvalidateRect(hWnd,NULL,TRUE) ' вынудить Windows послать сообщение WM_PAINT
case WM_PAINT ' сообщение отрисовки окна

'получим контекст устройства в hdc и начнем отрисовку
hdc = BeginPaint(hWnd, @ps)
TextOut(hdc,0,0,cPtr(LPCSTR,@char),1) ' отрисовать символ
EndPaint(hWnd, @ps) ' завершаем отрисовку и освобождаем хэндл контекста устройства
end select
function = DefWindowProc(hWnd,uMsg,wParam,lParam) ' Дефаултная функция обработки окна
end function


'функция WinMain
function WinMain _
(byval hInst as HINSTANCE, _ ' хэндл программы
byval hPrevInst as HINSTANCE, _ 'в win32 всегда 0
byval szCmdLine as LPSTR, _  'указатель на командную строку
byval iCmdShow as integer ) as integer  ' состояние окна при первом появлении

dim wc as WNDCLASSEX ' структура параметров окна
dim wMsg as MSG  ' структура сообщений
dim hWnd as HWND ' хэндл окна

 'структура класса окна wc
with wc ' заполняем структуру wc
.cbSize = SIZEOF( WNDCLASSEX )  ' размер структуры WNDCLASSEX
.style = CS_HREDRAW or CS_VREDRAW  ' Стиль окна
.lpfnWndProc = @WndProc ' Адрес процедуры окна WndProc
.cbClsExtra = NULL  ' резервирование  дополнительных байт за концом структуры
.cbWndExtra = NULL
.hInstance = hInst  ' хэндл модуля
.hbrBackground = cast(HGDIOBJ, COLOR_WINDOW+1) ' Цвет фона
.lpszMenuName = NULL ' Хэндл меню
.lpszClassName = @ClassName ' имя класса окна
.hIcon = LoadIcon( NULL,IDI_APPLICATION ) ' Хэндл иконки
.hIconSm = .hIcon 'Хэндл маленькой иконки
.hCursor = LoadCursor( NULL,IDC_ARROW) ' Хэндл курсора
end with

' регистрация нашего класса окна
if(RegisterClassEx(@wc) = FALSE) then
MessageBox(0,"Не могу зарегистрировать класс окна","Ошибка",0)
end 1
end if

' Создадим окно
hwnd = CreateWindowEx _
(NULL, _ ' дополнительные стили
ClassName, _ ' строка с именем класса окна
AppName, _ ' строка с именем окна
WS_OVERLAPPEDWINDOW, _ ' стиль окна
CW_USEDEFAULT, _ ' X
CW_USEDEFAULT, _ ' Y
CW_USEDEFAULT, _ ' ширина окна
CW_USEDEFAULT, _ ' высота окна
NULL, _ ' хэндл родительского окна
NULL, _ ' хэндл меню
hInst, _ ' хэндл модуля
NULL) ' указатель на структуру данных

ShowWindow( hwnd,iCmdShow) ' отобразить наше окно на десктопе
UpdateWindow( hwnd) ' обновить клиентскую область

while( GetMessage( @wMsg, NULL, 0, 0 ) <> FALSE )  'цикл сообщений
TranslateMessage( @wMsg )
DispatchMessage( @wMsg )
wend
function = wMsg.wParam
end function

Анализ:

dim shared char as WPARAM = &h20 ' символ, который программа получает от клавиатуры.
Это переменная, в которой будет сохраняться символ, получаемый от клавиатуры. Так как символ шлется в WPARAM процедуры окна, мы для простоты определяем эту переменную как обладающую типом WPARAM. Начальное значение - &h20 или "пробел", так как когда наше окно обновляет свою клиентскую область в первое время, символ еще не введен, поэтому мы делаем так, чтобы отображался пробел.

case WM_CHAR ' если получено сообщение WM_CHAR
char=wParam ' копируем символ из wParam в нашу переменную char
InvalidateRect(hWnd,NULL,TRUE) ' вынудить Windows послать сообщение WM_PAINT

Это было добавлено в процедуру окна для обработки сообщения WM_CHAR. Она всего лишь помещает символ в переменную char и затем вызывает InvalidateRect, что вынуждает Windows послать сообщение WM_PAINT процедуре окна. Синтаксис этой функции следующий:

function InvalidateRect _
(byval hWnd as HWND, _
byval lpRect as LPCRECT, _
byval bErase as BOOL) as BOOL

hWnd- хэндл окна
• lpRect - указатель на прямоугольник в клиентской области, который мы хотим объявить требующим перерисовки. Если этот параметр равен NULL'у, тогда вся клиентская область объявляется такой.
bErase - флаг, говорящий Windows, нужно ли уничтожать бэкграунд. Если он равен TRUE, тогда она делает это при вызове функции BeginPaint.

• Таким образом, мы будем использовать следующую стратегию: мы сохраним всю необходимую информацию, относящуюся к отрисовке клиентской области и генерирующую сообщение WM_PAINT, чтобы перерисовать ее. Конечно, код в секции WM_PAINT должен знать заранее, что от него ожидают. Это кажется обходным путем делать дела, но это путь Windows.
• На самом деле, мы можем отрисовать клиентскую область в ходе обработки сообщения WM_CHAR, между вызовами функций GetDC и ReleaseDC. Нет никаких проблем с этим. Но вся забава начнется, когда приложению понадобится перерисовать клиентскую область. Так как код, рисующий символ находится в секции WM_CHAR, программа не сможет перерисовать символ в клиентской части. Поэтому помещайте все необходимые данные и код, отвечающий за рисование в WM_PAINT. Вы можете послать это сообщение из любого места вашего кода, где вам нужно перерисовать клиентскую область.

TextOut(hdc,0,0,cPtr(LPCSTR,@char),1)

Когда InvalidateRect вызванна, она шлет сообщение WM_PAINT обратно процедуре окна, поэтому вызывается код в секции WM_PAINT. Он вызывает BeginPaint, чтобы
получить хэндл контекста устройства, и затем вызывает TextOut, рисующая наш символ в клиентской области в x=0, y=0. Когда вы запускаете программу и нажимаете любую клавишу, вы увидите, что символьное эхо в верхнем левом углу клиентского окна. И когда окно минимизируется и максимизируется, символ все равно там, так как все код и все данные, необходимые для перерисовки располагаются в секции WM_PAINT.

[C] Iczelion, пер. Aquila.

electrik

Сообщения : 391
Дата регистрации : 2008-09-02
Возраст : 36
Откуда : галактика Млечный путь, система Солнечная, планета Земля, страна россия, город Санкт Петербург

Посмотреть профиль

Вернуться к началу Перейти вниз

Предыдущая тема Следующая тема Вернуться к началу


 
Права доступа к этому форуму:
Вы не можете отвечать на сообщения