⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hidcontrollerclass.pas

📁 基于DELPHI的API
💻 PAS
📖 第 1 页 / 共 3 页
字号:
{ a Class interface for HID access }

unit HidControllerClass;

interface

uses
  Windows, Messages, Classes, DsgnIntf,
  Dialogs, Forms, Registry, SysUtils,
  DBT, SetupAPI, Hid;

const
  // strings from the registry for CheckOutByClass
  cHidKeyboardClass = 'Keyboard';
  cHidMouseClass    = 'Mouse';

type
  // forward declarations
  TJvHidDeviceController = class;
  TJvHidDevice           = class;

  // the Event function declarations
  TJvHidEnumerateEvent = function (HidDev: TJvHidDevice; Index: Integer): Boolean of object;
  TJvHidUnplugEvent    = procedure(HidDev: TJvHidDevice) of object;

  // the representation of a HID device

  TJvHidDevice = class(TObject)
  private
    // internal control variables
    FMyController:        TJvHidDeviceController;
    FIsPluggedIn:         Boolean;
    FIsCheckedOut:        Boolean;
    FIsEnumerated:        Boolean;
    FHidFileHandle:       THandle;
    // internal properties part
    FDevRegKey:           DWORD;
    FDevicePath:          string;
    FHardWareKey:         string;
    FRegDescr:            string;
    FRegClass:            string;
    FVendorName:          AnsiString;
    FProductName:         AnsiString;
    FSerialNumber:        AnsiString;
    FDeviceStrings:       TStringList;
    FLanguageStrings:     TStringList;
    FPreparsedData:       PHIDPPreparsedData;
    FAttributes:          THIDDAttributes;
    FCaps:                THIDPCaps;
    FConfiguration:       THIDDConfiguration;
    FNumInputBuffers:     Integer;
    FLinkCollection:      PHIDPLinkCollectionNode;
    FLinkCollectionNodes: TList;
    FMaxDataListLength:   ULong;
    FMaxUsageListLength:  ULong;
    FMaxButtonListLength: ULong;
    FReportTypeParam:     THIDPReportType;
    FUsagePageParam:      TUsage;
    FLinkCollectionParam: WORD;
    FUsageParam:          TUsage;
    FUnplug:              TJvHidUnplugEvent;

    // tells if access to device is allowed
    function  IsAccessible: Boolean;

    // internal property implementors
    procedure SetConfiguration  (Config: THIDDConfiguration);
    procedure SetNumInputBuffers(const Num: Integer);
    procedure SetReportTypeParam(const ReportType: THIDPReportType);
    procedure SetUsagePageParam (const UsagePage: TUsage);

    // Constructor is hidden! Only a TJvHidDeviceController can create a TJvHidDevice object.
    constructor Create(DevicePath: string; DevID: DWORD; Unplug: TJvHidUnplugEvent);

  protected
    // internal property implementors
    procedure DoUnplug;
    procedure SetUnplug(const value: TJvHidUnplugEvent);

  public

  published
    destructor Destroy; override;

    // methods
    procedure CloseFile;
    function  FlushQueue:                                                           Boolean;
    function  GetButtonCaps        (ButtonCaps: PHIDPButtonCaps; var Count: WORD):  NTSTATUS;
    function  GetButtons           (UsageList: PUsage; var UsageLength: ULong;
                                    var Report; ReportLength: ULong):               NTSTATUS;
    function  GetButtonsEx         (UsageList: PUsageAndPage; var UsageLength: ULong;
                                    var Report; ReportLength: ULong):               NTSTATUS;
    function  GetData              (DataList: PHIDPData; var DataLength: ULong;
                                    var Report; ReportLength: ULong):               NTSTATUS;
    function  GetFeature           (var Report; const Size: Integer):               Boolean;
    function  GetPhysicalDescriptor(var Buffer; const Size: Integer):               Boolean;
    function  GetScaledUsageValue  (var UsageValue: Integer;
                                    var Report; ReportLength: ULong):               NTSTATUS;
    function  GetSpecificButtonCaps(ButtonCaps: PHIDPButtonCaps; var Count: WORD):  NTSTATUS;
    function  GetSpecificValueCaps (ValueCaps:  PHIDPValueCaps;  var Count: WORD):  NTSTATUS;
    function  GetUsages            (UsageList: PUsage; var UsageLength: ULong;
                                    var Report; ReportLength: ULong):               NTSTATUS;
    function  GetUsagesEx          (UsageList: PUsageAndPage; var UsageLength: ULong;
                                    var Report; ReportLength: ULong):               NTSTATUS;
    function  GetUsageValue        (var UsageValue: ULong;
                                    var Report; ReportLength: ULong):               NTSTATUS;
    function  GetUsageValueArray   (UsageValue: PChar; UsageValueByteLength: WORD;
                                    var Report; ReportLength: ULong):               NTSTATUS;
    function  GetValueCaps         (ValueCaps:  PHIDPValueCaps;  var Count: WORD):  NTSTATUS;
    function  OpenFile: Boolean;
    function  SetButtons           (UsageList: PUsage; var UsageLength: ULong;
                                    var Report; ReportLength: ULong):               NTSTATUS;
    function  SetData              (DataList: PHIDPData; var DataLength: ULong;
                                    var Report; ReportLength: ULong):               NTSTATUS;
    function  SetFeature           (var Report; const Size: Integer):               Boolean;
    function  SetScaledUsageValue  (UsageValue: Integer;
                                    var Report; ReportLength: ULong):               NTSTATUS;
    function  SetUsages            (UsageList: PUsage; var UsageLength: ULong;
                                    var Report; ReportLength: ULong):               NTSTATUS;
    function  SetUsageValue        (UsageValue: ULong;
                                    var Report; ReportLength: ULong):               NTSTATUS;
    function  SetUsageValueArray   (UsageValue: PChar; UsageValueByteLength: WORD;
                                    var Report; ReportLength: ULong):               NTSTATUS;
    function  UnsetButtons         (UsageList: PUsage; var UsageLength: ULong;
                                    var Report; ReportLength: ULong):               NTSTATUS;
    function  UnsetUsages          (UsageList: PUsage; var UsageLength: ULong;
                                    var Report; ReportLength: ULong):               NTSTATUS;
    function  ReadFile             (var Report; ToRead:  DWORD; var BytesRead:    DWORD): Boolean;
    function  WriteFile            (var Report; ToWrite: DWORD; var BytesWritten: DWORD): Boolean;

    // management properties
    property Attributes:          THIDDAttributes     read FAttributes;
    property Caps:                THIDPCaps           read FCaps;
    property Configuration:       THIDDConfiguration  read FConfiguration       write SetConfiguration;
    property DevicePath:          string              read FDevicePath;
    property DeviceStrings:       TStringList         read FDeviceStrings;
    property DevRegKey:           DWORD               read FDevRegKey;
    property HardWareKey:         string              read FHardWareKey;
    property HidFileHandle:       THandle             read FHidFileHandle;
    property IsCheckedOut:        Boolean             read FIsCheckedOut;
    property IsPluggedIn:         Boolean             read FIsPluggedIn;
    property LanguageStrings:     TStringList         read FLanguageStrings;
    property LinkCollectionNodes: TList               read FLinkCollectionNodes;
    property LinkCollectionParam: WORD                read FLinkCollectionParam write FLinkCollectionParam;
    property MaxButtonListLength: ULong               read FMaxButtonListLength;
    property MaxDataListLength:   ULong               read FMaxDataListLength;
    property MaxUsageListLength:  ULong               read FMaxUsageListLength;
    property NumInputBuffers:     Integer             read FNumInputBuffers     write SetNumInputBuffers;
    property PreparsedData:       PHIDPPreparsedData  read FPreparsedData;
    property ProductName:         string              read FProductName;
    property RegClass:            string              read FRegClass;
    property RegDescr:            string              read FRegDescr;
    property ReportTypeParam:     THIDPReportType     read FReportTypeParam     write SetReportTypeParam;
    property SerialNumber:        string              read FSerialNumber;
    property VendorName:          string              read FVendorName;
    property UsageParam:          TUsage              read FUsageParam          write FUsageParam;
    property UsagePageParam:      TUsage              read FUsagePageParam      write SetUsagePageParam;
    // the only event property
    property OnUnplug:            TJvHidUnplugEvent   read FUnplug              write SetUnplug;
  end;

  // controller class to manage all HID devices

  TJvHidDeviceController = class(TComponent)
  private
    // internal property part
    FHidGuid:           TGUID;
    FDeviceChangeEvent: TNotifyEvent;
    FDeviceChangeFired: Boolean;
    FEnumerateEvent:    TJvHidEnumerateEvent;
    FDevUnplugEvent:    TJvHidUnplugEvent;
    // internal list of all HID device objects
    FList:              TList;
    // internal worker functions
    function    CheckThisOut(var HidDev: TJvHidDevice; Index: Integer; Check: Boolean): Boolean;
    procedure   FillInList  (var List: TList);
    function    EventPipe   (var Msg: TMessage): Boolean;

  protected
    procedure Loaded; override;
    // internal property implementors
    procedure   DoDeviceChange;
    function    DoEnumerate         (HidDev: TJvHidDevice; Index: Integer): Boolean;
    procedure   SetDeviceChangeEvent(const value: TNotifyEvent);
    procedure   SetEnumerate        (const value: TJvHidEnumerateEvent);
    procedure   SetDevUnplug        (const value: TJvHidUnplugEvent);

  published
    // normal constructor/destructor
    constructor Create(AOwner: TComponent); override;
    destructor  Destroy;                    override;

    // methods to hand out HID device objects
    procedure   CheckIn              (var HidDev: TJvHidDevice);
    function    CheckOut             (var HidDev: TJvHidDevice):                       Boolean;
    function    CheckOutByClass      (var HidDev: TJvHidDevice; ClassName:   string):  Boolean;
    function    CheckOutByID         (var HidDev: TJvHidDevice; Vid, Pid:    Integer): Boolean;
    function    CheckOutByIndex      (var HidDev: TJvHidDevice; const Index: Integer): Boolean;
    function    CheckOutByProductName(var HidDev: TJvHidDevice; ProductName: string):  Boolean;
    function    CheckOutByVendorName (var HidDev: TJvHidDevice; VendorName:  string):  Boolean;
    // iterate over the HID devices
    function    Enumerate: Integer;

    // just to be complete the GUID
    property    HidGuid:        TGUID                read FHidGuid;
    // the central event for HID device changes
    property    OnDeviceChange: TNotifyEvent         read FDeviceChangeEvent write SetDeviceChangeEvent;
    // this event is copied to TJvHidDeviceOnUnplug on creation
    property    OnDeviceUnplug: TJvHidUnplugEvent    read FDevUnplugEvent    write SetDevUnplug;
    // the iterator event
    property    OnEnumerate:    TJvHidEnumerateEvent read FEnumerateEvent    write SetEnumerate;
  end;

