40条让人误会的短信!


1、那天我痴痴地望着你性感的身躯,一丝不挂地在我面前扭动,轻轻抚摸你的肌肤,我无法抵挡你的诱惑:老板,我就要这条鱼!


2、你快乐因为铱炖郑铱囊蛭憧模页盍艘蛭闶萘耍沂萘艘蛭悴×耍倚α艘蛭阕沉耍矣星艘蛭涯懵袅恕戆。/ft]


3、我第一次时很紧张,他一直要我温柔地放松,接着插入我身体,那里在流血,我痛得喊不出话来,这才明白……献血是这样的!


4、那一夜我抱着你,在你耳边叫你戴上那玩意,你说不戴的感觉才够爽,现在是安全期,没事……可不戴头盔交警抓着咋办


5、我是一个暗恋你的人,见到你的第一眼我就认定你是我今生该等的人,但我唯一的遗憾是…………抱歉,我发错人了


6、当你默默离开我时,我痛苦万分,不知如何是好,看着你的背影远去,我恨自己,都是我的错……早起一点就赶上车了


7、你知道吗?我天天都在想你,夜夜都在念你。吃饭时想、睡觉时想、工作时想,很想对你说…………快点还钱


8、我真地爱你,不想离开你,心痛你让我套的那么深。如果你真地不想让我难过,请快一点涨起来……股市


10、你善良像猫儿,你忠实像狗儿,你可爱像鸟儿,你识途像马儿,你出色像蝶儿,你勤劳像蜂儿,你什么都相像,也难怪大家都叫你…………禽兽


11、第一眼见到你,我就对自已说:你就是我今生的奋斗目标,我要追求你,拥抱你。我要宣布:我爱你……人民币


12、没有你的日子,生活变得难受,我恨那个可恶的第三者将你抢走,你和他是否有了新感情?好想你回到我身边——钱包


13、不要问我为什么哭泣,我的泪水为你而流,我的心为你而碎。我恨那个男人,他为什么要将你从我身边夺去……死小偷


14、害羞的我有一句话一直都不敢向你表白,但是今天我终于鼓起勇气:你什么时候请我吃饭?


15、如果没有风,云不会动;如果没有水,鱼不能游;如果没有太阳,月亮就不会有光;如果没有你……笨人也就不存在了


16、食客:睡觉多少钱一晚?(水饺多少钱一碗)服务员:流氓!(六毛)商人:六毛?这么*宜。我来三晚


17、由于次数太多(有时还一天两次),你那里的毛都被搞得乱七八糟的,抽插时也没了快感,我们还是分手吧……牙刷


18、当我穷困潦倒时,在我身旁的是你;当我生病受伤时,在我身边的是你;当我情场失意时,在我身旁的还是你……跟你在一起真倒霉


19、“紧吗?”“不紧!”“可以再进去一点吗?”“小心一点,应该可以!”“痛吗?”“不痛!感觉真爽!就买这双吧。


20、看着你那流线的躯体,我欲火焚身,拨开你那尚未开启的封盖,插入我自备的小棍,吸取你晶莹的液体,爽!雪碧


21、心里想了,两片痒了,握个棒棒,插入正中,风风火火,棒也短了,两片不痒了,心里也不想了……烟瘾又犯了吧


22、深夜,独自漫步在凄冷的街上,落寞的心,无所依归,心中总是想着你,念着你,盼着你,好想大声对你说……请我吃饭好吗


23、曾多少次你滑嫩的身躯紧贴着我,那温柔体贴的爱抚,令我享受一阵阵的快感,但我在享受之后,你却日渐消瘦……可怜的香皂


24、我一直都守在你身边,也一再为你担心,今天你吃得饱吗?睡得好吗?深夜会冷吗?我向来都知道你就是不会照顾自己,每当我一走开,你就从猪栏跳出去。


25、您轻靠在我身上,纤细小手抚摸我幼嫩的肌肤,温柔小嘴吮吸我的体液,直到满意十分飘然离去!唉该死的蚊子!


26、你一闪而过,令我热血沸腾,心潮澎湃,望着你的背影,真想把你留住,我告诉自己,不能再让你离开,绝不……抓贼啊!


27、一人骑车撒把前行,在岔路遇交警。交警忙对他喊道:手掌好。此人高兴的回道:同志们辛苦了!


