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.

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