Bug: pending lasso-copy buffer gets pasted into the page when a plugin creates a programmatic lasso.
Hi all, and particularly the Supernote dev team and u/Mulan-sn,
I found another PluginHost/firmware bug, this time in the lasso pipeline.
if the user has lasso-copied something (copy buffer loaded), any plugin that creates a programmatic lasso (PluginCommAPI.lassoElements() → e.g. setLassoTitle()) triggers a phantom paste: the firmware inserts the copied strokes into the page during the plugin's lasso lifecycle. The user never asked for a paste.
Repro (100% reliable on my A5X):
- Handwrite anything on a note page, lasso-select it, tap Copy.
- Trigger any plugin that does a programmatic lasso — mine selects a zone with
lassoElements(rect)and converts it withsetLassoTitle({style}). - The copied strokes reappear inside the plugin's lasso zone. With my plugin the pasted strokes then get styled as a heading but the paste itself is firmware-side.
Notes:
- "Clear clipboard" does NOT help : the lasso copy buffer is separate from the text clipboard and apparently survives until something consumes it.
- A finger double-tap alone does NOT paste (tested ×10) : the trigger really is the programmatic lasso lifecycle.
- Proof it happens mid-pipeline: I log a full-page element census before/after. Before: 16 strokes. After: 24 strokes + my title + my text box : the copied strokes (+8) appear between
lassoElements()and the end of the pipeline, and they are NOT part of the lasso snapshot (bothgetLassoElementTypeCountsreads report the same count). - Possibly related: after
setLassoTitle()succeeds,setLassoBoxState(2)always fails withcode 904: "No lasso action has been performed": the lasso lifecycle seems to end in an inconsistent state.
For the Ratta team, please:
- Don't dispatch a pending lasso-paste when a lasso selection is created or released programmatically by a plugin.
- Or expose an API to query/clear the lasso copy buffer so plugins can protect themselves cleanly.
Workaround for plugin developers (ships in my plugin, works reliably, but poor UX): snapshot the page's element numbers before your lasso work, then delete any stroke that appeared during your pipeline, new strokes can only be the phantom paste (your own insertions are text/title elements, and you type-check each candidate so user content is never at risk):
// before your lasso work:
const before = new Set((await PluginFileAPI.getElementNumList(path, page)).result ?? []);
// ... lassoElements() / setLassoTitle() / your inserts ...
// after (save first):
const after = (await PluginFileAPI.getElementNumList(path, page)).result ?? [];
const parasites = [];
for (const n of after.filter(n => !before.has(n))) {
const el = (await PluginFileAPI.getElement(path, page, n))?.result;
if (el?.type === 0) parasites.push(n); // strokes only — never your own title/text
}
if (parasites.length) {
await PluginFileAPI.deleteElements(path, page, parasites);
await PluginCommAPI.reloadFile();
}
Setup: Supernote A5X (gen 1), firmware Chauvet 2.26.39, sn-plugin-lib 0.1.43.
Happy to share full logs, the census instrumentation, or a minimal repro plugin.
Thanks!