The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

260 lines
11KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. #ifndef __JUCE_KEYPRESSMAPPINGSET_JUCEHEADER__
  19. #define __JUCE_KEYPRESSMAPPINGSET_JUCEHEADER__
  20. #include "../keyboard/juce_KeyListener.h"
  21. #include "../commands/juce_ApplicationCommandManager.h"
  22. //==============================================================================
  23. /**
  24. Manages and edits a list of keypresses, which it uses to invoke the appropriate
  25. command in a ApplicationCommandManager.
  26. Normally, you won't actually create a KeyPressMappingSet directly, because
  27. each ApplicationCommandManager contains its own KeyPressMappingSet, so typically
  28. you'd create yourself an ApplicationCommandManager, and call its
  29. ApplicationCommandManager::getKeyMappings() method to get a pointer to its
  30. KeyPressMappingSet.
  31. For one of these to actually use keypresses, you'll need to add it as a KeyListener
  32. to the top-level component for which you want to handle keystrokes. So for example:
  33. @code
  34. class MyMainWindow : public Component
  35. {
  36. ApplicationCommandManager* myCommandManager;
  37. public:
  38. MyMainWindow()
  39. {
  40. myCommandManager = new ApplicationCommandManager();
  41. // first, make sure the command manager has registered all the commands that its
  42. // targets can perform..
  43. myCommandManager->registerAllCommandsForTarget (myCommandTarget1);
  44. myCommandManager->registerAllCommandsForTarget (myCommandTarget2);
  45. // this will use the command manager to initialise the KeyPressMappingSet with
  46. // the default keypresses that were specified when the targets added their commands
  47. // to the manager.
  48. myCommandManager->getKeyMappings()->resetToDefaultMappings();
  49. // having set up the default key-mappings, you might now want to load the last set
  50. // of mappings that the user configured.
  51. myCommandManager->getKeyMappings()->restoreFromXml (lastSavedKeyMappingsXML);
  52. // Now tell our top-level window to send any keypresses that arrive to the
  53. // KeyPressMappingSet, which will use them to invoke the appropriate commands.
  54. addKeyListener (myCommandManager->getKeyMappings());
  55. }
  56. ...
  57. }
  58. @endcode
  59. KeyPressMappingSet derives from ChangeBroadcaster so that interested parties can
  60. register to be told when a command or mapping is added, removed, etc.
  61. There's also a UI component called KeyMappingEditorComponent that can be used
  62. to easily edit the key mappings.
  63. @see Component::addKeyListener(), KeyMappingEditorComponent, ApplicationCommandManager
  64. */
  65. class JUCE_API KeyPressMappingSet : public KeyListener,
  66. public ChangeBroadcaster,
  67. private FocusChangeListener
  68. {
  69. public:
  70. //==============================================================================
  71. /** Creates a KeyPressMappingSet for a given command manager.
  72. Normally, you won't actually create a KeyPressMappingSet directly, because
  73. each ApplicationCommandManager contains its own KeyPressMappingSet, so the
  74. best thing to do is to create your ApplicationCommandManager, and use the
  75. ApplicationCommandManager::getKeyMappings() method to access its mappings.
  76. When a suitable keypress happens, the manager's invoke() method will be
  77. used to invoke the appropriate command.
  78. @see ApplicationCommandManager
  79. */
  80. explicit KeyPressMappingSet (ApplicationCommandManager* commandManager);
  81. /** Creates an copy of a KeyPressMappingSet. */
  82. KeyPressMappingSet (const KeyPressMappingSet& other);
  83. /** Destructor. */
  84. ~KeyPressMappingSet();
  85. //==============================================================================
  86. ApplicationCommandManager* getCommandManager() const noexcept { return commandManager; }
  87. //==============================================================================
  88. /** Returns a list of keypresses that are assigned to a particular command.
  89. @param commandID the command's ID
  90. */
  91. Array<KeyPress> getKeyPressesAssignedToCommand (CommandID commandID) const;
  92. /** Assigns a keypress to a command.
  93. If the keypress is already assigned to a different command, it will first be
  94. removed from that command, to avoid it triggering multiple functions.
  95. @param commandID the ID of the command that you want to add a keypress to. If
  96. this is 0, the keypress will be removed from anything that it
  97. was previously assigned to, but not re-assigned
  98. @param newKeyPress the new key-press
  99. @param insertIndex if this is less than zero, the key will be appended to the
  100. end of the list of keypresses; otherwise the new keypress will
  101. be inserted into the existing list at this index
  102. */
  103. void addKeyPress (CommandID commandID,
  104. const KeyPress& newKeyPress,
  105. int insertIndex = -1);
  106. /** Reset all mappings to the defaults, as dictated by the ApplicationCommandManager.
  107. @see resetToDefaultMapping
  108. */
  109. void resetToDefaultMappings();
  110. /** Resets all key-mappings to the defaults for a particular command.
  111. @see resetToDefaultMappings
  112. */
  113. void resetToDefaultMapping (CommandID commandID);
  114. /** Removes all keypresses that are assigned to any commands. */
  115. void clearAllKeyPresses();
  116. /** Removes all keypresses that are assigned to a particular command. */
  117. void clearAllKeyPresses (CommandID commandID);
  118. /** Removes one of the keypresses that are assigned to a command.
  119. See the getKeyPressesAssignedToCommand() for the list of keypresses to
  120. which the keyPressIndex refers.
  121. */
  122. void removeKeyPress (CommandID commandID, int keyPressIndex);
  123. /** Removes a keypress from any command that it may be assigned to.
  124. */
  125. void removeKeyPress (const KeyPress& keypress);
  126. /** Returns true if the given command is linked to this key. */
  127. bool containsMapping (CommandID commandID, const KeyPress& keyPress) const noexcept;
  128. //==============================================================================
  129. /** Looks for a command that corresponds to a keypress.
  130. @returns the UID of the command or 0 if none was found
  131. */
  132. CommandID findCommandForKeyPress (const KeyPress& keyPress) const noexcept;
  133. //==============================================================================
  134. /** Tries to recreate the mappings from a previously stored state.
  135. The XML passed in must have been created by the createXml() method.
  136. If the stored state makes any reference to commands that aren't
  137. currently available, these will be ignored.
  138. If the set of mappings being loaded was a set of differences (using createXml (true)),
  139. then this will call resetToDefaultMappings() and then merge the saved mappings
  140. on top. If the saved set was created with createXml (false), then this method
  141. will first clear all existing mappings and load the saved ones as a complete set.
  142. @returns true if it manages to load the XML correctly
  143. @see createXml
  144. */
  145. bool restoreFromXml (const XmlElement& xmlVersion);
  146. /** Creates an XML representation of the current mappings.
  147. This will produce a lump of XML that can be later reloaded using
  148. restoreFromXml() to recreate the current mapping state.
  149. The object that is returned must be deleted by the caller.
  150. @param saveDifferencesFromDefaultSet if this is false, then all keypresses
  151. will be saved into the XML. If it's true, then the XML will
  152. only store the differences between the current mappings and
  153. the default mappings you'd get from calling resetToDefaultMappings().
  154. The advantage of saving a set of differences from the default is that
  155. if you change the default mappings (in a new version of your app, for
  156. example), then these will be merged into a user's saved preferences.
  157. @see restoreFromXml
  158. */
  159. XmlElement* createXml (bool saveDifferencesFromDefaultSet) const;
  160. //==============================================================================
  161. /** @internal */
  162. bool keyPressed (const KeyPress& key, Component* originatingComponent);
  163. /** @internal */
  164. bool keyStateChanged (bool isKeyDown, Component* originatingComponent);
  165. /** @internal */
  166. void globalFocusChanged (Component* focusedComponent);
  167. private:
  168. //==============================================================================
  169. ApplicationCommandManager* commandManager;
  170. struct CommandMapping
  171. {
  172. CommandID commandID;
  173. Array <KeyPress> keypresses;
  174. bool wantsKeyUpDownCallbacks;
  175. };
  176. OwnedArray <CommandMapping> mappings;
  177. struct KeyPressTime
  178. {
  179. KeyPress key;
  180. uint32 timeWhenPressed;
  181. };
  182. OwnedArray <KeyPressTime> keysDown;
  183. void handleMessage (const Message& message);
  184. void invokeCommand (const CommandID commandID,
  185. const KeyPress& keyPress,
  186. const bool isKeyDown,
  187. const int millisecsSinceKeyPressed,
  188. Component* const originatingComponent) const;
  189. KeyPressMappingSet& operator= (const KeyPressMappingSet&);
  190. JUCE_LEAK_DETECTOR (KeyPressMappingSet);
  191. };
  192. #endif // __JUCE_KEYPRESSMAPPINGSET_JUCEHEADER__