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.

314 lines
11KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. KeyPress::KeyPress() noexcept
  18. : keyCode (0),
  19. textCharacter (0)
  20. {
  21. }
  22. KeyPress::KeyPress (const int code, ModifierKeys m,
  23. const juce_wchar textChar) noexcept
  24. : keyCode (code),
  25. mods (m),
  26. textCharacter (textChar)
  27. {
  28. }
  29. KeyPress::KeyPress (const int code) noexcept
  30. : keyCode (code),
  31. textCharacter (0)
  32. {
  33. }
  34. KeyPress::KeyPress (const KeyPress& other) noexcept
  35. : keyCode (other.keyCode),
  36. mods (other.mods),
  37. textCharacter (other.textCharacter)
  38. {
  39. }
  40. KeyPress& KeyPress::operator= (const KeyPress& other) noexcept
  41. {
  42. keyCode = other.keyCode;
  43. mods = other.mods;
  44. textCharacter = other.textCharacter;
  45. return *this;
  46. }
  47. bool KeyPress::operator== (int otherKeyCode) const noexcept
  48. {
  49. return keyCode == otherKeyCode && ! mods.isAnyModifierKeyDown();
  50. }
  51. bool KeyPress::operator== (const KeyPress& other) const noexcept
  52. {
  53. return mods.getRawFlags() == other.mods.getRawFlags()
  54. && (textCharacter == other.textCharacter
  55. || textCharacter == 0
  56. || other.textCharacter == 0)
  57. && (keyCode == other.keyCode
  58. || (keyCode < 256
  59. && other.keyCode < 256
  60. && CharacterFunctions::toLowerCase ((juce_wchar) keyCode)
  61. == CharacterFunctions::toLowerCase ((juce_wchar) other.keyCode)));
  62. }
  63. bool KeyPress::operator!= (const KeyPress& other) const noexcept
  64. {
  65. return ! operator== (other);
  66. }
  67. bool KeyPress::operator!= (int otherKeyCode) const noexcept
  68. {
  69. return ! operator== (otherKeyCode);
  70. }
  71. bool KeyPress::isCurrentlyDown() const
  72. {
  73. return isKeyCurrentlyDown (keyCode)
  74. && (ModifierKeys::getCurrentModifiers().getRawFlags() & ModifierKeys::allKeyboardModifiers)
  75. == (mods.getRawFlags() & ModifierKeys::allKeyboardModifiers);
  76. }
  77. //==============================================================================
  78. namespace KeyPressHelpers
  79. {
  80. struct KeyNameAndCode
  81. {
  82. const char* name;
  83. int code;
  84. };
  85. const KeyNameAndCode translations[] =
  86. {
  87. { "spacebar", KeyPress::spaceKey },
  88. { "return", KeyPress::returnKey },
  89. { "escape", KeyPress::escapeKey },
  90. { "backspace", KeyPress::backspaceKey },
  91. { "cursor left", KeyPress::leftKey },
  92. { "cursor right", KeyPress::rightKey },
  93. { "cursor up", KeyPress::upKey },
  94. { "cursor down", KeyPress::downKey },
  95. { "page up", KeyPress::pageUpKey },
  96. { "page down", KeyPress::pageDownKey },
  97. { "home", KeyPress::homeKey },
  98. { "end", KeyPress::endKey },
  99. { "delete", KeyPress::deleteKey },
  100. { "insert", KeyPress::insertKey },
  101. { "tab", KeyPress::tabKey },
  102. { "play", KeyPress::playKey },
  103. { "stop", KeyPress::stopKey },
  104. { "fast forward", KeyPress::fastForwardKey },
  105. { "rewind", KeyPress::rewindKey }
  106. };
  107. struct ModifierDescription
  108. {
  109. const char* name;
  110. int flag;
  111. };
  112. static const ModifierDescription modifierNames[] =
  113. {
  114. { "ctrl", ModifierKeys::ctrlModifier },
  115. { "control", ModifierKeys::ctrlModifier },
  116. { "ctl", ModifierKeys::ctrlModifier },
  117. { "shift", ModifierKeys::shiftModifier },
  118. { "shft", ModifierKeys::shiftModifier },
  119. { "alt", ModifierKeys::altModifier },
  120. { "option", ModifierKeys::altModifier },
  121. { "command", ModifierKeys::commandModifier },
  122. { "cmd", ModifierKeys::commandModifier }
  123. };
  124. static const char* numberPadPrefix() noexcept { return "numpad "; }
  125. static int getNumpadKeyCode (const String& desc)
  126. {
  127. if (desc.containsIgnoreCase (numberPadPrefix()))
  128. {
  129. const juce_wchar lastChar = desc.trimEnd().getLastCharacter();
  130. switch (lastChar)
  131. {
  132. case '0': case '1': case '2': case '3': case '4':
  133. case '5': case '6': case '7': case '8': case '9':
  134. return (int) (KeyPress::numberPad0 + lastChar - '0');
  135. case '+': return KeyPress::numberPadAdd;
  136. case '-': return KeyPress::numberPadSubtract;
  137. case '*': return KeyPress::numberPadMultiply;
  138. case '/': return KeyPress::numberPadDivide;
  139. case '.': return KeyPress::numberPadDecimalPoint;
  140. case '=': return KeyPress::numberPadEquals;
  141. default: break;
  142. }
  143. if (desc.endsWith ("separator")) return KeyPress::numberPadSeparator;
  144. if (desc.endsWith ("delete")) return KeyPress::numberPadDelete;
  145. }
  146. return 0;
  147. }
  148. #if JUCE_MAC
  149. struct OSXSymbolReplacement
  150. {
  151. const char* text;
  152. juce_wchar symbol;
  153. };
  154. const OSXSymbolReplacement osxSymbols[] =
  155. {
  156. { "shift + ", 0x21e7 },
  157. { "command + ", 0x2318 },
  158. { "option + ", 0x2325 },
  159. { "ctrl + ", 0x2303 },
  160. { "return", 0x23ce },
  161. { "cursor left", 0x2190 },
  162. { "cursor right", 0x2192 },
  163. { "cursor up", 0x2191 },
  164. { "cursor down", 0x2193 },
  165. { "backspace", 0x232b },
  166. { "delete", 0x2326 }
  167. };
  168. #endif
  169. }
  170. //==============================================================================
  171. KeyPress KeyPress::createFromDescription (const String& desc)
  172. {
  173. int modifiers = 0;
  174. for (int i = 0; i < numElementsInArray (KeyPressHelpers::modifierNames); ++i)
  175. if (desc.containsWholeWordIgnoreCase (KeyPressHelpers::modifierNames[i].name))
  176. modifiers |= KeyPressHelpers::modifierNames[i].flag;
  177. int key = 0;
  178. for (int i = 0; i < numElementsInArray (KeyPressHelpers::translations); ++i)
  179. {
  180. if (desc.containsWholeWordIgnoreCase (String (KeyPressHelpers::translations[i].name)))
  181. {
  182. key = KeyPressHelpers::translations[i].code;
  183. break;
  184. }
  185. }
  186. if (key == 0)
  187. key = KeyPressHelpers::getNumpadKeyCode (desc);
  188. if (key == 0)
  189. {
  190. // see if it's a function key..
  191. if (! desc.containsChar ('#')) // avoid mistaking hex-codes like "#f1"
  192. for (int i = 1; i <= 12; ++i)
  193. if (desc.containsWholeWordIgnoreCase ("f" + String (i)))
  194. key = F1Key + i - 1;
  195. if (key == 0)
  196. {
  197. // give up and use the hex code..
  198. const int hexCode = desc.fromFirstOccurrenceOf ("#", false, false)
  199. .retainCharacters ("0123456789abcdefABCDEF")
  200. .getHexValue32();
  201. if (hexCode > 0)
  202. key = hexCode;
  203. else
  204. key = (int) CharacterFunctions::toUpperCase (desc.getLastCharacter());
  205. }
  206. }
  207. return KeyPress (key, ModifierKeys (modifiers), 0);
  208. }
  209. String KeyPress::getTextDescription() const
  210. {
  211. String desc;
  212. if (keyCode > 0)
  213. {
  214. // some keyboard layouts use a shift-key to get the slash, but in those cases, we
  215. // want to store it as being a slash, not shift+whatever.
  216. if (textCharacter == '/')
  217. return "/";
  218. if (mods.isCtrlDown())
  219. desc << "ctrl + ";
  220. if (mods.isShiftDown())
  221. desc << "shift + ";
  222. #if JUCE_MAC
  223. if (mods.isAltDown())
  224. desc << "option + ";
  225. // only do this on the mac, because on Windows ctrl and command are the same,
  226. // and this would get confusing
  227. if (mods.isCommandDown())
  228. desc << "command + ";
  229. #else
  230. if (mods.isAltDown())
  231. desc << "alt + ";
  232. #endif
  233. for (int i = 0; i < numElementsInArray (KeyPressHelpers::translations); ++i)
  234. if (keyCode == KeyPressHelpers::translations[i].code)
  235. return desc + KeyPressHelpers::translations[i].name;
  236. if (keyCode >= F1Key && keyCode <= F16Key) desc << 'F' << (1 + keyCode - F1Key);
  237. else if (keyCode >= numberPad0 && keyCode <= numberPad9) desc << KeyPressHelpers::numberPadPrefix() << (keyCode - numberPad0);
  238. else if (keyCode >= 33 && keyCode < 176) desc += CharacterFunctions::toUpperCase ((juce_wchar) keyCode);
  239. else if (keyCode == numberPadAdd) desc << KeyPressHelpers::numberPadPrefix() << '+';
  240. else if (keyCode == numberPadSubtract) desc << KeyPressHelpers::numberPadPrefix() << '-';
  241. else if (keyCode == numberPadMultiply) desc << KeyPressHelpers::numberPadPrefix() << '*';
  242. else if (keyCode == numberPadDivide) desc << KeyPressHelpers::numberPadPrefix() << '/';
  243. else if (keyCode == numberPadSeparator) desc << KeyPressHelpers::numberPadPrefix() << "separator";
  244. else if (keyCode == numberPadDecimalPoint) desc << KeyPressHelpers::numberPadPrefix() << '.';
  245. else if (keyCode == numberPadDelete) desc << KeyPressHelpers::numberPadPrefix() << "delete";
  246. else desc << '#' << String::toHexString (keyCode);
  247. }
  248. return desc;
  249. }
  250. String KeyPress::getTextDescriptionWithIcons() const
  251. {
  252. #if JUCE_MAC
  253. String s (getTextDescription());
  254. for (int i = 0; i < numElementsInArray (KeyPressHelpers::osxSymbols); ++i)
  255. s = s.replace (KeyPressHelpers::osxSymbols[i].text,
  256. String::charToString (KeyPressHelpers::osxSymbols[i].symbol));
  257. return s;
  258. #else
  259. return getTextDescription();
  260. #endif
  261. }