Source file: /~heha/ewa/Ofen/Kamera.zip/input.cpp

#include <Arduino.h>
#include "input.h"

bool isTerm;

// String mit max. <bufsize-1> Zeichen auf serieller Konsole (Arduino, putty) eingeben
// Mit Kursorsteuerfunktion, ohne History, ohne Startmarkierung
// In einem Dialog müsste man mit ESC, TAB und evtl. vertikalen Kursortasten rauskommen
// Die Arduino-GUI 2.0.1 kommt NUR mit Startmarkierung zurecht und untestützt keine Farben.
// (vergebliche Liebesmüh, Zeileneditorfunktion nur bei Control-Zeichen, Löschen nicht möglich)
int input(const char*prompt,char*buf,int bufsize) {
 auto backspace=[](int n=1) {if (n) do Serial.print('\b'); while (--n);};
 auto ding=[]() {return Serial.print('\a'),false;};  // Simple Lambdafunktion
 auto strcount=[](const char*s,const char*e) {  // Zählt "ganze" UTF8-Zeichen
  int i=0;
  while (s!=e) if (byte(*s++&0xC0)!=0x80) i++;  // Non-Trailbytes zählen
  return i;
 };
 auto hilite=[]() {if (isTerm) Serial.print("\e[1;37;44m");};
 auto unmark=[]() {if (isTerm) Serial.print("\e[m");};
 Serial.print(prompt);
 Serial.print(": ");
 int l=strlen(buf), i;  // i wird auf UTF8-Sequenzgrenzen gehalten
 auto goLeft=[&]() {
  if (!i) return ding();
  backspace();
  while (byte(buf[--i]&0xC0)==0x80 && i);  // UTF8-Trailbytes übergehen
  return true;
 };
 auto goRight=[&]() {
  if (i==l) return ding();
  Serial.print(buf[i++]);
  while (byte(buf[i]&0xC0)==0x80 && i<l) Serial.print(buf[i++]);  // UTF8-Trailbytes ausgeben
  return true;
 };
 auto delChar=[&]() {
	if (i==l) return ding();  // Cursor hinter letztem Zeichen geht nicht
  int j=i;
  while (++j!=l && byte(buf[j]&0xC0)==0x80);
  memmove(buf+i,buf+j,l-j+1);  // Zeichen bei Index löschen
  l-=j-i;      // String kürzen
  Serial.print(buf+i); // String-Rest ausgeben (kann leer sein)
  unmark();
  Serial.print(' '); // Leerzeichen zum Zeichen löschen dahinter, uninvertiert
  backspace(strcount(buf+i,buf+l)+1);  // Kursor repositionieren
  hilite();
  return true;
 };
 if (l>bufsize-1) l=bufsize-1;  // Platz für '\0' behalten
 buf[i=l]=0;    // ggf. abhacken
 hilite();
 Serial.print(buf); // Vorgabe ausspucken, Kursor dahinter platzieren
// Mal schnell einen Zeileneditor gebastelt:
 int arg=-1;  // Numerisches Escape-Argument (nur eins)
 for(;;) {
  int c=Serial.read();
  if (c<0) continue;
  if (arg>=0) { // Escape-Modus?
   if ('0'<=c && c<='9') {arg=arg*10+c-'0'; continue;} // Ziffern zu Dezimalzahl zusammensetzen
   switch (c) {
    case '[':
    case 'O': continue;
// Kursortasten zum Editieren auswerten
// (Mit Shift markieren sowie Copy&Paste ist nicht möglich.)
    case 'C': c='F'-'@'; break;  // Pfeil rechts
    case 'D': c='B'-'@'; break;  // Pfeil links
    case 'K':
    case 'F': c='E'-'@'; break;  // Ende
    case 'H': c='A'-'@'; break;  // Pos1
    case '~': switch (arg) {
     case 1: c='A'-'@'; break;  // Pos1 (PuTTY)
     case 3: delChar(); c=-1; break; // Entf
     case 4: c='E'-'@'; break;  // Ende (PuTTY)
     default: c='\a';
    }break;
    default: c='\a';
   }
   arg=-1; // Ende Escape-Seqenz
  }
  if (arg<0 && c>=0) switch (c) {
   case 'A'-'@': backspace(strcount(buf,buf+i)); i=0; break;  // Pos1
   case 'B'-'@': goLeft(); break;
   case 'C'-'@': goto raus;     // Abbruch mit ^C
   case 'E'-'@': Serial.print(buf+i); i=l; break;  // Ende
   case 'F'-'@': goRight(); break;
   case '\a': ding(); break;  // Bimmel als -Echo
   case '\b':
   case 127: if (goLeft()) delChar(); break;
   case '\v':
   case '\t': ding(); break;  // TAB verwerfen
   case '\r': // Enter-Taste (mal so, mal so)
   case '\n': arg=l; goto raus; // Stringlänge reporten
   case 'U'-'@': {   // String von vorn anfangen
    backspace(strcount(buf,buf+i)); i=l;
    unmark();
    if (i) do Serial.print(' '); while(--i);  // Dargestellte Zeichen löschen
    backspace(l);
    hilite();
    buf[l=0]=0;
   }break;
   case '\e': arg=0; break;
// TODO: Akzentuierte Buchstaben bei Kursorpositionierung beachten
   default: // Buchstaben oder UTF-8-Bruchstücke
   if (l<bufsize-2) {
    memmove(buf+i+1,buf+i,++l-i);  // String verlängern
    buf[i]=c;    // Zeichen einfügen
    Serial.print(buf+i++); // Ab da ausgeben
    backspace(strcount(buf+i,buf+l));  // Kursor repositionieren
   }else ding();
  }//switch
 }//for
raus:
 unmark();
 Serial.println();
 return arg;
}
Detected encoding: UTF-80