Wie funktioniert die TAB-Vervollständigung bei cmd.exe ???



  • Hallo, ich habe eine Konsolenanwendung geschrieben mit der man in Verzeichnise wechseln kann, wie z.B. cd c:\test

    Hier der Code:

    #include <windows.h>
    #include <iostream>
    #include <string>
    #include <tchar.h>
    #include <sstream>
    #include <vector>
    #include <Shlwapi.h>
    
    using namespace std;
    
    #pragma comment(lib, "Shlwapi.lib")
    
    string ApplicationDirectory();
    
    //***Global***
    string Pfad = ApplicationDirectory();
    
    string ApplicationDirectory()
    {
    	TCHAR szPathName[_MAX_PATH];
    	::GetModuleFileName(NULL, szPathName, _MAX_PATH);
    	LPTSTR pszFileName = _tcsrchr(szPathName, '\\') + 1;
    	*pszFileName = '\0'; 
    
    	return szPathName;
    }
    
    int checkDir(string str)
    {
    	if (PathIsDirectory(str.c_str()))
    		return 1;
    	else
    		return 0;
    }
    
    //Ausgabe Prompt
    void prompt()
    {	
    	//cout << Pfad << ">>";
    	char ps[100];
    	GetCurrentDirectory(90, ps);
    	cout << endl << ps << ">";
    }
    
    int main()
    {
    	string str;
    	do
    	{
    		//Setzt den aktuellen Pfad
    		SetCurrentDirectory(Pfad.c_str());
    		prompt();
    
    		getline(cin, str);	
    
    		istringstream cmdline (str);
    		string input;
    		vector<string> params;
    
    		string tmp;
    		while (cmdline >> tmp) 
    		{
    			params.push_back (tmp);
    		}
    
    		if(params.size() >= 2)
    		{
    			if(params[0] == "cd")
    			{				
    				//Pfad = params[1];
    				if(checkDir(params[1]) == 1)
    				{
    					Pfad = params[1];
    				}
    				else
    					cout << "Verzeichnis '" << params[1] << "' nicht gefunden" << endl << endl;
    
    			}
    		}
    		if(params.size() >= 1)
    		{
    			if(params[0] == "exit")
    				return 0;
    			if(params[0] == "dir")
    				system("dir");
    		}
    
    	}while(1);
    	return 0;
    }
    

    Jeder oder einige von euch kennen wenn man in cmd ein Verzeichnis nicht ganz eingibt und dann Tab drückt, werden alle mit dem angefangen Verzeichnis oder Dateien ausgegeben, so kann man schneller in Verzeichnise wechseln.

    Jetzt wollte ich fragen wie funktioniert die TAB-Vervollständigung in cmd, wie wurde sie implementiert, ist es möglich sowas zu realisieren????



  • Naja, damit du möglichst schnell das Ergebnis bekommst, solltest du alle Verzeichnisse vorher in einen Baum speichern und dann ist das ein einfacher string vergleich und der string der passt wird ausgewählt. Sollte relative leicht zu implementieren st. Ansonsten kannst du dir ja irgendeine Shell ankucken wie die es dort gemacht haben.



  • Mit den normalen Eingabe Funktionen wie getline() kann sowas doch nicht klappen, es muss ja ganze Zeit gewartet werden das vielleicht die TAB Taste gedrückt wird, erst dann soll die Eingegebene Zeile Vervollständigt werden.

    Wie sieht der Aufbau so einer Funktion aus???

    Bitte um Hilfe!!!!



  • Mit SetConsoleMode den Line-Input Modus abstellen und dann ReadConsole(Input).



  • So habe folgenden Code zusammengebastelt:

    #include <windows.h>
    #include <stdio.h>
    #include <iostream>
    #include <string>
    
    using namespace std;
    
    VOID ErrorExit(LPSTR);
    VOID KeyEventProc(KEY_EVENT_RECORD); 
    
    int main(VOID) 
    {		
    	cout << "Eingabe:>";
    
        HANDLE hStdin; 
        DWORD cNumRead, fdwMode, fdwSaveOldMode, i; 
        INPUT_RECORD irInBuf[128]; 
        int counter=0;
    
        // Get the standard input handle. 
    
        hStdin = GetStdHandle(STD_INPUT_HANDLE); 
        if (hStdin == INVALID_HANDLE_VALUE) 
            ErrorExit(TEXT("GetStdHandle")); 
    
        // Save the current input mode, to be restored on exit. 
    
        if (! GetConsoleMode(hStdin, &fdwSaveOldMode) ) 
            ErrorExit(TEXT("GetConsoleMode")); 
    
        // Enable the window and mouse input events. 
    
        fdwMode = ENABLE_WINDOW_INPUT; 
        if (! SetConsoleMode(hStdin, fdwMode) ) 
            ErrorExit(TEXT("SetConsoleMode")); 
    
        // Loop to read and handle the input events. 
    
        while (counter++ <= 100) 
        { 
            // Wait for the events. 
    
            if (! ReadConsoleInput( 
                    hStdin,      // input buffer handle 
                    irInBuf,     // buffer to read into 
                    128,         // size of read buffer 
                    &cNumRead) ) // number of records read 
                ErrorExit(TEXT("ReadConsoleInput")); 
    
            // Dispatch the events to the appropriate handler. 
    
            for (i = 0; i < cNumRead; i++) 
            {
                switch(irInBuf.EventType) 
                { 
                    case KEY_EVENT: // keyboard input 
                        KeyEventProc(irInBuf[i].Event.KeyEvent); 
                        break;             
                } 
            }
        } 
    
        return 0; 
    }
    
    VOID ErrorExit (LPSTR lpszMessage) 
    { 
        fprintf(stderr, "%s\n", lpszMessage); 
        ExitProcess(0); 
    }
    
    VOID KeyEventProc(KEY_EVENT_RECORD ker)
    {
    	//Wartet auf TAB Taste
    	if(ker.wVirtualKeyCode == VK_TAB)
    	{	
    		if(ker.bKeyDown)
    			cout << "#TAB EVENT PRESSED#";
    		else 
    			cout << "#TAB EVENT RELEASED#";			
    	}
    
    	//Normale Eingabe
    	else
    	{
    		//hier kommt die normale eingabe
    		cout << "#Ausgabe#" << endl;
    	}    
    }
    

    Das Programm wartet auf bestimmte Key Events, in der Funktion [i]KeyEventProc()* wird geprüft ob die TAB Taste gedrückt wird.
    Wenn ich nun einmal TAB drücke, wird einmal die PRESSED und die RELEASED funktion ausegeben, obwohl ich nur einmal gedrückt habe, bei anderen Eingaben wird auch die Ausgabe zweimal ausgegeben, wo liegt der Fehler??

    Jetzt kommt die große Frage, wenn ich nicht die TAB Taste drücke, dann sollen erstmal die Eingaben ausgegeben werden wie bei getline(), wie macht man das???



  • Habe die Funktion erweitert:

    VOID KeyEventProc(KEY_EVENT_RECORD ker)
    {
    	//Wartet auf TAB Taste
    	if(ker.wVirtualKeyCode == VK_TAB)
    	{	
    		if(ker.bKeyDown)
    			cout << "#TAB EVENT PRESSED#";
    		else 
    			cout << "#TAB EVENT RELEASED#";			
    	}
    
    	//Wartet auf Enter Taste
    	if(ker.wVirtualKeyCode == VK_RETURN)
    	{		
    		cout << "NEWLINE" << endl;
    		cout << "INPUT: " << input << endl;
    		//Input löschen
    		input.clear();
    	}
    
    	//Normale String Eingabe
    	else
    	{
    		input += ker.uChar.AsciiChar;		
    	}
    }
    
    1. Wenn ich etwas eingebe dann sehe ich sie nicht in der Console, wie kann ich die Eingaben sichtbar machen?

    2. Wieso wird jedes eingegeben Zeichen doppelt gespeichert, wegen dem PRESSSED und RELEASED????

    Bitte um Hilfe!!!!!!



  • Habe noch einiges verändert, das mit den doppelten Zeichen habe ich beseitigt:

    #include <windows.h>
    #include <stdio.h>
    #include <iostream>
    #include <string>
    
    using namespace std;
    
    //Eingabe String
    string input = "";
    
    VOID ErrorExit (LPSTR lpszMessage) 
    { 
        fprintf(stderr, "%s\n", lpszMessage); 
        ExitProcess(0); 
    }
    
    //VOID KeyEventProc(KEY_EVENT_RECORD ker, HANDLE  hStdin, DWORD fdwSaveOldMode)
    VOID KeyEventProc(KEY_EVENT_RECORD ker)
    {
    	//Wartet auf TAB Taste
    	if(ker.wVirtualKeyCode == VK_TAB)
    	{	
    		if(ker.bKeyDown)
    			cout << "#TAB EVENT PRESSED#";
    		else 
    			cout << "#TAB EVENT RELEASED#";			
    	}
    
    	//Wartet auf Enter Taste
    	else if(ker.wVirtualKeyCode == VK_RETURN)
    	{		
    		cout << "NEWLINE" << endl;
    		cout << input << endl;
    		//Input löschen
    		input.clear();
    	}
    
    	if(ker.wVirtualKeyCode == VK_BACK)
    	{	
    		cout << "löschen" << endl;
    	}	
    
    	//Normale String Eingabe
    	else
    	{
    		//Alte Einstellungen wiederherstellen
    		//SetConsoleMode(hStdin, fdwSaveOldMode);
    
    		if(ker.bKeyDown){}
    		else
    		{
    			cout << "Zeichen: " << ker.uChar.AsciiChar << endl;
    			input += ker.uChar.AsciiChar;		
    		}		
    	}	
    }
    
    int ReadKeyInput()
    {
    	HANDLE hStdin; 
        DWORD cNumRead, fdwMode, fdwSaveOldMode, i; 
        INPUT_RECORD irInBuf[128]; 
        int counter=0;
    
        // Get the standard input handle. 
    
        hStdin = GetStdHandle(STD_INPUT_HANDLE); 
        if (hStdin == INVALID_HANDLE_VALUE) 
            ErrorExit(TEXT("GetStdHandle")); 
    
        // Save the current input mode, to be restored on exit. 
    
        if (! GetConsoleMode(hStdin, &fdwSaveOldMode) ) 
            ErrorExit(TEXT("GetConsoleMode")); 
    
        // Enable the window and mouse input events. 
    
        fdwMode = ENABLE_WINDOW_INPUT; 
        if (! SetConsoleMode(hStdin, fdwMode) ) 
            ErrorExit(TEXT("SetConsoleMode")); 
    
        // Loop to read and handle the input events.  
    
    	while (counter++ <= 100) 
    	//while(1)
        {
    
            // Wait for the events. 
    		//if(!ReadConsole(hStdin, irInBuf, 128, &cNumRead, NULL))
    		//	ErrorExit(TEXT("ReadConsole")); 
    
            if (! ReadConsoleInput( 
                    hStdin,      // input buffer handle 
                    irInBuf,     // buffer to read into 
                    128,         // size of read buffer 
                    &cNumRead) ) // number of records read 
                ErrorExit(TEXT("ReadConsoleInput")); 
    
            // Dispatch the events to the appropriate handler. 
    
            for (i = 0; i < cNumRead; i++) 
            {
                switch(irInBuf[i].EventType) 
                { 
                    case KEY_EVENT: // keyboard input 
                        //KeyEventProc(irInBuf[i].Event.KeyEvent, hStdin, fdwSaveOldMode); 
    					KeyEventProc(irInBuf[i].Event.KeyEvent); 
                        break;             
                } 
            }
        } 	 
        return 0; 
    }
    
    int main(VOID) 
    {	
    	ReadKeyInput();   
    
    	return 0;
    }
    

    Ist es überhaupt möglich mit der ReadConsoleInput() Funktion die Eingaben auch auszugeben, denn bei MSDN steht das nur die ReadConsole() Funktion das kann, bitte seht selbst vielleicht hab ich es nicht verstanden: http://msdn2.microsoft.com/en-us/library/ms686033.aspx

    ENABLE_ECHO_INPUT - Characters read by the ReadFile or ReadConsole function are written to the active screen buffer as they are read. This mode can be used only if the ENABLE_LINE_INPUT mode is also enabled.

    Also irgendwie glaube ich in

    cmd.exe
    

    steckt eine andere funktionsweise, bitte gibt mir weitere Verbesserungsvorschläge/Tipps sonst komme ich nicht weiter 😞 😞 😞



  • Ich frage jetzt ein letztes mal, kann man die TAB Funktion mit der WinAPI realisieren oder wie hat es Microsoft geschafft ????????????????


Anmelden zum Antworten