如何在Swift+Flutter的macOS应用中临时禁用键盘输入?
实现macOS下Flutter应用的临时键盘禁用功能
我正在用Swift和Flutter开发一款macOS应用,需要实现类似「Keyboard Clean Tool」的临时禁用键盘输入功能,已经搭建好Flutter MethodChannel的代码框架,但disableKeyboard和enableKeyboard方法的具体实现还没完成,需要程序化实现键盘输入的屏蔽与恢复。
原框架代码:
import Cocoa import FlutterMacOS class KeyboardServicePlugin: NSObject, FlutterPlugin { private var isBlockingKeyboard: Bool = false public static func register(with registrar: FlutterPluginRegistrar) { let channel = FlutterMethodChannel( name: "com.example.app/keyboard_service", binaryMessenger: registrar.messenger ) let instance = KeyboardServicePlugin() registrar.addMethodCallDelegate(instance, channel: channel) } public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { switch call.method { case "disableKeyboard": disableKeyboard() result(nil) case "enableKeyboard": enableKeyboard() result(nil) case "getKeyboardStatus": result(isBlockingKeyboard) case "toggleKeyboard": toggleKeyboard() result(nil) default: result(FlutterMethodNotImplemented) } } private func disableKeyboard() { // I'm not sure how to disable keyboard input in macOS } private func enableKeyboard() { // I'm not sure how to enable keyboard input in macOS } private func toggleKeyboard() { if isBlockingKeyboard { enableKeyboard() } else { disableKeyboard() } } }
解决方案:利用CGEventTap实现全局键盘拦截
通过macOS的CGEventTap API可以全局拦截键盘事件,从而实现临时禁用键盘的效果。以下是补全后的完整代码:
import Cocoa import FlutterMacOS import CoreGraphics class KeyboardServicePlugin: NSObject, FlutterPlugin { private var isBlockingKeyboard: Bool = false private var eventTap: CFMachPort? = nil private var runLoopSource: CFRunLoopSource? = nil public static func register(with registrar: FlutterPluginRegistrar) { let channel = FlutterMethodChannel( name: "com.example.app/keyboard_service", binaryMessenger: registrar.messenger ) let instance = KeyboardServicePlugin() registrar.addMethodCallDelegate(instance, channel: channel) } public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { switch call.method { case "disableKeyboard": disableKeyboard() result(nil) case "enableKeyboard": enableKeyboard() result(nil) case "getKeyboardStatus": result(isBlockingKeyboard) case "toggleKeyboard": toggleKeyboard() result(nil) case "checkPermission": result(checkAccessibilityPermission()) default: result(FlutterMethodNotImplemented) } } private func disableKeyboard() { guard !isBlockingKeyboard else { return } // 检查辅助功能权限 guard checkAccessibilityPermission() else { // 可在此处通知Flutter端权限不足,引导用户开启 return } // 创建全局键盘事件拦截tap let eventTap = CGEventTapCreate( .cghidEventTap, .headInsertEventTap, .defaultTap, CGEventMaskBit(.keyDown) | CGEventMaskBit(.keyUp), { _, _, _, _ in // 返回nil阻止事件传递到应用 return nil }, nil ) guard let tap = eventTap else { return } self.eventTap = tap runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, tap, 0) if let source = runLoopSource { CFRunLoopAddSource(CFRunLoopGetCurrent(), source, .commonModes) CGEventTapEnable(tap, true) isBlockingKeyboard = true } } private func enableKeyboard() { guard isBlockingKeyboard, let tap = eventTap else { return } CGEventTapEnable(tap, false) if let source = runLoopSource { CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source, .commonModes) } eventTap = nil runLoopSource = nil isBlockingKeyboard = false } private func toggleKeyboard() { isBlockingKeyboard ? enableKeyboard() : disableKeyboard() } // 检查辅助功能权限 private func checkAccessibilityPermission() -> Bool { let options: NSDictionary = [kAXTrustedCheckOptionPrompt.takeRetainedValue() as NSString: true] return AXIsProcessTrustedWithOptions(options) } }
关键说明
- 权限配置:macOS使用
CGEventTap需要开启辅助功能权限,需在应用Info.plist中添加权限说明:<key>NSAccessibilityUsageDescription</key> <string>需要权限来临时禁用键盘输入,防止误触</string> - 事件拦截逻辑:通过
CGEventTapCreate创建全局事件拦截点,拦截按键按下/抬起事件,返回nil阻止事件继续传递到任何应用。 - 状态管理:用
eventTap和runLoopSource保存拦截器引用,启用时加入当前RunLoop,禁用时移除并释放资源。 - 权限检查:新增
checkPermission方法可让Flutter端查询权限状态,引导用户在系统设置的「安全性与隐私」→「隐私」→「辅助功能」中开启权限。
内容的提问来源于stack exchange,提问作者Fathurrohman
相关产品推荐
相关产品推荐

