|
@@ -1,6 +1,7 @@ |
|
|
import * as React from 'react' |
|
|
import * as React from 'react' |
|
|
import * as PropTypes from 'prop-types' |
|
|
import * as PropTypes from 'prop-types' |
|
|
import reverseGetKeyFromPoint from '../../services/reverseGetKeyFromPoint' |
|
|
import reverseGetKeyFromPoint from '../../services/reverseGetKeyFromPoint' |
|
|
|
|
|
import { MIDIMessageEvent } from '../../services/midi' |
|
|
|
|
|
|
|
|
const propTypes = { |
|
|
const propTypes = { |
|
|
/** |
|
|
/** |
|
@@ -15,6 +16,17 @@ const propTypes = { |
|
|
* Map from key code to key number. |
|
|
* Map from key code to key number. |
|
|
*/ |
|
|
*/ |
|
|
keyboardMapping: PropTypes.object, |
|
|
keyboardMapping: PropTypes.object, |
|
|
|
|
|
/** |
|
|
|
|
|
* Received velocity when activating the component through the keyboard. |
|
|
|
|
|
*/ |
|
|
|
|
|
keyboardVelocity: PropTypes.number, |
|
|
|
|
|
/** |
|
|
|
|
|
* MIDI input for sending MIDI messages to the component. |
|
|
|
|
|
*/ |
|
|
|
|
|
midiInput: PropTypes.shape({ |
|
|
|
|
|
addEventListener: PropTypes.func.isRequired, |
|
|
|
|
|
removeEventListener: PropTypes.func.isRequired, |
|
|
|
|
|
}), |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
type Props = PropTypes.InferProps<typeof propTypes> |
|
|
type Props = PropTypes.InferProps<typeof propTypes> |
|
@@ -24,31 +36,34 @@ type Props = PropTypes.InferProps<typeof propTypes> |
|
|
* @param accidentalKeyLengthRatio - Ratio of the length of the accidental keys to the natural keys. |
|
|
* @param accidentalKeyLengthRatio - Ratio of the length of the accidental keys to the natural keys. |
|
|
* @param onChange - Event handler triggered upon change in activated keys in the component. |
|
|
* @param onChange - Event handler triggered upon change in activated keys in the component. |
|
|
* @param keyboardMapping - Map from key code to key number. |
|
|
* @param keyboardMapping - Map from key code to key number. |
|
|
|
|
|
* @param midiInput - MIDI input for sending MIDI messages to the component. |
|
|
|
|
|
* @param keyboardVelocity - Received velocity when activating the component through the keyboard. |
|
|
*/ |
|
|
*/ |
|
|
const KeyboardMap: React.FC<Props> = ({ accidentalKeyLengthRatio, onChange, keyboardMapping = {} }) => { |
|
|
|
|
|
|
|
|
const KeyboardMap: React.FC<Props> = ({ |
|
|
|
|
|
accidentalKeyLengthRatio, |
|
|
|
|
|
onChange, |
|
|
|
|
|
keyboardMapping = {}, |
|
|
|
|
|
midiInput, |
|
|
|
|
|
keyboardVelocity = 0.75, |
|
|
|
|
|
}) => { |
|
|
const baseRef = React.useRef<HTMLDivElement>(null) |
|
|
const baseRef = React.useRef<HTMLDivElement>(null) |
|
|
const keysOnRef = React.useRef<any[]>([]) |
|
|
const keysOnRef = React.useRef<any[]>([]) |
|
|
const lastVelocity = React.useRef<number | undefined>(undefined) |
|
|
const lastVelocity = React.useRef<number | undefined>(undefined) |
|
|
const isTouch = React.useRef<boolean>(false) |
|
|
|
|
|
|
|
|
|
|
|
const handleContextMenu: React.EventHandler<any> = (e) => { |
|
|
|
|
|
e.preventDefault() |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const handleDragStart: React.DragEventHandler = (e) => { |
|
|
|
|
|
|
|
|
const preventDefault: React.EventHandler<React.SyntheticEvent> = (e) => { |
|
|
e.preventDefault() |
|
|
e.preventDefault() |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const handleMouseDown: React.MouseEventHandler = (e) => { |
|
|
const handleMouseDown: React.MouseEventHandler = (e) => { |
|
|
if (isTouch.current) { |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
if (baseRef.current === null) { |
|
|
if (baseRef.current === null) { |
|
|
return |
|
|
return |
|
|
} |
|
|
} |
|
|
if (baseRef.current.parentElement === null) { |
|
|
if (baseRef.current.parentElement === null) { |
|
|
return |
|
|
return |
|
|
} |
|
|
} |
|
|
|
|
|
if (e.buttons !== 1) { |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
const keyData = reverseGetKeyFromPoint(baseRef.current!.parentElement!, accidentalKeyLengthRatio!)( |
|
|
const keyData = reverseGetKeyFromPoint(baseRef.current!.parentElement!, accidentalKeyLengthRatio!)( |
|
|
e.clientX, |
|
|
e.clientX, |
|
|
e.clientY, |
|
|
e.clientY, |
|
@@ -56,56 +71,62 @@ const KeyboardMap: React.FC<Props> = ({ accidentalKeyLengthRatio, onChange, keyb |
|
|
if (keyData! === null) { |
|
|
if (keyData! === null) { |
|
|
return |
|
|
return |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (e.buttons === 1) { |
|
|
|
|
|
if (lastVelocity.current === undefined) { |
|
|
|
|
|
lastVelocity.current = keyData.velocity > 1 ? 1 : keyData.velocity < 0 ? 0 : keyData.velocity |
|
|
|
|
|
} |
|
|
|
|
|
keysOnRef.current = [...keysOnRef.current, { ...keyData, velocity: lastVelocity.current, id: -1 }] |
|
|
|
|
|
if (typeof onChange! === 'function') { |
|
|
|
|
|
onChange(keysOnRef.current) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const handleTouchStart: React.TouchEventHandler = (e) => { |
|
|
|
|
|
isTouch.current = true |
|
|
|
|
|
if (baseRef.current === null) { |
|
|
|
|
|
return |
|
|
|
|
|
|
|
|
if (lastVelocity.current === undefined) { |
|
|
|
|
|
lastVelocity.current = keyData.velocity > 1 ? 1 : keyData.velocity < 0 ? 0 : keyData.velocity |
|
|
} |
|
|
} |
|
|
if (baseRef.current.parentElement === null) { |
|
|
|
|
|
return |
|
|
|
|
|
|
|
|
keysOnRef.current = [...keysOnRef.current, { ...keyData, velocity: lastVelocity.current, id: -1 }] |
|
|
|
|
|
if (typeof onChange! === 'function') { |
|
|
|
|
|
onChange(keysOnRef.current) |
|
|
} |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
Array.from(e.changedTouches).forEach((t) => { |
|
|
|
|
|
const keyData = reverseGetKeyFromPoint(baseRef.current!.parentElement!, accidentalKeyLengthRatio!)( |
|
|
|
|
|
t.clientX, |
|
|
|
|
|
t.clientY, |
|
|
|
|
|
) |
|
|
|
|
|
if (keyData! === null) { |
|
|
|
|
|
|
|
|
React.useEffect(() => { |
|
|
|
|
|
const baseRefCurrent = baseRef.current |
|
|
|
|
|
const handleTouchStart = (e: TouchEvent) => { |
|
|
|
|
|
e.preventDefault() |
|
|
|
|
|
if (baseRef.current === null) { |
|
|
return |
|
|
return |
|
|
} |
|
|
} |
|
|
if (lastVelocity.current === undefined) { |
|
|
|
|
|
lastVelocity.current = keyData.velocity > 1 ? 1 : keyData.velocity < 0 ? 0 : keyData.velocity |
|
|
|
|
|
|
|
|
if (baseRef.current.parentElement === null) { |
|
|
|
|
|
return |
|
|
} |
|
|
} |
|
|
keysOnRef.current = [...keysOnRef.current, { ...keyData, velocity: lastVelocity.current, id: t.identifier }] |
|
|
|
|
|
if (typeof onChange! === 'function') { |
|
|
|
|
|
onChange(keysOnRef.current) |
|
|
|
|
|
|
|
|
const touches = Array.from(e.changedTouches) |
|
|
|
|
|
const touchKeyData = touches.map<[React.Touch, { key: number; velocity: number } | null]>((t) => [ |
|
|
|
|
|
t, |
|
|
|
|
|
reverseGetKeyFromPoint(baseRef.current!.parentElement!, accidentalKeyLengthRatio!)(t.clientX, t.clientY), |
|
|
|
|
|
]) |
|
|
|
|
|
const validTouchKeyData = touchKeyData.filter(([, keyData]) => keyData! !== null) |
|
|
|
|
|
validTouchKeyData.forEach(([t, keyData]) => { |
|
|
|
|
|
const theKeyData = keyData! |
|
|
|
|
|
if (lastVelocity.current === undefined) { |
|
|
|
|
|
lastVelocity.current = theKeyData.velocity > 1 ? 1 : theKeyData.velocity < 0 ? 0 : theKeyData.velocity |
|
|
|
|
|
} |
|
|
|
|
|
keysOnRef.current = [...keysOnRef.current, { ...keyData, velocity: lastVelocity.current, id: t.identifier }] |
|
|
|
|
|
if (typeof onChange! === 'function') { |
|
|
|
|
|
onChange(keysOnRef.current) |
|
|
|
|
|
} |
|
|
|
|
|
}) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (baseRefCurrent !== null) { |
|
|
|
|
|
baseRefCurrent.addEventListener('touchstart', handleTouchStart, { passive: false }) |
|
|
|
|
|
} |
|
|
|
|
|
return () => { |
|
|
|
|
|
if (baseRefCurrent !== null) { |
|
|
|
|
|
baseRefCurrent.removeEventListener('touchstart', handleTouchStart) |
|
|
} |
|
|
} |
|
|
}) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
}, [accidentalKeyLengthRatio, onChange]) |
|
|
|
|
|
|
|
|
React.useEffect(() => { |
|
|
React.useEffect(() => { |
|
|
const handleTouchMove = (e: TouchEvent) => { |
|
|
const handleTouchMove = (e: TouchEvent) => { |
|
|
|
|
|
e.preventDefault() |
|
|
if (baseRef.current === null) { |
|
|
if (baseRef.current === null) { |
|
|
return |
|
|
return |
|
|
} |
|
|
} |
|
|
if (baseRef.current.parentElement === null) { |
|
|
if (baseRef.current.parentElement === null) { |
|
|
return |
|
|
return |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
e.preventDefault() |
|
|
|
|
|
|
|
|
|
|
|
Array.from(e.changedTouches).forEach((t) => { |
|
|
Array.from(e.changedTouches).forEach((t) => { |
|
|
const keyData = reverseGetKeyFromPoint(baseRef.current!.parentElement!, accidentalKeyLengthRatio!)( |
|
|
const keyData = reverseGetKeyFromPoint(baseRef.current!.parentElement!, accidentalKeyLengthRatio!)( |
|
|
t.clientX, |
|
|
t.clientX, |
|
@@ -118,7 +139,6 @@ const KeyboardMap: React.FC<Props> = ({ accidentalKeyLengthRatio, onChange, keyb |
|
|
} |
|
|
} |
|
|
return |
|
|
return |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const [mouseKey = null] = keysOnRef.current.filter((k) => k.id === t.identifier) |
|
|
const [mouseKey = null] = keysOnRef.current.filter((k) => k.id === t.identifier) |
|
|
if (mouseKey === null) { |
|
|
if (mouseKey === null) { |
|
|
keysOnRef.current = keysOnRef.current.filter((k) => k.id !== t.identifier) |
|
|
keysOnRef.current = keysOnRef.current.filter((k) => k.id !== t.identifier) |
|
@@ -158,36 +178,35 @@ const KeyboardMap: React.FC<Props> = ({ accidentalKeyLengthRatio, onChange, keyb |
|
|
if (baseRef.current.parentElement === null) { |
|
|
if (baseRef.current.parentElement === null) { |
|
|
return |
|
|
return |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (e.buttons === 1) { |
|
|
|
|
|
const keyData = reverseGetKeyFromPoint(baseRef.current!.parentElement, accidentalKeyLengthRatio!)( |
|
|
|
|
|
e.clientX, |
|
|
|
|
|
e.clientY, |
|
|
|
|
|
) |
|
|
|
|
|
if (keyData! === null) { |
|
|
|
|
|
keysOnRef.current = keysOnRef.current.filter((k) => k.id !== -1) |
|
|
|
|
|
if (typeof onChange! === 'function') { |
|
|
|
|
|
onChange(keysOnRef.current) |
|
|
|
|
|
} |
|
|
|
|
|
return |
|
|
|
|
|
|
|
|
if (e.buttons !== 1) { |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
const keyData = reverseGetKeyFromPoint(baseRef.current!.parentElement, accidentalKeyLengthRatio!)( |
|
|
|
|
|
e.clientX, |
|
|
|
|
|
e.clientY, |
|
|
|
|
|
) |
|
|
|
|
|
if (keyData! === null) { |
|
|
|
|
|
keysOnRef.current = keysOnRef.current.filter((k) => k.id !== -1) |
|
|
|
|
|
if (typeof onChange! === 'function') { |
|
|
|
|
|
onChange(keysOnRef.current) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const [mouseKey = null] = keysOnRef.current.filter((k) => k.id === -1) |
|
|
|
|
|
if (mouseKey === null) { |
|
|
|
|
|
keysOnRef.current = keysOnRef.current.filter((k) => k.id !== -1) |
|
|
|
|
|
if (typeof onChange! === 'function') { |
|
|
|
|
|
onChange(keysOnRef.current) |
|
|
|
|
|
} |
|
|
|
|
|
return |
|
|
|
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
const [mouseKey = null] = keysOnRef.current.filter((k) => k.id === -1) |
|
|
|
|
|
if (mouseKey === null) { |
|
|
|
|
|
keysOnRef.current = keysOnRef.current.filter((k) => k.id !== -1) |
|
|
|
|
|
if (typeof onChange! === 'function') { |
|
|
|
|
|
onChange(keysOnRef.current) |
|
|
} |
|
|
} |
|
|
if (mouseKey.key !== keyData.key) { |
|
|
|
|
|
keysOnRef.current = [ |
|
|
|
|
|
...keysOnRef.current.filter((k) => k.id !== -1), |
|
|
|
|
|
{ ...keyData, velocity: lastVelocity.current, id: -1 }, |
|
|
|
|
|
] |
|
|
|
|
|
if (typeof onChange! === 'function') { |
|
|
|
|
|
onChange(keysOnRef.current) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
if (mouseKey.key !== keyData.key) { |
|
|
|
|
|
keysOnRef.current = [ |
|
|
|
|
|
...keysOnRef.current.filter((k) => k.id !== -1), |
|
|
|
|
|
{ ...keyData, velocity: lastVelocity.current, id: -1 }, |
|
|
|
|
|
] |
|
|
|
|
|
if (typeof onChange! === 'function') { |
|
|
|
|
|
onChange(keysOnRef.current) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
@@ -218,7 +237,29 @@ const KeyboardMap: React.FC<Props> = ({ accidentalKeyLengthRatio, onChange, keyb |
|
|
return () => { |
|
|
return () => { |
|
|
window.removeEventListener('touchend', handleTouchEnd) |
|
|
window.removeEventListener('touchend', handleTouchEnd) |
|
|
} |
|
|
} |
|
|
}) |
|
|
|
|
|
|
|
|
}, [onChange]) |
|
|
|
|
|
|
|
|
|
|
|
React.useEffect(() => { |
|
|
|
|
|
const handleTouchCancel = (e: TouchEvent) => { |
|
|
|
|
|
if (baseRef.current === null) { |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
if (baseRef.current.parentElement === null) { |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
Array.from(e.changedTouches).forEach((t) => { |
|
|
|
|
|
keysOnRef.current = keysOnRef.current.filter((k) => k.id !== t.identifier) |
|
|
|
|
|
lastVelocity.current = undefined |
|
|
|
|
|
if (typeof onChange! === 'function') { |
|
|
|
|
|
onChange(keysOnRef.current) |
|
|
|
|
|
} |
|
|
|
|
|
}) |
|
|
|
|
|
} |
|
|
|
|
|
window.addEventListener('touchcancel', handleTouchCancel) |
|
|
|
|
|
return () => { |
|
|
|
|
|
window.removeEventListener('touchcancel', handleTouchCancel) |
|
|
|
|
|
} |
|
|
|
|
|
}, [onChange]) |
|
|
|
|
|
|
|
|
React.useEffect(() => { |
|
|
React.useEffect(() => { |
|
|
const handleMouseUp = (e: MouseEvent) => { |
|
|
const handleMouseUp = (e: MouseEvent) => { |
|
@@ -244,16 +285,16 @@ const KeyboardMap: React.FC<Props> = ({ accidentalKeyLengthRatio, onChange, keyb |
|
|
|
|
|
|
|
|
React.useEffect(() => { |
|
|
React.useEffect(() => { |
|
|
const baseRefComponent = baseRef.current |
|
|
const baseRefComponent = baseRef.current |
|
|
|
|
|
const theKeyboardMapping = keyboardMapping as Record<string, number> |
|
|
const handleKeyDown = (e: KeyboardEvent) => { |
|
|
const handleKeyDown = (e: KeyboardEvent) => { |
|
|
if (!keyboardMapping!) { |
|
|
|
|
|
|
|
|
if (!theKeyboardMapping) { |
|
|
return |
|
|
return |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (e.ctrlKey || e.altKey || e.metaKey || e.shiftKey) { |
|
|
if (e.ctrlKey || e.altKey || e.metaKey || e.shiftKey) { |
|
|
return |
|
|
return |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const { [e.code]: key = null } = keyboardMapping as Record<string, number> |
|
|
|
|
|
|
|
|
const { [e.code]: key = null } = theKeyboardMapping |
|
|
|
|
|
|
|
|
if (key === null) { |
|
|
if (key === null) { |
|
|
return |
|
|
return |
|
@@ -262,7 +303,7 @@ const KeyboardMap: React.FC<Props> = ({ accidentalKeyLengthRatio, onChange, keyb |
|
|
if (keysOnRef.current.some((k) => k.key === key && k.id === -2)) { |
|
|
if (keysOnRef.current.some((k) => k.key === key && k.id === -2)) { |
|
|
return |
|
|
return |
|
|
} |
|
|
} |
|
|
keysOnRef.current = [...keysOnRef.current, { key, velocity: 0.75, id: -2 }] |
|
|
|
|
|
|
|
|
keysOnRef.current = [...keysOnRef.current, { key, velocity: keyboardVelocity, id: -2 }] |
|
|
if (typeof onChange! === 'function') { |
|
|
if (typeof onChange! === 'function') { |
|
|
onChange(keysOnRef.current) |
|
|
onChange(keysOnRef.current) |
|
|
} |
|
|
} |
|
@@ -276,19 +317,19 @@ const KeyboardMap: React.FC<Props> = ({ accidentalKeyLengthRatio, onChange, keyb |
|
|
baseRefComponent.removeEventListener('keydown', handleKeyDown) |
|
|
baseRefComponent.removeEventListener('keydown', handleKeyDown) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
}) |
|
|
|
|
|
|
|
|
}, [onChange, keyboardMapping, keyboardVelocity]) |
|
|
|
|
|
|
|
|
React.useEffect(() => { |
|
|
React.useEffect(() => { |
|
|
|
|
|
const theKeyboardMapping = keyboardMapping as Record<string, number> |
|
|
const handleKeyUp = (e: KeyboardEvent) => { |
|
|
const handleKeyUp = (e: KeyboardEvent) => { |
|
|
if (!keyboardMapping!) { |
|
|
|
|
|
|
|
|
if (!theKeyboardMapping) { |
|
|
return |
|
|
return |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (e.ctrlKey || e.altKey || e.metaKey || e.shiftKey) { |
|
|
if (e.ctrlKey || e.altKey || e.metaKey || e.shiftKey) { |
|
|
return |
|
|
return |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const { [e.code]: key = null } = keyboardMapping as Record<string, number> |
|
|
|
|
|
|
|
|
const { [e.code]: key = null } = theKeyboardMapping |
|
|
|
|
|
|
|
|
if (key === null) { |
|
|
if (key === null) { |
|
|
return |
|
|
return |
|
@@ -304,7 +345,57 @@ const KeyboardMap: React.FC<Props> = ({ accidentalKeyLengthRatio, onChange, keyb |
|
|
return () => { |
|
|
return () => { |
|
|
window.removeEventListener('keyup', handleKeyUp) |
|
|
window.removeEventListener('keyup', handleKeyUp) |
|
|
} |
|
|
} |
|
|
}) |
|
|
|
|
|
|
|
|
}, [onChange, keyboardMapping]) |
|
|
|
|
|
|
|
|
|
|
|
React.useEffect(() => { |
|
|
|
|
|
const handleMidiMessage = (e: MIDIMessageEvent) => { |
|
|
|
|
|
const arg0 = e.data[0] |
|
|
|
|
|
const arg1 = e.data[1] |
|
|
|
|
|
const arg2 = e.data[2] |
|
|
|
|
|
|
|
|
|
|
|
let key: number |
|
|
|
|
|
let velocity: number |
|
|
|
|
|
|
|
|
|
|
|
switch (arg0 & 0b11110000) { |
|
|
|
|
|
case 0b10010000: |
|
|
|
|
|
velocity = arg2 & 0b01111111 |
|
|
|
|
|
key = arg1 & 0b01111111 |
|
|
|
|
|
if (velocity > 0) { |
|
|
|
|
|
keysOnRef.current = [ |
|
|
|
|
|
...keysOnRef.current, |
|
|
|
|
|
{ |
|
|
|
|
|
key, |
|
|
|
|
|
velocity: velocity / 127, |
|
|
|
|
|
id: -3, |
|
|
|
|
|
}, |
|
|
|
|
|
] |
|
|
|
|
|
} else { |
|
|
|
|
|
keysOnRef.current = keysOnRef.current.filter((k) => k.key !== key) |
|
|
|
|
|
} |
|
|
|
|
|
if (typeof onChange! === 'function') { |
|
|
|
|
|
onChange(keysOnRef.current) |
|
|
|
|
|
} |
|
|
|
|
|
break |
|
|
|
|
|
case 0b10000000: |
|
|
|
|
|
key = arg1 & 0b01111111 |
|
|
|
|
|
keysOnRef.current = keysOnRef.current.filter((k) => k.key !== key) |
|
|
|
|
|
if (typeof onChange! === 'function') { |
|
|
|
|
|
onChange(keysOnRef.current) |
|
|
|
|
|
} |
|
|
|
|
|
break |
|
|
|
|
|
default: |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
if (midiInput!) { |
|
|
|
|
|
midiInput!.addEventListener('midimessage', handleMidiMessage) |
|
|
|
|
|
} |
|
|
|
|
|
return () => { |
|
|
|
|
|
if (midiInput!) { |
|
|
|
|
|
midiInput!.removeEventListener('midimessage', handleMidiMessage) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
}, [midiInput, onChange]) |
|
|
|
|
|
|
|
|
return ( |
|
|
return ( |
|
|
<div |
|
|
<div |
|
@@ -319,10 +410,9 @@ const KeyboardMap: React.FC<Props> = ({ accidentalKeyLengthRatio, onChange, keyb |
|
|
outline: 0, |
|
|
outline: 0, |
|
|
cursor: 'pointer', |
|
|
cursor: 'pointer', |
|
|
}} |
|
|
}} |
|
|
onContextMenu={handleContextMenu} |
|
|
|
|
|
onDragStart={handleDragStart} |
|
|
|
|
|
|
|
|
onContextMenu={preventDefault} |
|
|
|
|
|
onDragStart={preventDefault} |
|
|
onMouseDown={handleMouseDown} |
|
|
onMouseDown={handleMouseDown} |
|
|
onTouchStart={handleTouchStart} |
|
|
|
|
|
tabIndex={0} |
|
|
tabIndex={0} |
|
|
/> |
|
|
/> |
|
|
) |
|
|
) |
|
|