mirror of
https://github.com/scratchfoundation/scratch-vm.git
synced 2025-06-12 13:31:18 -04:00
Merge 34cfc1f2aa
into f207757ef0
This commit is contained in:
commit
566d403ca8
3 changed files with 127 additions and 4 deletions
|
@ -12,6 +12,9 @@ class Scratch3EventBlocks {
|
|||
this.runtime.startHats('event_whenkeypressed', {
|
||||
KEY_OPTION: key
|
||||
});
|
||||
});
|
||||
|
||||
this.runtime.on('KEY_ANY_PRESSED', () => {
|
||||
this.runtime.startHats('event_whenkeypressed', {
|
||||
KEY_OPTION: 'any'
|
||||
});
|
||||
|
|
|
@ -10,9 +10,21 @@ const KEY_NAME = {
|
|||
UP: 'up arrow',
|
||||
RIGHT: 'right arrow',
|
||||
DOWN: 'down arrow',
|
||||
ENTER: 'enter'
|
||||
ENTER: 'enter',
|
||||
BACKSPACE: 'backspace',
|
||||
SHIFT: 'shift'
|
||||
};
|
||||
|
||||
/**
|
||||
* Names which don't count for the key "any" pressed? block. Items match the
|
||||
* values for KEY_NAME listed above. If a key isn't mentioned here, then it
|
||||
* does count for "any", provided Scratch detects that key at all.
|
||||
* @type {Array<string>}
|
||||
*/
|
||||
const KEY_NAMES_EXCLUDED_FOR_KEY_ANY_PRESSED = [
|
||||
'shift'
|
||||
];
|
||||
|
||||
/**
|
||||
* An array of the names of scratch keys.
|
||||
* @type {Array<string>}
|
||||
|
@ -58,6 +70,8 @@ class Keyboard {
|
|||
case 'Down':
|
||||
case 'ArrowDown': return KEY_NAME.DOWN;
|
||||
case 'Enter': return KEY_NAME.ENTER;
|
||||
case 'Backspace': return KEY_NAME.BACKSPACE;
|
||||
case 'Shift': return KEY_NAME.SHIFT;
|
||||
}
|
||||
// Ignore modifier keys
|
||||
if (keyString.length > 1) {
|
||||
|
@ -115,10 +129,19 @@ class Keyboard {
|
|||
postData (data) {
|
||||
if (!data.key) return;
|
||||
const scratchKey = this._keyStringToScratchKey(data.key);
|
||||
|
||||
if (scratchKey === '') return;
|
||||
const index = this._keysPressed.indexOf(scratchKey);
|
||||
|
||||
if (data.isDown) {
|
||||
// Emit a generic event indicating which key was pressed.
|
||||
this.runtime.emit('KEY_PRESSED', scratchKey);
|
||||
|
||||
// Emit a specific event indicating that some key valid for "any" was pressed.
|
||||
if (!KEY_NAMES_EXCLUDED_FOR_KEY_ANY_PRESSED.includes(scratchKey)) {
|
||||
this.runtime.emit('KEY_ANY_PRESSED');
|
||||
}
|
||||
|
||||
// If not already present, add to the list.
|
||||
if (index < 0) {
|
||||
this._keysPressed.push(scratchKey);
|
||||
|
@ -136,7 +159,8 @@ class Keyboard {
|
|||
*/
|
||||
getKeyIsDown (keyArg) {
|
||||
if (keyArg === 'any') {
|
||||
return this._keysPressed.length > 0;
|
||||
return this._keysPressed.some(key =>
|
||||
!KEY_NAMES_EXCLUDED_FOR_KEY_ANY_PRESSED.includes(key));
|
||||
}
|
||||
const scratchKey = this._keyArgToScratchKey(keyArg);
|
||||
return this._keysPressed.indexOf(scratchKey) > -1;
|
||||
|
|
|
@ -2,6 +2,37 @@ const test = require('tap').test;
|
|||
const Keyboard = require('../../src/io/keyboard');
|
||||
const Runtime = require('../../src/engine/runtime');
|
||||
|
||||
/**
|
||||
* Return a "live" object which tracks events that have been emitted. When an
|
||||
* event is emitted, the event object is pushed onto the corresponding array.
|
||||
* Use t.same() to match these (it strictly compares the array against the
|
||||
* expected value, including the length, i.e. number of tims emitted).
|
||||
*
|
||||
* Note that KEY_ANY_PRESSED doesn't emit any event details and so its array
|
||||
* should only contain `undefined`.
|
||||
*
|
||||
* @param {Runtime} rt - the runtime to listen for events on
|
||||
* @returns {object} live mapping of event name to emitted event values
|
||||
*/
|
||||
const listenForKeyboardEvents = function (rt) {
|
||||
const eventsEmitted = {
|
||||
KEY_PRESSED: [],
|
||||
KEY_ANY_PRESSED: []
|
||||
};
|
||||
|
||||
rt.on('KEY_PRESSED', event => {
|
||||
eventsEmitted.KEY_PRESSED.push(event);
|
||||
});
|
||||
|
||||
// Note that KEY_ANY_PRESSED doesn't emit any event details and so
|
||||
// the event value should be `undefined`.
|
||||
rt.on('KEY_ANY_PRESSED', event => {
|
||||
eventsEmitted.KEY_ANY_PRESSED.push(event);
|
||||
});
|
||||
|
||||
return eventsEmitted;
|
||||
};
|
||||
|
||||
test('spec', t => {
|
||||
const rt = new Runtime();
|
||||
const k = new Keyboard(rt);
|
||||
|
@ -15,89 +46,154 @@ test('spec', t => {
|
|||
test('space key', t => {
|
||||
const rt = new Runtime();
|
||||
const k = new Keyboard(rt);
|
||||
const eventsEmitted = listenForKeyboardEvents(rt);
|
||||
|
||||
k.postData({
|
||||
key: ' ',
|
||||
isDown: true
|
||||
});
|
||||
|
||||
t.strictDeepEquals(k._keysPressed, ['space']);
|
||||
|
||||
t.strictEquals(k.getKeyIsDown('space'), true);
|
||||
t.strictEquals(k.getKeyIsDown('any'), true);
|
||||
|
||||
t.same(eventsEmitted.KEY_PRESSED, ['space']);
|
||||
t.same(eventsEmitted.KEY_ANY_PRESSED, [undefined]);
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('letter key', t => {
|
||||
const rt = new Runtime();
|
||||
const k = new Keyboard(rt);
|
||||
const eventsEmitted = listenForKeyboardEvents(rt);
|
||||
|
||||
k.postData({
|
||||
key: 'a',
|
||||
isDown: true
|
||||
});
|
||||
|
||||
t.strictDeepEquals(k._keysPressed, ['A']);
|
||||
|
||||
t.strictEquals(k.getKeyIsDown(65), true);
|
||||
t.strictEquals(k.getKeyIsDown('a'), true);
|
||||
t.strictEquals(k.getKeyIsDown('A'), true);
|
||||
t.strictEquals(k.getKeyIsDown('any'), true);
|
||||
|
||||
t.same(eventsEmitted.KEY_PRESSED, ['A']);
|
||||
t.same(eventsEmitted.KEY_ANY_PRESSED, [undefined]);
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('number key', t => {
|
||||
const rt = new Runtime();
|
||||
const k = new Keyboard(rt);
|
||||
const eventsEmitted = listenForKeyboardEvents(rt);
|
||||
|
||||
k.postData({
|
||||
key: '1',
|
||||
isDown: true
|
||||
});
|
||||
|
||||
t.strictDeepEquals(k._keysPressed, ['1']);
|
||||
|
||||
t.strictEquals(k.getKeyIsDown(49), true);
|
||||
t.strictEquals(k.getKeyIsDown('1'), true);
|
||||
t.strictEquals(k.getKeyIsDown('any'), true);
|
||||
|
||||
t.same(eventsEmitted.KEY_PRESSED, ['1']);
|
||||
t.same(eventsEmitted.KEY_ANY_PRESSED, [undefined]);
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('non-english key', t => {
|
||||
const rt = new Runtime();
|
||||
const k = new Keyboard(rt);
|
||||
const eventsEmitted = listenForKeyboardEvents(rt);
|
||||
|
||||
k.postData({
|
||||
key: '日',
|
||||
isDown: true
|
||||
});
|
||||
|
||||
t.strictDeepEquals(k._keysPressed, ['日']);
|
||||
|
||||
t.strictEquals(k.getKeyIsDown('日'), true);
|
||||
t.strictEquals(k.getKeyIsDown('any'), true);
|
||||
|
||||
t.same(eventsEmitted.KEY_PRESSED, ['日']);
|
||||
t.same(eventsEmitted.KEY_ANY_PRESSED, [undefined]);
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('ignore modifier key', t => {
|
||||
test('shift key', t => {
|
||||
const rt = new Runtime();
|
||||
const k = new Keyboard(rt);
|
||||
const eventsEmitted = listenForKeyboardEvents(rt);
|
||||
|
||||
k.postData({
|
||||
key: 'Shift',
|
||||
isDown: true
|
||||
});
|
||||
t.strictDeepEquals(k._keysPressed, []);
|
||||
|
||||
t.strictDeepEquals(k._keysPressed, ['shift']);
|
||||
|
||||
t.strictEquals(k.getKeyIsDown('shift'), true);
|
||||
t.strictEquals(k.getKeyIsDown('any'), false);
|
||||
|
||||
t.same(eventsEmitted.KEY_PRESSED, ['shift']);
|
||||
t.same(eventsEmitted.KEY_ANY_PRESSED, []);
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('ignore control key', t => {
|
||||
const rt = new Runtime();
|
||||
const k = new Keyboard(rt);
|
||||
const eventsEmitted = listenForKeyboardEvents(rt);
|
||||
|
||||
k.postData({
|
||||
key: 'Control',
|
||||
isDown: true
|
||||
});
|
||||
|
||||
t.strictDeepEquals(k._keysPressed, []);
|
||||
|
||||
t.strictEquals(k.getKeyIsDown('control'), false);
|
||||
t.strictEquals(k.getKeyIsDown('any'), false);
|
||||
|
||||
t.same(eventsEmitted.KEY_PRESSED, []);
|
||||
t.same(eventsEmitted.KEY_ANY_PRESSED, []);
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('keyup', t => {
|
||||
const rt = new Runtime();
|
||||
const k = new Keyboard(rt);
|
||||
const eventsEmitted = listenForKeyboardEvents(rt);
|
||||
|
||||
k.postData({
|
||||
key: 'ArrowLeft',
|
||||
isDown: true
|
||||
});
|
||||
|
||||
k.postData({
|
||||
key: 'ArrowLeft',
|
||||
isDown: false
|
||||
});
|
||||
|
||||
t.strictDeepEquals(k._keysPressed, []);
|
||||
|
||||
t.strictEquals(k.getKeyIsDown('left arrow'), false);
|
||||
t.strictEquals(k.getKeyIsDown('any'), false);
|
||||
|
||||
t.same(eventsEmitted.KEY_PRESSED, ['left arrow']);
|
||||
t.same(eventsEmitted.KEY_ANY_PRESSED, [undefined]);
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue