2017-04-17 15:10:04 -04:00
|
|
|
const Cast = require('../util/cast');
|
2016-09-02 11:23:09 -04:00
|
|
|
|
2017-04-17 19:42:48 -04:00
|
|
|
class Keyboard {
|
|
|
|
constructor (runtime) {
|
|
|
|
/**
|
|
|
|
* List of currently pressed keys.
|
|
|
|
* @type{Array.<number>}
|
|
|
|
*/
|
|
|
|
this._keysPressed = [];
|
|
|
|
/**
|
|
|
|
* Reference to the owning Runtime.
|
|
|
|
* Can be used, for example, to activate hats.
|
|
|
|
* @type{!Runtime}
|
|
|
|
*/
|
|
|
|
this.runtime = runtime;
|
|
|
|
}
|
|
|
|
|
2016-09-03 16:33:45 -04:00
|
|
|
/**
|
2017-04-17 19:42:48 -04:00
|
|
|
* Convert a Scratch key name to a DOM keyCode.
|
|
|
|
* @param {Any} keyName Scratch key argument.
|
|
|
|
* @return {number} Key code corresponding to a DOM event.
|
|
|
|
* @private
|
2016-09-03 16:33:45 -04:00
|
|
|
*/
|
2017-04-17 19:42:48 -04:00
|
|
|
_scratchKeyToKeyCode (keyName) {
|
|
|
|
if (typeof keyName === 'number') {
|
|
|
|
// Key codes placed in with number blocks.
|
|
|
|
return keyName;
|
|
|
|
}
|
|
|
|
const keyString = Cast.toString(keyName);
|
|
|
|
switch (keyString) {
|
|
|
|
case 'space': return 32;
|
|
|
|
case 'left arrow': return 37;
|
|
|
|
case 'up arrow': return 38;
|
|
|
|
case 'right arrow': return 39;
|
|
|
|
case 'down arrow': return 40;
|
|
|
|
// @todo: Consider adding other special keys here.
|
|
|
|
}
|
|
|
|
// Keys reported by DOM keyCode are upper case.
|
|
|
|
return keyString.toUpperCase().charCodeAt(0);
|
2016-09-02 11:23:09 -04:00
|
|
|
}
|
|
|
|
|
2017-04-17 19:42:48 -04:00
|
|
|
/**
|
|
|
|
* Convert a DOM keyCode into a Scratch key name.
|
|
|
|
* @param {number} keyCode Key code from DOM event.
|
|
|
|
* @return {Any} Scratch key argument.
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
_keyCodeToScratchKey (keyCode) {
|
|
|
|
if (keyCode >= 48 && keyCode <= 90) {
|
|
|
|
// Standard letter.
|
|
|
|
return String.fromCharCode(keyCode).toLowerCase();
|
|
|
|
}
|
|
|
|
switch (keyCode) {
|
|
|
|
case 32: return 'space';
|
|
|
|
case 37: return 'left arrow';
|
|
|
|
case 38: return 'up arrow';
|
|
|
|
case 39: return 'right arrow';
|
|
|
|
case 40: return 'down arrow';
|
|
|
|
}
|
|
|
|
return '';
|
2016-09-03 16:33:45 -04:00
|
|
|
}
|
|
|
|
|
2017-04-17 19:42:48 -04:00
|
|
|
/**
|
|
|
|
* Keyboard DOM event handler.
|
|
|
|
* @param {object} data Data from DOM event.
|
|
|
|
*/
|
|
|
|
postData (data) {
|
|
|
|
if (data.keyCode) {
|
|
|
|
const index = this._keysPressed.indexOf(data.keyCode);
|
|
|
|
if (data.isDown) {
|
|
|
|
// If not already present, add to the list.
|
|
|
|
if (index < 0) {
|
|
|
|
this._keysPressed.push(data.keyCode);
|
|
|
|
}
|
|
|
|
// Always trigger hats, even if it was already pressed.
|
|
|
|
this.runtime.startHats('event_whenkeypressed', {
|
|
|
|
KEY_OPTION: this._keyCodeToScratchKey(data.keyCode)
|
|
|
|
});
|
|
|
|
this.runtime.startHats('event_whenkeypressed', {
|
|
|
|
KEY_OPTION: 'any'
|
|
|
|
});
|
|
|
|
} else if (index > -1) {
|
|
|
|
// If already present, remove from the list.
|
|
|
|
this._keysPressed.splice(index, 1);
|
2016-09-02 11:23:09 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-17 19:42:48 -04:00
|
|
|
/**
|
|
|
|
* Get key down state for a specified Scratch key name.
|
|
|
|
* @param {Any} key Scratch key argument.
|
|
|
|
* @return {boolean} Is the specified key down?
|
|
|
|
*/
|
|
|
|
getKeyIsDown (key) {
|
|
|
|
if (key === 'any') {
|
|
|
|
return this._keysPressed.length > 0;
|
|
|
|
}
|
|
|
|
const keyCode = this._scratchKeyToKeyCode(key);
|
|
|
|
return this._keysPressed.indexOf(keyCode) > -1;
|
2016-09-02 11:23:09 -04:00
|
|
|
}
|
2017-04-17 19:42:48 -04:00
|
|
|
}
|
2016-09-02 11:23:09 -04:00
|
|
|
|
|
|
|
module.exports = Keyboard;
|