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