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.

useKeyboardEvents.ts 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. /* eslint-disable @typescript-eslint/explicit-module-boundary-types */
  2. import { useEffect } from 'react'
  3. import state from 'state'
  4. import inputs from 'state/inputs'
  5. import { MoveType } from 'types'
  6. import { metaKey } from 'utils'
  7. export default function useKeyboardEvents() {
  8. useEffect(() => {
  9. function handleKeyDown(e: KeyboardEvent) {
  10. if (
  11. metaKey(e) &&
  12. ![
  13. 'a',
  14. 'i',
  15. 'r',
  16. 'j',
  17. 'ArrowLeft',
  18. 'ArrowRight',
  19. 'ArrowUp',
  20. 'ArrowDown',
  21. 'z',
  22. ].includes(e.key)
  23. ) {
  24. e.preventDefault()
  25. }
  26. const info = inputs.keydown(e)
  27. switch (e.key) {
  28. case 'ArrowUp': {
  29. state.send('NUDGED', { delta: [0, -1], ...info })
  30. break
  31. }
  32. case 'ArrowRight': {
  33. state.send('NUDGED', { delta: [1, 0], ...info })
  34. break
  35. }
  36. case 'ArrowDown': {
  37. state.send('NUDGED', { delta: [0, 1], ...info })
  38. break
  39. }
  40. case 'ArrowLeft': {
  41. state.send('NUDGED', { delta: [-1, 0], ...info })
  42. break
  43. }
  44. case '=': {
  45. if (e.metaKey) {
  46. state.send('ZOOMED_IN')
  47. }
  48. break
  49. }
  50. case '-': {
  51. if (e.metaKey) {
  52. state.send('ZOOMED_OUT')
  53. }
  54. break
  55. }
  56. case '!': {
  57. // Shift + 1
  58. if (e.shiftKey) {
  59. state.send('ZOOMED_TO_FIT')
  60. }
  61. break
  62. }
  63. case '@': {
  64. // Shift + 2
  65. if (e.shiftKey) {
  66. state.send('ZOOMED_TO_SELECTION')
  67. }
  68. break
  69. }
  70. case ')': {
  71. // Shift + 0
  72. if (e.shiftKey) {
  73. state.send('ZOOMED_TO_ACTUAL')
  74. }
  75. break
  76. }
  77. case 'Escape': {
  78. state.send('CANCELLED')
  79. break
  80. }
  81. case 'z': {
  82. if (metaKey(e)) {
  83. if (e.shiftKey) {
  84. state.send('REDO', info)
  85. } else {
  86. state.send('UNDO', info)
  87. }
  88. }
  89. break
  90. }
  91. case '‘': {
  92. if (metaKey(e)) {
  93. state.send('MOVED', {
  94. ...info,
  95. type: MoveType.ToFront,
  96. })
  97. }
  98. break
  99. }
  100. case '“': {
  101. if (metaKey(e)) {
  102. state.send('MOVED', {
  103. ...info,
  104. type: MoveType.ToBack,
  105. })
  106. }
  107. break
  108. }
  109. case ']': {
  110. if (metaKey(e)) {
  111. state.send('MOVED', {
  112. ...info,
  113. type: MoveType.Forward,
  114. })
  115. }
  116. break
  117. }
  118. case '[': {
  119. if (metaKey(e)) {
  120. state.send('MOVED', {
  121. ...info,
  122. type: MoveType.Backward,
  123. })
  124. }
  125. break
  126. }
  127. case 'Shift': {
  128. state.send('PRESSED_SHIFT_KEY', info)
  129. break
  130. }
  131. case 'Alt': {
  132. state.send('PRESSED_ALT_KEY', info)
  133. break
  134. }
  135. case 'Backspace': {
  136. if (metaKey(e)) {
  137. if (e.shiftKey) {
  138. if (window.confirm('Reset document and state?')) {
  139. state.send('RESET_DOCUMENT_STATE', info)
  140. }
  141. } else {
  142. state.send('FORCE_CLEARED_PAGE', info)
  143. }
  144. } else {
  145. state.send('DELETED', info)
  146. }
  147. break
  148. }
  149. case 'g': {
  150. if (metaKey(e)) {
  151. if (e.shiftKey) {
  152. state.send('UNGROUPED', info)
  153. } else {
  154. state.send('GROUPED', info)
  155. }
  156. }
  157. break
  158. }
  159. case 's': {
  160. if (metaKey(e)) {
  161. if (e.shiftKey) {
  162. state.send('SAVED_AS_TO_FILESYSTEM', info)
  163. } else {
  164. state.send('SAVED', info)
  165. }
  166. }
  167. break
  168. }
  169. case 'o': {
  170. if (metaKey(e)) {
  171. break
  172. } else {
  173. state.send('SELECTED_DOT_TOOL', info)
  174. }
  175. break
  176. }
  177. case 'v': {
  178. if (metaKey(e)) {
  179. state.send('PASTED', info)
  180. } else {
  181. state.send('SELECTED_SELECT_TOOL', info)
  182. }
  183. break
  184. }
  185. case 'a': {
  186. if (metaKey(e)) {
  187. state.send('SELECTED_ALL', info)
  188. } else {
  189. state.send('SELECTED_ARROW_TOOL', info)
  190. }
  191. break
  192. }
  193. case 'd': {
  194. if (metaKey(e)) {
  195. state.send('DUPLICATED', info)
  196. } else {
  197. state.send('SELECTED_DRAW_TOOL', info)
  198. }
  199. break
  200. }
  201. case 't': {
  202. state.send('SELECTED_TEXT_TOOL', info)
  203. break
  204. }
  205. case 'c': {
  206. if (metaKey(e)) {
  207. if (e.shiftKey) {
  208. state.send('COPIED_TO_SVG', info)
  209. } else {
  210. state.send('COPIED', info)
  211. }
  212. } else {
  213. state.send('SELECTED_ELLIPSE_TOOL', info)
  214. }
  215. break
  216. }
  217. case 'i': {
  218. if (metaKey(e)) {
  219. break
  220. } else {
  221. state.send('SELECTED_CIRCLE_TOOL', info)
  222. }
  223. break
  224. }
  225. case 'l': {
  226. if (metaKey(e)) {
  227. if (e.shiftKey) {
  228. state.send('LOADED_FROM_FILE_STSTEM', info)
  229. }
  230. } else {
  231. state.send('SELECTED_LINE_TOOL', info)
  232. }
  233. break
  234. }
  235. case 'y': {
  236. if (metaKey(e)) {
  237. break
  238. } else {
  239. state.send('SELECTED_RAY_TOOL', info)
  240. }
  241. break
  242. }
  243. case 'p': {
  244. if (metaKey(e)) {
  245. break
  246. } else {
  247. state.send('SELECTED_POLYLINE_TOOL', info)
  248. }
  249. break
  250. }
  251. case 'r': {
  252. if (metaKey(e)) {
  253. break
  254. } else {
  255. state.send('SELECTED_RECTANGLE_TOOL', info)
  256. }
  257. break
  258. }
  259. case '|': {
  260. state.send('COPIED_STATE_TO_CLIPBOARD')
  261. break
  262. }
  263. default: {
  264. state.send('PRESSED_KEY', info)
  265. }
  266. }
  267. }
  268. function handleKeyUp(e: KeyboardEvent) {
  269. const info = inputs.keyup(e)
  270. if (e.key === 'Shift') {
  271. state.send('RELEASED_SHIFT_KEY', info)
  272. }
  273. if (e.key === 'Alt') {
  274. state.send('RELEASED_ALT_KEY', info)
  275. }
  276. state.send('RELEASED_KEY', info)
  277. }
  278. document.body.addEventListener('keydown', handleKeyDown)
  279. document.body.addEventListener('keyup', handleKeyUp)
  280. return () => {
  281. document.body.removeEventListener('keydown', handleKeyDown)
  282. document.body.removeEventListener('keyup', handleKeyUp)
  283. }
  284. }, [])
  285. }