📄 jvhidcontrollerclass.pas
字号:
FMaxDataListLength := 0;
FMaxUsageListLength := 0;
FMaxButtonListLength := 0;
FReportTypeParam := HIDP_Input;
FThreadSleepTime := 100;
FUsagePageParam := 0;
FLinkCollectionParam := 0;
FUsageParam := 0;
FDataThread := nil;
OnData := Controller.OnDeviceData;
OnUnplug := Controller.OnDeviceUnplug;
FHidFileHandle := CreateFile(PChar(PnPInfo.DevicePath), GENERIC_READ or GENERIC_WRITE,
FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
FHasReadWriteAccess := HidFileHandle <> INVALID_HANDLE_VALUE;
// Win2000 hack
if not HasReadWriteAccess then
FHidFileHandle := CreateFile(PChar(PnPInfo.DevicePath), 0,
FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
if HidFileHandle <> INVALID_HANDLE_VALUE then
begin
FAttributes.Size := SizeOf(THIDDAttributes);
if not HidD_GetAttributes(HidFileHandle, FAttributes) then
raise EControllerError.CreateRes(@RsEDeviceCannotBeIdentified);
end
else
raise EControllerError.CreateRes(@RsEDeviceCannotBeOpened);
// 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 to replace it.
destructor TJvHidDevice.Destroy;
var
I: Integer;
TmpOnData: TJvHidDataEvent;
TmpOnUnplug: TJvHidUnplugEvent;
Dev: TJvHidDevice;
begin
// if we need to clone the object
TmpOnData := OnData;
TmpOnUnplug := OnUnplug;
// to prevent strange problems
OnData := nil;
OnUnplug := nil;
// free the data which needs special handling
CloseFile;
CloseFileEx(omhRead);
CloseFileEx(omhWrite);
if FPreparsedData <> nil then
HidD_FreePreparsedData(FPreparsedData);
FLanguageStrings.Free;
// if controller exists
if FMyController <> nil then
with FMyController do
begin
// delete device from controller list
for I := 0 to FList.Count - 1 do
if FList.Items[I] = Self then
begin
// if device is plugged in create a checked in copy
if IsPluggedIn then
begin
Dev := TJvHidDevice.CtlCreate(FPnPInfo, FMyController);
// make it a complete clone
Dev.OnData := TmpOnData;
Dev.OnUnplug := TmpOnUnplug;
Dev.ThreadSleepTime := ThreadSleepTime;
FList.Items[I] := Dev;
// the FPnPInfo has been handed over to the new object
FPnPInfo := nil;
if IsCheckedOut then
begin
Dec(FNumCheckedOutDevices);
Inc(FNumCheckedInDevices);
end;
end
else
begin
FList.Delete(I);
Dec(FNumUnpluggedDevices);
end;
Break;
end;
end;
PnPInfo.Free;
inherited Destroy;
end;
// if check changes change check only here
function TJvHidDevice.IsAccessible: Boolean;
begin
Result := IsPluggedIn and (IsCheckedOut or FIsEnumerated);
end;
// open the device "file" (for the other methods)
function TJvHidDevice.OpenFile: Boolean;
begin
// check if open allowed (propagates this state)
if IsAccessible then
if HidFileHandle = INVALID_HANDLE_VALUE then // if not already opened
begin
FHidFileHandle := CreateFile(PChar(PnPInfo.DevicePath), GENERIC_READ or GENERIC_WRITE,
FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
FHasReadWriteAccess := HidFileHandle <> INVALID_HANDLE_VALUE;
// Win2000 hack
if not HasReadWriteAccess then
FHidFileHandle := CreateFile(PChar(PnPInfo.DevicePath), 0,
FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
if HidFileHandle <> INVALID_HANDLE_VALUE then
begin
if NumInputBuffers <> 0 then
HidD_SetNumInputBuffers(HidFileHandle, NumInputBuffers);
HidD_GetNumInputBuffers(HidFileHandle, FNumInputBuffers);
end;
end;
Result := HidFileHandle <> INVALID_HANDLE_VALUE;
end;
// open second device "file" for ReadFileEx and WriteFileEx
function TJvHidDevice.OpenFileEx(Mode: TJvHidOpenExMode): Boolean;
begin
Result := False;
// check if open allowed (propagates this state)
if IsAccessible then
if Mode = omhRead then
begin
if HidOverlappedRead = INVALID_HANDLE_VALUE then // if not already opened
begin
FHidOverlappedRead := CreateFile(PChar(PnPInfo.DevicePath), GENERIC_READ,
FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
if FHidOverlappedRead <> INVALID_HANDLE_VALUE then
begin
if NumOverlappedBuffers <> 0 then
HidD_SetNumInputBuffers(FHidOverlappedRead, NumOverlappedBuffers);
HidD_GetNumInputBuffers(FHidOverlappedRead, FNumOverlappedBuffers);
end;
end;
Result := FHidOverlappedRead <> INVALID_HANDLE_VALUE;
end
else
begin
if HidOverlappedWrite = INVALID_HANDLE_VALUE then // if not already opened
FHidOverlappedWrite := CreateFile(PChar(PnPInfo.DevicePath), GENERIC_WRITE,
FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
Result := FHidOverlappedWrite <> INVALID_HANDLE_VALUE;
end;
end;
// implement OnUnplug event
procedure TJvHidDevice.DoUnplug;
begin
CloseFile;
CloseFileEx(omhRead);
CloseFileEx(omhWrite);
FIsPluggedIn := False;
// event even for checked in devices
if Assigned(FUnplug) then
FUnplug(Self);
// guarantees that event is only called once
OnUnplug := nil;
end;
// implementing indexed properties read
function TJvHidDevice.GetDeviceStringAnsi(Idx: Byte): string;
begin
Result := WideCharToString(PWideChar(GetDeviceStringUnicode(Idx)));
end;
function TJvHidDevice.GetDeviceStringUnicode(Idx: Byte): WideString;
var
Buffer: array [0..253] of WideChar;
begin
Result := '';
if Idx <> 0 then
if OpenFile then
if HidD_GetIndexedString(HidFileHandle, Idx, Buffer, SizeOf(Buffer)) then
Result := Buffer;
end;
function TJvHidDevice.GetLinkCollectionNode(Idx: WORD): THIDPLinkCollectionNode;
var
Siz: ULONG;
begin
if Length(FLinkCollection) = 0 then
begin
Siz := Caps.NumberLinkCollectionNodes;
SetLength(FLinkCollection, Siz);
HidP_GetLinkCollectionNodes(@FLinkCollection[0], Siz, PreparsedData);
end;
FillChar(Result, SizeOf(THIDPLinkCollectionNode), #0);
if Idx < Length(FLinkCollection) then
Result := FLinkCollection[Idx];
end;
// implementing properties write
procedure TJvHidDevice.SetNumInputBuffers(const Num: Integer);
begin
if (Num <> FNumInputBuffers) and OpenFile then
begin
HidD_SetNumInputBuffers(HidFileHandle, Num);
HidD_GetNumInputBuffers(HidFileHandle, FNumInputBuffers);
end;
end;
procedure TJvHidDevice.SetNumOverlappedBuffers(const Num: Integer);
begin
if (Num <> FNumOverlappedBuffers) and OpenFileEx(omhRead) then
begin
HidD_SetNumInputBuffers(HidOverlappedRead, Num);
HidD_GetNumInputBuffers(HidOverlappedRead, FNumOverlappedBuffers);
end;
end;
// internal helper for the following functions
procedure TJvHidDevice.GetMax;
begin
if IsAccessible then
begin
FMaxDataListLength := HidP_MaxDataListLength(ReportTypeParam, PreparsedData);
FMaxUsageListLength := HidP_MaxUsageListLength(ReportTypeParam, UsagePageParam, PreparsedData);
FMaxButtonListLength := HidP_MaxButtonListLength(ReportTypeParam, UsagePageParam, PreparsedData);
end;
end;
procedure TJvHidDevice.SetReportTypeParam(const ReportType: THIDPReportType);
begin
FReportTypeParam := ReportType;
GetMax;
end;
procedure TJvHidDevice.SetThreadSleepTime(const SleepTime: Integer);
begin
// limit to 10 msec .. 10 sec
if (SleepTime >= 10) and (SleepTime <= 10000) then
FThreadSleepTime := SleepTime;
end;
procedure TJvHidDevice.SetUsagePageParam(const UsagePage: TUsage);
begin
FUsagePageParam := UsagePage;
GetMax;
end;
function TJvHidDevice.GetConfiguration: THIDDConfiguration;
begin
Result.cookie := nil;
Result.size := 0;
Result.RingBufferSize := 0;
if OpenFile then
HidD_GetConfiguration(HidFileHandle, Result, SizeOf(THIDDConfiguration));
end;
function TJvHidDevice.GetPreparsedData: PHIDPPreparsedData;
begin
if FPreparsedData = nil then
if OpenFile then
begin
HidD_GetPreparsedData(HidFileHandle, FPreparsedData);
CloseFile;
end;
Result := FPreparsedData;
end;
function TJvHidDevice.GetCaps: THIDPCaps;
begin
FillChar(Result, SizeOf(THIDPCaps), #0);
HidP_GetCaps(PreparsedData, Result);
end;
function TJvHidDevice.GetVendorName: WideString;
var
Buffer: array [0..253] of WideChar;
begin
if FVendorName = '' then
if OpenFile then
begin
FillChar(Buffer, SizeOf(Buffer), #0);
if HidD_GetManufacturerString(HidFileHandle, Buffer, SizeOf(Buffer)) then
FVendorName := Buffer;
CloseFile;
end;
Result := FVendorName;
end;
function TJvHidDevice.GetProductName: WideString;
var
Buffer: array [0..253] of WideChar;
begin
if FProductName = '' then
if OpenFile then
begin
FillChar(Buffer, SizeOf(Buffer), #0);
if HidD_GetProductString(HidFileHandle, Buffer, SizeOf(Buffer)) then
FProductName := Buffer;
CloseFile;
end;
Result := FProductName;
end;
function TJvHidDevice.GetSerialNumber: WideString;
var
I: Integer;
Len: Integer;
IDs: array [0..253] of WORD;
Buffer: array [0..253] of WideChar;
begin
if FSerialNumber = '' then
if OpenFile then
begin
FillChar(Buffer, SizeOf(Buffer), #0);
if HidD_GetSerialNumberString(HidFileHandle, Buffer, SizeOf(Buffer)) then
begin
// calculate length of StringDescriptor 0
FillChar(IDs, SizeOf(IDs), $FF);
Len := 0;
HidD_GetIndexedString(HidFileHandle, 0, PWideChar(@IDs), SizeOf(IDs));
for I := High(IDs) downto 0 do
if IDs[I] <> $FFFF then
begin
if IDs[I] = 0 then
Len := I
else
Len := I + 1;
Break;
end;
// compensate for buggy function
for I := 0 to Len - 1 do
if IDs[I] <> WORD(Buffer[I]) then
begin
FSerialNumber := Buffer;
Break;
end;
end;
CloseFile;
end;
Result := FSerialNumber;
end;
function TJvHidDevice.GetPhysicalDescriptor: TJvPhysicalDescriptor;
var
I: Integer;
begin
if Length(FPhysicalDescriptor) = 0 then
if OpenFile then
begin
I := 0;
SetLength(FPhysicalDescriptor, 2048);
while not HidD_GetPhysicalDescriptor(HidFileHandle, FPhysicalDescriptor[0], I * SizeOf(WORD)) do
begin
Inc(I);
if (I > 2048) or (GetLastError <> ERROR_INSUFFICIENT_BUFFER) then
begin
I := 0;
Break;
end;
end;
SetLength(FPhysicalDescriptor, I);
CloseFile;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -