From 8d37f13a147e96274f68ffee556aba8d1bc1e9a4 Mon Sep 17 00:00:00 2001 From: LegoBrainBiker Date: Fri, 2 May 2025 09:34:13 -0700 Subject: [PATCH 01/16] legobrainbiker/more mouse controlls: implementation --- extensions/extensions.json | 1 + .../legobrainbiker/more mouse controls.js | 137 ++++++++++++++++++ images/legobrainbiker/more mouse controls.svg | 1 + 3 files changed, 139 insertions(+) create mode 100644 extensions/legobrainbiker/more mouse controls.js create mode 100644 images/legobrainbiker/more mouse controls.svg diff --git a/extensions/extensions.json b/extensions/extensions.json index d8ed71e33d..d6552981a3 100644 --- a/extensions/extensions.json +++ b/extensions/extensions.json @@ -7,6 +7,7 @@ "files", "pointerlock", "cursor", + "legobrainbiker/more mouse controls", "runtime-options", "fetch", "text", diff --git a/extensions/legobrainbiker/more mouse controls.js b/extensions/legobrainbiker/more mouse controls.js new file mode 100644 index 0000000000..79b17333ad --- /dev/null +++ b/extensions/legobrainbiker/more mouse controls.js @@ -0,0 +1,137 @@ +// Name: More Mouse Controls +// ID: legobrainbikerMoreMouseControls +// Description: Some features I felt were missing from the mouse, including right click detection. +// By: legobrainbiker +// License: MPL-2.0 +((Scratch) => { + "use strict"; + class moreMouseControls { + constructor() { + this.mouseX = 0; + this.mouseY = 0; + this.scroll = 0; + this.buttons = []; + document.addEventListener("mousewheel", (e) => { + this.mouseWheelDelta = e.deltaY; + Scratch.vm.runtime.startHats( + "legobrainbikerMoreMouseControls_onScroll" + ); + }); + document.addEventListener("mouseup", (e) => { + this.buttons[e.button] = false; + }); + document.addEventListener("mousedown", (e) => { + this.buttons[e.button] = true; + }); + document.addEventListener("mousemove", (e) => { + this.mouseX = e.clientX; + this.mouseY = e.clientY; + }); + } + getInfo() { + return { + id: "legobrainbikerMoreMouseControls", + name: Scratch.translate("More Mouse Controls"), + menuIconURI: + "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIzNi4zOTI4MSIgaGVpZ2h0PSIzNS40MjY1OSIgdmlld0JveD0iMCwwLDM2LjM5MjgxLDM1LjQyNjU5Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMTU2Ljg4NTQxLC0xNTcuNjM4NDcpIj48ZyBzdHJva2U9IiMwMDAwMDAiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCI+PHBhdGggZD0iTTE2Mi44NjU0NCwxNjcuNDYzMDljMCwtMi4wNDY3NCAxLjc0NjIsLTMuNzA1OTQgMy45MDAyNCwtMy43MDU5NGMyLjE1NDA0LDAgMy45MDAyNCwxLjY1OTIxIDMuOTAwMjQsMy43MDU5NGMwLDIuMDQ2NzQgLTEuNzQ2MiwzLjcwNTk1IC0zLjkwMDI0LDMuNzA1OTVjLTIuMTU0MDQsMCAtMy45MDAyNCwtMS42NTkyMSAtMy45MDAyNCwtMy43MDU5NXoiIGZpbGw9Im5vbmUiIHN0cm9rZS13aWR0aD0iMi41IiBzdHJva2UtbGluZWNhcD0iYnV0dCIvPjxwYXRoIGQ9Ik0xNTguMTM1NDEsMTY3LjQ2MzA5YzAsLTQuNzM1NjMgMy44NjM5LC04LjU3NDYyIDguNjMwMjcsLTguNTc0NjJjNC43NjYzNywwIDguNjMwMjcsMy44Mzg5OSA4LjYzMDI3LDguNTc0NjJjMCw0LjczNTYzIC0zLjg2MzksOC41NzQ2MiAtOC42MzAyNyw4LjU3NDYyYy00Ljc2NjM3LDAgLTguNjMwMjcsLTMuODM4OTkgLTguNjMwMjcsLTguNTc0NjJ6IiBmaWxsPSJub25lIiBzdHJva2Utd2lkdGg9IjIuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMTY3LjE0OTM5LDE3MC45MDY1YzEuNzMxMTMsMy41NzM5NSA3LjA5NTEzLDE0LjY0ODAxIDkuODg1MzksMjAuNDA4NTVjMS4wNDI2OSwyLjE1MjY1IDIuMzMzMzgsMS4xMzM2NiAyLjc1MjMyLC0wLjU0MjA4YzAuNDY3NjksLTEuODcwNzUgMS41NTMyMywtNi4yMTI5MiAyLjE0OTI5LC04LjU5NzE0YzAuMjQ3MDcsLTAuOTg4MjggMS4yMjc3NCwtMS45Mzk5OCAyLjAwNjEzLC0yLjIyNTM5YzEuMTc1NDYsLTAuNDMxIDQuNjg3NzgsLTEuNzE4ODUgNy41ODU3MSwtMi43ODE0MmMyLjMzMSwtMC44NTQ3IDIuMzU5MTIsLTIuMTQzNTMgLTAuNDQ3MjksLTIuOTk3NjVjLTYuNTM1MzMsLTEuOTg5MDEgLTE3Ljk1NzAzLC01LjQ2NTE4IC0yMS41ODI1MiwtNi41Njg1OWMtMi4xNzUxNCwtMC42NjIgLTMuNDAzNTEsMS4xMjY3MyAtMi4zNDkwMywzLjMwMzczeiIgZmlsbD0iI2EzYTNhMyIgc3Ryb2tlLXdpZHRoPSIzLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjwvZz48L2c+PC9zdmc+", + blockIconURI: + "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIzNi4zOTI4MSIgaGVpZ2h0PSIzNS40MjY1OSIgdmlld0JveD0iMCwwLDM2LjM5MjgxLDM1LjQyNjU5Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMTU2Ljg4NTQxLC0xNTcuNjM4NDcpIj48ZyBzdHJva2U9IiMwMDAwMDAiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCI+PHBhdGggZD0iTTE2Mi44NjU0NCwxNjcuNDYzMDljMCwtMi4wNDY3NCAxLjc0NjIsLTMuNzA1OTQgMy45MDAyNCwtMy43MDU5NGMyLjE1NDA0LDAgMy45MDAyNCwxLjY1OTIxIDMuOTAwMjQsMy43MDU5NGMwLDIuMDQ2NzQgLTEuNzQ2MiwzLjcwNTk1IC0zLjkwMDI0LDMuNzA1OTVjLTIuMTU0MDQsMCAtMy45MDAyNCwtMS42NTkyMSAtMy45MDAyNCwtMy43MDU5NXoiIGZpbGw9Im5vbmUiIHN0cm9rZS13aWR0aD0iMi41IiBzdHJva2UtbGluZWNhcD0iYnV0dCIvPjxwYXRoIGQ9Ik0xNTguMTM1NDEsMTY3LjQ2MzA5YzAsLTQuNzM1NjMgMy44NjM5LC04LjU3NDYyIDguNjMwMjcsLTguNTc0NjJjNC43NjYzNywwIDguNjMwMjcsMy44Mzg5OSA4LjYzMDI3LDguNTc0NjJjMCw0LjczNTYzIC0zLjg2MzksOC41NzQ2MiAtOC42MzAyNyw4LjU3NDYyYy00Ljc2NjM3LDAgLTguNjMwMjcsLTMuODM4OTkgLTguNjMwMjcsLTguNTc0NjJ6IiBmaWxsPSJub25lIiBzdHJva2Utd2lkdGg9IjIuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMTY3LjE0OTM5LDE3MC45MDY1YzEuNzMxMTMsMy41NzM5NSA3LjA5NTEzLDE0LjY0ODAxIDkuODg1MzksMjAuNDA4NTVjMS4wNDI2OSwyLjE1MjY1IDIuMzMzMzgsMS4xMzM2NiAyLjc1MjMyLC0wLjU0MjA4YzAuNDY3NjksLTEuODcwNzUgMS41NTMyMywtNi4yMTI5MiAyLjE0OTI5LC04LjU5NzE0YzAuMjQ3MDcsLTAuOTg4MjggMS4yMjc3NCwtMS45Mzk5OCAyLjAwNjEzLC0yLjIyNTM5YzEuMTc1NDYsLTAuNDMxIDQuNjg3NzgsLTEuNzE4ODUgNy41ODU3MSwtMi43ODE0MmMyLjMzMSwtMC44NTQ3IDIuMzU5MTIsLTIuMTQzNTMgLTAuNDQ3MjksLTIuOTk3NjVjLTYuNTM1MzMsLTEuOTg5MDEgLTE3Ljk1NzAzLC01LjQ2NTE4IC0yMS41ODI1MiwtNi41Njg1OWMtMi4xNzUxNCwtMC42NjIgLTMuNDAzNTEsMS4xMjY3MyAtMi4zNDkwMywzLjMwMzczeiIgZmlsbD0iI2EzYTNhMyIgc3Ryb2tlLXdpZHRoPSIzLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjwvZz48L2c+PC9zdmc+", + color1: "#99bbbb", + color2: "#88bbbb", + color3: "#88bbbb", + blocks: [ + { + opcode: "onMouseUp", + blockType: Scratch.BlockType.HAT, + text: Scratch.translate("when mouse button [button] is released"), + isEdgeActivated: true, + arguments: { + button: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: "0", + }, + }, + }, + { + opcode: "onMouseDown", + blockType: Scratch.BlockType.HAT, + text: Scratch.translate("when mouse button [button] is pressed"), + isEdgeActivated: true, + arguments: { + button: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: "0", + }, + }, + }, + { + opcode: "buttonPressed", + blockType: Scratch.BlockType.BOOLEAN, + text: Scratch.translate("mouse button [button] is pressed"), + arguments: { + button: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: "0", + }, + }, + }, + { + opcode: "dissableContextMenu", + blockType: Scratch.BlockType.COMMAND, + text: Scratch.translate("disable context menu"), + }, + { + opcode: "onScroll", + blockType: Scratch.BlockType.EVENT, + text: Scratch.translate("when scrolling"), + isEdgeActivated: false, + }, + { + opcode: "scrollamount", + blockType: Scratch.BlockType.REPORTER, + text: Scratch.translate("scroll amount"), + }, + { + opcode: "mouseGlobalX", + blockType: Scratch.BlockType.REPORTER, + text: Scratch.translate("mouse global x position"), + }, + { + opcode: "mouseGlobalY", + blockType: Scratch.BlockType.REPORTER, + text: Scratch.translate("mouse global y position"), + }, + ], + }; + } + onMouseUp(args) { + return !this.buttonPressed(args); + } + onMouseDown(args) { + return this.buttonPressed(args); + } + buttonPressed({ button }) { + console.log(button); + console.log(Scratch.Cast.toNumber(button)); + console.log(this.buttons[Scratch.Cast.toNumber(button)]); + return this.buttons[Scratch.Cast.toNumber(button)] || false; + } + dissableContextMenu() { + document.addEventListener("contextmenu", (e) => { + e.preventDefault(); + }); + } + scrollamount() { + return this.mouseWheelDelta || 0; + } + mouseGlobalX() { + const canvas = Scratch.renderer.canvas.getBoundingClientRect(); + return this.mouseX - canvas.x - canvas.width / 2; + } + mouseGlobalY() { + const canvas = Scratch.renderer.canvas.getBoundingClientRect(); + return -(this.mouseY - canvas.y - canvas.height / 2); + } + } + Scratch.extensions.register(new moreMouseControls()); +})(Scratch); diff --git a/images/legobrainbiker/more mouse controls.svg b/images/legobrainbiker/more mouse controls.svg new file mode 100644 index 0000000000..0d46c87595 --- /dev/null +++ b/images/legobrainbiker/more mouse controls.svg @@ -0,0 +1 @@ + \ No newline at end of file From 67cfbeb73cb12d5f19db031d6871714a9ebb23cc Mon Sep 17 00:00:00 2001 From: LegoBrainBiker Date: Fri, 2 May 2025 12:06:56 -0700 Subject: [PATCH 02/16] legobrainbiker/moremousecontrolls: update based on suggestions --- extensions/extensions.json | 2 +- .../{more mouse controls.js => MoreMouseControls.js} | 11 +++++------ ...{more mouse controls.svg => MoreMouseControls.svg} | 0 3 files changed, 6 insertions(+), 7 deletions(-) rename extensions/legobrainbiker/{more mouse controls.js => MoreMouseControls.js} (52%) rename images/legobrainbiker/{more mouse controls.svg => MoreMouseControls.svg} (100%) diff --git a/extensions/extensions.json b/extensions/extensions.json index d6552981a3..f57e0c3c11 100644 --- a/extensions/extensions.json +++ b/extensions/extensions.json @@ -7,7 +7,7 @@ "files", "pointerlock", "cursor", - "legobrainbiker/more mouse controls", + "legobrainbiker/MoreMouseControls", "runtime-options", "fetch", "text", diff --git a/extensions/legobrainbiker/more mouse controls.js b/extensions/legobrainbiker/MoreMouseControls.js similarity index 52% rename from extensions/legobrainbiker/more mouse controls.js rename to extensions/legobrainbiker/MoreMouseControls.js index 79b17333ad..8fc2ba8ab1 100644 --- a/extensions/legobrainbiker/more mouse controls.js +++ b/extensions/legobrainbiker/MoreMouseControls.js @@ -1,10 +1,11 @@ // Name: More Mouse Controls // ID: legobrainbikerMoreMouseControls -// Description: Some features I felt were missing from the mouse, including right click detection. +// Description: adds more options to detect properties of the cursor, including its position, clicking, and scrolling. // By: legobrainbiker // License: MPL-2.0 -((Scratch) => { +(function (Scratch) { "use strict"; + const iconURI = 'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIzNi4zOTI4MSIgaGVpZ2h0PSIzNS40MjY1OSIgdmlld0JveD0iMCwwLDM2LjM5MjgxLDM1LjQyNjU5Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMTU2Ljg4NTQxLC0xNTcuNjM4NDcpIj48ZyBzdHJva2U9IiMwMDAwMDAiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCI+PHBhdGggZD0iTTE2Mi44NjU0NCwxNjcuNDYzMDljMCwtMi4wNDY3NCAxLjc0NjIsLTMuNzA1OTQgMy45MDAyNCwtMy43MDU5NGMyLjE1NDA0LDAgMy45MDAyNCwxLjY1OTIxIDMuOTAwMjQsMy43MDU5NGMwLDIuMDQ2NzQgLTEuNzQ2MiwzLjcwNTk1IC0zLjkwMDI0LDMuNzA1OTVjLTIuMTU0MDQsMCAtMy45MDAyNCwtMS42NTkyMSAtMy45MDAyNCwtMy43MDU5NXoiIGZpbGw9Im5vbmUiIHN0cm9rZS13aWR0aD0iMi41IiBzdHJva2UtbGluZWNhcD0iYnV0dCIvPjxwYXRoIGQ9Ik0xNTguMTM1NDEsMTY3LjQ2MzA5YzAsLTQuNzM1NjMgMy44NjM5LC04LjU3NDYyIDguNjMwMjcsLTguNTc0NjJjNC43NjYzNywwIDguNjMwMjcsMy44Mzg5OSA4LjYzMDI3LDguNTc0NjJjMCw0LjczNTYzIC0zLjg2MzksOC41NzQ2MiAtOC42MzAyNyw4LjU3NDYyYy00Ljc2NjM3LDAgLTguNjMwMjcsLTMuODM4OTkgLTguNjMwMjcsLTguNTc0NjJ6IiBmaWxsPSJub25lIiBzdHJva2Utd2lkdGg9IjIuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMTY3LjE0OTM5LDE3MC45MDY1YzEuNzMxMTMsMy41NzM5NSA3LjA5NTEzLDE0LjY0ODAxIDkuODg1MzksMjAuNDA4NTVjMS4wNDI2OSwyLjE1MjY1IDIuMzMzMzgsMS4xMzM2NiAyLjc1MjMyLC0wLjU0MjA4YzAuNDY3NjksLTEuODcwNzUgMS41NTMyMywtNi4yMTI5MiAyLjE0OTI5LC04LjU5NzE0YzAuMjQ3MDcsLTAuOTg4MjggMS4yMjc3NCwtMS45Mzk5OCAyLjAwNjEzLC0yLjIyNTM5YzEuMTc1NDYsLTAuNDMxIDQuNjg3NzgsLTEuNzE4ODUgNy41ODU3MSwtMi43ODE0MmMyLjMzMSwtMC44NTQ3IDIuMzU5MTIsLTIuMTQzNTMgLTAuNDQ3MjksLTIuOTk3NjVjLTYuNTM1MzMsLTEuOTg5MDEgLTE3Ljk1NzAzLC01LjQ2NTE4IC0yMS41ODI1MiwtNi41Njg1OWMtMi4xNzUxNCwtMC42NjIgLTMuNDAzNTEsMS4xMjY3MyAtMi4zNDkwMywzLjMwMzczeiIgZmlsbD0iI2EzYTNhMyIgc3Ryb2tlLXdpZHRoPSIzLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjwvZz48L2c+PC9zdmc+' class moreMouseControls { constructor() { this.mouseX = 0; @@ -32,10 +33,8 @@ return { id: "legobrainbikerMoreMouseControls", name: Scratch.translate("More Mouse Controls"), - menuIconURI: - "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIzNi4zOTI4MSIgaGVpZ2h0PSIzNS40MjY1OSIgdmlld0JveD0iMCwwLDM2LjM5MjgxLDM1LjQyNjU5Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMTU2Ljg4NTQxLC0xNTcuNjM4NDcpIj48ZyBzdHJva2U9IiMwMDAwMDAiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCI+PHBhdGggZD0iTTE2Mi44NjU0NCwxNjcuNDYzMDljMCwtMi4wNDY3NCAxLjc0NjIsLTMuNzA1OTQgMy45MDAyNCwtMy43MDU5NGMyLjE1NDA0LDAgMy45MDAyNCwxLjY1OTIxIDMuOTAwMjQsMy43MDU5NGMwLDIuMDQ2NzQgLTEuNzQ2MiwzLjcwNTk1IC0zLjkwMDI0LDMuNzA1OTVjLTIuMTU0MDQsMCAtMy45MDAyNCwtMS42NTkyMSAtMy45MDAyNCwtMy43MDU5NXoiIGZpbGw9Im5vbmUiIHN0cm9rZS13aWR0aD0iMi41IiBzdHJva2UtbGluZWNhcD0iYnV0dCIvPjxwYXRoIGQ9Ik0xNTguMTM1NDEsMTY3LjQ2MzA5YzAsLTQuNzM1NjMgMy44NjM5LC04LjU3NDYyIDguNjMwMjcsLTguNTc0NjJjNC43NjYzNywwIDguNjMwMjcsMy44Mzg5OSA4LjYzMDI3LDguNTc0NjJjMCw0LjczNTYzIC0zLjg2MzksOC41NzQ2MiAtOC42MzAyNyw4LjU3NDYyYy00Ljc2NjM3LDAgLTguNjMwMjcsLTMuODM4OTkgLTguNjMwMjcsLTguNTc0NjJ6IiBmaWxsPSJub25lIiBzdHJva2Utd2lkdGg9IjIuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMTY3LjE0OTM5LDE3MC45MDY1YzEuNzMxMTMsMy41NzM5NSA3LjA5NTEzLDE0LjY0ODAxIDkuODg1MzksMjAuNDA4NTVjMS4wNDI2OSwyLjE1MjY1IDIuMzMzMzgsMS4xMzM2NiAyLjc1MjMyLC0wLjU0MjA4YzAuNDY3NjksLTEuODcwNzUgMS41NTMyMywtNi4yMTI5MiAyLjE0OTI5LC04LjU5NzE0YzAuMjQ3MDcsLTAuOTg4MjggMS4yMjc3NCwtMS45Mzk5OCAyLjAwNjEzLC0yLjIyNTM5YzEuMTc1NDYsLTAuNDMxIDQuNjg3NzgsLTEuNzE4ODUgNy41ODU3MSwtMi43ODE0MmMyLjMzMSwtMC44NTQ3IDIuMzU5MTIsLTIuMTQzNTMgLTAuNDQ3MjksLTIuOTk3NjVjLTYuNTM1MzMsLTEuOTg5MDEgLTE3Ljk1NzAzLC01LjQ2NTE4IC0yMS41ODI1MiwtNi41Njg1OWMtMi4xNzUxNCwtMC42NjIgLTMuNDAzNTEsMS4xMjY3MyAtMi4zNDkwMywzLjMwMzczeiIgZmlsbD0iI2EzYTNhMyIgc3Ryb2tlLXdpZHRoPSIzLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjwvZz48L2c+PC9zdmc+", - blockIconURI: - "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIzNi4zOTI4MSIgaGVpZ2h0PSIzNS40MjY1OSIgdmlld0JveD0iMCwwLDM2LjM5MjgxLDM1LjQyNjU5Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMTU2Ljg4NTQxLC0xNTcuNjM4NDcpIj48ZyBzdHJva2U9IiMwMDAwMDAiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCI+PHBhdGggZD0iTTE2Mi44NjU0NCwxNjcuNDYzMDljMCwtMi4wNDY3NCAxLjc0NjIsLTMuNzA1OTQgMy45MDAyNCwtMy43MDU5NGMyLjE1NDA0LDAgMy45MDAyNCwxLjY1OTIxIDMuOTAwMjQsMy43MDU5NGMwLDIuMDQ2NzQgLTEuNzQ2MiwzLjcwNTk1IC0zLjkwMDI0LDMuNzA1OTVjLTIuMTU0MDQsMCAtMy45MDAyNCwtMS42NTkyMSAtMy45MDAyNCwtMy43MDU5NXoiIGZpbGw9Im5vbmUiIHN0cm9rZS13aWR0aD0iMi41IiBzdHJva2UtbGluZWNhcD0iYnV0dCIvPjxwYXRoIGQ9Ik0xNTguMTM1NDEsMTY3LjQ2MzA5YzAsLTQuNzM1NjMgMy44NjM5LC04LjU3NDYyIDguNjMwMjcsLTguNTc0NjJjNC43NjYzNywwIDguNjMwMjcsMy44Mzg5OSA4LjYzMDI3LDguNTc0NjJjMCw0LjczNTYzIC0zLjg2MzksOC41NzQ2MiAtOC42MzAyNyw4LjU3NDYyYy00Ljc2NjM3LDAgLTguNjMwMjcsLTMuODM4OTkgLTguNjMwMjcsLTguNTc0NjJ6IiBmaWxsPSJub25lIiBzdHJva2Utd2lkdGg9IjIuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMTY3LjE0OTM5LDE3MC45MDY1YzEuNzMxMTMsMy41NzM5NSA3LjA5NTEzLDE0LjY0ODAxIDkuODg1MzksMjAuNDA4NTVjMS4wNDI2OSwyLjE1MjY1IDIuMzMzMzgsMS4xMzM2NiAyLjc1MjMyLC0wLjU0MjA4YzAuNDY3NjksLTEuODcwNzUgMS41NTMyMywtNi4yMTI5MiAyLjE0OTI5LC04LjU5NzE0YzAuMjQ3MDcsLTAuOTg4MjggMS4yMjc3NCwtMS45Mzk5OCAyLjAwNjEzLC0yLjIyNTM5YzEuMTc1NDYsLTAuNDMxIDQuNjg3NzgsLTEuNzE4ODUgNy41ODU3MSwtMi43ODE0MmMyLjMzMSwtMC44NTQ3IDIuMzU5MTIsLTIuMTQzNTMgLTAuNDQ3MjksLTIuOTk3NjVjLTYuNTM1MzMsLTEuOTg5MDEgLTE3Ljk1NzAzLC01LjQ2NTE4IC0yMS41ODI1MiwtNi41Njg1OWMtMi4xNzUxNCwtMC42NjIgLTMuNDAzNTEsMS4xMjY3MyAtMi4zNDkwMywzLjMwMzczeiIgZmlsbD0iI2EzYTNhMyIgc3Ryb2tlLXdpZHRoPSIzLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjwvZz48L2c+PC9zdmc+", + menuIconURI: iconURI, + blockIconURI: iconURI, color1: "#99bbbb", color2: "#88bbbb", color3: "#88bbbb", diff --git a/images/legobrainbiker/more mouse controls.svg b/images/legobrainbiker/MoreMouseControls.svg similarity index 100% rename from images/legobrainbiker/more mouse controls.svg rename to images/legobrainbiker/MoreMouseControls.svg From 04b7b1a408d9918d284c631bf0e3a35ae86120f4 Mon Sep 17 00:00:00 2001 From: "DangoCat[bot]" Date: Fri, 2 May 2025 19:09:24 +0000 Subject: [PATCH 03/16] [Automated] Format code --- extensions/legobrainbiker/MoreMouseControls.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extensions/legobrainbiker/MoreMouseControls.js b/extensions/legobrainbiker/MoreMouseControls.js index 8fc2ba8ab1..7cdb8f143c 100644 --- a/extensions/legobrainbiker/MoreMouseControls.js +++ b/extensions/legobrainbiker/MoreMouseControls.js @@ -5,7 +5,8 @@ // License: MPL-2.0 (function (Scratch) { "use strict"; - const iconURI = 'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIzNi4zOTI4MSIgaGVpZ2h0PSIzNS40MjY1OSIgdmlld0JveD0iMCwwLDM2LjM5MjgxLDM1LjQyNjU5Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMTU2Ljg4NTQxLC0xNTcuNjM4NDcpIj48ZyBzdHJva2U9IiMwMDAwMDAiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCI+PHBhdGggZD0iTTE2Mi44NjU0NCwxNjcuNDYzMDljMCwtMi4wNDY3NCAxLjc0NjIsLTMuNzA1OTQgMy45MDAyNCwtMy43MDU5NGMyLjE1NDA0LDAgMy45MDAyNCwxLjY1OTIxIDMuOTAwMjQsMy43MDU5NGMwLDIuMDQ2NzQgLTEuNzQ2MiwzLjcwNTk1IC0zLjkwMDI0LDMuNzA1OTVjLTIuMTU0MDQsMCAtMy45MDAyNCwtMS42NTkyMSAtMy45MDAyNCwtMy43MDU5NXoiIGZpbGw9Im5vbmUiIHN0cm9rZS13aWR0aD0iMi41IiBzdHJva2UtbGluZWNhcD0iYnV0dCIvPjxwYXRoIGQ9Ik0xNTguMTM1NDEsMTY3LjQ2MzA5YzAsLTQuNzM1NjMgMy44NjM5LC04LjU3NDYyIDguNjMwMjcsLTguNTc0NjJjNC43NjYzNywwIDguNjMwMjcsMy44Mzg5OSA4LjYzMDI3LDguNTc0NjJjMCw0LjczNTYzIC0zLjg2MzksOC41NzQ2MiAtOC42MzAyNyw4LjU3NDYyYy00Ljc2NjM3LDAgLTguNjMwMjcsLTMuODM4OTkgLTguNjMwMjcsLTguNTc0NjJ6IiBmaWxsPSJub25lIiBzdHJva2Utd2lkdGg9IjIuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMTY3LjE0OTM5LDE3MC45MDY1YzEuNzMxMTMsMy41NzM5NSA3LjA5NTEzLDE0LjY0ODAxIDkuODg1MzksMjAuNDA4NTVjMS4wNDI2OSwyLjE1MjY1IDIuMzMzMzgsMS4xMzM2NiAyLjc1MjMyLC0wLjU0MjA4YzAuNDY3NjksLTEuODcwNzUgMS41NTMyMywtNi4yMTI5MiAyLjE0OTI5LC04LjU5NzE0YzAuMjQ3MDcsLTAuOTg4MjggMS4yMjc3NCwtMS45Mzk5OCAyLjAwNjEzLC0yLjIyNTM5YzEuMTc1NDYsLTAuNDMxIDQuNjg3NzgsLTEuNzE4ODUgNy41ODU3MSwtMi43ODE0MmMyLjMzMSwtMC44NTQ3IDIuMzU5MTIsLTIuMTQzNTMgLTAuNDQ3MjksLTIuOTk3NjVjLTYuNTM1MzMsLTEuOTg5MDEgLTE3Ljk1NzAzLC01LjQ2NTE4IC0yMS41ODI1MiwtNi41Njg1OWMtMi4xNzUxNCwtMC42NjIgLTMuNDAzNTEsMS4xMjY3MyAtMi4zNDkwMywzLjMwMzczeiIgZmlsbD0iI2EzYTNhMyIgc3Ryb2tlLXdpZHRoPSIzLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjwvZz48L2c+PC9zdmc+' + const iconURI = + "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIzNi4zOTI4MSIgaGVpZ2h0PSIzNS40MjY1OSIgdmlld0JveD0iMCwwLDM2LjM5MjgxLDM1LjQyNjU5Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMTU2Ljg4NTQxLC0xNTcuNjM4NDcpIj48ZyBzdHJva2U9IiMwMDAwMDAiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCI+PHBhdGggZD0iTTE2Mi44NjU0NCwxNjcuNDYzMDljMCwtMi4wNDY3NCAxLjc0NjIsLTMuNzA1OTQgMy45MDAyNCwtMy43MDU5NGMyLjE1NDA0LDAgMy45MDAyNCwxLjY1OTIxIDMuOTAwMjQsMy43MDU5NGMwLDIuMDQ2NzQgLTEuNzQ2MiwzLjcwNTk1IC0zLjkwMDI0LDMuNzA1OTVjLTIuMTU0MDQsMCAtMy45MDAyNCwtMS42NTkyMSAtMy45MDAyNCwtMy43MDU5NXoiIGZpbGw9Im5vbmUiIHN0cm9rZS13aWR0aD0iMi41IiBzdHJva2UtbGluZWNhcD0iYnV0dCIvPjxwYXRoIGQ9Ik0xNTguMTM1NDEsMTY3LjQ2MzA5YzAsLTQuNzM1NjMgMy44NjM5LC04LjU3NDYyIDguNjMwMjcsLTguNTc0NjJjNC43NjYzNywwIDguNjMwMjcsMy44Mzg5OSA4LjYzMDI3LDguNTc0NjJjMCw0LjczNTYzIC0zLjg2MzksOC41NzQ2MiAtOC42MzAyNyw4LjU3NDYyYy00Ljc2NjM3LDAgLTguNjMwMjcsLTMuODM4OTkgLTguNjMwMjcsLTguNTc0NjJ6IiBmaWxsPSJub25lIiBzdHJva2Utd2lkdGg9IjIuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMTY3LjE0OTM5LDE3MC45MDY1YzEuNzMxMTMsMy41NzM5NSA3LjA5NTEzLDE0LjY0ODAxIDkuODg1MzksMjAuNDA4NTVjMS4wNDI2OSwyLjE1MjY1IDIuMzMzMzgsMS4xMzM2NiAyLjc1MjMyLC0wLjU0MjA4YzAuNDY3NjksLTEuODcwNzUgMS41NTMyMywtNi4yMTI5MiAyLjE0OTI5LC04LjU5NzE0YzAuMjQ3MDcsLTAuOTg4MjggMS4yMjc3NCwtMS45Mzk5OCAyLjAwNjEzLC0yLjIyNTM5YzEuMTc1NDYsLTAuNDMxIDQuNjg3NzgsLTEuNzE4ODUgNy41ODU3MSwtMi43ODE0MmMyLjMzMSwtMC44NTQ3IDIuMzU5MTIsLTIuMTQzNTMgLTAuNDQ3MjksLTIuOTk3NjVjLTYuNTM1MzMsLTEuOTg5MDEgLTE3Ljk1NzAzLC01LjQ2NTE4IC0yMS41ODI1MiwtNi41Njg1OWMtMi4xNzUxNCwtMC42NjIgLTMuNDAzNTEsMS4xMjY3MyAtMi4zNDkwMywzLjMwMzczeiIgZmlsbD0iI2EzYTNhMyIgc3Ryb2tlLXdpZHRoPSIzLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjwvZz48L2c+PC9zdmc+"; class moreMouseControls { constructor() { this.mouseX = 0; From 35beeaf88ce969c58365dd7f14e91372150f32cb Mon Sep 17 00:00:00 2001 From: LegoBrainBiker Date: Fri, 2 May 2025 13:16:34 -0700 Subject: [PATCH 04/16] legobrainbiker/moremousecontrols: implement mouse pad controls --- .../legobrainbiker/MoreMouseControls.js | 66 +++++++++++++++++-- 1 file changed, 59 insertions(+), 7 deletions(-) diff --git a/extensions/legobrainbiker/MoreMouseControls.js b/extensions/legobrainbiker/MoreMouseControls.js index 7cdb8f143c..881503337d 100644 --- a/extensions/legobrainbiker/MoreMouseControls.js +++ b/extensions/legobrainbiker/MoreMouseControls.js @@ -1,6 +1,6 @@ // Name: More Mouse Controls // ID: legobrainbikerMoreMouseControls -// Description: adds more options to detect properties of the cursor, including its position, clicking, and scrolling. +// Description: Adds more options to detect properties of the cursor, including its position, clicking, and scrolling. // By: legobrainbiker // License: MPL-2.0 (function (Scratch) { @@ -11,10 +11,20 @@ constructor() { this.mouseX = 0; this.mouseY = 0; - this.scroll = 0; + this.mouseWheelDelta = 0; + this.mouseWheelDeltaX = 0; + this.mouseZoomDelta = 0; this.buttons = []; - document.addEventListener("mousewheel", (e) => { - this.mouseWheelDelta = e.deltaY; + document.addEventListener("wheel", (e) => { + if (e.ctrlKey) { + this.mouseZoomDelta = e.deltaY; + this.mouseWheelDelta = 0; + this.mouseWheelDeltaX = 0; + } else { + this.mouseZoomDelta = 0; + this.mouseWheelDelta = e.deltaY; + this.mouseWheelDeltaX = e.deltaX; + } Scratch.vm.runtime.startHats( "legobrainbikerMoreMouseControls_onScroll" ); @@ -80,6 +90,11 @@ blockType: Scratch.BlockType.COMMAND, text: Scratch.translate("disable context menu"), }, + { + opcode: "dissableScroll", + blockType: Scratch.BlockType.COMMAND, + text: Scratch.translate("disable scrolling and zooming"), + }, { opcode: "onScroll", blockType: Scratch.BlockType.EVENT, @@ -87,10 +102,20 @@ isEdgeActivated: false, }, { - opcode: "scrollamount", + opcode: "scrollAmount", blockType: Scratch.BlockType.REPORTER, text: Scratch.translate("scroll amount"), }, + { + opcode: "horozontalScrollAmount", + blockType: Scratch.BlockType.REPORTER, + text: Scratch.translate("horozontal scroll amount"), + }, + { + opcode: "zoomAmount", + blockType: Scratch.BlockType.REPORTER, + text: Scratch.translate("zoom amount"), + }, { opcode: "mouseGlobalX", blockType: Scratch.BlockType.REPORTER, @@ -121,8 +146,35 @@ e.preventDefault(); }); } - scrollamount() { - return this.mouseWheelDelta || 0; + dissableScroll() { + Scratch.renderer.canvas.addEventListener( + "wheel", + (e) => { + e.preventDefault(); + if (e.ctrlKey) { + this.mouseZoomDelta = e.deltaY; + this.mouseWheelDelta = 0; + this.mouseWheelDeltaX = 0; + } else { + this.mouseZoomDelta = 0; + this.mouseWheelDelta = e.deltaY; + this.mouseWheelDeltaX = e.deltaX; + } + Scratch.vm.runtime.startHats( + "legobrainbikerMoreMouseControls_onScroll" + ); + }, + { passive: false } + ); + } + scrollAmount() { + return this.mouseWheelDelta; + } + horozontalScrollAmount() { + return this.mouseWheelDeltaX; + } + zoomAmount() { + return -this.mouseZoomDelta; } mouseGlobalX() { const canvas = Scratch.renderer.canvas.getBoundingClientRect(); From dbabd4af9a537d2b363a0f87a87cfe362fc988b2 Mon Sep 17 00:00:00 2001 From: LegoBrainBiker Date: Wed, 21 May 2025 12:59:53 -0700 Subject: [PATCH 05/16] legobrainbiker/moremousecontrols: consistency improvements --- .../legobrainbiker/MoreMouseControls.js | 84 +++++++++---------- 1 file changed, 40 insertions(+), 44 deletions(-) diff --git a/extensions/legobrainbiker/MoreMouseControls.js b/extensions/legobrainbiker/MoreMouseControls.js index 881503337d..fc37564b1a 100644 --- a/extensions/legobrainbiker/MoreMouseControls.js +++ b/extensions/legobrainbiker/MoreMouseControls.js @@ -15,20 +15,34 @@ this.mouseWheelDeltaX = 0; this.mouseZoomDelta = 0; this.buttons = []; - document.addEventListener("wheel", (e) => { - if (e.ctrlKey) { - this.mouseZoomDelta = e.deltaY; - this.mouseWheelDelta = 0; - this.mouseWheelDeltaX = 0; - } else { - this.mouseZoomDelta = 0; - this.mouseWheelDelta = e.deltaY; - this.mouseWheelDeltaX = e.deltaX; + this.contextMenuDissabled = false; + document.addEventListener("contextmenu", (e) => { + if (this.contextMenuDissabled) { + e.preventDefault(); } - Scratch.vm.runtime.startHats( - "legobrainbikerMoreMouseControls_onScroll" - ); }); + this.scrollDissabled = false; + document.addEventListener( + "wheel", + (e) => { + if (this.scrollDissabled) { + e.preventDefault(); + } + if (e.ctrlKey) { + this.mouseZoomDelta = e.deltaY; + this.mouseWheelDelta = 0; + this.mouseWheelDeltaX = 0; + } else { + this.mouseZoomDelta = 0; + this.mouseWheelDelta = e.deltaY; + this.mouseWheelDeltaX = e.deltaX; + } + Scratch.vm.runtime.startHats( + "legobrainbikerMoreMouseControls_onScroll" + ); + }, + { passive: false } + ); document.addEventListener("mouseup", (e) => { this.buttons[e.button] = false; }); @@ -39,6 +53,11 @@ this.mouseX = e.clientX; this.mouseY = e.clientY; }); + document.addEventListener("mouseleave", (e) => { + this.mouseX = NaN; + this.mouseY = NaN; + // this could be problomatic for some projects. it's not great to add another edge case + }); } getInfo() { return { @@ -86,14 +105,14 @@ }, }, { - opcode: "dissableContextMenu", + opcode: "toggleContextMenu", blockType: Scratch.BlockType.COMMAND, - text: Scratch.translate("disable context menu"), + text: Scratch.translate("toggle context menu"), }, { - opcode: "dissableScroll", + opcode: "toggleScroll", blockType: Scratch.BlockType.COMMAND, - text: Scratch.translate("disable scrolling and zooming"), + text: Scratch.translate("toggle scrolling and zooming"), }, { opcode: "onScroll", @@ -136,39 +155,16 @@ return this.buttonPressed(args); } buttonPressed({ button }) { - console.log(button); - console.log(Scratch.Cast.toNumber(button)); - console.log(this.buttons[Scratch.Cast.toNumber(button)]); return this.buttons[Scratch.Cast.toNumber(button)] || false; } - dissableContextMenu() { - document.addEventListener("contextmenu", (e) => { - e.preventDefault(); - }); + toggleContextMenu() { + this.contextMenuDissabled = !this.contextMenuDissabled; } - dissableScroll() { - Scratch.renderer.canvas.addEventListener( - "wheel", - (e) => { - e.preventDefault(); - if (e.ctrlKey) { - this.mouseZoomDelta = e.deltaY; - this.mouseWheelDelta = 0; - this.mouseWheelDeltaX = 0; - } else { - this.mouseZoomDelta = 0; - this.mouseWheelDelta = e.deltaY; - this.mouseWheelDeltaX = e.deltaX; - } - Scratch.vm.runtime.startHats( - "legobrainbikerMoreMouseControls_onScroll" - ); - }, - { passive: false } - ); + toggleScroll() { + this.scrollDissabled = !this.scrollDissabled; } scrollAmount() { - return this.mouseWheelDelta; + return -this.mouseWheelDelta; } horozontalScrollAmount() { return this.mouseWheelDeltaX; From a6c0beb75ed3b146eabebe971c759246cb6fb588 Mon Sep 17 00:00:00 2001 From: Sameer Brink <122649269+LegoBrainBiker@users.noreply.github.com> Date: Sat, 16 May 2026 09:39:33 -0700 Subject: [PATCH 06/16] make toggling scrolling and the context menu use a menu instead of toggleing and be persistent --- .../legobrainbiker/MoreMouseControls.js | 49 ++++++++++++++++--- 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/extensions/legobrainbiker/MoreMouseControls.js b/extensions/legobrainbiker/MoreMouseControls.js index fc37564b1a..8e696f3111 100644 --- a/extensions/legobrainbiker/MoreMouseControls.js +++ b/extensions/legobrainbiker/MoreMouseControls.js @@ -58,6 +58,13 @@ this.mouseY = NaN; // this could be problomatic for some projects. it's not great to add another edge case }); + vm.runtime.extensionStorage.legobrainbikerMoreMouseControls = vm.runtime.extensionStorage.legobrainbikerMoreMouseControls ?? {}; + if (vm.runtime.extensionStorage.legobrainbikerMoreMouseControls.contextMenuDissabled) { + this.contextMenuDissabled = true + } + if (vm.runtime.extensionStorage.legobrainbikerMoreMouseControls.scrollDissabled) { + this.scrollDissabled = true + } } getInfo() { return { @@ -104,16 +111,30 @@ }, }, }, + "---", { opcode: "toggleContextMenu", blockType: Scratch.BlockType.COMMAND, - text: Scratch.translate("toggle context menu"), + text: Scratch.translate("[TOGGLE] context menu"), + arguments: { + TOGGLE: { + type: Scratch.ArgumentType.STRING, + menu: "toggle", + } + } }, { opcode: "toggleScroll", blockType: Scratch.BlockType.COMMAND, - text: Scratch.translate("toggle scrolling and zooming"), + text: Scratch.translate("[TOGGLE] scrolling and zooming"), + arguments: { + TOGGLE: { + type: Scratch.ArgumentType.STRING, + menu: "toggle", + } + } }, + "---", { opcode: "onScroll", blockType: Scratch.BlockType.EVENT, @@ -146,6 +167,12 @@ text: Scratch.translate("mouse global y position"), }, ], + menus: { + toggle: { + acceptReporters: true, + items: ['enable', 'disable'] + }, + } }; } onMouseUp(args) { @@ -157,11 +184,21 @@ buttonPressed({ button }) { return this.buttons[Scratch.Cast.toNumber(button)] || false; } - toggleContextMenu() { - this.contextMenuDissabled = !this.contextMenuDissabled; + toggleContextMenu({ TOGGLE }) { + if (TOGGLE === 'enable') { + this.contextMenuDissabled = false; + } else if (TOGGLE === 'disable') { + this.contextMenuDissabled = true; + } + vm.runtime.extensionStorage.legobrainbikerMoreMouseControls.contextMenuDissabled = this.contextMenuDissabled; } - toggleScroll() { - this.scrollDissabled = !this.scrollDissabled; + toggleScroll({ TOGGLE }) { + if (TOGGLE === 'enable') { + this.scrollDissabled = false; + } else if (TOGGLE === 'disable') { + this.scrollDissabled = true; + } + vm.runtime.extensionStorage.legobrainbikerMoreMouseControls.scrollDissabled = this.scrollDissabled; } scrollAmount() { return -this.mouseWheelDelta; From 29149fe4b8ae81ec10252c8b63c6c86c6851cc8d Mon Sep 17 00:00:00 2001 From: "DangoCat[bot]" Date: Sat, 16 May 2026 16:41:11 +0000 Subject: [PATCH 07/16] [Automated] Format code --- .../legobrainbiker/MoreMouseControls.js | 43 +++++++++++-------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/extensions/legobrainbiker/MoreMouseControls.js b/extensions/legobrainbiker/MoreMouseControls.js index 8e696f3111..26b97f1bb7 100644 --- a/extensions/legobrainbiker/MoreMouseControls.js +++ b/extensions/legobrainbiker/MoreMouseControls.js @@ -58,12 +58,19 @@ this.mouseY = NaN; // this could be problomatic for some projects. it's not great to add another edge case }); - vm.runtime.extensionStorage.legobrainbikerMoreMouseControls = vm.runtime.extensionStorage.legobrainbikerMoreMouseControls ?? {}; - if (vm.runtime.extensionStorage.legobrainbikerMoreMouseControls.contextMenuDissabled) { - this.contextMenuDissabled = true + vm.runtime.extensionStorage.legobrainbikerMoreMouseControls = + vm.runtime.extensionStorage.legobrainbikerMoreMouseControls ?? {}; + if ( + vm.runtime.extensionStorage.legobrainbikerMoreMouseControls + .contextMenuDissabled + ) { + this.contextMenuDissabled = true; } - if (vm.runtime.extensionStorage.legobrainbikerMoreMouseControls.scrollDissabled) { - this.scrollDissabled = true + if ( + vm.runtime.extensionStorage.legobrainbikerMoreMouseControls + .scrollDissabled + ) { + this.scrollDissabled = true; } } getInfo() { @@ -120,8 +127,8 @@ TOGGLE: { type: Scratch.ArgumentType.STRING, menu: "toggle", - } - } + }, + }, }, { opcode: "toggleScroll", @@ -131,8 +138,8 @@ TOGGLE: { type: Scratch.ArgumentType.STRING, menu: "toggle", - } - } + }, + }, }, "---", { @@ -170,9 +177,9 @@ menus: { toggle: { acceptReporters: true, - items: ['enable', 'disable'] + items: ["enable", "disable"], }, - } + }, }; } onMouseUp(args) { @@ -185,20 +192,22 @@ return this.buttons[Scratch.Cast.toNumber(button)] || false; } toggleContextMenu({ TOGGLE }) { - if (TOGGLE === 'enable') { + if (TOGGLE === "enable") { this.contextMenuDissabled = false; - } else if (TOGGLE === 'disable') { + } else if (TOGGLE === "disable") { this.contextMenuDissabled = true; } - vm.runtime.extensionStorage.legobrainbikerMoreMouseControls.contextMenuDissabled = this.contextMenuDissabled; + vm.runtime.extensionStorage.legobrainbikerMoreMouseControls.contextMenuDissabled = + this.contextMenuDissabled; } toggleScroll({ TOGGLE }) { - if (TOGGLE === 'enable') { + if (TOGGLE === "enable") { this.scrollDissabled = false; - } else if (TOGGLE === 'disable') { + } else if (TOGGLE === "disable") { this.scrollDissabled = true; } - vm.runtime.extensionStorage.legobrainbikerMoreMouseControls.scrollDissabled = this.scrollDissabled; + vm.runtime.extensionStorage.legobrainbikerMoreMouseControls.scrollDissabled = + this.scrollDissabled; } scrollAmount() { return -this.mouseWheelDelta; From 3dd93131a5965a1db71cc6afd228bb48b920911e Mon Sep 17 00:00:00 2001 From: Brackets-Coder <142950368+Brackets-Coder@users.noreply.github.com> Date: Sat, 16 May 2026 12:43:57 -0400 Subject: [PATCH 08/16] Fix lint and format some things --- .../legobrainbiker/MoreMouseControls.js | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/extensions/legobrainbiker/MoreMouseControls.js b/extensions/legobrainbiker/MoreMouseControls.js index 26b97f1bb7..088192a1bb 100644 --- a/extensions/legobrainbiker/MoreMouseControls.js +++ b/extensions/legobrainbiker/MoreMouseControls.js @@ -5,8 +5,12 @@ // License: MPL-2.0 (function (Scratch) { "use strict"; + + const vm = Scratch.vm; + const iconURI = "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIzNi4zOTI4MSIgaGVpZ2h0PSIzNS40MjY1OSIgdmlld0JveD0iMCwwLDM2LjM5MjgxLDM1LjQyNjU5Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMTU2Ljg4NTQxLC0xNTcuNjM4NDcpIj48ZyBzdHJva2U9IiMwMDAwMDAiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCI+PHBhdGggZD0iTTE2Mi44NjU0NCwxNjcuNDYzMDljMCwtMi4wNDY3NCAxLjc0NjIsLTMuNzA1OTQgMy45MDAyNCwtMy43MDU5NGMyLjE1NDA0LDAgMy45MDAyNCwxLjY1OTIxIDMuOTAwMjQsMy43MDU5NGMwLDIuMDQ2NzQgLTEuNzQ2MiwzLjcwNTk1IC0zLjkwMDI0LDMuNzA1OTVjLTIuMTU0MDQsMCAtMy45MDAyNCwtMS42NTkyMSAtMy45MDAyNCwtMy43MDU5NXoiIGZpbGw9Im5vbmUiIHN0cm9rZS13aWR0aD0iMi41IiBzdHJva2UtbGluZWNhcD0iYnV0dCIvPjxwYXRoIGQ9Ik0xNTguMTM1NDEsMTY3LjQ2MzA5YzAsLTQuNzM1NjMgMy44NjM5LC04LjU3NDYyIDguNjMwMjcsLTguNTc0NjJjNC43NjYzNywwIDguNjMwMjcsMy44Mzg5OSA4LjYzMDI3LDguNTc0NjJjMCw0LjczNTYzIC0zLjg2MzksOC41NzQ2MiAtOC42MzAyNyw4LjU3NDYyYy00Ljc2NjM3LDAgLTguNjMwMjcsLTMuODM4OTkgLTguNjMwMjcsLTguNTc0NjJ6IiBmaWxsPSJub25lIiBzdHJva2Utd2lkdGg9IjIuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMTY3LjE0OTM5LDE3MC45MDY1YzEuNzMxMTMsMy41NzM5NSA3LjA5NTEzLDE0LjY0ODAxIDkuODg1MzksMjAuNDA4NTVjMS4wNDI2OSwyLjE1MjY1IDIuMzMzMzgsMS4xMzM2NiAyLjc1MjMyLC0wLjU0MjA4YzAuNDY3NjksLTEuODcwNzUgMS41NTMyMywtNi4yMTI5MiAyLjE0OTI5LC04LjU5NzE0YzAuMjQ3MDcsLTAuOTg4MjggMS4yMjc3NCwtMS45Mzk5OCAyLjAwNjEzLC0yLjIyNTM5YzEuMTc1NDYsLTAuNDMxIDQuNjg3NzgsLTEuNzE4ODUgNy41ODU3MSwtMi43ODE0MmMyLjMzMSwtMC44NTQ3IDIuMzU5MTIsLTIuMTQzNTMgLTAuNDQ3MjksLTIuOTk3NjVjLTYuNTM1MzMsLTEuOTg5MDEgLTE3Ljk1NzAzLC01LjQ2NTE4IC0yMS41ODI1MiwtNi41Njg1OWMtMi4xNzUxNCwtMC42NjIgLTMuNDAzNTEsMS4xMjY3MyAtMi4zNDkwMywzLjMwMzczeiIgZmlsbD0iI2EzYTNhMyIgc3Ryb2tlLXdpZHRoPSIzLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjwvZz48L2c+PC9zdmc+"; + class moreMouseControls { constructor() { this.mouseX = 0; @@ -16,12 +20,14 @@ this.mouseZoomDelta = 0; this.buttons = []; this.contextMenuDissabled = false; + document.addEventListener("contextmenu", (e) => { if (this.contextMenuDissabled) { e.preventDefault(); } }); this.scrollDissabled = false; + document.addEventListener( "wheel", (e) => { @@ -43,23 +49,29 @@ }, { passive: false } ); + document.addEventListener("mouseup", (e) => { this.buttons[e.button] = false; }); + document.addEventListener("mousedown", (e) => { this.buttons[e.button] = true; }); + document.addEventListener("mousemove", (e) => { this.mouseX = e.clientX; this.mouseY = e.clientY; }); + document.addEventListener("mouseleave", (e) => { this.mouseX = NaN; this.mouseY = NaN; // this could be problomatic for some projects. it's not great to add another edge case }); + vm.runtime.extensionStorage.legobrainbikerMoreMouseControls = vm.runtime.extensionStorage.legobrainbikerMoreMouseControls ?? {}; + if ( vm.runtime.extensionStorage.legobrainbikerMoreMouseControls .contextMenuDissabled @@ -72,7 +84,9 @@ ) { this.scrollDissabled = true; } + } + getInfo() { return { id: "legobrainbikerMoreMouseControls", @@ -182,15 +196,19 @@ }, }; } + onMouseUp(args) { return !this.buttonPressed(args); } + onMouseDown(args) { return this.buttonPressed(args); } + buttonPressed({ button }) { return this.buttons[Scratch.Cast.toNumber(button)] || false; } + toggleContextMenu({ TOGGLE }) { if (TOGGLE === "enable") { this.contextMenuDissabled = false; @@ -200,6 +218,7 @@ vm.runtime.extensionStorage.legobrainbikerMoreMouseControls.contextMenuDissabled = this.contextMenuDissabled; } + toggleScroll({ TOGGLE }) { if (TOGGLE === "enable") { this.scrollDissabled = false; @@ -209,19 +228,24 @@ vm.runtime.extensionStorage.legobrainbikerMoreMouseControls.scrollDissabled = this.scrollDissabled; } + scrollAmount() { return -this.mouseWheelDelta; } + horozontalScrollAmount() { return this.mouseWheelDeltaX; } + zoomAmount() { return -this.mouseZoomDelta; } + mouseGlobalX() { const canvas = Scratch.renderer.canvas.getBoundingClientRect(); return this.mouseX - canvas.x - canvas.width / 2; } + mouseGlobalY() { const canvas = Scratch.renderer.canvas.getBoundingClientRect(); return -(this.mouseY - canvas.y - canvas.height / 2); From 95a0a3258708302b9ac2a3cfc071f7f1016d2eec Mon Sep 17 00:00:00 2001 From: "DangoCat[bot]" Date: Sat, 16 May 2026 16:44:59 +0000 Subject: [PATCH 09/16] [Automated] Format code --- .../legobrainbiker/MoreMouseControls.js | 43 +++++++++---------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/extensions/legobrainbiker/MoreMouseControls.js b/extensions/legobrainbiker/MoreMouseControls.js index 088192a1bb..913a8524f9 100644 --- a/extensions/legobrainbiker/MoreMouseControls.js +++ b/extensions/legobrainbiker/MoreMouseControls.js @@ -7,10 +7,10 @@ "use strict"; const vm = Scratch.vm; - + const iconURI = "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIzNi4zOTI4MSIgaGVpZ2h0PSIzNS40MjY1OSIgdmlld0JveD0iMCwwLDM2LjM5MjgxLDM1LjQyNjU5Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMTU2Ljg4NTQxLC0xNTcuNjM4NDcpIj48ZyBzdHJva2U9IiMwMDAwMDAiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCI+PHBhdGggZD0iTTE2Mi44NjU0NCwxNjcuNDYzMDljMCwtMi4wNDY3NCAxLjc0NjIsLTMuNzA1OTQgMy45MDAyNCwtMy43MDU5NGMyLjE1NDA0LDAgMy45MDAyNCwxLjY1OTIxIDMuOTAwMjQsMy43MDU5NGMwLDIuMDQ2NzQgLTEuNzQ2MiwzLjcwNTk1IC0zLjkwMDI0LDMuNzA1OTVjLTIuMTU0MDQsMCAtMy45MDAyNCwtMS42NTkyMSAtMy45MDAyNCwtMy43MDU5NXoiIGZpbGw9Im5vbmUiIHN0cm9rZS13aWR0aD0iMi41IiBzdHJva2UtbGluZWNhcD0iYnV0dCIvPjxwYXRoIGQ9Ik0xNTguMTM1NDEsMTY3LjQ2MzA5YzAsLTQuNzM1NjMgMy44NjM5LC04LjU3NDYyIDguNjMwMjcsLTguNTc0NjJjNC43NjYzNywwIDguNjMwMjcsMy44Mzg5OSA4LjYzMDI3LDguNTc0NjJjMCw0LjczNTYzIC0zLjg2MzksOC41NzQ2MiAtOC42MzAyNyw4LjU3NDYyYy00Ljc2NjM3LDAgLTguNjMwMjcsLTMuODM4OTkgLTguNjMwMjcsLTguNTc0NjJ6IiBmaWxsPSJub25lIiBzdHJva2Utd2lkdGg9IjIuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMTY3LjE0OTM5LDE3MC45MDY1YzEuNzMxMTMsMy41NzM5NSA3LjA5NTEzLDE0LjY0ODAxIDkuODg1MzksMjAuNDA4NTVjMS4wNDI2OSwyLjE1MjY1IDIuMzMzMzgsMS4xMzM2NiAyLjc1MjMyLC0wLjU0MjA4YzAuNDY3NjksLTEuODcwNzUgMS41NTMyMywtNi4yMTI5MiAyLjE0OTI5LC04LjU5NzE0YzAuMjQ3MDcsLTAuOTg4MjggMS4yMjc3NCwtMS45Mzk5OCAyLjAwNjEzLC0yLjIyNTM5YzEuMTc1NDYsLTAuNDMxIDQuNjg3NzgsLTEuNzE4ODUgNy41ODU3MSwtMi43ODE0MmMyLjMzMSwtMC44NTQ3IDIuMzU5MTIsLTIuMTQzNTMgLTAuNDQ3MjksLTIuOTk3NjVjLTYuNTM1MzMsLTEuOTg5MDEgLTE3Ljk1NzAzLC01LjQ2NTE4IC0yMS41ODI1MiwtNi41Njg1OWMtMi4xNzUxNCwtMC42NjIgLTMuNDAzNTEsMS4xMjY3MyAtMi4zNDkwMywzLjMwMzczeiIgZmlsbD0iI2EzYTNhMyIgc3Ryb2tlLXdpZHRoPSIzLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjwvZz48L2c+PC9zdmc+"; - + class moreMouseControls { constructor() { this.mouseX = 0; @@ -20,14 +20,14 @@ this.mouseZoomDelta = 0; this.buttons = []; this.contextMenuDissabled = false; - + document.addEventListener("contextmenu", (e) => { if (this.contextMenuDissabled) { e.preventDefault(); } }); this.scrollDissabled = false; - + document.addEventListener( "wheel", (e) => { @@ -49,29 +49,29 @@ }, { passive: false } ); - + document.addEventListener("mouseup", (e) => { this.buttons[e.button] = false; }); - + document.addEventListener("mousedown", (e) => { this.buttons[e.button] = true; }); - + document.addEventListener("mousemove", (e) => { this.mouseX = e.clientX; this.mouseY = e.clientY; }); - + document.addEventListener("mouseleave", (e) => { this.mouseX = NaN; this.mouseY = NaN; // this could be problomatic for some projects. it's not great to add another edge case }); - + vm.runtime.extensionStorage.legobrainbikerMoreMouseControls = vm.runtime.extensionStorage.legobrainbikerMoreMouseControls ?? {}; - + if ( vm.runtime.extensionStorage.legobrainbikerMoreMouseControls .contextMenuDissabled @@ -84,9 +84,8 @@ ) { this.scrollDissabled = true; } - } - + getInfo() { return { id: "legobrainbikerMoreMouseControls", @@ -196,19 +195,19 @@ }, }; } - + onMouseUp(args) { return !this.buttonPressed(args); } - + onMouseDown(args) { return this.buttonPressed(args); } - + buttonPressed({ button }) { return this.buttons[Scratch.Cast.toNumber(button)] || false; } - + toggleContextMenu({ TOGGLE }) { if (TOGGLE === "enable") { this.contextMenuDissabled = false; @@ -218,7 +217,7 @@ vm.runtime.extensionStorage.legobrainbikerMoreMouseControls.contextMenuDissabled = this.contextMenuDissabled; } - + toggleScroll({ TOGGLE }) { if (TOGGLE === "enable") { this.scrollDissabled = false; @@ -228,24 +227,24 @@ vm.runtime.extensionStorage.legobrainbikerMoreMouseControls.scrollDissabled = this.scrollDissabled; } - + scrollAmount() { return -this.mouseWheelDelta; } - + horozontalScrollAmount() { return this.mouseWheelDeltaX; } - + zoomAmount() { return -this.mouseZoomDelta; } - + mouseGlobalX() { const canvas = Scratch.renderer.canvas.getBoundingClientRect(); return this.mouseX - canvas.x - canvas.width / 2; } - + mouseGlobalY() { const canvas = Scratch.renderer.canvas.getBoundingClientRect(); return -(this.mouseY - canvas.y - canvas.height / 2); From 1fbe5ee6872dd84731e0a166b1d501776427220b Mon Sep 17 00:00:00 2001 From: Den4ik-12 <133135758+DDen4ik-12@users.noreply.github.com> Date: Tue, 19 May 2026 19:03:19 +0500 Subject: [PATCH 10/16] =?UTF-8?q?MoreMouseControls.js:=20=E2=9C=A8=20Impro?= =?UTF-8?q?vements,=20fixes,=20new=20icons=20+=20blocks=20from=20Wheel=20S?= =?UTF-8?q?croll?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../legobrainbiker/MoreMouseControls.js | 446 ++++++++++++------ 1 file changed, 299 insertions(+), 147 deletions(-) diff --git a/extensions/legobrainbiker/MoreMouseControls.js b/extensions/legobrainbiker/MoreMouseControls.js index 913a8524f9..cf0db72fad 100644 --- a/extensions/legobrainbiker/MoreMouseControls.js +++ b/extensions/legobrainbiker/MoreMouseControls.js @@ -1,254 +1,406 @@ // Name: More Mouse Controls // ID: legobrainbikerMoreMouseControls -// Description: Adds more options to detect properties of the cursor, including its position, clicking, and scrolling. +// Description: Adds more options to detect properties of the mouse, including it's position, clicking, and wheel scrolling. // By: legobrainbiker +// By: Den4ik-12 // License: MPL-2.0 + (function (Scratch) { "use strict"; + if (!Scratch.extensions.unsandboxed) { + throw new Error( + 'Extension "More Mouse Controls" must run unsandboxed! Please enable the unsandboxed mode when loading the extension.' + ); + } + const vm = Scratch.vm; + const runtime = vm.runtime; + const canvas = Scratch.renderer.canvas; + const Cast = Scratch.Cast; + + const extId = "legobrainbikerMoreMouseControls"; + const extIcon = + "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgdmVyc2lvbj0iMS4xIgogICB3aWR0aD0iMjA1IgogICBoZWlnaHQ9IjIwNSIKICAgdmlld0JveD0iMCAwIDIwNSAyMDUiCiAgIGlkPSJzdmc4IgogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogIDxkZWZzCiAgICAgaWQ9ImRlZnM4IiAvPgogIDxwYXRoCiAgICAgZD0ibSAyLjUsMTAyLjUgYyAwLC01NS4yMjg0NyA0NC43NzE1MywtMTAwIDEwMCwtMTAwIDU1LjIyODQ3LDAgMTAwLDQ0Ljc3MTUzIDEwMCwxMDAgMCw1NS4yMjg0NyAtNDQuNzcxNTMsMTAwIC0xMDAsMTAwIC01NS4yMjg0NywwIC0xMDAsLTQ0Ljc3MTUzIC0xMDAsLTEwMCB6IgogICAgIGZpbGw9IiNlNzRjM2MiCiAgICAgc3Ryb2tlPSIjYjAzYTJlIgogICAgIHN0cm9rZS13aWR0aD0iNSIKICAgICBpZD0icGF0aDEiCiAgICAgc3R5bGU9Im1peC1ibGVuZC1tb2RlOm5vcm1hbDtmaWxsOiM5OWJiYmI7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOiM2MzdhN2E7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MSIgLz4KICA8cGF0aAogICAgIGQ9Ik0gOTcuMTY3OTY5LDIzLjc1NzgxMiBDIDczLjI0MDQ5OSwyNi40Mzk0NjMgNTQuNjQ0NTMxLDQ2LjczODYxOSA1NC42NDQ1MzEsNzEuMzgwODU5IGwgLTAuMTk5MjE5LDIxLjMwNDY4OCA0Mi41NTg1OTQsMC4xNjAxNTYgMC4wMzUxNiwtNS41MjczNDQgYyAwLDAgLTEwLjQxNTQxMiwtNC4wMzk0NDggLTEwLjQ0NTMxMiwtMTEuNzM2MzI4IC0wLjAxNTc4LC00LjA2NTI0IC0wLjE3MDg2MiwtMTQuNTgwOTA4IDAuMDg1OTQsLTIzLjUxNzU3OCAwLjI0NywtOC41OTU1MiAxMS41NTQ2ODgsLTEyLjM4ODY3MiAxMS41NTQ2ODgsLTEyLjM4ODY3MiAwLDAgLTAuNTEzMTM2LC0xNS45Nzk5NjkgLTEuMDY2NDA2LC0xNS45MTc5NjkgeiBtIDEwLjY2NDA2MSwwIGMgLTAuNTUzMjgsLTAuMDYyMDEgLTEuMDY2NCwxNS45MTc5NjkgLTEuMDY2NCwxNS45MTc5NjkgLTFlLTUsMCAxMS4zMDc2OCwzLjc5MzE3MiAxMS41NTQ2OCwxMi4zODg2NzIgMC4yNTY4Myw4LjkzNjY3IDAuMTAxNzQsMTkuNDUyMzQ4IDAuMDg1OSwyMy41MTc1NzggLTAuMDI5OSw3LjY5Njg5IC0xMC40NDUzMSwxMS43MzYzMjggLTEwLjQ0NTMxLDExLjczNjMyOCBsIDAuMDM1Miw1LjUyNzM0NCA0Mi41NTg2LC0wLjE2MDE1NiAtMC4xOTkyMiwtMjEuMzA0Njg4IGMgMCwtMjQuNjQyMjYgLTE4LjU5NTk3LC00NC45NDEzODYgLTQyLjUyMzQ0LC00Ny42MjMwNDcgeiBtIC01LjI2NTYyLDI0LjgwMDc4MiBjIC0zLjM4MTQxNCwwIC02LjEyMzA1MSwyLjc0MTkzNyAtNi4xMjMwNTEsNi4xMjMwNDcgdiAxNy45MTYwMTUgYyAwLDMuMzgxMTEgMi43NDIyMzcsNi4xMjEwOTQgNi4xMjMwNTEsNi4xMjEwOTQgMy4zODA4MiwwIDYuMTIxMDksLTIuNzM5OTg0IDYuMTIxMDksLTYuMTIxMDk0IFYgNTQuNjgxNjQxIGMgMCwtMy4zODE0MSAtMi43Mzk3LC02LjEyMzA0NyAtNi4xMjEwOSwtNi4xMjMwNDcgeiBNIDU0LjY0NDUzMSwxMDIuODU5MzggdiAzMC40NjI4OSBjIDAsMjYuNDY2NyAyMS40NTU0MjIsNDcuOTE5OTIgNDcuOTE5OTE5LDQ3LjkxOTkyIDI2LjQ2NDUsMCA0Ny45MjE4OCwtMjEuNDUzMiA0Ny45MjE4OCwtNDcuOTE5OTIgdiAtMzAuNDYyODkgeiIKICAgICBzdHlsZT0iZmlsbDojZmZmZmZmO3N0cm9rZS1taXRlcmxpbWl0OjEwIgogICAgIGlkPSJwYXRoOCIgLz4KPC9zdmc+CjwhLS1yb3RhdGlvbkNlbnRlcjoxMDIuNToxMDIuNS0tPgoK"; + const blockIcon = + "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgdmVyc2lvbj0iMS4xIgogICB3aWR0aD0iMTE3LjMzMzMzIgogICBoZWlnaHQ9IjExNy4zMzMzMyIKICAgdmlld0JveD0iMCAwIDExNy4zMzMzMyAxMTcuMzMzMzMiCiAgIGlkPSJzdmcxNCIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICA8ZGVmcwogICAgIGlkPSJkZWZzMTQiIC8+CiAgPHBhdGgKICAgICBkPSJNIDU1LjA4OTUxNSw1LjgzNzQ4MyBDIDM5LjAzNjk1NSw3LjYzNjU2MzEgMjYuNTYyMTcxLDIxLjI1NDYwMSAyNi41NjIxNzEsMzcuNzg2NzAxIGwgLTAuMTM0NzY1LDE0LjI5Mjk2OSAyOC41NTI3MzQsMC4xMDc0MjIgMC4wMjM0NCwtMy43MDcwMzEgYyAwLDAgLTYuOTg3NzEzLC0yLjcxMTI4IC03LjAwNzgxMywtNy44NzUgLTAuMDEwNywtMi43MjczMSAtMC4xMTU2NDksLTkuNzgxODc0IDAuMDU2NjQsLTE1Ljc3NzM0NCAwLjE2NTcxLC01Ljc2NjYxIDcuNzUxOTUzLC04LjMxMDU0NyA3Ljc1MTk1MywtOC4zMTA1NDcgMCwwIC0wLjM0MzY2NCwtMTAuNzIxMjg2OSAtMC43MTQ4NDQsLTEwLjY3OTY4NyB6IG0gNy4xNTQyOTcsMCBjIC0wLjM3MTE5LC0wLjA0MTU5IC0wLjcxNDg0NCwxMC42Nzk2ODcgLTAuNzE0ODQ0LDEwLjY3OTY4NyAwLDAgNy41ODYyNDQsMi41NDM5NDcgNy43NTE5NTMsOC4zMTA1NDcgMC4xNzIyNCw1Ljk5NTQ3IDAuMDY3MjQsMTMuMDUwMDQ0IDAuMDU2NjQsMTUuNzc3MzQ0IC0wLjAyMDA4LDUuMTYzNzIgLTcuMDA3ODEyLDcuODc1IC03LjAwNzgxMiw3Ljg3NSBsIDAuMDIzNDQsMy43MDcwMzEgMjguNTUyNzM0LC0wLjEwNzQyMiAtMC4xMzQ3NjUsLTE0LjI5Mjk2OSBjIDAsLTE2LjUzMjA4OSAtMTIuNDc0Nzg0LC0zMC4xNTAxMzggLTI4LjUyNzM0NCwtMzEuOTQ5MjE4IHogbSAtMy41MzMyMDMsMTYuNjM4NjcyIGMgLTIuMjY4NTMsMCAtNC4xMDc0MjIsMS44MzkwODIgLTQuMTA3NDIyLDQuMTA3NDIxIHYgMTIuMDE5NTMyIGMgMCwyLjI2ODMyIDEuODM5MjkyLDQuMTA3NDIyIDQuMTA3NDIyLDQuMTA3NDIyIDIuMjY4MTQsMCA0LjEwNzQyMiwtMS44MzkwODIgNC4xMDc0MjIsLTQuMTA3NDIyIFYgMjYuNTgzNTc2IGMgMCwtMi4yNjg1MjkgLTEuODM4OTAyLC00LjEwNzQyMSAtNC4xMDc0MjIsLTQuMTA3NDIxIHogTSAyNi41NjIxNzEsNTguOTA1ODQyIHYgMjAuNDM3NSBjIDAsMTcuNzU2MTIgMTQuMzkzODA4LDMyLjE0ODQzOCAzMi4xNDg0MzgsMzIuMTQ4NDM4IDE3Ljc1NDYzLDAgMzIuMTUwMzkxLC0xNC4zOTIzMjggMzIuMTUwMzkxLC0zMi4xNDg0MzggdiAtMjAuNDM3NSB6IgogICAgIHN0eWxlPSJmaWxsOiNmZmZmZmY7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjEwO3N0cm9rZS1taXRlcmxpbWl0OjEwO3N0cm9rZS1vcGFjaXR5OjAuMTQ5MDI7cGFpbnQtb3JkZXI6c3Ryb2tlIGZpbGwgbWFya2VycyIKICAgICBpZD0icGF0aDE0IiAvPgo8L3N2Zz4KPCEtLXJvdGF0aW9uQ2VudGVyOjU4LjY2NjY2NjY2NjY2NjY2OjU4LjY2NjY2NjY2NjY2NjY2LS0+Cgo="; - const iconURI = - "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIzNi4zOTI4MSIgaGVpZ2h0PSIzNS40MjY1OSIgdmlld0JveD0iMCwwLDM2LjM5MjgxLDM1LjQyNjU5Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMTU2Ljg4NTQxLC0xNTcuNjM4NDcpIj48ZyBzdHJva2U9IiMwMDAwMDAiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCI+PHBhdGggZD0iTTE2Mi44NjU0NCwxNjcuNDYzMDljMCwtMi4wNDY3NCAxLjc0NjIsLTMuNzA1OTQgMy45MDAyNCwtMy43MDU5NGMyLjE1NDA0LDAgMy45MDAyNCwxLjY1OTIxIDMuOTAwMjQsMy43MDU5NGMwLDIuMDQ2NzQgLTEuNzQ2MiwzLjcwNTk1IC0zLjkwMDI0LDMuNzA1OTVjLTIuMTU0MDQsMCAtMy45MDAyNCwtMS42NTkyMSAtMy45MDAyNCwtMy43MDU5NXoiIGZpbGw9Im5vbmUiIHN0cm9rZS13aWR0aD0iMi41IiBzdHJva2UtbGluZWNhcD0iYnV0dCIvPjxwYXRoIGQ9Ik0xNTguMTM1NDEsMTY3LjQ2MzA5YzAsLTQuNzM1NjMgMy44NjM5LC04LjU3NDYyIDguNjMwMjcsLTguNTc0NjJjNC43NjYzNywwIDguNjMwMjcsMy44Mzg5OSA4LjYzMDI3LDguNTc0NjJjMCw0LjczNTYzIC0zLjg2MzksOC41NzQ2MiAtOC42MzAyNyw4LjU3NDYyYy00Ljc2NjM3LDAgLTguNjMwMjcsLTMuODM4OTkgLTguNjMwMjcsLTguNTc0NjJ6IiBmaWxsPSJub25lIiBzdHJva2Utd2lkdGg9IjIuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMTY3LjE0OTM5LDE3MC45MDY1YzEuNzMxMTMsMy41NzM5NSA3LjA5NTEzLDE0LjY0ODAxIDkuODg1MzksMjAuNDA4NTVjMS4wNDI2OSwyLjE1MjY1IDIuMzMzMzgsMS4xMzM2NiAyLjc1MjMyLC0wLjU0MjA4YzAuNDY3NjksLTEuODcwNzUgMS41NTMyMywtNi4yMTI5MiAyLjE0OTI5LC04LjU5NzE0YzAuMjQ3MDcsLTAuOTg4MjggMS4yMjc3NCwtMS45Mzk5OCAyLjAwNjEzLC0yLjIyNTM5YzEuMTc1NDYsLTAuNDMxIDQuNjg3NzgsLTEuNzE4ODUgNy41ODU3MSwtMi43ODE0MmMyLjMzMSwtMC44NTQ3IDIuMzU5MTIsLTIuMTQzNTMgLTAuNDQ3MjksLTIuOTk3NjVjLTYuNTM1MzMsLTEuOTg5MDEgLTE3Ljk1NzAzLC01LjQ2NTE4IC0yMS41ODI1MiwtNi41Njg1OWMtMi4xNzUxNCwtMC42NjIgLTMuNDAzNTEsMS4xMjY3MyAtMi4zNDkwMywzLjMwMzczeiIgZmlsbD0iI2EzYTNhMyIgc3Ryb2tlLXdpZHRoPSIzLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjwvZz48L2c+PC9zdmc+"; + const deltaModes = ["px", "lines", "pages"]; + const scrollAxises = { X_AXIS: 0, Y_AXIS: 1, Z_AXIS: 2 }; + const scrollDirs = [ + { AXIS: "ax", NEG: "l", POS: "r" }, + { AXIS: "ay", NEG: "u", POS: "d" }, + { AXIS: "az", NEG: "o", POS: "i" }, + ]; - class moreMouseControls { + class MoreMouseControls { constructor() { + runtime.extensionStorage[extId] = runtime.extensionStorage[extId] ?? {}; + this.mouseX = 0; this.mouseY = 0; - this.mouseWheelDelta = 0; - this.mouseWheelDeltaX = 0; - this.mouseZoomDelta = 0; - this.buttons = []; - this.contextMenuDissabled = false; - - document.addEventListener("contextmenu", (e) => { - if (this.contextMenuDissabled) { - e.preventDefault(); - } + this.wheelScrolled = false; + this.wheelDelta = Object.assign(Object.create(null), { + x: 0, + y: 0, + z: 0, + mode: "", }); - this.scrollDissabled = false; + this.scrollDisabled = runtime.extensionStorage[extId].scrollDisabled || false; + runtime.ioDevices.mouse.usesRightClickDown = runtime.extensionStorage[extId].contextMenuDisabled || false; - document.addEventListener( + // An event listener is used instead of Mouse I/O API, + // as the latter doesn't provide deltaZ and deltaMode + canvas.addEventListener( "wheel", (e) => { - if (this.scrollDissabled) { + if (this.scrollDisabled) { e.preventDefault(); } - if (e.ctrlKey) { - this.mouseZoomDelta = e.deltaY; - this.mouseWheelDelta = 0; - this.mouseWheelDeltaX = 0; - } else { - this.mouseZoomDelta = 0; - this.mouseWheelDelta = e.deltaY; - this.mouseWheelDeltaX = e.deltaX; - } - Scratch.vm.runtime.startHats( - "legobrainbikerMoreMouseControls_onScroll" - ); + + this.wheelScrolled = true; + this.wheelDelta.x += e.deltaX; + this.wheelDelta.y += e.deltaY; + this.wheelDelta.z += e.deltaZ; + this.wheelDelta.mode = deltaModes[e.deltaMode] || ""; + + runtime.startHats(`${extId}_onScroll`); + this._startOnScrollHats(e.deltaX, scrollAxises.X_AXIS); + this._startOnScrollHats(e.deltaY, scrollAxises.Y_AXIS); + this._startOnScrollHats(e.deltaZ, scrollAxises.Z_AXIS); }, - { passive: false } + { passive: true } ); - - document.addEventListener("mouseup", (e) => { - this.buttons[e.button] = false; + runtime.on("AFTER_EXECUTE", () => { + this.wheelScrolled = false; + Object.assign(this.wheelDelta, { + x: 0, + y: 0, + z: 0, + mode: "", + }); }); - document.addEventListener("mousedown", (e) => { - this.buttons[e.button] = true; - }); + const ogIoMousePostData = runtime.ioDevices.mouse.postData; + // https://github.com/TurboWarp/scratch-vm/blob/develop/src/io/mouse.js + runtime.ioDevices.mouse.postData = function(data) { + if (typeof data.isDown !== "undefined") { + // Do not trigger if down state has not changed + if (data.isDown === this._isDown) { + ogIoMousePostData.call(this, data); + return; + } + + const button = data.button ?? 0; + if (data.isDown) { + runtime.startHats(`${extId}_onMouseDown`, { + BUTTON: Cast.toString(button), + }); + } else { + runtime.startHats(`${extId}_onMouseUp`, { + BUTTON: Cast.toString(button), + }); + } + } + ogIoMousePostData.call(this, data); + } document.addEventListener("mousemove", (e) => { this.mouseX = e.clientX; this.mouseY = e.clientY; }); - document.addEventListener("mouseleave", (e) => { this.mouseX = NaN; this.mouseY = NaN; - // this could be problomatic for some projects. it's not great to add another edge case + // This could be problematic for some projects. + // It's not great to add another edge case }); - - vm.runtime.extensionStorage.legobrainbikerMoreMouseControls = - vm.runtime.extensionStorage.legobrainbikerMoreMouseControls ?? {}; - - if ( - vm.runtime.extensionStorage.legobrainbikerMoreMouseControls - .contextMenuDissabled - ) { - this.contextMenuDissabled = true; - } - if ( - vm.runtime.extensionStorage.legobrainbikerMoreMouseControls - .scrollDissabled - ) { - this.scrollDissabled = true; - } } getInfo() { return { - id: "legobrainbikerMoreMouseControls", + id: extId, name: Scratch.translate("More Mouse Controls"), - menuIconURI: iconURI, - blockIconURI: iconURI, + menuIconURI: extIcon, + blockIconURI: blockIcon, color1: "#99bbbb", - color2: "#88bbbb", - color3: "#88bbbb", + color2: "#7a9696", + color3: "#637a7a", blocks: [ { opcode: "onMouseUp", - blockType: Scratch.BlockType.HAT, - text: Scratch.translate("when mouse button [button] is released"), - isEdgeActivated: true, + blockType: Scratch.BlockType.EVENT, + isEdgeActivated: false, + shouldRestartExistingThreads: true, + text: Scratch.translate("when [BUTTON] mouse button released"), arguments: { - button: { - type: Scratch.ArgumentType.NUMBER, + BUTTON: { + menu: "BUTTON_TYPE", defaultValue: "0", }, }, }, { opcode: "onMouseDown", - blockType: Scratch.BlockType.HAT, - text: Scratch.translate("when mouse button [button] is pressed"), - isEdgeActivated: true, + blockType: Scratch.BlockType.EVENT, + isEdgeActivated: false, + shouldRestartExistingThreads: true, + text: Scratch.translate("when [BUTTON] mouse button pressed"), arguments: { - button: { - type: Scratch.ArgumentType.NUMBER, + BUTTON: { + menu: "BUTTON_TYPE", defaultValue: "0", }, }, }, + "---", { - opcode: "buttonPressed", - blockType: Scratch.BlockType.BOOLEAN, - text: Scratch.translate("mouse button [button] is pressed"), + opcode: "onScrollInDir", + blockType: Scratch.BlockType.EVENT, + isEdgeActivated: false, + text: Scratch.translate("when mouse wheel scrolled [SCROLL_DIR]"), arguments: { - button: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: "0", + SCROLL_DIR: { + menu: "SCROLL_DIRS", + defaultValue: scrollDirs[scrollAxises.Y_AXIS].NEG, }, }, }, - "---", { - opcode: "toggleContextMenu", - blockType: Scratch.BlockType.COMMAND, - text: Scratch.translate("[TOGGLE] context menu"), - arguments: { - TOGGLE: { - type: Scratch.ArgumentType.STRING, - menu: "toggle", - }, - }, + opcode: "onScroll", + blockType: Scratch.BlockType.EVENT, + isEdgeActivated: false, + text: Scratch.translate("when mouse wheel scrolled"), }, { - opcode: "toggleScroll", - blockType: Scratch.BlockType.COMMAND, - text: Scratch.translate("[TOGGLE] scrolling and zooming"), + opcode: "isScrolledInDir", + blockType: Scratch.BlockType.BOOLEAN, + text: Scratch.translate("mouse wheel scrolled [SCROLL_DIR]?"), arguments: { - TOGGLE: { - type: Scratch.ArgumentType.STRING, - menu: "toggle", + SCROLL_DIR: { + menu: "SCROLL_DIRS", + defaultValue: scrollDirs[scrollAxises.Y_AXIS].NEG, }, }, }, - "---", { - opcode: "onScroll", - blockType: Scratch.BlockType.EVENT, - text: Scratch.translate("when scrolling"), - isEdgeActivated: false, + opcode: "isScrolled", + blockType: Scratch.BlockType.BOOLEAN, + text: Scratch.translate("mouse wheel scrolled?"), }, { - opcode: "scrollAmount", + opcode: "getDelta", blockType: Scratch.BlockType.REPORTER, - text: Scratch.translate("scroll amount"), + text: Scratch.translate("scroll delta [DELTA_TYPE]"), + disableMonitor: true, + arguments: { + DELTA_TYPE: { + menu: "DELTA_TYPE", + defaultValue: "y", + }, + }, }, + "---", { - opcode: "horozontalScrollAmount", + opcode: "mouseGlobalX", blockType: Scratch.BlockType.REPORTER, - text: Scratch.translate("horozontal scroll amount"), + text: Scratch.translate("global mouse x"), }, { - opcode: "zoomAmount", + opcode: "mouseGlobalY", blockType: Scratch.BlockType.REPORTER, - text: Scratch.translate("zoom amount"), + text: Scratch.translate("global mouse y"), }, + "---", { - opcode: "mouseGlobalX", - blockType: Scratch.BlockType.REPORTER, - text: Scratch.translate("mouse global x position"), + opcode: "toggleContextMenu", + blockType: Scratch.BlockType.COMMAND, + text: Scratch.translate("[TOGGLE] context menu"), + arguments: { + TOGGLE: { + menu: "TOGGLE_TYPE", + }, + }, }, { - opcode: "mouseGlobalY", - blockType: Scratch.BlockType.REPORTER, - text: Scratch.translate("mouse global y position"), + opcode: "toggleScroll", + blockType: Scratch.BlockType.COMMAND, + text: Scratch.translate("[TOGGLE] scrolling"), + arguments: { + TOGGLE: { + menu: "TOGGLE_TYPE", + }, + }, }, ], menus: { - toggle: { + BUTTON_TYPE: { + items: [ + { + text: Scratch.translate("(0) primary"), + value: "0", + }, + { + text: Scratch.translate("(1) middle"), + value: "1", + }, + { + text: Scratch.translate("(2) secondary"), + value: "2", + }, + { + text: Scratch.translate("(3) tertiary"), + value: "3", + }, + { + text: Scratch.translate("(4) quaternary"), + value: "4", + }, + ], + }, + SCROLL_DIRS: { + items: [ + { + text: Scratch.translate("up"), + value: scrollDirs[scrollAxises.Y_AXIS].NEG, + }, + { + text: Scratch.translate("down"), + value: scrollDirs[scrollAxises.Y_AXIS].POS, + }, + { + text: Scratch.translate("to the left"), + value: scrollDirs[scrollAxises.X_AXIS].NEG, + }, + { + text: Scratch.translate("to the right"), + value: scrollDirs[scrollAxises.X_AXIS].POS, + }, + { + text: Scratch.translate("out"), + value: scrollDirs[scrollAxises.Z_AXIS].NEG, + }, + { + text: Scratch.translate("in"), + value: scrollDirs[scrollAxises.Z_AXIS].POS, + }, + { + text: Scratch.translate("along the x-axis"), + value: scrollDirs[scrollAxises.X_AXIS].AXIS, + }, + { + text: Scratch.translate("along the y-axis"), + value: scrollDirs[scrollAxises.Y_AXIS].AXIS, + }, + { + text: Scratch.translate("along the z-axis"), + value: scrollDirs[scrollAxises.Z_AXIS].AXIS, + }, + ], + }, + DELTA_TYPE: { acceptReporters: true, - items: ["enable", "disable"], + items: [ + "x", + "y", + "z", + { text: Scratch.translate("mode"), value: "mode" }, + ], + }, + TOGGLE_TYPE: { + acceptReporters: true, + items: [ + { + text: Scratch.translate("enable"), + value: "enable", + }, + { + text: Scratch.translate("disable"), + value: "disable", + }, + ], }, }, }; } - onMouseUp(args) { - return !this.buttonPressed(args); - } - - onMouseDown(args) { - return this.buttonPressed(args); + _startOnScrollHats(delta, axis) { + if (delta === 0) return; + runtime.startHats(`${extId}_onScrollInDir`, { + SCROLL_DIR: scrollDirs[axis].AXIS, + }); + runtime.startHats(`${extId}_onScrollInDir`, { + SCROLL_DIR: delta > 0 + ? scrollDirs[axis].POS + : scrollDirs[axis].NEG, + }); } - buttonPressed({ button }) { - return this.buttons[Scratch.Cast.toNumber(button)] || false; + buttonPressed(args, util) { + const button = Cast.toNumber(args.BUTTON); + return util.ioQuery("mouse", "getButtonIsDown", [button]); } - toggleContextMenu({ TOGGLE }) { - if (TOGGLE === "enable") { - this.contextMenuDissabled = false; - } else if (TOGGLE === "disable") { - this.contextMenuDissabled = true; - } - vm.runtime.extensionStorage.legobrainbikerMoreMouseControls.contextMenuDissabled = - this.contextMenuDissabled; + isScrolledInDir(args) { + if (!this.wheelScrolled) return false; + const scrollDir = Cast.toString(args.SCROLL_DIR); + const wheelDeltaArray = [this.wheelDelta.x, this.wheelDelta.y, this.wheelDelta.z]; + scrollDirs.forEach((axisEnums, i) => { + if (scrollDir === axisEnums.AXIS && wheelDeltaArray[i] !== 0) return true; + if (scrollDir === axisEnums.NEG && wheelDeltaArray[i] < 0) return true; + if (scrollDir === axisEnums.POS && wheelDeltaArray[i] > 0) return true; + }); + return false; } - toggleScroll({ TOGGLE }) { - if (TOGGLE === "enable") { - this.scrollDissabled = false; - } else if (TOGGLE === "disable") { - this.scrollDissabled = true; - } - vm.runtime.extensionStorage.legobrainbikerMoreMouseControls.scrollDissabled = - this.scrollDissabled; + isScrolled() { + return this.wheelScrolled; } - scrollAmount() { - return -this.mouseWheelDelta; + getDelta(args) { + const deltaType = Cast.toString(args.DELTA_TYPE); + return this.wheelDelta[deltaType] ?? NaN; } - horozontalScrollAmount() { - return this.mouseWheelDeltaX; + mouseGlobalX() { + if (this.mouseX === NaN) return NaN; + const canvasRect = canvas.getBoundingClientRect(); + const k = canvasRect.width / runtime.stageWidth; + return (this.mouseX - canvasRect.x - canvasRect.width / 2) / k; } - zoomAmount() { - return -this.mouseZoomDelta; + mouseGlobalY() { + if (this.mouseY === NaN) return NaN; + const canvasRect = canvas.getBoundingClientRect(); + const k = canvasRect.height / runtime.stageHeight; + return -(this.mouseY - canvasRect.y - canvasRect.height / 2) / k; } - mouseGlobalX() { - const canvas = Scratch.renderer.canvas.getBoundingClientRect(); - return this.mouseX - canvas.x - canvas.width / 2; + toggleContextMenu(args) { + const strToogle = Cast.toString(args.TOGGLE); + const boolToggle = Cast.toBoolean(args.TOGGLE); + if (strToogle === "enable") { + runtime.ioDevices.mouse.usesRightClickDown = false; + } else if (strToogle === "disable") { + runtime.ioDevices.mouse.usesRightClickDown = true; + } else { + runtime.ioDevices.mouse.usesRightClickDown = !boolToggle; + } + runtime.extensionStorage[extId].contextMenuDisabled = runtime.ioDevices.mouse.usesRightClickDown; } - mouseGlobalY() { - const canvas = Scratch.renderer.canvas.getBoundingClientRect(); - return -(this.mouseY - canvas.y - canvas.height / 2); + toggleScroll(args) { + const strToogle = Cast.toString(args.TOGGLE); + const boolToggle = Cast.toBoolean(args.TOGGLE); + if (strToogle === "enable") { + this.scrollDisabled = false; + } else if (strToogle === "disable") { + this.scrollDisabled = true; + } else { + this.scrollDisabled = !boolToggle; + } + runtime.extensionStorage[extId].scrollDisabled = this.scrollDisabled; } } - Scratch.extensions.register(new moreMouseControls()); + Scratch.extensions.register(new MoreMouseControls()); })(Scratch); From e457e32ea993b8d5eec74f23cbbb7d1dc5813583 Mon Sep 17 00:00:00 2001 From: Den4ik-12 <133135758+DDen4ik-12@users.noreply.github.com> Date: Sun, 14 Jun 2026 15:22:40 +0500 Subject: [PATCH 11/16] =?UTF-8?q?MoreMouseControls.js:=20=E2=9C=A8=20Chang?= =?UTF-8?q?es=20requested=20by=20@LegoBrainBiker=20+=20fix=20and=20style?= =?UTF-8?q?=20changes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../legobrainbiker/MoreMouseControls.js | 123 ++++++++++-------- 1 file changed, 71 insertions(+), 52 deletions(-) diff --git a/extensions/legobrainbiker/MoreMouseControls.js b/extensions/legobrainbiker/MoreMouseControls.js index cf0db72fad..6d25ae069b 100644 --- a/extensions/legobrainbiker/MoreMouseControls.js +++ b/extensions/legobrainbiker/MoreMouseControls.js @@ -19,15 +19,15 @@ const canvas = Scratch.renderer.canvas; const Cast = Scratch.Cast; - const extId = "legobrainbikerMoreMouseControls"; - const extIcon = + const EXT_ID = "legobrainbikerMoreMouseControls"; + const EXT_ICON = "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgdmVyc2lvbj0iMS4xIgogICB3aWR0aD0iMjA1IgogICBoZWlnaHQ9IjIwNSIKICAgdmlld0JveD0iMCAwIDIwNSAyMDUiCiAgIGlkPSJzdmc4IgogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogIDxkZWZzCiAgICAgaWQ9ImRlZnM4IiAvPgogIDxwYXRoCiAgICAgZD0ibSAyLjUsMTAyLjUgYyAwLC01NS4yMjg0NyA0NC43NzE1MywtMTAwIDEwMCwtMTAwIDU1LjIyODQ3LDAgMTAwLDQ0Ljc3MTUzIDEwMCwxMDAgMCw1NS4yMjg0NyAtNDQuNzcxNTMsMTAwIC0xMDAsMTAwIC01NS4yMjg0NywwIC0xMDAsLTQ0Ljc3MTUzIC0xMDAsLTEwMCB6IgogICAgIGZpbGw9IiNlNzRjM2MiCiAgICAgc3Ryb2tlPSIjYjAzYTJlIgogICAgIHN0cm9rZS13aWR0aD0iNSIKICAgICBpZD0icGF0aDEiCiAgICAgc3R5bGU9Im1peC1ibGVuZC1tb2RlOm5vcm1hbDtmaWxsOiM5OWJiYmI7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOiM2MzdhN2E7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MSIgLz4KICA8cGF0aAogICAgIGQ9Ik0gOTcuMTY3OTY5LDIzLjc1NzgxMiBDIDczLjI0MDQ5OSwyNi40Mzk0NjMgNTQuNjQ0NTMxLDQ2LjczODYxOSA1NC42NDQ1MzEsNzEuMzgwODU5IGwgLTAuMTk5MjE5LDIxLjMwNDY4OCA0Mi41NTg1OTQsMC4xNjAxNTYgMC4wMzUxNiwtNS41MjczNDQgYyAwLDAgLTEwLjQxNTQxMiwtNC4wMzk0NDggLTEwLjQ0NTMxMiwtMTEuNzM2MzI4IC0wLjAxNTc4LC00LjA2NTI0IC0wLjE3MDg2MiwtMTQuNTgwOTA4IDAuMDg1OTQsLTIzLjUxNzU3OCAwLjI0NywtOC41OTU1MiAxMS41NTQ2ODgsLTEyLjM4ODY3MiAxMS41NTQ2ODgsLTEyLjM4ODY3MiAwLDAgLTAuNTEzMTM2LC0xNS45Nzk5NjkgLTEuMDY2NDA2LC0xNS45MTc5NjkgeiBtIDEwLjY2NDA2MSwwIGMgLTAuNTUzMjgsLTAuMDYyMDEgLTEuMDY2NCwxNS45MTc5NjkgLTEuMDY2NCwxNS45MTc5NjkgLTFlLTUsMCAxMS4zMDc2OCwzLjc5MzE3MiAxMS41NTQ2OCwxMi4zODg2NzIgMC4yNTY4Myw4LjkzNjY3IDAuMTAxNzQsMTkuNDUyMzQ4IDAuMDg1OSwyMy41MTc1NzggLTAuMDI5OSw3LjY5Njg5IC0xMC40NDUzMSwxMS43MzYzMjggLTEwLjQ0NTMxLDExLjczNjMyOCBsIDAuMDM1Miw1LjUyNzM0NCA0Mi41NTg2LC0wLjE2MDE1NiAtMC4xOTkyMiwtMjEuMzA0Njg4IGMgMCwtMjQuNjQyMjYgLTE4LjU5NTk3LC00NC45NDEzODYgLTQyLjUyMzQ0LC00Ny42MjMwNDcgeiBtIC01LjI2NTYyLDI0LjgwMDc4MiBjIC0zLjM4MTQxNCwwIC02LjEyMzA1MSwyLjc0MTkzNyAtNi4xMjMwNTEsNi4xMjMwNDcgdiAxNy45MTYwMTUgYyAwLDMuMzgxMTEgMi43NDIyMzcsNi4xMjEwOTQgNi4xMjMwNTEsNi4xMjEwOTQgMy4zODA4MiwwIDYuMTIxMDksLTIuNzM5OTg0IDYuMTIxMDksLTYuMTIxMDk0IFYgNTQuNjgxNjQxIGMgMCwtMy4zODE0MSAtMi43Mzk3LC02LjEyMzA0NyAtNi4xMjEwOSwtNi4xMjMwNDcgeiBNIDU0LjY0NDUzMSwxMDIuODU5MzggdiAzMC40NjI4OSBjIDAsMjYuNDY2NyAyMS40NTU0MjIsNDcuOTE5OTIgNDcuOTE5OTE5LDQ3LjkxOTkyIDI2LjQ2NDUsMCA0Ny45MjE4OCwtMjEuNDUzMiA0Ny45MjE4OCwtNDcuOTE5OTIgdiAtMzAuNDYyODkgeiIKICAgICBzdHlsZT0iZmlsbDojZmZmZmZmO3N0cm9rZS1taXRlcmxpbWl0OjEwIgogICAgIGlkPSJwYXRoOCIgLz4KPC9zdmc+CjwhLS1yb3RhdGlvbkNlbnRlcjoxMDIuNToxMDIuNS0tPgoK"; - const blockIcon = + const BLOCK_ICON = "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgdmVyc2lvbj0iMS4xIgogICB3aWR0aD0iMTE3LjMzMzMzIgogICBoZWlnaHQ9IjExNy4zMzMzMyIKICAgdmlld0JveD0iMCAwIDExNy4zMzMzMyAxMTcuMzMzMzMiCiAgIGlkPSJzdmcxNCIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICA8ZGVmcwogICAgIGlkPSJkZWZzMTQiIC8+CiAgPHBhdGgKICAgICBkPSJNIDU1LjA4OTUxNSw1LjgzNzQ4MyBDIDM5LjAzNjk1NSw3LjYzNjU2MzEgMjYuNTYyMTcxLDIxLjI1NDYwMSAyNi41NjIxNzEsMzcuNzg2NzAxIGwgLTAuMTM0NzY1LDE0LjI5Mjk2OSAyOC41NTI3MzQsMC4xMDc0MjIgMC4wMjM0NCwtMy43MDcwMzEgYyAwLDAgLTYuOTg3NzEzLC0yLjcxMTI4IC03LjAwNzgxMywtNy44NzUgLTAuMDEwNywtMi43MjczMSAtMC4xMTU2NDksLTkuNzgxODc0IDAuMDU2NjQsLTE1Ljc3NzM0NCAwLjE2NTcxLC01Ljc2NjYxIDcuNzUxOTUzLC04LjMxMDU0NyA3Ljc1MTk1MywtOC4zMTA1NDcgMCwwIC0wLjM0MzY2NCwtMTAuNzIxMjg2OSAtMC43MTQ4NDQsLTEwLjY3OTY4NyB6IG0gNy4xNTQyOTcsMCBjIC0wLjM3MTE5LC0wLjA0MTU5IC0wLjcxNDg0NCwxMC42Nzk2ODcgLTAuNzE0ODQ0LDEwLjY3OTY4NyAwLDAgNy41ODYyNDQsMi41NDM5NDcgNy43NTE5NTMsOC4zMTA1NDcgMC4xNzIyNCw1Ljk5NTQ3IDAuMDY3MjQsMTMuMDUwMDQ0IDAuMDU2NjQsMTUuNzc3MzQ0IC0wLjAyMDA4LDUuMTYzNzIgLTcuMDA3ODEyLDcuODc1IC03LjAwNzgxMiw3Ljg3NSBsIDAuMDIzNDQsMy43MDcwMzEgMjguNTUyNzM0LC0wLjEwNzQyMiAtMC4xMzQ3NjUsLTE0LjI5Mjk2OSBjIDAsLTE2LjUzMjA4OSAtMTIuNDc0Nzg0LC0zMC4xNTAxMzggLTI4LjUyNzM0NCwtMzEuOTQ5MjE4IHogbSAtMy41MzMyMDMsMTYuNjM4NjcyIGMgLTIuMjY4NTMsMCAtNC4xMDc0MjIsMS44MzkwODIgLTQuMTA3NDIyLDQuMTA3NDIxIHYgMTIuMDE5NTMyIGMgMCwyLjI2ODMyIDEuODM5MjkyLDQuMTA3NDIyIDQuMTA3NDIyLDQuMTA3NDIyIDIuMjY4MTQsMCA0LjEwNzQyMiwtMS44MzkwODIgNC4xMDc0MjIsLTQuMTA3NDIyIFYgMjYuNTgzNTc2IGMgMCwtMi4yNjg1MjkgLTEuODM4OTAyLC00LjEwNzQyMSAtNC4xMDc0MjIsLTQuMTA3NDIxIHogTSAyNi41NjIxNzEsNTguOTA1ODQyIHYgMjAuNDM3NSBjIDAsMTcuNzU2MTIgMTQuMzkzODA4LDMyLjE0ODQzOCAzMi4xNDg0MzgsMzIuMTQ4NDM4IDE3Ljc1NDYzLDAgMzIuMTUwMzkxLC0xNC4zOTIzMjggMzIuMTUwMzkxLC0zMi4xNDg0MzggdiAtMjAuNDM3NSB6IgogICAgIHN0eWxlPSJmaWxsOiNmZmZmZmY7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjEwO3N0cm9rZS1taXRlcmxpbWl0OjEwO3N0cm9rZS1vcGFjaXR5OjAuMTQ5MDI7cGFpbnQtb3JkZXI6c3Ryb2tlIGZpbGwgbWFya2VycyIKICAgICBpZD0icGF0aDE0IiAvPgo8L3N2Zz4KPCEtLXJvdGF0aW9uQ2VudGVyOjU4LjY2NjY2NjY2NjY2NjY2OjU4LjY2NjY2NjY2NjY2NjY2LS0+Cgo="; - const deltaModes = ["px", "lines", "pages"]; - const scrollAxises = { X_AXIS: 0, Y_AXIS: 1, Z_AXIS: 2 }; - const scrollDirs = [ + const DELTA_MODES = ["pixels", "lines", "pages"]; + const SCROLL_AXISES = { X_AXIS: 0, Y_AXIS: 1, Z_AXIS: 2 }; + const SCROLL_DIRS = [ { AXIS: "ax", NEG: "l", POS: "r" }, { AXIS: "ay", NEG: "u", POS: "d" }, { AXIS: "az", NEG: "o", POS: "i" }, @@ -35,22 +35,25 @@ class MoreMouseControls { constructor() { - runtime.extensionStorage[extId] = runtime.extensionStorage[extId] ?? {}; - this.mouseX = 0; this.mouseY = 0; this.wheelScrolled = false; this.wheelDelta = Object.assign(Object.create(null), { x: 0, y: 0, - z: 0, - mode: "", + zoom: 0, + }); + this.wheelDeltaMode = undefined; + this.scrollDisabled = false; + + Scratch.vm.runtime.on("PROJECT_LOADED", () => { + const stored = runtime.extensionStorage[EXT_ID]; + this.scrollDisabled = stored.scrollDisabled || false; + runtime.ioDevices.mouse.usesRightClickDown = stored.contextMenuDisabled || false; }); - this.scrollDisabled = runtime.extensionStorage[extId].scrollDisabled || false; - runtime.ioDevices.mouse.usesRightClickDown = runtime.extensionStorage[extId].contextMenuDisabled || false; - // An event listener is used instead of Mouse I/O API, - // as the latter doesn't provide deltaZ and deltaMode + // An event listener is used instead of Mouse Wheel I/O API, + // as the latter doesn't provide deltaZ and deltaMode. canvas.addEventListener( "wheel", (e) => { @@ -61,13 +64,13 @@ this.wheelScrolled = true; this.wheelDelta.x += e.deltaX; this.wheelDelta.y += e.deltaY; - this.wheelDelta.z += e.deltaZ; - this.wheelDelta.mode = deltaModes[e.deltaMode] || ""; + this.wheelDelta.zoom += e.deltaZ; + this.wheelDeltaMode = DELTA_MODES[e.deltaMode]; - runtime.startHats(`${extId}_onScroll`); - this._startOnScrollHats(e.deltaX, scrollAxises.X_AXIS); - this._startOnScrollHats(e.deltaY, scrollAxises.Y_AXIS); - this._startOnScrollHats(e.deltaZ, scrollAxises.Z_AXIS); + runtime.startHats(`${EXT_ID}_onScroll`); + this._startOnScrollHats(e.deltaX, SCROLL_AXISES.X_AXIS); + this._startOnScrollHats(e.deltaY, SCROLL_AXISES.Y_AXIS); + this._startOnScrollHats(e.deltaZ, SCROLL_AXISES.Z_AXIS); }, { passive: true } ); @@ -76,8 +79,7 @@ Object.assign(this.wheelDelta, { x: 0, y: 0, - z: 0, - mode: "", + zoom: 0, }); }); @@ -85,7 +87,7 @@ // https://github.com/TurboWarp/scratch-vm/blob/develop/src/io/mouse.js runtime.ioDevices.mouse.postData = function(data) { if (typeof data.isDown !== "undefined") { - // Do not trigger if down state has not changed + // Do not trigger if down state has not changed. if (data.isDown === this._isDown) { ogIoMousePostData.call(this, data); return; @@ -93,11 +95,11 @@ const button = data.button ?? 0; if (data.isDown) { - runtime.startHats(`${extId}_onMouseDown`, { + runtime.startHats(`${EXT_ID}_onMouseDown`, { BUTTON: Cast.toString(button), }); } else { - runtime.startHats(`${extId}_onMouseUp`, { + runtime.startHats(`${EXT_ID}_onMouseUp`, { BUTTON: Cast.toString(button), }); } @@ -113,16 +115,16 @@ this.mouseX = NaN; this.mouseY = NaN; // This could be problematic for some projects. - // It's not great to add another edge case + // It's not great to add another edge case. }); } getInfo() { return { - id: extId, + id: EXT_ID, name: Scratch.translate("More Mouse Controls"), - menuIconURI: extIcon, - blockIconURI: blockIcon, + menuIconURI: EXT_ICON, + BLOCK_ICONURI: BLOCK_ICON, color1: "#99bbbb", color2: "#7a9696", color3: "#637a7a", @@ -162,7 +164,7 @@ arguments: { SCROLL_DIR: { menu: "SCROLL_DIRS", - defaultValue: scrollDirs[scrollAxises.Y_AXIS].NEG, + defaultValue: SCROLL_DIRS[SCROLL_AXISES.Y_AXIS].NEG, }, }, }, @@ -179,7 +181,7 @@ arguments: { SCROLL_DIR: { menu: "SCROLL_DIRS", - defaultValue: scrollDirs[scrollAxises.Y_AXIS].NEG, + defaultValue: SCROLL_DIRS[SCROLL_AXISES.Y_AXIS].NEG, }, }, }, @@ -200,6 +202,11 @@ }, }, }, + { + opcode: "getDeltaMode", + blockType: Scratch.BlockType.REPORTER, + text: Scratch.translate("scroll delta mode"), + }, "---", { opcode: "mouseGlobalX", @@ -262,39 +269,39 @@ items: [ { text: Scratch.translate("up"), - value: scrollDirs[scrollAxises.Y_AXIS].NEG, + value: SCROLL_DIRS[SCROLL_AXISES.Y_AXIS].NEG, }, { text: Scratch.translate("down"), - value: scrollDirs[scrollAxises.Y_AXIS].POS, + value: SCROLL_DIRS[SCROLL_AXISES.Y_AXIS].POS, }, { text: Scratch.translate("to the left"), - value: scrollDirs[scrollAxises.X_AXIS].NEG, + value: SCROLL_DIRS[SCROLL_AXISES.X_AXIS].NEG, }, { text: Scratch.translate("to the right"), - value: scrollDirs[scrollAxises.X_AXIS].POS, + value: SCROLL_DIRS[SCROLL_AXISES.X_AXIS].POS, }, { text: Scratch.translate("out"), - value: scrollDirs[scrollAxises.Z_AXIS].NEG, + value: SCROLL_DIRS[SCROLL_AXISES.Z_AXIS].NEG, }, { text: Scratch.translate("in"), - value: scrollDirs[scrollAxises.Z_AXIS].POS, + value: SCROLL_DIRS[SCROLL_AXISES.Z_AXIS].POS, }, { text: Scratch.translate("along the x-axis"), - value: scrollDirs[scrollAxises.X_AXIS].AXIS, + value: SCROLL_DIRS[SCROLL_AXISES.X_AXIS].AXIS, }, { text: Scratch.translate("along the y-axis"), - value: scrollDirs[scrollAxises.Y_AXIS].AXIS, + value: SCROLL_DIRS[SCROLL_AXISES.Y_AXIS].AXIS, }, { - text: Scratch.translate("along the z-axis"), - value: scrollDirs[scrollAxises.Z_AXIS].AXIS, + text: Scratch.translate("along the z-axis (zoom)"), + value: SCROLL_DIRS[SCROLL_AXISES.Z_AXIS].AXIS, }, ], }, @@ -303,8 +310,10 @@ items: [ "x", "y", - "z", - { text: Scratch.translate("mode"), value: "mode" }, + { + text: Scratch.translate("zoom"), + value: "zoom", + }, ], }, TOGGLE_TYPE: { @@ -326,13 +335,13 @@ _startOnScrollHats(delta, axis) { if (delta === 0) return; - runtime.startHats(`${extId}_onScrollInDir`, { - SCROLL_DIR: scrollDirs[axis].AXIS, + runtime.startHats(`${EXT_ID}_onScrollInDir`, { + SCROLL_DIR: SCROLL_DIRS[axis].AXIS, }); - runtime.startHats(`${extId}_onScrollInDir`, { + runtime.startHats(`${EXT_ID}_onScrollInDir`, { SCROLL_DIR: delta > 0 - ? scrollDirs[axis].POS - : scrollDirs[axis].NEG, + ? SCROLL_DIRS[axis].POS + : SCROLL_DIRS[axis].NEG, }); } @@ -344,8 +353,8 @@ isScrolledInDir(args) { if (!this.wheelScrolled) return false; const scrollDir = Cast.toString(args.SCROLL_DIR); - const wheelDeltaArray = [this.wheelDelta.x, this.wheelDelta.y, this.wheelDelta.z]; - scrollDirs.forEach((axisEnums, i) => { + const wheelDeltaArray = [this.wheelDelta.x, this.wheelDelta.y, this.wheelDelta.zoom]; + SCROLL_DIRS.forEach((axisEnums, i) => { if (scrollDir === axisEnums.AXIS && wheelDeltaArray[i] !== 0) return true; if (scrollDir === axisEnums.NEG && wheelDeltaArray[i] < 0) return true; if (scrollDir === axisEnums.POS && wheelDeltaArray[i] > 0) return true; @@ -362,6 +371,10 @@ return this.wheelDelta[deltaType] ?? NaN; } + getDeltaMode() { + return this.wheelDeltaMode || ""; + } + mouseGlobalX() { if (this.mouseX === NaN) return NaN; const canvasRect = canvas.getBoundingClientRect(); @@ -386,7 +399,10 @@ } else { runtime.ioDevices.mouse.usesRightClickDown = !boolToggle; } - runtime.extensionStorage[extId].contextMenuDisabled = runtime.ioDevices.mouse.usesRightClickDown; + runtime.extensionStorage[EXT_ID] = { + ...(runtime.extensionStorage[EXT_ID] || {}), + contextMenuDisabled: runtime.ioDevices.mouse.usesRightClickDown, + }; } toggleScroll(args) { @@ -399,7 +415,10 @@ } else { this.scrollDisabled = !boolToggle; } - runtime.extensionStorage[extId].scrollDisabled = this.scrollDisabled; + runtime.extensionStorage[EXT_ID] = { + ...(runtime.extensionStorage[EXT_ID] || {}), + scrollDisabled: this.scrollDisabled, + }; } } Scratch.extensions.register(new MoreMouseControls()); From 720ede275e23959ee6ac0fa1ab5a5631949b6d6e Mon Sep 17 00:00:00 2001 From: Den4ik-12 <133135758+DDen4ik-12@users.noreply.github.com> Date: Sun, 14 Jun 2026 15:24:05 +0500 Subject: [PATCH 12/16] =?UTF-8?q?MoreMouseControls.js:=20=E2=AC=86=20Small?= =?UTF-8?q?=20change?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- extensions/legobrainbiker/MoreMouseControls.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/legobrainbiker/MoreMouseControls.js b/extensions/legobrainbiker/MoreMouseControls.js index 6d25ae069b..2359bf3ad8 100644 --- a/extensions/legobrainbiker/MoreMouseControls.js +++ b/extensions/legobrainbiker/MoreMouseControls.js @@ -46,7 +46,7 @@ this.wheelDeltaMode = undefined; this.scrollDisabled = false; - Scratch.vm.runtime.on("PROJECT_LOADED", () => { + runtime.on("PROJECT_LOADED", () => { const stored = runtime.extensionStorage[EXT_ID]; this.scrollDisabled = stored.scrollDisabled || false; runtime.ioDevices.mouse.usesRightClickDown = stored.contextMenuDisabled || false; From 3a1c4ec8c453124c688400e38b4512972a237c61 Mon Sep 17 00:00:00 2001 From: Den4ik-12 <133135758+DDen4ik-12@users.noreply.github.com> Date: Sun, 14 Jun 2026 17:59:27 +0500 Subject: [PATCH 13/16] =?UTF-8?q?MoreMouseControls.js:=20=F0=9F=94=A7=20Fi?= =?UTF-8?q?x?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- extensions/legobrainbiker/MoreMouseControls.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/legobrainbiker/MoreMouseControls.js b/extensions/legobrainbiker/MoreMouseControls.js index 2359bf3ad8..ce5d4c0210 100644 --- a/extensions/legobrainbiker/MoreMouseControls.js +++ b/extensions/legobrainbiker/MoreMouseControls.js @@ -124,7 +124,7 @@ id: EXT_ID, name: Scratch.translate("More Mouse Controls"), menuIconURI: EXT_ICON, - BLOCK_ICONURI: BLOCK_ICON, + blockIconURI: BLOCK_ICON, color1: "#99bbbb", color2: "#7a9696", color3: "#637a7a", From 4738d61eb804bac2b3b99b34e336be714895a8a1 Mon Sep 17 00:00:00 2001 From: "DangoCat[bot]" Date: Fri, 19 Jun 2026 22:11:32 +0000 Subject: [PATCH 14/16] [Automated] Format code --- .../legobrainbiker/MoreMouseControls.js | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/extensions/legobrainbiker/MoreMouseControls.js b/extensions/legobrainbiker/MoreMouseControls.js index ce5d4c0210..be1e1a2071 100644 --- a/extensions/legobrainbiker/MoreMouseControls.js +++ b/extensions/legobrainbiker/MoreMouseControls.js @@ -49,7 +49,8 @@ runtime.on("PROJECT_LOADED", () => { const stored = runtime.extensionStorage[EXT_ID]; this.scrollDisabled = stored.scrollDisabled || false; - runtime.ioDevices.mouse.usesRightClickDown = stored.contextMenuDisabled || false; + runtime.ioDevices.mouse.usesRightClickDown = + stored.contextMenuDisabled || false; }); // An event listener is used instead of Mouse Wheel I/O API, @@ -85,7 +86,7 @@ const ogIoMousePostData = runtime.ioDevices.mouse.postData; // https://github.com/TurboWarp/scratch-vm/blob/develop/src/io/mouse.js - runtime.ioDevices.mouse.postData = function(data) { + runtime.ioDevices.mouse.postData = function (data) { if (typeof data.isDown !== "undefined") { // Do not trigger if down state has not changed. if (data.isDown === this._isDown) { @@ -105,7 +106,7 @@ } } ogIoMousePostData.call(this, data); - } + }; document.addEventListener("mousemove", (e) => { this.mouseX = e.clientX; @@ -339,9 +340,7 @@ SCROLL_DIR: SCROLL_DIRS[axis].AXIS, }); runtime.startHats(`${EXT_ID}_onScrollInDir`, { - SCROLL_DIR: delta > 0 - ? SCROLL_DIRS[axis].POS - : SCROLL_DIRS[axis].NEG, + SCROLL_DIR: delta > 0 ? SCROLL_DIRS[axis].POS : SCROLL_DIRS[axis].NEG, }); } @@ -353,9 +352,14 @@ isScrolledInDir(args) { if (!this.wheelScrolled) return false; const scrollDir = Cast.toString(args.SCROLL_DIR); - const wheelDeltaArray = [this.wheelDelta.x, this.wheelDelta.y, this.wheelDelta.zoom]; + const wheelDeltaArray = [ + this.wheelDelta.x, + this.wheelDelta.y, + this.wheelDelta.zoom, + ]; SCROLL_DIRS.forEach((axisEnums, i) => { - if (scrollDir === axisEnums.AXIS && wheelDeltaArray[i] !== 0) return true; + if (scrollDir === axisEnums.AXIS && wheelDeltaArray[i] !== 0) + return true; if (scrollDir === axisEnums.NEG && wheelDeltaArray[i] < 0) return true; if (scrollDir === axisEnums.POS && wheelDeltaArray[i] > 0) return true; }); From 7e8831c91466ef35b759110720197cf837d51ecb Mon Sep 17 00:00:00 2001 From: Sameer Brink <122649269+LegoBrainBiker@users.noreply.github.com> Date: Fri, 19 Jun 2026 15:20:30 -0700 Subject: [PATCH 15/16] LegoBrainBiker/MoreMouseControlls: use isNaN and round global mouse coordinates --- extensions/legobrainbiker/MoreMouseControls.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/extensions/legobrainbiker/MoreMouseControls.js b/extensions/legobrainbiker/MoreMouseControls.js index be1e1a2071..9aa9ea23c3 100644 --- a/extensions/legobrainbiker/MoreMouseControls.js +++ b/extensions/legobrainbiker/MoreMouseControls.js @@ -380,17 +380,17 @@ } mouseGlobalX() { - if (this.mouseX === NaN) return NaN; + if (isNaN(this.mouseX)) return NaN; const canvasRect = canvas.getBoundingClientRect(); const k = canvasRect.width / runtime.stageWidth; - return (this.mouseX - canvasRect.x - canvasRect.width / 2) / k; + return Math.round((this.mouseX - canvasRect.x - canvasRect.width / 2) / k); } mouseGlobalY() { - if (this.mouseY === NaN) return NaN; + if (isNaN(this.mouseY)) return NaN; const canvasRect = canvas.getBoundingClientRect(); const k = canvasRect.height / runtime.stageHeight; - return -(this.mouseY - canvasRect.y - canvasRect.height / 2) / k; + return Math.round(-(this.mouseY - canvasRect.y - canvasRect.height / 2) / k); } toggleContextMenu(args) { From 178f539bfffc70c1fda5918b78724610a80e3084 Mon Sep 17 00:00:00 2001 From: "DangoCat[bot]" Date: Fri, 19 Jun 2026 22:21:53 +0000 Subject: [PATCH 16/16] [Automated] Format code --- extensions/legobrainbiker/MoreMouseControls.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/extensions/legobrainbiker/MoreMouseControls.js b/extensions/legobrainbiker/MoreMouseControls.js index 9aa9ea23c3..47c7f272c4 100644 --- a/extensions/legobrainbiker/MoreMouseControls.js +++ b/extensions/legobrainbiker/MoreMouseControls.js @@ -383,14 +383,18 @@ if (isNaN(this.mouseX)) return NaN; const canvasRect = canvas.getBoundingClientRect(); const k = canvasRect.width / runtime.stageWidth; - return Math.round((this.mouseX - canvasRect.x - canvasRect.width / 2) / k); + return Math.round( + (this.mouseX - canvasRect.x - canvasRect.width / 2) / k + ); } mouseGlobalY() { if (isNaN(this.mouseY)) return NaN; const canvasRect = canvas.getBoundingClientRect(); const k = canvasRect.height / runtime.stageHeight; - return Math.round(-(this.mouseY - canvasRect.y - canvasRect.height / 2) / k); + return Math.round( + -(this.mouseY - canvasRect.y - canvasRect.height / 2) / k + ); } toggleContextMenu(args) {