Пример использования DirectInput для опроса клавиатуры
01.01.2007
{****************************************************************************** * * * Придумал и написал Кода Виктор, Март 2002 * * * * Файл: main.pas * * Содержание: Пример использования DirectInput для опроса клавиатуры * * * ******************************************************************************} unit main; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, ComCtrls, StdCtrls, ExtCtrls; type TForm1 = class(TForm) gb1: TGroupBox; gb2: TGroupBox; gb3: TGroupBox; lbRemark: TLabel; imView: TImage; rbWM: TRadioButton; rgDI8: TRadioButton; lbKeys: TLabel; lbIndex: TLabel; btnClose: TButton; procedure FormCreate(Sender: TObject); procedure btnCloseClick(Sender: TObject); procedure FormDestroy(Sender: TObject); private { Private declarations } public { Public declarations } procedure Hook( var Msg: TMsg; var Handled: Boolean ); procedure Idle( Sender: TObject; var Done: Boolean ); end; var Form1: TForm1; implementation {$R *.DFM} uses DirectInput8; //------------------------------------------------------------------------------ // Константы и глобальные переменные //------------------------------------------------------------------------------ var lpDI8: IDirectInput8 = nil; lpDIKeyboard: IDirectInputDevice8 = nil; nXPos, nYPos: Integer; //------------------------------------------------------------------------------ // Имя: InitDirectInput() // Описание: Производит инициализацию объектов DirectInput в программе //------------------------------------------------------------------------------ function InitDirectInput( hWnd: HWND ): Boolean; begin Result := FALSE; // Создаём главный объект DirectInput if FAILED( DirectInput8Create( GetModuleHandle( 0 ), DIRECTINPUT_VERSION, IID_IDirectInput8, lpDI8, nil ) ) then Exit; lpDI8._AddRef(); // Создаём объект для работы с клавиатурой if FAILED( lpDI8.CreateDevice( GUID_SysKeyboard, lpDIKeyboard, nil ) ) then Exit; lpDIKeyboard._AddRef(); // Устанавливаем предопределённый формат для "простогй клавиатуры". В боль- // шинстве случаев можно удовлетвориться и установками, заданными в структуре // c_dfDIKeyboard по умолчанию, но в особых случаях нужно заполнить её самому if FAILED( lpDIKeyboard.SetDataFormat( @c_dfDIKeyboard ) ) then Exit; // Устанавливаем уровень кооперации. Подробности о флагах смотри в DirectX SDK if FAILED( lpDIKeyboard.SetCooperativeLevel( hWnd, DISCL_BACKGROUND or DISCL_NONEXCLUSIVE ) ) then Exit; // Захвытываем клавиатуру lpDIKeyboard.Acquire(); Result := TRUE; end; //------------------------------------------------------------------------------ // Имя: ReleaseDirectInput() // Описание: Производит удаление объектов DirectInput //------------------------------------------------------------------------------ procedure ReleaseDirectInput(); begin // Удаляем объект для работы с клавиатурой if lpDIKeyboard <> nil then // Можно проверить if Assigned( DIKeyboard ) begin lpDIKeyboard.Unacquire(); // Освобождаем устройство lpDIKeyboard._Release(); lpDIKeyboard := nil; end; // Последним удаляем главный объект DirectInput if lpDI8 <> nil then begin lpDI8._Release(); lpDI8 := nil; end; end; //------------------------------------------------------------------------------ // Имя: UpdateKeyboardState() // Описание: Обрабатывает клавиатурный ввод методом DirectInput //------------------------------------------------------------------------------ function UpdateKeyboardState(): Boolean; var bKeyBuffer: array [0..255] of Byte; i: Integer; hr: HRESULT; begin Result := FALSE; // Производим опрос состояния клавиш, данные записываются в буфер-массив if lpDIKeyboard.GetDeviceState( SizeOf( bKeyBuffer ), @bKeyBuffer ) = DIERR_INPUTLOST then begin // Захватываем снова lpDIKeyboard.Acquire(); // Производим повторный опрос if FAILED( lpDIKeyboard.GetDeviceState( SizeOf( bKeyBuffer ), @bKeyBuffer ) ) then Exit; end; // Изменяем координаты курсора if bKeyBuffer[ DIK_NUMPAD4 ] = $080 then Dec( nXPos ); if bKeyBuffer[ DIK_NUMPAD6 ] = $080 then Inc( nXPos ); if bKeyBuffer[ DIK_NUMPAD8 ] = $080 then Dec( nYPos ); if bKeyBuffer[ DIK_NUMPAD2 ] = $080 then Inc( nYPos ); // Выводим список кодов нажатых клавиш with Form1.lbKeys do begin Caption := ''; for i := 0 to 255 do if bKeyBuffer[ i ] = $080 then if i <= 9 then Caption := Caption + Format( '0%d ', [ i ] ) else Caption := Caption + Format( '%d ', [ i ] ); end; Result := TRUE; end; //------------------------------------------------------------------------------ // Имя: TForm1.Hook() // Описание: Обрабатывает клавиатурный ввод подобно главной функции окна //------------------------------------------------------------------------------ procedure TForm1.Hook( var Msg: TMsg; var Handled: Boolean ); var i: Integer; begin if Msg.message <> WM_KEYDOWN then Exit; // Изменяем координаты курсора case Msg.wParam of VK_NUMPAD4: Dec( nXPos ); VK_NUMPAD6: Inc( nXPos ); VK_NUMPAD8: Dec( nYPos ); VK_NUMPAD2: Inc( nYPos ); end; // Выводим код нажатой клавиши with Form1.lbKeys do begin Caption := ''; // Бессмысленно писать for i := 0 to 255 do ... При обработке сообщения // WM_KEYDOWN мы можем узнать состояние только одной клавиши - ведь массив // не используется. Справедливоси ради надо сказать, что в Windows есть // функция GetKeyboardState(), работающая с массивом и очень быстро if Msg.wParam <= 9 then Caption := Caption + Format( '0%d ', [ Msg.wParam ] ) else Caption := Caption + Format( '%d ', [ Msg.wParam ] ); end; // Блокируем дальнейшую обработку события Handled := TRUE; end; //------------------------------------------------------------------------------ // Имя: TForm1.Idle() // Описание: Вызывает функцию опроса состояния клавиатуры //------------------------------------------------------------------------------ procedure TForm1.Idle( Sender: TObject; var Done: Boolean ); var i: Integer; begin if rbWM.Checked then Application.OnMessage := Hook else begin Application.OnMessage := nil; // Если данные от клавиатуры не получены if not UpdateKeyboardState() then begin MessageBox( Form1.Handle, 'Потеряно устройство управления!', 'Ошибка!', MB_ICONHAND ); Form1.Close(); end; end; // Проверяем выход курсора за пределы диапазона if nXPos < 0 then nXPos := 0; if nXPos + 10 > 140 then nXPos := 130; if nYPos < 0 then nYPos := 0; if nYPos + 10 > 140 then nYPos := 130; // Рисуем курсор with imView.Canvas do begin FillRect( Canvas.ClipRect ); Brush.Color := clRed; Rectangle( nXPos, nYPos, nXPos + 10, nYPos + 10 ); Brush.Color := clWhite; end; Done := FALSE; end; //------------------------------------------------------------------------------ // Имя: TForm1.FormCreate() // Описание: Производит инициализацию DirectInput при старте программы //------------------------------------------------------------------------------ procedure TForm1.FormCreate(Sender: TObject); begin if not InitDirectInput( Form1.Handle ) then begin MessageBox( Form1.Handle, 'Ошибка при инициализации DirectInput!', 'Ошибка!', MB_ICONHAND ); ReleaseDirectInput(); Halt; end; // Приводим UI в соответствующий вид lbKeys.Caption := ''; // Назначаем обработчик Idle-события. Компонент TTimer не позволит раскрыть // всех преимуществ использования DirectInput Application.OnIdle := Idle; end; //------------------------------------------------------------------------------ // Имя: TForm1.btnCloseClick() // Описание: Закрывает программу //------------------------------------------------------------------------------ procedure TForm1.btnCloseClick(Sender: TObject); begin Form1.Close(); end; //------------------------------------------------------------------------------ // Имя: TForm1.FormDestroy() // Описание: Вызывается при удалении программы из памяти //------------------------------------------------------------------------------ procedure TForm1.FormDestroy(Sender: TObject); begin ReleaseDirectInput(); end; end.
Форма:
object Form1: TForm1 Left = 192 Top = 106 BorderIcons = [biSystemMenu, biMinimize] BorderStyle = bsSingle Caption = 'DirectInput 8: Клавиатура' ClientHeight = 318 ClientWidth = 377 Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'MS Sans Serif' Font.Style = [] OldCreateOrder = False Position = poScreenCenter OnCreate = FormCreate OnDestroy = FormDestroy PixelsPerInch = 96 TextHeight = 13 object lbRemark: TLabel Left = 8 Top = 8 Width = 338 Height = 13 Caption = 'Используйте num-клавиши клавиатуры для перемещения курсора' end object btnClose: TButton Left = 294 Top = 288 Width = 75 Height = 23 Cancel = True Caption = 'Закрыть' TabOrder = 0 OnClick = btnCloseClick end object gb1: TGroupBox Left = 8 Top = 32 Width = 177 Height = 177 Caption = 'Визуальная проверка' TabOrder = 1 object imView: TImage Left = 19 Top = 24 Width = 140 Height = 140 end end object gb3: TGroupBox Left = 8 Top = 216 Width = 361 Height = 65 Caption = 'Клавиши' TabOrder = 2 object lbKeys: TLabel Left = 64 Top = 24 Width = 289 Height = 17 AutoSize = False Caption = 'lbKeys' end object lbIndex: TLabel Left = 8 Top = 24 Width = 49 Height = 13 Caption = 'Индексы:' end end object gb2: TGroupBox Left = 200 Top = 32 Width = 169 Height = 177 Caption = 'Способ опроса' TabOrder = 3 object rbWM: TRadioButton Left = 24 Top = 56 Width = 129 Height = 17 Caption = 'Windows Messaging' Checked = True TabOrder = 0 TabStop = True end object rgDI8: TRadioButton Left = 24 Top = 104 Width = 129 Height = 17 Caption = 'DirectInput 8' TabOrder = 1 end end end
Взято с сайта Анатолия Подгорецкого https://podgoretsky.com
по материалам fido7.ru.delphi.*