• Among others, the conversation about 2 questions regarding Button and touch event stirred me to take yet another - 3rd - stab at that subject of a Bangle Touch Controller. The first one was in the Bangle emulator when a Bangle was not yet available to me.

    First and second failed because the nested condition checking and tracking of state became unbearable: lots of code, slow, and still a lot of unresolved (corner) cases, brittle and of limited functions.

    This 3rd time, I use a state machine with direct addressed / called functions for the state and transitions. It consists of 2 implementations:

    • Simple controller that provides event times and callbacks, but is only touch driven
    • Enhanced controller that provides additional - time driven - callbacks.

    In this conversations it's about the simple controller. Main design goal was to enable easy exchange of the application callbacks to reuse the one-time setup of the controller. Therefore, the callbacks are passed as object properties in an object. The property names map to the events, states and transitions of he state machine of the controller and are called Touch Signatures. They can have these values:

    1. 2.  ```r``` - right button touched and is touching as the only one, marking the start of a touch sequence
      2. ```L``` - left button untouched as the only button that was touched,  completing a left touch
      2.  ```r``` - right button untouched as the only button that was touched,  completing a right touch
      3.  ```b``` - second button touch down and both buttons are touched, initiating a both touch
      4. ```p``` - the first of two buttons of a both touch untouched, initiating the end of a both touch
      5. ```B```  - the second of two buttons  of a both touch untouched, completing a both touch
      6. ```e``` - error sequence - for example - retouching of first untouched button of a both touch 
      7. ```E``` - recovery from an error sequence - usually achieved with untouching both buttons
      
      Each callback is called with four (4) arguments:
      
      1. ```ts``` - touch signature (l, r, L, R, b, p, B, e, E)
      2. ```tt``` - touch start time in secs  - from getTime() when first touch of touch sequence happened.
      3. ```te``` - touch elapsed time in secs - can be used to determine short, medium, and long touches
      4. ```ctl``` - the touch controller object to provide access to additional information, such as state and detailed timings of the both button touches. Latter allow to determine which of the buttons was touched or untouched first and at what time relative to the touch begin (and corollary, within the elapsed time). ***Foremost*** though it is for expedient change of the callbacks object to enter in a new conversation context of the application without complicated state management.
      
      For additional information see the inline comments in the constructor.
      
      Running the controller usage example - code in next post running connected on BantleJS -produces  this output in the Espruno IDE console:
      
      

    Right touch for 0.17495727539 [sec] Left touch for 0.11331176757 [sec] at 1607677068.38404655456 Right touch for 0.83169555664 [sec] Left touch for 1.75540161132 [sec] at 1607677075.57887077331 B Both w/ details abt 2nd btn touch and 1st btn untouch at 0:58:0 for 1.31875610351 2nd touch after 1st t 0.02020263671 1st untouch aft 1st t 1.31472778320 2nd untouch aft 1st u 0.00402832031 2nd untouch aft 1st t 1.31875610351 =elapsed ign: bRr r 0 err e 3 ign: ebRrR R 3 err e 2 ign: e..Rr r 2 err e 2 ign: e..rR R 2 err e 3 ign: e..Rr r 3 err e 3 ign: e..rL L 3 err e 1 ign: e..LR R 1 err E 0

    
    - Lines 2..5 show single button touches of left and right touch button with different touch times.
    - Lines 6..12 show details about a both button touch
    - Lines 13..26 show re-occurring error cycle that started with touching again the 1st untouched button of a both button touch. Line 13 show as in the second item on the line state (```bR```) and transition (```r```) as concatenated (```bRr```) - (temp) ```.s``` property of the controller.  State ```bR``` means that a *both button touch* had begun and a *right button rouch* had started to wind it down, when 'all of a sudden' the right button is touched again. The dispatcher could not find a *state and transition* method/function and has directed it to the ```.ign()``` *error* method/function. The output producing  statement (  ```console.log("ign: ",_.s,e,_.sb);``` - between code lines 56 and 57 has since been removed. It produced all odd lines with error output ```ign:...```. Th even lines in between are the output from the ```e``` and ```E``` callback.
    
    The third - numeric - item in the ```.ign()```error message shows the buttons still touched in binary coding: left button bit 1 with value 2, and right button with value 1. As soon as this value goes to 0 the error is resolved and uppercase ```E``` touch signature shows and status is set to start (```"s"```). Lowercase l and r - touch events - set the bits, uperase L and R - untouch events - clear the bits... as simple as that - controller state binary (line 59): 
    
    

    .sb=(.sb^("RL".indexOf(e)+1))||("rl".indexOf(­e)+1)```

    A suitable application of the Simple Bangle Touch Controller will be a BangleJS Soft Keyboard as outlined in post #14 of above mentioned conversation about touch buttons and events, but without the issues of the (integrated) touch controller implementation. It will be presented in a separate conversation.

  • Here the code - about to be a module -with usage example:

    // SBTouchCtrl.js
    // 2020v1210_ao by allObjects
    // Simple Bangle Touch Controller (module to be)
    // Easy to use bangle touch controler by allObjects.
    // Provides events for left, right, and both touch
    // lifecycle w/ timings incl. on error and recovery. 
    /*
    
    ` ` `
    var l = function() { console.log.apply(console,arguments); };
      , sbtcMod = require("SBTouchCtrl");
      , sbtc; // instance of simple bangle touch controler
    function onInit() {
    sbtc = new SBTouchCtrl(
      // provide callback obj w/ named cbs for some events
      { L:(ts,tt,et)=>l("Left touch for",et,"[sec] at",tt)
      , E:()=>console.log("Error - recovered")
      }).watch(); // activate button touch button watching
      g.clear();
    } setTimeout(onInit,999);
    ` ` `
    
    */
    var SBTouchCtrl=function(cbs) { var _=0||this;
      _.cbs=cbs||{}; // obj w/ callbacks named after touchSignature
        // l: left touch down (touchSign,touchTime,elapsedTime,sbtctl)­
        // r: right touch down
        // b: 2nd both touch down
        // p: 1st untouch of both touch
        // e: error in sequncing (no recovery other than untouch all
        // L: untouch of left button and completion of left touch
        // R: untouch of right button and completion of right touch
        // B: untouch of both buttons and completion of both touch
        // E: end of error sequencing - all untouched - ready to cont
      _.tt=0;  // touch time
      _.bt=0;  // both touch time(+/-=L/R)
      _.pt=0;  // both untouch time(+/-=L/R)
      _.ut=0;  // untouch time
      _.et=0;  // elapsed time
      _.st=0;  // signature time
      _.ts=""; // touch signature
      _.sb=0;  // status bits (for error resolution)
      _.s="s"; // status, s (start)
      _.wl=_.wr=_.wL=_.wR=null; // touch button watchers
    } , p=SBTouchCtrl.prototype;
    p.sl=(_,t,e)=>{_.ts=_.s=e;_.tt=t;return _.cbs[e];};
    p.sr=(_,t,e)=>{_.ts=_.s=e;_.tt=t;return _.cbs[e];};
    p.lL=(_,t,e)=>{_.ts=e;_.s="s";_.et=(_.ut­=t)-_.tt;return _.cbs[e];};
    p.rR=(_,t,e)=>{_.ts=e;_.s="s";_.et=(_.ut­=t)-_.tt;return _.cbs[e];};
    p.lr=(_,t,e)=>{_.ts=_.s="b";_.bt=t-_.tt;­ return _.cbs.b;};
    p.rl=(_,t,e)=>{_.ts=_.s="b";_.bt=_.tt-t;­ return _.cbs.b;};
    p.bL=(_,t,e)=>{_.ts="p";_.pt=t-_.tt; return _.cbs.p;};
    p.bR=(_,t,e)=>{_.ts="p";_.pt=_.tt-t; return _.cbs.p;};
    p.bLR=(_,t,e)=>{_.ts="B";_.s="s";_.et=(_­.ut=t)-_.tt;return _.cbs.B;};
    p.bRL=(_,t,e)=>{_.ts="B";_.s="s";_.et=(_­.ut=t)-_.tt;return _.cbs.B;};
    p.ign=(_,t,e,c,b)=>{ // p - s ignore from 1st err: evt already in _.s
      if ((c=((s=_.s).charAt(0)))=="b") { // 1st time here switch to e(rr)
        _.sb=3; _.ts=c="e"; _.s=c+s; } else {
        if ((_.sb=(_.sb^("RL".indexOf(e)+1))||("rl"­.indexOf(e)+1))) {
          _.ts="e"; _.s="e.."+e; } else { _.ts="E"; _.s="s"; } }
      return _.cbs[c]; };
    p.ns=(_,e,b,f,t,cb)=>{ // dispatcher to state transitioners
      if ((cb=((f=_[_.s+=e])?f:_.ign).apply(_,[_,­_.st=t=getTime(),e,b]))
      )cb(_.ts,t,_.et,_);}; // touchSignCharlrbpeLRBE,time,elapsed,BTou­ch
    p.el=function(){this.ns(this,"l");}; // l touch event handler
    p.er=function(){this.ns(this,"r");}; // r ...
    p.eL=function(){this.ns(this,"L");}; // L untouch event handler
    p.eR=function(){this.ns(this,"R");}; // R ..
    p.watch=function(){var _=0||this,o;_.unwatch();// set watch on t btns
      _.wl=setWatch(_.el.bind(_),BTN4,o={repea­t:true,edge:"rising"});
      _.wr=setWatch(_.er.bind(_),BTN5,o);
      _.wL=setWatch(_.eL.bind(_),BTN4,o={repea­t:true,edge:"falling"});
      _.wR=setWatch(_.eR.bind(_),BTN5,o);
      return _; };
    p.unwatch=function() { var _=0||this,o; // clear watches touch btns
      if(_.wl)_.wl=clearWatch(_.wl); if(_.wr)_.wr=clearWatch(_.wr);
      if(_.wL)_.wL=clearWatch(_.Wr); if(_.wR)_.wR=clearWatch(_.wR);
      return _; };
    // exports=SBTouchCtrl; // ---------- end of SBTouchCtrl module
    
    
    // slim logging function
    var l = function(){console.log.apply(console,arg­uments); };
    
    // var SBTouchCtrl = require("SBTouchCtrl");
    var sbtc; // instance of simple bangle touch controler
    
    function onInit() {
    sbtc = new SBTouchCtrl(
      // provide callback obj w/ named cbs for some events
      { L:(ts,tt,et)=>l("Left touch for",et,"[sec] at",tt)
      , R:(ts,tt,et)=>l("Right touch for",et,"[sec]")
      , B:(ts,tt,et,ctl)=>{ var d=new Date(tt*1000); l(ts // touch sign
          ,"Both w/ details abt 2nd btn touch and 1st btn untouch"
          ,"\nat" ,d.getHours()+":"+d.getMinutes()+":"+d.g­etSeconds()
          ,"\nfor",et // elapsed in [s] from 1st touch to last untouch
          ,"\n2nd touch after 1st t",ctl.bt // +/- R/L[s] touched appart
          ,"\n1st untouch aft 1st t",ctl.pt // +/- R/L[s] before elapsed
          ,"\n2nd untouch aft 1st u",et-ctl.pt // +/- R/L[s]unt'd appart
          ,"\n2nd untouch aft 1st t",et,"=elapsed");} // +/- R/L[s]unt'd
      , e:(ts,tt,et,ctl)=>console.log("err",ts,c­tl.sb)
      , E:()=>console.log("Error - recovered")
      }).watch(); // activate button touch button watching
      g.clear();
    }
    
    setTimeout(onInit,999);
    
  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Simple Bangle Touch Controller for Left, Right and Both touches with timings and more...

Posted by Avatar for allObjects @allObjects

Actions