Tasten aus Konfigurationsdatei auslesen und verarbeiten



  • Ich möchte aus einer Konfigurationsdatei verschiedene Tasten auslesen und mit GetAsyncKeyState innerhalb des Programs überprüfen, wann diese gedrückt werden. Das Problem ist nun, dass GetAsyncKeyState als ersten und einzigen Parameter int erwartet, was die Sache kompliziert macht, da ich lieber die Definitionen wie z.B. VK_NUMPAD0 in der Konfigurationsdatei benutzen möchte. Ich könnte natürlich ganz einfach 0x60 (NUMPAD0) mit GetPrivateProfileInt auslesen, aber das ist eher weniger aufschlussreich.

    Die einzige und bestimmt uneleganteste Lösung, die mir auf Anhieb einfällt ist, die Einträge mit GetPrivateProfileString auszulesen und dann nacheinander abzugleichen.

    [Keys]
    Close = VK_NUMPAD0
    
    int closekey = 0;
    void readini()
    {
    	std::string str(50, 0); 
    	GetPrivateProfileString("Keys", "Close", "VK_NUMPAD0", (char*)str.c_str(), 50, "keys.ini");
    	if(str == "VK_NUMPAD0")
    		closekey = 0x60;
    	else if(str == "VK_NUMPAD1")
    		closekey = 0x61;
    	//else if ..............
    }
    
    int Main()
    {
    	if(closekey != 0)
    	{
    		if (GetKeyState(closekey) & 0x8000)
    			CloseWindow();
    	}
    }
    

    Das würde zwar funktionieren, aber so würde ich das niemals benutzen. Da gibt es bestimmt elegantere Lösungen, auch wenn mir das nicht ganz so einfach zu sein scheint. Ich bin für jede Hilfe dankbar.



  • Die Lösung ist nciht schlecht, irgendwie mußt du ja auch die Codes in die richtigen übersetzen. Das einzige was mir noch einfallen würde als alternative Lösung wäre die Buchstaben zusammenzurechnen und dann einen switch zu verwenden, also etwa so:

    void readin()
    {
        char/string str=GetPrivateProfileString(...);
        int stringvalue;
        for(int i=0;i<stringsize;++i)
        {
            stringvalue+=string[i];
        };
        switch(stringvalue)
        {};
    };
    

    Hier müsstest du nur einmal die Werte ausrechnen und dann ggf in den cases nochmal mit if arbeiten, da es sicher mehr als einen Code gibt der den selben Zahlenwert hat. Inwiefern allerdings diese Variante schneller ist als if/else if wenn man von über 100 möglichen Codes ausgeht weis ich nicht.

    Allgemein solltest du bei so eienr config aber auch bedenken das sie normalerweise nur 1x beim start ausgelesen wird und somit ein kleines bischen Zeit dafür durchaus vertretbar ist.



  • [quMir kommt da in erster Linie eine map in den Sinn, vor allem wenn es um noch mehr Keys der WinAPI geht (also nicht nur VK_NUMPADX). Etwa so:

    #include <string>                   // Für std::string
    #include <map>                      // Für std::map
    #include <boost/assign/list_of.hpp> // Für die coole Initialisierung
    
    void readini()
    {
        static const std::map<std::string,int> mapping = boost::assign::map_list_of
          ("VK_NUMPAD0", VK_NUMPAD0)
          ("VK_NUMPAD1", VK_NUMPAD1)
          (...)
          ("VK_ESCAPE", VK_ESCAPE)
        ;
    
        char str[50] = {0};
        GetPrivateProfileString("Keys", "Close", "VK_NUMPAD0", str, 50, "keys.ini");
    
        std::map<std::string,int>::iterator pos = mapping.find( str );
        if ( pos != mapping.end() )
            closekey = pos->second;
    }
    


  • An die Map hatte ich garnicht gedacht, die dürfte die schnellste Variante sein.



  • Map war genau das, was ich gesucht habe. Da ich kein Boost benutze, habe ich es nun wie folgt gelöst:

    typedef std::map<std::string, int> TStrIntMap;
    typedef std::pair<std::string, int> TStrIntPair;
    
    int closekey;
    int GetKeyValue(std::string ConfStr)
    {
    	TStrIntMap tMap;
    
    	tMap.insert(TStrIntPair("VK_NUMPAD0", VK_NUMPAD0));
    	tMap.insert(TStrIntPair("VK_NUMPAD1", VK_NUMPAD1));
    
    	TStrIntMap::iterator p;
    	for(p = tMap.begin(); p != tMap.end(); ++p)
    	{
    		std::string strKey;
    		strKey = p->first;
    		if( ConfStr  == strKey)
    		{
    			return p->second;
    		}
    	}
    	return 0;
    }
    
    void SetKeyValues()
    {
    	char str[50] = {0};
        GetPrivateProfileStringA("Keys", "Close", "VK_NUMPAD0", str, 50, szIniFile);
    
    	int keyvalue = GetKeyValue(str);
    	if(keyvalue != 0)
    		closekey = keyvalue;
    }
    


  • Erstmal entschuldige ich mich für den Doppelpost, aber bis jetzt bin ich noch nicht dazu gekommen, mich zu anzumelden. Also, nun zu meiner nächsten Frage. Ich habe mir den Code von Badestrand nochmals genauer angeschaut und gesehen, dass man das Ganze ohne For-Schleife lösen kann, dann nämlich mit "find". Diese Variante scheint mir besser zu sein. Stimmt das oder liege ich mit meiner Vermutung falsch? Wenn ich mir die Codes genauer ansehen, dann könnte ich mir sogar vorstellen, dass der erste Code ungefähr dasselbe macht wie der zweite, nur dass er letztendlich kürzer ist.

    TStrIntMap::iterator p = tMap.find(ConfStr);
    	if(p != tMap.end() )
    		return p->second;
    
    TStrIntMap::iterator p;
    	for(p = tMap.begin(); p != tMap.end(); ++p)
    	{
    		std::string strKey;
    		strKey = p->first;
    		if( ConfStr  == strKey)
    		{
    			return p->second;
    		}
    	}
    


  • Talin schrieb:

    Wenn ich mir die Codes genauer ansehen, dann könnte ich mir sogar vorstellen, dass der erste Code ungefähr dasselbe macht wie der zweite, nur dass er letztendlich kürzer ist.

    Nicht nur das, er dürfte auch schneller sein 🙂 Die std::map-Klasse ist oft als binärer Baum implementiert um das Finden schnell zu machen.

    Oh, und tMap.insert(TStrIntPair("VK_NUMPAD0", VK_NUMPAD0)); lässt sich auch kürzer schreiben mit tMap["VK_NUMPAD0"] = VK_NUMPAD0; (diesmal aber ohne Geschwindigkeitsunterschied).


Anmelden zum Antworten