修复键盘hid偶尔无法连上问题 dev
authorliangzhenying <867174124@qq.com>
Wed, 25 Jun 2025 04:29:03 +0000 (12:29 +0800)
committerliangzhenying <867174124@qq.com>
Wed, 25 Jun 2025 04:29:03 +0000 (12:29 +0800)
.gitignore
MouseSdk/AiMouseSdk/Manager/DeviceManger.m
MouseSdk/AiMouseSdk/Manager/HidManager.m
MouseSdk/MouseSdk.xcworkspace/xcuserdata/yaozuopan.xcuserdatad/UserInterfaceState.xcuserstate
MouseSdk/MouseSdk.xcworkspace/xcuserdata/yaozuopan.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
MouseSdk/Pods/Pods.xcodeproj/xcuserdata/yaozuopan.xcuserdatad/xcschemes/xcschememanagement.plist

index d3c3d5b..bd5fb6b 100644 (file)
@@ -5,4 +5,65 @@ MouseSdk_Demo
 MouseSdk/AiSdk/ffmpeg
 
 Demo/MouseSdk/libAiMouseManager
-Demo
\ No newline at end of file
+Demo
+
+# Xcode
+#
+# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
+
+## Build generated
+build/
+DerivedData/
+
+## Various settings
+*.pbxuser
+!default.pbxuser
+*.mode1v3
+!default.mode1v3
+*.mode2v3
+!default.mode2v3
+*.perspectivev3
+!default.perspectivev3
+xcuserdata/
+
+## Other
+*.moved-aside
+*.xccheckout
+*.xcscmblueprint
+
+## Obj-C/Swift specific
+*.hmap
+*.ipa
+*.dSYM.zip
+*.dSYM
+
+# CocoaPods
+#
+# We recommend against adding the Pods directory to your .gitignore. However
+# you should judge for yourself, the pros and cons are mentioned at:
+# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
+#
+## 自定义不要上传的文件
+#Pods/
+.DS_Store
+
+# Carthage
+#
+# Add this line if you want to avoid checking in source code from Carthage dependencies.
+# Carthage/Checkouts
+
+Carthage/Build
+
+# fastlane
+#
+# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
+# screenshots whenever they are needed.
+# For more information about the recommended setup visit:
+# https://docs.fastlane.tools/best-practices/source-control/#source-control
+
+MixSdk_iOS/
+
+# Code Injection
+#
+# After new code Injection tools there's a generated folder /iOSInjectionProject
+# https://github.com/johnno1962/injectionforxcode
\ No newline at end of file
index 55b4669..d8c1f71 100644 (file)
     };
     self.hid.receiveInfoDataCallBack = ^(NSData *data) {
         if (ws.isConneted == false) {
-            [ws.hid closeHid];
-            [ws.hid openHid];
+//            [ws.hid closeHid];
+//            [ws.hid openHid];
             return;
         }
         if (ws.productType == AiMouseProductType_n) {
         self.aiMouseConnectStateDidChangeCallBack(self.kbSdk.connectType == AiMouseConnectType_bluetooth ? 0:1,connected);
     }
     if(self.authCallBack && connected)self.authCallBack(connected);
+    if (connected == false) {
+        [self.hid closeHid];
+    }
 }
 
 
         [self.hid writeToDevice:data];
     }
 }
