HotkeysDetector.jsx 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. import React, { useCallback, useMemo } from 'react';
  2. import PropTypes from 'prop-types';
  3. import { GlobalHotKeys } from 'react-hotkeys';
  4. import HotkeyStroke from '~/client/models/HotkeyStroke';
  5. const HotkeysDetector = (props) => {
  6. const { keySet, strokeSet, onDetected } = props;
  7. // memorize HotkeyStroke instances
  8. const hotkeyStrokes = useMemo(() => {
  9. const strokes = Array.from(strokeSet);
  10. return strokes.map((stroke) => new HotkeyStroke(stroke));
  11. }, [strokeSet]);
  12. /**
  13. * return key expression string includes modifier
  14. */
  15. const getKeyExpression = useCallback((event) => {
  16. let eventKey = event.key;
  17. if (event.ctrlKey) {
  18. eventKey += '+ctrl';
  19. }
  20. if (event.metaKey) {
  21. eventKey += '+meta';
  22. }
  23. if (event.altKey) {
  24. eventKey += '+alt';
  25. }
  26. if (event.shiftKey) {
  27. eventKey += '+shift';
  28. }
  29. return eventKey;
  30. }, []);
  31. /**
  32. * evaluate the key user pressed and trigger onDetected
  33. */
  34. const checkHandler = useCallback(
  35. (event) => {
  36. const eventKey = getKeyExpression(event);
  37. hotkeyStrokes.forEach((hotkeyStroke) => {
  38. // if any stroke is completed
  39. if (hotkeyStroke.evaluate(eventKey)) {
  40. // cancel the key event
  41. event.preventDefault();
  42. // invoke detected handler
  43. onDetected(hotkeyStroke.stroke);
  44. }
  45. });
  46. },
  47. [hotkeyStrokes, getKeyExpression, onDetected],
  48. );
  49. // memorize keyMap for GlobalHotKeys
  50. const keyMap = useMemo(() => {
  51. return { check: Array.from(keySet) };
  52. }, [keySet]);
  53. // memorize handlers for GlobalHotKeys
  54. const handlers = useMemo(() => {
  55. return { check: checkHandler };
  56. }, [checkHandler]);
  57. return <GlobalHotKeys keyMap={keyMap} handlers={handlers} />;
  58. };
  59. HotkeysDetector.propTypes = {
  60. onDetected: PropTypes.func.isRequired,
  61. keySet: PropTypes.instanceOf(Set).isRequired,
  62. strokeSet: PropTypes.instanceOf(Set).isRequired,
  63. };
  64. export default HotkeysDetector;