Chapter 8, Episode 8

User Control: Keyboard Input

Learn how to handle keyboard events in JavaScript to create interactive, user-controlled animations and games.

The McTweak Agency Office

TrashyMcTweak

TrashyMcTweak

Who the hell just used MY keyboard?! There are crumbs EVERYWHERE! This is high-precision equipment for creating digital MASTERPIECES, not a goddamn picnic table!

FattyMcTweak

FattyMcTweak

Oh relax. I only borrowed it for a minute while mine was... updating. Besides, those aren't just ANY crumbs—those are artisanal sourdough breadcrumbs. Premium input requires premium snacks.

TrashyMcTweak

TrashyMcTweak

Great, now my W, A, S, and D keys are sticking! You know those are the most important keys for game controls! What were you even doing?

FattyMcTweak

FattyMcTweak

Testing a premium keyboard-controlled animation system, obviously. Users pay top dollar for my smooth movement algorithms. Those aren't just directional keys—they're gateways to immersive user experiences!

GrumpyMcTweak

GrumpyMcTweak

BOTH OF YOU SHUT UP! Do you have ANY idea of the security vulnerabilities in keyboard event listeners?! One rogue keypress and we could be EXPOSING USER DATA to the ENTIRE INTERNET!

AllyMcTweak

AllyMcTweak

Oh please, Grumpy. Not every keyboard input is trying to hack the Pentagon. Our student today actually needs to learn about keyboard controls for their game project. And I'm pretty sure they don't need a lecture about how the space bar is secretly communicating with SkyNet.

CodyMcTweak

CodyMcTweak

Um... I think I can help with this one! Even with my limited processing power, I can handle basic keyboard inputs pretty well! It's... kind of all I can afford to process, honestly.

GarbageMcTweak

GarbageMcTweak

*without looking up from his gaming console* The problem with modern keyboard handlers is nobody bothers to comment their code. The number of times I've had to debug event listeners with zero context... *sighs deeply*

AshleyMcTweak

AshleyMcTweak

Alright, enough bickering. Let's provide our student with a PROPERLY DOCUMENTED keyboard controller example. We have legal obligations for educational clarity. Also Fatty, clean those keys RIGHT NOW or I'm adding a "food damage" clause to your contract.

1. Understanding Keyboard Events

Before we dive into coding, let's understand the keyboard events available in JavaScript:

  • keydown - Triggered when a key is pressed down
  • keyup - Triggered when a key is released
  • keypress - Triggered when a key is pressed (but not for all keys like Shift, Ctrl, etc.)
CodyMcTweak

CodyMcTweak

For most games and animations, we'll use keydown and keyup events. They're more reliable and work for all keys!

Setting Up a Basic Keyboard Listener

Let's start with a simple example that detects when arrow keys are pressed:

// First, we need to add an event listener to the document document.addEventListener('keydown', handleKeyDown); // This function will run every time a key is pressed function handleKeyDown(event) { // The 'key' property tells us which key was pressed console.log('Key pressed:', event.key); // We can check for specific keys if (event.key === 'ArrowUp') { console.log('Up arrow was pressed!'); } else if (event.key === 'ArrowDown') { console.log('Down arrow was pressed!'); } else if (event.key === 'ArrowLeft') { console.log('Left arrow was pressed!'); } else if (event.key === 'ArrowRight') { console.log('Right arrow was pressed!'); } }
GrumpyMcTweak

GrumpyMcTweak

NOT ENOUGH COMMENTS! Every line needs to explain EXACTLY what it's doing! Security depends on clarity!

TrashyMcTweak

TrashyMcTweak

Oh come on! This code is so basic even Cody could understand it. Let's not insult our students' intelligence.

CodyMcTweak

CodyMcTweak

Hey! I... actually that's fair.

2. Building a Keyboard-Controlled Character

Now let's create a simple character that moves with the arrow keys:

// HTML Structure needed: // <div id="game-container" style="position: relative; width: 600px; height: 400px; border: 1px solid black;"> // <div id="character" style="position: absolute; width: 50px; height: 50px; background-color: red;"></div> // </div> // First, get references to our HTML elements const character = document.getElementById('character'); // Set initial position let x = 275; // Center horizontally (600/2 - 50/2) let y = 175; // Center vertically (400/2 - 50/2) let speed = 5; // How many pixels to move per key press // Update the character's position on screen function updateCharacterPosition() { character.style.left = x + 'px'; character.style.top = y + 'px'; } // Handle key presses function handleKeyDown(event) { // Move character based on which arrow key was pressed switch(event.key) { case 'ArrowUp': y -= speed; // Move up break; case 'ArrowDown': y += speed; // Move down break; case 'ArrowLeft': x -= speed; // Move left break; case 'ArrowRight': x += speed; // Move right break; } // Update the character's visual position updateCharacterPosition(); } // Add event listener for keyboard input document.addEventListener('keydown', handleKeyDown); // Set initial position when page loads updateCharacterPosition();

Checkpoint: Basic Movement

Now we have a character that moves when we press the arrow keys! Let's see it in action:

Use arrow keys to move
FattyMcTweak

FattyMcTweak

That's it? That's what my expensive keyboard was sacrificed for? The movement is jerky! There's no boundary detection! Where's the PREMIUM experience I'm known for?!

AllyMcTweak

AllyMcTweak

Calm down, we're teaching step by step. Let me add some improvements that won't break the bank for our students.

3. Adding Smooth Movement and Boundaries

Let's improve our character movement with these features:

  • Smooth, continuous movement
  • Boundary detection to prevent going off-screen
  • Support for multiple keys pressed at once
// Keep track of which keys are currently pressed const keys = { ArrowUp: false, ArrowDown: false, ArrowLeft: false, ArrowRight: false }; // Game settings const gameWidth = 600; const gameHeight = 300; const charWidth = 50; const charHeight = 50; let x = gameWidth / 2 - charWidth / 2; // Center horizontally let y = gameHeight / 2 - charHeight / 2; // Center vertically let speed = 3; // Pixels per frame // Listen for key down events document.addEventListener('keydown', function(event) { // Update our keys object when keys are pressed if (keys.hasOwnProperty(event.key)) { keys[event.key] = true; // Prevent default behavior (like page scrolling) event.preventDefault(); } }); // Listen for key up events document.addEventListener('keyup', function(event) { // Update our keys object when keys are released if (keys.hasOwnProperty(event.key)) { keys[event.key] = false; } }); // The game loop that runs continuously function gameLoop() { // Move character based on which keys are pressed if (keys.ArrowUp) { y -= speed; // Move up } if (keys.ArrowDown) { y += speed; // Move down } if (keys.ArrowLeft) { x -= speed; // Move left } if (keys.ArrowRight) { x += speed; // Move right } // Add boundary detection to keep character on screen // Left boundary if (x < 0) { x = 0; } // Right boundary if (x > gameWidth - charWidth) { x = gameWidth - charWidth; } // Top boundary if (y < 0) { y = 0; } // Bottom boundary if (y > gameHeight - charHeight) { y = gameHeight - charHeight; } // Update the character's position character.style.left = x + 'px'; character.style.top = y + 'px'; // Call this function again on the next frame (60 times per second) requestAnimationFrame(gameLoop); } // Start the game loop gameLoop();
GarbageMcTweak

GarbageMcTweak

Better. Using requestAnimationFrame instead of setInterval shows at least some basic understanding of animation principles.

GrumpyMcTweak

GrumpyMcTweak

I still don't see any error handling! What if the game container doesn't exist? What if the browser doesn't support requestAnimationFrame? CHAOS! DOOM!

Use arrow keys to move (smoother with boundaries)

4. Adding WASD Controls and Visual Feedback

Let's enhance our game with alternative controls and visual feedback when moving:

