mirror of
https://bitbucket.org/smil3y/kdelibs.git
synced 2025-03-01 13:22:51 +00:00
249 lines
8.1 KiB
C++
249 lines
8.1 KiB
C++
/*
|
|
Copyright (C) 2006 Marijn Kruisselbrink <m.kruisselbrink@student.tue.nl>
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "kkeyserver_mac.h"
|
|
|
|
#include <config.h>
|
|
|
|
#include <QtCore/QCOORD>
|
|
|
|
#ifdef Q_WS_MACX // Only compile this module if we're compiling for Mac OS X
|
|
|
|
#include "kshortcut.h"
|
|
#include <kdebug.h>
|
|
#include <QMultiMap>
|
|
#include <Carbon/Carbon.h>
|
|
|
|
namespace KKeyServer {
|
|
struct TransKey {
|
|
int qt_code;
|
|
int mac_code;
|
|
};
|
|
|
|
static TransKey qtKeyToChar[] = {
|
|
{Qt::Key_Escape, kEscapeCharCode},
|
|
{Qt::Key_Tab, kTabCharCode},
|
|
{Qt::Key_Backtab, kTabCharCode}, // Backtab == tab with different modifiers
|
|
{Qt::Key_Backspace, kBackspaceCharCode},
|
|
{Qt::Key_Return, kReturnCharCode},
|
|
{Qt::Key_Enter, kEnterCharCode},
|
|
// Insert
|
|
{Qt::Key_Delete, kDeleteCharCode},
|
|
// Pause, Print, SysReq
|
|
{Qt::Key_Clear, kClearCharCode},
|
|
{Qt::Key_Home, kHomeCharCode},
|
|
{Qt::Key_End, kEndCharCode},
|
|
{Qt::Key_Left, kLeftArrowCharCode},
|
|
{Qt::Key_Up, kUpArrowCharCode},
|
|
{Qt::Key_Right, kRightArrowCharCode},
|
|
{Qt::Key_Down, kDownArrowCharCode},
|
|
{Qt::Key_PageUp, kPageUpCharCode},
|
|
{Qt::Key_PageDown, kPageDownCharCode},
|
|
// Shift, Control, Meta, Alt, CapsLock, NumLock, ScrollLock
|
|
// Super_L, Super_R, Menu, Hyper_L, Hyper_R
|
|
{Qt::Key_Help, kHelpCharCode},
|
|
// Direction_L, Direction_R
|
|
{Qt::Key_nobreakspace, kNonBreakingSpaceCharCode},
|
|
{0, 0}
|
|
};
|
|
|
|
static QMultiMap<int, uint> scancodes;
|
|
static long lastLayoutID = -1;
|
|
#ifdef QT_MAC_USE_COCOA
|
|
static TISInputSourceRef lastLayout = 0;
|
|
#else
|
|
static KeyboardLayoutRef lastLayout = NULL;
|
|
#endif
|
|
|
|
void updateScancodes() {
|
|
#ifdef QT_MAC_USE_COCOA
|
|
TISInputSourceRef layout = TISCopyCurrentKeyboardLayoutInputSource();
|
|
if (!layout) {
|
|
kWarning() << "Error retrieving current layout";
|
|
return;
|
|
}
|
|
if (layout == lastLayout) {
|
|
CFRelease(layout);
|
|
} else {
|
|
// keyboard layout changed
|
|
#ifndef NDEBUG
|
|
const void *name = TISGetInputSourceProperty(layout, kTISPropertyLocalizedName);
|
|
kDebug() << "Layout changed to: " << CFStringGetCStringPtr((CFStringRef)name, 0);
|
|
#endif
|
|
lastLayout = layout;
|
|
scancodes.clear();
|
|
|
|
CFDataRef data = static_cast<CFDataRef>(TISGetInputSourceProperty(layout,
|
|
kTISPropertyUnicodeKeyLayoutData));
|
|
const UCKeyboardLayout *ucData = data ? reinterpret_cast<const UCKeyboardLayout *>(CFDataGetBytePtr(data)) : 0;
|
|
|
|
if (!ucData) {
|
|
kWarning() << "Error retrieving current layout character data";
|
|
return;
|
|
}
|
|
|
|
for (int i = 0; i < 128; ++i) {
|
|
UInt32 tmpState = 0;
|
|
UniChar str[4];
|
|
UniCharCount actualLength = 0;
|
|
OSStatus err = UCKeyTranslate(ucData, i, kUCKeyActionDown, 0, LMGetKbdType(),
|
|
kUCKeyTranslateNoDeadKeysMask, &tmpState, 4, &actualLength, str);
|
|
if (err != noErr) {
|
|
kWarning() << "Error translating unicode key" << err;
|
|
} else {
|
|
if (str[0] && str[0] != kFunctionKeyCharCode)
|
|
scancodes.insert(str[0], i);
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
KeyboardLayoutRef layout;
|
|
if (KLGetCurrentKeyboardLayout(&layout) != noErr) {
|
|
kWarning() << "Error retrieving current layout";
|
|
}
|
|
if (layout != lastLayout) {
|
|
#ifndef NDEBUG
|
|
void *name;
|
|
KLGetKeyboardLayoutProperty(layout, kKLName, const_cast<const void**>(&name));
|
|
kDebug() << "Layout changed to: " << CFStringGetCStringPtr((CFStringRef) name, 0);
|
|
#endif
|
|
lastLayout = layout;
|
|
scancodes.clear();
|
|
void *kchr;
|
|
if (KLGetKeyboardLayoutProperty(layout, kKLKCHRData, const_cast<const void**>(&kchr)) != noErr) {
|
|
kWarning() << "Couldn't load active keyboard layout";
|
|
} else {
|
|
for (int i = 0; i < 128; i++) {
|
|
UInt32 tmpState = 0;
|
|
UInt32 chr = KeyTranslate(kchr, i, &tmpState);
|
|
if (chr && chr != kFunctionKeyCharCode) {
|
|
scancodes.insert(chr, i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#define SCANCODE(name, value) { Qt::Key_ ## name, value }
|
|
static TransKey functionKeys[] = {
|
|
SCANCODE(F1, 122),
|
|
SCANCODE(F2, 120),
|
|
SCANCODE(F3, 99),
|
|
SCANCODE(F4, 118),
|
|
SCANCODE(F5, 96),
|
|
SCANCODE(F6, 97),
|
|
SCANCODE(F7, 98),
|
|
SCANCODE(F8, 100),
|
|
SCANCODE(F9, 101),
|
|
SCANCODE(F10, 109),
|
|
//TODO: figure out scancodes of other F* keys
|
|
{ 0, 0 }
|
|
};
|
|
#undef SCANCODE
|
|
|
|
bool keyQtToSymMac( int keyQt, int& sym )
|
|
{
|
|
// Printable ascii values, before A
|
|
if (keyQt >= 0x20 && keyQt < Qt::Key_A) {
|
|
sym = keyQt;
|
|
return true;
|
|
}
|
|
// Letters, return lower-case equivalent
|
|
if (keyQt >= Qt::Key_A && keyQt <= Qt::Key_Z) {
|
|
sym = keyQt - Qt::Key_A + 'a';
|
|
return true;
|
|
}
|
|
// Printable ascii values up to lower-case a
|
|
if (keyQt > Qt::Key_Z && keyQt <= 0x60) {
|
|
sym = keyQt;
|
|
return true;
|
|
}
|
|
// Remainder of printable ascii values
|
|
if (keyQt >= 0x7B && keyQt < 0x7F) {
|
|
sym = keyQt;
|
|
return true;
|
|
}
|
|
// Function keys
|
|
if (keyQt >= Qt::Key_F1 && keyQt <= Qt::Key_F35) {
|
|
sym = kFunctionKeyCharCode;
|
|
return true;
|
|
}
|
|
// Try to find in lookup table
|
|
for (int i = 0; qtKeyToChar[i].qt_code; i++) {
|
|
if (qtKeyToChar[i].qt_code == keyQt) {
|
|
sym = qtKeyToChar[i].mac_code;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Not found
|
|
return false;
|
|
}
|
|
|
|
bool keyQtToCodeMac( int keyQt, QList<uint>& keyCodes )
|
|
{
|
|
updateScancodes();
|
|
keyCodes.clear();
|
|
keyQt &= ~Qt::KeyboardModifierMask;
|
|
int chr;
|
|
if (!keyQtToSymMac( keyQt, chr ) ) return false;
|
|
|
|
if (chr == kFunctionKeyCharCode) {
|
|
for (int i = 0; functionKeys[i].qt_code; i++) {
|
|
if (functionKeys[i].qt_code == keyQt) {
|
|
keyCodes.append(functionKeys[i].mac_code);
|
|
}
|
|
}
|
|
} else {
|
|
keyCodes += scancodes.values(chr);
|
|
}
|
|
|
|
return keyCodes.count() > 0;
|
|
}
|
|
|
|
bool keyQtToModMac( int keyQt, uint& mod )
|
|
{
|
|
mod = 0;
|
|
if (keyQt & Qt::ShiftModifier) {
|
|
mod |= shiftKey;
|
|
}
|
|
if (keyQt & Qt::ControlModifier) {
|
|
mod |= cmdKey;
|
|
}
|
|
if (keyQt & Qt::AltModifier) {
|
|
mod |= optionKey;
|
|
}
|
|
if (keyQt & Qt::MetaModifier) {
|
|
mod |= controlKey;
|
|
}
|
|
if (keyQt & Qt::KeypadModifier) {
|
|
mod |= kEventKeyModifierNumLockMask;
|
|
}
|
|
// Special case for Qt::Key_Backtab
|
|
if ((keyQt & ~Qt::KeyboardModifierMask) == Qt::Key_Backtab) {
|
|
mod |= shiftKey;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
} // end of namespace KKeyServer
|
|
|
|
#endif // Q_WS_MACX
|
|
|