【问题标题】:How to measure touch pressure (keystroke) on iOS system keyboard?如何测量 iOS 系统键盘上的触摸压力(击键)?
【发布时间】:2018-08-07 12:01:57
【问题描述】:

可能无法使用自定义UIGestureRecognizer 测量触摸压力,因为我们无法直接访问系统键盘的视图 [1]。如果使用自定义inputViewController 可以实现,但这不是我的选择。我想存储每个键的按键保持时间和按键压力。你知道怎么做吗?

编辑:[1] 我说“我们不能直接访问系统键盘的视图。”但实际上我们可以: UIRemoteKeyboardWindow > InputSetContainerView > InputSetHostView.

我认为改进 Nirav Bhatt 的答案可能会解决这个问题,但它会禁用键盘视图上的触摸功能。当我触摸一个键时,它会输出触摸力,但相应的字母不会输入到文本字段中。

【问题讨论】:

  • 你能继承系统键盘,覆盖 touchesBegan,在那里获得力量,然后调用super.touchesBegan(..)吗?不过,你会以某种方式让 Swift 返回正确的 Keyboard 类。并为类提供正确的位置来传递可见的力,或者可能是静态函数。
  • 您还可以创建一个代理来实现 touchesBegan 等,您可以在其中调用 UIRemoteKeyboardWindow,但同时将看到的力输送到您想要的位置。并在 hitTest 而不是键盘窗口中返回所述代理。

标签: ios objective-c swift keystroke


【解决方案1】:

从 iOS 9 开始,作为 3D 触摸的一部分,UITouch has got force property 可以准确地为您提供触摸事件期间施加的压力。

您可以将其与您的自定义视图实现结合起来,将每个字母数字字符作为 UIButtons 接收触摸并传递。

更新:

在与UIWindow 讨价还价之后,我终于能够在苹果的标准键盘窗口中捕获触摸事件。

诀窍是在UIWindow 扩展内覆盖hittest(也可以在UIView 级别上完成,但它会产生更广泛的影响,因为UIView 是UIWindow 的祖先),并返回触摸处理每当您看到来自UIRemoteKeyboardWindow 的触摸时,对象。

extension UIWindow
{
    override open func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
    {
        print("kb touch")

        for touch in touches
        {
           let pressure = touch.force
           print("pressure is: \(String(describing: pressure))")
        }
    }

    override open func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        print("hittest")

        let view = super.hitTest(point, with: event)

        if (NSStringFromClass(type(of: self)) == "UIRemoteKeyboardWindow")
        {
            //will result in touchesBegan being called
            return self;
        }

        return view
    }
}

【讨论】:

  • 我熟悉 3D Touch,但正如我所说,使用自定义键盘不是我的选择。我需要找到一种方法来使用系统键盘。
  • 我想知道什么样的应用程序要求需要知道击键压力,所有这些都使用 Apple 内置键盘。您可能可以在 textField beginediting 回调中测量两次连续击键之间的时间,如果这可以代替测量压力。
  • 这样,就可以使用 UITextFieldDelegate 来测量按键的压力速度,而不是压力。对于商业应用程序,我的要求可能听起来有点奇怪,但事实并非如此。我将使用击键数据进行研究。
  • 是的,它不会给你压力数据。如果您的目的是研究,请考虑一下为什么有必要将您的研究基于 Apple 提供的键盘而不是任何其他类型的键盘视图(仍将基于 UIView 等公共 API)
  • 因为如果这项研究能够得到令人满意的结果,我可能会开发一个 SDK,其中可以跟踪用户击键(以及许多其他有用的数据)以增强目标应用程序的安全性。在目标应用程序中,很可能会使用系统键盘。顺便说一句,我实现了以某种方式访问​​键盘后面的图层,但向它们添加手势识别器不起作用。
【解决方案2】:

解决方案比我想象的要容易。对于 iOS 9+ 系统,我们可以按照以下步骤来访问系统键盘并监听击键...

首先,创建一个自定义UIGestureRecognizer 来监听击键。跳过这一步的实现,因为它很简单(只需覆盖touchesBegan、touchesMoved、touchesEnded)。

添加KeyboardManager 以访问键盘视图:

final class KeyboardManager {

    static let shared = KeyboardManager()

    private init() { }

    /// Returns keyboard view on application window
    ///
    /// - Returns: Keyboard view
    func keyboardView() -> UIView? {
        for window in UIApplication.shared.windows {
            if let keyboardView = keyboardViewFromWindow(window) {
                return keyboardView
            }
        }
        return nil
    }

    /// Returns keyboard view from given window
    ///
    /// - Parameter window: Keyboard view container candidate window
    /// - Returns: Keyboard view
    func keyboardViewFromWindow(_ window: UIWindow) -> UIView? {
        if window.hasClassNameSuffix("UIRemoteKeyboardWindow") {
            let inputSetContainerView = window.subview(withSuffix: "InputSetContainerView")
            let inputSetHostView = inputSetContainerView?.subview(withSuffix: "InputSetHostView")
            return inputSetHostView
        }

        return nil
    }
}

UIView上面用到的扩展函数:

@nonobjc extension UIView {

    /// Returns first found subview with given class name
    ///
    /// - Parameter className: Subview class name
    /// - Returns: First subview with given class name
    func subview(withSuffix className: String) -> UIView? {
        return subviews.first {
            $0.hasClassNameSuffix(className)
        }
    }

    /// Compares suffix of view class name with given name
    ///
    /// - Parameter className: Class name that will be compared
    /// - Returns: Comparison result of view class name and given name
    func hasClassNameSuffix(_ className: String) -> Bool {
        return NSStringFromClass(type(of: self)).hasSuffix(className)
    }
}

然后,使用以下函数将您的手势识别器添加到键盘视图:

KeyboardManager.shared.keyboardView()?.addGestureRecognizer(keyboardGestureRecognizer).

注意:您的手势识别器不应扩展 UITapGestureRecognizer。 UILongPressGestureRecognizer 没问题。我们无法将多个具有相同类型的点击手势识别器添加到视图中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-07-06
    • 2011-03-11
    • 2019-01-24
    • 1970-01-01
    • 2014-05-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多