How to Map Physical Keys to React Buttons
Get the project source code below, and follow along with the lesson material.
Download Project Source CodeTo set up the project on your local machine, please follow the directions provided in the README.md
file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.
Lesson Transcript
[00:00 - 00:05] Mapping real keys to virtual. Right now, our keyboard can play sounds when pressed by mouse click.
[00:06 - 00:17] However, we want to play notes when a user presses corresponding keys on their real keyboard. To do that, we want to map real keys with virtual ones so that when a user presses a key, our application would know what to do and which note to play.
[00:18 - 00:26] We create a component that will implement another pattern called "observer". Its main idea is to allow us to subscribe to some events and handle them as we want to.
[00:27 - 00:32] In our case, we want to subscribe to keypress events. Let's start again with designing an API.
[00:33 - 00:47] Create a new file, "src components press observer use press observer.ts" Here we want to define a bunch of type aliases first. Type is pressed.
[00:48 - 00:51] That will track if the button is pressed. It's going to be an alias to Boolean.
[00:52 - 01:03] Type event code is going to be an alias to type string. Type callback function is going to be an alias to a function that does not return any value.
[01:04 - 01:11] Now, let's define the settings type. Type settings is going to be an object with watch key of type key label.
[01:12 - 01:25] Key label is actually just a renamed key from domain keyboard. OnStartPress is a callback function, same as onFinishPress.
[01:26 - 01:37] The watch key defines what key do we want to observe. The onStartPress and onFinishPress are the handlers for when a user presses a key and leaves their finger up respectively.
[01:38 - 01:50] Define the hook, "export function use press observer". We want to get watch key onStartPress onFinishPress.
[01:51 - 01:56] The type of the props here is settings. As a result, we are going to return is pressed.
[01:57 - 02:07] It is our alias to a Boolean type. Define the state, pressed and a setter, set pressed, use state of type is pressed and default value false.
[02:08 - 02:10] We can immediately return it. Return pressed.
[02:11 - 02:23] Most of the work is going to happen inside of the use effect hook. This use effect is going to observe watch key, the pressed state, the set pressed, callback, the onStartPress and onFinishPress.
[02:24 - 02:31] Basically, everything. Inside of it, we will define the handlePressStart and handlePressFinishEventH enders.
[02:32 - 02:50] Function handlePressStart is going to receive the code from the event of type keyboard. We will return nothing and we will check if it is pressed or the watch key is not equal to the code that we received, then we return.
[02:51 - 03:05] So if the button is already pressed or whatever code we received is not the same as we are watching for, then we do nothing. Otherwise, we set pressed true and also call onStartPress.
[03:06 - 03:17] Let's define the equal function that we have used here. Function equal, we will just compare the watch key of type key label with the event code of type event code.
[03:18 - 03:34] The result is going to be a Boolean. Inside of it, we will return the result of comparison of the from event code, event code to upper case with the watched key to upper case.
[03:35 - 03:51] The from event code function is going to receive the code of type event code and return a key label const prefix regex equals key or digit. We look for it globally and ignore the case.
[03:52 - 04:05] Then return code replace prefix regex with an empty string. So basically, we transform the key from the event code by removing the word key or digit from the beginning.
[04:06 - 04:15] Then we transform it to upper case as well as the watched key and compare them. And this way, we know it was the same letter as we were actually watching for.
[04:16 - 04:25] All right. Now we check if it's pressed and the watch key and the code are not equal, then return otherwise set the press true and call the onStartPress.
[04:26 - 04:36] Now let's define the handlePressFinish function handlePressFinish. Here we also listen for the key codes and this function also returns nothing.
[04:37 - 04:54] Here we perform a similar check as in the previous function, but instead of checking the button is pressed, here we check for the notPress date and we also check if that's the relevant key. Then we set the pressed to false and call onFinishPress function.
[04:55 - 05:12] Now let's subscribe to key down on key up events document add event listener key down here we call handlePressStart and also subscribe to key up handlePressFinish. Define a cleanup function and return it.
[05:13 - 05:30] That will remove the event listeners. Inside of this function, we take those two event listeners that we subscribe before and instead of add, we call remove and make sure to use or instead of N in the press handlers, otherwise you will press all the keys at once.
[05:31 - 05:55] Hit an index file index.ts, export everything from usePressObserver, open the key.tsx, get the pressed state using the usePressObserver, pass watch key, the label onStart Press onDown, onFinishPress onUp. Add a new conditional class.
[05:56 - 06:09] It depends on the pressed state and we add the style is pressed. Alright, now we've connected the button to our observer by passing the onDown and onUp handles to the onStartPress and onStartFinish.
[06:10 - 06:15] If you open your app, you should be able to play some notes by pressing the physical keyboard keys. (light music)
This lesson preview is part of the Fullstack React with TypeScript Masterclass course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.
Get unlimited access to Fullstack React with TypeScript Masterclass, plus 70+ \newline books, guides and courses with the \newline Pro subscription.
![Thumbnail for the \newline course Fullstack React with TypeScript Masterclass](/_next/image?url=https%3A%2F%2Fs3.amazonaws.com%2Fassets.fullstack.io%2Fn%2F20220425171607321_CoverImage_FSReactWTypeScript_Masterclas.png&w=3840&q=75)