Sources
Delphi Russian Knowledge Base
DRKB - это самая большая и удобная в использовании база знаний по Дельфи в рунете, составленная Виталием Невзоровым

Пример использования 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.*