// Expanded key tracking to include both WASD and arrow keys const keys = { ArrowUp: false, ArrowDown: false, ArrowLeft: false, ArrowRight: false, w: false, // Alternative up s: false, // Alternative down a: false, // Alternative left d: false // Alternative right }; // Game settings const gameWidth = 600; const gameHeight = 300; const charWidth = 50; const charHeight = 50; let x = gameWidth / 2 - charWidth / 2; let y = gameHeight / 2 - charHeight / 2; let speed = 3; let isMoving = false; // Track if character is moving // Get reference to character element const character = document.getElementById('character-3'); // Listen for key events document.addEventListener('keydown', function(event) { // Convert key to lowercase to handle both upper and lower case const key = event.key.toLowerCase(); // Update our keys object when keys are pressed if (keys.hasOwnProperty(key)) { keys[key] = true; isMoving = true; event.preventDefault(); } }); document.addEventListener('keyup', function(event) { // Convert key to lowercase to handle both upper and lower case const key = event.key.toLowerCase(); // Update our keys object when keys are released if (keys.hasOwnProperty(key)) { keys[key] = false; // Check if any movement keys are still pressed isMoving = Object.values(keys).some(value => value === true); } }); function gameLoop() { // Handle vertical movement (up/down) if (keys.ArrowUp || keys.w) { y -= speed; } if (keys.ArrowDown || keys.s) { y += speed; } // Handle horizontal movement (left/right) if (keys.ArrowLeft || keys.a) { x -= speed; } if (keys.ArrowRight || keys.d) { x += speed; } // Boundary detection x = Math.max(0, Math.min(gameWidth - charWidth, x)); y = Math.max(0, Math.min(gameHeight - charHeight, y)); // Update visual appearance based on movement state if (isMoving) { character.style.backgroundColor = '#4ade80'; // Green when moving character.style.boxShadow = '0 0 15px #4ade80'; // Glow effect } else { character.style.backgroundColor = '#38bdf8'; // Blue when idle character.style.boxShadow = '0 0 5px #38bdf8'; // Subtle glow } // Update position character.style.left = x + 'px'; character.style.top = y + 'px'; // Continue the game loop requestAnimationFrame(gameLoop); } // Start the game loop gameLoop();
FattyMcTweak

FattyMcTweak

NOW we're talking! Visual feedback, WASD support, smooth boundaries... almost worth the breadcrumbs sacrificed to my keyboard!

Use ARROW KEYS or WASD to move

5. Best Practices for Keyboard Controls

  • Prevent Default Actions - Use event.preventDefault() to stop browser scrolling with arrow keys
  • Support Multiple Control Schemes - Offer arrow keys and WASD for broader accessibility
  • Track Key States - Use an object to track which keys are pressed rather than responding to individual events
  • Handle Boundaries - Always implement boundary detection to keep objects within their container
  • Provide Visual Feedback - Change appearance to indicate when movement occurs
  • Comment Your Code - Clearly document your keyboard control logic
TrashyMcTweak

TrashyMcTweak

Yeah yeah, all this basic stuff is fine, but where's the CREATIVITY? Let's add something UNEXPECTED! Maybe the character could leave a rainbow trail? Or explode into confetti when it hits the edge? Or—

AshleyMcTweak

AshleyMcTweak

Trashy, please. One step at a time. We're still teaching fundamentals. The student needs to master keyboard inputs before adding your... creative enhancements.

6. Challenge: Create Your Own Controlled Character

Now it's your turn! Use what you've learned to create a character that:

  1. Moves with keyboard controls (arrow keys and/or WASD)
  2. Stays within screen boundaries
  3. Changes appearance when moving
  4. Has well-commented code explaining how it works
SnowzieMcTweak

SnowzieMcTweak

*excited barking* Woof! Woof!

GarbageMcTweak

GarbageMcTweak

Snowzie approves of the code. Well-commented keyboard controls are fundamental to good game development. Take note: even the dog understands the importance of clear documentation.

CODE IS COMMITTED!

God is good, hug your Elkhound.