procedure Register;

implementation

{$R HidControllerClass.dcr}
type
  EControllerError = class(Exception);

var
  GlobalInstanceCount: Integer = 0;

//== TJvHidDevice =====================================================

// get the registry path to the individual device info

function DevIDToHardWareKey(DevID: DWORD): string;
var
  reg: TRegistry;
begin
  reg := TRegistry.Create;
  reg.RootKey := HKEY_DYN_DATA;
  reg.OpenKeyReadOnly('Config Manager\Enum\' + Format('%.8x', [DevID]));
  DevIDToHardWareKey := reg.ReadString('HardWareKey');
  reg.Free;
end;

// get some static device info from the registry

function HardWareKeyToString(key: string; val: string): string;
var
  reg: TRegistry;
begin
  reg := TRegistry.Create;
  reg.RootKey := HKEY_LOCAL_MACHINE;
  reg.OpenKeyReadOnly('Enum\' + key);
  HardWareKeyToString := reg.ReadString(val);
  reg.Free;
end;

//-- TJvHidDevice: basics and internals -------------------------------

{
* create and fill in a HidDevice object
* the constructor is only accessible from TJvHidController
* DevicePath names the device "file"
* DevID is a handle (registry key from dynamic registry data) to the
* individual device (differs even for two devices of the same kind)
}

constructor TJvHidDevice.Create(DevicePath: string; DevID: DWORD; Unplug: TJvHidUnplugEvent);
var
  i:      Integer;
  len:    ULONG;
  ptr:    PHIDPLinkCollectionNode;
  buffer: array [0..256] of WideChar;
  ids:    array [0..258] of WORD;
  name:   array [0..256] of Char;
begin
  inherited Create;

  // initialize private data
  FMyController        := nil;
  FIsPluggedIn         := True;
  FIsCheckedOut        := False;
  FIsEnumerated        := False;
  FDevRegKey           := 0;
  FDevicePath          := DevicePath;
  FHardWareKey         := '';
  FRegDescr            := '';
  FRegClass            := '';
  FVendorName          := '';
  FProductName         := '';
  FSerialNumber        := '';
  FDeviceStrings       := TStringList.Create;
  FLanguageStrings     := TStringList.Create;
  FPreparsedData       := 0;
  FNumInputBuffers     := 0;
  FLinkCollection      := nil;
  FLinkCollectionNodes := nil;
  FMaxDataListLength   := 0;
  FMaxUsageListLength  := 0;
  FMaxButtonListLength := 0;
  FReportTypeParam     := HIDP_Input;
  FUsagePageParam      := 0;
  FLinkCollectionParam := 0;
  FUsageParam          := 0;
  FUnplug              := Unplug;

  FHidFileHandle := CreateFile(PChar(FDevicePath), GENERIC_READ or GENERIC_WRITE,
    FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
  if HidFileHandle <> INVALID_HANDLE_VALUE then
  begin
    // get all device data through HID functions
    // this eliminates the need to redeclare them as methods
    FDevRegKey   := DevID;
    FHardWareKey := DevIDToHardWareKey(DevID);
    FRegDescr    := HardWareKeyToString(FHardWareKey, 'DeviceDesc');
    FRegClass    := HardWareKeyToString(FHardWareKey, 'Class');
    FAttributes.Size := SizeOf(THIDDAttributes);
    HidD_GetPreparsedData(HidFileHandle, FPreparsedData);
    HidD_GetAttributes   (HidFileHandle, FAttributes);
    FConfiguration.cookie         := nil;
    FConfiguration.size           := 0;
    FConfiguration.RingBufferSize := 0;
    HidD_GetConfiguration(HidFileHandle, FConfiguration, SizeOf(THIDDConfiguration));
    HidP_GetCaps(FPreparsedData, FCaps);
    if HidD_GetManufacturerString(HidFileHandle, buffer, SizeOf(buffer)) then
      FVendorName := WideCharToString(buffer);
    if HidD_GetProductString(HidFileHandle, buffer, SizeOf(buffer)) then
      FProductName := WideCharToString(buffer);
    if HidD_GetSerialNumberString(HidFileHandle, buffer, SizeOf(buffer)) then
      FSerialNumber := WideCharToString(buffer);
    // put all device strings in a TStringList
    i := 1;
    while (i < 256) and HidD_GetIndexedString(HidFileHandle, i, buffer, SizeOf(buffer)) do
    begin
      FDeviceStrings.Add(WideCharToString(buffer));
      Inc(i);
    end;
    // calculate length of StringDescriptor 0
    ZeroMemory(@ids,SizeOf(ids));
    len := 0;
    for i := 0 to 256 do
    begin
      if HidD_GetIndexedString(HidFileHandle, 0, PWideChar(@ids), i*2) then
        Break;
      Inc(len);
    end;
    // transform id in localized language name
    for i := 0 to len-1 do
    begin
      name[0] := #0;
      GetLocaleInfo(ids[i],LOCALE_SLANGUAGE,name,SizeOf(name));
      FLanguageStrings.Add(name);
    end;
    // put all LinkCollectionNodes in a TList
    FLinkCollectionNodes := TList.Create;
    len := FCaps.NumberLinkCollectionNodes;
    GetMem(FLinkCollection, len*SizeOf(THIDPLinkCollectionNode));
    HidP_GetLinkCollectionNodes(FLinkCollection, len, FPreparsedData);
    ptr := FLinkCollection;
    for i := 1 to len do
    begin
      FLinkCollectionNodes.Add(ptr);
      ptr := PHIDPLinkCollectionNode((PChar(ptr)+SizeOf(THIDPLinkCollectionNode)));
    end;
  end;
  // the file is closed to stop using up resources
  CloseFile;
end;

{
* if a TJvHidDevice is destroyed the TJvHidController has to be informed
* if the device is plugged in this TJvHidDevice instance is destroyed
* but another instance is created in the controller list

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -