Hi, There was some discussion on lyx-users a few years ago about patching Qt to swap the Command and Control keys on the Mac for people who use Emacs key bindings: http://www.mail-archive.com/[EMAIL PROTECTED]/msg49883.html.
Since then, Jens Noeckel and I have occasionally compiled binaries with the patch and posted links to them at http://wiki.lyx.org/Mac/LyXmodifierKeys. This is obviously not ideal. I finally got around to making a better patch that configures the swapping behavior at runtime based on a property in a preferences file. The patch is appended below. Details are posted on the LyXmodifierKeys wiki page, along with a patched Universal binary of LyX 1.5.4 (built with Qt/Mac 4.3.4) and scripts to create and apply the patch to a clean Qt source distribution. I also compiled and tested against the SVN trunk (r24030), and it appears to work fine. I believe the performance impact is negligible -- one or two extra "if" tests on a static boolean each time a modifier key is pressed -- and there is no change in Qt's behavior unless swapping is enabled. Thanks to Jens and Chris Menzel (on copy), it has now been tested on both PPC and Intel Macs under both Tiger and Leopard. Would the folks who maintain the Mac binaries (Bennett in particular) consider incorporating this patch into future "official" Mac releases? -j Jason Woodard [EMAIL PROTECTED] diff -Naur src/gui/kernel/qapplication_mac.cpp src-patched/gui/kernel/qapplication_mac.cpp --- src/gui/kernel/qapplication_mac.cpp 2008-03-23 22:25:23.000000000 +0800 +++ src-patched/gui/kernel/qapplication_mac.cpp 2008-03-23 22:26:56.000000000 +0800 @@ -157,6 +157,7 @@ static bool qt_button_down_in_content; // whether the button_down was in the content area. static bool qt_mac_previous_press_in_popup_mode = false; static bool qt_mac_no_click_through_mode = false; +extern bool qt_mac_swap_modifiers; // from qkeymapper_mac.cpp; keymap hack static QPointer<QWidget> qt_mouseover; #if defined(QT_DEBUG) static bool appNoGrab = false; // mouse/keyboard grabbing @@ -411,6 +412,12 @@ if (appleValue.isValid()) qt_antialiasing_threshold = appleValue.toInt(); + // begin keymap hack + appleValue = appleSettings.value(QLatin1String("QtSwapModifiers")); + if (appleValue.isValid()) + qt_mac_swap_modifiers = appleValue.toBool(); + // end keymap hack + #ifdef DEBUG_PLATFORM_SETTINGS qDebug("qt_mac_update_os_settings *********************************************************************"); #endif diff -Naur src/gui/kernel/qkeymapper_mac.cpp src-patched/gui/kernel/qkeymapper_mac.cpp --- src/gui/kernel/qkeymapper_mac.cpp 2008-03-23 22:24:27.000000000 +0800 +++ src-patched/gui/kernel/qkeymapper_mac.cpp 2008-03-26 21:38:38.000000000 +0800 @@ -62,6 +62,7 @@ Internal variables and functions ************************************************************************ *****/ bool qt_mac_eat_unicode_key = false; +bool qt_mac_swap_modifiers = false; // keymap hack extern bool qt_sendSpontaneousEvent(QObject *obj, QEvent *event); //qapplication_mac.cpp Q_GUI_EXPORT void qt_mac_secure_keyboard(bool b) @@ -144,20 +145,50 @@ { kEventKeyModifierNumLockMask, QT_MAC_MAP_ENUM(Qt::KeypadModifier) }, { 0, QT_MAC_MAP_ENUM(0) } }; + +// begin keymap hack +static qt_mac_enum_mapper qt_mac_modifier_symbols_swapped[] = { + { shiftKey, QT_MAC_MAP_ENUM(Qt::ShiftModifier) }, + { rightShiftKey, QT_MAC_MAP_ENUM(Qt::ShiftModifier) }, + { controlKey, QT_MAC_MAP_ENUM(Qt::ControlModifier) }, + { rightControlKey, QT_MAC_MAP_ENUM(Qt::ControlModifier) }, + { cmdKey, QT_MAC_MAP_ENUM(Qt::MetaModifier) }, + { kEventKeyModifierNumLockMask, QT_MAC_MAP_ENUM(Qt::KeypadModifier) }, + { 0, QT_MAC_MAP_ENUM(0) } +}; +// end keymap hack + Qt::KeyboardModifiers qt_mac_get_modifiers(int keys) { #ifdef DEBUG_KEY_BINDINGS_MODIFIERS qDebug("Qt: internal: **Mapping modifiers: %d (0x%04x)", keys, keys); #endif Qt::KeyboardModifiers ret = Qt::NoModifier; - for(int i = 0; qt_mac_modifier_symbols[i].qt_code; i++) { - if(keys & qt_mac_modifier_symbols[i].mac_code) { + + // begin keymap hack + if(qt_mac_swap_modifiers) { + // same as below except use swapped array instead of original one + for(int i = 0; qt_mac_modifier_symbols_swapped[i].qt_code; i++) { + if(keys & qt_mac_modifier_symbols_swapped[i].mac_code) { #ifdef DEBUG_KEY_BINDINGS_MODIFIERS - qDebug("Qt: internal: got modifier: %s", qt_mac_modifier_symbols[i].desc); + qDebug("Qt: internal: got swapped modifier: %s", qt_mac_modifier_symbols_swapped[i].desc); #endif - ret |= Qt::KeyboardModifier(qt_mac_modifier_symbols[i].qt_code); + ret |= Qt::KeyboardModifier(qt_mac_modifier_symbols_swapped[i].qt_code); + } + } + } else { + // original code + for(int i = 0; qt_mac_modifier_symbols[i].qt_code; i++) { + if(keys & qt_mac_modifier_symbols[i].mac_code) { +#ifdef DEBUG_KEY_BINDINGS_MODIFIERS + qDebug("Qt: internal: got modifier: %s", qt_mac_modifier_symbols[i].desc); +#endif + ret |= Qt::KeyboardModifier(qt_mac_modifier_symbols[i].qt_code); + } } } + // end keymap hack + return ret; } static int qt_mac_get_mac_modifiers(Qt::KeyboardModifiers keys) @@ -493,14 +524,29 @@ static UInt32 tmp_state = 0L; if(*outModifiers & Qt::ShiftModifier) tmp_mod |= shiftKey; - if(*outModifiers & Qt::MetaModifier) - tmp_mod |= controlKey; - if(*outModifiers & Qt::ControlModifier) - tmp_mod |= cmdKey; + + // begin keymap hack + if(qt_mac_swap_modifiers) { + // same as below except swap cmd and control keys, + // and omit alt key to avoid interfering with + // accented characters + if(*outModifiers & Qt::MetaModifier) + tmp_mod |= cmdKey; + if(*outModifiers & Qt::ControlModifier) + tmp_mod |= controlKey; + } else { + // original code + if(*outModifiers & Qt::MetaModifier) + tmp_mod |= controlKey; + if(*outModifiers & Qt::ControlModifier) + tmp_mod |= cmdKey; + if(*outModifiers & Qt::AltModifier) + tmp_mod |= optionKey; + } + // end keymap hack + if(GetCurrentEventKeyModifiers() & alphaLock) //no Qt mapper tmp_mod |= alphaLock; - if(*outModifiers & Qt::AltModifier) - tmp_mod |= optionKey; if(*outModifiers & Qt::KeypadModifier) tmp_mod |= kEventKeyModifierNumLockMask; translatedChar = KeyTranslate(keyboard_layout, tmp_mod | keyCode, &tmp_state);