mirror of https://github.com/espruino/BangleApps
Added BLE HID option for Joystick and bare Keyboard, update HID apps to send correct info
parent
23c5ea3829
commit
517c35a37d
13
apps.json
13
apps.json
|
@ -2,7 +2,7 @@
|
||||||
{ "id": "boot",
|
{ "id": "boot",
|
||||||
"name": "Bootloader",
|
"name": "Bootloader",
|
||||||
"icon": "bootloader.png",
|
"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",
|
"description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings",
|
||||||
"tags": "tool,system",
|
"tags": "tool,system",
|
||||||
"type":"bootloader",
|
"type":"bootloader",
|
||||||
|
@ -122,9 +122,10 @@
|
||||||
{ "id": "setting",
|
{ "id": "setting",
|
||||||
"name": "Settings",
|
"name": "Settings",
|
||||||
"icon": "settings.png",
|
"icon": "settings.png",
|
||||||
"version":"0.18",
|
"version":"0.19",
|
||||||
"description": "A menu for setting up Bangle.js",
|
"description": "A menu for setting up Bangle.js",
|
||||||
"tags": "tool,system",
|
"tags": "tool,system",
|
||||||
|
"readme": "README.md",
|
||||||
"storage": [
|
"storage": [
|
||||||
{"name":"setting.app.js","url":"settings.js"},
|
{"name":"setting.app.js","url":"settings.js"},
|
||||||
{"name":"setting.boot.js","url":"boot.js"},
|
{"name":"setting.boot.js","url":"boot.js"},
|
||||||
|
@ -480,7 +481,7 @@
|
||||||
"name": "Bluetooth Music Controls",
|
"name": "Bluetooth Music Controls",
|
||||||
"shortName": "Music Control",
|
"shortName": "Music Control",
|
||||||
"icon": "hid-music.png",
|
"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!",
|
"description": "Enable HID in settings, pair with your phone, then use this app to control music from your watch!",
|
||||||
"tags": "bluetooth",
|
"tags": "bluetooth",
|
||||||
"storage": [
|
"storage": [
|
||||||
|
@ -492,7 +493,7 @@
|
||||||
"name": "Bluetooth Keyboard",
|
"name": "Bluetooth Keyboard",
|
||||||
"shortName": "Bluetooth Kbd",
|
"shortName": "Bluetooth Kbd",
|
||||||
"icon": "hid-keyboard.png",
|
"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",
|
"description": "Enable HID in settings, pair with your phone/PC, then use this app to control other apps",
|
||||||
"tags": "bluetooth",
|
"tags": "bluetooth",
|
||||||
"storage": [
|
"storage": [
|
||||||
|
@ -504,7 +505,7 @@
|
||||||
"name": "Binary Bluetooth Keyboard",
|
"name": "Binary Bluetooth Keyboard",
|
||||||
"shortName": "Binary BT Kbd",
|
"shortName": "Binary BT Kbd",
|
||||||
"icon": "hid-binary-keyboard.png",
|
"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",
|
"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",
|
"tags": "bluetooth",
|
||||||
"storage": [
|
"storage": [
|
||||||
|
@ -1437,7 +1438,7 @@
|
||||||
"name": "Camera shutter",
|
"name": "Camera shutter",
|
||||||
"shortName":"Cam shutter",
|
"shortName":"Cam shutter",
|
||||||
"icon": "app.png",
|
"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",
|
"description": "Enable HID, connect to your phone, start your camera and trigger the shot on your Bangle",
|
||||||
"tags": "tools",
|
"tags": "tools",
|
||||||
"storage": [
|
"storage": [
|
||||||
|
|
|
@ -13,3 +13,4 @@
|
||||||
0.13: Now automatically load *.boot.js at startup
|
0.13: Now automatically load *.boot.js at startup
|
||||||
Move alarm code into alarm.boot.js
|
Move alarm code into alarm.boot.js
|
||||||
0.14: Move welcome loaders to *.boot.js
|
0.14: Move welcome loaders to *.boot.js
|
||||||
|
0.15: Added BLE HID option for Joystick and bare Keyboard
|
||||||
|
|
|
@ -4,7 +4,9 @@ E.setFlags({pretokenise:1});
|
||||||
var s = require('Storage').readJSON('setting.json',1)||{};
|
var s = require('Storage').readJSON('setting.json',1)||{};
|
||||||
if (s.ble!==false) {
|
if (s.ble!==false) {
|
||||||
if (s.HID) { // Human interface device
|
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});
|
NRF.setServices({}, {uart:true, hid:Bangle.HID});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
```
|
|
@ -0,0 +1,2 @@
|
||||||
|
0.01: Core functionnality
|
||||||
|
0.02: Offer to enable HID if disabled. Handle with/without media keys
|
|
@ -45,13 +45,7 @@ const KEY = {
|
||||||
0 : 39
|
0 : 39
|
||||||
};
|
};
|
||||||
|
|
||||||
function sendHID(code) {
|
var sendHID;
|
||||||
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);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
function showChars(x,chars) {
|
function showChars(x,chars) {
|
||||||
var lines = Math.round(Math.sqrt(chars.length)*2);
|
var lines = Math.round(Math.sqrt(chars.length)*2);
|
||||||
|
@ -103,10 +97,24 @@ function startKeyboardHID() {
|
||||||
}).then(startKeyboardHID);
|
}).then(startKeyboardHID);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!settings.HID) {
|
if (settings.HID=="kb" || settings.HID=="kbmedia") {
|
||||||
E.showMessage('HID disabled');
|
if (settings.HID=="kbmedia") {
|
||||||
setTimeout(load, 1000);
|
sendHID = function(code) {
|
||||||
} else {
|
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();
|
startKeyboardHID();
|
||||||
setWatch(() => {
|
setWatch(() => {
|
||||||
sendHID(44); // space
|
sendHID(44); // space
|
||||||
|
@ -114,4 +122,12 @@ if (!settings.HID) {
|
||||||
setWatch(() => {
|
setWatch(() => {
|
||||||
sendHID(40); // enter
|
sendHID(40); // enter
|
||||||
}, BTN3, {repeat:true});
|
}, 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);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
0.01: Core functionnality
|
0.01: Core functionnality
|
||||||
|
0.02: Offer to enable HID if disabled
|
||||||
|
|
|
@ -4,7 +4,7 @@ const settings = storage.readJSON('setting.json',1) || { HID: false };
|
||||||
|
|
||||||
var sendHid, camShot, profile;
|
var sendHid, camShot, profile;
|
||||||
|
|
||||||
if (settings.HID) {
|
if (settings.HID=="kbmedia") {
|
||||||
profile = 'camShutter';
|
profile = 'camShutter';
|
||||||
sendHid = function (code, cb) {
|
sendHid = function (code, cb) {
|
||||||
try {
|
try {
|
||||||
|
@ -19,8 +19,13 @@ if (settings.HID) {
|
||||||
};
|
};
|
||||||
camShot = function (cb) { sendHid(0x80, cb); };
|
camShot = function (cb) { sendHid(0x80, cb); };
|
||||||
} else {
|
} else {
|
||||||
E.showMessage('HID disabled');
|
E.showPrompt("Enable HID?",{title:"HID disabled"}).then(function(enable) {
|
||||||
setTimeout(load, 1000);
|
if (enable) {
|
||||||
|
settings.HID = "kbmedia";
|
||||||
|
require("Storage").write('setting.json', settings);
|
||||||
|
setTimeout(load, 1000, "hidcam.app.js");
|
||||||
|
} else setTimeout(load, 1000);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
function drawApp() {
|
function drawApp() {
|
||||||
g.clear();
|
g.clear();
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
0.01: Core functionnality
|
||||||
|
0.02: Offer to enable HID if disabled. Handle with/without media keys
|
|
@ -4,27 +4,46 @@ const settings = storage.readJSON('setting.json',1) || { HID: false };
|
||||||
|
|
||||||
var sendHid, next, prev, toggle, up, down, profile;
|
var sendHid, next, prev, toggle, up, down, profile;
|
||||||
|
|
||||||
if (settings.HID) {
|
if (settings.HID=="kb" || settings.HID=="kbmedia") {
|
||||||
profile = 'Keyboard';
|
profile = 'Keyboard';
|
||||||
sendHid = function (code, cb) {
|
if (settings.HID=="kbmedia") {
|
||||||
try {
|
sendHid = function (code, cb) {
|
||||||
NRF.sendHIDReport([2,0,0,code,0,0,0,0,0], () => {
|
try {
|
||||||
NRF.sendHIDReport([2,0,0,0,0,0,0,0,0], () => {
|
NRF.sendHIDReport([2,0,0,code,0,0,0,0,0], () => {
|
||||||
if (cb) cb();
|
NRF.sendHIDReport([2,0,0,0,0,0,0,0,0], () => {
|
||||||
|
if (cb) cb();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
} catch(e) {
|
||||||
} catch(e) {
|
print(e);
|
||||||
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); };
|
next = function (cb) { sendHid(0x4f, cb); };
|
||||||
prev = function (cb) { sendHid(0x50, cb); };
|
prev = function (cb) { sendHid(0x50, cb); };
|
||||||
toggle = function (cb) { sendHid(0x2c, cb); };
|
toggle = function (cb) { sendHid(0x2c, cb); };
|
||||||
up = function (cb) {sendHid(0x52, cb); };
|
up = function (cb) {sendHid(0x52, cb); };
|
||||||
down = function (cb) { sendHid(0x51, cb); };
|
down = function (cb) { sendHid(0x51, cb); };
|
||||||
} else {
|
} else {
|
||||||
E.showMessage('HID disabled');
|
E.showPrompt("Enable HID?",{title:"HID disabled"}).then(function(enable) {
|
||||||
setTimeout(load, 1000);
|
if (enable) {
|
||||||
|
settings.HID = "kb";
|
||||||
|
require("Storage").write('setting.json', settings);
|
||||||
|
setTimeout(load, 1000, "hidkbd.app.js");
|
||||||
|
} else setTimeout(load, 1000);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawApp() {
|
function drawApp() {
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
0.01: Core functionnality
|
|
@ -4,7 +4,7 @@ const settings = storage.readJSON('setting.json',1) || { HID: false };
|
||||||
|
|
||||||
var sendHid, next, prev, toggle, up, down, profile;
|
var sendHid, next, prev, toggle, up, down, profile;
|
||||||
|
|
||||||
if (settings.HID) {
|
if (settings.HID=="kbmedia") {
|
||||||
profile = 'Music';
|
profile = 'Music';
|
||||||
sendHid = function (code, cb) {
|
sendHid = function (code, cb) {
|
||||||
try {
|
try {
|
||||||
|
@ -23,8 +23,13 @@ if (settings.HID) {
|
||||||
up = function (cb) {sendHid(0x40, cb); };
|
up = function (cb) {sendHid(0x40, cb); };
|
||||||
down = function (cb) { sendHid(0x80, cb); };
|
down = function (cb) { sendHid(0x80, cb); };
|
||||||
} else {
|
} else {
|
||||||
E.showMessage('HID disabled');
|
E.showPrompt("Enable HID?",{title:"HID disabled"}).then(function(enable) {
|
||||||
setTimeout(load, 1000);
|
if (enable) {
|
||||||
|
settings.HID = "kbmedia";
|
||||||
|
require("Storage").write('setting.json', settings);
|
||||||
|
setTimeout(load, 1000, "hidmsc.app.js");
|
||||||
|
} else setTimeout(load, 1000);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawApp() {
|
function drawApp() {
|
||||||
|
|
|
@ -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"});
|
|
@ -20,3 +20,4 @@
|
||||||
0.16: Reduce memory usage further when running app settings page
|
0.16: Reduce memory usage further when running app settings page
|
||||||
0.17: Remove need for "settings" in appid.info
|
0.17: Remove need for "settings" in appid.info
|
||||||
0.18: Don't overwrite existing settings on app update
|
0.18: Don't overwrite existing settings on app update
|
||||||
|
0.19: Allow BLE HID settings, add README.md
|
||||||
|
|
|
@ -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
|
|
@ -61,6 +61,8 @@ const boolFormat = v => v ? "On" : "Off";
|
||||||
function showMainMenu() {
|
function showMainMenu() {
|
||||||
var beepV = [false, true, "vib"];
|
var beepV = [false, true, "vib"];
|
||||||
var beepN = ["Off", "Piezo", "Vibrate"];
|
var beepN = ["Off", "Piezo", "Vibrate"];
|
||||||
|
var hidV = [false, "kbmedia", "kb", "joy"];
|
||||||
|
var hidN = ["Off", "Kbrd & Media", "Kbrd","Joystick"];
|
||||||
const mainmenu = {
|
const mainmenu = {
|
||||||
'': { 'title': 'Settings' },
|
'': { 'title': 'Settings' },
|
||||||
'Make Connectable': ()=>makeConnectable(),
|
'Make Connectable': ()=>makeConnectable(),
|
||||||
|
@ -115,10 +117,10 @@ function showMainMenu() {
|
||||||
'Locale': ()=>showLocaleMenu(),
|
'Locale': ()=>showLocaleMenu(),
|
||||||
'Select Clock': ()=>showClockMenu(),
|
'Select Clock': ()=>showClockMenu(),
|
||||||
'HID': {
|
'HID': {
|
||||||
value: settings.HID,
|
value: 0 | hidV.indexOf(settings.HID),
|
||||||
format: boolFormat,
|
format: v => hidN[v],
|
||||||
onchange: () => {
|
onchange: v => {
|
||||||
settings.HID = !settings.HID;
|
settings.HID = hidV[v];
|
||||||
updateSettings();
|
updateSettings();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue