diff --git a/apps/presentor/app.js b/apps/presentor/app.js index e2b020a1c..819f1ebc2 100644 --- a/apps/presentor/app.js +++ b/apps/presentor/app.js @@ -2,73 +2,73 @@ // Version 2.2 const SpecialReport = new Uint8Array([ - 0x05, 0x01, // USAGE_PAGE (Generic Desktop) - 0x09, 0x02, // USAGE (Mouse) - 0xa1, 0x01, // COLLECTION (Application) - 0x85, 0x01, // REPORT_ID (1) - 0x09, 0x01, // USAGE (Pointer) - 0xa1, 0x00, // COLLECTION (Physical) - 0x05, 0x09, // USAGE_PAGE (Button) - 0x19, 0x01, // USAGE_MINIMUM (Button 1) - 0x29, 0x05, // USAGE_MAXIMUM (Button 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,Var,Abs) - 0x95, 0x01, // REPORT_COUNT (1) - 0x75, 0x03, // REPORT_SIZE (3) - 0x81, 0x03, // INPUT (Cnst,Var,Abs) - 0x05, 0x01, // USAGE_PAGE (Generic Desktop) - 0x09, 0x30, // USAGE (X) - 0x09, 0x31, // USAGE (Y) - 0x09, 0x38, // USAGE (Wheel) - 0x15, 0x81, // LOGICAL_MINIMUM (-127) - 0x25, 0x7f, // LOGICAL_MAXIMUM (127) - 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x03, // REPORT_COUNT (3) - 0x81, 0x06, // INPUT (Data,Var,Rel) - 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) - 0x0a, 0x38, 0x02, // USAGE (AC Pan) - 0x15, 0x81, // LOGICAL_MINIMUM (-127) - 0x25, 0x7f, // LOGICAL_MAXIMUM (127) - 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x01, // REPORT_COUNT (1) - 0x81, 0x06, // INPUT (Data,Var,Rel) - 0xc0, // END_COLLECTION - 0xc0, // END_COLLECTION - 0x05, 0x01, // USAGE_PAGE (Generic Desktop) - 0x09, 0x06, // USAGE (Keyboard) - 0xa1, 0x01, // COLLECTION (Application) - 0x85, 0x02, // REPORT_ID (2) - 0x05, 0x07, // USAGE_PAGE (Keyboard) - 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) - 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x25, 0x01, // LOGICAL_MAXIMUM (1) - 0x75, 0x01, // REPORT_SIZE (1) - 0x95, 0x08, // REPORT_COUNT (8) - 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x01, // REPORT_COUNT (1) - 0x81, 0x01, // INPUT (Cnst,Ary,Abs) - 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) - 0x29, 0x73, // USAGE_MAXIMUM (Keyboard F24) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x25, 0x73, // LOGICAL_MAXIMUM (115) - 0x95, 0x05, // REPORT_COUNT (5) - 0x75, 0x08, // REPORT_SIZE (8) - 0x81, 0x00, // INPUT (Data,Ary,Abs) - 0xc0 // END_COLLECTION + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x85, 0x01, // REPORT_ID (1) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x05, // USAGE_MAXIMUM (Button 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,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x09, 0x38, // USAGE (Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x03, // REPORT_COUNT (3) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) + 0x0a, 0x38, 0x02, // USAGE (AC Pan) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x85, 0x02, // REPORT_ID (2) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x01, // INPUT (Cnst,Ary,Abs) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x73, // USAGE_MAXIMUM (Keyboard F24) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x73, // LOGICAL_MAXIMUM (115) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION ]); const MouseButton = { - NONE : 0, - LEFT : 1, - RIGHT : 2, - MIDDLE : 4, - BACK : 8, - FORWARD: 16 +NONE : 0, +LEFT : 1, +RIGHT : 2, +MIDDLE : 4, +BACK : 8, +FORWARD: 16 }; const kb = require("ble_hid_keyboard"); @@ -76,130 +76,180 @@ const kb = require("ble_hid_keyboard"); const Layout = require("Layout"); const Locale = require("locale"); let mainLayout = new Layout( { - 'type': 'v', - filly: 1, - c: [ - { - type: 'txt', - font: '6x8', - label: 'Presentor', - valign: -1, - halign: 0, - col: g.theme.fg1, - // bgCol: g.theme.bg2, - bgCol: '#00F', - fillx: 1, - }, { - type: 'h', - fillx: 1, - c: [ - { - type: 'txt', - font: '15%', - label: '00:00', - id: 'Time', - halign: -1, - pad: 3 - }, { - fillx: 1 - }, { - type: 'txt', - font: '15%', - label: '00:00', - id: 'Timer', - halign: 1, - pad: 3 - } - ] - }, { - type: 'txt', - font: '10%', - label: '+00:00', - id: 'RestTime', - col: '#fff' - }, { - type: 'txt', - font: '10%', - label: '--------------' - }, { - type: 'txt', - font: '15%', - label: 'Subject', - id: 'Subject' - }, { - type: 'txt', - font: '6x8', - label: 'Notes...', - id: 'Notes', - col: '#ff0', - fillx: 1, - filly: 1, - valign: 1 - } - - ] +'type': 'v', +filly: 1, +c: [ + { + type: 'txt', + font: '6x8', + label: 'Presentor', + valign: -1, + halign: 0, + col: g.theme.fg1, + // bgCol: g.theme.bg2, + bgCol: '#00F', + fillx: 1, + }, { + type: 'h', + fillx: 1, + c: [ + { + type: 'txt', + font: '15%', + label: '00:00', + id: 'Time', + halign: -1, + pad: 3 + }, { + fillx: 1 + }, { + type: 'txt', + font: '15%', + label: '00:00', + id: 'Timer', + halign: 1, + pad: 3 + } + ] + }, { + type: 'txt', + font: '10%', + label: '+00:00', + id: 'RestTime', + col: '#fff' + }, { + type: 'txt', + font: '10%', + label: '--------------' + }, { + type: 'txt', + font: '15%', + label: 'Presenting', + id: 'Subject' + }, { + type: 'txt', + font: '6x8', + label: 'Swipe down to start the time.', + id: 'Notes', + col: '#ff0', + fillx: 1, + filly: 1, + valign: 1 + } + +] }, {lazy:true}); -let settings = require("Storage").readJSON('presentor.json'); +let settings = {pparts: [], sversion: 0}; let HIDenabled = false; // Application variables -let pparti = 0; +let pparti = -1; let lastx = 0; let lasty = 0; -let timeoutId = -1; + +// Mouse states let holding = false; +let trackPadMode = false; + +// Timeout IDs. +let timeoutId = -1; let timeoutHolding = -1; let timeoutDraw = -1; +let timeoutDrawTimer = -1; + let homeRoll = 0; let homePitch = 0; - -let trackPadMode = false; - let mCal = 0; - -let clearToSend = true; let mttl = 0; let cttl = 0; +// BT helper. +let clearToSend = true; + +// Presentation Timers +let ptimers = []; + +function loadSettings() { +settings = require("Storage").readJSON('presentor.json'); +for (let i = 0; i < settings.pparts.length; i++) { + ptimers[i] = { + active: false, + tracked: -1, + left: settings.pparts[i].minutes * 60 + settings.pparts[i].seconds + }; +} +} + +function getCurrentTimer() { +if (pparti < 0) return '00:00'; +if (!settings.pparts || pparti >= settings.pparts.length) return '00:00'; +if (ptimers[pparti].tracked == -1) return '00:00'; +ptimers[pparti].left -= (getTime() - ptimers[pparti].tracked); +ptimers[pparti].tracked = getTime(); +return `${Math.floor(ptimers[pparti].left/60)}:${Math.floor(ptimers[pparti].left%60)}`; +} + +function getRestTime() { +let rem = 0; +// Add all remaining time from previous presentation parts. +for (let i = 0; i < pparti; i++) { + rem += ptimers[i].left; +} +return `${rem >= 0 ? '+':'-'}${Math.floor(rem/60)}:${Math.floor(rem%60)}`; +} function drawMainFrame() { - var d = new Date(); - // update time - mainLayout.Time.label = Locale.time(d,1); - mainLayout.render(); - // schedule a draw for the next minute - if (timeoutDraw != -1) clearTimeout(timeoutDraw); - timeoutDraw = setTimeout(function() { - timeoutDraw = -1; - drawMainFrame(); - }, 60000 - (Date.now() % 60000)); +var d = new Date(); +// update time +mainLayout.Time.label = Locale.time(d,1); +// update timer +mainLayout.Timer.label = getCurrentTimer(); +mainLayout.RestTime.label = getRestTime(); +mainLayout.render(); +// schedule a draw for the next minute +if (timeoutDraw != -1) clearTimeout(timeoutDraw); +timeoutDraw = setTimeout(function() { + timeoutDraw = -1; + drawMainFrame(); +}, 1000 - (Date.now() % 1000)); } function drawMain() { - g.clear(); - mainLayout.forgetLazyState(); - drawMainFrame(); - // mainLayout.render(); - // E.showMessage('Presentor'); +g.clear(); +mainLayout.forgetLazyState(); +drawMainFrame(); +// mainLayout.render(); +// E.showMessage('Presentor'); +} + +function doPPart(r) { +pparti += r; +if (pparti < 0) return; +if (!settings.pparts || pparti >= settings.pparts.length) return; +let ppart = settings.pparts[pparti]; +mainLayout.Subject.label = ppart.subject; +mainLayout.Notes.label = ppart.notes; +ptimers[pparti].tracked = getTime(); +drawMainFrame(); } NRF.setServices(undefined, { hid : SpecialReport }); // TODO: figure out how to detect HID. NRF.on('HID', function() { - HIDenabled = true; +HIDenabled = true; }); function moveMouse(x,y,b,wheel,hwheel,callback) { - if (!HIDenabled) return; - if (!b) b = 0; - if (!wheel) wheel = 0; - if (!hwheel) hwheel = 0; - NRF.sendHIDReport([1,b,x,y,wheel,hwheel,0,0], function() { - if (callback) callback(); - }); +if (!HIDenabled) return; +if (!b) b = 0; +if (!wheel) wheel = 0; +if (!hwheel) hwheel = 0; +NRF.sendHIDReport([1,b,x,y,wheel,hwheel,0,0], function() { + if (callback) callback(); +}); } // function getSign(x) { @@ -207,161 +257,162 @@ function moveMouse(x,y,b,wheel,hwheel,callback) { // } function scroll(wheel,hwheel,callback) { - moveMouse(0,0,0,wheel,hwheel,callback); +moveMouse(0,0,0,wheel,hwheel,callback); } // Single click a certain button (immidiatly release). function clickMouse(b, callback) { - if (!HIDenabled) return; - NRF.sendHIDReport([1,b,0,0,0,0,0,0], function() { - NRF.sendHIDReport([1,0,0,0,0,0,0,0], function() { - if (callback) callback(); - }); +if (!HIDenabled) return; +NRF.sendHIDReport([1,b,0,0,0,0,0,0], function() { + NRF.sendHIDReport([1,0,0,0,0,0,0,0], function() { + if (callback) callback(); }); +}); } function pressKey(keyCode, modifiers, callback) { - if (!HIDenabled) return; - if (!modifiers) modifiers = 0; - NRF.sendHIDReport([2, modifiers,0,keyCode,0,0,0,0], function() { - NRF.sendHIDReport([2,0,0,0,0,0,0,0], function() { - if (callback) callback(); - }); +if (!HIDenabled) return; +if (!modifiers) modifiers = 0; +NRF.sendHIDReport([2, modifiers,0,keyCode,0,0,0,0], function() { + NRF.sendHIDReport([2,0,0,0,0,0,0,0], function() { + if (callback) callback(); }); +}); } function handleAcc(acc) { - let rRoll = acc.y * -50; - let rPitch = acc.x * -100; - if (mCal > 10) { - //console.log("x: " + (rRoll - homeRoll) + " y:" + (rPitch - homePitch)); - moveMouse(acc.y * -50 - homeRoll, acc.x * -100 - homePitch); - } else { - //console.log("homeroll: " +homeRoll +"homepitch: " + homePitch); - homeRoll = rRoll * 0.7 + homeRoll * 0.3; - homePitch = rPitch * 0.7 + homePitch * 0.3; - mCal = mCal + 1; - } +let rRoll = acc.y * -50; +let rPitch = acc.x * -100; +if (mCal > 10) { + //console.log("x: " + (rRoll - homeRoll) + " y:" + (rPitch - homePitch)); + moveMouse(acc.y * -50 - homeRoll, acc.x * -100 - homePitch); +} else { + //console.log("homeroll: " +homeRoll +"homepitch: " + homePitch); + homeRoll = rRoll * 0.7 + homeRoll * 0.3; + homePitch = rPitch * 0.7 + homePitch * 0.3; + mCal = mCal + 1; +} } Bangle.on('lock', function(on) { - if (on && holding) { - Bangle.setLocked(false); - Bangle.setLCDPower(1); - } +if (on && holding) { + Bangle.setLocked(false); + Bangle.setLCDPower(1); +} }); function startHolding() { - pressKey(kb.KEY.F10); - holding = true; - Bangle.buzz(); - E.showMessage('Holding'); - Bangle.on('accel', handleAcc); - Bangle.setLCDPower(1); +pressKey(kb.KEY.F10); +holding = true; +Bangle.buzz(); +E.showMessage('Holding'); +Bangle.on('accel', handleAcc); +Bangle.setLCDPower(1); } function stopHolding() { - clearTimeout(timeoutId); - if (holding) { - pressKey(kb.KEY.F10); - homePitch = 0; - homeRoll = 0; - holding = false; - mCal = 0; - Bangle.removeListener('accel', handleAcc); - Bangle.buzz(); - drawMain(); - } else { - timeoutId = setTimeout(drawMain, 1000); - } - clearTimeout(timeoutHolding); - timeoutHolding = -1; +clearTimeout(timeoutId); +if (holding) { + pressKey(kb.KEY.F10); + homePitch = 0; + homeRoll = 0; + holding = false; + mCal = 0; + Bangle.removeListener('accel', handleAcc); + Bangle.buzz(); + drawMain(); +} else { + timeoutId = setTimeout(drawMain, 1000); +} +clearTimeout(timeoutHolding); +timeoutHolding = -1; } Bangle.on('drag', function(e) { - if (cttl == 0) { cttl = getTime(); } - if (trackPadMode) { - if (lastx + lasty == 0) { - lastx = e.x; - lasty = e.y; - mttl = getTime(); +if (cttl == 0) { cttl = getTime(); } +if (trackPadMode) { + if (lastx + lasty == 0) { + lastx = e.x; + lasty = e.y; + mttl = getTime(); + } + if (clearToSend) { + clearToSend = false; + let difX = e.x - lastx, difY = e.y - lasty; + let dT = getTime() - mttl; + let vX = difX / dT, vY = difY / dT; + //let qX = getSign(difX) * Math.pow(Math.abs(difX), 1.2); + //let qY = getSign(difY) * Math.pow(Math.abs(difY), 1.2); + let qX = difX + 0.02 * vX, qY = difY + 0.02 * vY; + moveMouse(qX, qY, 0, 0, 0, function() { + setTimeout(function() {clearToSend = true;}, 50); + }); + lastx = e.x; + lasty = e.y; + mttl = getTime(); + console.log("Dx: " + (qX) + " Dy: " + (qY)); + } + if (!e.b) { + // short press + if (getTime() - cttl < 0.2) { + clickMouse(MouseButton.LEFT); + console.log("click left"); } - if (clearToSend) { - clearToSend = false; - let difX = e.x - lastx, difY = e.y - lasty; - let dT = getTime() - mttl; - let vX = difX / dT, vY = difY / dT; - //let qX = getSign(difX) * Math.pow(Math.abs(difX), 1.2); - //let qY = getSign(difY) * Math.pow(Math.abs(difY), 1.2); - let qX = difX + 0.02 * vX, qY = difY + 0.02 * vY; - moveMouse(qX, qY, 0, 0, 0, function() { - setTimeout(function() {clearToSend = true;}, 50); - }); - lastx = e.x; - lasty = e.y; - mttl = getTime(); - console.log("Dx: " + (qX) + " Dy: " + (qY)); + // longer press in center + else if (getTime() - cttl < 0.6 && e.x > g.getWidth()/4 && e.x < 3 * g.getWidth()/4 && e.y > g.getHeight() / 4 && e.y < 3 * g.getHeight() / 4) { + clickMouse(MouseButton.RIGHT); + console.log("click right"); } - if (!e.b) { - // short press - if (getTime() - cttl < 0.2) { - clickMouse(MouseButton.LEFT); - console.log("click left"); - } - // longer press in center - else if (getTime() - cttl < 0.6 && e.x > g.getWidth()/4 && e.x < 3 * g.getWidth()/4 && e.y > g.getHeight() / 4 && e.y < 3 * g.getHeight() / 4) { - clickMouse(MouseButton.RIGHT); - console.log("click right"); - } - cttl = 0; - lastx = 0; - lasty = 0; + cttl = 0; + lastx = 0; + lasty = 0; + } +} else { + if(!e.b){ + Bangle.buzz(100); + if(lasty > 40){ + doPPart(1); + E.showMessage('down'); + } else if(lasty < -40){ + doPPart(-1); + E.showMessage('up'); + } else if(lastx > 40){ + E.showMessage('right'); + //kb.tap(kb.KEY.RIGHT, 0); + scroll(-1); + } else if(lastx < -40){ + E.showMessage('left'); + //kb.tap(kb.KEY.LEFT, 0); + scroll(1); + } else if(lastx==0 && lasty==0 && holding == false){ + E.showMessage('press'); + clickMouse(MouseButton.LEFT); } - } else { - if(!e.b){ - Bangle.buzz(100); - if(lasty > 40){ - E.showMessage('down'); - scroll(0,1); - } else if(lasty < -40){ - E.showMessage(kb.KEY.A); - pressKey(kb.KEY.A); - } else if(lastx > 40){ - E.showMessage('right'); - //kb.tap(kb.KEY.RIGHT, 0); - scroll(-1); - } else if(lastx < -40){ - E.showMessage('left'); - //kb.tap(kb.KEY.LEFT, 0); - scroll(1); - } else if(lastx==0 && lasty==0 && holding == false){ - E.showMessage('press'); - clickMouse(MouseButton.LEFT); - } - stopHolding(); - lastx = 0; - lasty = 0; - } else{ - lastx = lastx + e.dx; - lasty = lasty + e.dy; - if (timeoutHolding == -1) { - timeoutHolding = setTimeout(startHolding, 500); - } + stopHolding(); + lastx = 0; + lasty = 0; + } else{ + lastx = lastx + e.dx; + lasty = lasty + e.dy; + if (timeoutHolding == -1) { + timeoutHolding = setTimeout(startHolding, 500); } } +} }); function onBtn() { - if (trackPadMode) { - trackPadMode = false; - stopHolding(); - drawMain(); - } else { - clearToSend = true; - trackPadMode = true; - E.showMessage('Mouse'); - } - Bangle.buzz(); +if (trackPadMode) { + trackPadMode = false; + stopHolding(); + drawMain(); +} else { + clearToSend = true; + trackPadMode = true; + E.showMessage('Mouse'); +} +Bangle.buzz(); } setWatch(onBtn, (process.env.HWVERSION==2) ? BTN1 : BTN2, {repeat: true}); -drawMain(); +loadSettings(); +drawMain(); \ No newline at end of file