"KeyboardHook" für Kommandozeilenapplikation



  • Hallo,

    ich hab ein ganz banales Problem: und zwar möchte ich in einer C++-Kommandozeilenapplikation auf eine Tastatureingabe reagieren, ohne die Ausführung dafür unterbrechen zu müssen. In den FAQ bin ich auch schon auf den Thread über das KeyboardHooking gestoßen http://www.c-plusplus.net/forum/viewtopic-var-t-is-39383.html, allerdings bezieht sich das ja auf eine Anwendung mit mehreren Fenstern. Gibt es da etwas äquivalentes für mein banales Problemchen?

    Vielen Dank für eure Antworten schonmal!
    blahhhh



  • Wenn ich dich richtig verstanden habe willst du Code ausführen ohne deine Anwedung zu blockieren. Da ist ein Keyboardhook der völlig falsche Ansatz. Dazu verwendet man Threads. Unter Windows wäre da die Funktion CreateThread erwähnenswert.



  • Hi,

    ich hab mir letztens mal eine kleine Klasse geschrieben die das oben genannte Problem loest:

    class Console : public Singleton<Console>
    	{
    		DECLARE_AS_SINGLETON(Console);
    
    	protected:
    		struct InputHandlerInfo
    		{
    			INPUT_TYPE InputType;
    			void* pData;
    			ConsoleInputHandler Handler;
    		};
    		static unsigned __stdcall InputHandlerThread(void* args);
    		Console();
    
    	public:
    		bool CreateConsole(bool bRedirectHandles);
    		void DestroyConsole();
    		bool RedirectHandles();
    		void RegisterInputFunc(INPUT_TYPE InputType,void* pData, ConsoleInputHandler InputHandler);
    		void RemoveInputFunc(ConsoleInputHandler InputHandler);
    		virtual ~Console();
    
    	private:
    		std::vector<InputHandlerInfo> m_vecInputHandler;
    		bool m_bAllocated;
    		bool m_bRedirectedHandles;
    		bool m_bThreadRun;
    		HANDLE m_hThread;
    		std::string m_strLastError;
    		CRITICAL_SECTION m_CritSecInputHandler;
    
    		FILE* stdOutputErrHandle_;
    		FILE* stdInputHandle_;
    		FILE* stdOutputHandle_;
    
    	};
    
    void Console::RegisterInputFunc(INPUT_TYPE InputType,void* pData, ConsoleInputHandler InputHandler)
    {
    	InputHandlerInfo HandlerInfo;
    
    	if(m_vecInputHandler.size() == 0)
    	{
    		m_bThreadRun = true;
    		m_hThread = (HANDLE)_beginthreadex(NULL, 0, InputHandlerThread , NULL, 0, NULL);
    	}
    
    	EnterCriticalSection(&m_CritSecInputHandler);
    
    	for(std::vector<InputHandlerInfo>::iterator iter = m_vecInputHandler.begin();
    		iter != m_vecInputHandler.end(); iter++)
    	{
    		if( iter->Handler == InputHandler)
    		{
    			iter->InputType = InputType;
    			iter->pData = pData;
    			LeaveCriticalSection(&m_CritSecInputHandler);
    			return;
    		}
    	}
    
    	HandlerInfo.pData = pData;
    	HandlerInfo.Handler = InputHandler;
    	HandlerInfo.InputType = InputType;
    	m_vecInputHandler.push_back(HandlerInfo);
    
    	LeaveCriticalSection(&m_CritSecInputHandler);
    }
    void Console::RemoveInputFunc(ConsoleInputHandler InputHandler)
    {
    	EnterCriticalSection(&m_CritSecInputHandler);
    
    	for(std::vector<InputHandlerInfo>::iterator iter = m_vecInputHandler.begin();
    		iter != m_vecInputHandler.end(); iter++)
    	{
    		if( iter->Handler == InputHandler)
    		{
    			m_vecInputHandler.erase(iter);
    			break;
    		}
    	}
    	LeaveCriticalSection(&m_CritSecInputHandler);
    
    	if(m_vecInputHandler.size() == 0)
    		m_bThreadRun = false;
    }
    
    unsigned __stdcall Console::InputHandlerThread(void* args)
    {
    	Console& Con = Console::Get();
    	HANDLE hStdInput = GetStdHandle(STD_INPUT_HANDLE);
    	DWORD dwEvents;
    	DWORD dwRead;
    	PINPUT_RECORD pInputRecord;
    
    	while(Con.m_bThreadRun)
    	{
    		switch( WaitForSingleObject( hStdInput, 500) )
    		{
    		case WAIT_OBJECT_0:
    			{
    				if( GetNumberOfConsoleInputEvents(hStdInput, &dwEvents) )
    				{
    					pInputRecord = new INPUT_RECORD[dwEvents];
    					if( pInputRecord)
    					{
    						if( ReadConsoleInput(hStdInput, pInputRecord, dwEvents, &dwRead) )
    						{
    							EnterCriticalSection(&Con.m_CritSecInputHandler);
    							for(std::vector<Console::InputHandlerInfo>::iterator iter = Con.m_vecInputHandler.begin();
    													iter !=Con. m_vecInputHandler.end(); iter++)
    							{
    								for(DWORD i = 0; i < dwRead; i++)
    								{
    
    									if(iter->InputType == BOTH ||
    										pInputRecord[i].EventType == KEY_EVENT && iter->InputType == KEYBOARD ||
    										pInputRecord[i].EventType == MOUSE_EVENT && iter->InputType == MOUSE)
    									{
    										iter->Handler(&pInputRecord[i], iter->pData);
    									}
    								}
    							}
    							LeaveCriticalSection(&Con.m_CritSecInputHandler);
    						}
    						delete[] pInputRecord;
    					}
    				}
    				break;
    			}
    		}
    	}
    	_endthreadex(0);
    	return 0;
    }
    

    Und zum anwenden einfach:

    bool g_bRun = true;
    
    void KeyHandler(PINPUT_RECORD pRec, void* pArgs)
    {
         if( pRec->Event.KeyEvent.wVirtualKeyCode == VK_ESC)
            g_bRun = false;
    }
    
    int main(int argc, char** argv)
    {
    Console& Con = Console::Get();
    
    Con.RegisterInputFunc( KEYBOARD, NULL, KeyHandler);
    
    while( g_bRun )
        Sleep(500);
    
    return 0;
    }
    

    Ich hoffe es hat dir geholfen.

    Gruessli C0de4Fun


Anmelden zum Antworten