1 /*
2  * barrier -- mouse and keyboard sharing utility
3  * Copyright (C) 2012-2016 Symless Ltd.
4  * Copyright (C) 2005 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 "barrier/key_types.h"
22 #include "base/String.h"
23 #include "common/stdmap.h"
24 #include "common/stdset.h"
25 #include "common/stdvector.h"
26 
27 namespace barrier {
28 
29 //! Key map
30 /*!
31 This class provides a keyboard mapping.
32 */
33 class KeyMap {
34 public:
35     KeyMap();
36     virtual ~KeyMap();
37 
38     //! KeyID synthesis info
39     /*!
40     This structure contains the information necessary to synthesize a
41     keystroke that generates a KeyID (stored elsewhere).  \c m_sensitive
42     lists the modifiers that the key is affected by and must therefore
43     be in the correct state, which is listed in \c m_required.  If the
44     key is mapped to a modifier, that modifier is in \c m_generates and
45     is not in \c m_sensitive.
46     */
47     struct KeyItem {
48     public:
49         KeyID            m_id;            //!< KeyID
50         SInt32            m_group;        //!< Group for key
51         KeyButton        m_button;        //!< Button to generate KeyID
52         KeyModifierMask    m_required;        //!< Modifiers required for KeyID
53         KeyModifierMask    m_sensitive;    //!< Modifiers key is sensitive to
54         KeyModifierMask    m_generates;    //!< Modifiers key is mapped to
55         bool            m_dead;            //!< \c true if this is a dead KeyID
56         bool            m_lock;            //!< \c true if this locks a modifier
57         UInt32            m_client;        //!< Client data
58 
59     public:
60         bool            operator==(const KeyItem&) const;
61     };
62 
63     //! The KeyButtons needed to synthesize a KeyID
64     /*!
65     An ordered list of \c KeyItems produces a particular KeyID.  If
66     the KeyID can be synthesized directly then there is one entry in
67     the list.  If dead keys are required then they're listed first.
68     A list is the minimal set of keystrokes necessary to synthesize
69     the KeyID, so it doesn't include no-ops.  A list does not include
70     any modifier keys unless the KeyID is a modifier, in which case
71     it has exactly one KeyItem for the modifier itself.
72     */
73     typedef std::vector<KeyItem> KeyItemList;
74 
75     //! A keystroke
76     class Keystroke {
77     public:
78         enum EType {
79             kButton,                    //!< Synthesize button
80             kGroup                        //!< Set new group
81         };
82 
83         Keystroke(KeyButton, bool press, bool repeat, UInt32 clientData);
84         Keystroke(SInt32 group, bool absolute, bool restore);
85 
86     public:
87         struct Button {
88         public:
89             KeyButton    m_button;        //!< Button to synthesize
90             bool        m_press;        //!< \c true iff press
91             bool        m_repeat;        //!< \c true iff for an autorepeat
92             UInt32        m_client;        //!< Client data
93         };
94         struct Group {
95         public:
96             SInt32        m_group;        //!< Group/offset to change to/by
97             bool        m_absolute;        //!< \c true iff change to, else by
98             bool        m_restore;        //!< \c true iff for restoring state
99         };
100         union Data {
101         public:
102             Button        m_button;
103             Group        m_group;
104         };
105 
106         EType            m_type;
107         Data            m_data;
108     };
109 
110     //! A sequence of keystrokes
111     typedef std::vector<Keystroke> Keystrokes;
112 
113     //! A mapping of a modifier to keys for that modifier
114     typedef std::multimap<KeyModifierMask, KeyItem> ModifierToKeys;
115 
116     //! A set of buttons
117     typedef std::map<KeyButton, const KeyItem*> ButtonToKeyMap;
118 
119     //! Callback type for \c foreachKey
120     typedef void (*ForeachKeyCallback)(KeyID, SInt32 group,
121                             KeyItem&, void* userData);
122 
123     //! @name manipulators
124     //@{
125 
126     //! Swap with another \c KeyMap
127     virtual void        swap(KeyMap&);
128 
129     //! Add a key entry
130     /*!
131     Adds \p item to the entries for the item's id and group.  The
132     \c m_dead member is set automatically.
133     */
134     void                addKeyEntry(const KeyItem& item);
135 
136     //! Add an alias key entry
137     /*!
138     If \p targetID with the modifiers given by \p targetRequired and
139     \p targetSensitive is not available in group \p group then find an
140     entry for \p sourceID with modifiers given by \p sourceRequired and
141     \p sourceSensitive in any group with exactly one item and, if found,
142     add a new item just like it except using id \p targetID.  This
143     effectively makes the \p sourceID an alias for \p targetID (i.e. we
144     can generate \p targetID using \p sourceID).
145     */
146     void                addKeyAliasEntry(KeyID targetID, SInt32 group,
147                             KeyModifierMask targetRequired,
148                             KeyModifierMask targetSensitive,
149                             KeyID sourceID,
150                             KeyModifierMask sourceRequired,
151                             KeyModifierMask sourceSensitive);
152 
153     //! Add a key sequence entry
154     /*!
155     Adds the sequence of keys \p keys (\p numKeys elements long) to
156     synthesize key \p id in group \p group.  This looks up in the
157     map each key in \p keys.  If all are found then each key is
158     converted to the button for that key and the buttons are added
159     as the entry for \p id.  If \p id is already in the map or at
160     least one key in \p keys is not in the map then nothing is added
161     and this returns \c false, otherwise it returns \c true.
162     */
163     bool                addKeyCombinationEntry(KeyID id, SInt32 group,
164                             const KeyID* keys, UInt32 numKeys);
165 
166     //! Enable composition across groups
167     /*!
168     If called then the keyboard map will allow switching between groups
169     during key composition.  Not all systems allow that.
170     */
171     void                allowGroupSwitchDuringCompose();
172 
173     //! Add a half-duplex button
174     /*!
175     Records that button \p button is a half-duplex key.  This is called
176     when translating the system's keyboard map.  It's independent of the
177     half-duplex modifier calls.
178     */
179     void                addHalfDuplexButton(KeyButton button);
180 
181     //! Remove all half-duplex modifiers
182     /*!
183     Removes all half-duplex modifiers.  This is called to set user
184     configurable half-duplex settings.
185     */
186     void                clearHalfDuplexModifiers();
187 
188     //! Add a half-duplex modifier
189     /*!
190     Records that modifier key \p key is half-duplex.  This is called to
191     set user configurable half-duplex settings.
192     */
193     virtual void        addHalfDuplexModifier(KeyID key);
194 
195     //! Finish adding entries
196     /*!
197     Called after adding entries, this does some internal housekeeping.
198     */
199     virtual void        finish();
200 
201     //! Iterate over all added keys items
202     /*!
203     Calls \p cb for every key item.
204     */
205     virtual void        foreachKey(ForeachKeyCallback cb, void* userData);
206 
207     //@}
208     //! @name accessors
209     //@{
210 
211     //! Map key press/repeat to keystrokes.
212     /*!
213     Converts press/repeat of key \p id in group \p group with current
214     modifiers as given in \p currentState and the desired modifiers in
215     \p desiredMask into the keystrokes necessary to synthesize that key
216     event in \p keys.  It returns the \c KeyItem of the key being
217     pressed/repeated, or NULL if the key cannot be mapped.
218     */
219     virtual const KeyItem*    mapKey(Keystrokes& keys, KeyID id, SInt32 group,
220                             ModifierToKeys& activeModifiers,
221                             KeyModifierMask& currentState,
222                             KeyModifierMask desiredMask,
223                             bool isAutoRepeat) const;
224 
225     //! Get number of groups
226     /*!
227     Returns the number of keyboard groups (independent layouts) in the map.
228     */
229     SInt32                getNumGroups() const;
230 
231     //! Compute a group number
232     /*!
233     Returns the number of the group \p offset groups after group \p group.
234     */
235     SInt32                getEffectiveGroup(SInt32 group, SInt32 offset) const;
236 
237     //! Find key entry compatible with modifiers
238     /*!
239     Returns the \c KeyItemList for the first entry for \p id in group
240     \p group that is compatible with the given modifiers, or NULL
241     if there isn't one.  A button list is compatible with a modifiers
242     if it is either insensitive to all modifiers in \p sensitive or
243     it requires the modifiers to be in the state indicated by \p required
244     for every modifier indicated by \p sensitive.
245     */
246     const KeyItemList*    findCompatibleKey(KeyID id, SInt32 group,
247                             KeyModifierMask required,
248                             KeyModifierMask sensitive) const;
249 
250     //! Test if modifier is half-duplex
251     /*!
252     Returns \c true iff modifier key \p key or button \p button is
253     half-duplex.
254     */
255     virtual bool        isHalfDuplex(KeyID key, KeyButton button) const;
256 
257     //! Test if modifiers indicate a command
258     /*!
259     Returns \c true iff the modifiers in \p mask contain any command
260     modifiers.  A command modifier is used for keyboard shortcuts and
261     hotkeys,  Rather than trying to synthesize a character, a command
262     is trying to synthesize a particular set of buttons.  So it's not
263     important to match the shift or AltGr state to achieve a character
264     but it is important to match the modifier state exactly.
265     */
266     bool                isCommand(KeyModifierMask mask) const;
267 
268     // Get the modifiers that indicate a command
269     /*!
270     Returns the modifiers that when combined with other keys indicate
271     a command (e.g. shortcut or hotkey).
272     */
273     KeyModifierMask        getCommandModifiers() const;
274 
275     //! Get buttons from modifier map
276     /*!
277     Put all the keys in \p modifiers into \p keys.
278     */
279     static void            collectButtons(const ModifierToKeys& modifiers,
280                             ButtonToKeyMap& keys);
281 
282     //! Set modifier key state
283     /*!
284     Sets the modifier key state (\c m_generates and \c m_lock) in \p item
285     based on the \c m_id in \p item.
286     */
287     static void            initModifierKey(KeyItem& item);
288 
289     //! Test for a dead key
290     /*!
291     Returns \c true if \p key is a dead key.
292     */
293     static bool            isDeadKey(KeyID key);
294 
295     //! Get corresponding dead key
296     /*!
297     Returns the dead key corresponding to \p key if one exists, otherwise
298     return \c kKeyNone.  This returns \p key if it's already a dead key.
299     */
300     static KeyID        getDeadKey(KeyID key);
301 
302     //! Get string for a key and modifier mask
303     /*!
304     Converts a key and modifier mask into a string representing the
305     combination.
306     */
307     static String        formatKey(KeyID key, KeyModifierMask);
308 
309     //! Parse a string into a key
310     /*!
311     Converts a string into a key.  Returns \c true on success and \c false
312     if the string cannot be parsed.
313     */
314     static bool            parseKey(const String&, KeyID&);
315 
316     //! Parse a string into a modifier mask
317     /*!
318     Converts a string into a modifier mask.  Returns \c true on success
319     and \c false if the string cannot be parsed.  The modifiers plus any
320     remaining leading and trailing whitespace is stripped from the input
321     string.
322     */
323     static bool            parseModifiers(String&, KeyModifierMask&);
324 
325     //@}
326 
327 private:
328     //! Ways to synthesize a key
329     enum EKeystroke {
330         kKeystrokePress,        //!< Synthesize a press
331         kKeystrokeRelease,        //!< Synthesize a release
332         kKeystrokeRepeat,        //!< Synthesize an autorepeat
333         kKeystrokeClick,        //!< Synthesize a press and release
334         kKeystrokeModify,        //!< Synthesize pressing a modifier
335         kKeystrokeUnmodify        //!< Synthesize releasing a modifier
336     };
337 
338     // A list of ways to synthesize a KeyID
339     typedef std::vector<KeyItemList> KeyEntryList;
340 
341     // computes the number of groups
342     SInt32                findNumGroups() const;
343 
344     // computes the map of modifiers to the keys that generate the modifiers
345     void                setModifierKeys();
346 
347     // maps a command key.  a command key is a keyboard shortcut and we're
348     // trying to synthesize a button press with an exact sets of modifiers,
349     // not trying to synthesize a character.  so we just need to find the
350     // right button and synthesize the requested modifiers without regard
351     // to what character they would synthesize.  we disallow multikey
352     // entries since they don't make sense as hotkeys.
353     const KeyItem*        mapCommandKey(Keystrokes& keys,
354                             KeyID id, SInt32 group,
355                             ModifierToKeys& activeModifiers,
356                             KeyModifierMask& currentState,
357                             KeyModifierMask desiredMask,
358                             bool isAutoRepeat) const;
359 
360     // maps a character key.  a character key is trying to synthesize a
361     // particular KeyID and isn't entirely concerned with the modifiers
362     // used to do it.
363     const KeyItem*        mapCharacterKey(Keystrokes& keys,
364                             KeyID id, SInt32 group,
365                             ModifierToKeys& activeModifiers,
366                             KeyModifierMask& currentState,
367                             KeyModifierMask desiredMask,
368                             bool isAutoRepeat) const;
369 
370     // maps a modifier key
371     const KeyItem*        mapModifierKey(Keystrokes& keys,
372                             KeyID id, SInt32 group,
373                             ModifierToKeys& activeModifiers,
374                             KeyModifierMask& currentState,
375                             KeyModifierMask desiredMask,
376                             bool isAutoRepeat) const;
377 
378     // returns the index into \p entryList of the KeyItemList requiring
379     // the fewest modifier changes between \p currentState and
380     // \p desiredState.
381     SInt32                findBestKey(const KeyEntryList& entryList,
382                             KeyModifierMask currentState,
383                             KeyModifierMask desiredState) const;
384 
385     // gets the \c KeyItem used to synthesize the modifier who's bit is
386     // given by \p modifierBit in group \p group and does not synthesize
387     // the key \p button.
388     const KeyItem*        keyForModifier(KeyButton button, SInt32 group,
389                             SInt32 modifierBit) const;
390 
391     // fills \p keystrokes with the keys to synthesize the key in
392     // \p keyItem taking the modifiers into account.  returns \c true
393     // iff successful and sets \p currentState to the
394     // resulting modifier state.
395     bool                keysForKeyItem(const KeyItem& keyItem,
396                             SInt32& group,
397                             ModifierToKeys& activeModifiers,
398                             KeyModifierMask& currentState,
399                             KeyModifierMask desiredState,
400                             KeyModifierMask overrideModifiers,
401                             bool isAutoRepeat,
402                             Keystrokes& keystrokes) const;
403 
404     // fills \p keystrokes with the keys to synthesize the modifiers
405     // in \p desiredModifiers from the active modifiers listed in
406     // \p activeModifiers not including the key in \p keyItem.
407     // returns \c true iff successful.
408     bool                keysToRestoreModifiers(const KeyItem& keyItem,
409                             SInt32 group,
410                             ModifierToKeys& activeModifiers,
411                             KeyModifierMask& currentState,
412                             const ModifierToKeys& desiredModifiers,
413                             Keystrokes& keystrokes) const;
414 
415     // fills \p keystrokes and \p undo with the keys to change the
416     // current modifier state in \p currentState to match the state in
417     // \p requiredState for each modifier indicated in \p sensitiveMask.
418     // returns \c true iff successful and sets \p currentState to the
419     // resulting modifier state.
420     bool                keysForModifierState(KeyButton button, SInt32 group,
421                             ModifierToKeys& activeModifiers,
422                             KeyModifierMask& currentState,
423                             KeyModifierMask requiredState,
424                             KeyModifierMask sensitiveMask,
425                             KeyModifierMask notRequiredMask,
426                             Keystrokes& keystrokes) const;
427 
428     // Adds keystrokes to synthesize key \p keyItem in mode \p type to
429     // \p keystrokes and to undo the synthesis to \p undo.
430     void                addKeystrokes(EKeystroke type,
431                             const KeyItem& keyItem,
432                             ModifierToKeys& activeModifiers,
433                             KeyModifierMask& currentState,
434                             Keystrokes& keystrokes) const;
435 
436     // Returns the number of modifiers indicated in \p state.
437     static SInt32        getNumModifiers(KeyModifierMask state);
438 
439     // Initialize key name/id maps
440     static void            initKeyNameMaps();
441 
442     // not implemented
443     KeyMap(const KeyMap&);
444     KeyMap&            operator=(const KeyMap&);
445 
446 private:
447     // Ways to synthesize a KeyID over multiple keyboard groups
448     typedef std::vector<KeyEntryList> KeyGroupTable;
449 
450     // Table of KeyID to ways to synthesize that KeyID
451     typedef std::map<KeyID, KeyGroupTable> KeyIDMap;
452 
453     // List of KeyItems that generate a particular modifier
454     typedef std::vector<const KeyItem*> ModifierKeyItemList;
455 
456     // Map a modifier to the KeyItems that synthesize that modifier
457     typedef std::vector<ModifierKeyItemList> ModifierToKeyTable;
458 
459     // A set of keys
460     typedef std::set<KeyID> KeySet;
461 
462     // A set of buttons
463     typedef std::set<KeyButton> KeyButtonSet;
464 
465     // Key maps for parsing/formatting
466     typedef std::map<String, KeyID,
467                             barrier::string::CaselessCmp> NameToKeyMap;
468     typedef std::map<String, KeyModifierMask,
469                             barrier::string::CaselessCmp> NameToModifierMap;
470     typedef std::map<KeyID, String> KeyToNameMap;
471     typedef std::map<KeyModifierMask, String> ModifierToNameMap;
472 
473     // KeyID info
474     KeyIDMap            m_keyIDMap;
475     SInt32                m_numGroups;
476     ModifierToKeyTable    m_modifierKeys;
477 
478     // composition info
479     bool                m_composeAcrossGroups;
480 
481     // half-duplex info
482     KeyButtonSet        m_halfDuplex;            // half-duplex set by barrier
483     KeySet                m_halfDuplexMods;        // half-duplex set by user
484 
485     // dummy KeyItem for changing modifiers
486     KeyItem                m_modifierKeyItem;
487 
488     // parsing/formatting tables
489     static NameToKeyMap*        s_nameToKeyMap;
490     static NameToModifierMap*    s_nameToModifierMap;
491     static KeyToNameMap*        s_keyToNameMap;
492     static ModifierToNameMap*    s_modifierToNameMap;
493 };
494 
495 }
496