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-08 12:04:30 +00:00
|
|
|
|
2023-05-09 06:38:56 +00:00
|
|
|
const onSwipe = ((_lr, ud) => {
|
2023-05-08 19:44:21 +00:00
|
|
|
if((Bangle as BangleExt).CLKINFO_FOCUS) return;
|
|
|
|
|
2023-05-08 13:59:14 +00:00
|
|
|
if(!activeTimeout && ud! > 0){
|
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
|
|
|
}
|
2023-05-09 06:38:56 +00:00
|
|
|
}) satisfies SwipeCallback;
|
2023-05-08 12:04:30 +00:00
|
|
|
|
2023-05-08 13:59:14 +00:00
|
|
|
const onDrag = (e => {
|
|
|
|
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){
|
|
|
|
suspendOthers();
|
|
|
|
waitForRelease = true; // wait for first touch up before accepting gestures
|
|
|
|
Bangle.on("drag", onDrag);
|
|
|
|
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
|
|
|
resumeOthers();
|
|
|
|
|
2023-05-08 13:59:14 +00:00
|
|
|
redraw();
|
|
|
|
}, 3000);
|
2023-05-08 12:04:30 +00:00
|
|
|
};
|
|
|
|
|
2023-05-09 06:38:56 +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() {
|
2023-05-08 14:07:42 +00:00
|
|
|
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
|
|
|
|
);
|
|
|
|
},
|
2023-05-09 06:38:56 +00:00
|
|
|
width: connected ? 24 : 0,
|
2023-05-08 12:04:30 +00:00
|
|
|
};
|
|
|
|
|
2023-05-09 06:38:56 +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;
|
2023-05-09 06:38:56 +00:00
|
|
|
Bangle.on("swipe", onSwipe);
|
2023-05-08 12:04:30 +00:00
|
|
|
redraw();
|
|
|
|
});
|
|
|
|
NRF.on("disconnect", () => {
|
|
|
|
WIDGETS["hid"]!.width = 0;
|
2023-05-09 06:38:56 +00:00
|
|
|
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
|
|
|
|
2023-05-08 20:46:16 +00:00
|
|
|
// similarly to the lightswitch app, we tangle with the listener arrays to
|
|
|
|
// disable event handlers
|
|
|
|
type Handler = () => void;
|
|
|
|
const touchEvents: {
|
|
|
|
[key: string]: null | Handler[]
|
|
|
|
} = {
|
|
|
|
tap: null,
|
|
|
|
gesture: null,
|
|
|
|
aiGesture: null,
|
|
|
|
swipe: null,
|
|
|
|
touch: null,
|
|
|
|
drag: null,
|
|
|
|
stroke: null,
|
|
|
|
};
|
|
|
|
|
2023-05-08 12:04:30 +00:00
|
|
|
const suspendOthers = () => {
|
2023-05-08 20:46:16 +00:00
|
|
|
for(const event in touchEvents){
|
|
|
|
const handlers: Handler[] | Handler | undefined
|
|
|
|
= (Bangle as any)[`#on${event}`];
|
|
|
|
|
|
|
|
if(!handlers) continue;
|
|
|
|
|
|
|
|
let newEvents;
|
|
|
|
if(handlers instanceof Array)
|
|
|
|
newEvents = handlers.slice();
|
|
|
|
else
|
|
|
|
newEvents = [handlers /* single fn */];
|
|
|
|
|
|
|
|
for(const handler of newEvents)
|
|
|
|
Bangle.removeListener(event, handler);
|
|
|
|
|
|
|
|
touchEvents[event] = newEvents;
|
|
|
|
}
|
2023-05-08 12:04:30 +00:00
|
|
|
};
|
|
|
|
const resumeOthers = () => {
|
2023-05-08 20:46:16 +00:00
|
|
|
for(const event in touchEvents){
|
|
|
|
const handlers = touchEvents[event];
|
|
|
|
touchEvents[event] = null;
|
|
|
|
|
|
|
|
if(handlers)
|
|
|
|
for(const handler of handlers)
|
2023-05-08 21:06:01 +00:00
|
|
|
try{
|
|
|
|
Bangle.on(event as any, handler);
|
|
|
|
}catch(e){
|
|
|
|
console.log(`couldn't restore "${event}" handler:`, e);
|
|
|
|
}
|
2023-05-08 20:46:16 +00:00
|
|
|
}
|
2023-05-08 12:04:30 +00:00
|
|
|
};
|
|
|
|
})()
|