Как перехватить нажатия клавиш в командной строке Windows?

Я работаю над инструментом динамики нажатия клавиш для конкретного приложения. Мое требование - получить данные о времени нажатия клавиш пользователя в приглашении Windows CMD. После нескольких поисков я нашел 2 способа сделать это: 1) использовать хуки Windows 2) Pyhook - модуль оболочки python.

Мне кажется, что функциональность моих приложений будет во многом схожа с таковой у клавиатурного шпионского ПО. Но я не могу понять, следует ли мне использовать глобальные перехватчики или перехватчик потока для перехвата нажатий клавиш в командной строке CMD. И если используется глобальный перехватчик, можно ли фильтровать нажатия клавиш на основе целевого приложения?


person secfreak    schedule 01.05.2012    source источник
comment
Почему ваше приложение просто не получает эти события нажатия клавиш? Зачем вам нужно перехватывать его глобально для командной строки? Вы создали приложение из командной строки?   -  person Cody Gray    schedule 01.05.2012
comment
@CodyGray: Прошу прощения, если мое описание было неполным. Я написал консольное приложение, в котором используется ловушка WH_KEYBOARD_LL. Я могу регистрировать нажатия клавиш и информацию об их времени, но приложение регистрирует общесистемные данные. Теперь я пытаюсь ограничить ведение журнала только из окна CMD. Пожалуйста, дайте мне знать, есть ли способ лучше выполнить задачу. Я новичок в выигрыше api, и я почти не царапаю поверхность. :)   -  person secfreak    schedule 01.05.2012
comment
Если ваше приложение работает в командной строке, почему вы не можете просто заставить его прослушивать события клавиатуры, как обычное приложение? Перехватчик WH_KEYBOARD_LL - это глобальный низкоуровневый перехватчик клавиатуры - это означает, что вы будете получать уведомления о всех событиях клавиатуры, которые происходят в масштабе всей системы. Поскольку похоже, что это не то, что вам нужно, вам вообще не нужен глобальный перехватчик.   -  person Cody Gray    schedule 01.05.2012
comment
@CodyGray: Спасибо! Я посмотрю. Просто из любопытства: знаете ли вы о каком-либо параметре или функции фильтра, которая будет возвращать текущее приложение, из которого регистрируются нажатия клавиш, если используется глобальный перехватчик?   -  person secfreak    schedule 01.05.2012
comment
Нет, это невозможно. Весь смысл глобальной ловушки, особенно низкоуровневой, состоит в том, что ваша подключаемая процедура получает уведомление о событии до того, как оно будет передано в какое-либо приложение. Вот почему вы можете использовать / отменить событие и предотвратить его обработку приложением. Установка ловушки в основном вставляет вашу подключаемую процедуру в апстрим всего остального. (Но, как я уже сказал, я, честно говоря, не понимаю, зачем вам нужен перехватчик. Похоже, вы могли бы просто обработать обычный ввод с клавиатуры, направленный в консольное приложение.)   -  person Cody Gray    schedule 01.05.2012
comment
@CodeGray: я не хочу, чтобы события нажатия клавиш направлялись в мое консольное приложение. Я хочу, чтобы мое консольное приложение прослушивало события нажатия клавиш в командной строке Windows CMD или командной строке PowerShell.   -  person secfreak    schedule 01.05.2012


Ответы (1)


Этот хороший код ниже представляет собой приложение Hotkey, которое находится в фоновом режиме и прослушивает комбинацию клавиш CTRL-y, и вы можете изменять или добавлять любые другие комбинации клавиш в приложение. Используйте CTRL-q для выхода из скрытого приложения.

Если вы хотите полностью скрыть окно консоли, не комментируйте эту строку в main (): //ShowWindow(FindWindowA("ConsoleWindowClass", NULL), false). Наслаждаться.

if (CTRL_key !=0 && key == 'y' )
{
   MessageBox(NULL, "CTRL-y was pressed\nLaunch your app here", "H O T K E Y", MB_OK); 
   CTRL_key=0;
}

Полный листинг кода:

#define _WIN32_WINNT 0x0400
#pragma comment( lib, "user32.lib" )

#include <windows.h>
#include <stdio.h>

HHOOK hKeyboardHook;

__declspec(dllexport) LRESULT CALLBACK KeyboardEvent (int nCode, WPARAM wParam, LPARAM lParam)
{
    DWORD SHIFT_key=0;
    DWORD CTRL_key=0;
    DWORD ALT_key=0;

    if  ((nCode == HC_ACTION) &&   ((wParam == WM_SYSKEYDOWN) ||  (wParam == WM_KEYDOWN)))      
    {
        KBDLLHOOKSTRUCT hooked_key =    *((KBDLLHOOKSTRUCT*)lParam);
        DWORD dwMsg = 1;
        dwMsg += hooked_key.scanCode << 16;
        dwMsg += hooked_key.flags << 24;
        char lpszKeyName[1024] = {0};
        lpszKeyName[0] = '[';

        int i = GetKeyNameText(dwMsg,   (lpszKeyName+1),0xFF) + 1;
        lpszKeyName[i] = ']';

        int key = hooked_key.vkCode;

        SHIFT_key = GetAsyncKeyState(VK_SHIFT);
        CTRL_key = GetAsyncKeyState(VK_CONTROL);
        ALT_key = GetAsyncKeyState(VK_MENU);

        if (key >= 'A' && key <= 'Z')   
        {

            if  (GetAsyncKeyState(VK_SHIFT)>= 0) key +=32;

            if (CTRL_key !=0 && key == 'y' )
            {
               MessageBox(NULL, "CTRL-y was pressed\nLaunch your app here", "H O T K E Y", MB_OK); 
               CTRL_key=0;
            }

            if (CTRL_key !=0 && key == 'q' )
            {
                MessageBox(NULL, "Shutting down", "H O T K E Y", MB_OK); 
               PostQuitMessage(0);
            }




            printf("key = %c\n", key);

            SHIFT_key = 0;
            CTRL_key = 0;
            ALT_key = 0;

        }

        printf("lpszKeyName = %s\n",  lpszKeyName );
    }
    return CallNextHookEx(hKeyboardHook,    nCode,wParam,lParam);
}

void MessageLoop()
{
    MSG message;
    while (GetMessage(&message,NULL,0,0)) 
    {
        TranslateMessage( &message );
        DispatchMessage( &message );
    }
}

DWORD WINAPI my_HotKey(LPVOID lpParm)
{
    HINSTANCE hInstance = GetModuleHandle(NULL);
    if (!hInstance) hInstance = LoadLibrary((LPCSTR) lpParm); 
    if (!hInstance) return 1;

    hKeyboardHook = SetWindowsHookEx (  WH_KEYBOARD_LL, (HOOKPROC) KeyboardEvent,   hInstance,  NULL    );
    MessageLoop();
    UnhookWindowsHookEx(hKeyboardHook);
    return 0;
}

int main(int argc, char** argv)
{
    HANDLE hThread;
    DWORD dwThread;

    hThread = CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)   my_HotKey, (LPVOID) argv[0], NULL, &dwThread);

    //ShowWindow(FindWindowA("ConsoleWindowClass", NULL), false);

    if (hThread) return WaitForSingleObject(hThread,INFINITE);
    else return 1;

}
person Software_Designer    schedule 01.05.2012