-
-
Notifications
You must be signed in to change notification settings - Fork 3.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Replaced deprecated keyCode functionality and docs with KeyboardEvent.code & KeyboardEvent.key also updates the keyIsDown function to accept alphanumerics as parameters #7472
base: dev-2.0
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for taking this on, this is a great start!
I think we might need to keep track of two downkey objects, one for code
s and one for key
s, in order to fully support querying of both.
/** | ||
* @typedef {18} ALT | ||
* @typedef {'AltLeft' | 'AltRight'} ALT |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason why the typedef is both of these while the constant is just one?
src/events/keyboard.js
Outdated
console.log('Current key:', this.key); | ||
|
||
// For backward compatibility - if code is a number | ||
if (typeof code === 'number') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this work if our key event handlers only set _downkeys[e.code]
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also @limzykenneth do you think we need backwards compatibility? We might need to put a lookup table like this https://stackoverflow.com/a/66180965 into our code to map old key codes to keys, although it looks like it's hard to get complete backwards compatibility. That's probably enough though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the numerical code has been deprecated as a standard, we can remove it since its the point of this implementation to use the easier code
property instead.
src/events/keyboard.js
Outdated
if (code.length === 1) { | ||
if (/[A-Za-z]/.test(code)) { | ||
// For letters, we need to check the actual key value | ||
return this.key === code; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this only checks if the last pressed key was the one passed in, rather than if that key is currently down. We might need to make two objects, _downKeyCodes
and _downKeys
, and update both on keydown/keyup.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
okay, got it
src/events/keyboard.js
Outdated
// For letters, we need to check the actual key value | ||
return this.key === code; | ||
} else if (/[0-9]/.test(code)) { | ||
return this._downKeys[`Digit${code}`] || false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably be consistent and check for keys if code.length === 1
and check for key codes otherwise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, we are currently checking with key
if code.length === 1
. and checking for code
otherwise. I'm assuming that we have to completely replace the usage the keyCode ig
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fully replacing event.keyCode
is correct! I think ideally we could tell users that if they pass in a code (e.g. 'Digits3'
), then it will check if that physical key is pressed, and if the user passes in a character (e.g. '3'
), it checks whether whatever key produces that character is pressed. I think that would mean we have to detect whether they passed in an event.key
or an event.code
, and then handling each branch separately.
The slight inconsistency right now is if the user passes in the string '3'
, it is checking for the physical key via the code
still.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, got it.
I think this logic might work, for allowing the user to enter both key and code and seperate classification of them
fn.keyIsDown = function(input){
if (typeof input ==='string'){
if (input.length === 1) {
return this._downKeys[input] ||
(/[0-9]/.test(input) && this._downKeyCodes[`Digit${input}`])
|| false;
}
return this._downKeyCodes[input] || this._downKeys[input] || false;
}
return false;
};
here _downKeyCodes is storing e.code and _downKeys is storing e.key.
now if user passes 'a'
or '3'
, this will be checked by key and returned true,
and if passes 'Digit3'
, this will be checked by code and returned true. and for special keys such as Enter, ' ', Shift, ShiftLeft, this will give true as they are getting checked for key or code.
Hence, user can use either key or code for the keyisDown function,
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good! It might makes sense to make a isCode()
function that we can call, so you can do:
fn.keyIsDown = function(input) {
if (isCode(input)) {
return this._downCodes[input];
} else {
return this._downKeys[input];
}
}
...and possibly also unit test isCode
separately too.
src/events/keyboard.js
Outdated
// For string inputs (new functionality) | ||
if (typeof code === 'string') { | ||
// Handle single character inputs | ||
if (code.length === 1) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should also add an else if branch to handle the multi-character possibilities for key
, for things like Enter and the arrow keys: https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values If it's one of those, we would need to check against down keys as opposed to down key codes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are some overlap between key
and code
, we'll need to decide which to prefer in case of overlap I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here, we are using key
only for the single characters(because of same code for characters i.e. keyA for 'a' and 'A') and for rest of the inputs we are using code
src/events/keyboard.js
Outdated
@@ -97,6 +97,8 @@ function keyboard(p5, fn){ | |||
*/ | |||
fn.isKeyPressed = false; | |||
fn.keyIsPressed = false; // khan | |||
fn._code = null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is only used in this module and not used by other modules through the instance, it should be a local variable and not attached to fn
if possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, currently user is able to do
text(key, 50, 50)
giving the key
of the key pressed.
Maybe the same can be done for code
with added documentation.
src/events/keyboard.js
Outdated
fn.keyIsDown = function(code) { | ||
// p5._validateParameters('keyIsDown', arguments); | ||
return this._downKeys[code] || false; | ||
p5.prototype.keyIsDown = function(code) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should still be fn.keyIsDown
and the indentation fixed.
src/events/keyboard.js
Outdated
// For backward compatibility - if code is a number | ||
if (typeof code === 'number') { | ||
return this._downKeys[code] || false; | ||
// If it's a single digit, it should be treated as a code (with "Digit" prefix) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason why we should treat single digits as codes rather than keys, like we would for alphabetic single characters?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, no specefic reason for that. for single character such as a
or A
, we cant use code
because of overlapping value KeyA
, while for numeric, it doesn't matter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If a user remaps their keyboard to a different layout, the codes will be the same as before, but the keys will be different, so there could be a difference still between handling the key for a digit and the code for a digit. If we automatically convert digits to codes, then there would be no way for a user to handle the keys for the digits, only the codes (e.g. if you pass in '1', it would turn into the code 'Digit1'
). If we don't special-case digits, though, then users can handle both, either by passing in '1'
if they want the key, or Digit1
if they want the code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, when I run the test script in preview/index.html.
It gives friendly error in console that keyisDown
is expecting number as parameter, not string.
I looked into the param_valdator
and validate_params
file but couldn't any call to keyboard.js file.
Can you guide me to how to fix this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh good catch! It gets the expected type from the comment above the function here:
Line 113 in 5709aac
* @property {String} key |
npm run docs
. Try giving that command a run and then testing it out again, does that fix it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this is an error in FES. For now just ignore parameter validation, I can handle that in a separate PR. For your own testing, you can set p5.disableFriendlyErrors = true
to avoid the error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm working on a fix in #7497, once that's merged you can update your fork to include new changes from dev-2.0 and it should be ok again!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure,
Also I had a problem while writing the tests, like after writing the tests for the new isCode function,
I am getting the isCode
not defined error while it is defined in the keyboard.js and also works when I test its usage in the preview file.
these are the tests,
suite('p5.prototype.isCode', function() {
test('returns false for non-string inputs', function() {
assert.isFalse(isCode(null));
assert.isFalse(isCode(undefined));
assert.isFalse(isCode(123));
assert.isFalse(isCode({}));
assert.isFalse(isCode([]));
});
test('returns false for single non-digit characters', function() {
assert.isFalse(isCode('a'));
assert.isFalse(isCode('Z'));
assert.isFalse(isCode('!'));
assert.isFalse(isCode(' '));
});
test('returns true for multi-character strings', function() {
assert.isTrue(isCode('Enter'));
assert.isTrue(isCode('ArrowUp'));
assert.isTrue(isCode('Shift'));
assert.isTrue(isCode('Control'));
assert.isTrue(isCode('ab'));
});
test('handles edge cases correctly', function() {
assert.isFalse(isCode('')); // empty string
assert.isTrue(isCode('11')); // multi-digit number
assert.isTrue(isCode('1a')); // digit + letter
});
});
i wanted to change this as per the updated logic but stuck here because of this. Can you recommend something for this.
The isCode function is like this,
fn.isCode = function(input){...}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd recommend moving isCode
outside of function keyboard
and exporting it, i.e.:
export function isCode(input) {
// ...
}
function keyboard(p5, fn) {
// ...
}
Then, in your test file, you can import it:
import { isCode } from '../../../src/events/keyboard.js';
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yupp this worked. Thanks!
return input.length > 1; | ||
} | ||
fn.keyIsDown = function(input) { | ||
if (isCode(input)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice!
Resolves #7436 and #6798
Changes:
This PR modernizes keyboard event handling by transitioning from the deprecated
keyCode
property to the modernKeyboardEvent.code
andKeyboardEvent.key
properties. This change improves keyboard input reliability and brings p5.js in line with current web standards.KeyboardEvent.code
instead ofe.which
_code
propertyconstants
to use modern string valuesScreenshots of the change:
/preview/index.html test sketch is:
PR Checklist
npm run lint
passes