Qt模块扩展:将Qt虚拟键盘的拼音输入法扩展,支持键盘硬件输入的输入法方法(QtVirtualkeyboard)

QtVirtualkeyboard是一个Qt官方给触摸屏提供的Qt应用专用的 (只支持Qt应用程序唤出)输入法解决方案。他支持中文(拼英、手写、仓吉等)、日文、韩文文字的联想词、自动补全等操作,且中文拼英输入法也比较全面好用,可移植性高。可是没有对物理键盘的输入加以支持,导致在研发过程中,如果某些需要对外接物理键盘进行支持,则需要额外的成本加入第三方输入法,十分麻烦且风险巨大。

在这里介绍一种方法,可以让它支持物理键盘输入。

我先通过修改

QVirtualKeyboardInputContextPrivate::filterEvent 函数,增加新的过滤物理键盘事件的方式。这样我们可以监听得到想要的物理键盘事件,比如它自身就支持的上下左右导航键的代码如下:
#ifdef QT_VIRTUALKEYBOARD_ARROW_KEY_NAVIGATION
        int key = keyEvent->key();
        if ((key >= Qt::Key_Left && key <= Qt::Key_Down) || key == Qt::Key_Return) {
            if (type == QEvent::KeyPress && platformInputContext->isInputPanelVisible()) {
                activeNavigationKeys += key;
                emit navigationKeyPressed(key, keyEvent->isAutoRepeat());
                return true;
            } else if (type == QEvent::KeyRelease && activeNavigationKeys.contains(key)) {
                activeNavigationKeys -= key;
                emit navigationKeyReleased(key, keyEvent->isAutoRepeat());
                return true;
            }
        }
#endif

我们可以照搬它的实现,在下面实现一个过滤物理键盘事件的过程

#ifdef QT_VIRTUALKEYBOARD_FILTER_HARDWARE_KEY
        int keycode = keyEvent->key();
        {
            Q_Q(QVirtualKeyboardInputContext);
            HKeyState state = (type == QEvent::KeyRelease ? HKeyState::HKeyRelease : HKeyState::HKeyOther);
            if(state == HKeyState::HKeyOther)state = (type == QEvent::KeyPress ? HKeyState::HKeyPress : HKeyState::HKeyOther);
            bool reval = (emit q->hardKeyBoardChanged(keycode , state));
            return reval;
        }
#else 
        // Break composing text since the virtual keyboard does not support hard keyboard events (! now supperted (●'◡'●))
        if (!preeditText.isEmpty())
            commit();     
#endif

通过自定一个 hardKeyBoardChanged 信号来触发物理键盘信号,再通过修改每个不同输入法reset方法来监听该事件,达到每个不同输入法获取不同键盘事件又不影响其他功能的目的。

比如我修改了pinyininputmethod.cpp的reset

    if(inputContext())
    {
        connect(inputContext(), &QVirtualKeyboardInputContext::hardKeyBoardChanged, this, [&](qint32 keycode, qint32 keystate)
        {
            Q_D(PinyinInputMethod);

            if(d->inputMode != QVirtualKeyboardInputEngine::InputMode::Pinyin
                   || !inputContext()
                   || (keycode >= Qt::Key_Left && keycode <= Qt::Key_Down) // nav key
              )
                return false;

            if(keycode == Qt::Key_Backspace || keycode == Qt::Key_Delete || keycode == Qt::Key_Space)
                return  keyEvent(static_cast<Qt::Key>(keycode), QString(QChar(keycode)).toLower(), Qt::NoModifier );

            if( keystate == HKeyRelease )
            {
                d->activeHardwareKeys -= keycode;
            }
            else if( keystate == HKeyPress )
            {
                if(!d->activeHardwareKeys.contains(keycode))
                {
                    QString text = QString(QChar(keycode)).toLower();
                    d->activeHardwareKeys += keycode;

                    bool reval = keyEvent(static_cast<Qt::Key>(keycode), text, Qt::NoModifier );
                    return reval;
                }
            }

            return true;
        }, Qt::UniqueConnection );
    }

这样就可以传递物理键盘的点击事件到输入法代码中,并进行输入法的自动联想词等一系列的处理,达到我们让QtVirtualkeyboard变成一个全功能的输入法的目的了。

根据GPL情况,github地址:

https://github.com/wan2004/qtvirtualkeyboard