popcon: use E.stopEventPropagation() for the drag handler

pull/2743/head
Rob Pilling 2023-05-13 08:44:50 +01:00
parent b12fa58215
commit 109fd078f4
3 changed files with 14 additions and 151 deletions

View File

@ -13,6 +13,7 @@ Swipe down to enable - note the icon changes from blue to orange, indicating it'
All other watch interaction is disabled for 3 seconds, to prevent clashing taps/drags - this period is extended as you continue to alter the volume, play/pause and jump between tracks. All other watch interaction is disabled for 3 seconds, to prevent clashing taps/drags - this period is extended as you continue to alter the volume, play/pause and jump between tracks.
Requires espruino firmware > 2v17 to avoid event handler clashes.
# Setup / Technical details # Setup / Technical details

View File

@ -10,34 +10,14 @@
var dragging = false; var dragging = false;
var activeTimeout; var activeTimeout;
var waitForRelease = true; var waitForRelease = true;
var mayInterceptSwipe = function () {
if (Bangle.CLKINFO_FOCUS)
return 0;
if (Bangle.CLOCK)
return 1;
var swipes = Bangle["#onswipe"];
if (typeof swipes === "function") {
if (swipes !== onSwipe)
return swipes.length > 1;
}
else if (swipes) {
for (var _i = 0, swipes_1 = swipes; _i < swipes_1.length; _i++) {
var handler = swipes_1[_i];
if (handler !== onSwipe && (handler === null || handler === void 0 ? void 0 : handler.length) > 1)
return 0;
}
}
if (Bangle["#ondrag"])
return 0;
return 1;
};
var onSwipe = (function (_lr, ud) { var onSwipe = (function (_lr, ud) {
if (ud > 0 && !activeTimeout && mayInterceptSwipe()) { if (ud > 0 && !activeTimeout && !Bangle.CLKINFO_FOCUS) {
listen(); listen();
Bangle.buzz(20); Bangle.buzz(20);
} }
}); });
var onDrag = (function (e) { var onDrag = (function (e) {
E.stopEventPropagation && E.stopEventPropagation();
if (e.b === 0) { if (e.b === 0) {
var wasDragging = dragging; var wasDragging = dragging;
dragging = false; dragging = false;
@ -99,9 +79,9 @@
var listen = function () { var listen = function () {
var wasActive = !!activeTimeout; var wasActive = !!activeTimeout;
if (!wasActive) { if (!wasActive) {
suspendOthers();
waitForRelease = true; waitForRelease = true;
Bangle.on("drag", onDrag); Bangle.on("drag", onDrag);
Bangle["#ondrag"] = [onDrag].concat(Bangle["#ondrag"].filter(function (f) { return f !== onDrag; }));
redraw(); redraw();
} }
if (activeTimeout) if (activeTimeout)
@ -109,7 +89,6 @@
activeTimeout = setTimeout(function () { activeTimeout = setTimeout(function () {
activeTimeout = undefined; activeTimeout = undefined;
Bangle.removeListener("drag", onDrag); Bangle.removeListener("drag", onDrag);
resumeOthers();
redraw(); redraw();
}, 3000); }, 3000);
}; };
@ -148,48 +127,4 @@
var toggle = function () { return sendHid(0x10); }; var toggle = function () { return sendHid(0x10); };
var up = function () { return sendHid(0x40); }; var up = function () { return sendHid(0x40); };
var down = function () { return sendHid(0x80); }; var down = function () { return sendHid(0x80); };
var touchEvents = {
tap: null,
gesture: null,
aiGesture: null,
swipe: null,
touch: null,
drag: null,
stroke: null,
};
var suspendOthers = function () {
for (var event_ in touchEvents) {
var event = event_;
var handlers = Bangle["#on".concat(event)];
if (!handlers)
continue;
var newEvents = void 0;
if (handlers instanceof Array)
newEvents = handlers.filter(function (f) { return f; });
else
newEvents = [handlers];
for (var _i = 0, newEvents_1 = newEvents; _i < newEvents_1.length; _i++) {
var handler = newEvents_1[_i];
Bangle.removeListener(event, handler);
}
touchEvents[event] = newEvents;
}
};
var resumeOthers = function () {
for (var event_ in touchEvents) {
var event = event_;
var handlers = touchEvents[event];
touchEvents[event] = null;
if (handlers)
for (var _i = 0, handlers_1 = handlers; _i < handlers_1.length; _i++) {
var handler = handlers_1[_i];
try {
Bangle.on(event, handler);
}
catch (e) {
console.log("couldn't restore \"".concat(event, "\" handler:"), e);
}
}
}
};
})(); })();

View File

@ -1,9 +1,4 @@
(() => { (() => {
type BangleEventKeys = "tap" | "gesture" | "aiGesture" | "swipe" | "touch" | "drag" | "stroke";
type BangleEvents = {
[key in BangleEventKeys as `#on${key}`]?: Handler | (Handler | undefined)[]
};
const settings: Settings = require("Storage").readJSON("setting.json", true) || { HID: false } as Settings; const settings: Settings = require("Storage").readJSON("setting.json", true) || { HID: false } as Settings;
if (settings.HID !== "kbmedia") { if (settings.HID !== "kbmedia") {
console.log("widhid: can't enable, HID setting isn't \"kbmedia\""); console.log("widhid: can't enable, HID setting isn't \"kbmedia\"");
@ -18,40 +13,18 @@
let activeTimeout: number | undefined; let activeTimeout: number | undefined;
let waitForRelease = true; let waitForRelease = true;
// If the user shows a menu, we want to temporarily disable ourselves
//
// We could detect showing of a menu by overriding E.showMenu
// and to detect hiding of a menu, we hook setUI
//
// Perhaps easier to check Bangle.swipeHandler - set by setUI,
// called by E.showMenu
const mayInterceptSwipe = () => {
if((Bangle as BangleExt).CLKINFO_FOCUS) return 0;
if(Bangle.CLOCK) return 1;
const swipes = (Bangle as BangleEvents)["#onswipe"];
if(typeof swipes === "function"){
if(swipes !== onSwipe)
return swipes.length > 1; // second argument is up/down
}else if(swipes){
for(const handler of swipes)
if(handler !== onSwipe && handler?.length > 1)
return 0;
}
if((Bangle as BangleEvents)["#ondrag"]) return 0;
return 1;
};
const onSwipe = ((_lr, ud) => { const onSwipe = ((_lr, ud) => {
// do these checks in order of cheapness // do these checks in order of cheapness
if(ud! > 0 && !activeTimeout && mayInterceptSwipe()){ if(ud! > 0 && !activeTimeout && !(Bangle as BangleExt).CLKINFO_FOCUS){
listen(); listen();
Bangle.buzz(20); Bangle.buzz(20);
} }
}) satisfies SwipeCallback; }) satisfies SwipeCallback;
const onDrag = (e => { const onDrag = (e => {
// Espruino/35c8cb9be11
(E as any).stopEventPropagation && (E as any).stopEventPropagation();
if(e.b === 0){ if(e.b === 0){
// released // released
const wasDragging = dragging; const wasDragging = dragging;
@ -108,9 +81,14 @@
const listen = () => { const listen = () => {
const wasActive = !!activeTimeout; const wasActive = !!activeTimeout;
if(!wasActive){ if(!wasActive){
suspendOthers();
waitForRelease = true; // wait for first touch up before accepting gestures waitForRelease = true; // wait for first touch up before accepting gestures
Bangle.on("drag", onDrag); Bangle.on("drag", onDrag);
// move our drag to the start of the event listener array
(Bangle as any)["#ondrag"] = [onDrag].concat(
(Bangle as any)["#ondrag"].filter((f: unknown) => f !== onDrag)
);
redraw(); redraw();
} }
@ -119,7 +97,6 @@
activeTimeout = undefined; activeTimeout = undefined;
Bangle.removeListener("drag", onDrag); Bangle.removeListener("drag", onDrag);
resumeOthers();
redraw(); redraw();
}, 3000); }, 3000);
@ -174,54 +151,4 @@
const toggle = () => /*DEBUG ? console.log("toggle") : */ sendHid(0x10); const toggle = () => /*DEBUG ? console.log("toggle") : */ sendHid(0x10);
const up = () => /*DEBUG ? console.log("up") : */ sendHid(0x40); const up = () => /*DEBUG ? console.log("up") : */ sendHid(0x40);
const down = () => /*DEBUG ? console.log("down") : */ sendHid(0x80); const down = () => /*DEBUG ? console.log("down") : */ sendHid(0x80);
// similarly to the lightswitch app, we tangle with the listener arrays to
// disable event handlers
type Handler = () => void;
const touchEvents: {
[key in BangleEventKeys]: null | Handler[]
} = {
tap: null,
gesture: null,
aiGesture: null,
swipe: null,
touch: null,
drag: null,
stroke: null,
};
const suspendOthers = () => {
for(const event_ in touchEvents){
const event = event_ as BangleEventKeys;
const handlers = (Bangle as BangleEvents)[`#on${event}`];
if(!handlers) continue;
let newEvents;
if(handlers instanceof Array)
newEvents = handlers.filter(f=>f) as Handler[];
else
newEvents = [handlers /* single fn */];
for(const handler of newEvents)
Bangle.removeListener(event, handler);
touchEvents[event] = newEvents;
}
};
const resumeOthers = () => {
for(const event_ in touchEvents){
const event = event_ as BangleEventKeys;
const handlers = touchEvents[event];
touchEvents[event] = null;
if(handlers)
for(const handler of handlers)
try{
Bangle.on(event as any, handler);
}catch(e){
console.log(`couldn't restore "${event}" handler:`, e);
}
}
};
})() })()