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.

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