@scratch/scratch-vm 11.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.jsdoc.json +20 -0
- package/.nvmrc +1 -0
- package/CHANGELOG.md +7004 -0
- package/LICENSE +12 -0
- package/README.md +120 -0
- package/TRADEMARK +1 -0
- package/commitlint.config.js +4 -0
- package/docs/extensions.md +527 -0
- package/package.json +103 -0
- package/release.config.js +13 -0
- package/src/blocks/scratch3_control.js +206 -0
- package/src/blocks/scratch3_core_example.js +69 -0
- package/src/blocks/scratch3_data.js +257 -0
- package/src/blocks/scratch3_event.js +137 -0
- package/src/blocks/scratch3_looks.js +612 -0
- package/src/blocks/scratch3_motion.js +288 -0
- package/src/blocks/scratch3_operators.js +154 -0
- package/src/blocks/scratch3_procedures.js +79 -0
- package/src/blocks/scratch3_sensing.js +336 -0
- package/src/blocks/scratch3_sound.js +350 -0
- package/src/dispatch/central-dispatch.js +143 -0
- package/src/dispatch/shared-dispatch.js +235 -0
- package/src/dispatch/worker-dispatch.js +110 -0
- package/src/engine/adapter.js +176 -0
- package/src/engine/block-utility.js +242 -0
- package/src/engine/blocks-execute-cache.js +19 -0
- package/src/engine/blocks-runtime-cache.js +78 -0
- package/src/engine/blocks.js +1299 -0
- package/src/engine/comment.js +56 -0
- package/src/engine/execute.js +580 -0
- package/src/engine/monitor-record.js +23 -0
- package/src/engine/mutation-adapter.js +48 -0
- package/src/engine/profiler.js +390 -0
- package/src/engine/runtime.js +2686 -0
- package/src/engine/scratch-blocks-constants.js +27 -0
- package/src/engine/sequencer.js +361 -0
- package/src/engine/stage-layering.js +29 -0
- package/src/engine/target.js +799 -0
- package/src/engine/thread.js +404 -0
- package/src/engine/variable.js +70 -0
- package/src/extension-support/argument-type.js +47 -0
- package/src/extension-support/block-type.js +50 -0
- package/src/extension-support/define-messages.js +18 -0
- package/src/extension-support/extension-manager.js +440 -0
- package/src/extension-support/extension-metadata.js +64 -0
- package/src/extension-support/extension-worker.js +59 -0
- package/src/extension-support/reporter-scope.js +18 -0
- package/src/extension-support/target-type.js +17 -0
- package/src/extensions/scratch3_boost/index.js +2113 -0
- package/src/extensions/scratch3_ev3/index.js +1355 -0
- package/src/extensions/scratch3_gdx_for/index.js +981 -0
- package/src/extensions/scratch3_gdx_for/scratch-link-device-adapter.js +44 -0
- package/src/extensions/scratch3_makeymakey/index.js +396 -0
- package/src/extensions/scratch3_microbit/index.js +984 -0
- package/src/extensions/scratch3_music/assets/drums/1-snare.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/drums/10-wood-block.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/drums/11-cowbell.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/drums/12-triangle.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/drums/13-bongo.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/drums/14-conga.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/drums/15-cabasa.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/drums/16-guiro.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/drums/17-vibraslap.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/drums/18-cuica.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/drums/2-bass-drum.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/drums/3-side-stick.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/drums/4-crash-cymbal.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/drums/5-open-hi-hat.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/drums/6-closed-hi-hat.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/drums/7-tambourine.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/drums/8-hand-clap.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/drums/9-claves.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/1-piano/108.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/1-piano/24.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/1-piano/36.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/1-piano/48.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/1-piano/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/1-piano/72.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/1-piano/84.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/1-piano/96.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/10-clarinet/48.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/10-clarinet/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/11-saxophone/36.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/11-saxophone/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/11-saxophone/84.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/12-flute/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/12-flute/72.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/13-wooden-flute/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/13-wooden-flute/72.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/14-bassoon/36.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/14-bassoon/48.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/14-bassoon/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/15-choir/48.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/15-choir/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/15-choir/72.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/16-vibraphone/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/16-vibraphone/72.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/17-music-box/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/18-steel-drum/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/19-marimba/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/2-electric-piano/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/20-synth-lead/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/21-synth-pad/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/3-organ/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/4-guitar/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/5-electric-guitar/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/6-bass/36.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/6-bass/48.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/7-pizzicato/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/8-cello/36.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/8-cello/48.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/8-cello/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/9-trombone/36.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/9-trombone/48.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/9-trombone/60.mp3 +0 -0
- package/src/extensions/scratch3_music/index.js +1333 -0
- package/src/extensions/scratch3_music/manifest.js +63 -0
- package/src/extensions/scratch3_pen/index.js +770 -0
- package/src/extensions/scratch3_speech2text/index.js +700 -0
- package/src/extensions/scratch3_text2speech/index.js +766 -0
- package/src/extensions/scratch3_translate/index.js +286 -0
- package/src/extensions/scratch3_video_sensing/debug.js +13 -0
- package/src/extensions/scratch3_video_sensing/index.js +594 -0
- package/src/extensions/scratch3_video_sensing/library.js +384 -0
- package/src/extensions/scratch3_video_sensing/math.js +76 -0
- package/src/extensions/scratch3_video_sensing/view.js +509 -0
- package/src/extensions/scratch3_wedo2/index.js +1616 -0
- package/src/import/load-costume.js +416 -0
- package/src/import/load-sound.js +116 -0
- package/src/index.js +10 -0
- package/src/io/ble.js +256 -0
- package/src/io/bt.js +202 -0
- package/src/io/clock.js +39 -0
- package/src/io/cloud.js +169 -0
- package/src/io/keyboard.js +146 -0
- package/src/io/mouse.js +145 -0
- package/src/io/mouseWheel.js +28 -0
- package/src/io/userData.js +24 -0
- package/src/io/video.js +210 -0
- package/src/playground/benchmark.css +83 -0
- package/src/playground/benchmark.js +753 -0
- package/src/playground/index.html +111 -0
- package/src/playground/suite.css +78 -0
- package/src/playground/suite.html +25 -0
- package/src/playground/suite.js +544 -0
- package/src/playground/video-sensing.html +18 -0
- package/src/playground/video-sensing.js +133 -0
- package/src/serialization/deserialize-assets.js +178 -0
- package/src/serialization/sb2.js +1295 -0
- package/src/serialization/sb2_specmap.js +1818 -0
- package/src/serialization/sb3.js +1320 -0
- package/src/serialization/serialize-assets.js +60 -0
- package/src/sprites/rendered-target.js +1115 -0
- package/src/sprites/sprite.js +177 -0
- package/src/util/base64-util.js +48 -0
- package/src/util/cast.js +218 -0
- package/src/util/clone.js +17 -0
- package/src/util/color.js +204 -0
- package/src/util/fetch-with-timeout.js +53 -0
- package/src/util/get-monitor-id.js +33 -0
- package/src/util/jsonrpc.js +114 -0
- package/src/util/log.js +4 -0
- package/src/util/math-util.js +122 -0
- package/src/util/maybe-format-message.js +18 -0
- package/src/util/new-block-ids.js +33 -0
- package/src/util/rateLimiter.js +73 -0
- package/src/util/scratch-link-websocket.js +133 -0
- package/src/util/string-util.js +94 -0
- package/src/util/task-queue.js +203 -0
- package/src/util/timer.js +103 -0
- package/src/util/uid.js +29 -0
- package/src/util/variable-util.js +48 -0
- package/src/util/xml-escape.js +33 -0
- package/src/virtual-machine.js +1586 -0
- package/webpack.config.js +134 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const Base64Util = require('../../util/base64-util');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Adapter class
|
|
5
|
+
*/
|
|
6
|
+
class ScratchLinkDeviceAdapter {
|
|
7
|
+
constructor (socket, {service, commandChar, responseChar}) {
|
|
8
|
+
this.socket = socket;
|
|
9
|
+
|
|
10
|
+
this._service = service;
|
|
11
|
+
this._commandChar = commandChar;
|
|
12
|
+
this._responseChar = responseChar;
|
|
13
|
+
this._onResponse = this._onResponse.bind(this);
|
|
14
|
+
this._deviceOnResponse = null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
get godirectAdapter () {
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
writeCommand (commandBuffer) {
|
|
22
|
+
const data = Base64Util.uint8ArrayToBase64(commandBuffer);
|
|
23
|
+
|
|
24
|
+
return this.socket
|
|
25
|
+
.write(this._service, this._commandChar, data, 'base64');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
setup ({onResponse}) {
|
|
29
|
+
this._deviceOnResponse = onResponse;
|
|
30
|
+
return this.socket
|
|
31
|
+
.startNotifications(this._service, this._responseChar, this._onResponse);
|
|
32
|
+
|
|
33
|
+
// TODO:
|
|
34
|
+
// How do we find out from scratch link if communication closes?
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
_onResponse (base64) {
|
|
38
|
+
const array = Base64Util.base64ToUint8Array(base64);
|
|
39
|
+
const response = new DataView(array.buffer);
|
|
40
|
+
return this._deviceOnResponse(response);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
module.exports = ScratchLinkDeviceAdapter;
|
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
const formatMessage = require('format-message');
|
|
2
|
+
const ArgumentType = require('../../extension-support/argument-type');
|
|
3
|
+
const BlockType = require('../../extension-support/block-type');
|
|
4
|
+
const Cast = require('../../util/cast');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Icon svg to be displayed at the left edge of each extension block, encoded as a data URI.
|
|
8
|
+
* @type {string}
|
|
9
|
+
*/
|
|
10
|
+
// eslint-disable-next-line max-len
|
|
11
|
+
const blockIconURI = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHN0eWxlPi5zdDJ7ZmlsbDpyZWR9LnN0M3tmaWxsOiNlMGUwZTB9LnN0NHtmaWxsOm5vbmU7c3Ryb2tlOiM2NjY7c3Ryb2tlLXdpZHRoOi41O3N0cm9rZS1taXRlcmxpbWl0OjEwfTwvc3R5bGU+PHBhdGggZD0iTTM1IDI4SDVhMSAxIDAgMCAxLTEtMVYxMmMwLS42LjQtMSAxLTFoMzBjLjUgMCAxIC40IDEgMXYxNWMwIC41LS41IDEtMSAxeiIgZmlsbD0iI2ZmZiIgaWQ9IkxheWVyXzYiLz48ZyBpZD0iTGF5ZXJfNCI+PHBhdGggY2xhc3M9InN0MiIgZD0iTTQgMjVoMzJ2Mi43SDR6TTEzIDI0aC0yLjJhMSAxIDAgMCAxLTEtMXYtOS43YzAtLjYuNC0xIDEtMUgxM2MuNiAwIDEgLjQgMSAxVjIzYzAgLjYtLjUgMS0xIDF6Ii8+PHBhdGggY2xhc3M9InN0MiIgZD0iTTYuMSAxOS4zdi0yLjJjMC0uNS40LTEgMS0xaDkuN2MuNSAwIDEgLjUgMSAxdjIuMmMwIC41LS41IDEtMSAxSDcuMWExIDEgMCAwIDEtMS0xeiIvPjxjaXJjbGUgY2xhc3M9InN0MiIgY3g9IjIyLjgiIGN5PSIxOC4yIiByPSIzLjQiLz48Y2lyY2xlIGNsYXNzPSJzdDIiIGN4PSIzMC42IiBjeT0iMTguMiIgcj0iMy40Ii8+PHBhdGggY2xhc3M9InN0MiIgZD0iTTQuMiAyN2gzMS45di43SDQuMnoiLz48L2c+PGcgaWQ9IkxheWVyXzUiPjxjaXJjbGUgY2xhc3M9InN0MyIgY3g9IjIyLjgiIGN5PSIxOC4yIiByPSIyLjMiLz48Y2lyY2xlIGNsYXNzPSJzdDMiIGN4PSIzMC42IiBjeT0iMTguMiIgcj0iMi4zIi8+PHBhdGggY2xhc3M9InN0MyIgZD0iTTEyLjUgMjIuOWgtMS4yYy0uMyAwLS41LS4yLS41LS41VjE0YzAtLjMuMi0uNS41LS41aDEuMmMuMyAwIC41LjIuNS41djguNGMwIC4zLS4yLjUtLjUuNXoiLz48cGF0aCBjbGFzcz0ic3QzIiBkPSJNNy4yIDE4Ljd2LTEuMmMwLS4zLjItLjUuNS0uNWg4LjRjLjMgMCAuNS4yLjUuNXYxLjJjMCAuMy0uMi41LS41LjVINy43Yy0uMyAwLS41LS4yLS41LS41ek00IDI2aDMydjJINHoiLz48L2c+PGcgaWQ9IkxheWVyXzMiPjxwYXRoIGNsYXNzPSJzdDQiIGQ9Ik0zNS4yIDI3LjlINC44YTEgMSAwIDAgMS0xLTFWMTIuMWMwLS42LjUtMSAxLTFoMzAuNWMuNSAwIDEgLjQgMSAxVjI3YTEgMSAwIDAgMS0xLjEuOXoiLz48cGF0aCBjbGFzcz0ic3Q0IiBkPSJNMzUuMiAyNy45SDQuOGExIDEgMCAwIDEtMS0xVjEyLjFjMC0uNi41LTEgMS0xaDMwLjVjLjUgMCAxIC40IDEgMVYyN2ExIDEgMCAwIDEtMS4xLjl6Ii8+PC9nPjwvc3ZnPg==';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Length of the buffer to store key presses for the "when keys pressed in order" hat
|
|
15
|
+
* @type {number}
|
|
16
|
+
*/
|
|
17
|
+
const KEY_BUFFER_LENGTH = 100;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Timeout in milliseconds to reset the completed flag for a sequence.
|
|
21
|
+
* @type {number}
|
|
22
|
+
*/
|
|
23
|
+
const SEQUENCE_HAT_TIMEOUT = 100;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* An id for the space key on a keyboard.
|
|
27
|
+
*/
|
|
28
|
+
const KEY_ID_SPACE = 'SPACE';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* An id for the left arrow key on a keyboard.
|
|
32
|
+
*/
|
|
33
|
+
const KEY_ID_LEFT = 'LEFT';
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* An id for the right arrow key on a keyboard.
|
|
37
|
+
*/
|
|
38
|
+
const KEY_ID_RIGHT = 'RIGHT';
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* An id for the up arrow key on a keyboard.
|
|
42
|
+
*/
|
|
43
|
+
const KEY_ID_UP = 'UP';
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* An id for the down arrow key on a keyboard.
|
|
47
|
+
*/
|
|
48
|
+
const KEY_ID_DOWN = 'DOWN';
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Names used by keyboard io for keys used in scratch.
|
|
52
|
+
* @enum {string}
|
|
53
|
+
*/
|
|
54
|
+
const SCRATCH_KEY_NAME = {
|
|
55
|
+
[KEY_ID_SPACE]: 'space',
|
|
56
|
+
[KEY_ID_LEFT]: 'left arrow',
|
|
57
|
+
[KEY_ID_UP]: 'up arrow',
|
|
58
|
+
[KEY_ID_RIGHT]: 'right arrow',
|
|
59
|
+
[KEY_ID_DOWN]: 'down arrow'
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Class for the makey makey blocks in Scratch 3.0
|
|
64
|
+
* @constructor
|
|
65
|
+
*/
|
|
66
|
+
class Scratch3MakeyMakeyBlocks {
|
|
67
|
+
constructor (runtime) {
|
|
68
|
+
/**
|
|
69
|
+
* The runtime instantiating this block package.
|
|
70
|
+
* @type {Runtime}
|
|
71
|
+
*/
|
|
72
|
+
this.runtime = runtime;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* A toggle that alternates true and false each frame, so that an
|
|
76
|
+
* edge-triggered hat can trigger on every other frame.
|
|
77
|
+
* @type {boolean}
|
|
78
|
+
*/
|
|
79
|
+
this.frameToggle = false;
|
|
80
|
+
|
|
81
|
+
// Set an interval that toggles the frameToggle every frame.
|
|
82
|
+
setInterval(() => {
|
|
83
|
+
this.frameToggle = !this.frameToggle;
|
|
84
|
+
}, this.runtime.currentStepTime);
|
|
85
|
+
|
|
86
|
+
this.keyPressed = this.keyPressed.bind(this);
|
|
87
|
+
this.runtime.on('KEY_PRESSED', this.keyPressed);
|
|
88
|
+
|
|
89
|
+
this._clearkeyPressBuffer = this._clearkeyPressBuffer.bind(this);
|
|
90
|
+
this.runtime.on('PROJECT_STOP_ALL', this._clearkeyPressBuffer);
|
|
91
|
+
|
|
92
|
+
/*
|
|
93
|
+
* An object containing a set of sequence objects.
|
|
94
|
+
* These are the key sequences currently being detected by the "when
|
|
95
|
+
* keys pressed in order" hat block. Each sequence is keyed by its
|
|
96
|
+
* string representation (the sequence's value in the menu, which is a
|
|
97
|
+
* string of KEY_IDs separated by spaces). Each sequence object
|
|
98
|
+
* has an array property (an array of KEY_IDs) and a boolean
|
|
99
|
+
* completed property that is true when the sequence has just been
|
|
100
|
+
* pressed.
|
|
101
|
+
* @type {object}
|
|
102
|
+
*/
|
|
103
|
+
this.sequences = {};
|
|
104
|
+
|
|
105
|
+
/*
|
|
106
|
+
* An array of the key codes of recently pressed keys.
|
|
107
|
+
* @type {array}
|
|
108
|
+
*/
|
|
109
|
+
this.keyPressBuffer = [];
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/*
|
|
113
|
+
* Localized short-form names of the space bar and arrow keys, for use in the
|
|
114
|
+
* displayed menu items of the "when keys pressed in order" block.
|
|
115
|
+
* @type {object}
|
|
116
|
+
*/
|
|
117
|
+
get KEY_TEXT_SHORT () {
|
|
118
|
+
return {
|
|
119
|
+
[KEY_ID_SPACE]: formatMessage({
|
|
120
|
+
id: 'makeymakey.spaceKey',
|
|
121
|
+
default: 'space',
|
|
122
|
+
description: 'The space key on a computer keyboard.'
|
|
123
|
+
}),
|
|
124
|
+
[KEY_ID_LEFT]: formatMessage({
|
|
125
|
+
id: 'makeymakey.leftArrowShort',
|
|
126
|
+
default: 'left',
|
|
127
|
+
description: 'Short name for the left arrow key on a computer keyboard.'
|
|
128
|
+
}),
|
|
129
|
+
[KEY_ID_UP]: formatMessage({
|
|
130
|
+
id: 'makeymakey.upArrowShort',
|
|
131
|
+
default: 'up',
|
|
132
|
+
description: 'Short name for the up arrow key on a computer keyboard.'
|
|
133
|
+
}),
|
|
134
|
+
[KEY_ID_RIGHT]: formatMessage({
|
|
135
|
+
id: 'makeymakey.rightArrowShort',
|
|
136
|
+
default: 'right',
|
|
137
|
+
description: 'Short name for the right arrow key on a computer keyboard.'
|
|
138
|
+
}),
|
|
139
|
+
[KEY_ID_DOWN]: formatMessage({
|
|
140
|
+
id: 'makeymakey.downArrowShort',
|
|
141
|
+
default: 'down',
|
|
142
|
+
description: 'Short name for the down arrow key on a computer keyboard.'
|
|
143
|
+
})
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/*
|
|
148
|
+
* An array of strings of KEY_IDs representing the default set of
|
|
149
|
+
* key sequences for use by the "when keys pressed in order" block.
|
|
150
|
+
* @type {array}
|
|
151
|
+
*/
|
|
152
|
+
get DEFAULT_SEQUENCES () {
|
|
153
|
+
return [
|
|
154
|
+
`${KEY_ID_LEFT} ${KEY_ID_UP} ${KEY_ID_RIGHT}`,
|
|
155
|
+
`${KEY_ID_RIGHT} ${KEY_ID_UP} ${KEY_ID_LEFT}`,
|
|
156
|
+
`${KEY_ID_LEFT} ${KEY_ID_RIGHT}`,
|
|
157
|
+
`${KEY_ID_RIGHT} ${KEY_ID_LEFT}`,
|
|
158
|
+
`${KEY_ID_UP} ${KEY_ID_DOWN}`,
|
|
159
|
+
`${KEY_ID_DOWN} ${KEY_ID_UP}`,
|
|
160
|
+
`${KEY_ID_UP} ${KEY_ID_RIGHT} ${KEY_ID_DOWN} ${KEY_ID_LEFT}`,
|
|
161
|
+
`${KEY_ID_UP} ${KEY_ID_LEFT} ${KEY_ID_DOWN} ${KEY_ID_RIGHT}`,
|
|
162
|
+
`${KEY_ID_UP} ${KEY_ID_UP} ${KEY_ID_DOWN} ${KEY_ID_DOWN} ` +
|
|
163
|
+
`${KEY_ID_LEFT} ${KEY_ID_RIGHT} ${KEY_ID_LEFT} ${KEY_ID_RIGHT}`
|
|
164
|
+
];
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* @returns {object} metadata for this extension and its blocks.
|
|
169
|
+
*/
|
|
170
|
+
getInfo () {
|
|
171
|
+
return {
|
|
172
|
+
id: 'makeymakey',
|
|
173
|
+
name: 'Makey Makey',
|
|
174
|
+
blockIconURI: blockIconURI,
|
|
175
|
+
blocks: [
|
|
176
|
+
{
|
|
177
|
+
opcode: 'whenMakeyKeyPressed',
|
|
178
|
+
text: formatMessage({
|
|
179
|
+
id: 'makeymakey.whenKeyPressed',
|
|
180
|
+
default: 'when [KEY] key pressed',
|
|
181
|
+
description: 'when a keyboard key is pressed'
|
|
182
|
+
}),
|
|
183
|
+
blockType: BlockType.HAT,
|
|
184
|
+
arguments: {
|
|
185
|
+
KEY: {
|
|
186
|
+
type: ArgumentType.STRING,
|
|
187
|
+
menu: 'KEY',
|
|
188
|
+
defaultValue: KEY_ID_SPACE
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
opcode: 'whenCodePressed',
|
|
194
|
+
text: formatMessage({
|
|
195
|
+
id: 'makeymakey.whenKeysPressedInOrder',
|
|
196
|
+
default: 'when [SEQUENCE] pressed in order',
|
|
197
|
+
description: 'when a sequence of keyboard keys is pressed in a specific order'
|
|
198
|
+
}),
|
|
199
|
+
blockType: BlockType.HAT,
|
|
200
|
+
arguments: {
|
|
201
|
+
SEQUENCE: {
|
|
202
|
+
type: ArgumentType.STRING,
|
|
203
|
+
menu: 'SEQUENCE',
|
|
204
|
+
defaultValue: this.DEFAULT_SEQUENCES[0]
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
],
|
|
209
|
+
menus: {
|
|
210
|
+
KEY: {
|
|
211
|
+
acceptReporters: true,
|
|
212
|
+
items: [
|
|
213
|
+
{
|
|
214
|
+
text: formatMessage({
|
|
215
|
+
id: 'makeymakey.spaceKey',
|
|
216
|
+
default: 'space',
|
|
217
|
+
description: 'The space key on a computer keyboard.'
|
|
218
|
+
}),
|
|
219
|
+
value: KEY_ID_SPACE
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
text: formatMessage({
|
|
223
|
+
id: 'makeymakey.upArrow',
|
|
224
|
+
default: 'up arrow',
|
|
225
|
+
description: 'The up arrow key on a computer keyboard.'
|
|
226
|
+
}),
|
|
227
|
+
value: KEY_ID_UP
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
text: formatMessage({
|
|
231
|
+
id: 'makeymakey.downArrow',
|
|
232
|
+
default: 'down arrow',
|
|
233
|
+
description: 'The down arrow key on a computer keyboard.'
|
|
234
|
+
}),
|
|
235
|
+
value: KEY_ID_DOWN
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
text: formatMessage({
|
|
239
|
+
id: 'makeymakey.rightArrow',
|
|
240
|
+
default: 'right arrow',
|
|
241
|
+
description: 'The right arrow key on a computer keyboard.'
|
|
242
|
+
}),
|
|
243
|
+
value: KEY_ID_RIGHT
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
text: formatMessage({
|
|
247
|
+
id: 'makeymakey.leftArrow',
|
|
248
|
+
default: 'left arrow',
|
|
249
|
+
description: 'The left arrow key on a computer keyboard.'
|
|
250
|
+
}),
|
|
251
|
+
value: KEY_ID_LEFT
|
|
252
|
+
},
|
|
253
|
+
{text: 'w', value: 'w'},
|
|
254
|
+
{text: 'a', value: 'a'},
|
|
255
|
+
{text: 's', value: 's'},
|
|
256
|
+
{text: 'd', value: 'd'},
|
|
257
|
+
{text: 'f', value: 'f'},
|
|
258
|
+
{text: 'g', value: 'g'}
|
|
259
|
+
]
|
|
260
|
+
},
|
|
261
|
+
SEQUENCE: {
|
|
262
|
+
acceptReporters: true,
|
|
263
|
+
items: this.buildSequenceMenu(this.DEFAULT_SEQUENCES)
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/*
|
|
270
|
+
* Build the menu of key sequences.
|
|
271
|
+
* @param {array} sequencesArray an array of strings of KEY_IDs.
|
|
272
|
+
* @returns {array} an array of objects with text and value properties.
|
|
273
|
+
*/
|
|
274
|
+
buildSequenceMenu (sequencesArray) {
|
|
275
|
+
return sequencesArray.map(
|
|
276
|
+
str => this.getMenuItemForSequenceString(str)
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/*
|
|
281
|
+
* Create a menu item for a sequence string.
|
|
282
|
+
* @param {string} sequenceString a string of KEY_IDs.
|
|
283
|
+
* @return {object} an object with text and value properties.
|
|
284
|
+
*/
|
|
285
|
+
getMenuItemForSequenceString (sequenceString) {
|
|
286
|
+
let sequenceArray = sequenceString.split(' ');
|
|
287
|
+
sequenceArray = sequenceArray.map(str => this.KEY_TEXT_SHORT[str]);
|
|
288
|
+
return {
|
|
289
|
+
text: sequenceArray.join(' '),
|
|
290
|
+
value: sequenceString
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/*
|
|
295
|
+
* Check whether a keyboard key is currently pressed.
|
|
296
|
+
* Also, toggle the results of the test on alternate frames, so that the
|
|
297
|
+
* hat block fires repeatedly.
|
|
298
|
+
* @param {object} args - the block arguments.
|
|
299
|
+
* @property {number} KEY - a key code.
|
|
300
|
+
* @param {object} util - utility object provided by the runtime.
|
|
301
|
+
*/
|
|
302
|
+
whenMakeyKeyPressed (args, util) {
|
|
303
|
+
let key = args.KEY;
|
|
304
|
+
// Convert the key arg, if it is a KEY_ID, to the key name used by
|
|
305
|
+
// the Keyboard io module.
|
|
306
|
+
if (SCRATCH_KEY_NAME[args.KEY]) {
|
|
307
|
+
key = SCRATCH_KEY_NAME[args.KEY];
|
|
308
|
+
}
|
|
309
|
+
const isDown = util.ioQuery('keyboard', 'getKeyIsDown', [key]);
|
|
310
|
+
return (isDown && this.frameToggle);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/*
|
|
314
|
+
* A function called on the KEY_PRESSED event, to update the key press
|
|
315
|
+
* buffer and check if any of the key sequences have been completed.
|
|
316
|
+
* @param {string} key A scratch key name.
|
|
317
|
+
*/
|
|
318
|
+
keyPressed (key) {
|
|
319
|
+
// Store only the first word of the Scratch key name, so that e.g. when
|
|
320
|
+
// "left arrow" is pressed, we store "LEFT", which matches KEY_ID_LEFT
|
|
321
|
+
key = key.split(' ')[0];
|
|
322
|
+
key = key.toUpperCase();
|
|
323
|
+
this.keyPressBuffer.push(key);
|
|
324
|
+
// Keep the buffer under the length limit
|
|
325
|
+
if (this.keyPressBuffer.length > KEY_BUFFER_LENGTH) {
|
|
326
|
+
this.keyPressBuffer.shift();
|
|
327
|
+
}
|
|
328
|
+
// Check the buffer for each sequence in use
|
|
329
|
+
for (const str in this.sequences) {
|
|
330
|
+
const arr = this.sequences[str].array;
|
|
331
|
+
// Bail out if we don't have enough presses for this sequence
|
|
332
|
+
if (this.keyPressBuffer.length < arr.length) {
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
let missFlag = false;
|
|
336
|
+
// Slice the buffer to the length of the sequence we're checking
|
|
337
|
+
const bufferSegment = this.keyPressBuffer.slice(-1 * arr.length);
|
|
338
|
+
for (let i = 0; i < arr.length; i++) {
|
|
339
|
+
if (arr[i] !== bufferSegment[i]) {
|
|
340
|
+
missFlag = true;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
// If the miss flag is false, the sequence matched the buffer
|
|
344
|
+
if (!missFlag) {
|
|
345
|
+
this.sequences[str].completed = true;
|
|
346
|
+
// Clear the completed flag after a timeout. This is necessary because
|
|
347
|
+
// the hat is edge-triggered (not event triggered). Multiple hats
|
|
348
|
+
// may be checking the same sequence, so this timeout gives them enough
|
|
349
|
+
// time to all trigger before resetting the flag.
|
|
350
|
+
setTimeout(() => {
|
|
351
|
+
this.sequences[str].completed = false;
|
|
352
|
+
}, SEQUENCE_HAT_TIMEOUT);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Clear the key press buffer.
|
|
359
|
+
*/
|
|
360
|
+
_clearkeyPressBuffer () {
|
|
361
|
+
this.keyPressBuffer = [];
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/*
|
|
365
|
+
* Add a key sequence to the set currently being checked on each key press.
|
|
366
|
+
* @param {string} sequenceString a string of space-separated KEY_IDs.
|
|
367
|
+
* @param {array} sequenceArray an array of KEY_IDs.
|
|
368
|
+
*/
|
|
369
|
+
addSequence (sequenceString, sequenceArray) {
|
|
370
|
+
// If we already have this sequence string, return.
|
|
371
|
+
if (Object.prototype.hasOwnProperty.call(this.sequences, sequenceString)) {
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
this.sequences[sequenceString] = {
|
|
375
|
+
array: sequenceArray,
|
|
376
|
+
completed: false
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/*
|
|
381
|
+
* Check whether a key sequence was recently completed.
|
|
382
|
+
* @param {object} args The block arguments.
|
|
383
|
+
* @property {number} SEQUENCE A string of KEY_IDs.
|
|
384
|
+
*/
|
|
385
|
+
whenCodePressed (args) {
|
|
386
|
+
const sequenceString = Cast.toString(args.SEQUENCE).toUpperCase();
|
|
387
|
+
const sequenceArray = sequenceString.split(' ');
|
|
388
|
+
if (sequenceArray.length < 2) {
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
this.addSequence(sequenceString, sequenceArray);
|
|
392
|
+
|
|
393
|
+
return this.sequences[sequenceString].completed;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
module.exports = Scratch3MakeyMakeyBlocks;
|