shortcuts.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. // TODO: This file was created by bulk-decaffeinate.
  2. // Sanity-check the conversion and remove this comment.
  3. /*
  4. * decaffeinate suggestions:
  5. * DS102: Remove unnecessary code created because of implicit returns
  6. * DS103: Rewrite code to no longer use __guard__, or convert again using --optional-chaining
  7. * DS205: Consider reworking code to avoid use of IIFEs
  8. * DS206: Consider reworking classes to avoid initClass
  9. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
  10. */
  11. app.Shortcuts = class Shortcuts {
  12. static initClass() {
  13. $.extend(this.prototype, Events);
  14. }
  15. constructor() {
  16. this.onKeydown = this.onKeydown.bind(this);
  17. this.onKeypress = this.onKeypress.bind(this);
  18. this.isMac = $.isMac();
  19. this.start();
  20. }
  21. start() {
  22. $.on(document, "keydown", this.onKeydown);
  23. $.on(document, "keypress", this.onKeypress);
  24. }
  25. stop() {
  26. $.off(document, "keydown", this.onKeydown);
  27. $.off(document, "keypress", this.onKeypress);
  28. }
  29. swapArrowKeysBehavior() {
  30. return app.settings.get("arrowScroll");
  31. }
  32. spaceScroll() {
  33. return app.settings.get("spaceScroll");
  34. }
  35. showTip() {
  36. app.showTip("KeyNav");
  37. return (this.showTip = null);
  38. }
  39. spaceTimeout() {
  40. return app.settings.get("spaceTimeout");
  41. }
  42. onKeydown(event) {
  43. if (this.buggyEvent(event)) {
  44. return;
  45. }
  46. const result = (() => {
  47. if (event.ctrlKey || event.metaKey) {
  48. if (!event.altKey && !event.shiftKey) {
  49. return this.handleKeydownSuperEvent(event);
  50. }
  51. } else if (event.shiftKey) {
  52. if (!event.altKey) {
  53. return this.handleKeydownShiftEvent(event);
  54. }
  55. } else if (event.altKey) {
  56. return this.handleKeydownAltEvent(event);
  57. } else {
  58. return this.handleKeydownEvent(event);
  59. }
  60. })();
  61. if (result === false) {
  62. event.preventDefault();
  63. }
  64. }
  65. onKeypress(event) {
  66. if (
  67. this.buggyEvent(event) ||
  68. (event.charCode === 63 && document.activeElement.tagName === "INPUT")
  69. ) {
  70. return;
  71. }
  72. if (!event.ctrlKey && !event.metaKey) {
  73. const result = this.handleKeypressEvent(event);
  74. if (result === false) {
  75. event.preventDefault();
  76. }
  77. }
  78. }
  79. handleKeydownEvent(event, _force) {
  80. if (
  81. !_force &&
  82. [37, 38, 39, 40].includes(event.which) &&
  83. this.swapArrowKeysBehavior()
  84. ) {
  85. return this.handleKeydownAltEvent(event, true);
  86. }
  87. if (
  88. !event.target.form &&
  89. ((48 <= event.which && event.which <= 57) ||
  90. (65 <= event.which && event.which <= 90))
  91. ) {
  92. this.trigger("typing");
  93. return;
  94. }
  95. switch (event.which) {
  96. case 8:
  97. if (!event.target.form) {
  98. return this.trigger("typing");
  99. }
  100. break;
  101. case 13:
  102. return this.trigger("enter");
  103. case 27:
  104. this.trigger("escape");
  105. return false;
  106. case 32:
  107. if (
  108. event.target.type === "search" &&
  109. this.spaceScroll() &&
  110. (!this.lastKeypress ||
  111. this.lastKeypress < Date.now() - this.spaceTimeout() * 1000)
  112. ) {
  113. this.trigger("pageDown");
  114. return false;
  115. }
  116. break;
  117. case 33:
  118. return this.trigger("pageUp");
  119. case 34:
  120. return this.trigger("pageDown");
  121. case 35:
  122. if (!event.target.form) {
  123. return this.trigger("pageBottom");
  124. }
  125. break;
  126. case 36:
  127. if (!event.target.form) {
  128. return this.trigger("pageTop");
  129. }
  130. break;
  131. case 37:
  132. if (!event.target.value) {
  133. return this.trigger("left");
  134. }
  135. break;
  136. case 38:
  137. this.trigger("up");
  138. if (typeof this.showTip === "function") {
  139. this.showTip();
  140. }
  141. return false;
  142. case 39:
  143. if (!event.target.value) {
  144. return this.trigger("right");
  145. }
  146. break;
  147. case 40:
  148. this.trigger("down");
  149. if (typeof this.showTip === "function") {
  150. this.showTip();
  151. }
  152. return false;
  153. case 191:
  154. if (!event.target.form) {
  155. this.trigger("typing");
  156. return false;
  157. }
  158. break;
  159. }
  160. }
  161. handleKeydownSuperEvent(event) {
  162. switch (event.which) {
  163. case 13:
  164. return this.trigger("superEnter");
  165. case 37:
  166. if (this.isMac) {
  167. this.trigger("superLeft");
  168. return false;
  169. }
  170. break;
  171. case 38:
  172. this.trigger("pageTop");
  173. return false;
  174. case 39:
  175. if (this.isMac) {
  176. this.trigger("superRight");
  177. return false;
  178. }
  179. break;
  180. case 40:
  181. this.trigger("pageBottom");
  182. return false;
  183. case 188:
  184. this.trigger("preferences");
  185. return false;
  186. }
  187. }
  188. handleKeydownShiftEvent(event, _force) {
  189. if (
  190. !_force &&
  191. [37, 38, 39, 40].includes(event.which) &&
  192. this.swapArrowKeysBehavior()
  193. ) {
  194. return this.handleKeydownEvent(event, true);
  195. }
  196. if (!event.target.form && 65 <= event.which && event.which <= 90) {
  197. this.trigger("typing");
  198. return;
  199. }
  200. switch (event.which) {
  201. case 32:
  202. this.trigger("pageUp");
  203. return false;
  204. case 38:
  205. if (!__guard__(getSelection(), (x) => x.toString())) {
  206. this.trigger("altUp");
  207. return false;
  208. }
  209. break;
  210. case 40:
  211. if (!__guard__(getSelection(), (x1) => x1.toString())) {
  212. this.trigger("altDown");
  213. return false;
  214. }
  215. break;
  216. }
  217. }
  218. handleKeydownAltEvent(event, _force) {
  219. if (
  220. !_force &&
  221. [37, 38, 39, 40].includes(event.which) &&
  222. this.swapArrowKeysBehavior()
  223. ) {
  224. return this.handleKeydownEvent(event, true);
  225. }
  226. switch (event.which) {
  227. case 9:
  228. return this.trigger("altRight", event);
  229. case 37:
  230. if (!this.isMac) {
  231. this.trigger("superLeft");
  232. return false;
  233. }
  234. break;
  235. case 38:
  236. this.trigger("altUp");
  237. return false;
  238. case 39:
  239. if (!this.isMac) {
  240. this.trigger("superRight");
  241. return false;
  242. }
  243. break;
  244. case 40:
  245. this.trigger("altDown");
  246. return false;
  247. case 67:
  248. this.trigger("altC");
  249. return false;
  250. case 68:
  251. this.trigger("altD");
  252. return false;
  253. case 70:
  254. return this.trigger("altF", event);
  255. case 71:
  256. this.trigger("altG");
  257. return false;
  258. case 79:
  259. this.trigger("altO");
  260. return false;
  261. case 82:
  262. this.trigger("altR");
  263. return false;
  264. case 83:
  265. this.trigger("altS");
  266. return false;
  267. }
  268. }
  269. handleKeypressEvent(event) {
  270. if (event.which === 63 && !event.target.value) {
  271. this.trigger("help");
  272. return false;
  273. } else {
  274. return (this.lastKeypress = Date.now());
  275. }
  276. }
  277. buggyEvent(event) {
  278. try {
  279. event.target;
  280. event.ctrlKey;
  281. event.which;
  282. return false;
  283. } catch (error) {
  284. return true;
  285. }
  286. }
  287. };
  288. app.Shortcuts.initClass();
  289. function __guard__(value, transform) {
  290. return typeof value !== "undefined" && value !== null
  291. ? transform(value)
  292. : undefined;
  293. }