summaryrefslogtreecommitdiffstats
path: root/src/lib/platform/OSXKeyState.h
blob: e688394cf33499a32d6854116e29615722ae0e0b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
/*
 * barrier -- mouse and keyboard sharing utility
 * Copyright (C) 2012-2016 Symless Ltd.
 * Copyright (C) 2004 Chris Schoeneman
 *
 * This package is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * found in the file LICENSE that should have accompanied this file.
 *
 * This package 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include "barrier/KeyState.h"
#include "common/stdmap.h"
#include "common/stdset.h"
#include "common/stdvector.h"

#include <Carbon/Carbon.h>

typedef TISInputSourceRef KeyLayout;
class IOSXKeyResource;

//! OS X key state
/*!
A key state for OS X.
*/
class OSXKeyState : public KeyState {
public:
    typedef std::vector<KeyID> KeyIDs;

    OSXKeyState(IEventQueue* events);
    OSXKeyState(IEventQueue* events, barrier::KeyMap& keyMap);
    virtual ~OSXKeyState();

    //! @name modifiers
    //@{

    //! Handle modifier key change
    /*!
    Determines which modifier keys have changed and updates the modifier
    state and sends key events as appropriate.
    */
    void                handleModifierKeys(void* target,
                            KeyModifierMask oldMask, KeyModifierMask newMask);

    //@}
    //! @name accessors
    //@{

    //! Convert OS X modifier mask to barrier mask
    /*!
    Returns the barrier modifier mask corresponding to the OS X modifier
    mask in \p mask.
    */
    KeyModifierMask        mapModifiersFromOSX(UInt32 mask) const;

    //! Convert CG flags-style modifier mask to old-style Carbon
    /*!
    Still required in a few places for translation calls.
    */
    KeyModifierMask        mapModifiersToCarbon(UInt32 mask) const;

    //! Map key event to keys
    /*!
    Converts a key event into a sequence of KeyIDs and the shadow modifier
    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.
    */
    KeyButton            mapKeyFromEvent(KeyIDs& ids,
                            KeyModifierMask* maskOut, CGEventRef event) const;

    //! Map key and mask to native values
    /*!
    Calculates mac virtual key and mask for a key \p key and modifiers
    \p mask.  Returns \c true if the key can be mapped, \c false otherwise.
    */
    bool                mapBarrierHotKeyToMac(KeyID key, KeyModifierMask mask,
                            UInt32& macVirtualKey,
                            UInt32& macModifierMask) const;

    //@}

    // IKeyState overrides
    virtual bool        fakeCtrlAltDel();
    virtual bool        fakeMediaKey(KeyID id);
    virtual KeyModifierMask
                        pollActiveModifiers() const;
    virtual SInt32        pollActiveGroup() const;
    virtual void        pollPressedKeys(KeyButtonSet& pressedKeys) const;

    CGEventFlags getModifierStateAsOSXFlags();
protected:
    // KeyState overrides
    virtual void        getKeyMap(barrier::KeyMap& keyMap);
    virtual void        fakeKey(const Keystroke& keystroke);

private:
    class KeyResource;
    typedef std::vector<KeyLayout> GroupList;

    // Add hard coded special keys to a barrier::KeyMap.
    void                getKeyMapForSpecialKeys(
                            barrier::KeyMap& keyMap, SInt32 group) const;

    // Convert keyboard resource to a key map
    bool                getKeyMap(barrier::KeyMap& keyMap,
                            SInt32 group, const IOSXKeyResource& r) const;

    // Get the available keyboard groups
    bool                getGroups(GroupList&) const;

    // Change active keyboard group to group
    void                setGroup(SInt32 group);

    // Check if the keyboard layout has changed and update keyboard state
    // if so.
    void                checkKeyboardLayout();

    // Send an event for the given modifier key
    void                handleModifierKey(void* target,
                            UInt32 virtualKey, KeyID id,
                            bool down, KeyModifierMask newMask);

    // Checks if any in \p ids is a glyph key and if \p isCommand is false.
    // If so it adds the AltGr modifier to \p mask.  This allows OS X
    // servers to use the option key both as AltGr and as a modifier.  If
    // option is acting as AltGr (i.e. it generates a glyph and there are
    // no command modifiers active) then we don't send the super modifier
    // to clients because they'd try to match it as a command modifier.
    void                adjustAltGrModifier(const KeyIDs& ids,
                            KeyModifierMask* mask, bool isCommand) 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);

    void                init();

    // Post a key event to HID manager. It posts an event to HID client, a
    // much lower level than window manager which's the target from carbon
    // CGEventPost
    void                postHIDVirtualKey(const UInt8 virtualKeyCode,
                            const bool postDown);

private:
    // OS X uses a physical key if 0 for the 'A' key.  barrier 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
    };

    typedef std::map<CFDataRef, SInt32> GroupMap;
    typedef std::map<UInt32, KeyID> VirtualKeyMap;

    VirtualKeyMap        m_virtualKeyMap;
    mutable UInt32        m_deadKeyState;
    GroupList            m_groups;
    GroupMap            m_groupMap;
    bool                m_shiftPressed;
    bool                m_controlPressed;
    bool                m_altPressed;
    bool                m_superPressed;
    bool                m_capsPressed;
};