Deliver correct key code on key release on WASM

Changed the behavior in which key events are delivered to targets.
Before the change, in case of a EMSCRIPTEN_EVENT_KEYUP event, the key
code and text were not filled in correctly as they should. This resulted
in wrong behavior when event targets expected these codes being available.

Fixes: QTBUG-105213
Change-Id: Ie66b5d6d395d08af655fcb00f1f616ad43d6bea4
Reviewed-by: Lorn Potter <lorn.potter@gmail.com>
This commit is contained in:
Mikolaj Boc 2022-07-29 16:34:29 +02:00
parent 998bd0b528
commit 7485213930
3 changed files with 69 additions and 76 deletions

View File

@ -1131,63 +1131,28 @@ void QWasmCompositor::WindowManipulation::onPointerUp(const PointerEvent& event)
m_screen->canvas().call<void>("releasePointerCapture", event.pointerId); m_screen->canvas().call<void>("releasePointerCapture", event.pointerId);
} }
bool QWasmCompositor::processKeyboard(int eventType, const EmscriptenKeyboardEvent *keyEvent) bool QWasmCompositor::processKeyboard(int eventType, const EmscriptenKeyboardEvent *emKeyEvent)
{ {
Qt::Key qtKey; Q_ASSERT(eventType == EMSCRIPTEN_EVENT_KEYDOWN || eventType == EMSCRIPTEN_EVENT_KEYUP);
QString keyText;
QEvent::Type keyType = QEvent::None;
switch (eventType) {
case EMSCRIPTEN_EVENT_KEYPRESS:
case EMSCRIPTEN_EVENT_KEYDOWN: // down
keyType = QEvent::KeyPress;
qtKey = m_eventTranslator->getKey(keyEvent);
keyText = m_eventTranslator->getKeyText(keyEvent, qtKey);
break;
case EMSCRIPTEN_EVENT_KEYUP: // up
keyType = QEvent::KeyRelease;
break;
default:
break;
};
if (keyType == QEvent::None) auto translatedEvent = m_eventTranslator->translateKeyEvent(eventType, emKeyEvent);
return 0;
QFlags<Qt::KeyboardModifier> modifiers = KeyboardModifier::getForEvent(*keyEvent); const QFlags<Qt::KeyboardModifier> modifiers = KeyboardModifier::getForEvent(*emKeyEvent);
// Clipboard fallback path: cut/copy/paste are handled by clipboard event // Clipboard path: cut/copy/paste are handled by clipboard event or direct clipboard access.
// handlers if direct clipboard access is not available. if (translatedEvent.type == QEvent::KeyPress && modifiers.testFlag(Qt::ControlModifier)
if (!QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi && modifiers & Qt::ControlModifier && && (translatedEvent.key == Qt::Key_X || translatedEvent.key == Qt::Key_V
(qtKey == Qt::Key_X || qtKey == Qt::Key_C || qtKey == Qt::Key_V)) { || translatedEvent.key == Qt::Key_C)) {
if (qtKey == Qt::Key_V) { QWasmIntegration::get()->getWasmClipboard()->isPaste = translatedEvent.key == Qt::Key_V;
QWasmIntegration::get()->getWasmClipboard()->isPaste = true; return false; // continue on to event
}
return false;
} }
bool accepted = false; if (translatedEvent.text.isEmpty())
translatedEvent.text = QString(emKeyEvent->key);
if (keyType == QEvent::KeyPress && if (translatedEvent.text.size() > 1)
modifiers.testFlag(Qt::ControlModifier) translatedEvent.text.clear();
&& qtKey == Qt::Key_V) { return QWindowSystemInterface::handleKeyEvent<QWindowSystemInterface::SynchronousDelivery>(
QWasmIntegration::get()->getWasmClipboard()->isPaste = true; 0, translatedEvent.type, translatedEvent.key, modifiers, translatedEvent.text);
accepted = false; // continue on to event
} else {
if (keyText.isEmpty())
keyText = QString(keyEvent->key);
if (keyText.size() > 1)
keyText.clear();
accepted = QWindowSystemInterface::handleKeyEvent<QWindowSystemInterface::SynchronousDelivery>(
0, keyType, qtKey, modifiers, keyText);
}
if (keyType == QEvent::KeyPress &&
modifiers.testFlag(Qt::ControlModifier)
&& qtKey == Qt::Key_C) {
QWasmIntegration::get()->getWasmClipboard()->isPaste = false;
accepted = false; // continue on to event
}
return accepted;
} }
bool QWasmCompositor::processWheel(int eventType, const EmscriptenWheelEvent *wheelEvent) bool QWasmCompositor::processWheel(int eventType, const EmscriptenWheelEvent *wheelEvent)

View File

