Using low-level keyboard for input

This is a discussion on Using low-level keyboard for input within the C++ Programming forums, part of the General Programming Boards category; If i use 'keybd_event()', i would be able to set the program automatically type on the notepad or something, but ...

  1. #1
    Computer guy
    Join Date
    Sep 2005
    Location
    I'm lost!!!
    Posts
    200

    Using low-level keyboard for input

    If i use 'keybd_event()', i would be able to set the program automatically type on the notepad or something, but would that be considered as low-level keyboard input?

    I searched online and came across some examples that said you have to hook the program to the driver or what ever it is. Anyone has any suggestion?
    Here is the code i found:

    Code:
    #define _WIN32_WINNT 0x0400
    #include <Windows.h>
    
    
    ///////////////////////////////////////////////////////////////////////////////
    
    
    LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM
    lParam)
    {
    
      BOOL fEatKeystroke = FALSE;
    
      if (nCode == HC_ACTION) 
      {
         switch (wParam) 
    	 {
    		case WM_KEYDOWN:  
    		case WM_SYSKEYDOWN:
    		case WM_KEYUP:    
    		case WM_SYSKEYUP:
    			{
    				PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT) lParam;
    				fEatKeystroke=(p->vkCode == VK_SNAPSHOT);
    				if (fEatKeystroke)
    				{
    					//Here goes your printkey code
    				}
    				break;
    			}
         }
      }
    
      return(fEatKeystroke ? 1 : CallNextHookEx(NULL, nCode, wParam,
    lParam));
    }
    
    
    ///////////////////////////////////////////////////////////////////////////////
    
    
    int WINAPI WinMain(HINSTANCE hinstExe, HINSTANCE, PTSTR pszCmdLine, int) 
    {
    
      // Install the low-level keyboard & mouse hooks
      HHOOK hhkLowLevelKybd  = SetWindowsHookEx(WH_KEYBOARD_LL,
         LowLevelKeyboardProc, hinstExe, 0);
    
      // Keep this app running until we're told to stop
      MessageBox(NULL,
         TEXT("Print Key is now disabled.\n")
         TEXT("Click \"Ok\" to terminate this application and re-enable that key."),
         TEXT("Disable Low-Level Keys"), MB_OK);
    
      UnhookWindowsHookEx(hhkLowLevelKybd);
    
      return(0);
    }
    Hello, testing testing. Everthing is running perfectly...for now

  2. #2
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    I personally wouldn't call that "Low Level Keyboard input", but I guess that all depends on how you interpret the term.

    In my interpretation, it means "reading data directly from the keyboard controller itself".

    Different people will, however, take this phrase as different things.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  3. #3
    Computer guy
    Join Date
    Sep 2005
    Location
    I'm lost!!!
    Posts
    200
    Is there any way that i could write a loop that automatically reading from the keyboard (just like some MMORPG game trainer ).
    I could do it from the keybd_event() but how would i going to do that with the code above? Thx
    Hello, testing testing. Everthing is running perfectly...for now

  4. #4
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,059
    Is there any way that i could write a loop that automatically reading from the keyboard (just like some MMORPG game trainer ).
    I could do it from the keybd_event() but how would i going to do that with the code above? Thx
    Code:
    #define _WIN32_WINNT 0x0400
    #include <Windows.h>
    
    ///////////////////////////////////////////////////////////////////////////////
    
    LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM
        lParam)
    {
        BOOL fEatKeystroke = FALSE;
        if (nCode == HC_ACTION) 
        {
            switch (wParam) 
            {
                case WM_KEYDOWN:  
                case WM_SYSKEYDOWN:
                case WM_KEYUP:    
                case WM_SYSKEYUP:
                    {
                        PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT) lParam;
                        fEatKeystroke=(p->vkCode == VK_SNAPSHOT);
                        if (fEatKeystroke)
                        {
    			
                            //Here goes your printkey code
                        }
                        break;
                    }
            }
        }
        return(fEatKeystroke ? 1 : CallNextHookEx(NULL, nCode, wParam,
            lParam));
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    
    void MessageLoop()
    {
        MSG message;
        while (GetMessage(&message,NULL,0,0)) {
            TranslateMessage( &message );
            DispatchMessage( &message );
        }
    }
    
    DWORD WINAPI  TheKeyLogger()
    {
        HINSTANCE hinstExe = GetModuleHandle(NULL);
        // Install the low-level keyboard & mouse hooks
        HHOOK hhkLowLevelKybd  = SetWindowsHookEx(WH_KEYBOARD_LL,
            LowLevelKeyboardProc, hinstExe, 0);
    
        // Keep this app running until we're told to stop
        //  MessageBox(NULL,
        //   TEXT("Print Key is now disabled.\n")
        // TEXT("Click \"Ok\" to terminate this application and re-enable that key."),
        //  TEXT("Disable Low-Level Keys"), MB_OK);
    
        MessageLoop();
        UnhookWindowsHookEx(hhkLowLevelKybd);
        return(0);
    }
    
    int main(int argc, char **argv) 
    {
        HANDLE hThread;
        DWORD dwThread;
    
        hThread = CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)
            TheKeyLogger, (LPVOID) argv[0], NULL, &dwThread);
        if (hThread)
            return WaitForSingleObject(hThread,INFINITE);
        else return 1;
    }

  5. #5
    Super Moderator VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,596
    If you want low level inside Windows you must use DirectInput. Everything else goes through the message pump which is anything but low level.

  6. #6
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,059
    Or possibly Raw Input.

  7. #7
    C++まいる!Cをこわせ! Elysia's Avatar
    Join Date
    Oct 2007
    Posts
    22,659
    I would think that DirectInput is easier and more flexible.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  8. #8
    Computer guy
    Join Date
    Sep 2005
    Location
    I'm lost!!!
    Posts
    200
    So how do you apply directInput in c++? I dont really know about directInput. Is it possible that i can apply directInput in window console project in visual studio? Well, my goal is trying to set a series of keys that will automatically loop through them and send to the system, just like some macro.
    Hello, testing testing. Everthing is running perfectly...for now

  9. #9
    C++まいる!Cをこわせ! Elysia's Avatar
    Join Date
    Oct 2007
    Posts
    22,659
    Sure enough. You just have to get the DirectX SDK from Microsoft.
    It comes with docs, libraries, example source - all you need to build projects with DirectInput!
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  10. #10
    Super Moderator VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,596
    Contrary to popular belief but both DirectInput and DirectAudio will function by themselves without ever touching Direct3D. All they both need are window handles and some other basic rudimentary data and you are set.

    It may even be possible to do this from a console app given that you can retrieve the window handle by setting the title to a known value, searching for a window with that title and then store the hwnd that Windows finds. From here you could definitely fire up DirectInput and/or DirectSound.

    If you have problems with DirectInput let me know as I have plenty of experience with it to get you going. Remember that you MUST #define the version of DirectInput you wish to use PRIOR to including dinput.h. If you fail to do this you will get some very nasty cryptic errors. The DirectInput header file relies on this #define to determine which functions to compile and which ones to ignore. That little bit of info will you save you hours of frustration - or at least it would have for me.
    Last edited by VirtualAce; 12-13-2007 at 09:22 PM.

  11. #11
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,059
    Example of a rudimentary console app. I'd be interested in your approach to send "macros" back to the system using Direct Input. Hopefully, you can post some code to illustrate this macro sending concept.

    Code:
    #include <windows.h>
    #include <stdio.h>
    #define DIRECTINPUT_VERSION 0x0800
    #include <dinput.h>
    
    #pragma comment (lib, "dinput8.lib")
    
    LPDIRECTINPUT8 din;   
    LPDIRECTINPUTDEVICE8 directinputdevice;  
    
    void InitializeDirectInput(HINSTANCE hInstance, HWND hWnd)
    {
        DirectInput8Create(hInstance,   
            DIRECTINPUT_VERSION,    
            IID_IDirectInput8,    
            (void**)&din,    
            NULL);   
        din->CreateDevice(GUID_SysKeyboard,  
            &directinputdevice,   
            NULL);    
        directinputdevice->SetDataFormat(&c_dfDIKeyboard); 
        directinputdevice->SetCooperativeLevel(hWnd,
            DISCL_NONEXCLUSIVE | DISCL_BACKGROUND);
    }
    
    void DetectKeys(void)
    {
        static BYTE keystate[256];    
        directinputdevice->Acquire();   
        directinputdevice->GetDeviceState(256, (LPVOID)keystate);
        if(keystate[DIK_A] & 0x80)  // Check for a depressed 'A'   
            printf("A\n");          // This is where you'll implement
                                    // your custom key capture routine  
    }
    
    void CloseDirectInput(void)
    {
        directinputdevice->Unacquire(); 
        din->Release();    
    }
    
    void MessageLoop()
    {
        MSG msg;
        while(TRUE)
        {
            DWORD dwStartPoint = GetTickCount();
            if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
            {
                if (msg.message == WM_QUIT)
                    break;
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            } 
            DetectKeys();
            while ((GetTickCount() - dwStartPoint) < 25);
        }
        CloseDirectInput();
    }
    
    DWORD WINAPI MyDirectInput(LPVOID lpParm)
    {
        HINSTANCE hInstance = GetModuleHandle(NULL);
        InitializeDirectInput(hInstance, NULL);
        MessageLoop();
        return 0;
    }
    
    int main(int argc, char** argv)
    {
        HANDLE hThread;
        DWORD dwThread;
    
        hThread = CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)
            MyDirectInput, (LPVOID) argv[0], NULL, &dwThread);
        if (hThread)
            return WaitForSingleObject(hThread,INFINITE);
        else return 1;
    }

  12. #12
    Super Moderator VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,596
    As you can see DirectInput is actually quite simple and lightweight and perfect for a thread. But sending data back and forth between console and Windows app may prove to be a challenge. You can utilize SendMessage() provided you both have each other's window handles. You can then define messages starting at WM_USER+1 to implement the specific functionality of your app.

    Since SendMessage() is part of the Win32 API it is perfectly thread safe. This also allows the thread complete access to the keyboard data without having to provide access to the Windows app. Your console app would need to store the previous state of the keyboard and at the moment that changes you would send a message to the Windows app. If you take the approach to actually share the keyboard state buffer then you will have to mutex it so you ensure that the buffer is only accessed by one process at any given time. Otherwise you will most certainly crash and/or threadlock.

  13. #13
    C++まいる!Cをこわせ! Elysia's Avatar
    Join Date
    Oct 2007
    Posts
    22,659
    Using SendMessage from a thread is usually not recommended because it waits until the message is processed before returning (possibility of a deadlock). It's better to use PostMessage or SendMessageCallback to post the message to the queue and return immediately.
    Generally, with threads and messages you need to be careful.
    Last edited by Elysia; 12-14-2007 at 03:49 AM.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  14. #14
    Super Moderator VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,596
    Yes I thought about that after posting it. PostMessage or a callback would be better. But it's not because any of the functions are not thread-safe per se but moreso because SendMessage is like a 'blocking' call.

  15. #15
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,059
    Unfortunately, PostMessage has an issue or two. For instance, when PostMessage inputs the message into the targeted windows queue, that input does not update the targeted windows keyboard shift state even though PostMessage may indicate a change in keyboard shift state. When the code behind the targeted window calls either GetKeyState or GeyAsyncKeyState function, it will see the "real" shift state not the "faked" keyboard state from PostMessage.

    So, I suggest using SendInput:

    Code:
    #define _WIN32_WINNT 0x0501
    #include <windows.h>
    #include <stdio.h>
    
    #define KEYEVENTF_UNICODE 0x0004
    
    static void SendString(LPCTSTR str)
    {
        INPUT inp[2];
        memset(inp,0,sizeof(INPUT));
        inp[0].type = INPUT_KEYBOARD;
        inp[0].ki.dwFlags =  KEYEVENTF_UNICODE; 
        inp[1] = inp[0];
        inp[1].ki.dwFlags |= KEYEVENTF_KEYUP;
    
        for (LPCTSTR p=str; *p; p++) {
            inp[0].ki.wScan = inp[1].ki.wScan = *p;
            SendInput(2, inp, sizeof(INPUT));
        }
    }
    
    int main(void)
    {
        HWND windowHandle = FindWindow(0, "test - Notepad");
        if(windowHandle == NULL)
        {
            printf("Main window not found, terminating\n");
            return -1;
        }
        HWND childWindow = GetWindow(windowHandle,GW_CHILD);
        if(childWindow   == NULL)
        {
            printf("Child window not found\n");
            return -1;
        }
        SetForegroundWindow(childWindow);
        Sleep(1000);
        SendString("\nTesting\n");
        return 0;
    }

Page 1 of 2 12 LastLast
Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Low Level Keyboard Hook
    By sumone4life in forum C# Programming
    Replies: 3
    Last Post: 06-22-2009, 05:10 PM
  2. C/C++, low or high level?
    By Sentral in forum A Brief History of Cprogramming.com
    Replies: 4
    Last Post: 01-23-2007, 10:43 PM
  3. Low Level Hard Disk Access
    By samGwilliam in forum Tech Board
    Replies: 5
    Last Post: 04-01-2005, 05:14 PM
  4. Low Level Drive Access?
    By coldfusion244 in forum C++ Programming
    Replies: 1
    Last Post: 03-09-2005, 07:19 AM
  5. Low level debuggers
    By Korn1699 in forum C++ Programming
    Replies: 8
    Last Post: 03-27-2002, 12:39 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21