Last active
November 24, 2021 05:08
-
-
Save osteele/986252244a0e7973ca3ffe92f85fef18 to your computer and use it in GitHub Desktop.
Demonstrate how to keep track of currently held keyboard keys in Processing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* This sketch demonstrates how to keep track of which keyboard keys are held | |
* down (pressed, and not released). Multiple keys can be held at the same time | |
* (if a second key is pressed before the first key is released). | |
* | |
* The list of currently-held keys is printed to the console each time a key is | |
* pressed or released. | |
* | |
* Instructions: | |
* 1. Run the sketch. | |
* 2. Click on the sketch window to select it. | |
* 3. Press and release keyboard keys. | |
* 4. Watch the console. | |
* 5. Try pressing and releasing multiple keys. | |
* | |
* Things to try: | |
* - Draw different things on the canvas depending on what keys are currently | |
* held. | |
* - Change the properties of an object (shape, color, stroke width) or the | |
* canvas (scale, translation, rotation) depending on what keys are currently | |
* held. | |
* - Can you design a two-player game where one player holds down one or more of | |
* QWERASDFZXCV and the other player uses UIOPJKL:NM<> ? | |
* | |
* The code can be modified to store values of `keyCode` instead of (or as well | |
* as) values of `key`. | |
* | |
* An alternative implementation, that uses `char[]` instead of `IntArray`, is | |
* available at https://gist.githubusercontent.com/osteele/54566a328c78cf12c000cbcea2e12a75 | |
* | |
* Author: Oliver Steele | |
* Date: 2021-11-23 | |
*/ | |
/** A list of all the keyboard keys that are currently held (have been pressed | |
* but not released). | |
* | |
* We use an IntList instead of an Array of integers `int[]` or characters | |
* `char[]`, because we don't know how many keys might be pressed at once so we | |
* don't know how large to make the array. | |
* | |
* `key` is a `char`, not an `int`, but it can be stored in a list or array of | |
* ints. | |
* | |
* Some alternatives to using IntList: | |
* - Use an array that is large enough to hold all the keys in the keyboard, | |
* and keep track of how much of the array is used. | |
* - Use an array, and use append() and shorten() to add and remove values. | |
* This implementation is at https://gist.githubusercontent.com/osteele/54566a328c78cf12c000cbcea2e12a75 | |
* - Use an array of `boolean`s to indicate whether a key is pressed or not. | |
*/ | |
IntList heldKeys = new IntList(); | |
void setup() { | |
size(100, 100); | |
} | |
// This sketch doesn't draw anything. However, if this function is not defined, | |
// Processing never calls keyPressed() or keyReleased(). | |
void draw() { | |
} | |
void keyPressed() { | |
// Because keyPressed() is called repeatedly while a key is held down, in | |
// addition to when it is first pressed, heldKeys may already contain the key. | |
// In this case, don't add it a second time, and don't print to the console | |
// again. | |
if (!heldKeys.hasValue(key)) { | |
heldKeys.append(key); | |
heldKeys.sort(); // this is optional, but it makes the output easier to read | |
printHeldKeys(); | |
} | |
} | |
void keyReleased() { | |
// It should always be the case that heldKeys contains key, but the | |
// conditional guard makes the code more robust in case this turns out not be | |
// true. (For example, what happens if the user is holding down some keys when | |
// the sketch starts running?) | |
if (heldKeys.hasValue(key)) { | |
intArrayListRemove(heldKeys, key); | |
printHeldKeys(); | |
} | |
} | |
/** Print the currently pressed keys to the console. */ | |
void printHeldKeys() { | |
print("Currently pressed keys: "); | |
var sep = ""; | |
for (var c: heldKeys) { | |
print(sep); | |
print(char(c)); | |
sep = " "; | |
} | |
if (heldKeys.size() == 0) { | |
print("none"); | |
} | |
println(); | |
} | |
/** Remove all occurrences of `value` from `arrayList`. If `arrayList` does not | |
* contain `value`, has no effect. */ | |
void intArrayListRemove(IntList arrayList, int value) { | |
for (int i = 0; i < arrayList.size(); i++) { | |
if (arrayList.get(i) == value) { | |
arrayList.remove(i); | |
// Decrement the loop counter so that the next iteration looks at the | |
// value that follows the one that was removed. This following value is | |
// now in arrayList.get(i) (the same index that the removed item | |
// previously occupied). | |
// | |
// Without this special case, this function would only remove the first | |
// value from a list that contained two values in a row. In this | |
// particular program, this will never happen; however, a function with a | |
// generic name such as this one might get used in other program where | |
// this matters; or, someone might modify the code that uses this | |
// function, without noticing the issue. | |
i--; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment