Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

ISSUE-008

Unity默认键位卡手问题

常见表现

游戏自带键位支持但存在一些问题,例如:WASD走不动路、按键无法长按、按键无法连点。

相关源码

Unity引擎 UnityView+Keyboard.mm

static const double kKeyTimeoutInSeconds = 0.5;

- (void)processKeyboard
{
    KeyMap& map = GetKeyMap();
    if (map.size() == 0)
        return;
    std::vector<int> keysToUnpress;
    double nowTime = GetTimeInSeconds();
    for (KeyMap::iterator item = map.begin();
         item != map.end();
         item++)
    {
        // Key has expired, register it for key up event
        if (nowTime - item->second > kKeyTimeoutInSeconds)
            keysToUnpress.push_back(item->first);
    }

    for (std::vector<int>::iterator item = keysToUnpress.begin();
         item != keysToUnpress.end();
         item++)
    {
        map.erase(*item);
        UnitySetKeyboardKeyState(*item, false);
    }
}

原因分析

在Unity引擎中可以通过两种方式去捕获键盘输入,一种是使用旧的API,即Input.GetKeyDown(),另一种是使用最新的Input System Package方式。如果游戏选择使用旧的API,就会出现键位卡手的问题。

iOS系统从14.0开始才有提供访问键盘设备的API,即GCKeyboard。而在此之前Unity就已经写好了UnityView+Keyboard.mm,只不过Unity是通过UIKeyCommand取巧的方式来实现的。

UIKeyCommand只支持监听按键按下事件,并不支持按键抬起事件。Unity则通过“0.5秒后自动松开”来模拟按键抬起,也就造成了游戏过程中按键卡手的情况。

解决方法

玩家方面:通过PlayCover的按键映射去覆盖默认键位。

开发者方面:使用GCKeyboard API重写UnityView+Keyboard.mm。

有一份现成的版本:gist,但这个版本不支持设备断开重连,通过GCKeyboardDidConnectNotificationGCKeyboardDidDisconnectNotification可以监听到设备断开重连。