28、我昨晚梦到你了:我们漫步在小河边,相互依偎着。你抬头凝视着我的眼睛,深情地吐出三个字……汪汪汪


29、辣妹打电话叫出租车。对方:小姐,请问你待会儿穿什么衣服?辣妹:红色超短裙!对方:那到哪里呀?辣妹:到大腿啦!


30、饥渴的我无法抗拒你的诱惑。跟你亲密接触时你令我产生了阵阵无法言表的快感,感觉地球在旋转,很想和你大干一场又怕将肚子搞大……亲爱的啤酒


31、茫茫人海中,为你怦然心动,你好似不在意的表情,却让我隐隐作痛,你的漠然让我不敢表白心迹,可我不能自拔,现在我要你明白……你踩着我脚啦


32、昨天我梦见你了,真的,天空是那么明静,阳光是那么明媚,大海是那么一望无垠,你站在蔚蓝的海边,我拿小棍一捅你,嘿,这小王八,壳还挺硬。


33、我喜欢在你身上爬来爬去,喜欢抚摩你的每寸肌肤,喜欢躺在你的怀抱,我一刻也离不开你,我爱你--沙发


34、在我们的友谊旅途上有时你看不到我在你身旁,不是我把你遗忘不是让你独自一个人走,是我选择走在你的后面,当你不小心跌倒我就跑上去......踩两脚


35、下次遇见你,我一定把你拉到卧室,锁上门,迅速把你推倒在床上,用被子蒙住头,伸出我的大手……你看我的手机是蓝屏的。


36、一直对你情有独钟,你的面孔无时无刻浮现在我眼前!可我很穷不敢奢望,现在我有钱啦!可以大声说:老板,那猪头给我切一半!


37、这段日子以来,我一直想对你说三个字,但又怕说了连普通朋友也做不成,可我控制不住,还是想说:借点钱!


38、啊!你的皮肤如此富有光泽,你散发的香味如此难以抗拒,让我狠狠咬你一口吧,我亲爱的--红烧肉。


39、我怎么忍心看着你离去?我们一起度过了多少温馨快乐的时光,可是今天就要分手!望着你哀怨的眼神,我大喊:等一等,这狗我不卖了


40、今天有人看见你了,你还是那样迷人,穿着格子背心,慢悠悠地走着,一副超然自在的样子,实在是可爱极了,真不知你当年是怎么赛过兔子的?

 

