wasm: improve key handling

Allow for extended non English keys

Task-number: QTBUG-68189
Task-number: QTBUG-69392
Change-Id: I12187ebc1250a5c29022cd2d3ad3a77eb45c06a8
Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
This commit is contained in:
Lorn Potter 2018-07-17 14:58:41 +10:00
parent 91deac4a65
commit 5242126a61
2 changed files with 450 additions and 268 deletions

View File

@ -40,6 +40,9 @@
#include <QtCore/qobject.h>
#include <QtCore/qdeadlinetimer.h>
#include <private/qmakearray_p.h>
#include <QtCore/qnamespace.h>
#include <emscripten/bind.h>
#include <iostream>
@ -47,6 +50,257 @@
QT_BEGIN_NAMESPACE
using namespace emscripten;
typedef struct emkb2qt {
const char *em;
unsigned int qt;
constexpr bool operator <=(const emkb2qt &that) const noexcept
{
return !(strcmp(that) > 0);
}
bool operator <(const emkb2qt &that) const noexcept
{
return ::strcmp(em, that.em) < 0;
}
constexpr int strcmp(const emkb2qt &that, const int i = 0) const
{
return em[i] == 0 && that.em[i] == 0 ? 0
: em[i] == 0 ? -1
: that.em[i] == 0 ? 1
: em[i] < that.em[i] ? -1
: em[i] > that.em[i] ? 1
: strcmp(that, i + 1);
}
} emkb2qt_t;
template<unsigned int Qt, char ... EmChar>
struct Emkb2Qt
{
static constexpr const char storage[sizeof ... (EmChar) + 1] = {EmChar..., '\0'};
using Type = emkb2qt_t;
static constexpr Type data() noexcept { return Type{storage, Qt}; }
};
template<unsigned int Qt, char ... EmChar> constexpr char Emkb2Qt<Qt, EmChar...>::storage[];
static constexpr const auto KeyTbl = qMakeArray(
QSortedData<
Emkb2Qt< Qt::Key_Escape, 'E','s','c','a','p','e' >,
Emkb2Qt< Qt::Key_Tab, 'T','a','b' >,
Emkb2Qt< Qt::Key_Backspace, 'B','a','c','k','s','p','a','c','e' >,
Emkb2Qt< Qt::Key_Return, 'E','n','t','e','r' >,
Emkb2Qt< Qt::Key_Insert, 'I','n','s','e','r','t' >,
Emkb2Qt< Qt::Key_Delete, 'D','e','l','e','t','e' >,
Emkb2Qt< Qt::Key_Pause, 'P','a','u','s','e' >,
Emkb2Qt< Qt::Key_Pause, 'C','l','e','a','r' >,
Emkb2Qt< Qt::Key_Home, 'H','o','m','e' >,
Emkb2Qt< Qt::Key_End, 'E','n','d' >,
Emkb2Qt< Qt::Key_Left, 'A','r','r','o','w','L','e','f','t' >,
Emkb2Qt< Qt::Key_Up, 'A','r','r','o','w','U','p' >,
Emkb2Qt< Qt::Key_Right, 'A','r','r','o','w','R','i','g','h','t' >,
Emkb2Qt< Qt::Key_Down, 'A','r','r','o','w','D','o','w','n' >,
Emkb2Qt< Qt::Key_PageUp, 'P','a','g','e','U','p' >,
Emkb2Qt< Qt::Key_PageDown, 'P','a','g','e','D','o','w','n' >,
Emkb2Qt< Qt::Key_Shift, 'S','h','i','f','t' >,
Emkb2Qt< Qt::Key_Control, 'C','o','n','t','r','o','l' >,
Emkb2Qt< Qt::Key_Meta, 'O','S'>,
Emkb2Qt< Qt::Key_Alt, 'A','l','t','L','e','f','t' >,
Emkb2Qt< Qt::Key_Alt, 'A','l','t' >,
Emkb2Qt< Qt::Key_CapsLock, 'C','a','p','s','L','o','c','k' >,
Emkb2Qt< Qt::Key_NumLock, 'N','u','m','L','o','c','k' >,
Emkb2Qt< Qt::Key_ScrollLock, 'S','c','r','o','l','l','L','o','c','k' >,
Emkb2Qt< Qt::Key_F1, 'F','1' >,
Emkb2Qt< Qt::Key_F2, 'F','2' >,
Emkb2Qt< Qt::Key_F3, 'F','3' >,
Emkb2Qt< Qt::Key_F4, 'F','4' >,
Emkb2Qt< Qt::Key_F5, 'F','5' >,
Emkb2Qt< Qt::Key_F6, 'F','6' >,
Emkb2Qt< Qt::Key_F7, 'F','7' >,
Emkb2Qt< Qt::Key_F8, 'F','8' >,
Emkb2Qt< Qt::Key_F9, 'F','9' >,
Emkb2Qt< Qt::Key_F10, 'F','1','0' >,
Emkb2Qt< Qt::Key_F11, 'F','1','1' >,
Emkb2Qt< Qt::Key_F12, 'F','1','2' >,
Emkb2Qt< Qt::Key_F13, 'F','1','3' >,
Emkb2Qt< Qt::Key_F14, 'F','1','4' >,
Emkb2Qt< Qt::Key_F15, 'F','1','5' >,
Emkb2Qt< Qt::Key_F16, 'F','1','6' >,
Emkb2Qt< Qt::Key_F17, 'F','1','7' >,
Emkb2Qt< Qt::Key_F18, 'F','1','8' >,
Emkb2Qt< Qt::Key_F19, 'F','1','9' >,
Emkb2Qt< Qt::Key_F20, 'F','2','0' >,
Emkb2Qt< Qt::Key_F21, 'F','2','1' >,
Emkb2Qt< Qt::Key_F22, 'F','2','2' >,
Emkb2Qt< Qt::Key_F23, 'F','2','3' >,
Emkb2Qt< Qt::Key_Space, ' ' >,
Emkb2Qt< Qt::Key_Comma, ',' >,
Emkb2Qt< Qt::Key_Minus, '-' >,
Emkb2Qt< Qt::Key_Period, '.' >,
Emkb2Qt< Qt::Key_Slash, '/' >,
Emkb2Qt< Qt::Key_0, '0' >,
Emkb2Qt< Qt::Key_1, '1' >,
Emkb2Qt< Qt::Key_2, '2' >,
Emkb2Qt< Qt::Key_3, '3' >,
Emkb2Qt< Qt::Key_4, '4' >,
Emkb2Qt< Qt::Key_5, '5' >,
Emkb2Qt< Qt::Key_6, '6' >,
Emkb2Qt< Qt::Key_7, '7' >,
Emkb2Qt< Qt::Key_8, '8' >,
Emkb2Qt< Qt::Key_9, '9' >,
Emkb2Qt< Qt::Key_Semicolon, ';' >,
Emkb2Qt< Qt::Key_Equal, '=' >,
Emkb2Qt< Qt::Key_A, 'K','e','y','A' >,
Emkb2Qt< Qt::Key_B, 'K','e','y','B' >,
Emkb2Qt< Qt::Key_C, 'K','e','y','C' >,
Emkb2Qt< Qt::Key_D, 'K','e','y','D' >,
Emkb2Qt< Qt::Key_E, 'K','e','y','E' >,
Emkb2Qt< Qt::Key_F, 'K','e','y','F' >,
Emkb2Qt< Qt::Key_G, 'K','e','y','G' >,
Emkb2Qt< Qt::Key_H, 'K','e','y','H' >,
Emkb2Qt< Qt::Key_I, 'K','e','y','I' >,
Emkb2Qt< Qt::Key_J, 'K','e','y','J' >,
Emkb2Qt< Qt::Key_K, 'K','e','y','K' >,
Emkb2Qt< Qt::Key_L, 'K','e','y','L' >,
Emkb2Qt< Qt::Key_M, 'K','e','y','M' >,
Emkb2Qt< Qt::Key_N, 'K','e','y','N' >,
Emkb2Qt< Qt::Key_O, 'K','e','y','O' >,
Emkb2Qt< Qt::Key_P, 'K','e','y','P' >,
Emkb2Qt< Qt::Key_Q, 'K','e','y','Q' >,
Emkb2Qt< Qt::Key_R, 'K','e','y','R' >,
Emkb2Qt< Qt::Key_S, 'K','e','y','S' >,
Emkb2Qt< Qt::Key_T, 'K','e','y','T' >,
Emkb2Qt< Qt::Key_U, 'K','e','y','U' >,
Emkb2Qt< Qt::Key_V, 'K','e','y','V' >,
Emkb2Qt< Qt::Key_W, 'K','e','y','W' >,
Emkb2Qt< Qt::Key_X, 'K','e','y','X' >,
Emkb2Qt< Qt::Key_Y, 'K','e','y','Y' >,
Emkb2Qt< Qt::Key_Z, 'K','e','y','Z' >,
Emkb2Qt< Qt::Key_BracketLeft, '[' >,
Emkb2Qt< Qt::Key_Backslash, '\\' >,
Emkb2Qt< Qt::Key_BracketRight, ']' >,
Emkb2Qt< Qt::Key_Apostrophe, '\'' >,
Emkb2Qt< Qt::Key_QuoteLeft, 'B','a','c','k','q','u','o','t','e' >,
Emkb2Qt< Qt::Key_multiply, 'N','u','m','p','a','d','M','u','l','t','i','p','l','y' >,
Emkb2Qt< Qt::Key_Minus, 'N','u','m','p','a','d','S','u','b','t','r','a','c','t' >,
Emkb2Qt< Qt::Key_Period, 'N','u','m','p','a','d','D','e','c','i','m','a','l' >,
Emkb2Qt< Qt::Key_Plus, 'N','u','m','p','a','d','A','d','d' >,
Emkb2Qt< Qt::Key_division, 'N','u','m','p','a','d','D','i','v','i','d','e' >,
Emkb2Qt< Qt::Key_Equal, 'N','u','m','p','a','d','E','q','u','a','l' >,
Emkb2Qt< Qt::Key_0, 'N','u','m','p','a','d','0' >,
Emkb2Qt< Qt::Key_1, 'N','u','m','p','a','d','1' >,
Emkb2Qt< Qt::Key_2, 'N','u','m','p','a','d','2' >,
Emkb2Qt< Qt::Key_3, 'N','u','m','p','a','d','3' >,
Emkb2Qt< Qt::Key_4, 'N','u','m','p','a','d','4' >,
Emkb2Qt< Qt::Key_5, 'N','u','m','p','a','d','5' >,
Emkb2Qt< Qt::Key_6, 'N','u','m','p','a','d','6' >,
Emkb2Qt< Qt::Key_7, 'N','u','m','p','a','d','7' >,
Emkb2Qt< Qt::Key_8, 'N','u','m','p','a','d','8' >,
Emkb2Qt< Qt::Key_9, 'N','u','m','p','a','d','9' >,
Emkb2Qt< Qt::Key_Comma, 'N','u','m','p','a','d','C','o','m','m','a' >,
Emkb2Qt< Qt::Key_Enter, 'N','u','m','p','a','d','E','n','t','e','r' >,
Emkb2Qt< Qt::Key_Paste, 'P','a','s','t','e' >,
Emkb2Qt< Qt::Key_AltGr, 'A','l','t','R','i','g','h','t' >,
Emkb2Qt< Qt::Key_Help, 'H','e','l','p' >,
Emkb2Qt< Qt::Key_Equal, '=' >,
Emkb2Qt< Qt::Key_yen, 'I','n','t','l','Y','e','n' >,
Emkb2Qt< Qt::Key_Exclam, '\x21' >,
Emkb2Qt< Qt::Key_QuoteDbl, '\x22' >,
Emkb2Qt< Qt::Key_NumberSign, '\x23' >,
Emkb2Qt< Qt::Key_Dollar, '\x24' >,
Emkb2Qt< Qt::Key_Percent, '\x25' >,
Emkb2Qt< Qt::Key_Ampersand, '\x26' >,
Emkb2Qt< Qt::Key_ParenLeft, '\x28' >,
Emkb2Qt< Qt::Key_ParenRight, '\x29' >,
Emkb2Qt< Qt::Key_Asterisk, '\x2a' >,
Emkb2Qt< Qt::Key_Plus, '\x2b' >,
Emkb2Qt< Qt::Key_Colon, '\x3a' >,
Emkb2Qt< Qt::Key_Semicolon, '\x3b' >,
Emkb2Qt< Qt::Key_Less, '\x3c' >,
Emkb2Qt< Qt::Key_Equal, '\x3d' >,
Emkb2Qt< Qt::Key_Greater, '\x3e' >,
Emkb2Qt< Qt::Key_Question, '\x3f' >,
Emkb2Qt< Qt::Key_At, '\x40' >,
Emkb2Qt< Qt::Key_BracketLeft, '\x5b' >,
Emkb2Qt< Qt::Key_Backslash, '\x5c' >,
Emkb2Qt< Qt::Key_BracketRight, '\x5d' >,
Emkb2Qt< Qt::Key_AsciiCircum, '\x5e' >,
Emkb2Qt< Qt::Key_Underscore, '\x5f' >,
Emkb2Qt< Qt::Key_QuoteLeft, '\x60'>,
Emkb2Qt< Qt::Key_BraceLeft, '\x7b'>,
Emkb2Qt< Qt::Key_Bar, '\x7c'>,
Emkb2Qt< Qt::Key_BraceRight, '\x7d'>,
Emkb2Qt< Qt::Key_AsciiTilde, '\x7e'>,
Emkb2Qt< Qt::Key_Space, '\x20' >,
Emkb2Qt< Qt::Key_Comma, '\x2c' >,
Emkb2Qt< Qt::Key_Minus, '\x2d' >,
Emkb2Qt< Qt::Key_Period, '\x2e' >,
Emkb2Qt< Qt::Key_Slash, '\x2f' >,
Emkb2Qt< Qt::Key_Apostrophe, '\x27' >,
Emkb2Qt< Qt::Key_Menu, 'C','o','n','t','e','x','t','M','e','n','u' >,
Emkb2Qt< Qt::Key_Agrave, '\xc3','\xa0' >,
Emkb2Qt< Qt::Key_Aacute, '\xc3','\xa1' >,
Emkb2Qt< Qt::Key_Acircumflex, '\xc3','\xa2' >,
Emkb2Qt< Qt::Key_Adiaeresis, '\xc3','\xa4' >,
Emkb2Qt< Qt::Key_AE, '\xc3','\xa6' >,
Emkb2Qt< Qt::Key_Atilde, '\xc3','\xa3' >,
Emkb2Qt< Qt::Key_Aring, '\xc3','\xa5' >,
Emkb2Qt< Qt::Key_Ccedilla, '\xc3','\xa7' >,
Emkb2Qt< Qt::Key_Egrave, '\xc3','\xa8' >,
Emkb2Qt< Qt::Key_Eacute, '\xc3','\xa9' >,
Emkb2Qt< Qt::Key_Ecircumflex, '\xc3','\xaa' >,
Emkb2Qt< Qt::Key_Ediaeresis, '\xc3','\xab' >,
Emkb2Qt< Qt::Key_Icircumflex, '\xc3','\xae' >,
Emkb2Qt< Qt::Key_Idiaeresis, '\xc3','\xaf' >,
Emkb2Qt< Qt::Key_Ocircumflex, '\xc3','\xb4' >,
Emkb2Qt< Qt::Key_Odiaeresis, '\xc3','\xb6' >,
Emkb2Qt< Qt::Key_Ograve, '\xc3','\xb2' >,
Emkb2Qt< Qt::Key_Oacute, '\xc3','\xb3' >,
Emkb2Qt< Qt::Key_Ooblique, '\xc3','\xb8' >,
Emkb2Qt< Qt::Key_Otilde, '\xc3','\xb5' >,
Emkb2Qt< Qt::Key_Ucircumflex, '\xc3','\xbb' >,
Emkb2Qt< Qt::Key_Udiaeresis, '\xc3','\xbc' >,
Emkb2Qt< Qt::Key_Ugrave, '\xc3','\xb9' >,
Emkb2Qt< Qt::Key_Uacute, '\xc3','\xba' >,
Emkb2Qt< Qt::Key_Ntilde, '\xc3','\xb1' >,
Emkb2Qt< Qt::Key_ydiaeresis, '\xc3','\xbf' >
>::Data{}
);
static constexpr const auto DeadKeyShiftTbl = qMakeArray(
QSortedData<
// shifted
Emkb2Qt< Qt::Key_Agrave, '\xc3','\x80' >,
Emkb2Qt< Qt::Key_Aacute, '\xc3','\x81' >,
Emkb2Qt< Qt::Key_Acircumflex, '\xc3','\x82' >,
Emkb2Qt< Qt::Key_Adiaeresis, '\xc3','\x84' >,
Emkb2Qt< Qt::Key_AE, '\xc3','\x86' >,
Emkb2Qt< Qt::Key_Atilde, '\xc3','\x83' >,
Emkb2Qt< Qt::Key_Aring, '\xc3','\x85' >,
Emkb2Qt< Qt::Key_Egrave, '\xc3','\x88' >,
Emkb2Qt< Qt::Key_Eacute, '\xc3','\x89' >,
Emkb2Qt< Qt::Key_Ecircumflex, '\xc3','\x8a' >,
Emkb2Qt< Qt::Key_Ediaeresis, '\xc3','\x8b' >,
Emkb2Qt< Qt::Key_Icircumflex, '\xc3','\x8e' >,
Emkb2Qt< Qt::Key_Idiaeresis, '\xc3','\x8f' >,
Emkb2Qt< Qt::Key_Ocircumflex, '\xc3','\x94' >,
Emkb2Qt< Qt::Key_Odiaeresis, '\xc3','\x96' >,
Emkb2Qt< Qt::Key_Ograve, '\xc3','\x92' >,
Emkb2Qt< Qt::Key_Oacute, '\xc3','\x93' >,
Emkb2Qt< Qt::Key_Ooblique, '\xc3','\x98' >,
Emkb2Qt< Qt::Key_Otilde, '\xc3','\x95' >,
Emkb2Qt< Qt::Key_Ucircumflex, '\xc3','\x9b' >,
Emkb2Qt< Qt::Key_Udiaeresis, '\xc3','\x9c' >,
Emkb2Qt< Qt::Key_Ugrave, '\xc3','\x99' >,
Emkb2Qt< Qt::Key_Uacute, '\xc3','\x9a' >,
Emkb2Qt< Qt::Key_Ntilde, '\xc3','\x91' >,
Emkb2Qt< Qt::Key_Ccedilla, '\xc3','\x87' >,
Emkb2Qt< Qt::Key_ydiaeresis, '\xc3','\x8f' >
>::Data{}
);
// macOS CTRL <-> META switching. We most likely want to enable
// the existing switching code in QtGui, but for now do it here.
static bool g_usePlatformMacCtrlMetaSwitching = false;
@ -155,148 +409,44 @@ QFlags<Qt::KeyboardModifier> QWasmEventTranslator::translateMouseEventModifier(c
int QWasmEventTranslator::keyboard_cb(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)
{
Q_UNUSED(userData)
bool alphanumeric;
Qt::Key qtKey = translateEmscriptKey(keyEvent, &alphanumeric);
QEvent::Type keyType = QEvent::None;
switch (eventType) {
case EMSCRIPTEN_EVENT_KEYPRESS:
case EMSCRIPTEN_EVENT_KEYDOWN: //down
keyType = QEvent::KeyPress;
break;
case EMSCRIPTEN_EVENT_KEYUP: //up
keyType = QEvent::KeyRelease;
break;
default:
break;
};
if (keyType == QEvent::None)
return 0;
QFlags<Qt::KeyboardModifier> mods = translateKeyboardEventModifier(keyEvent);
bool accepted = false;
if (keyType == QEvent::KeyPress &&
mods.testFlag(Qt::ControlModifier)
&& qtKey == Qt::Key_V) {
QWasmIntegration::get()->getWasmClipboard()->readTextFromClipboard();
} else {
QString keyText = alphanumeric ? QString(keyEvent->key) : QString();
accepted = QWindowSystemInterface::handleKeyEvent<QWindowSystemInterface::SynchronousDelivery>(
0, keyType, qtKey, translateKeyboardEventModifier(keyEvent), keyText);
}
if (keyType == QEvent::KeyPress &&
mods.testFlag(Qt::ControlModifier)
&& qtKey == Qt::Key_C) {
QWasmIntegration::get()->getWasmClipboard()->writeTextToClipboard();
}
QWasmEventDispatcher::maintainTimers();
QWasmEventTranslator *wasmTranslator = reinterpret_cast<QWasmEventTranslator *>(userData);
bool accepted = wasmTranslator->processKeyboard(eventType, keyEvent);
return accepted ? 1 : 0;
}
Qt::Key QWasmEventTranslator::translateEmscriptKey(const EmscriptenKeyboardEvent *emscriptKey, bool *outAlphanumeric)
Qt::Key QWasmEventTranslator::translateEmscriptKey(const EmscriptenKeyboardEvent *emscriptKey)
{
Qt::Key qtKey;
if (outAlphanumeric)
*outAlphanumeric = false;
Qt::Key qtKey = Qt::Key_unknown;
switch (emscriptKey->keyCode) {
case KeyMultiply: qtKey = Qt::Key_Asterisk; *outAlphanumeric = true; break;
case KeyAdd: qtKey = Qt::Key_Plus; *outAlphanumeric = true; break;
case KeyMinus: qtKey = Qt::Key_Minus; *outAlphanumeric = true; break;
case KeySubtract: qtKey = Qt::Key_Minus; *outAlphanumeric = true; break;
case KeyDecimal: qtKey = Qt::Key_Period; *outAlphanumeric = true; break;
case KeyDivide: qtKey = Qt::Key_Slash; *outAlphanumeric = true; break;
case KeyNumPad0: qtKey = Qt::Key_0; *outAlphanumeric = true; break;
case KeyNumPad1: qtKey = Qt::Key_1; *outAlphanumeric = true; break;
case KeyNumPad2: qtKey = Qt::Key_2; *outAlphanumeric = true; break;
case KeyNumPad3: qtKey = Qt::Key_3; *outAlphanumeric = true; break;
case KeyNumPad4: qtKey = Qt::Key_4; *outAlphanumeric = true; break;
case KeyNumPad5: qtKey = Qt::Key_5; *outAlphanumeric = true; break;
case KeyNumPad6: qtKey = Qt::Key_6; *outAlphanumeric = true; break;
case KeyNumPad7: qtKey = Qt::Key_7; *outAlphanumeric = true; break;
case KeyNumPad8: qtKey = Qt::Key_8; *outAlphanumeric = true; break;
case KeyNumPad9: qtKey = Qt::Key_9; *outAlphanumeric = true; break;
case KeyComma: qtKey = Qt::Key_Comma; *outAlphanumeric = true; break;
case KeyPeriod: qtKey = Qt::Key_Period; *outAlphanumeric = true; break;
case KeySlash: qtKey = Qt::Key_Slash; *outAlphanumeric = true; break;
case KeySemiColon: qtKey = Qt::Key_Semicolon; *outAlphanumeric = true; break;
case KeyEquals: qtKey = Qt::Key_Equal; *outAlphanumeric = true; break;
case KeyOpenBracket: qtKey = Qt::Key_BracketLeft; *outAlphanumeric = true; break;
case KeyCloseBracket: qtKey = Qt::Key_BracketRight; *outAlphanumeric = true; break;
case KeyBackSlash: qtKey = Qt::Key_Backslash; *outAlphanumeric = true; break;
case KeyMeta:
Q_FALLTHROUGH();
case KeyMetaRight:
qtKey = Qt::Key_Meta;
break;
case KeyTab: qtKey = Qt::Key_Tab; break;
case KeyClear: qtKey = Qt::Key_Clear; break;
case KeyBackSpace: qtKey = Qt::Key_Backspace; break;
case KeyEnter: qtKey = Qt::Key_Return; break;
case KeyShift: qtKey = Qt::Key_Shift; break;
case KeyControl: qtKey = Qt::Key_Control; break;
case KeyAlt: qtKey = Qt::Key_Alt; break;
case KeyCapsLock: qtKey = Qt::Key_CapsLock; break;
case KeyEscape: qtKey = Qt::Key_Escape; break;
case KeyPageUp: qtKey = Qt::Key_PageUp; break;
case KeyPageDown: qtKey = Qt::Key_PageDown; break;
case KeyEnd: qtKey = Qt::Key_End; break;
case KeyHome: qtKey = Qt::Key_Home; break;
case KeyLeft: qtKey = Qt::Key_Left; break;
case KeyUp: qtKey = Qt::Key_Up; break;
case KeyRight: qtKey = Qt::Key_Right; break;
case KeyDown: qtKey = Qt::Key_Down; break;
case KeyBrightnessDown: qtKey = Qt::Key_MonBrightnessDown; break;
case KeyBrightnessUp: qtKey = Qt::Key_MonBrightnessUp; break;
case KeyMediaTrackPrevious: qtKey = Qt::Key_MediaPrevious; break;
case KeyMediaPlayPause: qtKey = Qt::Key_MediaTogglePlayPause; break;
case KeyMediaTrackNext: qtKey = Qt::Key_MediaNext; break;
case KeyAudioVolumeMute: qtKey = Qt::Key_VolumeMute; break;
case KeyAudioVolumeDown: qtKey = Qt::Key_VolumeDown; break;
case KeyAudioVolumeUp: qtKey = Qt::Key_VolumeUp; break;
case KeyDelete: qtKey = Qt::Key_Delete; break;
if (qstrncmp(emscriptKey->code, "Key", 3) == 0 || qstrncmp(emscriptKey->code, "Numpad", 6) == 0) {
case KeyF1: qtKey = Qt::Key_F1; break;
case KeyF2: qtKey = Qt::Key_F2; break;
case KeyF3: qtKey = Qt::Key_F3; break;
case KeyF4: qtKey = Qt::Key_F4; break;
case KeyF5: qtKey = Qt::Key_F5; break;
case KeyF6: qtKey = Qt::Key_F6; break;
case KeyF7: qtKey = Qt::Key_F7; break;
case KeyF8: qtKey = Qt::Key_F8; break;
case KeyF9: qtKey = Qt::Key_F9; break;
case KeyF10: qtKey = Qt::Key_F10; break;
case KeyF11: qtKey = Qt::Key_F11; break;
case KeyF12: qtKey = Qt::Key_F12; break;
case 124: qtKey = Qt::Key_F13; break;
case 125: qtKey = Qt::Key_F14; break;
case KeySpace:
default:
if (outAlphanumeric)
*outAlphanumeric = true;
qtKey = static_cast<Qt::Key>(emscriptKey->keyCode);
break;
emkb2qt_t searchKey{emscriptKey->code, 0}; // search emcsripten code
auto it1 = std::lower_bound(KeyTbl.cbegin(), KeyTbl.cend(), searchKey);
if (it1 != KeyTbl.end() && !(searchKey < *it1)) {
qtKey = static_cast<Qt::Key>(it1->qt);
}
} else if (qstrncmp(emscriptKey->key, "Dead", 4) == 0 ) {
emkb2qt_t searchKey1{emscriptKey->code, 0};
for (auto it1 = KeyTbl.cbegin(); it1 != KeyTbl.end(); ++it1)
if (it1 != KeyTbl.end() && (qstrcmp(searchKey1.em, it1->em) == 0)) {
qtKey = static_cast<Qt::Key>(it1->qt);
}
}
// Handle Mac command key. Using event->keyCode as above is
// no reliable since the codes differ between browsers.
if (qstrncmp(emscriptKey->key, "Meta", 4) == 0) {
qtKey = Qt::Key_Meta;
*outAlphanumeric = false;
if (qtKey == Qt::Key_unknown) {
emkb2qt_t searchKey{emscriptKey->key, 0}; // search unicode key
auto it1 = std::lower_bound(KeyTbl.cbegin(), KeyTbl.cend(), searchKey);
if (it1 != KeyTbl.end() && !(searchKey < *it1)) {
qtKey = static_cast<Qt::Key>(it1->qt);
}
}
if (g_usePlatformMacCtrlMetaSwitching) {
if (qtKey == Qt::Key_Meta)
qtKey = Qt::Key_Control;
else if (qtKey == Qt::Key_Control)
qtKey = Qt::Key_Meta;
if (qtKey == Qt::Key_unknown) {//try harder with shifted number keys
emkb2qt_t searchKey1{emscriptKey->key, 0};
for (auto it1 = KeyTbl.cbegin(); it1 != KeyTbl.end(); ++it1)
if (it1 != KeyTbl.end() && (qstrcmp(searchKey1.em, it1->em) == 0)) {
qtKey = static_cast<Qt::Key>(it1->qt);
}
}
return qtKey;
@ -481,7 +631,6 @@ int QWasmEventTranslator::focus_cb(int /*eventType*/, const EmscriptenFocusEvent
int QWasmEventTranslator::wheel_cb(int eventType, const EmscriptenWheelEvent *wheelEvent, void *userData)
{
Q_UNUSED(eventType)
Q_UNUSED(userData)
EmscriptenMouseEvent mouseEvent = wheelEvent->mouse;
@ -501,7 +650,8 @@ int QWasmEventTranslator::wheel_cb(int eventType, const EmscriptenWheelEvent *wh
if (g_useNaturalScrolling) //macOS platform has document oriented scrolling
scrollFactor = -scrollFactor;
Qt::KeyboardModifiers modifiers = translateMouseEventModifier(&mouseEvent);
QWasmEventTranslator *translator = (QWasmEventTranslator*)userData;
Qt::KeyboardModifiers modifiers = translator->translateMouseEventModifier(&mouseEvent);
auto timestamp = mouseEvent.timestamp;
QPoint globalPoint(mouseEvent.canvasX, mouseEvent.canvasY);
@ -514,8 +664,8 @@ int QWasmEventTranslator::wheel_cb(int eventType, const EmscriptenWheelEvent *wh
if (wheelEvent->deltaY != 0) pixelDelta.setY(wheelEvent->deltaY * scrollFactor);
if (wheelEvent->deltaX != 0) pixelDelta.setX(wheelEvent->deltaX * scrollFactor);
QWindowSystemInterface::handleWheelEvent(window2, timestamp, localPoint, globalPoint, QPoint(), pixelDelta, modifiers);
QWindowSystemInterface::handleWheelEvent(window2, timestamp, localPoint,
globalPoint, QPoint(), pixelDelta, modifiers);
QWasmEventDispatcher::maintainTimers();
return 1;
@ -562,12 +712,16 @@ int QWasmEventTranslator::touchCallback(int eventType, const EmscriptenTouchEven
}
QWasmEventTranslator *wasmEventTranslator = (QWasmEventTranslator*)userData;
QFlags<Qt::KeyboardModifier> keyModifier = translatKeyModifier(touchEvent);
QFlags<Qt::KeyboardModifier> keyModifier = wasmEventTranslator->translatKeyModifier(touchEvent);
if (eventType != EMSCRIPTEN_EVENT_TOUCHCANCEL)
QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>(window2, wasmEventTranslator->getTimestamp(), wasmEventTranslator->touchDevice, touchPointList, keyModifier);
QWindowSystemInterface::handleTouchEvent
<QWindowSystemInterface::SynchronousDelivery>(window2, wasmEventTranslator->getTimestamp(),
wasmEventTranslator->touchDevice,
touchPointList, keyModifier);
else
QWindowSystemInterface::handleTouchCancelEvent(window2, wasmEventTranslator->getTimestamp(), wasmEventTranslator->touchDevice, keyModifier);
QWindowSystemInterface::handleTouchCancelEvent(window2, wasmEventTranslator->getTimestamp(),
wasmEventTranslator->touchDevice, keyModifier);
QWasmEventDispatcher::maintainTimers();
return 1;
@ -578,4 +732,112 @@ quint64 QWasmEventTranslator::getTimestamp()
return QDeadlineTimer::current().deadlineNSecs() / 1000;
}
Qt::Key QWasmEventTranslator::translateDeadKey(Qt::Key deadKey, Qt::Key accentBaseKey)
{
Qt::Key wasmKey = Qt::Key_unknown;
switch (deadKey) {
#ifdef Q_OS_MACOS
case Qt::Key_QuoteLeft: // ` macOS: Key_Dead_Grave
#else
case Qt::Key_O: // ´ Key_Dead_Grave
#endif
wasmKey = graveKeyTable.value(accentBaseKey);
break;
case Qt::Key_E: // ´ Key_Dead_Acute
wasmKey = acuteKeyTable.value(accentBaseKey);
break;
case Qt::Key_AsciiTilde:
case Qt::Key_N:// Key_Dead_Tilde
wasmKey = tildeKeyTable.value(accentBaseKey);
break;
#ifndef Q_OS_MACOS
case Qt::Key_QuoteLeft:
#endif
case Qt::Key_U:// ¨ Key_Dead_Diaeresis
wasmKey = diaeresisKeyTable.value(accentBaseKey);
break;
case Qt::Key_I:// macOS Key_Dead_Circumflex
case Qt::Key_6:// linux
case Qt::Key_Apostrophe:// linux
wasmKey = circumflexKeyTable.value(accentBaseKey);
break;
break;
default:
break;
};
return wasmKey;
}
bool QWasmEventTranslator::processKeyboard(int eventType, const EmscriptenKeyboardEvent *keyEvent)
{
Qt::Key qtKey = translateEmscriptKey(keyEvent);
Qt::KeyboardModifiers modifiers = translateKeyboardEventModifier(keyEvent);
QString keyText;
QEvent::Type keyType = QEvent::None;
switch (eventType) {
case EMSCRIPTEN_EVENT_KEYPRESS:
case EMSCRIPTEN_EVENT_KEYDOWN: // down
keyType = QEvent::KeyPress;
if (m_emDeadKey != Qt::Key_unknown) {
Qt::Key transformedKey = translateDeadKey(m_emDeadKey, qtKey);
if (transformedKey != Qt::Key_unknown)
qtKey = transformedKey;
if (keyEvent->shiftKey == 0) {
for (auto it = KeyTbl.cbegin(); it != KeyTbl.end(); ++it) {
if (it != KeyTbl.end() && (qtKey == static_cast<Qt::Key>(it->qt))) {
keyText = it->em;
m_emDeadKey = Qt::Key_unknown;
break;
}
}
} else {
for (auto it = DeadKeyShiftTbl.cbegin(); it != DeadKeyShiftTbl.end(); ++it) {
if (it != DeadKeyShiftTbl.end() && (qtKey == static_cast<Qt::Key>(it->qt))) {
keyText = it->em;
m_emDeadKey = Qt::Key_unknown;
break;
}
}
}
}
if (qstrncmp(keyEvent->key, "Dead", 4) == 0 || qtKey == Qt::Key_AltGr) {
qtKey = translateEmscriptKey(keyEvent);
m_emStickyDeadKey = true;
if (keyEvent->shiftKey == 1 && qtKey == Qt::Key_QuoteLeft)
qtKey = Qt::Key_AsciiTilde;
m_emDeadKey = qtKey;
}
break;
case EMSCRIPTEN_EVENT_KEYUP: // up
keyType = QEvent::KeyRelease;
if (m_emStickyDeadKey && qtKey != Qt::Key_Alt) {
m_emStickyDeadKey = false;
}
break;
default:
break;
};
if (keyType == QEvent::None)
return 0;
bool accepted = false;
if (keyText.isEmpty())
keyText = QString(keyEvent->key);
if (keyText.size() > 1)
keyText.clear();
accepted = QWindowSystemInterface::handleKeyEvent<QWindowSystemInterface::SynchronousDelivery>(
0, keyType, qtKey, modifiers, keyText);
QWasmEventDispatcher::maintainTimers();
return accepted ? 1 : 0;
}
QT_END_NAMESPACE

View File

@ -36,6 +36,7 @@
#include <emscripten/html5.h>
#include "qwasmwindow.h"
#include <QtGui/qtouchdevice.h>
#include <QHash>
QT_BEGIN_NAMESPACE
@ -45,130 +46,6 @@ class QWasmEventTranslator : public QObject
{
Q_OBJECT
enum KeyCode {
// numpad
KeyNumPad0 = 0x60,
KeyNumPad1 = 0x61,
KeyNumPad2 = 0x62,
KeyNumPad3 = 0x63,
KeyNumPad4 = 0x64,
KeyNumPad5 = 0x65,
KeyNumPad6 = 0x66,
KeyNumPad7 = 0x67,
KeyNumPad8 = 0x68,
KeyNumPad9 = 0x69,
KeyMultiply = 0x6A,
KeyAdd = 0x6B,
KeySeparator = 0x6C,
KeySubtract = 0x6D,
KeyDecimal = 0x6E,
KeyDivide = 0x6F,
KeyMeta = 0x5B,
KeyMetaRight = 0x5C,
////////
KeyClear = 0x90,
KeyEnter = 0xD,
KeyBackSpace = 0x08,
KeyCancel = 0x03,
KeyTab = 0x09,
KeyShift = 0x10,
KeyControl = 0x11,
KeyAlt = 0x12,
KeyPause = 0x13,
KeyCapsLock = 0x14,
KeyEscape = 0x1B,
KeySpace = 0x20,
KeyPageUp = 0x21,
KeyPageDown = 0x22,
KeyEnd = 0x23,
KeyHome = 0x24,
KeyLeft = 0x25,
KeyUp = 0x26,
KeyRight = 0x27,
KeyDown = 0x28,
KeyComma = 0xBC,
KeyPeriod = 0xBE,
KeySlash = 0xBF,
KeyZero = 0x30,
KeyOne = 0x31,
KeyTwo = 0x32,
KeyThree = 0x33,
KeyFour = 0x34,
KeyFive = 0x35,
KeySix = 0x36,
KeySeven = 0x37,
KeyEight = 0x38,
KeyNine = 0x39,
KeyBrightnessDown = 0xD8,
KeyBrightnessUp = 0xD9,
KeyMediaTrackPrevious = 0xB1,
KeyMediaPlayPause = 0xB3,
KeyMediaTrackNext = 0xB0,
KeyAudioVolumeMute = 0xAD,
KeyAudioVolumeDown = 0xAE,
KeyAudioVolumeUp = 0xAF,
KeySemiColon = 0xBA,
KeyEquals = 0xBB,
KeyMinus = 0xBD,
KeyA = 0x41,
KeyB = 0x42,
KeyC = 0x43,
KeyD = 0x44,
KeyE = 0x45,
KeyF = 0x46,
KeyG = 0x47,
KeyH = 0x48,
KeyI = 0x49,
KeyJ = 0x4A,
KeyK = 0x4B,
KeyL = 0x4C,
KeyM = 0x4D,
KeyN = 0x4E,
KeyO = 0x4F,
KeyP = 0x50,
KeyQ = 0x51,
KeyR = 0x52,
KeyS = 0x53,
KeyT = 0x54,
KeyU = 0x55,
KeyV = 0x56,
KeyW = 0x57,
KeyX = 0x58,
KeyY = 0x59,
KeyZ = 0x5A,
KeyOpenBracket = 0xDB,
KeyBackSlash = 0xDC,
KeyCloseBracket = 0xDD,
KeyF1 = 0x70,
KeyF2 = 0x71,
KeyF3 = 0x72,
KeyF4 = 0x73,
KeyF5 = 0x74,
KeyF6 = 0x75,
KeyF7 = 0x76,
KeyF8 = 0x77,
KeyF9 = 0x78,
KeyF10 = 0x79,
KeyF11 = 0x7A,
KeyF12 = 0x7B,
KeyDelete = 0x2E,
KeyNumLock = 0x90,
KeyScrollLock = 0x91,
KeyPrintScreen = 0x9A,
KeyInsert = 0x9B,
KeyHelp = 0x9C,
KeyBackQuote = 0xC0,
KeyQuote = 0xDE,
KeyFinal = 0x18,
KeyConvert = 0x1C,
KeyNonConvert = 0x1D,
KeyAccept = 0x1E,
KeyModeChange = 0x1F,
KeyKana = 0x15,
KeyKanji = 0x19,
KeyUndefined = 0x0
};
public:
explicit QWasmEventTranslator(QObject *parent = 0);
@ -185,14 +62,54 @@ public:
Q_SIGNALS:
void getWindowAt(const QPoint &point, QWindow **window);
private:
static Qt::Key translateEmscriptKey(const EmscriptenKeyboardEvent *emscriptKey, bool *outAlphanumretic);
Qt::Key translateEmscriptKey(const EmscriptenKeyboardEvent *emscriptKey);
template <typename Event>
static QFlags<Qt::KeyboardModifier> translatKeyModifier(const Event *event);
static QFlags<Qt::KeyboardModifier> translateKeyboardEventModifier(const EmscriptenKeyboardEvent *keyEvent);
static QFlags<Qt::KeyboardModifier> translateMouseEventModifier(const EmscriptenMouseEvent *mouseEvent);
static Qt::MouseButton translateMouseButton(unsigned short button);
QFlags<Qt::KeyboardModifier> translatKeyModifier(const Event *event);
QFlags<Qt::KeyboardModifier> translateKeyboardEventModifier(const EmscriptenKeyboardEvent *keyEvent);
QFlags<Qt::KeyboardModifier> translateMouseEventModifier(const EmscriptenMouseEvent *mouseEvent);
Qt::MouseButton translateMouseButton(unsigned short button);
void processMouse(int eventType, const EmscriptenMouseEvent *mouseEvent);
bool processKeyboard(int eventType, const EmscriptenKeyboardEvent *keyEvent);
Qt::Key translateDeadKey(Qt::Key deadKey, Qt::Key accentBaseKey);
QHash<Qt::Key , Qt::Key> tildeKeyTable { // ~
{ Qt::Key_A, Qt::Key_Atilde},
{ Qt::Key_N, Qt::Key_Ntilde},
{ Qt::Key_O, Qt::Key_Otilde}
};
QHash<Qt::Key , Qt::Key> graveKeyTable { // `
{ Qt::Key_A, Qt::Key_Agrave},
{ Qt::Key_E, Qt::Key_Egrave},
{ Qt::Key_I, Qt::Key_Igrave},
{ Qt::Key_O, Qt::Key_Ograve},
{ Qt::Key_U, Qt::Key_Ugrave}
};
QHash<Qt::Key , Qt::Key> acuteKeyTable { // '
{ Qt::Key_A, Qt::Key_Aacute},
{ Qt::Key_E, Qt::Key_Eacute},
{ Qt::Key_I, Qt::Key_Iacute},
{ Qt::Key_O, Qt::Key_Oacute},
{ Qt::Key_U, Qt::Key_Uacute},
{ Qt::Key_Y, Qt::Key_Yacute}
};
QHash<Qt::Key , Qt::Key> diaeresisKeyTable { // umlaut ¨
{ Qt::Key_A, Qt::Key_Adiaeresis},
{ Qt::Key_E, Qt::Key_Ediaeresis},
{ Qt::Key_I, Qt::Key_Idiaeresis},
{ Qt::Key_O, Qt::Key_Odiaeresis},
{ Qt::Key_U, Qt::Key_Udiaeresis},
{ Qt::Key_Y, Qt::Key_ydiaeresis}
};
QHash<Qt::Key , Qt::Key> circumflexKeyTable { // ^
{ Qt::Key_A, Qt::Key_Acircumflex},
{ Qt::Key_E, Qt::Key_Ecircumflex},
{ Qt::Key_I, Qt::Key_Icircumflex},
{ Qt::Key_O, Qt::Key_Ocircumflex},
{ Qt::Key_U, Qt::Key_Ucircumflex}
};
private:
QWindow *draggedWindow;
@ -205,6 +122,9 @@ private:
QRect resizeStartRect;
QTouchDevice *touchDevice;
quint64 getTimestamp();
Qt::Key m_emDeadKey = Qt::Key_unknown;
bool m_emStickyDeadKey = false;
};
QT_END_NAMESPACE