Merge pull request #2269 from emilazy/fix-qt6-macos
Fix Qt 6 build and modifier key handling on macOS
This commit is contained in:
@@ -22,6 +22,14 @@ endif()
|
|||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
find_package(Qt${QT_MAJOR} COMPONENTS Core Widgets Network OpenGL REQUIRED)
|
find_package(Qt${QT_MAJOR} COMPONENTS Core Widgets Network OpenGL REQUIRED)
|
||||||
find_package(Qt${QT_MAJOR}LinguistTools REQUIRED)
|
find_package(Qt${QT_MAJOR}LinguistTools REQUIRED)
|
||||||
|
# TODO: Is this the correct way to do this, and is it required on any
|
||||||
|
# other platforms or with Qt 5?
|
||||||
|
if(APPLE AND USE_QT6)
|
||||||
|
find_package(Qt6Gui/Qt6QCocoaIntegrationPlugin REQUIRED)
|
||||||
|
find_package(Qt6Widgets/Qt6QMacStylePlugin REQUIRED)
|
||||||
|
find_package(Qt6Gui/Qt6QICOPlugin REQUIRED)
|
||||||
|
find_package(Qt6Gui/Qt6QICNSPlugin REQUIRED)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_library(plat STATIC
|
add_library(plat STATIC
|
||||||
qt.c
|
qt.c
|
||||||
@@ -232,17 +240,13 @@ if (APPLE AND CMAKE_MACOSX_BUNDLE)
|
|||||||
set(INSTALL_CMAKE_DIR "${prefix}/Resources")
|
set(INSTALL_CMAKE_DIR "${prefix}/Resources")
|
||||||
|
|
||||||
# using the install_qt5_plugin to add Qt plugins into the macOS app bundle
|
# using the install_qt5_plugin to add Qt plugins into the macOS app bundle
|
||||||
if (USE_QT6)
|
install_qt5_plugin("Qt${QT_MAJOR}::QCocoaIntegrationPlugin" QT_PLUGINS ${prefix})
|
||||||
install_qt5_plugin("Qt6::QCocoaIntegrationPlugin" QT_PLUGINS ${prefix})
|
install_qt5_plugin("Qt${QT_MAJOR}::QMacStylePlugin" QT_PLUGINS ${prefix})
|
||||||
else()
|
install_qt5_plugin("Qt${QT_MAJOR}::QICOPlugin" QT_PLUGINS ${prefix})
|
||||||
install_qt5_plugin("Qt5::QCocoaIntegrationPlugin" QT_PLUGINS ${prefix})
|
install_qt5_plugin("Qt${QT_MAJOR}::QICNSPlugin" QT_PLUGINS ${prefix})
|
||||||
install_qt5_plugin("Qt5::QMacStylePlugin" QT_PLUGINS ${prefix})
|
|
||||||
install_qt5_plugin("Qt5::QICOPlugin" QT_PLUGINS ${prefix})
|
|
||||||
install_qt5_plugin("Qt5::QICNSPlugin" QT_PLUGINS ${prefix})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/qt.conf"
|
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/qt.conf"
|
||||||
"[Paths]\nPlugins = ${_qt_plugin_dir}\n")
|
"[Paths]\nPlugins = PlugIns\n")
|
||||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/qt.conf"
|
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/qt.conf"
|
||||||
DESTINATION "${INSTALL_CMAKE_DIR}")
|
DESTINATION "${INSTALL_CMAKE_DIR}")
|
||||||
|
|
||||||
@@ -253,8 +257,8 @@ if (APPLE AND CMAKE_MACOSX_BUNDLE)
|
|||||||
endforeach()
|
endforeach()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Append Qt's lib folder which is two levels above Qt5Widgets_DIR
|
# Append Qt's lib folder which is two levels above Qt*Widgets_DIR
|
||||||
list(APPEND DIRS "${Qt5Widgets_DIR}/../..")
|
list(APPEND DIRS "${Qt${QT_MAJOR}Widgets_DIR}/../..")
|
||||||
|
|
||||||
include(InstallRequiredSystemLibraries)
|
include(InstallRequiredSystemLibraries)
|
||||||
|
|
||||||
|
|||||||
@@ -82,6 +82,14 @@ extern "C" {
|
|||||||
#undef KeyRelease
|
#undef KeyRelease
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef Q_OS_MACOS
|
||||||
|
// The namespace is required to avoid clashing typedefs; we only use this
|
||||||
|
// header for its #defines anyway.
|
||||||
|
namespace IOKit {
|
||||||
|
#include <IOKit/hidsystem/IOLLEvent.h>
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __HAIKU__
|
#ifdef __HAIKU__
|
||||||
#include <os/AppKit.h>
|
#include <os/AppKit.h>
|
||||||
#include <os/InterfaceKit.h>
|
#include <os/InterfaceKit.h>
|
||||||
@@ -1215,7 +1223,7 @@ uint16_t x11_keycode_to_keysym(uint32_t keycode)
|
|||||||
uint16_t finalkeycode = 0;
|
uint16_t finalkeycode = 0;
|
||||||
#if defined(Q_OS_WINDOWS)
|
#if defined(Q_OS_WINDOWS)
|
||||||
finalkeycode = (keycode & 0xFFFF);
|
finalkeycode = (keycode & 0xFFFF);
|
||||||
#elif defined(__APPLE__)
|
#elif defined(Q_OS_MACOS)
|
||||||
finalkeycode = darwin_to_xt[keycode];
|
finalkeycode = darwin_to_xt[keycode];
|
||||||
#elif defined(__HAIKU__)
|
#elif defined(__HAIKU__)
|
||||||
finalkeycode = be_to_xt[keycode];
|
finalkeycode = be_to_xt[keycode];
|
||||||
@@ -1252,6 +1260,68 @@ uint16_t x11_keycode_to_keysym(uint32_t keycode)
|
|||||||
return finalkeycode;
|
return finalkeycode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef Q_OS_MACOS
|
||||||
|
// These modifiers are listed as "device-dependent" in IOLLEvent.h, but
|
||||||
|
// that's followed up with "(really?)". It's the only way to distinguish
|
||||||
|
// left and right modifiers with Qt 6 on macOS, so let's just roll with it.
|
||||||
|
static std::unordered_map<uint32_t, uint16_t> mac_modifiers_to_xt = {
|
||||||
|
{NX_DEVICELCTLKEYMASK, 0x1D},
|
||||||
|
{NX_DEVICELSHIFTKEYMASK, 0x2A},
|
||||||
|
{NX_DEVICERSHIFTKEYMASK, 0x36},
|
||||||
|
{NX_DEVICELCMDKEYMASK, 0x15B},
|
||||||
|
{NX_DEVICERCMDKEYMASK, 0x15C},
|
||||||
|
{NX_DEVICELALTKEYMASK, 0x38},
|
||||||
|
{NX_DEVICERALTKEYMASK, 0x138},
|
||||||
|
{NX_DEVICE_ALPHASHIFT_STATELESS_MASK, 0x3A},
|
||||||
|
{NX_DEVICERCTLKEYMASK, 0x11D},
|
||||||
|
};
|
||||||
|
|
||||||
|
void MainWindow::processMacKeyboardInput(bool down, const QKeyEvent* event) {
|
||||||
|
// Per QTBUG-69608 (https://bugreports.qt.io/browse/QTBUG-69608),
|
||||||
|
// QKeyEvents QKeyEvents for presses/releases of modifiers on macOS give
|
||||||
|
// nativeVirtualKey() == 0 (at least in Qt 6). Handle this by manually
|
||||||
|
// processing the nativeModifiers(). We need to check whether the key() is
|
||||||
|
// a known modifier because because kVK_ANSI_A is also 0, so the
|
||||||
|
// nativeVirtualKey() == 0 condition is ambiguous...
|
||||||
|
if (event->nativeVirtualKey() == 0
|
||||||
|
&& (event->key() == Qt::Key_Shift
|
||||||
|
|| event->key() == Qt::Key_Control
|
||||||
|
|| event->key() == Qt::Key_Meta
|
||||||
|
|| event->key() == Qt::Key_Alt
|
||||||
|
|| event->key() == Qt::Key_AltGr
|
||||||
|
|| event->key() == Qt::Key_CapsLock)) {
|
||||||
|
// We only process one modifier at a time since events from Qt seem to
|
||||||
|
// always be non-coalesced (NX_NONCOALESCEDMASK is always set).
|
||||||
|
uint32_t changed_modifiers = last_modifiers ^ event->nativeModifiers();
|
||||||
|
for (auto const& pair : mac_modifiers_to_xt) {
|
||||||
|
if (changed_modifiers & pair.first) {
|
||||||
|
last_modifiers ^= pair.first;
|
||||||
|
keyboard_input(down, pair.second);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Caps Lock seems to be delivered as a single key press event when
|
||||||
|
// enabled and a single key release event when disabled, so we can't
|
||||||
|
// detect Caps Lock being held down; just send an infinitesimally-long
|
||||||
|
// press and release as a compromise.
|
||||||
|
//
|
||||||
|
// The event also doesn't get delivered if you turn Caps Lock off after
|
||||||
|
// turning it on when the window isn't focused. Doing better than this
|
||||||
|
// probably requires bypassing Qt input processing.
|
||||||
|
//
|
||||||
|
// It's possible that other lock keys get delivered in this way, but
|
||||||
|
// standard Apple keyboards don't have them, so this is untested.
|
||||||
|
if (event->key() == Qt::Key_CapsLock) {
|
||||||
|
keyboard_input(1, 0x3A);
|
||||||
|
keyboard_input(0, 0x3A);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
keyboard_input(down, x11_keycode_to_keysym(event->nativeVirtualKey()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void MainWindow::on_actionFullscreen_triggered() {
|
void MainWindow::on_actionFullscreen_triggered() {
|
||||||
if (video_fullscreen > 0) {
|
if (video_fullscreen > 0) {
|
||||||
showNormal();
|
showNormal();
|
||||||
@@ -1370,8 +1440,8 @@ void MainWindow::keyPressEvent(QKeyEvent* event)
|
|||||||
{
|
{
|
||||||
if (send_keyboard_input && !(kbd_req_capture && !mouse_capture && !video_fullscreen))
|
if (send_keyboard_input && !(kbd_req_capture && !mouse_capture && !video_fullscreen))
|
||||||
{
|
{
|
||||||
#ifdef __APPLE__
|
#ifdef Q_OS_MACOS
|
||||||
keyboard_input(1, x11_keycode_to_keysym(event->nativeVirtualKey()));
|
processMacKeyboardInput(true, event);
|
||||||
#else
|
#else
|
||||||
keyboard_input(1, x11_keycode_to_keysym(event->nativeScanCode()));
|
keyboard_input(1, x11_keycode_to_keysym(event->nativeScanCode()));
|
||||||
#endif
|
#endif
|
||||||
@@ -1397,8 +1467,8 @@ void MainWindow::keyReleaseEvent(QKeyEvent* event)
|
|||||||
if (!send_keyboard_input)
|
if (!send_keyboard_input)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef Q_OS_MACOS
|
||||||
keyboard_input(0, x11_keycode_to_keysym(event->nativeVirtualKey()));
|
processMacKeyboardInput(false, event);
|
||||||
#else
|
#else
|
||||||
keyboard_input(0, x11_keycode_to_keysym(event->nativeScanCode()));
|
keyboard_input(0, x11_keycode_to_keysym(event->nativeScanCode()));
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -118,6 +118,11 @@ private:
|
|||||||
std::unique_ptr<MachineStatus> status;
|
std::unique_ptr<MachineStatus> status;
|
||||||
std::shared_ptr<MediaMenu> mm;
|
std::shared_ptr<MediaMenu> mm;
|
||||||
|
|
||||||
|
#ifdef Q_OS_MACOS
|
||||||
|
uint32_t last_modifiers = 0;
|
||||||
|
void processMacKeyboardInput(bool down, const QKeyEvent* event);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* If main window should send keyboard input */
|
/* If main window should send keyboard input */
|
||||||
bool send_keyboard_input = true;
|
bool send_keyboard_input = true;
|
||||||
bool shownonce = false;
|
bool shownonce = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user