From: liangzhenying <867174124@qq.com> Date: Wed, 25 Jun 2025 04:29:03 +0000 (+0800) Subject: 修复键盘hid偶尔无法连上问题 X-Git-Url: http://git.snicker.com.cn/?a=commitdiff_plain;h=790737863845714a0c8805fe6b0944a4417492b5;p=mirrors%2FMouseSdk-MacOS.git 修复键盘hid偶尔无法连上问题 --- diff --git a/.gitignore b/.gitignore index d3c3d5b..bd5fb6b 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/MouseSdk/AiMouseSdk/Manager/DeviceManger.m b/MouseSdk/AiMouseSdk/Manager/DeviceManger.m index 55b4669..d8c1f71 100644 --- a/MouseSdk/AiMouseSdk/Manager/DeviceManger.m +++ b/MouseSdk/AiMouseSdk/Manager/DeviceManger.m @@ -161,8 +161,8 @@ }; 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) { @@ -866,6 +866,9 @@ self.aiMouseConnectStateDidChangeCallBack(self.kbSdk.connectType == AiMouseConnectType_bluetooth ? 0:1,connected); } if(self.authCallBack && connected)self.authCallBack(connected); + if (connected == false) { + [self.hid closeHid]; + } } @@ -879,7 +882,7 @@ [self.hid writeToDevice:data]; } } - + /// 鼠标按键指令回调 - (void)keyboardSendCmdData:(NSData *)data{ uint8 cmd; diff --git a/MouseSdk/AiMouseSdk/Manager/HidManager.m b/MouseSdk/AiMouseSdk/Manager/HidManager.m index 3935125..edf8d74 100644 --- a/MouseSdk/AiMouseSdk/Manager/HidManager.m +++ b/MouseSdk/AiMouseSdk/Manager/HidManager.m @@ -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){ diff --git a/MouseSdk/MouseSdk.xcworkspace/xcuserdata/yaozuopan.xcuserdatad/UserInterfaceState.xcuserstate b/MouseSdk/MouseSdk.xcworkspace/xcuserdata/yaozuopan.xcuserdatad/UserInterfaceState.xcuserstate index 1e7b9b1..c559e17 100644 Binary files a/MouseSdk/MouseSdk.xcworkspace/xcuserdata/yaozuopan.xcuserdatad/UserInterfaceState.xcuserstate and b/MouseSdk/MouseSdk.xcworkspace/xcuserdata/yaozuopan.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/MouseSdk/MouseSdk.xcworkspace/xcuserdata/yaozuopan.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/MouseSdk/MouseSdk.xcworkspace/xcuserdata/yaozuopan.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index 45774dd..4195c21 100644 --- a/MouseSdk/MouseSdk.xcworkspace/xcuserdata/yaozuopan.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/MouseSdk/MouseSdk.xcworkspace/xcuserdata/yaozuopan.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -3,4 +3,95 @@ uuid = "D56CBD13-B1CD-4964-946C-9C0A140796C8" type = "0" version = "2.0"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MouseSdk/Pods/Pods.xcodeproj/xcuserdata/yaozuopan.xcuserdatad/xcschemes/xcschememanagement.plist b/MouseSdk/Pods/Pods.xcodeproj/xcuserdata/yaozuopan.xcuserdatad/xcschemes/xcschememanagement.plist index d2ea65a..e170469 100644 --- a/MouseSdk/Pods/Pods.xcodeproj/xcuserdata/yaozuopan.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/MouseSdk/Pods/Pods.xcodeproj/xcuserdata/yaozuopan.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ Masonry.xcscheme_^#shared#^_ orderHint - 4 + 2 Pods-MouseSdk.xcscheme_^#shared#^_ orderHint - 2 + 4