C++ getch() eingegebenes Zeichen löschen



  • @wob Danke für deine Antwort! Das probiere ich definitiv aus, vielen Dank!



  • @Bernd25 Wie Dir glaube ich schon gesagt worden ist solltest Du Dich nach einer Bibliothek umsehen die Dir den Umgang mit der Konsole erleichtert. Da Du Linux erwähnt hast: https://www.linuxjournal.com/content/getting-started-ncurses



  • Danke für deine Antwort @Swordfish! Ich verwende schon ncurses, aber ich werde mir den Link von dir gleich näher ansehen. Danke für deine Mühe!



  • @Bernd25: Wenn der Anwender bei der Funktion immer etwas eingeben muß, dann könntest du bei ESC auch einfach einen Leerstring zurückgeben (anstatt eines Magic-Strings):

    return std::string();
    

    Alternative wäre z.B. eine Exception zu werfen (throw) und diese dann zu fangen (catch) - je nachdem, ob du dies als eine Programmlogik-Ausnahme ansiehst.
    Oder es ginge auch noch per zusätzlichem Parameter:

    std::string MeineFunktion(bool& ESCgedrueckt)
    {
      ESCgedrueckt = false;
    
      // ...
    }
    

    Oder ab C++11 auch ein std::tuple zurückgeben:

    std::tuple<std::string, bool> MeineFunktion()
    {
      // ...
      return std::make_tuple(AusgabeString, ESCgedrueckt);
      // bzw.
      return { AusgabeString, ESCgedrueckt };
    }
    

    (ich habe mal extra hier jetzt die deutschen Bezeichner gelassen, auch wenn ich dir anrate, alles in englisch zu erstellen!)



  • @Th69
    Was spricht gegen:

    /**
     * @brief 
     * @param s Vom Benutzer eingegebenen String
     * @return false wenn die Eingabe vom Benutzer abgebrochen wurde, sonst true
     */
    bool MeineFunktion(std::string& s)
    {
        char c;             // EingabeChar habe ich auf c (= Char) verkürzt
        int Zaehler = 0;
    
        s.clear();
        while ((c = getch()) != 13)     // 13 = Carriage return, Enter-Taste
        {
            std::cout << Zaehler;		
            if (c == 27)                // 27 = Escape, ESC-Taste
                return false;
            if (isalnum(c))
            {
                s.push_back(c);
                Zaehler++;
            }
        }
        return true;
    }
    


  • Ab C++ 17 gibt´s auch noch std::optional.



  • Genau so gut wie mein Vorschlag "per zusätzlichem Parameter" (welches nun der Rückgabewert und welches der zusätzliche Parameter ist, ist wohl Geschmackssache).



  • Ich bedanke mich für die vielen Rückmeldungen und vorallem für die Beispiele. Ihr habt mir sehr geholfen!!

    Jetzt bin ich aber dran, die Funktion entsprechend anzupassen und es auszuprobieren. Ich werde mich morgen melden, sobald ich es umgesetzt habe.

    Vielen Dank!



  • Ohne Backspace ist das allerdings ziemlich benutzerunfreundlich...
    Allerdings flackerten meine Versuche diesbezüglich (wenn BS und length()>0: Springen zum Zeilenanfang, Ausgabe von Leerzeichen, pop_back() und Ausgabe des Strings.
    Blieben noch die Cursortasten und Einfügen.
    Vermutlich wäre es einfacher, einen modalen Dialog anzuzeigen, in dem sämtliche Eingaben vorgenommen werden können.



  • Früher gab's auch mal Turbo Vision von Borland. Und da ist ein linux port: http://tvision.sourceforge.net/



  • @Quiche-Lorraine Vielen Dank für das tolle Beispiel, damit hast du mir sehr geholfen. Ich habe leider noch keine Informationen im Internet gefunden, wie ich den string anschließend auswerten kann. Jedoch denke ich, dass ich die Funktion so aufrufen muss:

    if (MeineFunktion(std::string test)) { 
    // kein ESC und Eingabe in "test"
    }
    else {
    // ESC
    }
    

    Ich nutze die Funktion aktuell so:

    bool MeineFunktion(std::string& s)
    {
        char c;             // EingabeChar habe ich auf c (= Char) verkürzt
        int Zaehler = 0;
    
        s.clear();
        while ((c = getch()) != 13)     // 13 = Carriage return, Enter-Taste
        {
            std::cout << Zaehler;		
            if (c == 27)                // 27 = Escape, ESC-Taste
                return false;
            if (isalnum(c))
            {
                s.push_back(c);
                Zaehler++;
            }
        }
        return true;
    }
    

    Da ich ncurses verwende, befindet sich der Cursor in der Mitte des Bildschirms, nach meiner Text-Ausgabe mit mvprintw. Also z. B. nach: "Hier eingeben: ". Dies ist auch so gewünscht. Gebe ich nun etwas ein und drücke ENTER verschiebt sich der Cursor ganz nach links in die Zeile, also in die erste Spalte und die Eingabe wird weiterhin erwartet.

    Gebe ich bei der Eingabe "test" ein und drücke anschließend die ESC-Taste, wird meine Eingabe einfach gelöscht und der Curser ist wieder in der Mitte vom Bildschirm wo er ursprünglich war.

    Sehr komisch irgendwie...

    EDIT: Und ich habe bei der Eingabe die Möglichkeit mit der zurück Taste, so weit zu löschen, bis ich in der ersten Spalte bin. Das ist natürlich ganz doof.... Hast du für mich einen Tipp, was ich versuchen kann? Ich danke dir!



  • @Bernd25
    Mit ncurses kenne ich mich nicht aus.

    Da ich aber eine Idee mit Control Codes hatte, habe ich folgendes ausprobiert:

    #include <string>
    #include <iostream>
    #include <cstdio>
    #include <conio.h>
    
    /**
     * @brief 
     * 
     * @todo Die Funktion nutzt die Control Codes 13 = Carriage Return, 27 = Escape und 
     * 8 = Backspace. Ich bin mit aber nicht sicher ob auf allen Terminals diese auch so
     * unterstuetzt werden, wie wir sie hier benötigen. Daher ist es wichtig diese auf 
     * dem Zielterminal zu testen. Getestete Terminals: Windows cmd.exe
     * 
     * @todo Die Funktion würde ich als Hack einstufen. Eine grafische Variante mit GUI
     * wäre mir lieber. 
     * 
     * @param s Vom Benutzer eingegebenen String
     * 
     * @return false wenn die Eingabe vom Benutzer abgebrochen wurde, sonst true
     */
    bool MeineFunktion2(std::string& s)
    {
        char c;             // EingabeChar habe ich auf c (= Char) verkürzt
    
        std::cout << "Eingabe: ";
        s.clear();
        while ((c = getch()) != 13)     // 13 = Carriage return, Enter-Taste
        {
            if (c == 27)                // 27 = Escape, ESC-Taste
            {
                std::cout << "\n";
                return false;
            }
            else if (c == 8)            // 8 = Backspace
            {
                if (!s.empty())
                {
                    s.pop_back();            
                    std::cout << c << ' ' << c;
                }
            }
            if (isalnum(c))
            {
                s.push_back(c);
                std::cout << c;
            }
            //std::cout << s.size();      // Sobald wie ein Zeichen eingegeben wurde, wollen wir auch die Länge ausgeben        
        }
        std::cout << "\n";
        return true;
    }
    
    int main(int argc, char** argv)
    {
        std::string s;
        
        if (MeineFunktion2(s))
            std::cout << "Benutzereingabe: " << s << "\n";
        else
            std::cout << "Benutzereingabe wurde mittels ESC abgebrochen\n";
        return 0;
    }
    

    Aber ich würde diesen Code als Hack bezeichnen, da ich mir nicht sicher bin ob jedes Terminal auch den ASCII Code 8 = Backspace versteht. Auf der Windows Kommandozeile cmd.exe scheint er zu funktionieren.

    Ich habe leider noch keine Informationen im Internet gefunden, wie ich den string anschließend auswerten kann.

    Doku zu std::string auf cppreference



  • @Quiche-Lorraine Vielen herzlichen Dank für deine Mühe! Das hätte ich nun wirklich nicht erwartet.

    Ich war früher schon in einigen Foren unterwegs, aber so Hilfsbereit wie hier alle sind - das habe ich nicht erwartet. Ich bin allen sehr dankbar!

    Ich werde es testen und werde anschließend berichten wie es gelaufen ist. Vielen Dank auch für den Link zur Doku von std::string auf cppreference - diese werde ich mir durchlesen. Dankeschön!