BangleApps/apps/widhid/wid.ts

155 lines
3.7 KiB
TypeScript
Raw Normal View History

2023-05-08 12:04:30 +00:00
(() => {
2023-05-08 13:58:08 +00:00
const settings: Settings = require("Storage").readJSON("setting.json", true) || { HID: false } as Settings;
2023-05-08 12:04:30 +00:00
if (settings.HID !== "kbmedia") {
console.log("widhid: can't enable, HID setting isn't \"kbmedia\"");
return;
}
2023-05-10 07:05:29 +00:00
// @ts-ignore
delete settings;
2023-05-08 12:04:30 +00:00
2023-05-08 13:59:14 +00:00
let anchor = {x:0,y:0};
let start = {x:0,y:0};
2023-05-08 12:04:30 +00:00
let dragging = false;
let activeTimeout: number | undefined;
2023-05-08 13:59:14 +00:00
let waitForRelease = true;
2023-05-10 22:13:19 +00:00
const onSwipe = ((_lr, ud) => {
// do these checks in order of cheapness
if(ud! > 0 && !activeTimeout && !(Bangle as BangleExt).CLKINFO_FOCUS){
2023-05-08 12:04:30 +00:00
listen();
2023-05-08 13:59:14 +00:00
Bangle.buzz(20);
2023-05-08 12:04:30 +00:00
}
}) satisfies SwipeCallback;
2023-05-08 12:04:30 +00:00
2023-05-08 13:59:14 +00:00
const onDrag = (e => {
// Espruino/35c8cb9be11
(E as any).stopEventPropagation && (E as any).stopEventPropagation();
2023-05-08 13:59:14 +00:00
if(e.b === 0){
// released
const wasDragging = dragging;
dragging = false;
2023-05-08 12:04:30 +00:00
2023-05-08 13:59:14 +00:00
if(waitForRelease){
waitForRelease = false;
return;
}
if(!wasDragging // i.e. tap
|| (Math.abs(e.x - anchor.x) < 2 && Math.abs(e.y - anchor.y) < 2))
{
toggle();
onEvent();
return;
}
}
if(waitForRelease) return;
if(e.b && !dragging){
2023-05-08 12:04:30 +00:00
dragging = true;
2023-05-08 13:59:14 +00:00
setStart(e);
Object.assign(anchor, start);
2023-05-08 12:04:30 +00:00
return;
}
2023-05-08 13:59:14 +00:00
const dx = e.x - start.x;
const dy = e.y - start.y;
2023-05-08 12:04:30 +00:00
2023-05-08 13:59:14 +00:00
if(Math.abs(dy) > 25 && Math.abs(dx) > 25){
// diagonal, ignore
setStart(e);
2023-05-08 12:04:30 +00:00
return;
}
2023-05-08 13:59:14 +00:00
// had a drag in a single axis
2023-05-08 21:05:41 +00:00
if(dx > 40){ next(); onEvent(); waitForRelease = true; }
2023-05-08 13:59:14 +00:00
else if(dx < -40){ prev(); onEvent(); waitForRelease = true; }
2023-05-08 21:05:41 +00:00
else if(dy > 30){ down(); onEvent(); setStart(e); }
2023-05-08 13:59:14 +00:00
else if(dy < -30){ up(); onEvent(); setStart(e); }
}) satisfies DragCallback;
2023-05-08 12:04:30 +00:00
2023-05-08 13:59:14 +00:00
const setStart = ({ x, y }: { x: number, y: number }) => {
start.x = x;
start.y = y;
};
const onEvent = () => {
Bangle.buzz(20); // feedback event sent
listen(); // had an event, keep listening for more
};
2023-05-08 12:04:30 +00:00
2023-05-08 13:59:14 +00:00
const listen = () => {
2023-05-08 12:04:30 +00:00
const wasActive = !!activeTimeout;
2023-05-08 13:59:14 +00:00
if(!wasActive){
waitForRelease = true; // wait for first touch up before accepting gestures
2023-05-08 13:59:14 +00:00
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)
);
2023-05-08 13:59:14 +00:00
redraw();
}
2023-05-08 12:04:30 +00:00
2023-05-08 13:59:14 +00:00
if(activeTimeout) clearTimeout(activeTimeout);
2023-05-08 12:04:30 +00:00
activeTimeout = setTimeout(() => {
activeTimeout = undefined;
2023-05-08 13:59:14 +00:00
Bangle.removeListener("drag", onDrag);
2023-05-08 12:04:30 +00:00
2023-05-08 13:59:14 +00:00
redraw();
}, 3000);
2023-05-08 12:04:30 +00:00
};
const redraw = () => setTimeout(Bangle.drawWidgets, 50);
const connected = NRF.getSecurityStatus().connected;
2023-05-08 12:04:30 +00:00
WIDGETS["hid"] = {
area: "tr",
sortorder: -20,
draw: function() {
if(this.width === 0) return;
2023-05-08 12:04:30 +00:00
g.drawImage(
activeTimeout
2023-05-08 13:57:33 +00:00
? require("heatshrink").decompress(atob("jEYxH+AEfH44XXAAYXXDKIXZDYp3pC/6KHUMwWHC/4XvUy4YGdqoA/AFoA=="))
: require("heatshrink").decompress(atob("jEYxH+AEcdjoXXAAYXXDKIXZDYp3pC/6KHUMwWHC/4XvUy4YGdqoA/AFoA==")),
2023-05-08 12:04:30 +00:00
this.x! + 2,
this.y! + 2
);
},
width: connected ? 24 : 0,
2023-05-08 12:04:30 +00:00
};
if(connected)
Bangle.on("swipe", onSwipe);
2023-05-10 07:05:29 +00:00
// @ts-ignore
delete connected;
2023-05-08 12:04:30 +00:00
NRF.on("connect", () => {
WIDGETS["hid"]!.width = 24;
Bangle.on("swipe", onSwipe);
2023-05-08 12:04:30 +00:00
redraw();
});
NRF.on("disconnect", () => {
WIDGETS["hid"]!.width = 0;
Bangle.removeListener("swipe", onSwipe);
2023-05-08 12:04:30 +00:00
redraw();
});
2023-05-08 13:59:30 +00:00
//const DEBUG = true;
2023-05-08 12:04:30 +00:00
const sendHid = (code: number) => {
2023-05-08 13:59:30 +00:00
//if(DEBUG) return;
2023-05-08 12:04:30 +00:00
NRF.sendHIDReport(
[1, code],
() => NRF.sendHIDReport([1, 0]),
);
};
2023-05-08 13:59:30 +00:00
const next = () => /*DEBUG ? console.log("next") : */ sendHid(0x01);
const prev = () => /*DEBUG ? console.log("prev") : */ sendHid(0x02);
const toggle = () => /*DEBUG ? console.log("toggle") : */ sendHid(0x10);
const up = () => /*DEBUG ? console.log("up") : */ sendHid(0x40);
const down = () => /*DEBUG ? console.log("down") : */ sendHid(0x80);
2023-05-08 12:04:30 +00:00
})()