Transfer the key handling logic to QWasmWindow
Also, use the embind approach as the rest of the events do, and introduce a KeyEvent class which simplifies and streamlines event support. The event translator has been given a more specific function of just handling the dead keys. Rest of the translation functionality is coded directly in KeyEvent for more encapsulation. Change-Id: I11b0262fc42fe920206ecc6de0d434b9d9ab9998 Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
This commit is contained in:
parent
62be4ab5be
commit
d141d68949
@ -23,9 +23,9 @@ qt_internal_add_plugin(QWasmIntegrationPlugin
|
|||||||
qwasmdom.cpp qwasmdom.h
|
qwasmdom.cpp qwasmdom.h
|
||||||
qwasmevent.cpp qwasmevent.h
|
qwasmevent.cpp qwasmevent.h
|
||||||
qwasmeventdispatcher.cpp qwasmeventdispatcher.h
|
qwasmeventdispatcher.cpp qwasmeventdispatcher.h
|
||||||
qwasmeventtranslator.cpp qwasmeventtranslator.h
|
|
||||||
qwasmfontdatabase.cpp qwasmfontdatabase.h
|
qwasmfontdatabase.cpp qwasmfontdatabase.h
|
||||||
qwasmintegration.cpp qwasmintegration.h
|
qwasmintegration.cpp qwasmintegration.h
|
||||||
|
qwasmkeytranslator.cpp qwasmkeytranslator.h
|
||||||
qwasmoffscreensurface.cpp qwasmoffscreensurface.h
|
qwasmoffscreensurface.cpp qwasmoffscreensurface.h
|
||||||
qwasmopenglcontext.cpp qwasmopenglcontext.h
|
qwasmopenglcontext.cpp qwasmopenglcontext.h
|
||||||
qwasmplatform.cpp qwasmplatform.h
|
qwasmplatform.cpp qwasmplatform.h
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "qwasmclipboard.h"
|
#include "qwasmclipboard.h"
|
||||||
#include "qwasmdom.h"
|
#include "qwasmdom.h"
|
||||||
|
#include "qwasmevent.h"
|
||||||
#include "qwasmwindow.h"
|
#include "qwasmwindow.h"
|
||||||
|
|
||||||
#include <private/qstdweb_p.h>
|
#include <private/qstdweb_p.h>
|
||||||
@ -129,11 +130,9 @@ void QWasmClipboard::setMimeData(QMimeData *mimeData, QClipboard::Mode mode)
|
|||||||
writeToClipboard();
|
writeToClipboard();
|
||||||
}
|
}
|
||||||
|
|
||||||
QWasmClipboard::ProcessKeyboardResult
|
QWasmClipboard::ProcessKeyboardResult QWasmClipboard::processKeyboard(const KeyEvent &event)
|
||||||
QWasmClipboard::processKeyboard(const QWasmEventTranslator::TranslatedEvent &event,
|
|
||||||
const QFlags<Qt::KeyboardModifier> &modifiers)
|
|
||||||
{
|
{
|
||||||
if (event.type != QEvent::KeyPress || !modifiers.testFlag(Qt::ControlModifier))
|
if (event.type != EventType::KeyDown || !event.modifiers.testFlag(Qt::ControlModifier))
|
||||||
return ProcessKeyboardResult::Ignored;
|
return ProcessKeyboardResult::Ignored;
|
||||||
|
|
||||||
if (event.key != Qt::Key_C && event.key != Qt::Key_V && event.key != Qt::Key_X)
|
if (event.key != Qt::Key_C && event.key != Qt::Key_V && event.key != Qt::Key_X)
|
||||||
|
@ -12,10 +12,10 @@
|
|||||||
#include <emscripten/bind.h>
|
#include <emscripten/bind.h>
|
||||||
#include <emscripten/val.h>
|
#include <emscripten/val.h>
|
||||||
|
|
||||||
#include "qwasmeventtranslator.h"
|
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
struct KeyEvent;
|
||||||
|
|
||||||
class QWasmClipboard : public QObject, public QPlatformClipboard
|
class QWasmClipboard : public QObject, public QPlatformClipboard
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -34,8 +34,7 @@ public:
|
|||||||
bool supportsMode(QClipboard::Mode mode) const override;
|
bool supportsMode(QClipboard::Mode mode) const override;
|
||||||
bool ownsMode(QClipboard::Mode mode) const override;
|
bool ownsMode(QClipboard::Mode mode) const override;
|
||||||
|
|
||||||
ProcessKeyboardResult processKeyboard(const QWasmEventTranslator::TranslatedEvent &event,
|
ProcessKeyboardResult processKeyboard(const KeyEvent &event);
|
||||||
const QFlags<Qt::KeyboardModifier> &modifiers);
|
|
||||||
static void installEventHandlers(const emscripten::val &target);
|
static void installEventHandlers(const emscripten::val &target);
|
||||||
bool hasClipboardApi();
|
bool hasClipboardApi();
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
#include "qwasmcompositor.h"
|
#include "qwasmcompositor.h"
|
||||||
#include "qwasmwindow.h"
|
#include "qwasmwindow.h"
|
||||||
#include "qwasmeventtranslator.h"
|
|
||||||
#include "qwasmeventdispatcher.h"
|
#include "qwasmeventdispatcher.h"
|
||||||
#include "qwasmclipboard.h"
|
#include "qwasmclipboard.h"
|
||||||
#include "qwasmevent.h"
|
#include "qwasmevent.h"
|
||||||
@ -30,9 +29,7 @@ using namespace emscripten;
|
|||||||
Q_GUI_EXPORT int qt_defaultDpiX();
|
Q_GUI_EXPORT int qt_defaultDpiX();
|
||||||
|
|
||||||
QWasmCompositor::QWasmCompositor(QWasmScreen *screen)
|
QWasmCompositor::QWasmCompositor(QWasmScreen *screen)
|
||||||
: QObject(screen),
|
: QObject(screen), m_windowStack(std::bind(&QWasmCompositor::onTopWindowChanged, this))
|
||||||
m_windowStack(std::bind(&QWasmCompositor::onTopWindowChanged, this)),
|
|
||||||
m_eventTranslator(std::make_unique<QWasmEventTranslator>())
|
|
||||||
{
|
{
|
||||||
m_touchDevice = std::make_unique<QPointingDevice>(
|
m_touchDevice = std::make_unique<QPointingDevice>(
|
||||||
"touchscreen", 1, QInputDevice::DeviceType::TouchScreen,
|
"touchscreen", 1, QInputDevice::DeviceType::TouchScreen,
|
||||||
@ -61,12 +58,11 @@ void QWasmCompositor::onScreenDeleting()
|
|||||||
void QWasmCompositor::deregisterEventHandlers()
|
void QWasmCompositor::deregisterEventHandlers()
|
||||||
{
|
{
|
||||||
QByteArray screenElementSelector = screen()->eventTargetId().toUtf8();
|
QByteArray screenElementSelector = screen()->eventTargetId().toUtf8();
|
||||||
emscripten_set_keydown_callback(screenElementSelector.constData(), 0, 0, NULL);
|
|
||||||
emscripten_set_keyup_callback(screenElementSelector.constData(), 0, 0, NULL);
|
|
||||||
|
|
||||||
emscripten_set_touchstart_callback(screenElementSelector.constData(), 0, 0, NULL);
|
emscripten_set_touchstart_callback(screenElementSelector.constData(), 0, 0, NULL);
|
||||||
emscripten_set_touchend_callback(screenElementSelector.constData(), 0, 0, NULL);
|
emscripten_set_touchend_callback(screenElementSelector.constData(), 0, 0, NULL);
|
||||||
emscripten_set_touchmove_callback(screenElementSelector.constData(), 0, 0, NULL);
|
emscripten_set_touchmove_callback(screenElementSelector.constData(), 0, 0, NULL);
|
||||||
|
|
||||||
emscripten_set_touchcancel_callback(screenElementSelector.constData(), 0, 0, NULL);
|
emscripten_set_touchcancel_callback(screenElementSelector.constData(), 0, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,11 +78,6 @@ void QWasmCompositor::initEventHandlers()
|
|||||||
constexpr EM_BOOL UseCapture = 1;
|
constexpr EM_BOOL UseCapture = 1;
|
||||||
|
|
||||||
const QByteArray screenElementSelector = screen()->eventTargetId().toUtf8();
|
const QByteArray screenElementSelector = screen()->eventTargetId().toUtf8();
|
||||||
emscripten_set_keydown_callback(screenElementSelector.constData(), (void *)this, UseCapture,
|
|
||||||
&keyboard_cb);
|
|
||||||
emscripten_set_keyup_callback(screenElementSelector.constData(), (void *)this, UseCapture,
|
|
||||||
&keyboard_cb);
|
|
||||||
|
|
||||||
emscripten_set_touchstart_callback(screenElementSelector.constData(), (void *)this, UseCapture,
|
emscripten_set_touchstart_callback(screenElementSelector.constData(), (void *)this, UseCapture,
|
||||||
&touchCallback);
|
&touchCallback);
|
||||||
emscripten_set_touchend_callback(screenElementSelector.constData(), (void *)this, UseCapture,
|
emscripten_set_touchend_callback(screenElementSelector.constData(), (void *)this, UseCapture,
|
||||||
@ -283,46 +274,12 @@ QWasmScreen *QWasmCompositor::screen()
|
|||||||
return static_cast<QWasmScreen *>(parent());
|
return static_cast<QWasmScreen *>(parent());
|
||||||
}
|
}
|
||||||
|
|
||||||
int QWasmCompositor::keyboard_cb(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)
|
|
||||||
{
|
|
||||||
QWasmCompositor *wasmCompositor = reinterpret_cast<QWasmCompositor *>(userData);
|
|
||||||
return static_cast<int>(wasmCompositor->processKeyboard(eventType, keyEvent));
|
|
||||||
}
|
|
||||||
|
|
||||||
int QWasmCompositor::touchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)
|
int QWasmCompositor::touchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)
|
||||||
{
|
{
|
||||||
auto compositor = reinterpret_cast<QWasmCompositor*>(userData);
|
auto compositor = reinterpret_cast<QWasmCompositor*>(userData);
|
||||||
return static_cast<int>(compositor->processTouch(eventType, touchEvent));
|
return static_cast<int>(compositor->processTouch(eventType, touchEvent));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QWasmCompositor::processKeyboard(int eventType, const EmscriptenKeyboardEvent *emKeyEvent)
|
|
||||||
{
|
|
||||||
constexpr bool ProceedToNativeEvent = false;
|
|
||||||
Q_ASSERT(eventType == EMSCRIPTEN_EVENT_KEYDOWN || eventType == EMSCRIPTEN_EVENT_KEYUP);
|
|
||||||
|
|
||||||
auto translatedEvent = m_eventTranslator->translateKeyEvent(eventType, emKeyEvent);
|
|
||||||
|
|
||||||
const QFlags<Qt::KeyboardModifier> modifiers = KeyboardModifier::getForEvent(*emKeyEvent);
|
|
||||||
|
|
||||||
const auto clipboardResult = QWasmIntegration::get()->getWasmClipboard()->processKeyboard(
|
|
||||||
translatedEvent, modifiers);
|
|
||||||
|
|
||||||
using ProcessKeyboardResult = QWasmClipboard::ProcessKeyboardResult;
|
|
||||||
if (clipboardResult == ProcessKeyboardResult::NativeClipboardEventNeeded)
|
|
||||||
return ProceedToNativeEvent;
|
|
||||||
|
|
||||||
if (translatedEvent.text.isEmpty())
|
|
||||||
translatedEvent.text = QString(emKeyEvent->key);
|
|
||||||
if (translatedEvent.text.size() > 1)
|
|
||||||
translatedEvent.text.clear();
|
|
||||||
const auto result =
|
|
||||||
QWindowSystemInterface::handleKeyEvent(
|
|
||||||
0, translatedEvent.type, translatedEvent.key, modifiers, translatedEvent.text);
|
|
||||||
return clipboardResult == ProcessKeyboardResult::NativeClipboardEventAndCopiedDataNeeded
|
|
||||||
? ProceedToNativeEvent
|
|
||||||
: result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QWasmCompositor::processTouch(int eventType, const EmscriptenTouchEvent *touchEvent)
|
bool QWasmCompositor::processTouch(int eventType, const EmscriptenTouchEvent *touchEvent)
|
||||||
{
|
{
|
||||||
QList<QWindowSystemInterface::TouchPoint> touchPointList;
|
QList<QWindowSystemInterface::TouchPoint> touchPointList;
|
||||||
|
@ -26,7 +26,6 @@ class QWasmWindow;
|
|||||||
class QWasmScreen;
|
class QWasmScreen;
|
||||||
class QOpenGLContext;
|
class QOpenGLContext;
|
||||||
class QOpenGLTexture;
|
class QOpenGLTexture;
|
||||||
class QWasmEventTranslator;
|
|
||||||
|
|
||||||
class QWasmCompositor final : public QObject
|
class QWasmCompositor final : public QObject
|
||||||
{
|
{
|
||||||
@ -69,11 +68,8 @@ private:
|
|||||||
void deliverUpdateRequests();
|
void deliverUpdateRequests();
|
||||||
void deliverUpdateRequest(QWasmWindow *window, UpdateRequestDeliveryType updateType);
|
void deliverUpdateRequest(QWasmWindow *window, UpdateRequestDeliveryType updateType);
|
||||||
|
|
||||||
static int keyboard_cb(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData);
|
|
||||||
|
|
||||||
static int touchCallback(int eventType, const EmscriptenTouchEvent *ev, void *userData);
|
static int touchCallback(int eventType, const EmscriptenTouchEvent *ev, void *userData);
|
||||||
|
|
||||||
bool processKeyboard(int eventType, const EmscriptenKeyboardEvent *keyEvent);
|
|
||||||
bool processTouch(int eventType, const EmscriptenTouchEvent *touchEvent);
|
bool processTouch(int eventType, const EmscriptenTouchEvent *touchEvent);
|
||||||
|
|
||||||
void updateEnabledState();
|
void updateEnabledState();
|
||||||
@ -89,8 +85,6 @@ private:
|
|||||||
std::unique_ptr<QPointingDevice> m_touchDevice;
|
std::unique_ptr<QPointingDevice> m_touchDevice;
|
||||||
|
|
||||||
QMap<int, QPointF> m_pressedTouchIds;
|
QMap<int, QPointF> m_pressedTouchIds;
|
||||||
|
|
||||||
std::unique_ptr<QWasmEventTranslator> m_eventTranslator;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -3,8 +3,39 @@
|
|||||||
|
|
||||||
#include "qwasmevent.h"
|
#include "qwasmevent.h"
|
||||||
|
|
||||||
|
#include "qwasmkeytranslator.h"
|
||||||
|
|
||||||
|
#include <QtCore/private/qmakearray_p.h>
|
||||||
|
#include <QtCore/private/qstringiterator_p.h>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
constexpr std::string_view WebDeadKeyValue = "Dead";
|
||||||
|
|
||||||
|
bool isDeadKeyEvent(const char *key)
|
||||||
|
{
|
||||||
|
return qstrncmp(key, WebDeadKeyValue.data(), WebDeadKeyValue.size()) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::Key webKeyToQtKey(const std::string &code, const std::string &key, bool isDeadKey)
|
||||||
|
{
|
||||||
|
if (isDeadKey) {
|
||||||
|
if (auto mapping = QWasmKeyTranslator::mapWebKeyTextToQtKey(code.c_str()))
|
||||||
|
return *mapping;
|
||||||
|
}
|
||||||
|
if (auto mapping = QWasmKeyTranslator::mapWebKeyTextToQtKey(key.c_str()))
|
||||||
|
return *mapping;
|
||||||
|
if (isDeadKey)
|
||||||
|
return Qt::Key_unknown;
|
||||||
|
|
||||||
|
// cast to unicode key
|
||||||
|
QString str = QString::fromUtf8(key.c_str()).toUpper();
|
||||||
|
QStringIterator i(str);
|
||||||
|
return static_cast<Qt::Key>(i.next(0));
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
namespace KeyboardModifier
|
namespace KeyboardModifier
|
||||||
{
|
{
|
||||||
template <>
|
template <>
|
||||||
@ -28,6 +59,51 @@ Event &Event::operator=(const Event &other) = default;
|
|||||||
|
|
||||||
Event &Event::operator=(Event &&other) = default;
|
Event &Event::operator=(Event &&other) = default;
|
||||||
|
|
||||||
|
KeyEvent::KeyEvent(EventType type, emscripten::val event) : Event(type, event["target"])
|
||||||
|
{
|
||||||
|
const auto code = event["code"].as<std::string>();
|
||||||
|
const auto webKey = event["key"].as<std::string>();
|
||||||
|
deadKey = isDeadKeyEvent(webKey.c_str());
|
||||||
|
|
||||||
|
key = webKeyToQtKey(code, webKey, deadKey);
|
||||||
|
|
||||||
|
modifiers = KeyboardModifier::getForEvent(event);
|
||||||
|
text = QString::fromUtf8(webKey);
|
||||||
|
if (text.size() > 1)
|
||||||
|
text.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyEvent::~KeyEvent() = default;
|
||||||
|
|
||||||
|
KeyEvent::KeyEvent(const KeyEvent &other) = default;
|
||||||
|
|
||||||
|
KeyEvent::KeyEvent(KeyEvent &&other) = default;
|
||||||
|
|
||||||
|
KeyEvent &KeyEvent::operator=(const KeyEvent &other) = default;
|
||||||
|
|
||||||
|
KeyEvent &KeyEvent::operator=(KeyEvent &&other) = default;
|
||||||
|
|
||||||
|
std::optional<KeyEvent> KeyEvent::fromWebWithDeadKeyTranslation(emscripten::val event,
|
||||||
|
QWasmDeadKeySupport *deadKeySupport)
|
||||||
|
{
|
||||||
|
const auto eventType = ([&event]() -> std::optional<EventType> {
|
||||||
|
const auto eventTypeString = event["type"].as<std::string>();
|
||||||
|
|
||||||
|
if (eventTypeString == "keydown")
|
||||||
|
return EventType::KeyDown;
|
||||||
|
else if (eventTypeString == "keyup")
|
||||||
|
return EventType::KeyUp;
|
||||||
|
return std::nullopt;
|
||||||
|
})();
|
||||||
|
if (!eventType)
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
auto result = KeyEvent(*eventType, event);
|
||||||
|
deadKeySupport->applyDeadKeyTranslations(&result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
MouseEvent::MouseEvent(EventType type, emscripten::val event) : Event(type, event["target"])
|
MouseEvent::MouseEvent(EventType type, emscripten::val event) : Event(type, event["target"])
|
||||||
{
|
{
|
||||||
mouseButton = MouseEvent::buttonFromWeb(event["button"].as<int>());
|
mouseButton = MouseEvent::buttonFromWeb(event["button"].as<int>());
|
||||||
|
@ -17,8 +17,12 @@
|
|||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
class QWasmDeadKeySupport;
|
||||||
|
|
||||||
enum class EventType {
|
enum class EventType {
|
||||||
Drop,
|
Drop,
|
||||||
|
KeyDown,
|
||||||
|
KeyUp,
|
||||||
PointerDown,
|
PointerDown,
|
||||||
PointerMove,
|
PointerMove,
|
||||||
PointerUp,
|
PointerUp,
|
||||||
@ -113,26 +117,37 @@ QFlags<Qt::KeyboardModifier> getForEvent<EmscriptenKeyboardEvent>(
|
|||||||
|
|
||||||
struct Event
|
struct Event
|
||||||
{
|
{
|
||||||
EventType type;
|
|
||||||
emscripten::val target = emscripten::val::undefined();
|
|
||||||
|
|
||||||
Event(EventType type, emscripten::val target);
|
Event(EventType type, emscripten::val target);
|
||||||
~Event();
|
~Event();
|
||||||
Event(const Event &other);
|
Event(const Event &other);
|
||||||
Event(Event &&other);
|
Event(Event &&other);
|
||||||
Event &operator=(const Event &other);
|
Event &operator=(const Event &other);
|
||||||
Event &operator=(Event &&other);
|
Event &operator=(Event &&other);
|
||||||
|
|
||||||
|
EventType type;
|
||||||
|
emscripten::val target = emscripten::val::undefined();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct KeyEvent : public Event
|
||||||
|
{
|
||||||
|
static std::optional<KeyEvent>
|
||||||
|
fromWebWithDeadKeyTranslation(emscripten::val webEvent, QWasmDeadKeySupport *deadKeySupport);
|
||||||
|
|
||||||
|
KeyEvent(EventType type, emscripten::val webEvent);
|
||||||
|
~KeyEvent();
|
||||||
|
KeyEvent(const KeyEvent &other);
|
||||||
|
KeyEvent(KeyEvent &&other);
|
||||||
|
KeyEvent &operator=(const KeyEvent &other);
|
||||||
|
KeyEvent &operator=(KeyEvent &&other);
|
||||||
|
|
||||||
|
Qt::Key key;
|
||||||
|
QFlags<Qt::KeyboardModifier> modifiers;
|
||||||
|
bool deadKey;
|
||||||
|
QString text;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MouseEvent : public Event
|
struct MouseEvent : public Event
|
||||||
{
|
{
|
||||||
QPoint localPoint;
|
|
||||||
QPoint pointInPage;
|
|
||||||
QPoint pointInViewport;
|
|
||||||
Qt::MouseButton mouseButton;
|
|
||||||
Qt::MouseButtons mouseButtons;
|
|
||||||
QFlags<Qt::KeyboardModifier> modifiers;
|
|
||||||
|
|
||||||
MouseEvent(EventType type, emscripten::val webEvent);
|
MouseEvent(EventType type, emscripten::val webEvent);
|
||||||
~MouseEvent();
|
~MouseEvent();
|
||||||
MouseEvent(const MouseEvent &other);
|
MouseEvent(const MouseEvent &other);
|
||||||
@ -174,6 +189,13 @@ struct MouseEvent : public Event
|
|||||||
return QEvent::None;
|
return QEvent::None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPoint localPoint;
|
||||||
|
QPoint pointInPage;
|
||||||
|
QPoint pointInViewport;
|
||||||
|
Qt::MouseButton mouseButton;
|
||||||
|
Qt::MouseButtons mouseButtons;
|
||||||
|
QFlags<Qt::KeyboardModifier> modifiers;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PointerEvent : public MouseEvent
|
struct PointerEvent : public MouseEvent
|
||||||
|
@ -1,339 +0,0 @@
|
|||||||
// Copyright (C) 2018 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
|
||||||
|
|
||||||
#include "qwasmeventtranslator.h"
|
|
||||||
#include "qwasmeventdispatcher.h"
|
|
||||||
#include "qwasmcompositor.h"
|
|
||||||
#include "qwasmintegration.h"
|
|
||||||
#include "qwasmclipboard.h"
|
|
||||||
#include "qwasmcursor.h"
|
|
||||||
#include <QtGui/qevent.h>
|
|
||||||
#include <qpa/qwindowsysteminterface.h>
|
|
||||||
#include <QtCore/qcoreapplication.h>
|
|
||||||
#include <QtCore/qglobal.h>
|
|
||||||
#include <QtCore/qobject.h>
|
|
||||||
|
|
||||||
#include <QtCore/qdeadlinetimer.h>
|
|
||||||
#include <private/qmakearray_p.h>
|
|
||||||
#include <QtCore/qnamespace.h>
|
|
||||||
#include <QCursor>
|
|
||||||
#include <QtCore/private/qstringiterator_p.h>
|
|
||||||
|
|
||||||
#include <emscripten/bind.h>
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
|
||||||
|
|
||||||
using namespace emscripten;
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
constexpr std::string_view WebDeadKeyValue = "Dead";
|
|
||||||
|
|
||||||
struct Emkb2QtData
|
|
||||||
{
|
|
||||||
static constexpr char StringTerminator = '\0';
|
|
||||||
|
|
||||||
const char *em;
|
|
||||||
unsigned int qt;
|
|
||||||
|
|
||||||
constexpr bool operator<=(const Emkb2QtData &that) const noexcept
|
|
||||||
{
|
|
||||||
return !(strcmp(that) > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator<(const Emkb2QtData &that) const noexcept { return ::strcmp(em, that.em) < 0; }
|
|
||||||
|
|
||||||
constexpr bool operator==(const Emkb2QtData &that) const noexcept { return strcmp(that) == 0; }
|
|
||||||
|
|
||||||
constexpr int strcmp(const Emkb2QtData &that, const int i = 0) const
|
|
||||||
{
|
|
||||||
return em[i] == StringTerminator && that.em[i] == StringTerminator ? 0
|
|
||||||
: em[i] == StringTerminator ? -1
|
|
||||||
: that.em[i] == StringTerminator ? 1
|
|
||||||
: em[i] < that.em[i] ? -1
|
|
||||||
: em[i] > that.em[i] ? 1
|
|
||||||
: strcmp(that, i + 1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<unsigned int Qt, char ... EmChar>
|
|
||||||
struct Emkb2Qt
|
|
||||||
{
|
|
||||||
static constexpr const char storage[sizeof ... (EmChar) + 1] = {EmChar..., '\0'};
|
|
||||||
using Type = Emkb2QtData;
|
|
||||||
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 WebToQtKeyCodeMappings = 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, 'M','e','t','a'>,
|
|
||||||
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_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_yen, 'I','n','t','l','Y','e','n' >,
|
|
||||||
Emkb2Qt< Qt::Key_Menu, 'C','o','n','t','e','x','t','M','e','n','u' >
|
|
||||||
>::Data{}
|
|
||||||
);
|
|
||||||
|
|
||||||
static constexpr const auto WebToQtKeyCodeMappingsWithShift = 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_Iacute, '\xc3','\x8d' >,
|
|
||||||
Emkb2Qt< Qt::Key_Icircumflex, '\xc3','\x8e' >,
|
|
||||||
Emkb2Qt< Qt::Key_Idiaeresis, '\xc3','\x8f' >,
|
|
||||||
Emkb2Qt< Qt::Key_Igrave, '\xc3','\x8c' >,
|
|
||||||
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' >,
|
|
||||||
Emkb2Qt< Qt::Key_Yacute, '\xc3','\x9d' >
|
|
||||||
>::Data{}
|
|
||||||
);
|
|
||||||
|
|
||||||
std::optional<Qt::Key> findMappingByBisection(const char *toFind)
|
|
||||||
{
|
|
||||||
const Emkb2QtData searchKey{ toFind, 0 };
|
|
||||||
const auto it = std::lower_bound(WebToQtKeyCodeMappings.cbegin(), WebToQtKeyCodeMappings.cend(),
|
|
||||||
searchKey);
|
|
||||||
return it != WebToQtKeyCodeMappings.cend() && searchKey == *it ? static_cast<Qt::Key>(it->qt)
|
|
||||||
: std::optional<Qt::Key>();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isDeadKeyEvent(const EmscriptenKeyboardEvent *emKeyEvent)
|
|
||||||
{
|
|
||||||
return qstrncmp(emKeyEvent->key, WebDeadKeyValue.data(), WebDeadKeyValue.size()) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Qt::Key translateEmscriptKey(const EmscriptenKeyboardEvent *emscriptKey)
|
|
||||||
{
|
|
||||||
const bool deadKeyEvent = isDeadKeyEvent(emscriptKey);
|
|
||||||
if (deadKeyEvent) {
|
|
||||||
if (auto mapping = findMappingByBisection(emscriptKey->code))
|
|
||||||
return *mapping;
|
|
||||||
}
|
|
||||||
if (auto mapping = findMappingByBisection(emscriptKey->key))
|
|
||||||
return *mapping;
|
|
||||||
if (deadKeyEvent)
|
|
||||||
return Qt::Key_unknown;
|
|
||||||
|
|
||||||
// cast to unicode key
|
|
||||||
QString str = QString::fromUtf8(emscriptKey->key).toUpper();
|
|
||||||
QStringIterator i(str);
|
|
||||||
return static_cast<Qt::Key>(i.next(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
struct KeyMapping { Qt::Key from, to; };
|
|
||||||
|
|
||||||
constexpr KeyMapping tildeKeyTable[] = { // ~
|
|
||||||
{ Qt::Key_A, Qt::Key_Atilde },
|
|
||||||
{ Qt::Key_N, Qt::Key_Ntilde },
|
|
||||||
{ Qt::Key_O, Qt::Key_Otilde },
|
|
||||||
};
|
|
||||||
constexpr KeyMapping 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 },
|
|
||||||
};
|
|
||||||
constexpr KeyMapping 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 },
|
|
||||||
};
|
|
||||||
constexpr KeyMapping 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 },
|
|
||||||
};
|
|
||||||
constexpr KeyMapping 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 },
|
|
||||||
};
|
|
||||||
|
|
||||||
static Qt::Key find_impl(const KeyMapping *first, const KeyMapping *last, Qt::Key key) noexcept
|
|
||||||
{
|
|
||||||
while (first != last) {
|
|
||||||
if (first->from == key)
|
|
||||||
return first->to;
|
|
||||||
++first;
|
|
||||||
}
|
|
||||||
return Qt::Key_unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <size_t N>
|
|
||||||
static Qt::Key find(const KeyMapping (&map)[N], Qt::Key key) noexcept
|
|
||||||
{
|
|
||||||
return find_impl(map, map + N, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
Qt::Key translateBaseKeyUsingDeadKey(Qt::Key accentBaseKey, Qt::Key deadKey)
|
|
||||||
{
|
|
||||||
switch (deadKey) {
|
|
||||||
case Qt::Key_QuoteLeft: {
|
|
||||||
// ` macOS: Key_Dead_Grave
|
|
||||||
return platform() == Platform::MacOS ? find(graveKeyTable, accentBaseKey)
|
|
||||||
: find(diaeresisKeyTable, accentBaseKey);
|
|
||||||
}
|
|
||||||
case Qt::Key_O: // ´ Key_Dead_Grave
|
|
||||||
return find(graveKeyTable, accentBaseKey);
|
|
||||||
case Qt::Key_E: // ´ Key_Dead_Acute
|
|
||||||
return find(acuteKeyTable, accentBaseKey);
|
|
||||||
case Qt::Key_AsciiTilde:
|
|
||||||
case Qt::Key_N: // Key_Dead_Tilde
|
|
||||||
return find(tildeKeyTable, accentBaseKey);
|
|
||||||
case Qt::Key_U: // ¨ Key_Dead_Diaeresis
|
|
||||||
return find(diaeresisKeyTable, accentBaseKey);
|
|
||||||
case Qt::Key_I: // macOS Key_Dead_Circumflex
|
|
||||||
case Qt::Key_6: // linux
|
|
||||||
case Qt::Key_Apostrophe: // linux
|
|
||||||
return find(circumflexKeyTable, accentBaseKey);
|
|
||||||
default:
|
|
||||||
return Qt::Key_unknown;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
std::optional<QString> findKeyTextByKeyId(const T &mappingArray, Qt::Key qtKey)
|
|
||||||
{
|
|
||||||
const auto it = std::find_if(mappingArray.cbegin(), mappingArray.cend(),
|
|
||||||
[qtKey](const Emkb2QtData &data) { return data.qt == qtKey; });
|
|
||||||
return it != mappingArray.cend() ? it->em : std::optional<QString>();
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
QWasmEventTranslator::QWasmEventTranslator() = default;
|
|
||||||
|
|
||||||
QWasmEventTranslator::~QWasmEventTranslator() = default;
|
|
||||||
|
|
||||||
QWasmEventTranslator::TranslatedEvent
|
|
||||||
QWasmEventTranslator::translateKeyEvent(int emEventType, const EmscriptenKeyboardEvent *keyEvent)
|
|
||||||
{
|
|
||||||
TranslatedEvent ret;
|
|
||||||
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;
|
|
||||||
} else 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)
|
|
||||||
ret.key = translatedKey;
|
|
||||||
|
|
||||||
if (auto text = keyEvent->shiftKey
|
|
||||||
? findKeyTextByKeyId(WebToQtKeyCodeMappingsWithShift, ret.key)
|
|
||||||
: findKeyTextByKeyId(WebToQtKeyCodeMappings, ret.key)) {
|
|
||||||
if (ret.type == QEvent::KeyPress) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ret.text = QString::fromUtf8(keyEvent->key);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
|
@ -1,46 +0,0 @@
|
|||||||
// Copyright (C) 2018 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
|
||||||
|
|
||||||
#ifndef QWASMEVENTTRANSLATOR_H
|
|
||||||
#define QWASMEVENTTRANSLATOR_H
|
|
||||||
|
|
||||||
#include <QtCore/qobject.h>
|
|
||||||
#include <QtCore/qrect.h>
|
|
||||||
#include <QtCore/qpoint.h>
|
|
||||||
#include <emscripten/html5.h>
|
|
||||||
#include "qwasmwindow.h"
|
|
||||||
#include <QtGui/qinputdevice.h>
|
|
||||||
#include <QHash>
|
|
||||||
#include <QCursor>
|
|
||||||
#include "qwasmevent.h"
|
|
||||||
#include "qwasmplatform.h"
|
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
|
||||||
|
|
||||||
class QWindow;
|
|
||||||
|
|
||||||
class QWasmEventTranslator : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
struct TranslatedEvent
|
|
||||||
{
|
|
||||||
QEvent::Type type;
|
|
||||||
Qt::Key key;
|
|
||||||
QString text;
|
|
||||||
};
|
|
||||||
explicit QWasmEventTranslator();
|
|
||||||
~QWasmEventTranslator();
|
|
||||||
|
|
||||||
TranslatedEvent translateKeyEvent(int emEventType, const EmscriptenKeyboardEvent *keyEvent);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static quint64 getTimestamp();
|
|
||||||
|
|
||||||
Qt::Key m_emDeadKey = Qt::Key_unknown;
|
|
||||||
Qt::Key m_keyModifiedByDeadKeyOnPress = Qt::Key_unknown;
|
|
||||||
};
|
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
|
||||||
#endif // QWASMEVENTTRANSLATOR_H
|
|
@ -5,9 +5,9 @@
|
|||||||
|
|
||||||
#include "qwasminputcontext.h"
|
#include "qwasminputcontext.h"
|
||||||
#include "qwasmintegration.h"
|
#include "qwasmintegration.h"
|
||||||
|
#include "qwasmplatform.h"
|
||||||
#include <QRectF>
|
#include <QRectF>
|
||||||
#include <qpa/qplatforminputcontext.h>
|
#include <qpa/qplatforminputcontext.h>
|
||||||
#include "qwasmeventtranslator.h"
|
|
||||||
#include "qwasmscreen.h"
|
#include "qwasmscreen.h"
|
||||||
#include <qguiapplication.h>
|
#include <qguiapplication.h>
|
||||||
#include <qwindow.h>
|
#include <qwindow.h>
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||||
|
|
||||||
#include "qwasmintegration.h"
|
#include "qwasmintegration.h"
|
||||||
#include "qwasmeventtranslator.h"
|
|
||||||
#include "qwasmeventdispatcher.h"
|
#include "qwasmeventdispatcher.h"
|
||||||
#include "qwasmcompositor.h"
|
#include "qwasmcompositor.h"
|
||||||
#include "qwasmopenglcontext.h"
|
#include "qwasmopenglcontext.h"
|
||||||
@ -164,8 +163,10 @@ bool QWasmIntegration::hasCapability(QPlatformIntegration::Capability cap) const
|
|||||||
|
|
||||||
QPlatformWindow *QWasmIntegration::createPlatformWindow(QWindow *window) const
|
QPlatformWindow *QWasmIntegration::createPlatformWindow(QWindow *window) const
|
||||||
{
|
{
|
||||||
QWasmCompositor *compositor = QWasmScreen::get(window->screen())->compositor();
|
auto *wasmScreen = QWasmScreen::get(window->screen());
|
||||||
return new QWasmWindow(window, compositor, m_backingStores.value(window));
|
QWasmCompositor *compositor = wasmScreen->compositor();
|
||||||
|
return new QWasmWindow(window, wasmScreen->deadKeySupport(), compositor,
|
||||||
|
m_backingStores.value(window));
|
||||||
}
|
}
|
||||||
|
|
||||||
QPlatformBackingStore *QWasmIntegration::createPlatformBackingStore(QWindow *window) const
|
QPlatformBackingStore *QWasmIntegration::createPlatformBackingStore(QWindow *window) const
|
||||||
|
249
src/plugins/platforms/wasm/qwasmkeytranslator.cpp
Normal file
249
src/plugins/platforms/wasm/qwasmkeytranslator.cpp
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||||
|
|
||||||
|
#include "qwasmkeytranslator.h"
|
||||||
|
#include "qwasmevent.h"
|
||||||
|
|
||||||
|
#include <QtCore/private/qmakearray_p.h>
|
||||||
|
#include <QtCore/qglobal.h>
|
||||||
|
#include <QtCore/qobject.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
struct WebKb2QtData
|
||||||
|
{
|
||||||
|
static constexpr char StringTerminator = '\0';
|
||||||
|
|
||||||
|
const char *web;
|
||||||
|
unsigned int qt;
|
||||||
|
|
||||||
|
constexpr bool operator<=(const WebKb2QtData &that) const noexcept
|
||||||
|
{
|
||||||
|
return !(strcmp(that) > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<(const WebKb2QtData &that) const noexcept { return ::strcmp(web, that.web) < 0; }
|
||||||
|
|
||||||
|
constexpr bool operator==(const WebKb2QtData &that) const noexcept { return strcmp(that) == 0; }
|
||||||
|
|
||||||
|
constexpr int strcmp(const WebKb2QtData &that, const int i = 0) const
|
||||||
|
{
|
||||||
|
return web[i] == StringTerminator && that.web[i] == StringTerminator ? 0
|
||||||
|
: web[i] == StringTerminator ? -1
|
||||||
|
: that.web[i] == StringTerminator ? 1
|
||||||
|
: web[i] < that.web[i] ? -1
|
||||||
|
: web[i] > that.web[i] ? 1
|
||||||
|
: strcmp(that, i + 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<unsigned int Qt, char... WebChar>
|
||||||
|
struct Web2Qt
|
||||||
|
{
|
||||||
|
static constexpr const char storage[sizeof...(WebChar) + 1] = { WebChar..., '\0' };
|
||||||
|
using Type = WebKb2QtData;
|
||||||
|
static constexpr Type data() noexcept { return Type{ storage, Qt }; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<unsigned int Qt, char... WebChar>
|
||||||
|
constexpr char Web2Qt<Qt, WebChar...>::storage[];
|
||||||
|
|
||||||
|
static constexpr const auto WebToQtKeyCodeMappings = qMakeArray(
|
||||||
|
QSortedData<Web2Qt<Qt::Key_Escape, 'E', 's', 'c', 'a', 'p', 'e'>,
|
||||||
|
Web2Qt<Qt::Key_Tab, 'T', 'a', 'b'>,
|
||||||
|
Web2Qt<Qt::Key_Backspace, 'B', 'a', 'c', 'k', 's', 'p', 'a', 'c', 'e'>,
|
||||||
|
Web2Qt<Qt::Key_Return, 'E', 'n', 't', 'e', 'r'>,
|
||||||
|
Web2Qt<Qt::Key_Insert, 'I', 'n', 's', 'e', 'r', 't'>,
|
||||||
|
Web2Qt<Qt::Key_Delete, 'D', 'e', 'l', 'e', 't', 'e'>,
|
||||||
|
Web2Qt<Qt::Key_Pause, 'P', 'a', 'u', 's', 'e'>,
|
||||||
|
Web2Qt<Qt::Key_Pause, 'C', 'l', 'e', 'a', 'r'>,
|
||||||
|
Web2Qt<Qt::Key_Home, 'H', 'o', 'm', 'e'>, Web2Qt<Qt::Key_End, 'E', 'n', 'd'>,
|
||||||
|
Web2Qt<Qt::Key_Left, 'A', 'r', 'r', 'o', 'w', 'L', 'e', 'f', 't'>,
|
||||||
|
Web2Qt<Qt::Key_Up, 'A', 'r', 'r', 'o', 'w', 'U', 'p'>,
|
||||||
|
Web2Qt<Qt::Key_Right, 'A', 'r', 'r', 'o', 'w', 'R', 'i', 'g', 'h', 't'>,
|
||||||
|
Web2Qt<Qt::Key_Down, 'A', 'r', 'r', 'o', 'w', 'D', 'o', 'w', 'n'>,
|
||||||
|
Web2Qt<Qt::Key_PageUp, 'P', 'a', 'g', 'e', 'U', 'p'>,
|
||||||
|
Web2Qt<Qt::Key_PageDown, 'P', 'a', 'g', 'e', 'D', 'o', 'w', 'n'>,
|
||||||
|
Web2Qt<Qt::Key_Shift, 'S', 'h', 'i', 'f', 't'>,
|
||||||
|
Web2Qt<Qt::Key_Control, 'C', 'o', 'n', 't', 'r', 'o', 'l'>,
|
||||||
|
Web2Qt<Qt::Key_Meta, 'M', 'e', 't', 'a'>, Web2Qt<Qt::Key_Meta, 'O', 'S'>,
|
||||||
|
Web2Qt<Qt::Key_Alt, 'A', 'l', 't', 'L', 'e', 'f', 't'>,
|
||||||
|
Web2Qt<Qt::Key_Alt, 'A', 'l', 't'>,
|
||||||
|
Web2Qt<Qt::Key_CapsLock, 'C', 'a', 'p', 's', 'L', 'o', 'c', 'k'>,
|
||||||
|
Web2Qt<Qt::Key_NumLock, 'N', 'u', 'm', 'L', 'o', 'c', 'k'>,
|
||||||
|
Web2Qt<Qt::Key_ScrollLock, 'S', 'c', 'r', 'o', 'l', 'l', 'L', 'o', 'c', 'k'>,
|
||||||
|
Web2Qt<Qt::Key_F1, 'F', '1'>, Web2Qt<Qt::Key_F2, 'F', '2'>,
|
||||||
|
Web2Qt<Qt::Key_F3, 'F', '3'>, Web2Qt<Qt::Key_F4, 'F', '4'>,
|
||||||
|
Web2Qt<Qt::Key_F5, 'F', '5'>, Web2Qt<Qt::Key_F6, 'F', '6'>,
|
||||||
|
Web2Qt<Qt::Key_F7, 'F', '7'>, Web2Qt<Qt::Key_F8, 'F', '8'>,
|
||||||
|
Web2Qt<Qt::Key_F9, 'F', '9'>, Web2Qt<Qt::Key_F10, 'F', '1', '0'>,
|
||||||
|
Web2Qt<Qt::Key_F11, 'F', '1', '1'>, Web2Qt<Qt::Key_F12, 'F', '1', '2'>,
|
||||||
|
Web2Qt<Qt::Key_F13, 'F', '1', '3'>, Web2Qt<Qt::Key_F14, 'F', '1', '4'>,
|
||||||
|
Web2Qt<Qt::Key_F15, 'F', '1', '5'>, Web2Qt<Qt::Key_F16, 'F', '1', '6'>,
|
||||||
|
Web2Qt<Qt::Key_F17, 'F', '1', '7'>, Web2Qt<Qt::Key_F18, 'F', '1', '8'>,
|
||||||
|
Web2Qt<Qt::Key_F19, 'F', '1', '9'>, Web2Qt<Qt::Key_F20, 'F', '2', '0'>,
|
||||||
|
Web2Qt<Qt::Key_F21, 'F', '2', '1'>, Web2Qt<Qt::Key_F22, 'F', '2', '2'>,
|
||||||
|
Web2Qt<Qt::Key_F23, 'F', '2', '3'>,
|
||||||
|
Web2Qt<Qt::Key_Paste, 'P', 'a', 's', 't', 'e'>,
|
||||||
|
Web2Qt<Qt::Key_AltGr, 'A', 'l', 't', 'R', 'i', 'g', 'h', 't'>,
|
||||||
|
Web2Qt<Qt::Key_Help, 'H', 'e', 'l', 'p'>,
|
||||||
|
Web2Qt<Qt::Key_yen, 'I', 'n', 't', 'l', 'Y', 'e', 'n'>,
|
||||||
|
Web2Qt<Qt::Key_Menu, 'C', 'o', 'n', 't', 'e', 'x', 't', 'M', 'e', 'n',
|
||||||
|
'u'>>::Data{});
|
||||||
|
|
||||||
|
static constexpr const auto WebToQtKeyCodeMappingsWithShift = qMakeArray(
|
||||||
|
QSortedData<
|
||||||
|
// shifted
|
||||||
|
Web2Qt<Qt::Key_Agrave, '\xc3', '\x80'>, Web2Qt<Qt::Key_Aacute, '\xc3', '\x81'>,
|
||||||
|
Web2Qt<Qt::Key_Acircumflex, '\xc3', '\x82'>,
|
||||||
|
Web2Qt<Qt::Key_Adiaeresis, '\xc3', '\x84'>, Web2Qt<Qt::Key_AE, '\xc3', '\x86'>,
|
||||||
|
Web2Qt<Qt::Key_Atilde, '\xc3', '\x83'>, Web2Qt<Qt::Key_Aring, '\xc3', '\x85'>,
|
||||||
|
Web2Qt<Qt::Key_Egrave, '\xc3', '\x88'>, Web2Qt<Qt::Key_Eacute, '\xc3', '\x89'>,
|
||||||
|
Web2Qt<Qt::Key_Ecircumflex, '\xc3', '\x8a'>,
|
||||||
|
Web2Qt<Qt::Key_Ediaeresis, '\xc3', '\x8b'>, Web2Qt<Qt::Key_Iacute, '\xc3', '\x8d'>,
|
||||||
|
Web2Qt<Qt::Key_Icircumflex, '\xc3', '\x8e'>,
|
||||||
|
Web2Qt<Qt::Key_Idiaeresis, '\xc3', '\x8f'>, Web2Qt<Qt::Key_Igrave, '\xc3', '\x8c'>,
|
||||||
|
Web2Qt<Qt::Key_Ocircumflex, '\xc3', '\x94'>,
|
||||||
|
Web2Qt<Qt::Key_Odiaeresis, '\xc3', '\x96'>, Web2Qt<Qt::Key_Ograve, '\xc3', '\x92'>,
|
||||||
|
Web2Qt<Qt::Key_Oacute, '\xc3', '\x93'>, Web2Qt<Qt::Key_Ooblique, '\xc3', '\x98'>,
|
||||||
|
Web2Qt<Qt::Key_Otilde, '\xc3', '\x95'>, Web2Qt<Qt::Key_Ucircumflex, '\xc3', '\x9b'>,
|
||||||
|
Web2Qt<Qt::Key_Udiaeresis, '\xc3', '\x9c'>, Web2Qt<Qt::Key_Ugrave, '\xc3', '\x99'>,
|
||||||
|
Web2Qt<Qt::Key_Uacute, '\xc3', '\x9a'>, Web2Qt<Qt::Key_Ntilde, '\xc3', '\x91'>,
|
||||||
|
Web2Qt<Qt::Key_Ccedilla, '\xc3', '\x87'>,
|
||||||
|
Web2Qt<Qt::Key_ydiaeresis, '\xc3', '\x8f'>,
|
||||||
|
Web2Qt<Qt::Key_Yacute, '\xc3', '\x9d'>>::Data{});
|
||||||
|
|
||||||
|
struct KeyMapping
|
||||||
|
{
|
||||||
|
Qt::Key from, to;
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr KeyMapping tildeKeyTable[] = {
|
||||||
|
// ~
|
||||||
|
{ Qt::Key_A, Qt::Key_Atilde },
|
||||||
|
{ Qt::Key_N, Qt::Key_Ntilde },
|
||||||
|
{ Qt::Key_O, Qt::Key_Otilde },
|
||||||
|
};
|
||||||
|
constexpr KeyMapping 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 },
|
||||||
|
};
|
||||||
|
constexpr KeyMapping 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 },
|
||||||
|
};
|
||||||
|
constexpr KeyMapping 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 },
|
||||||
|
};
|
||||||
|
constexpr KeyMapping 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 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static Qt::Key find_impl(const KeyMapping *first, const KeyMapping *last, Qt::Key key) noexcept
|
||||||
|
{
|
||||||
|
while (first != last) {
|
||||||
|
if (first->from == key)
|
||||||
|
return first->to;
|
||||||
|
++first;
|
||||||
|
}
|
||||||
|
return Qt::Key_unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t N>
|
||||||
|
static Qt::Key find(const KeyMapping (&map)[N], Qt::Key key) noexcept
|
||||||
|
{
|
||||||
|
return find_impl(map, map + N, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::Key translateBaseKeyUsingDeadKey(Qt::Key accentBaseKey, Qt::Key deadKey)
|
||||||
|
{
|
||||||
|
switch (deadKey) {
|
||||||
|
case Qt::Key_QuoteLeft: {
|
||||||
|
// ` macOS: Key_Dead_Grave
|
||||||
|
return platform() == Platform::MacOS ? find(graveKeyTable, accentBaseKey)
|
||||||
|
: find(diaeresisKeyTable, accentBaseKey);
|
||||||
|
}
|
||||||
|
case Qt::Key_O: // ´ Key_Dead_Grave
|
||||||
|
return find(graveKeyTable, accentBaseKey);
|
||||||
|
case Qt::Key_E: // ´ Key_Dead_Acute
|
||||||
|
return find(acuteKeyTable, accentBaseKey);
|
||||||
|
case Qt::Key_AsciiTilde:
|
||||||
|
case Qt::Key_N: // Key_Dead_Tilde
|
||||||
|
return find(tildeKeyTable, accentBaseKey);
|
||||||
|
case Qt::Key_U: // ¨ Key_Dead_Diaeresis
|
||||||
|
return find(diaeresisKeyTable, accentBaseKey);
|
||||||
|
case Qt::Key_I: // macOS Key_Dead_Circumflex
|
||||||
|
case Qt::Key_6: // linux
|
||||||
|
case Qt::Key_Apostrophe: // linux
|
||||||
|
return find(circumflexKeyTable, accentBaseKey);
|
||||||
|
default:
|
||||||
|
return Qt::Key_unknown;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
std::optional<QString> findKeyTextByKeyId(const T &mappingArray, Qt::Key qtKey)
|
||||||
|
{
|
||||||
|
const auto it = std::find_if(mappingArray.cbegin(), mappingArray.cend(),
|
||||||
|
[qtKey](const WebKb2QtData &data) { return data.qt == qtKey; });
|
||||||
|
return it != mappingArray.cend() ? it->web : std::optional<QString>();
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
std::optional<Qt::Key> QWasmKeyTranslator::mapWebKeyTextToQtKey(const char *toFind)
|
||||||
|
{
|
||||||
|
const WebKb2QtData searchKey{ toFind, 0 };
|
||||||
|
const auto it = std::lower_bound(WebToQtKeyCodeMappings.cbegin(), WebToQtKeyCodeMappings.cend(),
|
||||||
|
searchKey);
|
||||||
|
return it != WebToQtKeyCodeMappings.cend() && searchKey == *it ? static_cast<Qt::Key>(it->qt)
|
||||||
|
: std::optional<Qt::Key>();
|
||||||
|
}
|
||||||
|
|
||||||
|
QWasmDeadKeySupport::QWasmDeadKeySupport() = default;
|
||||||
|
|
||||||
|
QWasmDeadKeySupport::~QWasmDeadKeySupport() = default;
|
||||||
|
|
||||||
|
void QWasmDeadKeySupport::applyDeadKeyTranslations(KeyEvent *event)
|
||||||
|
{
|
||||||
|
if (event->deadKey || event->key == Qt::Key_AltGr) {
|
||||||
|
if (event->modifiers.testFlag(Qt::ShiftModifier) && event->key == Qt::Key_QuoteLeft)
|
||||||
|
event->key = Qt::Key_AsciiTilde;
|
||||||
|
m_activeDeadKey = event->key;
|
||||||
|
} else if (m_activeDeadKey != Qt::Key_unknown
|
||||||
|
&& (m_keyModifiedByDeadKeyOnPress == Qt::Key_unknown
|
||||||
|
|| m_keyModifiedByDeadKeyOnPress == event->key)) {
|
||||||
|
const Qt::Key baseKey = event->key;
|
||||||
|
const Qt::Key translatedKey = translateBaseKeyUsingDeadKey(baseKey, m_activeDeadKey);
|
||||||
|
if (translatedKey != Qt::Key_unknown)
|
||||||
|
event->key = translatedKey;
|
||||||
|
|
||||||
|
if (auto foundText = event->modifiers.testFlag(Qt::ShiftModifier)
|
||||||
|
? findKeyTextByKeyId(WebToQtKeyCodeMappingsWithShift, event->key)
|
||||||
|
: findKeyTextByKeyId(WebToQtKeyCodeMappings, event->key)) {
|
||||||
|
if (event->type == EventType::KeyDown) {
|
||||||
|
Q_ASSERT(m_keyModifiedByDeadKeyOnPress == Qt::Key_unknown);
|
||||||
|
m_activeDeadKey = Qt::Key_unknown;
|
||||||
|
} else {
|
||||||
|
Q_ASSERT(event->type == EventType::KeyUp);
|
||||||
|
Q_ASSERT(m_keyModifiedByDeadKeyOnPress == baseKey);
|
||||||
|
m_activeDeadKey = Qt::Key_unknown;
|
||||||
|
m_keyModifiedByDeadKeyOnPress = Qt::Key_unknown;
|
||||||
|
}
|
||||||
|
event->text = foundText->size() == 1 ? *foundText : QString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QT_END_NAMESPACE
|
34
src/plugins/platforms/wasm/qwasmkeytranslator.h
Normal file
34
src/plugins/platforms/wasm/qwasmkeytranslator.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||||
|
|
||||||
|
#ifndef QWASMKEYTRANSLATOR_H
|
||||||
|
#define QWASMKEYTRANSLATOR_H
|
||||||
|
|
||||||
|
#include <QtCore/qnamespace.h>
|
||||||
|
#include <QtCore/qtypes.h>
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
struct KeyEvent;
|
||||||
|
|
||||||
|
namespace QWasmKeyTranslator {
|
||||||
|
std::optional<Qt::Key> mapWebKeyTextToQtKey(const char *toFind);
|
||||||
|
}
|
||||||
|
|
||||||
|
class QWasmDeadKeySupport
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit QWasmDeadKeySupport();
|
||||||
|
~QWasmDeadKeySupport();
|
||||||
|
|
||||||
|
void applyDeadKeyTranslations(KeyEvent *event);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Qt::Key m_activeDeadKey = Qt::Key_unknown;
|
||||||
|
Qt::Key m_keyModifiedByDeadKeyOnPress = Qt::Key_unknown;
|
||||||
|
};
|
||||||
|
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
#endif // QWASMKEYTRANSLATOR_H
|
@ -2,11 +2,12 @@
|
|||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||||
|
|
||||||
#include "qwasmscreen.h"
|
#include "qwasmscreen.h"
|
||||||
#include "qwasmwindow.h"
|
|
||||||
#include "qwasmeventtranslator.h"
|
|
||||||
#include "qwasmcompositor.h"
|
#include "qwasmcompositor.h"
|
||||||
#include "qwasmintegration.h"
|
|
||||||
#include "qwasmcssstyle.h"
|
#include "qwasmcssstyle.h"
|
||||||
|
#include "qwasmintegration.h"
|
||||||
|
#include "qwasmkeytranslator.h"
|
||||||
|
#include "qwasmwindow.h"
|
||||||
|
|
||||||
#include <emscripten/bind.h>
|
#include <emscripten/bind.h>
|
||||||
#include <emscripten/val.h>
|
#include <emscripten/val.h>
|
||||||
@ -29,7 +30,7 @@ QWasmScreen::QWasmScreen(const emscripten::val &containerOrCanvas)
|
|||||||
: m_container(containerOrCanvas),
|
: m_container(containerOrCanvas),
|
||||||
m_shadowContainer(emscripten::val::undefined()),
|
m_shadowContainer(emscripten::val::undefined()),
|
||||||
m_compositor(new QWasmCompositor(this)),
|
m_compositor(new QWasmCompositor(this)),
|
||||||
m_eventTranslator(new QWasmEventTranslator())
|
m_deadKeySupport(std::make_unique<QWasmDeadKeySupport>())
|
||||||
{
|
{
|
||||||
auto document = m_container["ownerDocument"];
|
auto document = m_container["ownerDocument"];
|
||||||
// Each screen is represented by a div container. All of the windows exist therein as
|
// Each screen is represented by a div container. All of the windows exist therein as
|
||||||
@ -111,11 +112,6 @@ QWasmCompositor *QWasmScreen::compositor()
|
|||||||
return m_compositor.get();
|
return m_compositor.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
QWasmEventTranslator *QWasmScreen::eventTranslator()
|
|
||||||
{
|
|
||||||
return m_eventTranslator.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
emscripten::val QWasmScreen::element() const
|
emscripten::val QWasmScreen::element() const
|
||||||
{
|
{
|
||||||
return m_shadowContainer;
|
return m_shadowContainer;
|
||||||
|
@ -20,7 +20,7 @@ class QPlatformOpenGLContext;
|
|||||||
class QWasmWindow;
|
class QWasmWindow;
|
||||||
class QWasmBackingStore;
|
class QWasmBackingStore;
|
||||||
class QWasmCompositor;
|
class QWasmCompositor;
|
||||||
class QWasmEventTranslator;
|
class QWasmDeadKeySupport;
|
||||||
class QOpenGLContext;
|
class QOpenGLContext;
|
||||||
|
|
||||||
class QWasmScreen : public QObject, public QPlatformScreen
|
class QWasmScreen : public QObject, public QPlatformScreen
|
||||||
@ -38,7 +38,7 @@ public:
|
|||||||
QString outerScreenId() const;
|
QString outerScreenId() const;
|
||||||
|
|
||||||
QWasmCompositor *compositor();
|
QWasmCompositor *compositor();
|
||||||
QWasmEventTranslator *eventTranslator();
|
QWasmDeadKeySupport *deadKeySupport() { return m_deadKeySupport.get(); }
|
||||||
|
|
||||||
QRect geometry() const override;
|
QRect geometry() const override;
|
||||||
int depth() const override;
|
int depth() const override;
|
||||||
@ -67,7 +67,7 @@ private:
|
|||||||
emscripten::val m_container;
|
emscripten::val m_container;
|
||||||
emscripten::val m_shadowContainer;
|
emscripten::val m_shadowContainer;
|
||||||
std::unique_ptr<QWasmCompositor> m_compositor;
|
std::unique_ptr<QWasmCompositor> m_compositor;
|
||||||
std::unique_ptr<QWasmEventTranslator> m_eventTranslator;
|
std::unique_ptr<QWasmDeadKeySupport> m_deadKeySupport;
|
||||||
QRect m_geometry = QRect(0, 0, 100, 100);
|
QRect m_geometry = QRect(0, 0, 100, 100);
|
||||||
int m_depth = 32;
|
int m_depth = 32;
|
||||||
QImage::Format m_format = QImage::Format_RGB32;
|
QImage::Format m_format = QImage::Format_RGB32;
|
||||||
|
@ -11,6 +11,9 @@
|
|||||||
|
|
||||||
#include "qwasmbase64iconstore.h"
|
#include "qwasmbase64iconstore.h"
|
||||||
#include "qwasmdom.h"
|
#include "qwasmdom.h"
|
||||||
|
#include "qwasmclipboard.h"
|
||||||
|
#include "qwasmintegration.h"
|
||||||
|
#include "qwasmkeytranslator.h"
|
||||||
#include "qwasmwindow.h"
|
#include "qwasmwindow.h"
|
||||||
#include "qwasmwindowclientarea.h"
|
#include "qwasmwindowclientarea.h"
|
||||||
#include "qwasmscreen.h"
|
#include "qwasmscreen.h"
|
||||||
@ -31,11 +34,13 @@ QT_BEGIN_NAMESPACE
|
|||||||
|
|
||||||
Q_GUI_EXPORT int qt_defaultDpiX();
|
Q_GUI_EXPORT int qt_defaultDpiX();
|
||||||
|
|
||||||
QWasmWindow::QWasmWindow(QWindow *w, QWasmCompositor *compositor, QWasmBackingStore *backingStore)
|
QWasmWindow::QWasmWindow(QWindow *w, QWasmDeadKeySupport *deadKeySupport,
|
||||||
|
QWasmCompositor *compositor, QWasmBackingStore *backingStore)
|
||||||
: QPlatformWindow(w),
|
: QPlatformWindow(w),
|
||||||
m_window(w),
|
m_window(w),
|
||||||
m_compositor(compositor),
|
m_compositor(compositor),
|
||||||
m_backingStore(backingStore),
|
m_backingStore(backingStore),
|
||||||
|
m_deadKeySupport(deadKeySupport),
|
||||||
m_document(dom::document()),
|
m_document(dom::document()),
|
||||||
m_qtWindow(m_document.call<emscripten::val>("createElement", emscripten::val("div"))),
|
m_qtWindow(m_document.call<emscripten::val>("createElement", emscripten::val("div"))),
|
||||||
m_windowContents(m_document.call<emscripten::val>("createElement", emscripten::val("div"))),
|
m_windowContents(m_document.call<emscripten::val>("createElement", emscripten::val("div"))),
|
||||||
@ -89,15 +94,15 @@ QWasmWindow::QWasmWindow(QWindow *w, QWasmCompositor *compositor, QWasmBackingSt
|
|||||||
|
|
||||||
m_compositor->addWindow(this);
|
m_compositor->addWindow(this);
|
||||||
|
|
||||||
const auto callback = std::function([this](emscripten::val event) {
|
const auto pointerCallback = std::function([this](emscripten::val event) {
|
||||||
if (processPointer(*PointerEvent::fromWeb(event)))
|
if (processPointer(*PointerEvent::fromWeb(event)))
|
||||||
event.call<void>("preventDefault");
|
event.call<void>("preventDefault");
|
||||||
});
|
});
|
||||||
|
|
||||||
m_pointerEnterCallback =
|
m_pointerEnterCallback =
|
||||||
std::make_unique<qstdweb::EventCallback>(m_qtWindow, "pointerenter", callback);
|
std::make_unique<qstdweb::EventCallback>(m_qtWindow, "pointerenter", pointerCallback);
|
||||||
m_pointerLeaveCallback =
|
m_pointerLeaveCallback =
|
||||||
std::make_unique<qstdweb::EventCallback>(m_qtWindow, "pointerleave", callback);
|
std::make_unique<qstdweb::EventCallback>(m_qtWindow, "pointerleave", pointerCallback);
|
||||||
|
|
||||||
m_dropCallback = std::make_unique<qstdweb::EventCallback>(
|
m_dropCallback = std::make_unique<qstdweb::EventCallback>(
|
||||||
m_qtWindow, "drop", [this](emscripten::val event) {
|
m_qtWindow, "drop", [this](emscripten::val event) {
|
||||||
@ -110,6 +115,15 @@ QWasmWindow::QWasmWindow(QWindow *w, QWasmCompositor *compositor, QWasmBackingSt
|
|||||||
if (processWheel(*WheelEvent::fromWeb(event)))
|
if (processWheel(*WheelEvent::fromWeb(event)))
|
||||||
event.call<void>("preventDefault");
|
event.call<void>("preventDefault");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const auto keyCallback = std::function([this](emscripten::val event) {
|
||||||
|
if (processKey(*KeyEvent::fromWebWithDeadKeyTranslation(event, m_deadKeySupport)))
|
||||||
|
event.call<void>("preventDefault");
|
||||||
|
});
|
||||||
|
|
||||||
|
m_keyDownCallback =
|
||||||
|
std::make_unique<qstdweb::EventCallback>(m_qtWindow, "keydown", keyCallback);
|
||||||
|
m_keyUpCallback = std::make_unique<qstdweb::EventCallback>(m_qtWindow, "keyup", keyCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
QWasmWindow::~QWasmWindow()
|
QWasmWindow::~QWasmWindow()
|
||||||
@ -433,6 +447,26 @@ void QWasmWindow::applyWindowState()
|
|||||||
setGeometry(newGeom);
|
setGeometry(newGeom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QWasmWindow::processKey(const KeyEvent &event)
|
||||||
|
{
|
||||||
|
constexpr bool ProceedToNativeEvent = false;
|
||||||
|
Q_ASSERT(event.type == EventType::KeyDown || event.type == EventType::KeyUp);
|
||||||
|
|
||||||
|
const auto clipboardResult =
|
||||||
|
QWasmIntegration::get()->getWasmClipboard()->processKeyboard(event);
|
||||||
|
|
||||||
|
using ProcessKeyboardResult = QWasmClipboard::ProcessKeyboardResult;
|
||||||
|
if (clipboardResult == ProcessKeyboardResult::NativeClipboardEventNeeded)
|
||||||
|
return ProceedToNativeEvent;
|
||||||
|
|
||||||
|
const auto result = QWindowSystemInterface::handleKeyEvent(
|
||||||
|
0, event.type == EventType::KeyDown ? QEvent::KeyPress : QEvent::KeyRelease, event.key,
|
||||||
|
event.modifiers, event.text);
|
||||||
|
return clipboardResult == ProcessKeyboardResult::NativeClipboardEventAndCopiedDataNeeded
|
||||||
|
? ProceedToNativeEvent
|
||||||
|
: result;
|
||||||
|
}
|
||||||
|
|
||||||
bool QWasmWindow::processPointer(const PointerEvent &event)
|
bool QWasmWindow::processPointer(const PointerEvent &event)
|
||||||
{
|
{
|
||||||
if (event.pointerType != PointerType::Mouse)
|
if (event.pointerType != PointerType::Mouse)
|
||||||
@ -548,6 +582,9 @@ void QWasmWindow::requestActivateWindow()
|
|||||||
|
|
||||||
if (window()->isTopLevel())
|
if (window()->isTopLevel())
|
||||||
raise();
|
raise();
|
||||||
|
|
||||||
|
m_canvas.call<void>("focus");
|
||||||
|
|
||||||
QPlatformWindow::requestActivateWindow();
|
QPlatformWindow::requestActivateWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,13 +32,16 @@ class EventCallback;
|
|||||||
|
|
||||||
class ClientArea;
|
class ClientArea;
|
||||||
struct DragEvent;
|
struct DragEvent;
|
||||||
|
struct KeyEvent;
|
||||||
struct PointerEvent;
|
struct PointerEvent;
|
||||||
|
class QWasmDeadKeySupport;
|
||||||
struct WheelEvent;
|
struct WheelEvent;
|
||||||
|
|
||||||
class QWasmWindow final : public QPlatformWindow
|
class QWasmWindow final : public QPlatformWindow
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QWasmWindow(QWindow *w, QWasmCompositor *compositor, QWasmBackingStore *backingStore);
|
QWasmWindow(QWindow *w, QWasmDeadKeySupport *deadKeySupport, QWasmCompositor *compositor,
|
||||||
|
QWasmBackingStore *backingStore);
|
||||||
~QWasmWindow() final;
|
~QWasmWindow() final;
|
||||||
|
|
||||||
void destroy();
|
void destroy();
|
||||||
@ -95,6 +98,7 @@ private:
|
|||||||
bool hasMaximizeButton() const;
|
bool hasMaximizeButton() const;
|
||||||
void applyWindowState();
|
void applyWindowState();
|
||||||
|
|
||||||
|
bool processKey(const KeyEvent &event);
|
||||||
bool processPointer(const PointerEvent &event);
|
bool processPointer(const PointerEvent &event);
|
||||||
bool processDrop(const DragEvent &event);
|
bool processDrop(const DragEvent &event);
|
||||||
bool processWheel(const WheelEvent &event);
|
bool processWheel(const WheelEvent &event);
|
||||||
@ -102,6 +106,7 @@ private:
|
|||||||
QWindow *m_window = nullptr;
|
QWindow *m_window = nullptr;
|
||||||
QWasmCompositor *m_compositor = nullptr;
|
QWasmCompositor *m_compositor = nullptr;
|
||||||
QWasmBackingStore *m_backingStore = nullptr;
|
QWasmBackingStore *m_backingStore = nullptr;
|
||||||
|
QWasmDeadKeySupport *m_deadKeySupport;
|
||||||
QRect m_normalGeometry {0, 0, 0 ,0};
|
QRect m_normalGeometry {0, 0, 0 ,0};
|
||||||
|
|
||||||
emscripten::val m_document;
|
emscripten::val m_document;
|
||||||
@ -115,6 +120,9 @@ private:
|
|||||||
std::unique_ptr<NonClientArea> m_nonClientArea;
|
std::unique_ptr<NonClientArea> m_nonClientArea;
|
||||||
std::unique_ptr<ClientArea> m_clientArea;
|
std::unique_ptr<ClientArea> m_clientArea;
|
||||||
|
|
||||||
|
std::unique_ptr<qstdweb::EventCallback> m_keyDownCallback;
|
||||||
|
std::unique_ptr<qstdweb::EventCallback> m_keyUpCallback;
|
||||||
|
|
||||||
std::unique_ptr<qstdweb::EventCallback> m_pointerLeaveCallback;
|
std::unique_ptr<qstdweb::EventCallback> m_pointerLeaveCallback;
|
||||||
std::unique_ptr<qstdweb::EventCallback> m_pointerEnterCallback;
|
std::unique_ptr<qstdweb::EventCallback> m_pointerEnterCallback;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user