// Done by TheTutor -- 6/27/02
// Перевод © 2004 Евгений Казеко
// www.gamecoder.kazeko.com
// evgeniy@kazeko.com
/* Эта обучалка о том, как получать ввод с клавиатуры в вашем приложении Win32.
Windows позволяет сделать это многими способами, но эта обучалка фокусируется
на методе, который получает ввод с клавиатуры вне WndProc().
Что касается приложения, мы сделаем его достаточно простым. Мы напишем
функцию, которая будет определять, нажата ли клавиша. Мы будем проверять
и верхний, и нижний регистры. Если вы нажмете одну из букв слова "GameTutorials",
вы увидите на экране надпись "GameTutorials", напечатанную случайным цветом.
Итак, приступим.
*/
#include "input.h"
typedef unsigned char uchar; // Чтобы меньше набирать
#define WIN_WIDTH 640
#define WIN_HEIGHT 480
// Откуда начинать рисование текста
#define TEXT_X 280
#define TEXT_Y 220
#define class_name "GT_KeyboardInput2"
// Эта функция напечатает на экран передаваемый текст
// используя передаваемый RGB цвет.
void PrintColoredText(HWND hwnd, char *text, uchar R, uchar G, uchar B);
// Стандартная callback функция
LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprev, PSTR cmdline, int ishow)
{
HWND hwnd; // Ссылка на наше окно
MSG msg; // В этой переменной будут сохраняться сообщения (такие, как
// нажатие клавиши), которые может получить наше окно.
WNDCLASSEX wndclassex = {0}; // Это наш "класс окна". "EX" означает
// "extended style" (расширенный стиль),
// который дает нам больше опций, когда
// мы создаем наше окно (хотя мы и проигнорируем их).
// Заполняем нужные нам поля
wndclassex.cbSize = sizeof(WNDCLASSEX); // Всегда должно быть установлено
wndclassex.style = CS_HREDRAW | CS_VREDRAW; // Стиль класса окна
wndclassex.lpfnWndProc = WinProc; // Указатель туда, где определена WinProc()
wndclassex.hInstance = hinstance; // Ссылка на экземпляр нашего окна
wndclassex.lpszClassName = class_name; // Имя нашего класса окна
wndclassex.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); // Устанавливаем фоновый
// цвет окна - белый
RegisterClassEx(&wndclassex); // Регистрируем класс окна, чтобы вызовы CreateWindow()
// и CreateWindowEx() знали, какой класс окна использовать
// при создании окна
hwnd = CreateWindowEx(NULL, // Дополнительные атрибуты окна, NULL - их нет
class_name, // Имя, которое мы дали WNDCLASSEX
"Keyboard 2", // Текст заголовка окна
WS_OVERLAPPEDWINDOW, // Стиль окна
CW_USEDEFAULT, // x левого верхнего угла окна (по умолчанию)
CW_USEDEFAULT, // y левого верхнего угла окна (по умолчанию)
WIN_WIDTH, // Ширина окна в пикселях
WIN_HEIGHT, // Высота окна в пикселях
NULL, // Ссылка на "родительское окно" (у нас его нет)
NULL, // Ссылка на меню (у нас его нет)
hinstance, // Ссылка на экземпляр окна (передается WinMain())
NULL); // "Дополнительная информация" для передачи
// в WinProc (у нас ее нет)
// Проверка ошибок
if(!hwnd)
return EXIT_FAILURE; // Случилось что-то плохое!
ShowWindow(hwnd, ishow); // Показать окно (сделать его видимым)
UpdateWindow(hwnd); // Обновить окно (нарисовать его)
while(1)
{
// Получить сообщения (например, нажатие клавиши) если они есть
if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
if(msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
// Если нажата какая-либо буква слова "GameTutorials" (регистр важен),
// напечатать "GameTutorials" на экран случайным цветом
if (KeyPressed('G') || KeyPressed('a') ||
KeyPressed('m') || KeyPressed('e') ||
KeyPressed('T') || KeyPressed('u') ||
KeyPressed('t') || KeyPressed('o') ||
KeyPressed('r') || KeyPressed('i') ||
KeyPressed('l') || KeyPressed('s'))
{
uchar red = rand()%256;
uchar green = rand()%256;
uchar blue = rand()%256;
PrintColoredText(hwnd, "GameTutorials", red, green, blue);
}
Sleep(100); // Сделаем паузу
}
}
UnregisterClass(class_name,hinstance); // Освободим память, выделенную WNDCLASSEX
return msg.wParam; // И выходим
}
// Оконная процедура
LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
{
PAINTSTRUCT ps;
// Здесь мы многого делать не будем
switch(message)
{
case WM_PAINT:
BeginPaint(hwnd,&ps);
EndPaint(hwnd,&ps);
return 0;
case WM_DESTROY:
case WM_CLOSE:
PostQuitMessage(0);
return 0;
} // конец switch(message)
return DefWindowProc(hwnd, message, wparam, lparam);
}
void PrintColoredText(HWND hwnd, char *text, uchar red, uchar green, uchar blue)
{
// Проверка ошибок
if(!text)
return; // Если "text" недействителен, выходим из функции
HDC hdc = GetDC(hwnd); // Получаем контекст устройства окна
// Проверка ошибок
if(!hdc)
return; // Не можем рисовать без HDC, выходим из функции
RECT rect;
GetClientRect(hwnd, &rect); // Получаем RECT клиент-области окна
// Сбрасываем клиент-область окна в белый цвет
FillRect(hdc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
// Эта функция делает то, что вы и ожидаете, она устанавливает
// цвет текста для определенного контекста устройства в
// передаваемые значения RGB цвета.
SetTextColor(hdc,RGB(red,green,blue));
/* Эта функция печатает текст в окне. Рассмотрим ее по параметрам:
hdc - контекст устройства где нужно рисовать (в нашем случае
hdc == "наше окно").
TEXT_X - координата Х, откуда начинать рисовать текст
TEXT_Y - координата Y, откуда начинать рисовать текст
text - char* (Windows определяет эту переменную как LPCSTR,
но на самом деле это то же, что и char*), который содержит
отображаемую строку
strlen(text) - число символов в строке
*/
TextOut(hdc,TEXT_X,TEXT_Y,text,strlen(text));
ReleaseDC(hwnd,hdc); // Всегда освобождайте HDC
/*****
Замечание:
В SetTextColor() мы используем макрос RGB()
RGB() это Win32 макрос, который делает COLORREF. COLORREF это
32-битное значение, определяющее RGB цвет. Вот так COLORREF
выглядит в шестнадцатиричном виде:
0x00bbggrr
Где bb - синий компонент, gg - зеленый компонент, и rr - красный
компонент, каждый из который может иметь беззнаковое значение
между 0 - 255
*****/
}
// Работа с клавиатурой
/*
К счастью, Windows позволяет легко получать информацию с клавиатуры вне WinProc().
Тем не менее, важно упомянуть две другие функции, которые также могут получать
данные с клавиатуры:
short GetKeyState(int virtualKey); // Эта функция в точности такая же, как мы написали.
// Вы передаете виртуальный код клавиши, и она
// возвращает short. Если высший бит возвращаемого
// значения установлен в единицу, клавиша нажата.
// Если низший бит установлен в единицу, то клавиша
// "отжата". В другом случае клавиша не нажата.
А теперь, если вы пишете функции ввода для игры, и скорость критична, вы захотите
использовать эту функцию:
short GetAsyncKeyState(int virtualKey); // Эта функция пропускает нормальный процесс
// "хорошо, клавиша была нажата, поместим ее
// в очередь для обработки" и дает вам
// информацию о состоянии клавиши асинхронно
// (т.е. немедленно). Подобно другим функциям,
// если высший бит установлен в 1, то клавиша
// нажата. Но низший бит на этот раз равен 1,
// если клавиша была нажата после предыдущего
// вызова GetAsyncKeyState()
Поэтому, если вы пишете код ввода для игры, и вам неважен регистр, вы можете
просто написать функцию KeyPressed() вот таким образом:
bool KeyPressed(char key) // Проверка, была ли нажата буква
{
key = toupper(key);
return (GetAsyncKeyState(key) & 0x8000) == 0x8000;
}
Задание:
Напишите функции "key pressed" для алфавитных, цифровых или знаковых клавиш
клавиатуры, чувствительные к регистру.
*/
/*
| TheTutor
| thetutor@gametutorials.com
| © 2000-2002 GameTutorials
*/
// Перевод © 2004 Евгений Казеко
// www.gamecoder.kazeko.com
// evgeniy@kazeko.com
|