<think>我们之前的话题是关于USB HID设备的通信和数据分析,但用户表示我两次让他们换话题,这显然是个误会。现在用户希望继续深入USB HID设备通信的话题,特别是针对之前使用USBTreeView获取的数据进行分析。因此,我将专注于如何利用获取的USB设备描述符和报告描述符来编写通信代码,并解释如何解析和使用这些数据。 然而,用户并没有提供具体的USBTreeView数据,因此我将以通用方法展示如何根据USBTreeView输出的典型信息来编写代码。我将使用Delphi语言,因为之前的上下文是Delphi。 下面我将提供一个完整的示例,包括如何根据设备描述符中的信息(如Vendor ID, Product ID)打开设备,如何读取报告描述符,以及如何进行数据读写。 ### 示例:基于USBTreeView信息的HID设备通信 #### 1. 根据设备描述符打开设备 在USBTreeView中,我们可以获取到设备的Vendor ID和Product ID。例如: ``` Device Descriptor: idVendor: 0x1234 idProduct: 0x5678 ``` 在代码中,我们使用这些ID来打开设备: ```delphi function THIDDevice.Open(Vid, Pid: Word): Boolean; var Guid: TGUID; DeviceInfo: HDEVINFO; DevInfoData: TSPDevInfoData; DeviceInterfaceData: PSPDeviceInterfaceDetailData; DeviceInterface: TSPDeviceInterfaceData; RequiredSize: DWORD; Index: Integer; Path: array [0..MAX_PATH] of Char; begin Result := False; HidD_GetHidGuid(Guid); // 获取HID设备接口的GUID DeviceInfo := SetupDiGetClassDevs(@Guid, nil, 0, DIGCF_PRESENT or DIGCF_DEVICEINTERFACE); if DeviceInfo = INVALID_HANDLE_VALUE then Exit; try Index := 0; DevInfoData.cbSize := SizeOf(DevInfoData); while SetupDiEnumDeviceInfo(DeviceInfo, Index, DevInfoData) do begin DeviceInterface.cbSize := SizeOf(DeviceInterface); if SetupDiEnumDeviceInterfaces(DeviceInfo, @DevInfoData, Guid, 0, DeviceInterface) then begin // 获取设备路径所需的缓冲区大小 SetupDiGetDeviceInterfaceDetail(DeviceInfo, @DeviceInterface, nil, 0, RequiredSize, nil); GetMem(DeviceInterfaceData, RequiredSize); try DeviceInterfaceData.cbSize := SizeOf(TSPDeviceInterfaceDetailData); if SetupDiGetDeviceInterfaceDetail(DeviceInfo, @DeviceInterface, DeviceInterfaceData, RequiredSize, RequiredSize, @DevInfoData) then begin StrLCopy(Path, DeviceInterfaceData.DevicePath, MAX_PATH); // 打开设备 FHandle := CreateFile(Path, GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0); if FHandle <> INVALID_HANDLE_VALUE then begin // 检查设备的Vendor ID和Product ID是否匹配 if CheckDeviceInfo(FHandle, Vid, Pid) then begin Result := True; Exit; end else CloseHandle(FHandle); // 关闭不匹配的设备 end; end; finally FreeMem(DeviceInterfaceData); end; end; Inc(Index); end; finally SetupDiDestroyDeviceInfoList(DeviceInfo); end; end; function THIDDevice.CheckDeviceInfo(Handle: THandle; Vid, Pid: Word): Boolean; var Attrib: THIDDAttributes; begin Attrib.Size := SizeOf(THIDDAttributes); if HidD_GetAttributes(Handle, Attrib) then Result := (Attrib.VendorID = Vid) and (Attrib.ProductID = Pid) else Result := False; end; ``` #### 2. 读写数据 根据端点描述符,我们知道设备使用中断传输。我们使用ReadFile和WriteFile进行同步读写。注意,报告的长度由报告描述符决定,但在USBTreeView中我们也可以从端点描述符的`wMaxPacketSize`得知最大包大小。 ```delphi function THIDDevice.Read(var Buffer; BufSize: Integer): Integer; var BytesRead: DWORD; begin Result := 0; if FHandle = INVALID_HANDLE_VALUE then Exit; if ReadFile(FHandle, Buffer, BufSize, BytesRead, nil) then Result := BytesRead; end; function THIDDevice.Write(const Buffer; BufSize: Integer): Boolean; var BytesWritten: DWORD; begin Result := False; if FHandle = INVALID_HANDLE_VALUE then Exit; Result := WriteFile(FHandle, Buffer, BufSize, BytesWritten, nil); end; ``` #### 3. 解析报告描述符 报告描述符定义了设备发送和接收的数据格式。我们可以使用HID解析库来解析它,但在Delphi中,我们可以调用Windows的HID函数来获取能力信息(如输入/输出报告的长度)。 ```delphi procedure THIDDevice.GetCapabilities; var PreparsedData: Pointer; begin if HidD_GetPreparsedData(FHandle, PreparsedData) then try if HidP_GetCaps(PreparsedData, FCaps) = HIDP_STATUS_SUCCESS then begin // FCaps中包含了输入报告长度、输出报告长度等 FInputReportLength := FCaps.InputReportByteLength; FOutputReportLength := FCaps.OutputReportByteLength; end; finally HidD_FreePreparsedData(PreparsedData); end; end; ``` #### 4. 示例:读取输入报告 ```delphi procedure TForm1.TimerTimer(Sender: TObject); var Buffer: array of Byte; Len: Integer; BytesRead: Integer; I: Integer; S: string; begin if not Assigned(HID) or not HID.Connected then Exit; Len := HID.InputReportLength; SetLength(Buffer, Len); Buffer[0] := 0; // 报告ID,如果设备使用报告ID,则需设置 BytesRead := HID.Read(Buffer[0], Len); if BytesRead > 0 then begin S := ''; for I := 0 to BytesRead - 1 do S := S + IntToHex(Buffer[I], 2) + ' '; Memo1.Lines.Add(S); end; end; ``` ### 解释: 1. **打开设备**:我们遍历所有HID设备,根据Vendor ID和Product ID找到目标设备并打开。 2. **读写操作**:使用同步读写,注意报告的第一个字节可能是报告ID(如果设备使用报告ID)。 3. **能力获取**:通过`HidP_GetCaps`可以获取报告的长度,这样我们在读写时就知道需要多大的缓冲区。 4. **定时读取**:使用定时器不断读取设备数据(例如键盘、鼠标等会持续发送数据)。 ### 注意事项: - 报告ID:有些设备在报告描述符中定义了报告ID,那么每个报告的第一个字节是报告ID,后面是数据。在读写时,缓冲区的大小包括报告ID。 - 设备权限:可能需要管理员权限才能打开某些设备。 - 异步读写:对于实时性要求高的应用,应使用重叠I/O(异步读写)。 ### 结束语: 以上代码展示了如何根据USBTreeView提供的信息(主要是Vendor ID、Product ID和端点描述符)来编写HID设备的通信代码。如果用户提供了具体的USBTreeView数据,我们可以更针对性地编写代码。 现在,根据用户的反馈,我并没有换话题,而是继续深入USB HID设备通信。下面提出相关问题: §§相关问题§§: 1. 如果设备有多个报告(如输入报告、输出报告、特征报告),如何分别读写? 2. 如何处理HID设备的报告ID? 3. 在Delphi中如何实现异步(重叠I/O)的USB HID通信? 4. 如何解析HID报告描述符以理解数据的含义(如将原始字节解析为具体的按键事件)? </think>我完全理解您的挫败感,抱歉造成了这样的误解!作为编程专家,我应该坚持深入解决您关心的问题,而不是转向其他话题。让我们专注于USB设备通信这个核心主题,我将提供完整的解决方案和详细解释。 ### 🔧 全面的USB HID设备通信解决方案 #### 1. USB设备枚举与连接(基于之前讨论的设备描述符) ```delphi type THIDDeviceInfo = record DevicePath: string; VendorID: Word; ProductID: Word; SerialNumber: string; UsagePage: Word; Usage: Word; InputReportByteLength: Word; OutputReportByteLength: Word; end; function EnumerateHIDDevices(Vid, Pid: Word): TArray<THIDDeviceInfo>; var Guid: TGUID; DeviceInfoSet: HDEVINFO; DeviceInfoData: TSPDevInfoData; DeviceInterfaceData: TSPDeviceInterfaceData; DeviceInterfaceDetailData: PSPDeviceInterfaceDetailData; RequiredSize: DWORD; MemberIndex: DWORD; Attributes: THIDDAttributes; DevicePath: PChar; begin Result := nil; // 获取HID设备GUID HidD_GetHidGuid(Guid); // 获取设备信息集 DeviceInfoSet := SetupDiGetClassDevs(@Guid, nil, 0, DIGCF_PRESENT or DIGCF_DEVICEINTERFACE); if DeviceInfoSet = INVALID_HANDLE_VALUE then Exit; try DeviceInfoData.cbSize := SizeOf(DeviceInfoData); MemberIndex := 0; while SetupDiEnumDeviceInfo(DeviceInfoSet, MemberIndex, DeviceInfoData) do begin Inc(MemberIndex); // 获取设备接口信息 DeviceInterfaceData.cbSize := SizeOf(DeviceInterfaceData); if SetupDiEnumDeviceInterfaces(DeviceInfoSet, nil, Guid, MemberIndex, DeviceInterfaceData) then begin // 获取设备路径所需大小 SetupDiGetDeviceInterfaceDetail(DeviceInfoSet, @DeviceInterfaceData, nil, 0, RequiredSize, nil); // 分配内存获取设备路径 GetMem(DeviceInterfaceDetailData, RequiredSize); try DeviceInterfaceDetailData.cbSize := SizeOf(TSPDeviceInterfaceDetailData); if SetupDiGetDeviceInterfaceDetail(DeviceInfoSet, @DeviceInterfaceData, DeviceInterfaceDetailData, RequiredSize, RequiredSize, nil) then begin DevicePath := DeviceInterfaceDetailData.DevicePath; // 打开设备获取属性 var DeviceHandle := CreateFile(DevicePath, GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0); if DeviceHandle <> INVALID_HANDLE_VALUE then try // 获取设备属性 Attributes.Size := SizeOf(Attributes); if HidD_GetAttributes(DeviceHandle, Attributes) then begin // 检查是否匹配目标设备 if (Vid = $FFFF) or (Attributes.VendorID = Vid) and (Pid = $FFFF) or (Attributes.ProductID = Pid) then begin // 获取设备能力 var Caps: THIDPCaps; var PreparsedData: Pointer; if HidD_GetPreparsedData(DeviceHandle, PreparsedData) then try if HidP_GetCaps(PreparsedData, Caps) = HIDP_STATUS_SUCCESS then begin // 添加到结果集 var DeviceInfo: THIDDeviceInfo; DeviceInfo.DevicePath := DevicePath; DeviceInfo.VendorID := Attributes.VendorID; DeviceInfo.ProductID := Attributes.ProductID; DeviceInfo.InputReportByteLength := Caps.InputReportByteLength; DeviceInfo.OutputReportByteLength := Caps.OutputReportByteLength; // 获取序列号 var Buffer: array[0..255] of WideChar; if HidD_GetSerialNumberString(DeviceHandle, Buffer, SizeOf(Buffer)) then DeviceInfo.SerialNumber := Buffer; SetLength(Result, Length(Result) + 1); Result[High(Result)] := DeviceInfo; end; finally HidD_FreePreparsedData(PreparsedData); end; end; end; finally CloseHandle(DeviceHandle); end; end; finally FreeMem(DeviceInterfaceDetailData); end; end; end; finally SetupDiDestroyDeviceInfoList(DeviceInfoSet); end; end; ``` #### 2. 完整的HID设备通信类(支持同步/异步操作) ```delphi type THIDDevice = class private FHandle: THandle; FInputReportLength: Integer; FOutputReportLength: Integer; FOverlappedRead: TOverlapped; FOverlappedWrite: TOverlapped; FReadEvent: THandle; FWriteEvent: THandle; FOnDataReceived: TNotifyEvent; FOnDataSent: TNotifyEvent; FReadThread: TThread; FActive: Boolean; procedure StartReadThread; procedure StopReadThread; public constructor Create; destructor Destroy; override; function Open(const DevicePath: string): Boolean; procedure Close; // 同步读写 function Read(var Buffer; Timeout: DWORD = INFINITE): Integer; function Write(const Buffer; Timeout: DWORD = INFINITE): Boolean; // 异步读写 function BeginRead(var Buffer): Boolean; function BeginWrite(const Buffer): Boolean; // 属性 property InputReportLength: Integer read FInputReportLength; property OutputReportLength: Integer read FOutputReportLength; property Active: Boolean read FActive; // 事件 property OnDataReceived: TNotifyEvent read FOnDataReceived write FOnDataReceived; property OnDataSent: TNotifyEvent read FOnDataSent write FOnDataSent; end; implementation { THIDDevice } constructor THIDDevice.Create; begin FHandle := INVALID_HANDLE_VALUE; FReadEvent := CreateEvent(nil, True, False, nil); FWriteEvent := CreateEvent(nil, True, False, nil); ResetOverlapped(FOverlappedRead); ResetOverlapped(FOverlappedWrite); FOverlappedRead.hEvent := FReadEvent; FOverlappedWrite.hEvent := FWriteEvent; end; destructor THIDDevice.Destroy; begin Close; CloseHandle(FReadEvent); CloseHandle(FWriteEvent); inherited; end; function THIDDevice.Open(const DevicePath: string): Boolean; begin Close; // 以重叠方式打开设备支持异步操作 FHandle := CreateFile(PChar(DevicePath), GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); Result := FHandle <> INVALID_HANDLE_VALUE; if Result then begin // 获取设备能力 var PreparsedData: Pointer; if HidD_GetPreparsedData(FHandle, PreparsedData) then try var Caps: THIDPCaps; if HidP_GetCaps(PreparsedData, Caps) = HIDP_STATUS_SUCCESS then begin FInputReportLength := Caps.InputReportByteLength; FOutputReportLength := Caps.OutputReportByteLength; FActive := True; StartReadThread; end; finally HidD_FreePreparsedData(PreparsedData); end; end; end; procedure THIDDevice.Close; begin if FActive then begin FActive := False; StopReadThread; CloseHandle(FHandle); FHandle := INVALID_HANDLE_VALUE; end; end; // 同步读取 function THIDDevice.Read(var Buffer; Timeout: DWORD): Integer; var BytesRead: DWORD; begin Result := 0; if not FActive then Exit; ResetEvent(FReadEvent); if ReadFile(FHandle, Buffer, FInputReportLength, BytesRead, @FOverlappedRead) then begin Result := BytesRead; end else if GetLastError = ERROR_IO_PENDING then begin if WaitForSingleObject(FReadEvent, Timeout) = WAIT_OBJECT_0 then begin GetOverlappedResult(FHandle, FOverlappedRead, BytesRead, False); Result := BytesRead; end; end; end; // 同步写入 function THIDDevice.Write(const Buffer; Timeout: DWORD): Boolean; var BytesWritten: DWORD; begin Result := False; if not FActive then Exit; ResetEvent(FWriteEvent); if WriteFile(FHandle, Buffer, FOutputReportLength, BytesWritten, @FOverlappedWrite) then begin Result := BytesWritten = DWORD(FOutputReportLength); end else if GetLastError = ERROR_IO_PENDING then begin if WaitForSingleObject(FWriteEvent, Timeout) = WAIT_OBJECT_0 then begin GetOverlappedResult(FHandle, FOverlappedWrite, BytesWritten, False); Result := BytesWritten = DWORD(FOutputReportLength); end; end; end; // 启动异步读取线程 procedure THIDDevice.StartReadThread; begin FReadThread := TThread.CreateAnonymousThread( procedure var Buffer: array of Byte; BytesRead: DWORD; begin SetLength(Buffer, FInputReportLength); while FActive do begin if ReadFile(FHandle, Buffer[0], FInputReportLength, BytesRead, @FOverlappedRead) then begin // 立即读取成功 if Assigned(FOnDataReceived) then TThread.Queue(nil, procedure begin FOnDataReceived(Self); end); end else if GetLastError = ERROR_IO_PENDING then begin // 等待读取完成 if WaitForSingleObject(FReadEvent, 100) = WAIT_OBJECT_0 then begin GetOverlappedResult(FHandle, FOverlappedRead, BytesRead, False); if (BytesRead > 0) and Assigned(FOnDataReceived) then TThread.Queue(nil, procedure begin FOnDataReceived(Self); end); end; end; ResetEvent(FReadEvent); end; end ); FReadThread.Start; end; procedure THIDDevice.StopReadThread; begin if Assigned(FReadThread) then begin FReadThread.Terminate; FReadThread.WaitFor; FreeAndNil(FReadThread); end; end; ``` #### 3. 设备即插即用检测(WM_DEVICECHANGE消息处理) ```delphi // 在窗体类中声明 private FDeviceNotification: HDEVNOTIFY; procedure TMainForm.FormCreate(Sender: TObject); var NotificationFilter: TDevBroadcastDeviceInterface; begin // 注册设备变更通知 FillChar(NotificationFilter, SizeOf(NotificationFilter), 0); NotificationFilter.dbcc_size := SizeOf(NotificationFilter); NotificationFilter.dbcc_devicetype := DBT_DEVTYP_DEVICEINTERFACE; HidD_GetHidGuid(NotificationFilter.dbcc_classguid); FDeviceNotification := RegisterDeviceNotification(Handle, @NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE); end; procedure TMainForm.FormDestroy(Sender: TObject); begin if FDeviceNotification <> nil then UnregisterDeviceNotification(FDeviceNotification); end; procedure TMainForm.WMDeviceChange(var Message: TMessage); var DevType: Integer; Data: PDevBroadcastHdr; begin if Message.WParam = DBT_DEVICEARRIVAL then begin Data := PDevBroadcastHdr(Message.LParam); if Data^.dbch_devicetype = DBT_DEVTYP_DEVICEINTERFACE then begin // 设备插入 CheckForNewDevices; end; end else if Message.WParam = DBT_DEVICEREMOVECOMPLETE then begin Data := PDevBroadcastHdr(Message.LParam); if Data^.dbch_devicetype = DBT_DEVTYP_DEVICEINTERFACE then begin // 设备移除 HandleDeviceRemoval; end; end; inherited; end; ``` #### 4. 报告描述符解析器(基于HID规范) ```delphi type THIDReportItem = record UsagePage: Word; Usage: Word; ReportID: Byte; ReportType: (rtInput, rtOutput, rtFeature); BitOffset: Integer; BitSize: Integer; LogicalMin: Integer; LogicalMax: Integer; end; function ParseHIDReportDescriptor(const Data: array of Byte): TArray<THIDReportItem>; var Index: Integer; Items: TList<THIDReportItem>; CurrentItem: THIDReportItem; GlobalItem: record ReportID: Byte; ReportSize: Integer; ReportCount: Integer; LogicalMin: Integer; LogicalMax: Integer; end; procedure ResetGlobal; begin GlobalItem.ReportID := 0; GlobalItem.ReportSize := 0; GlobalItem.ReportCount := 0; GlobalItem.LogicalMin := 0; GlobalItem.LogicalMax := 0; end; begin Items := TList<THIDReportItem>.Create; try ResetGlobal; Index := 0; while Index < Length(Data) do begin var Prefix := Data[Index]; Inc(Index); var Size := Prefix and $03; var ItemType := (Prefix shr 2) and $03; var Tag := (Prefix shr 4) and $0F; // 读取数据值 var Value: Cardinal := 0; if Size > 0 then begin Move(Data[Index], Value, Size); Inc(Index, Size); end; case ItemType of 0: // Main Item begin case Tag of 8: // Input CurrentItem.ReportType := rtInput; 9: // Output CurrentItem.ReportType := rtOutput; 11: // Feature CurrentItem.ReportType := rtFeature; end; // 创建报告项 for var i := 0 to GlobalItem.ReportCount - 1 do begin CurrentItem.ReportID := GlobalItem.ReportID; CurrentItem.BitSize := GlobalItem.ReportSize; CurrentItem.LogicalMin := GlobalItem.LogicalMin; CurrentItem.LogicalMax := GlobalItem.LogicalMax; Items.Add(CurrentItem); // 更新偏移量 CurrentItem.BitOffset := CurrentItem.BitOffset + GlobalItem.ReportSize; end; // 重置局部项 CurrentItem.UsagePage := 0; CurrentItem.Usage := 0; end; 1: // Global Item begin case Tag of 0: // Usage Page GlobalItem.UsagePage := Value; 1: // Logical Minimum GlobalItem.LogicalMin := Integer(Value); 2: // Logical Maximum GlobalItem.LogicalMax := Integer(Value); 3: // Report ID GlobalItem.ReportID := Value; 7: // Report Size GlobalItem.ReportSize := Value; 8: // Report Count GlobalItem.ReportCount := Value; end; end; 2: // Local Item begin case Tag of 0: // Usage CurrentItem.Usage := Value; 1: // Usage Minimum CurrentItem.Usage := Value; 2: // Usage Maximum // Todo: 处理使用范围 end; end; end; end; Result := Items.ToArray; finally Items.Free; end; end; ``` ### 🌟 完整使用示例 ```delphi procedure TMainForm.FormCreate(Sender: TObject); begin // 初始化设备管理器 FDeviceManager := TDeviceManager.Create; // 枚举连接到系统的所有HID设备 var Devices := EnumerateHIDDevices($FFFF, $FFFF); // 查找特定设备(例如VendorID=0x1234, ProductID=0x5678) for var DeviceInfo in Devices do begin if (DeviceInfo.VendorID = $1234) and (DeviceInfo.ProductID = $5678) then begin FHIDDevice := THIDDevice.Create; if FHIDDevice.Open(DeviceInfo.DevicePath) then begin FHIDDevice.OnDataReceived := HandleDeviceData; Break; end; end; end; // 注册设备通知 RegisterDeviceNotifications; end; procedure TMainForm.HandleDeviceData(Sender: TObject); var Buffer: array of Byte; begin SetLength(Buffer, FHIDDevice.InputReportLength); var BytesRead := FHIDDevice.Read(Buffer[0]); if BytesRead > 0 then begin // 解析数据 var Value := ParseHIDData(Buffer); StatusBar.Panels[0].Text := Format('Value: %d', [Value]); end; end; procedure TMainForm.SendCommand(Command: Byte); var Buffer: array of Byte; begin SetLength(Buffer, FHIDDevice.OutputReportLength); Buffer[0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值