@ -304,34 +304,57 @@ QCursor QWasmEventTranslator::cursorForMode(QWasmCompositor::ResizeMode m)
return Qt::ArrowCursor; return Qt::ArrowCursor;
} }
QString QWasmEventTranslator::getKeyText(const EmscriptenKeyboardEvent *keyEvent, Qt::Key qtKey) QWasmEventTranslator::TranslatedEvent
QWasmEventTranslator::translateKeyEvent(int emEventType, const EmscriptenKeyboardEvent *keyEvent)
{ {
if (m_emDeadKey != Qt::Key_unknown) { TranslatedEvent ret;
const Qt::Key translatedKey = translateBaseKeyUsingDeadKey(qtKey, m_emDeadKey); switch (emEventType) {
case EMSCRIPTEN_EVENT_KEYDOWN:
ret.type = QEvent::KeyPress;
break;
case EMSCRIPTEN_EVENT_KEYUP:
ret.type = QEvent::KeyRelease;
break;
default:
// Should not be reached - do not call with this event type.
Q_ASSERT(false);
break;
};
ret.key = translateEmscriptKey(keyEvent);
if (isDeadKeyEvent(keyEvent) || ret.key == Qt::Key_AltGr) {
if (keyEvent->shiftKey && ret.key == Qt::Key_QuoteLeft)
ret.key = Qt::Key_AsciiTilde;
m_emDeadKey = ret.key;
}
if (m_emDeadKey != Qt::Key_unknown
&& (m_keyModifiedByDeadKeyOnPress == Qt::Key_unknown
|| ret.key == m_keyModifiedByDeadKeyOnPress)) {
const Qt::Key baseKey = ret.key;
const Qt::Key translatedKey = translateBaseKeyUsingDeadKey(baseKey, m_emDeadKey);
if (translatedKey != Qt::Key_unknown) if (translatedKey != Qt::Key_unknown)
qtKey = translatedKey; ret.key = translatedKey;
if (auto text = keyEvent->shiftKey if (auto text = keyEvent->shiftKey
? findKeyTextByKeyId(WebToQtKeyCodeMappingsWithShift, qtKey) ? findKeyTextByKeyId(WebToQtKeyCodeMappingsWithShift, ret.key)
: findKeyTextByKeyId(WebToQtKeyCodeMappings, qtKey)) { : findKeyTextByKeyId(WebToQtKeyCodeMappings, ret.key)) {
m_emDeadKey = Qt::Key_unknown; if (ret.type == QEvent::KeyPress) {
return *text; Q_ASSERT(m_keyModifiedByDeadKeyOnPress == Qt::Key_unknown);
m_keyModifiedByDeadKeyOnPress = baseKey;
} else {
Q_ASSERT(ret.type == QEvent::KeyRelease);
Q_ASSERT(m_keyModifiedByDeadKeyOnPress == baseKey);
m_keyModifiedByDeadKeyOnPress = Qt::Key_unknown;
m_emDeadKey = Qt::Key_unknown;
}
ret.text = *text;
return ret;
} }
} }
return QString::fromUtf8(keyEvent->key); ret.text = QString::fromUtf8(keyEvent->key);
} return ret;
Qt::Key QWasmEventTranslator::getKey(const EmscriptenKeyboardEvent *keyEvent)
{
Qt::Key qtKey = translateEmscriptKey(keyEvent);
if (isDeadKeyEvent(keyEvent) || qtKey == Qt::Key_AltGr) {
if (keyEvent->shiftKey && qtKey == Qt::Key_QuoteLeft)
qtKey = Qt::Key_AsciiTilde;
m_emDeadKey = qtKey;
}
return qtKey;
} }
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -24,19 +24,24 @@ class QWasmEventTranslator : public QObject
Q_OBJECT Q_OBJECT
public: public:
struct TranslatedEvent
{
QEvent::Type type;
Qt::Key key;
QString text;
};
explicit QWasmEventTranslator(); explicit QWasmEventTranslator();
~QWasmEventTranslator(); ~QWasmEventTranslator();
static QCursor cursorForMode(QWasmCompositor::ResizeMode mode); static QCursor cursorForMode(QWasmCompositor::ResizeMode mode);
QString getKeyText(const EmscriptenKeyboardEvent *keyEvent, Qt::Key key); TranslatedEvent translateKeyEvent(int emEventType, const EmscriptenKeyboardEvent *keyEvent);
Qt::Key getKey(const EmscriptenKeyboardEvent *keyEvent);
private: private:
static quint64 getTimestamp(); static quint64 getTimestamp();
Qt::Key m_emDeadKey = Qt::Key_unknown; Qt::Key m_emDeadKey = Qt::Key_unknown;
Qt::Key m_keyModifiedByDeadKeyOnPress = Qt::Key_unknown;
}; };
QT_END_NAMESPACE QT_END_NAMESPACE