Made OS X key mapping dynamic based on current key layout. It

now includes full support for dead keys and non-ascii glyph keys.
This commit is contained in:
crs 2004-10-24 18:15:33 +00:00
parent 13a0f8671f
commit 9f6c8f937a
3 changed files with 592 additions and 504 deletions

File diff suppressed because it is too large Load Diff

View File

@ -17,6 +17,7 @@
#include "CKeyState.h" #include "CKeyState.h"
#include "stdmap.h" #include "stdmap.h"
#include "stdvector.h"
#include <Carbon/Carbon.h> #include <Carbon/Carbon.h>
//! OS X key state //! OS X key state
@ -25,38 +26,21 @@ A key state for OS X.
*/ */
class COSXKeyState : public CKeyState { class COSXKeyState : public CKeyState {
public: public:
// OS X uses a physical key if 0 for the 'A' key. synergy reserves typedef std::vector<KeyID> CKeyIDs;
// KeyButton 0 so we offset all OS X physical key ids by this much
// when used as a KeyButton and by minus this much to map a KeyButton
// to a physical button.
enum {
KeyButtonOffset = 1
};
COSXKeyState(); COSXKeyState();
virtual ~COSXKeyState(); virtual ~COSXKeyState();
//! Map physical key id to a KeyButton id //! Map key event to keys
/*! /*!
Maps an OS X key code to a KeyButton. This simply remaps the ids Converts a key event into a sequence of KeyIDs and the shadow modifier
so we don't use KeyButton 0. state to a modifier mask. The KeyIDs list, in order, the characters
generated by the key press/release. It returns the id of the button
that was pressed or released, or 0 if the button doesn't map to a known
KeyID.
*/ */
static KeyButton mapKeyCodeToKeyButton(UInt32 keyCode); KeyButton mapKeyFromEvent(CKeyIDs& ids,
KeyModifierMask* maskOut, EventRef event) const;
//! Map KeyButton id to a physical key id
/*!
Maps a KeyButton to an OS X key code. This is the inverse of
mapKeyCodeToKeyButton.
*/
static UInt32 mapKeyButtonToKeyCode(KeyButton keyButton);
//! Map key event to a key
/*!
Converts a key event into a KeyID and the shadow modifier state
to a modifier mask.
*/
KeyID mapKeyFromEvent(EventRef event,
KeyModifierMask* maskOut) const;
//! Handle modifier key change //! Handle modifier key change
/*! /*!
@ -85,18 +69,91 @@ protected:
bool isAutoRepeat) const; bool isAutoRepeat) const;
private: private:
typedef std::vector<std::pair<KeyButton, KeyModifierMask> > CKeySequence;
typedef std::map<KeyID, CKeySequence> CKeyIDMap;
typedef std::map<UInt32, KeyID> CVirtualKeyMap;
KeyButton addKeystrokes(Keystrokes& keys,
KeyButton keyButton,
KeyModifierMask desiredMask,
KeyModifierMask requiredMask,
bool isAutoRepeat) const;
bool adjustModifiers(Keystrokes& keys, bool adjustModifiers(Keystrokes& keys,
Keystrokes& undo, Keystrokes& undo,
KeyModifierMask desiredMask) const; KeyModifierMask desiredMask,
KeyModifierMask requiredMask) const;
void addKeyButton(KeyButtons& keys, KeyID id) const; void addKeyButton(KeyButtons& keys, KeyID id) const;
void handleModifierKey(void* target, KeyID id, bool down); void handleModifierKey(void* target, KeyID id, bool down);
// Check if the keyboard layout has changed and call doUpdateKeys
// if so.
void checkKeyboardLayout();
// Switch to a new keyboard layout.
void setKeyboardLayout(SInt16 keyboardLayoutID);
// Insert KeyID to key sequences for non-printing characters, like
// delete, home, up arrow, etc. and the virtual key to KeyID mapping.
void fillSpecialKeys(CKeyIDMap& keyMap,
CVirtualKeyMap& virtualKeyMap) const;
// Convert the KCHR resource to a KeyID to key sequence map. the
// map maps each KeyID to the sequence of keys (with modifiers)
// that would have to be synthesized to generate the KeyID character.
// Returns false iff no KCHR resource was found.
bool fillKCHRKeysMap(CKeyIDMap& keyMap) const;
// Convert the uchr resource to a KeyID to key sequence map. the
// map maps each KeyID to the sequence of keys (with modifiers)
// that would have to be synthesized to generate the KeyID character.
// Returns false iff no uchr resource was found.
bool filluchrKeysMap(CKeyIDMap& keyMap) const;
// Maps an OS X virtual key id to a KeyButton. This simply remaps
// the ids so we don't use KeyButton 0.
static KeyButton mapVirtualKeyToKeyButton(UInt32 keyCode);
// Maps a KeyButton to an OS X key code. This is the inverse of
// mapVirtualKeyToKeyButton.
static UInt32 mapKeyButtonToVirtualKey(KeyButton keyButton);
// Convert a character in the current script to the equivalent KeyID.
static KeyID charToKeyID(UInt8);
// Convert a unicode character to the equivalent KeyID.
static KeyID unicharToKeyID(UniChar);
// Choose the modifier mask with the fewest modifiers for character
// mapping table i.
static KeyModifierMask
maskForTable(UInt8 i, UInt8* tableSelectors);
private: private:
typedef std::map<KeyID, KeyButton> CKeyMap; // OS X uses a physical key if 0 for the 'A' key. synergy reserves
// KeyButton 0 so we offset all OS X physical key ids by this much
// when used as a KeyButton and by minus this much to map a KeyButton
// to a physical button.
enum {
KeyButtonOffset = 1
};
CKeyMap m_keyMap; // KCHR resource header
struct CKCHRResource {
public:
SInt16 m_version;
UInt8 m_tableSelectionIndex[256];
SInt16 m_numTables;
UInt8 m_characterTables[1][128];
};
static const KeyID s_virtualKey[]; SInt16 m_keyboardLayoutID;
mutable UInt32 m_deadKeyState;
Handle m_KCHRHandle;
Handle m_uchrHandle;
CKCHRResource* m_KCHRResource;
UCKeyboardLayout* m_uchrResource;
CKeyIDMap m_keyMap;
CVirtualKeyMap m_virtualKeyMap;
}; };
#endif #endif

View File

@ -808,16 +808,15 @@ COSXScreen::onKey(EventRef event) const
UInt32 eventKind = GetEventKind(event); UInt32 eventKind = GetEventKind(event);
// get the key // get the key
UInt32 keyCode; UInt32 virtualKey;
GetEventParameter(event, kEventParamKeyCode, typeUInt32, GetEventParameter(event, kEventParamKeyCode, typeUInt32,
NULL, sizeof(keyCode), NULL, &keyCode); NULL, sizeof(virtualKey), NULL, &virtualKey);
LOG((CLOG_DEBUG1 "event: Key event kind: %d, keycode=%d", eventKind, keyCode)); LOG((CLOG_DEBUG1 "event: Key event kind: %d, keycode=%d", eventKind, virtualKey));
KeyButton button = COSXKeyState::mapKeyCodeToKeyButton(keyCode);
// sadly, OS X doesn't report the keyCode for modifier keys. keyCode // sadly, OS X doesn't report the virtualKey for modifier keys.
// will be zero for modifier keys. since that's not good enough we'll // virtualKey will be zero for modifier keys. since that's not good
// have to figure out what the key was. // enough we'll have to figure out what the key was.
if (keyCode == 0 && eventKind == kEventRawKeyModifiersChanged) { if (virtualKey == 0 && eventKind == kEventRawKeyModifiersChanged) {
// get old and new modifier state // get old and new modifier state
KeyModifierMask oldMask = getActiveModifiers(); KeyModifierMask oldMask = getActiveModifiers();
KeyModifierMask newMask = mapMacModifiersToSynergy(event); KeyModifierMask newMask = mapMacModifiersToSynergy(event);
@ -825,22 +824,37 @@ COSXScreen::onKey(EventRef event) const
return true; return true;
} }
// decode event type
bool down = (eventKind == kEventRawKeyDown); bool down = (eventKind == kEventRawKeyDown);
bool up = (eventKind == kEventRawKeyUp); bool up = (eventKind == kEventRawKeyUp);
bool isRepeat = (eventKind == kEventRawKeyRepeat); bool isRepeat = (eventKind == kEventRawKeyRepeat);
// map event to keys
KeyModifierMask mask;
COSXKeyState::CKeyIDs keys;
KeyButton button = m_keyState->mapKeyFromEvent(keys, &mask, event);
if (button == 0) {
return false;
}
// update button state
if (down) { if (down) {
m_keyState->setKeyDown(button, true); m_keyState->setKeyDown(button, true);
} }
else if (up) { else if (up) {
if (!isKeyDown(button)) {
// up event for a dead key. throw it away.
return false;
}
m_keyState->setKeyDown(button, false); m_keyState->setKeyDown(button, false);
} }
KeyModifierMask mask; // send key events
KeyID key = m_keyState->mapKeyFromEvent(event, &mask); for (COSXKeyState::CKeyIDs::const_iterator i = keys.begin();
i != keys.end(); ++i) {
m_keyState->sendKeyEvent(getEventTarget(), down, isRepeat, m_keyState->sendKeyEvent(getEventTarget(), down, isRepeat,
key, mask, 1, button); *i, mask, 1, button);
}
return true; return true;
} }