Added BLE HID option for Joystick and bare Keyboard, update HID apps to send correct info

pull/361/head
Gordon Williams 2020-04-28 15:23:02 +01:00
parent 23c5ea3829
commit 517c35a37d
16 changed files with 411 additions and 41 deletions

View File

@ -2,7 +2,7 @@
{ "id": "boot",
"name": "Bootloader",
"icon": "bootloader.png",
"version":"0.14",
"version":"0.15",
"description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings",
"tags": "tool,system",
"type":"bootloader",
@ -122,9 +122,10 @@
{ "id": "setting",
"name": "Settings",
"icon": "settings.png",
"version":"0.18",
"version":"0.19",
"description": "A menu for setting up Bangle.js",
"tags": "tool,system",
"readme": "README.md",
"storage": [
{"name":"setting.app.js","url":"settings.js"},
{"name":"setting.boot.js","url":"boot.js"},
@ -480,7 +481,7 @@
"name": "Bluetooth Music Controls",
"shortName": "Music Control",
"icon": "hid-music.png",
"version":"0.01",
"version":"0.02",
"description": "Enable HID in settings, pair with your phone, then use this app to control music from your watch!",
"tags": "bluetooth",
"storage": [
@ -492,7 +493,7 @@
"name": "Bluetooth Keyboard",
"shortName": "Bluetooth Kbd",
"icon": "hid-keyboard.png",
"version":"0.01",
"version":"0.02",
"description": "Enable HID in settings, pair with your phone/PC, then use this app to control other apps",
"tags": "bluetooth",
"storage": [
@ -504,7 +505,7 @@
"name": "Binary Bluetooth Keyboard",
"shortName": "Binary BT Kbd",
"icon": "hid-binary-keyboard.png",
"version":"0.01",
"version":"0.02",
"description": "Enable HID in settings, pair with your phone/PC, then type messages using the onscreen keyboard by tapping repeatedly on the key you want",
"tags": "bluetooth",
"storage": [
@ -1437,7 +1438,7 @@
"name": "Camera shutter",
"shortName":"Cam shutter",
"icon": "app.png",
"version":"0.01",
"version":"0.02",
"description": "Enable HID, connect to your phone, start your camera and trigger the shot on your Bangle",
"tags": "tools",
"storage": [

View File

@ -13,3 +13,4 @@
0.13: Now automatically load *.boot.js at startup
Move alarm code into alarm.boot.js
0.14: Move welcome loaders to *.boot.js
0.15: Added BLE HID option for Joystick and bare Keyboard

View File

@ -4,7 +4,9 @@ E.setFlags({pretokenise:1});
var s = require('Storage').readJSON('setting.json',1)||{};
if (s.ble!==false) {
if (s.HID) { // Human interface device
Bangle.HID = E.toUint8Array(atob("BQEJBqEBhQIFBxngKecVACUBdQGVCIEClQF1CIEBlQV1AQUIGQEpBZEClQF1A5EBlQZ1CBUAJXMFBxkAKXOBAAkFFQAm/wB1CJUCsQLABQwJAaEBhQEVACUBdQGVAQm1gQIJtoECCbeBAgm4gQIJzYECCeKBAgnpgQIJ6oECwA=="));
if (s.HID=="joy") Bangle.HID = E.toUint8Array(atob("BQEJBKEBhQMJAaEABQkZASkFFQAlAZUFdQGBApUDdQGBAwUBCTAJMRWBJX91CJUCgQLAwA=="));
else if (s.HID=="kb") Bangle.HID = E.toUint8Array(atob("BQEJBqEBBQcZ4CnnFQAlAXUBlQiBApUBdQiBAZUFdQEFCBkBKQWRApUBdQORAZUGdQgVACVzBQcZAClzgQAJBRUAJv8AdQiVArECwA=="));
else /*kbmedia*/Bangle.HID = E.toUint8Array(atob("BQEJBqEBhQIFBxngKecVACUBdQGVCIEClQF1CIEBlQV1AQUIGQEpBZEClQF1A5EBlQZ1CBUAJXMFBxkAKXOBAAkFFQAm/wB1CJUCsQLABQwJAaEBhQEVACUBdQGVAQm1gQIJtoECCbeBAgm4gQIJzYECCeKBAgnpgQIJ6oECwA=="));
NRF.setServices({}, {uart:true, hid:Bangle.HID});
}
}

88
apps/boot/hid_info.txt Normal file
View File

@ -0,0 +1,88 @@
## Joystick:
https://github.com/espruino/BangleApps/issues/349#issuecomment-620231524
```
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x04, // Usage (Joystick)
0xA1, 0x01, // Collection (Application)
0x09, 0x01, // Usage (Pointer)
0xA1, 0x00, // Collection (Physical)
// Buttons
0x05, 0x09, // Usage Page (Buttons)
0x19, 0x01, // Usage Minimum (1)
0x29, 0x05, // Usage Maximum (5)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x95, 0x05, // Report Count (5)
0x75, 0x01, // Report Size (1)
0x81, 0x02, // Input (Data, Variable, Absolute)
// padding bits
0x95, 0x03, // Report Count (3)
0x75, 0x01, // Report Size (1)
0x81, 0x03, // Input (Constant)
// Stick
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x15, 0x81, // Logical Minimum (-127)
0x25, 0x7f, // Logical Maximum (127)
0x75, 0x08, // Report Size (8)
0x95, 0x02, // Report Count (2)
0x81, 0x02, // Input (Data, Variable, Absolute)
0xC0, // End Collection (Physical)
0xC0 // End Collection (Application)
```
## Keyboard
http://www.espruino.com/BLE+Keyboard
```
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x06, // Usage (Keyboard)
0xA1, 0x01, // Collection (Application)
0x05, 0x07, // Usage Page (Key Codes)
0x19, 0xe0, // Usage Minimum (224)
0x29, 0xe7, // Usage Maximum (231)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x08, // Report Count (8)
0x81, 0x02, // Input (Data, Variable, Absolute)
0x95, 0x01, // Report Count (1)
0x75, 0x08, // Report Size (8)
0x81, 0x01, // Input (Constant) reserved byte(1)
0x95, 0x05, // Report Count (5)
0x75, 0x01, // Report Size (1)
0x05, 0x08, // Usage Page (Page# for LEDs)
0x19, 0x01, // Usage Minimum (1)
0x29, 0x05, // Usage Maximum (5)
0x91, 0x02, // Output (Data, Variable, Absolute), Led report
0x95, 0x01, // Report Count (1)
0x75, 0x03, // Report Size (3)
0x91, 0x01, // Output (Data, Variable, Absolute), Led report padding
0x95, 0x06, // Report Count (6)
0x75, 0x08, // Report Size (8)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x73, // Logical Maximum (115 - include F13, etc)
0x05, 0x07, // Usage Page (Key codes)
0x19, 0x00, // Usage Minimum (0)
0x29, 0x73, // Usage Maximum (115 - include F13, etc)
0x81, 0x00, // Input (Data, Array) Key array(6 bytes)
0x09, 0x05, // Usage (Vendor Defined)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Count (2)
0x95, 0x02, // Report Size (8 bit)
0xB1, 0x02, // Feature (Data, Variable, Absolute)
0xC0 // End Collection (Application)
```

2
apps/hidbkbd/ChangeLog Normal file
View File

@ -0,0 +1,2 @@
0.01: Core functionnality
0.02: Offer to enable HID if disabled. Handle with/without media keys

View File

@ -45,13 +45,7 @@ const KEY = {
0 : 39
};
function sendHID(code) {
return new Promise(resolve=>{
NRF.sendHIDReport([2,0,0,code,0,0,0,0,0], () => {
NRF.sendHIDReport([2,0,0,0,0,0,0,0,0], resolve);
});
});
};
var sendHID;
function showChars(x,chars) {
var lines = Math.round(Math.sqrt(chars.length)*2);
@ -103,10 +97,24 @@ function startKeyboardHID() {
}).then(startKeyboardHID);
};
if (!settings.HID) {
E.showMessage('HID disabled');
setTimeout(load, 1000);
} else {
if (settings.HID=="kb" || settings.HID=="kbmedia") {
if (settings.HID=="kbmedia") {
sendHID = function(code) {
return new Promise(resolve=>{
NRF.sendHIDReport([2,0,0,code,0,0,0,0,0], () => {
NRF.sendHIDReport([2,0,0,0,0,0,0,0,0], resolve);
});
});
};
} else {
sendHID = function(code) {
return new Promise(resolve=>{
NRF.sendHIDReport([0,0,code,0,0,0,0,0], () => {
NRF.sendHIDReport([0,0,0,0,0,0,0,0], resolve);
});
});
};
}
startKeyboardHID();
setWatch(() => {
sendHID(44); // space
@ -114,4 +122,12 @@ if (!settings.HID) {
setWatch(() => {
sendHID(40); // enter
}, BTN3, {repeat:true});
} else {
E.showPrompt("Enable HID?",{title:"HID disabled"}).then(function(enable) {
if (enable) {
settings.HID = "kb";
require("Storage").write('setting.json', settings);
setTimeout(load, 1000, "hidbkbd.app.js");
} else setTimeout(load, 1000);
});
}

View File

@ -1 +1,2 @@
0.01: Core functionnality
0.02: Offer to enable HID if disabled

View File

@ -4,7 +4,7 @@ const settings = storage.readJSON('setting.json',1) || { HID: false };
var sendHid, camShot, profile;
if (settings.HID) {
if (settings.HID=="kbmedia") {
profile = 'camShutter';
sendHid = function (code, cb) {
try {
@ -19,8 +19,13 @@ if (settings.HID) {
};
camShot = function (cb) { sendHid(0x80, cb); };
} else {
E.showMessage('HID disabled');
setTimeout(load, 1000);
E.showPrompt("Enable HID?",{title:"HID disabled"}).then(function(enable) {
if (enable) {
settings.HID = "kbmedia";
require("Storage").write('setting.json', settings);
setTimeout(load, 1000, "hidcam.app.js");
} else setTimeout(load, 1000);
});
}
function drawApp() {
g.clear();

2
apps/hidkbd/ChangeLog Normal file
View File

@ -0,0 +1,2 @@
0.01: Core functionnality
0.02: Offer to enable HID if disabled. Handle with/without media keys

View File

@ -4,8 +4,9 @@ const settings = storage.readJSON('setting.json',1) || { HID: false };
var sendHid, next, prev, toggle, up, down, profile;
if (settings.HID) {
if (settings.HID=="kb" || settings.HID=="kbmedia") {
profile = 'Keyboard';
if (settings.HID=="kbmedia") {
sendHid = function (code, cb) {
try {
NRF.sendHIDReport([2,0,0,code,0,0,0,0,0], () => {
@ -17,14 +18,32 @@ if (settings.HID) {
print(e);
}
};
} else {
sendHid = function (code, cb) {
try {
NRF.sendHIDReport([0,0,code,0,0,0,0,0], () => {
NRF.sendHIDReport([0,0,0,0,0,0,0,0], () => {
if (cb) cb();
});
});
} catch(e) {
print(e);
}
};
}
next = function (cb) { sendHid(0x4f, cb); };
prev = function (cb) { sendHid(0x50, cb); };
toggle = function (cb) { sendHid(0x2c, cb); };
up = function (cb) {sendHid(0x52, cb); };
down = function (cb) { sendHid(0x51, cb); };
} else {
E.showMessage('HID disabled');
setTimeout(load, 1000);
E.showPrompt("Enable HID?",{title:"HID disabled"}).then(function(enable) {
if (enable) {
settings.HID = "kb";
require("Storage").write('setting.json', settings);
setTimeout(load, 1000, "hidkbd.app.js");
} else setTimeout(load, 1000);
});
}
function drawApp() {

1
apps/hidmsic/ChangeLog Normal file
View File

@ -0,0 +1 @@
0.01: Core functionnality

View File

@ -4,7 +4,7 @@ const settings = storage.readJSON('setting.json',1) || { HID: false };
var sendHid, next, prev, toggle, up, down, profile;
if (settings.HID) {
if (settings.HID=="kbmedia") {
profile = 'Music';
sendHid = function (code, cb) {
try {
@ -23,8 +23,13 @@ if (settings.HID) {
up = function (cb) {sendHid(0x40, cb); };
down = function (cb) { sendHid(0x80, cb); };
} else {
E.showMessage('HID disabled');
setTimeout(load, 1000);
E.showPrompt("Enable HID?",{title:"HID disabled"}).then(function(enable) {
if (enable) {
settings.HID = "kbmedia";
require("Storage").write('setting.json', settings);
setTimeout(load, 1000, "hidmsc.app.js");
} else setTimeout(load, 1000);
});
}
function drawApp() {

View File

@ -0,0 +1,206 @@
var locale = require("locale");
var CHARW = 34;
var CHARP = 2;
var Y = 50;
// Offscreen buffer
var buf = Graphics.createArrayBuffer(CHARW+CHARP*2,CHARW*2 + CHARP*2,1,{msb:true});
var bufimg = {width:buf.getWidth(),height:buf.getHeight(),buffer:buf.buffer};
// The last time that we displayed
var lastTime = " ";
// If animating, this is the interval's id
var animInterval;
var timeInterval;
/* Get array of lines from digit d to d+1.
n is the amount (0..1)
maxFive is true is this digit only counts 0..5 */
const DIGITS = {
" ":(g,s,p,n)=>{},
"0":(g,s,p,n)=>{
g.fillRect(1+s*n,1-p, 1+s,1+p);
g.fillRect(1+s-p,1, 1+s+p,1+s);
g.fillRect(1+s-p,1+s, 1+s+p,1+2*s);
g.fillRect(1+s*n,1+2*s-p, 1+s,1+2*s+p);
g.fillRect(1+s*n,1+s-p, 1+s*n,1+2*s+p);
g.fillRect(1+s*n-p,1, 1+s*n+p,1+s)},
"1":(g,s,p,n)=>{
g.fillRect(1+(1-n)*s,1-p, 1+s,1+p);
g.fillRect(1+s-p,1, 1+s+p,1+s);
g.fillRect(1+(1-n)*s,1+s-p, 1+s,1+s+p);
g.fillRect(1-p+(1-n)*s,1+s, 1+p+(1-n)*s,1+2*s);
g.fillRect(1+(1-n)*s,1-p+2*s, 1+s,1+p+2*s)},
"2":(g,s,p,n)=>{
g.fillRect(1,1-p, 1+s,1+p);
g.fillRect(1+s-p,1, 1+s+p,1+s);
g.fillRect(1,1+s-p, 1+s,1+s+p);
g.fillRect(1-p,1+(1+n)*s, 1+p,1+2*s);
g.fillRect(1+s-p,1+(2-n)*s, 1+s+p,1+2*s);
g.fillRect(1,1+2*s-p, 1+s,1+2*s+p)},
"3":(g,s,p,n)=>{
g.fillRect(1,1-p, 1+(1-n)*s,1+p);
g.fillRect(1-p,1, 1+p,n);
g.fillRect(1+s-p,1, 1+s+p,1+s);
g.fillRect(1,1+s-p, 1+s,1+s+p);
g.fillRect(1+s-p,1+s, 1+s+p,1+2*s);
g.fillRect(1+s*n,1+2*s-p, 1+s,1+2*s+p)},
"4":(g,s,p,n)=>{
g.fillRect(1-p,1, 1+p,1+s);
g.fillRect(1+s,1-p, 1+(1-n)*s,1+p);
g.fillRect(1+s-p,1, 1+s+p,1+(1-n)*s);
g.fillRect(1,1+s-p, 1+s,1+s+p);
g.fillRect(1+s-p,1+s, 1+s+p,1+2*s);
g.fillRect(1+(1-n)*s,1+2*s-p, 1+s,1+2*s+p)},
"5to0": (g,s,p,n)=>{ // 5 -> 0
g.fillRect(1-p,1, 1+p,1+s);
g.fillRect(1,1-p, 1+s,1+p);
g.fillRect(1+s*n,1+s-p, 1+s,1+s+p);
g.fillRect(1+s-p,1+s, 1+s+p,1+2*s);
g.fillRect(1,1+2*s*p, 1+s,1+2*s+p);
g.fillRect(1,1+2*s-p, 1,1+2*s+p);
g.fillRect(1+s-p,1+(1-n)*s, 1+s+p,1+s);
g.fillRect(1-p,1+s, 1+p,1+(1+n)*s)},
"5to6": (g,s,p,n)=>{ // 5 -> 6
g.fillRect(1-p,1, 1+p,1+s);
g.fillRect(1,1-p, 1+s,1+p);
g.fillRect(1,1+s-p, 1+s,1+s+p);
g.fillRect(1+s-p,1+s, 1+s+p,1+2*s);
g.fillRect(1,1+2*s-p, 1+s,1+2*s+p);
g.fillRect(1-p,2-n, 1+p,1+2*s)},
"6":(g,s,p,n)=>{
g.fillRect(1-p,1, 1+p,1+(1-n)*s);
g.fillRect(1,1-p, 1+s,1+p);
g.fillRect(1+s*n,1+s-p, 1+s,1+s+p);
g.fillRect(1+s-p,1+(1-n)*s, 1+s+p,1+s);
g.fillRect(1+s-p,1+s, 1+s+p,1+2*s);
g.fillRect(1+s*n,1+2*s-p, 1+s,1+2*s+p);
g.fillRect(1-p,1+(1-n)*s, 1+p,1+s*(2-2*n))},
"7":(g,s,p,n)=>{
g.fillRect(1-p,1, 1+p,n);
g.fillRect(1,1-p, 1+s,1+p);
g.fillRect(1+s-p,1, 1+s+p,1+s);
g.fillRect(1+(1-n)*s,1+s-p, 1+s,1+s+p);
g.fillRect(1+s-p,1+s, 1+s+p,1+2*s);
g.fillRect(1+(1-n)*s,1+2*s-p, 1+s,1+2*s+p);
g.fillRect(1+(1-n)*s-p,1+s, 1+(1-n)*s+p,1+2*s)},
"8":(g,s,p,n)=>{
g.fillRect(1-p,1, 1+p,1+s);
g.fillRect(1,1-p, 1+s,1+p);
g.fillRect(1+s-p,1, 1+s+p,1+s);
g.fillRect(1,1+s-p, 1+s,1+s+p);
g.fillRect(1+s-p,1+s, 1+s+p,1+2*s);
g.fillRect(1,1+2*s-p, 1+s,1+2*s+p);
g.fillRect(1-p,1+s, 1+p,1+s*(2-n))},
"9":(g,s,p,n)=>{
g.fillRect(1-p,1, 1+p,1+s);
g.fillRect(1,1-p, 1+s,1+p);
g.fillRect(1+s-p,1, 1+s+p,1+s);
g.fillRect(1,1+s-p, 1+(1-n)*s,1+s+p);
g.fillRect(1-p,1+s, 1+p,1+(1+n)*s);
g.fillRect(1+s-p,1+s, 1+s+p,1+2*s);
g.fillRect(1,1+2*s-p, 1+s,1+2*s+p)},
":":(g,s,p,n)=>{
g.fillRect(1+s*0.4,1+s*0.4-p, 1+s*0.6,1+s*0.4+p);
g.fillRect(1+s*0.6-p,1+s*0.4, 1+s*0.6+p,1+s*0.6);
g.fillRect(1+s*0.6,1+s*0.6-p, 1+s*0.4,1+s*0.6+p);
g.fillRect(1+s*0.4-p,1+s*0.4, 1+s*0.4+p,1+s*0.6);
g.fillRect(1+s*0.4,1+s*1.4-p, 1+s*0.6,1+s*1.4+p);
g.fillRect(1+s*0.6-p,1+s*1.4, 1+s*0.6+p,1+s*1.6);
g.fillRect(1+s*0.6,1+s*1.6-p, 1+s*0.4,1+s*1.6+p);
g.fillRect(1+s*0.4-p,1+s*1.4, 1+s*0.4+p,1+s*1.6)
}};
/* Draw a transition between lastText and thisText.
'n' is the amount - 0..1 */
function drawDigits(lastText,thisText,n) {
const p = CHARP; // padding around digits
const s = CHARW; // character size
var x = p; // x offset
var y = Y+p; // y offset
g.reset();
for (var i=0;i<lastText.length;i++) {
var lastCh = lastText[i];
var thisCh = thisText[i];
if (thisCh==":") x-=4;
if (lastCh!=thisCh) {
var ch, chn = n;
if ((thisCh-1==lastCh ||
(thisCh==0 && lastCh==5) ||
(thisCh==0 && lastCh==9)))
ch = lastCh;
else {
ch = thisCh;
chn = 0;
}
if (ch=="5") ch = (lastCh==5 && thisCh==0)?"5to0":"5to6";
buf.clear();
DIGITS[ch](buf,s,p,chn);
g.drawImage(bufimg,x-1,y-1);
}
if (thisCh==":") x-=4;
x+=s+p+7;
}
}
function drawSeconds() {
var x = CHARW*6 + CHARP*2 - 4;
var y = Y + 2*CHARW + CHARP;
var d = new Date();
g.reset();
g.setFont("6x8");
g.setFontAlign(-1,-1);
g.drawString(("0"+d.getSeconds()).substr(-2), x, y-8, true);
// date
g.setFontAlign(0,-1);
var date = locale.date(d,false);
g.drawString(date, g.getWidth()/2, y+8, true);
}
/* Show the current time, and animate if needed */
function showTime() {
if (animInterval) return; // in animation - quit
var d = new Date();
var t = (" "+d.getHours()).substr(-2)+":"+
("0"+d.getMinutes()).substr(-2);
var l = lastTime;
// same - don't animate
if (t==l || l==" ") {
drawDigits(t,l,0);
drawSeconds();
return;
}
var n = 0;
animInterval = setInterval(function() {
n += 1/10;
if (n>=1) {
n=1;
clearInterval(animInterval);
animInterval = undefined;
}
drawDigits(l,t,n);
}, 20);
lastTime = t;
}
Bangle.on('lcdPower',function(on) {
if (animInterval) {
clearInterval(animInterval);
animInterval = undefined;
}
if (timeInterval) {
clearInterval(timeInterval);
timeInterval = undefined;
}
if (on) {
showTime();
timeInterval = setInterval(showTime, 1000);
}
});
g.clear();
Bangle.loadWidgets();
Bangle.drawWidgets();
// Update time once a second
timeInterval = setInterval(showTime, 1000);
showTime();
// Show launcher when middle button pressed
setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"});

View File

@ -20,3 +20,4 @@
0.16: Reduce memory usage further when running app settings page
0.17: Remove need for "settings" in appid.info
0.18: Don't overwrite existing settings on app update
0.19: Allow BLE HID settings, add README.md

18
apps/setting/README.md Normal file
View File

@ -0,0 +1,18 @@
# Settings
This is Bangle.js's settings menu
* **Make Connectable** regardless of the current Bluetooth settings, makes Bangle.js so you can connect to it (while the window is up)
* **App/Widget Settings** settings specific to installed applications
* **BLE** is Bluetooth LE enabled and the watch connectable?
* **Programmable** if BLE is on, can the watch be connected to in order to program/upload apps?
* **Debug Info** should debug info be shown on the watch's screen or not?
* **Beep** most Bangle.js do not have a speaker inside, but they can use the vibration motor to beep in different pitches. You can change the behaviour here to use a Piezo speaker if one is connected
* **Vibration** enable/disable the vibration motor
* **Locale** set time zone/whether the clock is 12/24 hour (for supported clocks)
* **Select Clock** if you have more than one clock face, select the default one
* **HID** When Bluetooth is enabled, Bangle.js can appear as a Bluetooth Keyboard/Joystick/etc to send keypresses to a connected device. **Note:** on some platforms enabling HID can cause you problems when trying to connect to Bangle.js to upload apps.
* **Set Time** Configure the current time - Note that this can be done much more easily by choosing 'Set Time' from the App Loader
* **LCD** Configure settings about the screen. How long it stays on, how bright it is, and when it turns on.
* **Reset Settings** Reset the settings to defaults
* **Turn Off** Turn Bangle.js off

View File

@ -61,6 +61,8 @@ const boolFormat = v => v ? "On" : "Off";
function showMainMenu() {
var beepV = [false, true, "vib"];
var beepN = ["Off", "Piezo", "Vibrate"];
var hidV = [false, "kbmedia", "kb", "joy"];
var hidN = ["Off", "Kbrd & Media", "Kbrd","Joystick"];
const mainmenu = {
'': { 'title': 'Settings' },
'Make Connectable': ()=>makeConnectable(),
@ -115,10 +117,10 @@ function showMainMenu() {
'Locale': ()=>showLocaleMenu(),
'Select Clock': ()=>showClockMenu(),
'HID': {
value: settings.HID,
format: boolFormat,
onchange: () => {
settings.HID = !settings.HID;
value: 0 | hidV.indexOf(settings.HID),
format: v => hidN[v],
onchange: v => {
settings.HID = hidV[v];
updateSettings();
}
},