Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
220 changes: 220 additions & 0 deletions static/extensions/Better Keyboard
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please refrain from using spaces in the file name, also make sure to make it a .js file for JavaScript.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also another note, please make a folder for yourself instead of putting it in the base extensions directory.

Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
// Name: Better Keyboard
// ID: SuperCodes_BetterKeyboard
// Description: Advanced text input and display on the stage.
// By: SuperCodes_

// A message for users of the version from pen-group's site.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is on the pen-group site.

Also this should be inside the (function (Scratch) { on line 7

if (!Scratch.extensions.unsandboxed) {
alert("Better Keyboard must be run unsandboxed!");
throw new Error("Better Keyboard must run unsandboxed");
}

(function (Scratch) {
"use strict";

const vm = Scratch.vm;
const runtime = vm.runtime;
const renderer = runtime.renderer;

// Use a WeakMap to store sprite-specific data, such as the text buffer.
const spriteData = new WeakMap();

// The state of the extension.
class BetterKeyboard {
constructor() {
this._isTypingMode = false;
this._fontSettings = {
size: 24,
type: "sans-serif",
color: "#000000",
};
this._typingTarget = null;
this._keyListener = this._handleKeyPress.bind(this);
}

getInfo() {
return {
id: 'SuperCodes_BetterKeyboard', // This is the ID that needs to be updated.
name: 'Better Keyboard',
blocks: [
{
opcode: 'setFontSize',
blockType: Scratch.BlockType.COMMAND,
text: 'set font size to [SIZE]',
arguments: {
SIZE: {
type: Scratch.ArgumentType.NUMBER,
defaultValue: 24
}
}
},
{
opcode: 'setFontType',
blockType: Scratch.BlockType.COMMAND,
text: 'set font type to [TYPE]',
arguments: {
TYPE: {
type: Scratch.ArgumentType.STRING,
defaultValue: 'sans-serif'
}
}
},
{
opcode: 'setFontColor',
blockType: Scratch.BlockType.COMMAND,
text: 'set font color to [COLOR]',
arguments: {
COLOR: {
type: Scratch.ArgumentType.COLOR,
defaultValue: '#000000'
}
}
},
{
opcode: 'toggleTypingMode',
blockType: Scratch.BlockType.COMMAND,
text: 'turn typing mode [MODE]',
arguments: {
MODE: {
type: Scratch.ArgumentType.STRING,
menu: 'typing_mode_options'
}
}
},
{
opcode: 'isTypingModeOn',
blockType: Scratch.BlockType.BOOLEAN,
text: 'typing mode is on?',
disableMonitor: true
},
{
opcode: 'getTypingModeStatus',
blockType: Scratch.BlockType.REPORTER,
text: 'typing mode status',
disableMonitor: true
}
],
menus: {
typing_mode_options: {
acceptReporters: true,
items: ['on', 'off']
}
}
};
}

// --- Block Implementations ---

setFontSize(args) {
this._fontSettings.size = Scratch.Cast.toNumber(args.SIZE);
}

setFontType(args) {
this._fontSettings.type = Scratch.Cast.toString(args.TYPE);
}

setFontColor(args) {
this._fontSettings.color = Scratch.Cast.toCSSColor(args.COLOR);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The scratch object does not have a toCSSColor do you mean toRgbColorList or toRgbColorObject?

}

toggleTypingMode(args, util) {
const mode = args.MODE.toLowerCase();
const wasTyping = this._isTypingMode;
if (mode === 'on') {
this._isTypingMode = true;
// Add the event listener only once.
if (!wasTyping) {
window.addEventListener('keydown', this._keyListener);
// Set the typing target to the current sprite.
this._typingTarget = util.target;
// Initialize the text buffer for the sprite.
this._getSpriteData(util.target).textBuffer = '';
}
} else {
this._isTypingMode = false;
// Remove the event listener to stop capturing keys.
if (wasTyping) {
window.removeEventListener('keydown', this._keyListener);
}
}
}

isTypingModeOn() {
return this._isTypingMode;
}

getTypingModeStatus() {
return this._isTypingMode ? "on" : "off";
}

// --- Internal Methods ---

_getSpriteData(target) {
if (!spriteData.has(target)) {
spriteData.set(target, {
textBuffer: '',
costume: null
});
}
return spriteData.get(target);
}

_updateTextCostume(target) {
const targetData = this._getSpriteData(target);
const text = targetData.textBuffer;

// Create an offscreen canvas to render the text.
const textCanvas = document.createElement('canvas');
const context = textCanvas.getContext('2d');

context.font = `${this._fontSettings.size}px ${this._fontSettings.type}`;
const metrics = context.measureText(text);

// Set canvas size based on text metrics.
textCanvas.width = metrics.width + 10;
textCanvas.height = this._fontSettings.size + 10;

context.clearRect(0, 0, textCanvas.width, textCanvas.height);
context.font = `${this._fontSettings.size}px ${this._fontSettings.type}`;
context.fillStyle = this._fontSettings.color;
context.fillText(text, 5, this._fontSettings.size - 2);

// Create a new costume from the canvas and set it for the sprite.
const costume = {
name: 'typed text',
assetId: 'typed_text_asset',
dataFormat: 'svg',
is==svg: false,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Running this throws Expected "}" but found "==" = is not allowed unless it is in quotes.

bitmapResolution: 1,
skinId: renderer.createBitmapSkinFromCanvas(textCanvas, 1),
rotationCenter: [textCanvas.width / 2, textCanvas.height / 2]
};

target.setCostume(costume);
}

_handleKeyPress(event) {
if (!this._isTypingMode || this._typingTarget === null) {
return;
}

const targetData = this._getSpriteData(this._typingTarget);
const key = event.key;

if (key === 'Enter') {
targetData.textBuffer += '\n';
} else if (key === 'Backspace') {
targetData.textBuffer = targetData.textBuffer.slice(0, -1);
} else if (key.length === 1) {
targetData.textBuffer += key;
}

// Immediately update the sprite's costume to show the new text.
this._updateTextCostume(this._typingTarget);
runtime.requestRedraw();
}
}

Scratch.extensions.register(new BetterKeyboard());

})(Scratch);
Binary file added static/images/Banner.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.