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(Qt${QT_MAJOR} COMPONENTS Core Widgets Network OpenGL 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
|
||||
qt.c
|
||||
@@ -232,17 +240,13 @@ if (APPLE AND CMAKE_MACOSX_BUNDLE)
|
||||
set(INSTALL_CMAKE_DIR "${prefix}/Resources")
|
||||
|
||||
# using the install_qt5_plugin to add Qt plugins into the macOS app bundle
|
||||
if (USE_QT6)
|
||||
install_qt5_plugin("Qt6::QCocoaIntegrationPlugin" QT_PLUGINS ${prefix})
|
||||
else()
|
||||
install_qt5_plugin("Qt5::QCocoaIntegrationPlugin" 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()
|
||||
install_qt5_plugin("Qt${QT_MAJOR}::QCocoaIntegrationPlugin" QT_PLUGINS ${prefix})
|
||||
install_qt5_plugin("Qt${QT_MAJOR}::QMacStylePlugin" QT_PLUGINS ${prefix})
|
||||
install_qt5_plugin("Qt${QT_MAJOR}::QICOPlugin" QT_PLUGINS ${prefix})
|
||||
install_qt5_plugin("Qt${QT_MAJOR}::QICNSPlugin" QT_PLUGINS ${prefix})
|
||||
|
||||
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"
|
||||
DESTINATION "${INSTALL_CMAKE_DIR}")
|
||||
|
||||
@@ -253,8 +257,8 @@ if (APPLE AND CMAKE_MACOSX_BUNDLE)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# Append Qt's lib folder which is two levels above Qt5Widgets_DIR
|
||||
list(APPEND DIRS "${Qt5Widgets_DIR}/../..")
|
||||
# Append Qt's lib folder which is two levels above Qt*Widgets_DIR
|
||||
list(APPEND DIRS "${Qt${QT_MAJOR}Widgets_DIR}/../..")
|
||||
|
||||
include(InstallRequiredSystemLibraries)
|
||||
|
||||
|
@@ -82,6 +82,14 @@ extern "C" {
|
||||
#undef KeyRelease
|
||||
#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__
|
||||
#include <os/AppKit.h>
|
||||
#include <os/InterfaceKit.h>
|
||||
@@ -1215,7 +1223,7 @@ uint16_t x11_keycode_to_keysym(uint32_t keycode)
|
||||
uint16_t finalkeycode = 0;
|
||||
#if defined(Q_OS_WINDOWS)
|
||||
finalkeycode = (keycode & 0xFFFF);
|
||||
#elif defined(__APPLE__)
|
||||
#elif defined(Q_OS_MACOS)
|
||||
finalkeycode = darwin_to_xt[keycode];
|
||||
#elif defined(__HAIKU__)
|
||||
finalkeycode = be_to_xt[keycode];
|
||||
@@ -1252,6 +1260,68 @@ uint16_t x11_keycode_to_keysym(uint32_t keycode)
|
||||
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() {
|
||||
if (video_fullscreen > 0) {
|
||||
showNormal();
|
||||
@@ -1370,8 +1440,8 @@ void MainWindow::keyPressEvent(QKeyEvent* event)
|
||||
{
|
||||
if (send_keyboard_input && !(kbd_req_capture && !mouse_capture && !video_fullscreen))
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
keyboard_input(1, x11_keycode_to_keysym(event->nativeVirtualKey()));
|
||||
#ifdef Q_OS_MACOS
|
||||
processMacKeyboardInput(true, event);
|
||||
#else
|
||||
keyboard_input(1, x11_keycode_to_keysym(event->nativeScanCode()));
|
||||
#endif
|
||||
@@ -1397,8 +1467,8 @@ void MainWindow::keyReleaseEvent(QKeyEvent* event)
|
||||
if (!send_keyboard_input)
|
||||
return;
|
||||
|
||||
#ifdef __APPLE__
|
||||
keyboard_input(0, x11_keycode_to_keysym(event->nativeVirtualKey()));
|
||||
#ifdef Q_OS_MACOS
|
||||
processMacKeyboardInput(false, event);
|
||||
#else
|
||||
keyboard_input(0, x11_keycode_to_keysym(event->nativeScanCode()));
|
||||
#endif
|
||||
|
@@ -118,6 +118,11 @@ private:
|
||||
std::unique_ptr<MachineStatus> status;
|
||||
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 */
|
||||
bool send_keyboard_input = true;
|
||||
bool shownonce = false;
|
||||
|
Reference in New Issue
Block a user