1 /*
2  * synergy -- mouse and keyboard sharing utility
3  * Copyright (C) 2012-2016 Symless Ltd.
4  * Copyright (C) 2004 Chris Schoeneman
5  *
6  * This package is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * found in the file LICENSE that should have accompanied this file.
9  *
10  * This package is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #pragma once
20 
21 #include "synergy/KeyState.h"
22 #include "common/stdmap.h"
23 #include "common/stdset.h"
24 #include "common/stdvector.h"
25 
26 #include <Carbon/Carbon.h>
27 
28 class IOSXKeyResource;
29 
30 
31 //! OS X key state
32 /*!
33 A key state for OS X.
34 */
35 class OSXKeyState : public KeyState {
36 public:
37     typedef std::vector<KeyID> KeyIDs;
38 
39     OSXKeyState(IEventQueue* events);
40     OSXKeyState(IEventQueue* events, synergy::KeyMap& keyMap);
41     virtual ~OSXKeyState();
42 
43     //! @name modifiers
44     //@{
45 
46     //! Handle modifier key change
47     /*!
48     Determines which modifier keys have changed and updates the modifier
49     state and sends key events as appropriate.
50     */
51     void                handleModifierKeys(void* target,
52                             KeyModifierMask oldMask, KeyModifierMask newMask);
53 
54     //@}
55     //! @name accessors
56     //@{
57 
58     //! Convert OS X modifier mask to synergy mask
59     /*!
60     Returns the synergy modifier mask corresponding to the OS X modifier
61     mask in \p mask.
62     */
63     KeyModifierMask        mapModifiersFromOSX(UInt32 mask) const;
64 
65     //! Convert CG flags-style modifier mask to old-style Carbon
66     /*!
67     Still required in a few places for translation calls.
68     */
69     KeyModifierMask        mapModifiersToCarbon(UInt32 mask) const;
70 
71     //! Map key event to keys
72     /*!
73     Converts a key event into a sequence of KeyIDs and the shadow modifier
74     state to a modifier mask.  The KeyIDs list, in order, the characters
75     generated by the key press/release.  It returns the id of the button
76     that was pressed or released, or 0 if the button doesn't map to a known
77     KeyID.
78     */
79     KeyButton            mapKeyFromEvent(KeyIDs& ids,
80                             KeyModifierMask* maskOut, CGEventRef event) const;
81 
82     //! Map key and mask to native values
83     /*!
84     Calculates mac virtual key and mask for a key \p key and modifiers
85     \p mask.  Returns \c true if the key can be mapped, \c false otherwise.
86     */
87     bool                mapSynergyHotKeyToMac(KeyID key, KeyModifierMask mask,
88                             UInt32& macVirtualKey,
89                             UInt32& macModifierMask) const;
90 
91     //@}
92 
93     // IKeyState overrides
94     virtual bool        fakeCtrlAltDel();
95     virtual bool        fakeMediaKey(KeyID id);
96     virtual KeyModifierMask
97                         pollActiveModifiers() const;
98     virtual SInt32        pollActiveGroup() const;
99     virtual void        pollPressedKeys(KeyButtonSet& pressedKeys) const;
100 
101     CGEventFlags getModifierStateAsOSXFlags();
102 protected:
103     // KeyState overrides
104     virtual void        getKeyMap(synergy::KeyMap& keyMap);
105     virtual void        fakeKey(const Keystroke& keystroke);
106 
107 private:
108     class KeyResource;
109     typedef void(*CFDeallocator)(CFTypeRef);
110     typedef std::unique_ptr<const __CFArray, CFDeallocator> GroupList;
111     typedef std::unique_ptr<const __CFDictionary, CFDeallocator> AutoCFDictionary;
112     typedef std::unique_ptr<__TISInputSource, CFDeallocator> AutoTISInputSourceRef;
113 
114 
115     // Add hard coded special keys to a synergy::KeyMap.
116     void                getKeyMapForSpecialKeys(
117                             synergy::KeyMap& keyMap, SInt32 group) const;
118 
119     // Convert keyboard resource to a key map
120     bool                getKeyMap(synergy::KeyMap& keyMap,
121                             SInt32 group, const IOSXKeyResource& r) const;
122 
123     // Get the available keyboard groups
124     bool                getGroups(GroupList&) const;
125 
126     // Change active keyboard group to group
127     void                setGroup(SInt32 group);
128 
129     // Send an event for the given modifier key
130     void                handleModifierKey(void* target,
131                             UInt32 virtualKey, KeyID id,
132                             bool down, KeyModifierMask newMask);
133 
134     // Checks if any in \p ids is a glyph key and if \p isCommand is false.
135     // If so it adds the AltGr modifier to \p mask.  This allows OS X
136     // servers to use the option key both as AltGr and as a modifier.  If
137     // option is acting as AltGr (i.e. it generates a glyph and there are
138     // no command modifiers active) then we don't send the super modifier
139     // to clients because they'd try to match it as a command modifier.
140     void                adjustAltGrModifier(const KeyIDs& ids,
141                             KeyModifierMask* mask, bool isCommand) const;
142 
143     // Maps an OS X virtual key id to a KeyButton.  This simply remaps
144     // the ids so we don't use KeyButton 0.
145     static KeyButton    mapVirtualKeyToKeyButton(UInt32 keyCode);
146 
147     // Maps a KeyButton to an OS X key code.  This is the inverse of
148     // mapVirtualKeyToKeyButton.
149     static UInt32        mapKeyButtonToVirtualKey(KeyButton keyButton);
150 
151     void                init();
152 
153     // Post a key event to HID manager. It posts an event to HID client, a
154     // much lower level than window manager which's the target from carbon
155     // CGEventPost
156     void                postHIDVirtualKey(const UInt8 virtualKeyCode,
157                             const bool postDown);
158 
159 private:
160     // OS X uses a physical key if 0 for the 'A' key.  synergy reserves
161     // KeyButton 0 so we offset all OS X physical key ids by this much
162     // when used as a KeyButton and by minus this much to map a KeyButton
163     // to a physical button.
164     enum {
165         KeyButtonOffset = 1
166     };
167 
168     typedef std::map<CFDataRef, SInt32> GroupMap;
169     typedef std::map<UInt32, KeyID> VirtualKeyMap;
170 
171     VirtualKeyMap        m_virtualKeyMap;
172     mutable UInt32        m_deadKeyState;
173     GroupList           m_groups{nullptr, CFRelease};
174     GroupMap            m_groupMap;
175     bool                m_shiftPressed;
176     bool                m_controlPressed;
177     bool                m_altPressed;
178     bool                m_superPressed;
179     bool                m_capsPressed;
180 };
181