📄 hidcontrollerclass.pas
字号:
unit HidControllerClass;
interface
uses
Windows, Messages, Classes, Forms, SysUtils,
DBT, SetupAPI, Hid;
const
// strings from the registry for CheckOutByClass
cHidKeyboardClass = 'Keyboard';
cHidMouseClass = 'Mouse';
cHidNoClass = 'HIDClass';
type
// forward declarations
TJvHidDeviceController = class;
TJvHidDevice = class;
// the Event function declarations
TJvHidEnumerateEvent = function (HidDev: TJvHidDevice; Idx: 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;
FHidOverlappedHandle: THandle;
// internal properties part
FDeviceID: DWORD;
FDevicePath: string;
FRegDescr: string;
FRegClass: string;
FVendorName: AnsiString;
FProductName: AnsiString;
FPhysicalDescriptor: AnsiString;
FSerialNumber: AnsiString;
FLanguageStrings: TStringList;
FPreparsedData: PHIDPPreparsedData;
FAttributes: THIDDAttributes;
FCaps: THIDPCaps;
FConfiguration: THIDDConfiguration;
FNumInputBuffers: Integer;
FNumOverlappedBuffers: Integer;
FLinkCollection: array of THIDPLinkCollectionNode;
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;
procedure GetMax;
// internal property implementors
function GetDeviceString (Idx: Byte): string;
function GetLinkCollectionNode (Idx: WORD): THIDPLinkCollectionNode;
procedure SetConfiguration (Config: THIDDConfiguration);
procedure SetNumInputBuffers (const Num: Integer);
procedure SetNumOverlappedBuffers(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(const DevicePath: string; const DevID: DWORD;
const DevDesc, ClassDesc: string;
Controller: TJvHidDeviceController);
protected
// internal property implementors
procedure DoUnplug;
procedure SetUnplug(const Event: TJvHidUnplugEvent);
public
// indexed properties
property DeviceStrings [Idx: Byte]: string read GetDeviceString;
property LinkCollectionNodes[Idx: WORD]: THIDPLinkCollectionNode read GetLinkCollectionNode;
published
destructor Destroy; override;
// methods
procedure CloseFile;
procedure CloseFileEx;
function DeviceIoControl (IoControlCode: DWORD; InBuffer: Pointer; InSize: DWORD;
OutBuffer: Pointer; OutSize: DWORD;
var BytesReturned: DWORD): Boolean;
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 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 OpenFileEx: 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 ReadFileEx (var Report; ToRead: DWORD;
CallBack: TPROverlappedCompletionRoutine): Boolean;
function WriteFile (var Report; ToWrite: DWORD; var BytesWritten: DWORD): Boolean;
function WriteFileEx (var Report; ToWrite: DWORD;
CallBack: TPROverlappedCompletionRoutine): 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 DeviceID: DWORD read FDeviceID;
property HidFileHandle: THandle read FHidFileHandle;
property HidOverlappedHandle: THandle read FHidOverlappedHandle;
property IsCheckedOut: Boolean read FIsCheckedOut;
property IsPluggedIn: Boolean read FIsPluggedIn;
property LanguageStrings: TStringList read FLanguageStrings;
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 NumOverlappedBuffers: Integer read FNumOverlappedBuffers write SetNumOverlappedBuffers;
property PhysicalDescriptor: string read FPhysicalDescriptor;
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 properties part
FHidGuid: TGUID;
FDeviceChangeEvent: TNotifyEvent;
FDeviceChangeFired: Boolean;
FEnumerateEvent: TJvHidEnumerateEvent;
FDevUnplugEvent: TJvHidUnplugEvent;
// internal list of all HID device objects
FList: TList;
// counters for the list
FNumCheckedInDevices: Integer;
FNumCheckedOutDevices: Integer;
FNumUnpluggedDevices: Integer;
// internal worker functions
function CheckThisOut(var HidDev: TJvHidDevice; Idx: 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; Idx: Integer): Boolean;
procedure SetDeviceChangeEvent(const Notifier: TNotifyEvent);
procedure SetEnumerate (const Enumerator: TJvHidEnumerateEvent);
procedure SetDevUnplug (const Unplugger: 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 Idx: 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;
property NumCheckedInDevices: Integer read FNumCheckedInDevices;
property NumCheckedOutDevices: Integer read FNumCheckedOutDevices;
property NumUnpluggedDevices: Integer read FNumUnpluggedDevices;
// 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;
// the central event for HID device changes
property OnDeviceChange: TNotifyEvent read FDeviceChangeEvent write SetDeviceChangeEvent;
end;
// helpers to check the HID function and method results
function HidCheck(const RetVal: NTSTATUS): NTSTATUS; overload;
function HidCheck(const RetVal: LongBool): LongBool; overload;
function HidError(const RetVal: NTSTATUS): NTSTATUS;
// to register the component in the palette
procedure Register;
implementation
{$R HidControllerClass.dcr}
type
EControllerError = class(Exception);
EHidClientError = class(Exception);
var
// counter to prevent a second TJvHidDeviceController instance
GlobalInstanceCount: Integer = 0;
//== these are declared inconsistent in Windows.pas ===================
function ReadFileEx(hFile: THandle; var Buffer; nNumberOfBytesToRead: DWORD;
var Overlapped: TOverlapped; lpCompletionRoutine: TPROverlappedCompletionRoutine): BOOL; stdcall;
external 'kernel32.dll' name 'ReadFileEx';
function WriteFileEx(hFile: THandle; var Buffer; nNumberOfBytesToWrite: DWORD;
var Overlapped: TOverlapped; lpCompletionRoutine: TPROverlappedCompletionRoutine): BOOL; stdcall;
external 'kernel32.dll' name 'WriteFileEx';
//== TJvHidDevice =====================================================
// internal helper to read string values from a devices registry area
function GetRegistryProperty(PnPHandle: HDEVINFO; var DevData: TSPDevInfoData; ClassID: DWORD): string;
var
BytesReturned: DWORD;
RegData: DWORD;
Buffer: array [0..256] of Char;
begin
BytesReturned := 0;
RegData := REG_SZ;
Buffer[0] := #0;
SetupDiGetDeviceRegistryProperty(PnPHandle, DevData, ClassID,
@RegData, @Buffer[0], SizeOf(Buffer), @BytesReturned);
Result := Buffer;
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 to the individual device
// (differs even for two devices of the same kind)
// DevDesc and ClassDesc are two strings from the devices registry space
// Controller is the devices controller object
constructor TJvHidDevice.Create(const DevicePath: string; const DevID: DWORD;
const DevDesc, ClassDesc: string; Controller: TJvHidDeviceController);
var
I: Integer;
Len: ULONG;
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 := Controller;
FIsPluggedIn := True;
FIsCheckedOut := False;
FIsEnumerated := False;
FHidOverlappedHandle := INVALID_HANDLE_VALUE;
FDeviceID := 0;
FDevicePath := DevicePath;
FRegDescr := '';
FRegClass := '';
FVendorName := '';
FProductName := '';
FPhysicalDescriptor := '';
FSerialNumber := '';
FLanguageStrings := TStringList.Create;
FPreparsedData := 0;
FillChar(FCaps, SizeOf(FCaps), #0);
FillChar(FConfiguration, SizeOf(FConfiguration), #0);
FNumInputBuffers := 0;
FNumOverlappedBuffers := 0;
SetLength(FLinkCollection, 0);
FMaxDataListLength := 0;
FMaxUsageListLength := 0;
FMaxButtonListLength := 0;
FReportTypeParam := HIDP_Input;
FUsagePageParam := 0;
FLinkCollectionParam := 0;
FUsageParam := 0;
FUnplug := Controller.FDevUnplugEvent;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -