Merge pull request #3942 from bobrippling/workaround/promenu-2v27

promenu: workaround `setUI` touch handler bug (2v26/2v27)
master
Rob Pilling 2025-07-27 21:49:51 +01:00 committed by GitHub
commit 318656a5d8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 69 additions and 23 deletions

View File

@ -16,3 +16,4 @@
0.12: Fix bug where settings would behave as if all were set to false 0.12: Fix bug where settings would behave as if all were set to false
0.13: Update to new touch-event handling 0.13: Update to new touch-event handling
0.14: Fix bug in handling changes to `Bangle.appRect` 0.14: Fix bug in handling changes to `Bangle.appRect`
0.15: Workaround bug in 2v26/2v27 firmware

View File

@ -2,7 +2,11 @@ var _a, _b;
var prosettings = (require("Storage").readJSON("promenu.settings.json", true) || {}); var prosettings = (require("Storage").readJSON("promenu.settings.json", true) || {});
(_a = prosettings.naturalScroll) !== null && _a !== void 0 ? _a : (prosettings.naturalScroll = false); (_a = prosettings.naturalScroll) !== null && _a !== void 0 ? _a : (prosettings.naturalScroll = false);
(_b = prosettings.wrapAround) !== null && _b !== void 0 ? _b : (prosettings.wrapAround = true); (_b = prosettings.wrapAround) !== null && _b !== void 0 ? _b : (prosettings.wrapAround = true);
E.showMenu = function (items) { E.showMenu = (function (items) {
if (items == null) {
g.clearRect(Bangle.appRect);
return Bangle.setUI();
}
var RectRnd = function (x1, y1, x2, y2, r) { var RectRnd = function (x1, y1, x2, y2, r) {
var pp = []; var pp = [];
pp.push.apply(pp, g.quadraticBezier([x2 - r, y1, x2, y1, x2, y1 + r])); pp.push.apply(pp, g.quadraticBezier([x2 - r, y1, x2, y1, x2, y1 + r]));
@ -122,7 +126,6 @@ E.showMenu = function (items) {
nameScroll_1 = 0; nameScroll_1 = 0;
}, 300, name, v, item, idx, x, iy); }, 300, name, v, item, idx, x, iy);
} }
g.setColor(g.theme.fg);
iy += fontHeight; iy += fontHeight;
idx++; idx++;
}; };
@ -204,7 +207,10 @@ E.showMenu = function (items) {
else else
l.select(evt); l.select(evt);
}; };
Bangle.setUI({ var touchcb = (function (_button, xy) {
cb(void 0, xy);
});
var uiopts = {
mode: "updown", mode: "updown",
back: back, back: back,
remove: function () { remove: function () {
@ -212,11 +218,20 @@ E.showMenu = function (items) {
if (nameScroller) if (nameScroller)
clearInterval(nameScroller); clearInterval(nameScroller);
Bangle.removeListener("swipe", onSwipe); Bangle.removeListener("swipe", onSwipe);
if (setUITouch)
Bangle.removeListener("touch", touchcb);
(_a = options.remove) === null || _a === void 0 ? void 0 : _a.call(options); (_a = options.remove) === null || _a === void 0 ? void 0 : _a.call(options);
}, },
touch: (function (_button, xy) {
cb(void 0, xy);
}),
}, cb);
return l;
}; };
var setUITouch = process.env.VERSION >= "2v26";
if (!setUITouch) {
uiopts.touch = touchcb;
}
Bangle.setUI(uiopts, cb);
if (setUITouch) {
Bangle.removeListener("touch", Bangle.touchHandler);
delete Bangle.touchHandler;
Bangle.on("touch", touchcb);
}
return l;
});

View File

@ -13,7 +13,12 @@ const prosettings = (require("Storage").readJSON("promenu.settings.json", true)
prosettings.naturalScroll ??= false; prosettings.naturalScroll ??= false;
prosettings.wrapAround ??= true; prosettings.wrapAround ??= true;
E.showMenu = (items?: Menu): MenuInstance => { E.showMenu = ((items?: Menu): MenuInstance | void => {
if(items == null){
g.clearRect(Bangle.appRect);
return Bangle.setUI();
}
const RectRnd = (x1: number, y1: number, x2: number, y2: number, r: number) => { const RectRnd = (x1: number, y1: number, x2: number, y2: number, r: number) => {
const pp = []; const pp = [];
pp.push(...g.quadraticBezier([x2 - r, y1, x2, y1, x2, y1 + r])); pp.push(...g.quadraticBezier([x2 - r, y1, x2, y1, x2, y1 + r]));
@ -167,7 +172,6 @@ E.showMenu = (items?: Menu): MenuInstance => {
}, 300, name, v, item, idx, x, iy); }, 300, name, v, item, idx, x, iy);
} }
g.setColor(g.theme.fg);
iy += fontHeight; iy += fontHeight;
idx++; idx++;
} }
@ -252,21 +256,47 @@ E.showMenu = (items?: Menu): MenuInstance => {
else l.select(evt); else l.select(evt);
}; };
Bangle.setUI({ const touchcb = ((_button, xy) => {
mode: "updown",
back,
remove: () => {
if (nameScroller) clearInterval(nameScroller);
Bangle.removeListener("swipe", onSwipe);
options.remove?.();
},
touch: ((_button, xy) => {
// since we've specified options.touch, // since we've specified options.touch,
// we need to pass through all taps since the default // we need to pass through all taps since the default
// touchHandler isn't installed in setUI // touchHandler isn't installed in setUI
cb(void 0, xy); cb(void 0, xy);
}) satisfies TouchCallback, }) satisfies TouchCallback;
} as SetUIArg<"updown">, cb);
const uiopts = {
mode: "updown",
back: back as () => void,
remove: () => {
if (nameScroller) clearInterval(nameScroller);
Bangle.removeListener("swipe", onSwipe);
if(setUITouch)
Bangle.removeListener("touch", touchcb);
options.remove?.();
},
} satisfies SetUIArg<"updown">;
// does setUI install its own touch handler?
const setUITouch = process.env.VERSION >= "2v26";
if (!setUITouch) {
// old firmware, we can use its touch handler - no need for workaround
(uiopts as any).touch = touchcb;
}
Bangle.setUI(uiopts, cb);
if(setUITouch){
// new firmware, remove setUI's touch handler and use just our own to
// avoid `cb` drawing the menu (as part of setUI's touch handler)
// followed by us drawing the menu (as part of our touch handler)
//
// work around details:
// - https://github.com/espruino/Espruino/issues/2648
// - https://github.com/orgs/espruino/discussions/7697#discussioncomment-13782299
Bangle.removeListener("touch", (Bangle as any).touchHandler);
delete (Bangle as any).touchHandler;
Bangle.on("touch", touchcb);
}
return l; return l;
}; }) as typeof E.showMenu;

View File

@ -1,7 +1,7 @@
{ {
"id": "promenu", "id": "promenu",
"name": "Pro Menu", "name": "Pro Menu",
"version": "0.14", "version": "0.15",
"description": "Replace the built in menu function. Supports Bangle.js 1 and Bangle.js 2.", "description": "Replace the built in menu function. Supports Bangle.js 1 and Bangle.js 2.",
"icon": "icon.png", "icon": "icon.png",
"type": "bootloader", "type": "bootloader",