Konsoleneingabeverfahren (Auto completion)



  • Hallo,

    ich würde gern eine art autovervollständigungsroutine bei drücken von tab in meiner konsolenapplikation integrieren.
    cin stellt sowas nicht zur verfügung oder? müsste ich da sozusagen eine selbstgetsrickte eingaberoutine basteln? sonderzeichen wie pfeiltasten lassen sich ja über getch() abfangen oder?
    Hat jemand eventuell schon mal eine eingaberoutine geschrieben und mag sie posten? stell mir das nämlich ganz schön stressig vor, gerade so mit pfeil-links und dann zeichen einfügen und so...
    oder auch pfeil nach oben für die letzten paar befehle, die müsste man dann auch irgendwo zwischenspeichern.....

    ich habe mir das so vorgestellt, dass die routine einfach bei drücken von tab den bisherigen string checkt und in einem <vector> nach möglichen kandidaten für eine vervollständigung schaut.

    nun gut,
    falls jemand was hat kann er es ja mal schicken, ansonsten muss ich halt selbst ran.....

    gruß
    jOe



  • mc_ginley schrieb:

    stell mir das nämlich ganz schön stressig vor, gerade so mit pfeil-links und dann zeichen einfügen und so...

    naja, es hält sich in grenzen. ich hab in basic öfters sowas gemacht.
    es war recht einfach zu implementieren, wenn ich zwei strings für die aktuele zeile genommen habe, einen string für das vor dem corsor und einen string für das nach dem cursor. ich nenne die strings mal left und right. dann sind die komischen tasten bald beherrschbar.
    backspace: letztes zeichen von left löschen
    del: erstes zeichen von right löschen
    cursor-left: letzes von left löschen und vorn an right hängen
    cursor-right: erstes von right löschen und hinten an left hängen
    anderes zeichen: zeichen hinten an left hängen

    und wenn's einem spaß macht, kann man sich überlegen, ob right nicht besser anderesrum gespeichert werden sollte (war in basic ausgeschlossen). man kann für die tasten pos1 und end feine implementierunen machen. und so weiter.



  • ...ja genau pos1 und ende! nicht zu vergesssen!

    nun gut, aber wie siehts aus mit solchen einagben wie î oder á oder à? diese ganzen sonderzeichen die zwei tastendrücke benötigen müssten dann so richtig von hand implementiert werden? ich seh schon schweißperlen auf meiner stirn...
    wie schauts mit ALT-GR + ziffernblock? setzt getch() sowas um, bzw liefer [ALT GR] +[7] auch "{"?

    gruß
    jOe



  • mc_ginley schrieb:

    ...ja genau pos1 und ende! nicht zu vergesssen!

    nun gut, aber wie siehts aus mit solchen einagben wie î oder á oder à? diese ganzen sonderzeichen die zwei tastendrücke benötigen müssten dann so richtig von hand implementiert werden? ich seh schon schweißperlen auf meiner stirn...
    wie schauts mit ALT-GR + ziffernblock? setzt getch() sowas um, bzw liefer [ALT GR] +[7] auch "{"?

    gruß
    jOe

    ich schätze, getch macht das alles. probiers aus mit

    for(;;)
       cout<<getch()<<'\n;
    

    und sag mal bescheid, ob í und ì und î gehen. [altgr]+ziffernblock macht sicherlich jemand anderes.



  • ... ja also ALT-GR funktioniert, auch die Geschichte mit dem â - PUUUHH.
    Ich hab nur gerade das Problem das getch sich mit den Pfeiltasten nicht so verhält wie es soll.
    Normalerweise soll getch() bei Pfeil oder Funktionstasten 0 oder 0xE0 (224) liefern. Bei den Funktionstasten klappt das auch, da kommt 0.
    0xE0 bzw 224 erhalte ich aber nie! Somit kann ich auch [TAB] nicht abfangen (das worums ja eigentlich ging....
    woran kann das denn liegen?

    gruß
    jOe



  • ..is ok, lag daran dass ich mein zeichen als char und nicht als int definiert hatte....
    wie kann ich diesen integer wert nun an einen string anhängen?



  • mc_ginley schrieb:

    woran kann das denn liegen?

    ich tippe zuerst auf messfehler.
    wobei ich nicht auf 224 warten würde, sondern nur gucken, was denn bei cursortasten geliefert wird. getch() mag gerne mal bei jedem compiler ein anderes mapping von taste zu zahlenkombination haben.



  • mc_ginley schrieb:

    ..is ok, lag daran dass ich mein zeichen als char und nicht als int definiert hatte....

    denk noch drüber nach, ob bei dir

    int getKey(){
       int key=getch();//getch gibt doch keine munuszahlen, oder?
       if(key==0)
          key=256+getch();
       return result;
    }
    

    sich auf den code positiv auswürken würde.



  • ... so ich poste mal das was ich zusammengeschrieben hab. falls mal jemand sowas braucht 😃
    bis jetzt keine groben bugs... ich lass mich aber gern eines besseren belehren

    features:
    - multiline, eingabe kann über mehrere zeilen gehen, auch am konsolenbufferende (war das ein gefrickel!)
    - entfernen/einfügen im string
    - pos1, ende, links, rechts

    mögliche verbesserungen:
    - vector für die letzten eingaben ( für pfeil nach oben/unten)
    - die cursor x-koordinate müsste man irgendwie mal klug berechnen und nicht durchiterieren ( beim berechnen treten bei perioden 0.333333 usw rundungsfehler auf deswegen hab ichs erst mal so gelöst)
    - wie fügt man ein int an einen string an? ich habs mit stringstream "notgelöst", das lässt sich sicher besser machen....

    so, die vervollständigung macht dann Inpcomplete. Das sollte true zurückgeben wenn eine lösung gefunden wurde. das ist dann aber aufgabenspezifisch und kann sich ja jeder selber zusammenfrickeln....

    char getlast( string* in )
    {
    	char ch;
    	if ( in->length() == 0)
    		return 0;
    	ch = in->c_str()[in->length() - 1 ];
    	return ch;
    }
    
    char getfirst( string* in )
    {
    	char ch;
    	if ( in->length() == 0)
    		return 0;
    	ch = in->c_str()[0];
    	return ch;
    }
    
    string cutlast( string in )
    {
    	string tmp;
    	if ( in.length() == 0 )
    		return tmp;
    	tmp.assign ( in.substr( 0, in.length()-1 ) );
    	return tmp;
    }
    
    string cutfirst( string in )
    {
    	string tmp;
    	if ( in.length() == 0 )
    		return tmp;
    	tmp.assign( in.substr( 1 ) );
    	return tmp;
    }
    
    //////////////////////////////////////////////////////////////////////////////////////////////
    // setcursor
    //
    void setcursor ( DWORD dimx, DWORD dimy, DWORD x, DWORD y , UINT _pos )
    {
    	UINT ox,oy;
    	///////////////////////////////////////////////////////////////////
    	// calculate y
    	oy = y + (_pos + x)/dimx;
    	///////////////////////////////////////////////////////////////////
    	// iterate x
    	ox = x;
    	for ( int i = 0; i < _pos; i++ ){
    		ox++;
    		if ( ox == dimx )
    			ox = 0;
    	}
    
    	gotoxy(ox,oy);
    	return;
    }
    
    //////////////////////////////////////////////////////////////////////////////////////////////
    // out
    //
    void out( DWORD dimx, DWORD dimy, DWORD* x, DWORD* y, string* left, string* right, bool del)
    {
    	DWORD		written;
    	UINT		len;
    	SHORT		ox,oy;
    	long		ctoe;		// characters to end
    	UINT		_pos;
    
    	len = left->length() + right->length();
    	_pos = left->length();
    
    	gotoxy( *x, *y );
    
    	////////////////////////////
    	// calculate reseading space
    	ctoe = dimx * dimy - ( *y * dimx + *x);
    	////////////////////////////
    	// adjust y if new line
    	if ( len >= ctoe ){
    		*y = *y - 1;
    	}
    	////////////////////////////
    	// write left part
    	WriteConsole( GetStdHandle(STD_OUTPUT_HANDLE), left->c_str(), (DWORD)left->length(), &written, 0);
    	////////////////////////////
    	// write right part	
    	WriteConsole( GetStdHandle(STD_OUTPUT_HANDLE), right->c_str(), (DWORD)right->length(), &written, 0);	
    	////////////////////////////
    	// write ' ' if string got shorter
    	if ( del )
    		cout << " ";
    
    	setcursor( dimx, dimy, *x,*y,left->length() );
    }
    
    //////////////////////////////////////////////////////////////////////////////////////////////
    // GetInput
    //
    string GetInput()
    {
    	string			left_,right_;
    	string			inp;
    	int				ch;
    	DWORD			x_start,y_start;
    	DWORD			dimx,dimy;
    	DWORD			conmode;
    
    	x_start = con.getCaretX();							// initial cursorpos on start
    	y_start = con.getCaretY();
    	dimx	= con.getSizeX();
    	dimy	= con.getSizeY();
    
    	////////////////////////////////////
    	// enable wrap (important for out())
    	GetConsoleMode( GetStdHandle(STD_OUTPUT_HANDLE), &conmode );
    	SetConsoleMode( GetStdHandle(STD_OUTPUT_HANDLE), conmode | ENABLE_WRAP_AT_EOL_OUTPUT );
    
    start:
    
    	ch = _getch();
    
    	/////////////////////////////////////////////////////////////////////////////////////////////
    	// handle TAB ==> Input Completion
    	if ( ch == 9 ) {
    
    		string tmp;
    		tmp.assign( left_.c_str() );
    		tmp.append( right_.c_str() );
    		int oldlen = (int)tmp.length();
    
    		/////////////////////////////////////////////////////////////////////////////////////////////
    		// if Completion successfull
    		if ( InpComplete(&tmp) ) {
    			left_.clear();
    			right_.clear();
    			left_.assign( tmp.c_str() );
    			out(dimx,dimy,&x_start,&y_start,&left_,&right_,false);
    			///////////////////////////////////////
    			// if new string is shorter, print " "
    			while ( oldlen > (int)left_.length() ) {
    				cout << " ";
    				oldlen--;
    			}
    			out(dimx,dimy,&x_start,&y_start,&left_,&right_,false);
    
    		}
    		goto start;
    	}
    	/////////////////////////////////////////////////////////////////////////////////////////////
    	// handle backspace
    	if ( ch == 8 ) {
    
    		if ( getlast(&left_) != 0 ) {
    			////////////////////////
    			// cut last from left
    			left_ = cutlast( left_ );
    			////////////////////////
    			// print output
    			out(dimx,dimy,&x_start,&y_start,&left_,&right_,true);
    		}
    		goto start;
    	}
    	/////////////////////////////////////////////////////////////////////////////////////////////
    	// handle function keys
    	if ( ( ch == 0) || ( ch == 0xE0 ) )  {
    
    		ch = _getch();
    		/////////////////////////////////////////////////////////////////////////////////////////////
    		// handle end
    		if ( ch == 79 ) {
    			//if ( pos < ( left_.length() + right_.length() ) ) {
    			if ( right_.length() > 0 ) {
    				///////////////////////////
    				// copy everything to left
    				string tmp;
    				tmp.assign( left_.c_str() );
    				tmp.append( right_.c_str() );
    				left_.clear();
    				right_.clear();
    				left_.assign( tmp.c_str() );
    				///////////////////////////
    				// print output
    				setcursor( dimx, dimy, x_start,y_start, left_.length());
    			}
    		}
    		/////////////////////////////////////////////////////////////////////////////////////////////
    		// handle Pos1
    		if ( ch == 71 ) {
    			if ( left_.length() > 0 ) {
    				///////////////////////////
    				// copy everything to right
    				string tmp;
    				tmp.assign( left_.c_str() );
    				tmp.append( right_.c_str() );
    				left_.clear();
    				right_.clear();
    				right_.assign( tmp.c_str() );
    				///////////////////////////
    				// print output
    				//out(dimx,dimy,&x_start,&y_start,&left_,&right_,false);
    				setcursor( dimx, dimy, x_start,y_start, left_.length());
    			}
    		}
    		/////////////////////////////////////////////////////////////////////////////////////////////
    		// handle Erase
    		if ( ch == 83 ) {
    			if ( getfirst(&right_) != 0 ) {
    				///////////////////////////
    				// cut first right
    				string tmp2;
    				tmp2.assign( right_.substr( 1 ) );
    				right_.clear();
    				right_.assign( tmp2.c_str() );
    				///////////////////////////
    				// print output
    				out(dimx,dimy,&x_start,&y_start,&left_,&right_,true);
    			}
    		}
    		/////////////////////////////////////////////////////////////////////////////////////////////
    		// handle right arrow
    		if ( ch == 77 ) {
    			if ( getfirst(&right_) != 0 ) {
    				///////////////////////////
    				// append first right to left
    				stringstream tmp;
    				tmp << left_.c_str();
    				tmp << (char)getfirst(&right_);
    				left_.clear();
    				left_.assign( tmp.str().c_str() );
    				///////////////////////////
    				// cut first right
    				string tmp2;
    				tmp2.assign( right_.substr( 1 ) );
    				right_.clear();
    				right_.assign( tmp2.c_str() );
    				///////////////////////////
    				// move cursor
    				setcursor( dimx, dimy, x_start,y_start, left_.length());
    			}
    		}
    		/////////////////////////////////////////////////////////////////////////////////////////////
    		// handle left arrow
    		if ( ch == 75 ) {
    			if ( getlast(&left_) != 0 ) {
    				///////////////////////////
    				// copy last character from left to first right
    				stringstream tmp;
    				tmp << (char)getlast(&left_);
    				tmp << right_.c_str();
    				right_.clear();
    				right_.assign( tmp.str().c_str() );
    				///////////////////////////
    				// cut last character from left
    				left_ = cutlast(left_);
    				///////////////////////////
    				// move cursor - x
    				setcursor( dimx, dimy, x_start,y_start, left_.length());
    			}
    		}
    		goto start;
    	}
    
    	/////////////////////////////////////////////////////////////////////////////////////////////
    	// append the character and put it on screen
    	if ( ch != 13 ) {
    		stringstream tmp;
    		tmp << left_.c_str();
    		tmp << (char)ch;
    		left_.clear();
    		left_.assign( tmp.str().c_str() );
    		/////////////////////////
    		// print output
    		out(dimx,dimy,&x_start,&y_start,&left_,&right_,false);
    	}
    
    	if ( ch != 13 )
    		goto start;
    
    	cout << "\n";
    	//////////////////////////
    	// reset mode
    	SetConsoleMode( GetStdHandle(STD_OUTPUT_HANDLE), conmode );
    
    	inp.assign( left_ );
    	inp.append( right_ );
    	return inp;
    }
    

Anmelden zum Antworten