-
+ 
 /// 鼠标按键指令回调
 - (void)keyboardSendCmdData:(NSData *)data{
     uint8 cmd;
index 3935125..edf8d74 100644 (file)
@@ -47,7 +47,7 @@
 /// 匹配到设备回调
 static void hidAppearDevice(void *inContext,IOReturn inResult,void *inSender,IOHIDDeviceRef deviceRef) {
     if ([DeviceManger shared].isConneted) {
-        //        [[HidManager shared] showLog:(@"当前处于连接状态,对监听到有USB 插入 的事件不做处理")];
+        //[[HidManager shared] showLog:(@"当前处于连接状态,对监听到有USB 插入 的事件不做处理")];
         return;
     }
     
@@ -262,6 +262,7 @@ static void hidAppearDevice(void *inContext,IOReturn inResult,void *inSender,IOH
         IOReturn ret = IOHIDDeviceClose(deviceRef, kIOHIDOptionsTypeNone);
         if (ret != kIOReturnSuccess) {
             [self showLog:(@"关闭device失败!")];
+            return;
         }
         
         // 清除引用
@@ -343,14 +344,20 @@ static void hidReceiveData(void* context, IOReturn result, void* sender, IOHIDRe
 //检查是否已连接
 - (void)checkedConected{
     if (![DeviceManger shared].isConneted) {
-        [HidManager shared].connectStateCallBack(true);
+        if ([HidManager shared].productType == AiMouseProductType_keyboard) {
+            [[HidManager shared] closeHid];
+            [[HidManager shared] openHid];
+            return;
+        }
+        else{
+            [HidManager shared].connectStateCallBack(true);
+        }
     }
 }
 
 #pragma mark - public
 
 - (void)openHid{
-    //    [self close];
     if (self.hidManager == nil) {
         self.deviceInfoCha = nil;
         self.hidManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
@@ -358,6 +365,7 @@ static void hidReceiveData(void* context, IOReturn result, void* sender, IOHIDRe
         IOReturn ret = IOHIDManagerOpen(self.hidManager, 0L);
         if (ret != kIOReturnSuccess) {
             [self showLog:(@"打开hid失败!")];
+            return;
         }else{
             [self showLog:(@"打开hid成功!")];
         }
@@ -370,20 +378,102 @@ static void hidReceiveData(void* context, IOReturn result, void* sender, IOHIDRe
         IOHIDManagerRegisterDeviceRemovalCallback(self.hidManager, &hidDisAppearDevice, NULL);
     }
 }
-
 - (BOOL)closeHid{
     [self showLog:@"关闭hid"];
-    // 关闭所有已连接的设备
-    if (self.deviceInfoCha) {
-        [self closeDevice:self.deviceInfoCha];
+    
+    // 标记正在关闭,防止重复调用
+    static BOOL isClosing = NO;
+    if (isClosing) {
+        [self showLog:@"已经在关闭过程中,忽略重复请求"];
+        return NO;
+    }
+    isClosing = YES;
+    
+    // 禁用回调处理
+    static BOOL callbacksDisabled = NO;
+    if (!callbacksDisabled) {
+        callbacksDisabled = YES;
+        
+        // 创建一个临时队列来处理后续操作
+        dispatch_queue_t tempQueue = dispatch_queue_create("com.hidmanager.cleanup", DISPATCH_QUEUE_SERIAL);
+        dispatch_async(tempQueue, ^{
+            
+            // 第一步:取消所有设备的调度并关闭
+            [self performSelector:@selector(closeAllDevices) withObject:nil afterDelay:0.1];
+            
+            // 第二步:延迟后关闭HID管理器
+            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+                [self performSelector:@selector(closeHIDManager) withObject:nil afterDelay:0.1];
+                
+                // 第三步:重置状态
+                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+                    isClosing = NO;
+                    callbacksDisabled = NO;
+                });
+            });
+        });
+        
+        return YES;
     }
     
+    return NO;
+}
+
+- (void)closeAllDevices {
+    [self showLog:@"开始关闭所有设备"];
+    
+    // 关闭voiceRef设备
     if (self.voiceRef) {
-        [self closeDevice:self.voiceRef];
+        [self showLog:@"关闭voiceRef设备"];
+        IOHIDDeviceUnscheduleFromRunLoop(self.voiceRef, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
+        IOHIDDeviceRegisterInputReportCallback(self.voiceRef, NULL, 0, NULL, NULL);
+        
+        // 关闭设备前发送空报告,确保没有挂起的操作
+        IOHIDDeviceSetReport(self.voiceRef, kIOHIDReportTypeOutput, 0, NULL, 0);
+        
+        IOReturn ret = IOHIDDeviceClose(self.voiceRef, kIOHIDOptionsTypeNone);
+        if (ret == kIOReturnSuccess) {
+            [self showLog:@"voiceRef设备关闭成功"];
+            self.voiceRef = nil;
+        } else {
+            [self showLog:[NSString stringWithFormat:@"voiceRef设备关闭失败,错误码:%d", ret]];
+        }
     }
     
+    // 关闭moveRef设备
     if (self.moveRef) {
-        [self closeDevice:self.moveRef];
+        [self showLog:@"关闭moveRef设备"];
+        IOHIDDeviceUnscheduleFromRunLoop(self.moveRef, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
+        IOHIDDeviceRegisterInputReportCallback(self.moveRef, NULL, 0, NULL, NULL);
+        
+        // 关闭设备前发送空报告,确保没有挂起的操作
+        IOHIDDeviceSetReport(self.moveRef, kIOHIDReportTypeOutput, 0, NULL, 0);
+        
+        IOReturn ret = IOHIDDeviceClose(self.moveRef, kIOHIDOptionsTypeNone);
+        if (ret == kIOReturnSuccess) {
+            [self showLog:@"moveRef设备关闭成功"];
+            self.moveRef = nil;
+        } else {
+            [self showLog:[NSString stringWithFormat:@"moveRef设备关闭失败,错误码:%d", ret]];
+        }
+    }
+    
+    // 关闭deviceInfoCha设备(最后关闭,因为它是主设备)
+    if (self.deviceInfoCha) {
+        [self showLog:@"关闭deviceInfoCha设备"];
+        IOHIDDeviceUnscheduleFromRunLoop(self.deviceInfoCha, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
+        IOHIDDeviceRegisterInputReportCallback(self.deviceInfoCha, NULL, 0, NULL, NULL);
+        
+        // 关闭设备前发送空报告,确保没有挂起的操作
+        IOHIDDeviceSetReport(self.deviceInfoCha, kIOHIDReportTypeOutput, 0, NULL, 0);
+        
+        IOReturn ret = IOHIDDeviceClose(self.deviceInfoCha, kIOHIDOptionsTypeNone);
+        if (ret == kIOReturnSuccess) {
+            [self showLog:@"deviceInfoCha设备关闭成功"];
+            self.deviceInfoCha = nil;
+        } else {
+            [self showLog:[NSString stringWithFormat:@"deviceInfoCha设备关闭失败,错误码:%d", ret]];
+        }
     }
     
     // 清空缓冲区字典
@@ -393,24 +483,42 @@ static void hidReceiveData(void* context, IOReturn result, void* sender, IOHIDRe
     }
     [self.deviceBuffers removeAllObjects];
     
-    // 关闭HID管理器
+    [self showLog:@"所有设备关闭操作已完成"];
+}
+
+- (void)closeHIDManager {
+    [self showLog:@"开始关闭HID管理器"];
+    
     if (self.hidManager != nil) {
-        // 取消注册回调
+        // 确保所有回调都被注销
         IOHIDManagerRegisterDeviceMatchingCallback(self.hidManager, NULL, NULL);
         IOHIDManagerRegisterDeviceRemovalCallback(self.hidManager, NULL, NULL);
         
-        IOReturn ret = IOHIDManagerClose(self.hidManager, 0);
-        if (ret != kIOReturnSuccess) {
-            [self showLog:[NSString stringWithFormat:@"关闭hid失败! 错误码:%d", ret]];
-        }
+        // 停止HID管理器在RunLoop中的运行
+        IOHIDManagerUnscheduleFromRunLoop(self.hidManager, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
         
-        [self showLog:@"IOHIDManager已关闭"];
-         self.hidManager = nil;
+        // 运行RunLoop一小段时间,让系统处理可能的挂起操作
+        CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.5, false);
+        
+        // 尝试关闭HID管理器
+        IOReturn ret = IOHIDManagerClose(self.hidManager, kIOHIDOptionsTypeNone);
+        
+        if (ret == kIOReturnSuccess) {
+            [self showLog:@"IOHIDManager关闭成功"];
+            self.hidManager = nil;
+        } else {
+            [self showLog:[NSString stringWithFormat:@"IOHIDManager关闭失败,错误码:%d", ret]];
+            
+            // 尝试强制释放
+            [self showLog:@"尝试强制释放HID管理器资源"];
+            CFRelease(self.hidManager);
+            self.hidManager = nil;
+        }
     }
     
-    return true;
+    [self showLog:@"HID管理器关闭操作已完成"];
+    [self openHid];
 }
-
 /// 发送数据给设备
 -(void)writeToDevice:(NSData *)data{
     if(self.deviceInfoCha == nil){
index 1e7b9b1..c559e17 100644 (file)
Binary files a/MouseSdk/MouseSdk.xcworkspace/xcuserdata/yaozuopan.xcuserdatad/UserInterfaceState.xcuserstate and b/MouseSdk/MouseSdk.xcworkspace/xcuserdata/yaozuopan.xcuserdatad/UserInterfaceState.xcuserstate differ
index 45774dd..4195c21 100644 (file)
@@ -3,4 +3,95 @@
    uuid = "D56CBD13-B1CD-4964-946C-9C0A140796C8"
    type = "0"
    version = "2.0">
+   <Breakpoints>
+      <BreakpointProxy
+         BreakpointExtensionID = "Xcode.Breakpoint.ExceptionBreakpoint">
+         <BreakpointContent
+            uuid = "7ADC72BB-C729-4CB1-A83F-A2B865E07EA2"
+            shouldBeEnabled = "Yes"
+            ignoreCount = "0"
+            continueAfterRunningActions = "No"
+            breakpointStackSelectionBehavior = "1"
+            scope = "1"
+            stopOnStyle = "0">
+         </BreakpointContent>
+      </BreakpointProxy>
+      <BreakpointProxy
+         BreakpointExtensionID = "Xcode.Breakpoint.SymbolicBreakpoint">
+         <BreakpointContent
+            uuid = "9DAE9373-E045-4357-AD27-9C8D84EB335F"
+            shouldBeEnabled = "Yes"
+            ignoreCount = "0"
+            continueAfterRunningActions = "No"
+            symbolName = ""
+            moduleName = "">
+            <Locations>
+            </Locations>
+         </BreakpointContent>
+      </BreakpointProxy>
+      <BreakpointProxy
+         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
+         <BreakpointContent
+            uuid = "6E24C828-D956-49E9-8DE9-FAC25C078B6C"
+            shouldBeEnabled = "Yes"
+            ignoreCount = "0"
+            continueAfterRunningActions = "No"
+            filePath = "AiMouseSdk/Manager/HidManager.m"
+            startingColumnNumber = "9223372036854775807"
+            endingColumnNumber = "9223372036854775807"
+            startingLineNumber = "280"
+            endingLineNumber = "280"
+            landmarkName = "hidDisAppearDevice(inContext, inResult, inSender, deviceRef)"
+            landmarkType = "9">
+         </BreakpointContent>
+      </BreakpointProxy>
+      <BreakpointProxy
+         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
+         <BreakpointContent
+            uuid = "7188EF66-0443-491E-875C-6B4DD9B0A8BF"
+            shouldBeEnabled = "Yes"
+            ignoreCount = "0"
+            continueAfterRunningActions = "No"
+            filePath = "AiMouseSdk/Manager/HidManager.m"
+            startingColumnNumber = "9223372036854775807"
+            endingColumnNumber = "9223372036854775807"
+            startingLineNumber = "296"
+            endingLineNumber = "296"
+            landmarkName = "hidReceiveData(context, result, sender, type, reportID, report, reportLength)"
+            landmarkType = "9">
+         </BreakpointContent>
+      </BreakpointProxy>
+      <BreakpointProxy
+         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
+         <BreakpointContent
+            uuid = "569CAE7A-0458-4538-B95A-BD92FABAAEC0"
+            shouldBeEnabled = "Yes"
+            ignoreCount = "0"
+            continueAfterRunningActions = "No"
+            filePath = "AiMouseSdk/Manager/HidManager.m"
+            startingColumnNumber = "9223372036854775807"
+            endingColumnNumber = "9223372036854775807"
+            startingLineNumber = "290"
+            endingLineNumber = "290"
+            landmarkName = "mouseData(context, result, sender, type, reportID, report, reportLength)"
+            landmarkType = "9">
+         </BreakpointContent>
+      </BreakpointProxy>
+      <BreakpointProxy
+         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
+         <BreakpointContent
+            uuid = "FD2BC354-975B-4060-8012-AA80EB63A88A"
+            shouldBeEnabled = "Yes"
+            ignoreCount = "0"
+            continueAfterRunningActions = "No"
+            filePath = "AiMouseSdk/Manager/HidManager.m"
+            startingColumnNumber = "9223372036854775807"
+            endingColumnNumber = "9223372036854775807"
+            startingLineNumber = "524"
+            endingLineNumber = "524"
+            landmarkName = "-writeToDevice:"
+            landmarkType = "7">
+         </BreakpointContent>
+      </BreakpointProxy>
+   </Breakpoints>
 </Bucket>
index d2ea65a..e170469 100644 (file)
@@ -7,12 +7,12 @@
                <key>Masonry.xcscheme_^#shared#^_</key>
                <dict>
                        <key>orderHint</key>
-                       <integer>4</integer>
+                       <integer>2</integer>
                </dict>
                <key>Pods-MouseSdk.xcscheme_^#shared#^_</key>
                <dict>
                        <key>orderHint</key>
-                       <integer>2</integer>
+                       <integer>4</integer>
                </dict>
        </dict>
 </dict>