You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 18:13:13