Skip to content

Commit 52412f0

Browse files
committed
Release 1.2.2
1 parent 3697682 commit 52412f0

File tree

4 files changed

+76
-34
lines changed

4 files changed

+76
-34
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ There's a gazillion exciting things to do :)
119119

120120
Changelog
121121
---------
122+
2024-06-22: 1.2.2 make copy/paste work on mobile
122123
2024-05-27: 1.2.1 add virtual cmd button, fix touch events
123124
2024-03-25: 1.2.0 add FFI and MIDI plugins, JIT for Sista bytecodes, JPEG write prim, fix keyboard input, copy/paste, scroll wheel, highdpi, allow ES6 in source
124125
2023-11-24: 1.1.2 fixed BitBlt bug (symptom reported 9 years ago, thanks to Agustin Martinez for narrowing it down), add object pinning, support keyboard in ancient Scratch images

dist/squeak_bundle.js

Lines changed: 69 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,8 @@
116116
Object.extend(Squeak,
117117
"version", {
118118
// system attributes
119-
vmVersion: "SqueakJS 1.2.1",
120-
vmDate: "2024-05-27", // Maybe replace at build time?
119+
vmVersion: "SqueakJS 1.2.2",
120+
vmDate: "2024-06-22", // Maybe replace at build time?
121121
vmBuild: "unknown", // or replace at runtime by last-modified?
122122
vmPath: "unknown", // Replace at runtime
123123
vmFile: "vm.js",
@@ -4912,8 +4912,8 @@
49124912
},
49134913
stObjectatput: function(array, index, obj) {
49144914
if (array.sqClass !== this.classArray()) throw Error("Array expected");
4915-
if (index < 1 || index >= array.pointers.length) return this.successFlag = false;
4916-
array.pointers[index] = obj;
4915+
if (index < 1 || index > array.pointers.length) return this.successFlag = false;
4916+
array.pointers[index-1] = obj;
49174917
},
49184918
},
49194919
'constant access',
@@ -10071,14 +10071,39 @@
1007110071
Object.extend(Squeak.Primitives.prototype,
1007210072
'input', {
1007310073
primitiveClipboardText: function(argCount) {
10074+
// There are two ways this primitive is invoked:
10075+
// 1: via the DOM keyboard event thandler in squeak.js that intercepts cmd-c/cmd-v,
10076+
// reads/writes the system clipboard from/to display.clipboardString
10077+
// and then the interpreter calls the primitive
10078+
// 2: via the image code e.g. a menu copy/paste item, which calls the primitive
10079+
// and we try to read/write the system clipboard directly.
10080+
// To support this, squeak.js keeps running the interpreter for 100 ms within
10081+
// the DOM event 'mouseup' handler so the code below runs in the click-handler context,
10082+
// (otherwise the browser would block access to the clipboard)
1007410083
if (argCount === 0) { // read from clipboard
10075-
if (typeof(this.display.clipboardString) !== 'string') return false;
10076-
this.vm.popNandPush(1, this.makeStString(this.display.clipboardString));
10084+
// Try to read from system clipboard, which is async if available.
10085+
// It will likely fail outside of an event handler.
10086+
var clipBoardPromise = null;
10087+
if (this.display.readFromSystemClipboard) clipBoardPromise = this.display.readFromSystemClipboard();
10088+
if (clipBoardPromise) {
10089+
var unfreeze = this.vm.freeze();
10090+
clipBoardPromise
10091+
.then(() => this.vm.popNandPush(1, this.makeStString(this.display.clipboardString)))
10092+
.catch(() => this.vm.popNandPush(1, this.vm.nilObj))
10093+
.finally(() => unfreeze());
10094+
} else {
10095+
if (typeof(this.display.clipboardString) !== 'string') return false;
10096+
this.vm.popNandPush(1, this.makeStString(this.display.clipboardString));
10097+
}
1007710098
} else if (argCount === 1) { // write to clipboard
1007810099
var stringObj = this.vm.top();
1007910100
if (stringObj.bytes) {
1008010101
this.display.clipboardString = stringObj.bytesAsString();
10081-
this.display.clipboardStringChanged = true;
10102+
this.display.clipboardStringChanged = true; // means it should be written to system clipboard
10103+
if (this.display.writeToSystemClipboard) {
10104+
// no need to wait for the promise
10105+
this.display.writeToSystemClipboard();
10106+
}
1008210107
}
1008310108
this.vm.pop();
1008410109
}
@@ -56270,11 +56295,8 @@
5627056295
display.signalInputEvent();
5627156296
}
5627256297
display.idle = 0;
56273-
if (what == 'mouseup') {
56274-
if (display.runFor) display.runFor(100); // maybe we catch the fullscreen flag change
56275-
} else {
56276-
if (display.runNow) display.runNow(); // don't wait for timeout to run
56277-
}
56298+
if (what === 'mouseup') display.runFor(100, what); // process copy/paste or fullscreen flag change
56299+
else display.runNow(what); // don't wait for timeout to run
5627856300
}
5627956301

5628056302
function recordWheelEvent(evt, display) {
@@ -56297,6 +56319,7 @@
5629756319
if (display.signalInputEvent)
5629856320
display.signalInputEvent();
5629956321
display.idle = 0;
56322+
if (display.runNow) display.runNow('wheel'); // don't wait for timeout to run
5630056323
}
5630156324

5630256325
// Squeak traditional keycodes are MacRoman
@@ -56348,7 +56371,7 @@
5634856371
display.keys.push(modifiersAndKey);
5634956372
}
5635056373
display.idle = 0;
56351-
if (display.runNow) display.runNow(); // don't wait for timeout to run
56374+
if (display.runNow) display.runNow('keyboard'); // don't wait for timeout to run
5635256375
}
5635356376

5635456377
function recordDragDropEvent(type, evt, canvas, display) {
@@ -56365,6 +56388,8 @@
5636556388
]);
5636656389
if (display.signalInputEvent)
5636756390
display.signalInputEvent();
56391+
display.idle = 0;
56392+
if (display.runNow) display.runNow('drag-drop'); // don't wait for timeout to run
5636856393
}
5636956394

5637056395
function fakeCmdOrCtrlKey(key, timestamp, display) {
@@ -56404,6 +56429,7 @@
5640456429
eventQueue: null, // only used if image uses event primitives
5640556430
clipboardString: '',
5640656431
clipboardStringChanged: false,
56432+
handlingEvent: '', // set to 'mouse' or 'keyboard' while handling an event
5640756433
cursorCanvas: options.cursor !== false && document.getElementById("sqCursor") || document.createElement("canvas"),
5640856434
cursorOffsetX: 0,
5640956435
cursorOffsetY: 0,
@@ -56490,7 +56516,7 @@
5649056516
ctx.fillStyle = style.color || "#F90";
5649156517
ctx.fillRect(x, y, w * value, h);
5649256518
};
56493-
display.executeClipboardPaste = function(text, timestamp) {
56519+
display.executeClipboardPasteKey = function(text, timestamp) {
5649456520
if (!display.vm) return true;
5649556521
try {
5649656522
display.clipboardString = text;
@@ -56500,7 +56526,7 @@
5650056526
console.error("paste error " + err);
5650156527
}
5650256528
};
56503-
display.executeClipboardCopy = function(key, timestamp) {
56529+
display.executeClipboardCopyKey = function(key, timestamp) {
5650456530
if (!display.vm) return true;
5650556531
// simulate copy event for Squeak so it places its text in clipboard
5650656532
display.clipboardStringChanged = false;
@@ -56906,18 +56932,18 @@
5690656932
switch (evt.key) {
5690756933
case "c":
5690856934
case "x":
56909-
if (!navigator.clipboard?.writeText) return; // fire document.oncopy/oncut
56910-
var text = display.executeClipboardCopy(evt.key, evt.timeStamp);
56935+
if (!navigator.clipboard) return; // fire document.oncopy/oncut
56936+
var text = display.executeClipboardCopyKey(evt.key, evt.timeStamp);
5691156937
if (typeof text === 'string') {
5691256938
navigator.clipboard.writeText(text)
5691356939
.catch(function(err) { console.error("display: copy error " + err.message); });
5691456940
}
5691556941
return evt.preventDefault();
5691656942
case "v":
56917-
if (!navigator.clipboard?.readText) return; // fire document.onpaste
56943+
if (!navigator.clipboard) return; // fire document.onpaste
5691856944
navigator.clipboard.readText()
5691956945
.then(function(text) {
56920-
display.executeClipboardPaste(text, evt.timeStamp);
56946+
display.executeClipboardPasteKey(text, evt.timeStamp);
5692156947
})
5692256948
.catch(function(err) { console.error("display: paste error " + err.message); });
5692356949
return evt.preventDefault();
@@ -56935,10 +56961,25 @@
5693556961
if (!display.vm) return true;
5693656962
recordModifiers(evt, display);
5693756963
};
56938-
// copy/paste old-style
56939-
if (!navigator.clipboard?.writeText) {
56964+
// more copy/paste
56965+
if (navigator.clipboard) {
56966+
// new-style copy/paste (all modern browsers)
56967+
display.readFromSystemClipboard = () => navigator.clipboard.readText()
56968+
.then(text => display.clipboardString = text)
56969+
.catch(err => {
56970+
if (!display.handlingEvent) console.warn("reading from clipboard outside event handler");
56971+
console.error("readFromSystemClipboard" + err.message);
56972+
});
56973+
display.writeToSystemClipboard = () => navigator.clipboard.writeText(display.clipboardString)
56974+
.then(() => display.clipboardStringChanged = false)
56975+
.catch(err => {
56976+
if (!display.handlingEvent) console.warn("writing to clipboard outside event handler");
56977+
console.error("writeToSystemClipboard" + err.message);
56978+
});
56979+
} else {
56980+
// old-style copy/paste
5694056981
document.oncopy = function(evt, key) {
56941-
var text = display.executeClipboardCopy(key, evt.timeStamp);
56982+
var text = display.executeClipboardCopyKey(key, evt.timeStamp);
5694256983
if (typeof text === 'string') {
5694356984
evt.clipboardData.setData("Text", text);
5694456985
}
@@ -56948,11 +56989,9 @@
5694856989
if (!display.vm) return true;
5694956990
document.oncopy(evt, 'x');
5695056991
};
56951-
}
56952-
if (!navigator.clipboard?.readText) {
5695356992
document.onpaste = function(evt) {
5695456993
var text = evt.clipboardData.getData('Text');
56955-
display.executeClipboardPaste(text, evt.timeStamp);
56994+
display.executeClipboardPasteKey(text, evt.timeStamp);
5695656995
evt.preventDefault();
5695756996
};
5695856997
}
@@ -57155,15 +57194,17 @@
5715557194
alert(error);
5715657195
}
5715757196
}
57158-
display.runNow = function() {
57197+
display.runNow = function(event) {
5715957198
window.clearTimeout(loop);
57199+
display.handlingEvent = event;
5716057200
run();
57201+
display.handlingEvent = '';
5716157202
};
57162-
display.runFor = function(milliseconds) {
57203+
display.runFor = function(milliseconds, event) {
5716357204
var stoptime = Date.now() + milliseconds;
5716457205
do {
5716557206
if (display.quitFlag) return;
57166-
display.runNow();
57207+
display.runNow(event);
5716757208
} while (Date.now() < stoptime);
5716857209
};
5716957210
if (options.onStart) options.onStart(vm, display, options);

dist/squeak_headless_bundle.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,8 @@ if (!Function.prototype.subclass) {
113113
Object.extend(Squeak,
114114
"version", {
115115
// system attributes
116-
vmVersion: "SqueakJS 1.2.1",
117-
vmDate: "2024-05-27", // Maybe replace at build time?
116+
vmVersion: "SqueakJS 1.2.2",
117+
vmDate: "2024-06-22", // Maybe replace at build time?
118118
vmBuild: "unknown", // or replace at runtime by last-modified?
119119
vmPath: "unknown", // Replace at runtime
120120
vmFile: "vm.js",
@@ -4909,8 +4909,8 @@ Object.subclass('Squeak.InterpreterProxy',
49094909
},
49104910
stObjectatput: function(array, index, obj) {
49114911
if (array.sqClass !== this.classArray()) throw Error("Array expected");
4912-
if (index < 1 || index >= array.pointers.length) return this.successFlag = false;
4913-
array.pointers[index] = obj;
4912+
if (index < 1 || index > array.pointers.length) return this.successFlag = false;
4913+
array.pointers[index-1] = obj;
49144914
},
49154915
},
49164916
'constant access',

vm.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
Object.extend(Squeak,
2525
"version", {
2626
// system attributes
27-
vmVersion: "SqueakJS 1.2.1",
28-
vmDate: "2024-05-27", // Maybe replace at build time?
27+
vmVersion: "SqueakJS 1.2.2",
28+
vmDate: "2024-06-22", // Maybe replace at build time?
2929
vmBuild: "unknown", // or replace at runtime by last-modified?
3030
vmPath: "unknown", // Replace at runtime
3131
vmFile: "vm.js",

0 commit comments

Comments
 (0)