From 0108c93e2d88055df129f3b8669a21273218032f Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Tue, 30 Nov 2021 16:26:49 +0600 Subject: [PATCH] Render emulator output on main window Introduce hardware renderer --- src/qt/CMakeLists.txt | 14 + src/qt/cocoa_mouse.hpp | 10 + src/qt/macos_event_filter.mm | 107 ++++++ src/qt/qt_gleswidget.cpp | 154 ++++++++ src/qt/qt_gleswidget.hpp | 41 ++ src/qt/qt_main.cpp | 11 + src/qt/qt_mainwindow.cpp | 703 +++++++++++++++++++++++++++-------- src/qt/qt_mainwindow.hpp | 6 + src/qt/qt_ui.cpp | 5 + 9 files changed, 888 insertions(+), 163 deletions(-) create mode 100644 src/qt/cocoa_mouse.hpp create mode 100644 src/qt/macos_event_filter.mm create mode 100644 src/qt/qt_gleswidget.cpp create mode 100644 src/qt/qt_gleswidget.hpp diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index 0f119f8c5..9bda243b2 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -6,6 +6,11 @@ set(CMAKE_AUTORCC ON) find_package(Threads REQUIRED) +set(UI_EXTRA_FILES) +if (APPLE) + set(UI_EXTRA_FILES "macos_event_filter.mm") +endif() + add_library(plat STATIC qt.c qt_main.cpp qt_platform.cpp qt_midi.cpp cpp11_thread.cpp) add_library(ui STATIC qt_ui.cpp @@ -18,6 +23,10 @@ add_library(ui STATIC qt_machinestatus.cpp qt_machinestatus.hpp qt_machinestatus.ui + qt_gleswidget.cpp + qt_gleswidget.hpp + + ${UI_EXTRA_FILES} qt_settings.cpp qt_settings.hpp @@ -89,3 +98,8 @@ target_link_libraries( Qt5::Widgets Threads::Threads ) + +if (NOT APPLE) + find_package(X11 REQUIRED) + target_link_libraries(ui PRIVATE X11::X11) +endif() \ No newline at end of file diff --git a/src/qt/cocoa_mouse.hpp b/src/qt/cocoa_mouse.hpp new file mode 100644 index 000000000..83939a233 --- /dev/null +++ b/src/qt/cocoa_mouse.hpp @@ -0,0 +1,10 @@ +#include +#include + +class CocoaEventFilter : public QAbstractNativeEventFilter +{ +public: + CocoaEventFilter() {}; + ~CocoaEventFilter(); + virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) override; +}; \ No newline at end of file diff --git a/src/qt/macos_event_filter.mm b/src/qt/macos_event_filter.mm new file mode 100644 index 000000000..e942b5f49 --- /dev/null +++ b/src/qt/macos_event_filter.mm @@ -0,0 +1,107 @@ +#include +#include "86box/plat.h" +#include "cocoa_mouse.hpp" +#import +extern "C" +{ +#include <86box/86box.h> +#include <86box/keyboard.h> +#include <86box/mouse.h> +#include <86box/config.h> +//#include <86box/plat.h> +#include <86box/plat_dynld.h> +#include <86box/device.h> +#include <86box/timer.h> +#include <86box/ui.h> +#include <86box/video.h> +extern int mouse_capture; +} + +typedef struct mouseinputdata +{ + int deltax, deltay, deltaz; + int mousebuttons; +} mouseinputdata; + +extern SDL_mutex* mousemutex; +extern mouseinputdata mousedata; + +CocoaEventFilter::~CocoaEventFilter() +{ + +} + +bool CocoaEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, long *result) +{ + if (mouse_capture) + { + if (eventType == "mac_generic_NSEvent") + { + NSEvent* event = (NSEvent*)message; + if ([event type] == NSEventTypeMouseMoved) + { + SDL_LockMutex(mousemutex); + mousedata.deltax += [event deltaX]; + mousedata.deltay += [event deltaY]; + SDL_UnlockMutex(mousemutex); + return true; + } + if ([event type] == NSEventTypeScrollWheel) + { + SDL_LockMutex(mousemutex); + mousedata.deltaz += [event deltaY]; + SDL_UnlockMutex(mousemutex); + return true; + } + switch ([event type]) + { + default: return false; + case NSEventTypeLeftMouseDown: + { + SDL_LockMutex(mousemutex); + mousedata.mousebuttons |= 1; + SDL_UnlockMutex(mousemutex); + break; + } + case NSEventTypeLeftMouseUp: + { + SDL_LockMutex(mousemutex); + mousedata.mousebuttons &= ~1; + SDL_UnlockMutex(mousemutex); + break; + } + case NSEventTypeRightMouseDown: + { + SDL_LockMutex(mousemutex); + mousedata.mousebuttons |= 2; + SDL_UnlockMutex(mousemutex); + break; + } + case NSEventTypeRightMouseUp: + { + SDL_LockMutex(mousemutex); + mousedata.mousebuttons &= ~2; + SDL_UnlockMutex(mousemutex); + break; + } + case NSEventTypeOtherMouseDown: + { + SDL_LockMutex(mousemutex); + mousedata.mousebuttons |= 4; + SDL_UnlockMutex(mousemutex); + break; + } + case NSEventTypeOtherMouseUp: + { + if (mouse_get_buttons() < 3) { plat_mouse_capture(0); return true; } + SDL_LockMutex(mousemutex); + mousedata.mousebuttons &= ~4; + SDL_UnlockMutex(mousemutex); + break; + } + } + return true; + } + } + return false; +} diff --git a/src/qt/qt_gleswidget.cpp b/src/qt/qt_gleswidget.cpp new file mode 100644 index 000000000..d7078db45 --- /dev/null +++ b/src/qt/qt_gleswidget.cpp @@ -0,0 +1,154 @@ +#include +#include +#include "qt_gleswidget.hpp" +#ifdef __APPLE__ +#include +#endif + +extern "C" +{ +#include <86box/mouse.h> +#include <86box/plat.h> +#include <86box/video.h> +} + +typedef struct mouseinputdata +{ + int deltax, deltay, deltaz; + int mousebuttons; +} mouseinputdata; + +mouseinputdata mousedata; +SDL_mutex* mousemutex; + +void +qt_mouse_capture(int on) +{ + if (!on) + { + mouse_capture = 0; + QApplication::setOverrideCursor(Qt::ArrowCursor); +#ifdef __APPLE__ + CGAssociateMouseAndMouseCursorPosition(true); +#endif + return; + } + mouse_capture = 1; + QApplication::setOverrideCursor(Qt::BlankCursor); +#ifdef __APPLE__ + CGAssociateMouseAndMouseCursorPosition(false); +#endif + return; +} + +void qt_mouse_poll() +{ + SDL_LockMutex(mousemutex); + mouse_x = mousedata.deltax; + mouse_y = mousedata.deltay; + mouse_z = mousedata.deltaz; + mousedata.deltax = mousedata.deltay = mousedata.deltaz = 0; + mouse_buttons = mousedata.mousebuttons; + SDL_UnlockMutex(mousemutex); +} + +void GLESWidget::resizeGL(int w, int h) +{ + glViewport(0, 0, w, h); +} + +void GLESWidget::initializeGL() +{ + initializeOpenGLFunctions(); +} +void GLESWidget::paintGL() +{ + QPainter painter(this); + //painter.fillRect(rect, QColor(0, 0, 0)); + painter.drawImage(QRect(0, 0, width(), height()), m_image.convertToFormat(QImage::Format_RGBA8888), QRect(sx, sy, sw, sh)); + painter.end(); + update(); +} + +void GLESWidget::mouseReleaseEvent(QMouseEvent *event) +{ + if (this->geometry().contains(event->pos()) && event->button() == Qt::LeftButton && !mouse_capture) + { + this->grabMouse(); + return; + } + if (mouse_capture && event->button() == Qt::MiddleButton && mouse_get_buttons() < 3) + { + this->releaseMouse(); + return; + } + if (mouse_capture) + { + SDL_LockMutex(mousemutex); + mousedata.mousebuttons &= ~event->button(); + SDL_UnlockMutex(mousemutex); + } +} +void GLESWidget::mousePressEvent(QMouseEvent *event) +{ + if (mouse_capture) + { + SDL_LockMutex(mousemutex); + mousedata.mousebuttons |= event->button(); + SDL_UnlockMutex(mousemutex); + } +} +void GLESWidget::wheelEvent(QWheelEvent *event) +{ + if (mouse_capture) + { + SDL_LockMutex(mousemutex); + mousedata.deltay += event->pixelDelta().y(); + SDL_UnlockMutex(mousemutex); + } +} + +int ignoreNextMouseEvent = 0; +void GLESWidget::mouseMoveEvent(QMouseEvent *event) +{ + if (!mouse_capture) { event->ignore(); return; } +#ifdef __APPLE__ + event->accept(); + return; +#else + static QPoint oldPos = QCursor::pos(); + if (ignoreNextMouseEvent) { oldPos = event->pos(); ignoreNextMouseEvent--; event->accept(); return; } + SDL_LockMutex(mousemutex); + mousedata.deltax += event->pos().x() - oldPos.x(); + mousedata.deltay += event->pos().y() - oldPos.y(); + SDL_UnlockMutex(mousemutex); + QCursor::setPos(mapToGlobal(QPoint(width() / 2, height() / 2))); + oldPos = event->pos(); + ignoreNextMouseEvent = 1; +#endif +} + +void GLESWidget::qt_real_blit(int x, int y, int w, int h) +{ + // printf("Offpainter thread ID: %X\n", SDL_ThreadID()); + if ((w <= 0) || (h <= 0) || (w > 2048) || (h > 2048) || (buffer32 == NULL)) + { + video_blit_complete(); + return; + } + sx = x; + sy = y; + sw = this->w = w; + sh = this->h = h; + auto imagebits = m_image.bits(); + for (int y1 = y; y1 < (y + h - 1); y1++) + { + auto scanline = imagebits + (y1 * (2048 + 64) * 4); + video_copy(scanline + (x * 4), &(buffer32->line[y1][x]), w * 4); + } + if (screenshots) + { + video_screenshot((uint32_t *)imagebits, 0, 0, 2048 + 64); + } + video_blit_complete(); +} \ No newline at end of file diff --git a/src/qt/qt_gleswidget.hpp b/src/qt/qt_gleswidget.hpp new file mode 100644 index 000000000..8689cdf1d --- /dev/null +++ b/src/qt/qt_gleswidget.hpp @@ -0,0 +1,41 @@ +#include +#include +#include +#include +#include + +class GLESWidget : public QOpenGLWidget, protected QOpenGLFunctions +{ + Q_OBJECT + +private: + QImage m_image{QSize(2048 + 64, 2048 + 64), QImage::Format_RGB32}; + int x, y, w, h, sx, sy, sw, sh; +public: + void resizeGL(int w, int h) override; + void initializeGL() override; + void paintGL() override; + GLESWidget(QWidget* parent = nullptr) + : QOpenGLWidget(parent) + { + setMinimumSize(16, 16); + } + ~GLESWidget() + { + makeCurrent(); + } + void mousePressEvent(QMouseEvent* event) override; + void mouseReleaseEvent(QMouseEvent* event) override; + void mouseMoveEvent(QMouseEvent* event) override; + void wheelEvent(QWheelEvent *event) override; + void keyPressEvent(QKeyEvent* event) override + { + event->ignore(); + } + void keyReleaseEvent(QKeyEvent* event) override + { + event->ignore(); + } +public slots: + void qt_real_blit(int x, int y, int w, int h); +}; \ No newline at end of file diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 3fb6dd2ca..56a486ac8 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -11,8 +11,11 @@ #include +#include "SDL.h" +#include "SDL_mutex.h" #include "qt_mainwindow.hpp" #include "qt_sdl.h" +#include "cocoa_mouse.hpp" // Void Cast @@ -73,9 +76,16 @@ main_thread_fn() is_quit = 1; } +extern SDL_mutex* mousemutex; int main(int argc, char* argv[]) { QApplication app(argc, argv); +#ifdef __APPLE__ + CocoaEventFilter cocoafilter; + app.installNativeEventFilter(&cocoafilter); +#endif elapsed_timer.start(); + SDL_Init(SDL_INIT_TIMER); + mousemutex = SDL_CreateMutex(); main_window = new MainWindow(); main_window->show(); @@ -91,6 +101,7 @@ int main(int argc, char* argv[]) { // plat_pause(0); /* Initialize the rendering window, or fullscreen. */ + QTimer::singleShot(50, []() { plat_resize(640, 480); } ); auto main_thread = std::thread([] { main_thread_fn(); }); diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 34f3a0340..fdde83dc5 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -1,10 +1,14 @@ #include "qt_mainwindow.hpp" +#include "ui_qt_machinestatus.h" #include "ui_qt_mainwindow.h" +#include extern "C" { #include <86box/86box.h> #include <86box/config.h> +#include <86box/keyboard.h> #include <86box/plat.h> +#include <86box/video.h> #include "qt_sdl.h" }; @@ -16,7 +20,19 @@ extern "C" { #include #include +#include + #include "qt_settings.hpp" +#include "qt_gleswidget.hpp" + +#ifdef __unix__ +#include +#include +#endif + +extern void qt_mouse_poll(); +extern void qt_mouse_capture(int); +extern "C" void qt_blit(int x, int y, int w, int h); MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), @@ -25,25 +41,36 @@ MainWindow::MainWindow(QWidget *parent) : Q_INIT_RESOURCE(qt_resources); ui->setupUi(this); + video_setblit(qt_blit); + + this->hw_widget = new GLESWidget(this); + this->hw_widget->setMouseTracking(true); + this->hw_widget->setGeometry(QRect(this->menuWidget() ? QPoint(0,this->menuWidget()->size().height()) : QPoint(0,0), QSize(640, 480))); + this->setCentralWidget(this->hw_widget); + connect(this, &MainWindow::blitToWidget, (GLESWidget*)this->hw_widget, &GLESWidget::qt_real_blit); connect(this, &MainWindow::showMessageForNonQtThread, this, &MainWindow::showMessage_, Qt::BlockingQueuedConnection); connect(this, &MainWindow::pollMouse, this, [] { - sdl_mouse_poll(); + qt_mouse_poll(); }); - connect(this, &MainWindow::setMouseCapture, this, [](bool state) { + connect(this, &MainWindow::setMouseCapture, this, [this](bool state) { mouse_capture = state ? 1 : 0; - sdl_mouse_capture(mouse_capture); + qt_mouse_capture(mouse_capture); + if (mouse_capture) hw_widget->grabMouse(); + else hw_widget->releaseMouse(); }); - connect(this, &MainWindow::setFullscreen, this, [](bool state) { + connect(this, &MainWindow::setFullscreen, this, [this](bool state) { video_fullscreen = state ? 1 : 0; - sdl_set_fs(video_fullscreen); + //sdl_set_fs(video_fullscreen); + this->setFullscreen(state); }); connect(this, &MainWindow::resizeContents, this, [this](int w, int h) { - sdl_resize(w, h); + this->hw_widget->resize(w, h); + this->resize(w, h + menuBar()->height() + statusBar()->height()); }); connect(ui->menubar, &QMenuBar::triggered, this, [] { @@ -56,7 +83,7 @@ MainWindow::MainWindow(QWidget *parent) : ui->actionKeyboard_requires_capture->setChecked(kbd_req_capture); ui->actionRight_CTRL_is_left_ALT->setChecked(rctrl_is_lalt); - +#if 0 sdl_inits(); sdl_timer = new QTimer(this); connect(sdl_timer, &QTimer::timeout, this, [] { @@ -66,10 +93,13 @@ MainWindow::MainWindow(QWidget *parent) : } }); sdl_timer->start(5); +#endif } MainWindow::~MainWindow() { - sdl_close(); + //sdl_close(); + startblit(); + //delete hw_widget; delete ui; } @@ -123,165 +153,494 @@ void MainWindow::on_actionSettings_triggered() { } } -static const int keycode_entries = 136; -// xmodmap -pk -static const uint16_t xfree86_keycode_table[keycode_entries] = { - /* 0 */ 0, - /* 1 */ 0, - /* 2 */ 0, - /* 3 */ 0, - /* 4 */ 0, - /* 5 */ 0, - /* 6 */ 0, - /* 7 */ 0, - /* 8 */ 0, - /* 9 */ 0x01, // Esc - /* 10 */ 0x02, // 1 - /* 11 */ 0x03, // 2 - /* 12 */ 0x04, // 3 - /* 13 */ 0x05, // 4 - /* 14 */ 0x06, // 5 - /* 15 */ 0x07, // 6 - /* 16 */ 0x08, // 7 - /* 17 */ 0x09, // 8 - /* 18 */ 0x0a, // 9 - /* 19 */ 0x0b, // 0 - /* 20 */ 0x0c, // - - /* 21 */ 0x0d, // = - /* 22 */ 0x0e, // BackSpace - /* 23 */ 0x0f, // Tab - /* 24 */ 0x10, // Q - /* 25 */ 0x11, // W - /* 26 */ 0x12, // E - /* 27 */ 0x13, // R - /* 28 */ 0x14, // T - /* 29 */ 0x15, // Y - /* 30 */ 0x16, // U - /* 31 */ 0x17, // I - /* 32 */ 0x18, // O - /* 33 */ 0x19, // P - /* 34 */ 0x1a, // [ - /* 35 */ 0x1b, // ] - /* 36 */ 0x1c, // Return - /* 37 */ 0x1d, // LeftControl - /* 38 */ 0x1e, // A - /* 39 */ 0x1f, // S - /* 40 */ 0x20, // D - /* 41 */ 0x21, // F - /* 42 */ 0x22, // G - /* 43 */ 0x23, // H - /* 44 */ 0x24, // J - /* 45 */ 0x25, // K - /* 46 */ 0x26, // L - /* 47 */ 0x27, // ; - /* 48 */ 0x28, // ' - /* 49 */ 0x29, // ` (???) - /* 50 */ 0x2a, // LeftShift - /* 51 */ 0x2b, // BackSlash - /* 52 */ 0x2c, // Z - /* 53 */ 0x2d, // X - /* 54 */ 0x2e, // C - /* 55 */ 0x2f, // V - /* 56 */ 0x30, // B - /* 57 */ 0x31, // N - /* 58 */ 0x32, // M - /* 59 */ 0x33, // , - /* 60 */ 0x34, // . - /* 61 */ 0x35, // - - /* 62 */ 0x36, // RightShift - /* 63 */ 0x37, // KeyPad Multiply - /* 64 */ 0x38, // LeftAlt - /* 65 */ 0x39, // Space - /* 66 */ 0x3a, // CapsLock - /* 67 */ 0x3b, // F01 - /* 68 */ 0x3c, // F02 - /* 69 */ 0x3d, // F03 - /* 70 */ 0x3e, // F04 - /* 71 */ 0x3f, // F05 - /* 72 */ 0x40, // F06 - /* 73 */ 0x41, // F07 - /* 74 */ 0x42, // F08 - /* 75 */ 0x43, // F09 - /* 76 */ 0x44, // F10 - /* 77 */ 0x45, // NumLock - /* 78 */ 0x46, // ScrollLock - /* 79 */ 0x47, // KeyPad7 - /* 80 */ 0x48, // KeyPad8 - /* 81 */ 0x49, // KeyPad9 - /* 82 */ 0x4a, // KeyPad Minus - /* 83 */ 0x4b, // KeyPad4 - /* 84 */ 0x4c, // KeyPad5 - /* 85 */ 0x4d, // KeyPad6 - /* 86 */ 0x4e, // KeyPad Plus - /* 87 */ 0x4f, // KeyPad1 - /* 88 */ 0x50, // KeyPad2 - /* 89 */ 0x51, // KeyPad3 - /* 90 */ 0x52, // KeyPad0 - /* 91 */ 0x53, // KeyPad . - /* 92 */ 0, - /* 93 */ 0, - /* 94 */ 0x56, // Less/Great - /* 95 */ 0x57, // F11 - /* 96 */ 0x58, // F12 - /* 97 */ 0, - /* 98 */ 0, - /* 99 */ 0, - /* 100 */ 0, - /* 101 */ 0, - /* 102 */ 0, - /* 103 */ 0, - /* 104 */ 0x11c, // KeyPad Enter - /* 105 */ 0x11d, // RightControl - /* 106 */ 0x135, // KeyPad Divide - /* 107 */ 0x137, // PrintScreen / SysReq - /* 108 */ 0x138, // RightAlt - /* 109 */ 0, - /* 110 */ 0x147, // Home - /* 111 */ 0x148, // Up - /* 112 */ 0x149, // PageUp - /* 113 */ 0x14b, // Left - /* 114 */ 0x14d, // Right - /* 115 */ 0x14f, // End - /* 116 */ 0x150, // Down - /* 117 */ 0x151, // PageDown - /* 118 */ 0x152, // Insert - /* 119 */ 0x153, // Delete - /* 120 */ 0, - /* 121 */ 0, - /* 122 */ 0, - /* 123 */ 0, - /* 124 */ 0, - /* 125 */ 0, - /* 126 */ 0, - /* 127 */ 0, - /* 128 */ 0, - /* 129 */ 0, - /* 130 */ 0, - /* 131 */ 0, - /* 132 */ 0, - /* 133 */ 0x15b, // SuperLeft - /* 134 */ 0x15c, // SuperRight - /* 135 */ 0x15d, // Application +std::array x11_to_xt_base +{ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0x01, + 0x02, + 0x03, + 0x04, + 0x05, + 0x06, + 0x07, + 0x08, + 0x09, + 0x0A, + 0x0B, + 0x0C, + 0x0D, + 0x0E, + 0x0F, + 0x10, + 0x11, + 0x12, + 0x13, + 0x14, + 0x15, + 0x16, + 0x17, + 0x18, + 0x19, + 0x1A, + 0x1B, + 0x1C, + 0x1D, + 0x1E, + 0x1F, + 0x20, + 0x21, + 0x22, + 0x23, + 0x24, + 0x25, + 0x26, + 0x27, + 0x28, + 0x29, + 0x2A, + 0x2B, + 0x2C, + 0x2D, + 0x2E, + 0x2F, + 0x30, + 0x31, + 0x32, + 0x33, + 0x34, + 0x35, + 0x36, + 0x37, + 0x38, + 0x39, + 0x3A, + 0x3B, + 0x3C, + 0x3D, + 0x3E, + 0x3F, + 0x40, + 0x41, + 0x42, + 0x43, + 0x44, + 0x45, + 0x46, + 0x47, + 0x48, + 0x49, + 0x4A, + 0x4B, + 0x4C, + 0x4D, + 0x4E, + 0x4F, + 0x50, + 0x51, + 0x52, + 0x53, + 0x54, + 0x55, + 0x56, + 0x57, + 0x58, + 0x147, + 0x148, + 0x149, + 0, + 0x14B, + 0, + 0x14D, + 0x14F, + 0x150, + 0x151, + 0x152, + 0x153, + 0x11C, + 0x11D, + 0, // Pause/Break key. + 0x137, + 0x135, + 0x138, + 0, // Ditto as above comment. + 0x15B, + 0x15C, + 0x15D, }; -//static void handle_keypress_event(int state, quint32 native_scancode) { -// if (native_scancode > keycode_entries) { -// return; -// } -// uint16_t translated_code = xfree86_keycode_table[native_scancode]; -// if (translated_code == 0) { -// return; -// } -// keyboard_input(state, translated_code); +std::array x11_to_xt_2 +{ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0x01, + 0x02, + 0x03, + 0x04, + 0x05, + 0x06, + 0x07, + 0x08, + 0x09, + 0x0A, + 0x0B, + 0x0C, + 0x0D, + 0x0E, + 0x0F, + 0x10, + 0x11, + 0x12, + 0x13, + 0x14, + 0x15, + 0x16, + 0x17, + 0x18, + 0x19, + 0x1A, + 0x1B, + 0x1C, + 0x1D, + 0x1E, + 0x1F, + 0x20, + 0x21, + 0x22, + 0x23, + 0x24, + 0x25, + 0x26, + 0x27, + 0x28, + 0x29, + 0x2A, + 0x2B, + 0x2C, + 0x2D, + 0x2E, + 0x2F, + 0x30, + 0x31, + 0x32, + 0x33, + 0x34, + 0x35, + 0x36, + 0x37, + 0x38, + 0x39, + 0x3A, + 0x3B, + 0x3C, + 0x3D, + 0x3E, + 0x3F, + 0x40, + 0x41, + 0x42, + 0x43, + 0x44, + 0x45, + 0x46, + 0x47, + 0x48, + 0x49, + 0x4A, + 0x4B, + 0x4C, + 0x4D, + 0x4E, + 0x4F, + 0x50, + 0x51, + 0x52, + 0x53, + 0x54, + 0x55, + 0x56, + 0x57, + 0x58, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0x11C, + 0x11D, + 0x135, + 0x137, + 0x138, + 0, + 0x147, + 0x148, + 0x149, + 0x14B, + 0x14D, + 0x14F, + 0x150, + 0x151, + 0x152, + 0x153 +}; -// if (keyboard_isfsexit() > 0) { -// plat_setfullscreen(0); -// } +std::array x11_to_xt_vnc +{ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0x1D, + 0x11D, + 0x2A, + 0x36, + 0, + 0, + 0x38, + 0x138, + 0x39, + 0x0B, + 0x02, + 0x03, + 0x04, + 0x05, + 0x06, + 0x07, + 0x08, + 0x09, + 0x0A, + 0x0C, + 0x0D, + 0x1A, + 0x1B, + 0x27, + 0x28, + 0x29, + 0x33, + 0x34, + 0x35, + 0x2B, + 0x1E, + 0x30, + 0x2E, + 0x20, + 0x12, + 0x21, + 0x22, + 0x23, + 0x17, + 0x24, + 0x25, + 0x26, + 0x32, + 0x31, + 0x18, + 0x19, + 0x10, + 0x13, + 0x1F, + 0x14, + 0x16, + 0x2F, + 0x11, + 0x2D, + 0x15, + 0x2C, + 0x0E, + 0x1C, + 0x0F, + 0x01, + 0x153, + 0x147, + 0x14F, + 0x149, + 0x151, + 0x148, + 0x150, + 0x14B, + 0x14D, +}; -// if (keyboard_ismsexit() > 0) { -// plat_mouse_capture(0); -// } -//} +std::array darwin_to_xt +{ + 0x1E, + 0x1F, + 0x20, + 0x21, + 0x23, + 0x22, + 0x2C, + 0x2D, + 0x2E, + 0x2F, + 0x2B, + 0x30, + 0x10, + 0x11, + 0x12, + 0x13, + 0x15, + 0x14, + 0x02, + 0x03, + 0x04, + 0x05, + 0x07, + 0x06, + 0x0D, + 0x0A, + 0x08, + 0x0C, + 0x09, + 0x0B, + 0x1B, + 0x18, + 0x16, + 0x1A, + 0x17, + 0x19, + 0x1C, + 0x26, + 0x24, + 0x28, + 0x25, + 0x27, + 0x2B, + 0x33, + 0x35, + 0x31, + 0x32, + 0x34, + 0x0F, + 0x39, + 0x29, + 0x0E, + 0x11C, + 0x01, + 0x15C, + 0x15B, + 0x2A, + 0x3A, + 0x38, + 0x1D, + 0x36, + 0x138, + 0x11D, + 0x15C, + 0, + 0x53, + 0, + 0x37, + 0, + 0x4E, + 0, + 0x45, + 0x130, + 0x12E, + 0x120, + 0x135, + 0x11C, + 0, + 0x4A, + 0, + 0, + 0, + 0x52, + 0x4F, + 0x50, + 0x51, + 0x4B, + 0x4C, + 0x4D, + 0x47, + 0, + 0x48, + 0x49, + 0, + 0, + 0, + 0x3F, + 0x40, + 0x41, + 0x3D, + 0x42, + 0x43, + 0, + 0x57, + 0, + 0x137, + 0, + 0x46, + 0, + 0x44, + 0x15D, + 0x58, + 0, + 0, // Pause/Break key. + 0x152, + 0x147, + 0x149, + 0x153, + 0x3E, + 0x14F, + 0x3C, + 0x151, + 0x3B, + 0x14B, + 0x14D, + 0x150, + 0x148, + 0, +}; + +static std::array& selected_keycode = x11_to_xt_base; + +uint16_t x11_keycode_to_keysym(uint32_t keycode) +{ +#ifdef __APPLE__ + return darwin_to_xt[keycode]; +#else + static Display* x11display = nullptr; + if (QApplication::platformName().contains("wayland")) + { + selected_keycode = x11_to_xt_2; + } + else if (!x11display) + { + x11display = XOpenDisplay(nullptr); + if (XKeysymToKeycode(x11display, XK_Home) == 110) + { + selected_keycode = x11_to_xt_2; + } + else if (XKeysymToKeycode(x11display, XK_Home) == 69) + { + selected_keycode = x11_to_xt_vnc; + } + } + return selected_keycode[keycode]; +#endif +} void MainWindow::on_actionFullscreen_triggered() { setFullscreen(true); @@ -299,3 +658,21 @@ void MainWindow::showMessage_(const QString &header, const QString &message) { QMessageBox box(QMessageBox::Warning, header, message, QMessageBox::NoButton, this); box.exec(); } + +void MainWindow::keyPressEvent(QKeyEvent* event) +{ +#ifdef __APPLE__ + keyboard_input(1, x11_keycode_to_keysym(event->nativeVirtualKey())); +#else + keyboard_input(1, x11_keycode_to_keysym(event->nativeScanCode())); +#endif +} + +void MainWindow::keyReleaseEvent(QKeyEvent* event) +{ +#ifdef __APPLE__ + keyboard_input(0, x11_keycode_to_keysym(event->nativeVirtualKey())); +#else + keyboard_input(0, x11_keycode_to_keysym(event->nativeScanCode())); +#endif +} diff --git a/src/qt/qt_mainwindow.hpp b/src/qt/qt_mainwindow.hpp index ba7867120..7a075a174 100644 --- a/src/qt/qt_mainwindow.hpp +++ b/src/qt/qt_mainwindow.hpp @@ -3,6 +3,7 @@ #include #include +#include namespace Ui { class MainWindow; @@ -19,6 +20,7 @@ public: void showMessage(const QString& header, const QString& message); signals: void paint(const QImage& image); + void blitToWidget(int x, int y, int w, int h); void resizeContents(int w, int h); void pollMouse(); void updateStatusBarPanes(); @@ -41,6 +43,9 @@ private slots: void on_actionKeyboard_requires_capture_triggered(); void showMessage_(const QString& header, const QString& message); +protected: + void keyPressEvent(QKeyEvent* event) override; + void keyReleaseEvent(QKeyEvent* event) override; private: struct DeltaPos { int x = 0; @@ -51,6 +56,7 @@ private: DeltaPos mouseDelta; QWindow* sdl_wrapped_window; QWidget* sdl_wrapped_widget; + QWidget* hw_widget; QTimer* sdl_timer; }; diff --git a/src/qt/qt_ui.cpp b/src/qt/qt_ui.cpp index decca9f24..1e24ac792 100644 --- a/src/qt/qt_ui.cpp +++ b/src/qt/qt_ui.cpp @@ -36,6 +36,11 @@ wchar_t* ui_window_title(wchar_t* str) return str; } +extern "C" void qt_blit(int x, int y, int w, int h) +{ + main_window->blitToWidget(x, y, w, h); +} + void mouse_poll() { main_window->pollMouse(); }