Xbox LIVE Indie Games
Sort Discussions: Previous Discussion Next Discussion
Page 1 of 1 (14 posts)

What is the rationale for the buffered Direct Input methods not treating a keyboard like buttons?

Last post 10/25/2012 5:26 PM by Charybdis. 13 replies.
  • 10/19/2012 5:49 AM

    What is the rationale for the buffered Direct Input methods not treating a keyboard like buttons?

    It's hard to find info on this, but sources (and experience) suggest that the likes of GetDeviceData only return key down events for the system keyboard. It seems to report them rapid fire like for some reason too. How is this supposed to be useful?? Is it just for typing? That's not even what DX is for! To make matters more grating the Microsoft documentation says the buffered data should report key ups too, but it's only ever key downs. What the hell!?

    What are you expected to do about this? Why should the keys not work like mouse buttons? Is it because of "ghosting" ambiguities? Either way as is often the case the documentation is apparently completely wrong... unless of course I am wrong. But either way this is the behavior I am getting and seeing described elsewhere (among the dwindling amount of Direct Input search results) :/

    Presumably the only way to work around it is to pull the complete device state until a key is released to know when it is no longer considered to be pressed, but ghosting excuses or not why the hell can't Direct Input manage this so that the abstraction is uniform?!
  • 10/19/2012 2:58 PM In reply to

    Re: What is the rationale for the buffered Direct Input methods not treating a keyboard like buttons?

    As noted in the DirectInput documentation:
    MSDN:
    The DirectInput API is used to process data from a joystick, or other game controller. The use of DirectInput for keyboard and mouse input is not recommended. You should use Windows messages instead.


  • 10/19/2012 9:47 PM In reply to

    Re: What is the rationale for the buffered Direct Input methods not treating a keyboard like buttons?

    David Hunt:
    As noted in the DirectInput documentation:
    MSDN:
    The DirectInput API is used to process data from a joystick, or other game controller. The use of DirectInput for keyboard and mouse input is not recommended. You should use Windows messages instead.




    That comment is presumably there to discourage novice programmers from using Direct Input to do things that would normally be done with the win32 message APIs. Obviously it's intended for game use and the other APIs are not well suited to games, and games usually use the unbuffered methods to poll the keyboard state. The other ways for keyboard are Raw Input which is low level and probably only useful if you need to distinguish two different keyboards, or GetAsyncKeyState which is obviously not appropriate (though I used it to work around this misbehavior)

    Anyway. If anyone is reading this looking for a solution. What I setup was a buffer to track up to X down keys and just call GetAsyncKeyState on those keys until they go down until the buffer is empty. Which is really annoying because the DIK codes must be translated to VK so you must add a translation table to your implementation.
  • 10/20/2012 3:27 AM In reply to

    Re: What is the rationale for the buffered Direct Input methods not treating a keyboard like buttons?

    That comment is there to discourage all programmers from using DirectInput for keyboard and mouse. Why? Because all DirectInput does is create a separate thread where it monitors Windows messages and then translates them for you. This introduces latency. It also makes it so that you never get any of the repeat messages (if you hold down, e.g., the 'a' key then with DirectInput you just get a single "hey the user pressed 'a' down" message whereas with normal Win32 messages you would get both the key press and all system-generated repeat messages (there's a bool flag you can check to see if its a new press or a repeat due to the user holding the key down). The same sorts of things happen with the mouse where DirectInput introduces latency and limits how much information you can get.

    Also, DirectInput is very, very legacy at this point. The reason all the interfaces have an 8 in them is because DirectX 8 was the last time anything happened with DirectInput. Seeing as we're up to DirectX 11.1 and it's been over 10 years since DirectX 8 was launched, you're talking about an API that came out before the launch of Windows XP. Indeed the only reason it hasn't been eliminated entirely from the Windows SDK is that it's the only sane way to support legacy joysticks. (XInput2 is for Xbox 360 controllers and other controllers that are compatible with it). All of the guidance from MS is (and has been for a while) to use either Win32 message (or raw input) for keyboard and mouse, to use XInput2 for Xbox 360 & compatible controllers, and to only use DirectInput if you need/want to support legacy controllers and joysticks.
  • 10/20/2012 9:09 AM In reply to

    Re: What is the rationale for the buffered Direct Input methods not treating a keyboard like buttons?

    Well I wrote up a reply but the goddamn page reloaded while typing. Anyway you are correct if you want translated input (eg. repeats) then DI is wrong wrong wrong, but DI was developed and pushed exactly for gaming. It's stuck at 8 because controllers have not changed and they are not even close to taking advantage of most of the stuff provided by DI8. As for XInput it is limited to the Xbox spec. I don't know if it does keyboard or not. Realistically you would need to implement both. But DI provides a uniform abstraction layer. The only thing that had to be coded differently for it is this keyboard work around and only because it doesn't not follow its own documentation in terms of emitting buffered key release events.

    How it's implemented is up to MS. It's a piss poor ghetto institution with a huge advertising budget so we are just stuck with it. It won't be the only feature of Windows that makes Windows look bad, but you just have to work with what people have. Even the Raw Input APIs are message based.

    And again if you are not supposed to use DI for keyboard and mouse then what are you supposed to use? Again this is a warning about using DI for everything. But for game inputs its the only fit. And should definitely be supported before Xinput if you have to pick one or the other or which to do first.
  • 10/20/2012 4:13 PM In reply to

    Re: What is the rationale for the buffered Direct Input methods not treating a keyboard like buttons?

    Rants agains Microsoft aside...

    MickP:
    And again if you are not supposed to use DI for keyboard and mouse then what are you supposed to use?


    The documentation tells you what you're supposed to use instead - Windows Messages.

    At any rate, I've used DirectInput for keyboard input in the past and I didn't experience the problem you described. Both key-down and key-up events were reported.

    Perhaps instead of asking why DirectInput doesn't work the way the documentation says, you should consider looking at your code and asking why your code isn't doing what you think it should? From your post on GameDev, it appears that you are misinterpreting a comment in the code snippet you borrowed. The comment states that only key presses are reported. That comment doesn't mean that DirectInput only reports key presses. It means that particular line of code only reports key presses.

    It's not the "ghetto corporation's" fault that you are having difficulty with your code.

  • 10/20/2012 4:51 PM In reply to

    Re: What is the rationale for the buffered Direct Input methods not treating a keyboard like buttons?

    Bob Taco Industries:
    All of the guidance from MS is (and has been for a while) to use either Win32 message (or raw input) for keyboard and mouse


    MickP:
    And again if you are not supposed to use DI for keyboard and mouse then what are you supposed to use?


    See the above quote from my previous post. For further reference, see: http://msdn.microsoft.com/en-us/library/ms645530(VS.85).aspx (keyboard) and http://msdn.microsoft.com/en-us/library/ms645533(VS.85).aspx (mouse). In particular WM_KEYDOWN and WMKEYUP for keys and WM_LBUTTONDOWN, WM_LBUTTONUP, WM_LBUTTONDBLCLK, (the M, R, and X variants of those L messages), WM_MOUSEMOVE, and WM_MOUSEWHEEL. Those are the main messages of important (see the links for documentation describing their use) but other keyboard and mouse messages may be useful and there are related functions that are also useful.
  • 10/21/2012 6:04 AM In reply to

    Re: What is the rationale for the buffered Direct Input methods not treating a keyboard like buttons?

    ^Here (http://www.gamedev.net/topic/633011-keyboard-getdevicedata-buffered-never-releases-keys/) is the aforementioned post on Gamedev.net.

    Anyway the reply miss attributed the code I posted. Like the thread says it comes from here (http://www.flipcode.com/archives/DirectInput_Example.shtml) and it just represents my attempt to find corroborating evidence in this day and age.

    I would love to believe that there is something horribly wrong here. But the fact of the matter is that the buffered API is only returning down events and seems to be translating them into a repeat pattern, as if it was intended to be used for text input. There's nothing "Direct" about that.

    I will still contend that message APIs are a must for windows but don't make sense for games. Plus the messaging APIs are sent to windows AFAIK. What if there is no window? Then what?

    I gotta admit that all of the Direct X APIs should be windowless. But so far SetCooperativeLevel works if you give it 0 for a window and I had awful trouble with feeding it a hidden window. Direct3D on XP will not work correctly without a hidden window. Though I got an idea to see if giving it the desktop window would work from another gamedev.net thread just now that I intend to try.

    PS: I am just being a devil's advocate here. I intend to work with the Raw Input APIs as they allow multiplayer with mice/keyboards from what I can tell and require [hidden] windows. But I am just MS bashing as you say because there is no reason to act like Direct Input is deprecated when the alternatives are like 20 years old and never intended for game like things.
  • 10/21/2012 10:58 AM In reply to

    Re: What is the rationale for the buffered Direct Input methods not treating a keyboard like buttons?

    Well, your code is broken; buffered keyboard input with release works fine.

    Using VS 2012 create a Win32 application. Name it "DirectInputBufferedKeyboardTest". Replace the contents of DirectInputBufferedKeyboardTest.cpp with the following:

    // DirectInputBufferedKeyboardTest.cpp : Defines the entry point for the application.  
    //  
     
    #include "stdafx.h"
    #include "DirectInputBufferedKeyboardTest.h"  
    #define DIRECTINPUT_VERSION 0x0800
    #include <dinput.h>  
    #include <wrl/client.h>
    #include <exception>  
    #include <string>
    #pragma comment(lib, "dxguid.lib")  
    #pragma comment(lib, "dinput8.lib")
    #define MAX_LOADSTRING 100  
     
    void ThrowIfFailed(HRESULT hr)  
    {  
        if (FAILED(hr))  
        {  
            throw std::exception();  
        }  
    }  
     
    // Global Variables:  
    HINSTANCE hInst;                                // current instance  
    HWND g_mainHWND;  
    Microsoft::WRL::ComPtr<IDirectInput8>   dInput;  
    Microsoft::WRL::ComPtr<IDirectInputDevice8> dInputDeviceKeyboard;  
     
    TCHAR szTitle[MAX_LOADSTRING];                  // The title bar text  
    TCHAR szWindowClass[MAX_LOADSTRING];            // the main window class name  
     
    // Forward declarations of functions included in this code module:  
    ATOM                MyRegisterClass(HINSTANCE hInstance);  
    BOOL                InitInstance(HINSTANCE, int);  
    LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);  
    INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);  
     
    int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,  
                           _In_opt_ HINSTANCE hPrevInstance,  
                           _In_ LPTSTR    lpCmdLine,  
                           _In_ int       nCmdShow)  
    {  
        UNREFERENCED_PARAMETER(hPrevInstance);  
        UNREFERENCED_PARAMETER(lpCmdLine);  
     
        // TODO: Place code here.  
        MSG msg;  
        HACCEL hAccelTable;  
     
        // Initialize global strings  
        LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);  
        LoadString(hInstance, IDC_DIRECTINPUTBUFFEREDKEYBOARDTEST, szWindowClass, MAX_LOADSTRING);  
        MyRegisterClass(hInstance);  
     
        // Perform application initialization:  
        if (!InitInstance (hInstance, nCmdShow))  
        {  
            return FALSE;  
        }  
     
        hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_DIRECTINPUTBUFFEREDKEYBOARDTEST));  
     
        ThrowIfFailed(  
            DirectInput8Create(hInstance, DIRECTINPUT_VERSION, IID_IDirectInput8W, &dInput, NULL)  
            );  
     
        ThrowIfFailed(  
            dInput->CreateDevice(GUID_SysKeyboard, &dInputDeviceKeyboard, NULL)  
            );  
     
        ThrowIfFailed(  
            dInputDeviceKeyboard->SetCooperativeLevel(g_mainHWND, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE)  
            );  
     
        ThrowIfFailed(  
            dInputDeviceKeyboard->SetDataFormat(&c_dfDIKeyboard)  
            );  
     
        DIPROPDWORD  dipdw;   
        dipdw.diph.dwSize = sizeof(DIPROPDWORD);   
        dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);   
        dipdw.diph.dwObj = 0;   
        dipdw.diph.dwHow = DIPH_DEVICE;   
        dipdw.dwData = 10;   
     
        ThrowIfFailed(  
            dInputDeviceKeyboard->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph)  
            );  
     
        ThrowIfFailed(  
            dInputDeviceKeyboard->Acquire()  
            );  
     
        // Main message loop:  
        while (GetMessage(&msg, NULL, 0, 0))  
        {  
            if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))  
            {  
                TranslateMessage(&msg);  
                DispatchMessage(&msg);  
            }  
        }  
     
        ThrowIfFailed(  
            dInputDeviceKeyboard->Unacquire()  
            );  
     
        return (int) msg.wParam;  
    }  
     
     
     
    //  
    //  FUNCTION: MyRegisterClass()  
    //  
    //  PURPOSE: Registers the window class.  
    //  
    ATOM MyRegisterClass(HINSTANCE hInstance)  
    {  
        WNDCLASSEX wcex;  
     
        wcex.cbSize = sizeof(WNDCLASSEX);  
     
        wcex.style          = CS_HREDRAW | CS_VREDRAW;  
        wcex.lpfnWndProc    = WndProc;  
        wcex.cbClsExtra     = 0;  
        wcex.cbWndExtra     = 0;  
        wcex.hInstance      = hInstance;  
        wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_DIRECTINPUTBUFFEREDKEYBOARDTEST));  
        wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);  
        wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);  
        wcex.lpszMenuName   = MAKEINTRESOURCE(IDC_DIRECTINPUTBUFFEREDKEYBOARDTEST);  
        wcex.lpszClassName  = szWindowClass;  
        wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));  
     
        return RegisterClassEx(&wcex);  
    }  
     
    //  
    //   FUNCTION: InitInstance(HINSTANCE, int)  
    //  
    //   PURPOSE: Saves instance handle and creates main window  
    //  
    //   COMMENTS:  
    //  
    //        In this function, we save the instance handle in a global variable and  
    //        create and display the main program window.  
    //  
    BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)  
    {  
        HWND hWnd;  
     
        hInst = hInstance; // Store instance handle in our global variable  
     
        hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,  
            CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);  
     
        if (!hWnd)  
        {  
            return FALSE;  
        }  
     
        ShowWindow(hWnd, nCmdShow);  
        UpdateWindow(hWnd);  
     
        g_mainHWND = hWnd;  
     
        return TRUE;  
    }  
     
    //  
    //  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)  
    //  
    //  PURPOSE:  Processes messages for the main window.  
    //  
    //  WM_COMMAND  - process the application menu  
    //  WM_PAINT    - Paint the main window  
    //  WM_DESTROY  - post a quit message and return  
    //  
    //  
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)  
    {  
        int wmId, wmEvent;  
        PAINTSTRUCT ps;  
        HDC hdc;  
     
        static std::wstring diKeyPressAndReleaseMsgs;  
     
        if (dInputDeviceKeyboard != nullptr)  
        {  
            DIDEVICEOBJECTDATA rgdod[10];   
            DWORD dwItems = 10;  
            HRESULT hr;  
            hr = dInputDeviceKeyboard->GetDeviceData(   
                sizeof(DIDEVICEOBJECTDATA),   
                rgdod,   
                &dwItems,   
                0);  
     
            if (SUCCEEDED(hr))  
            {  
                if (diKeyPressAndReleaseMsgs.length() > 1000)  
                {  
                    diKeyPressAndReleaseMsgs.clear();  
                }  
                for (DWORD i = 0; i < dwItems; ++i)  
                {  
                    auto item = rgdod[i];  
                    diKeyPressAndReleaseMsgs.append(L" The following key was " 
                        ).append((item.dwData & 0x80) ? L"pressed: " : L"released: " 
                        ).append(std::to_wstring(item.dwOfs)  
                        ).append(L".\n" 
                        );  
     
                    InvalidateRect(g_mainHWND, NULL, TRUE);  
                }  
                // dwItems = Number of elements read (could be zero).  
                if (hr == DI_BUFFEROVERFLOW)  
                {   
                    // Buffer had overflowed.  
                    OutputDebugString(L"Overflow - more than 10 items were pending.\n");  
                }   
            }   
            else 
            {  
                ThrowIfFailed(hr);  
            }  
        }  
     
        switch (message)  
        {  
        case WM_COMMAND:  
            wmId    = LOWORD(wParam);  
            wmEvent = HIWORD(wParam);  
            // Parse the menu selections:  
            switch (wmId)  
            {  
            case IDM_ABOUT:  
                DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);  
                break;  
            case IDM_EXIT:  
                DestroyWindow(hWnd);  
                break;  
            default:  
                return DefWindowProc(hWnd, message, wParam, lParam);  
            }  
            break;  
        case WM_PAINT:  
            RECT rc;  
            SetRect(&rc, 10, 10, 500, 500);  
            hdc = BeginPaint(hWnd, &ps);  
            SetDCBrushColor(hdc, RGB(0,0,0));  
            DrawText(hdc, diKeyPressAndReleaseMsgs.c_str(),  
                static_cast<int>(diKeyPressAndReleaseMsgs.length()),  
                &rc,  
                DT_LEFT | DT_WORDBREAK  
                );  
            // TODO: Add any drawing code here...  
            EndPaint(hWnd, &ps);  
            break;  
        case WM_DESTROY:  
            PostQuitMessage(0);  
            break;  
        default:  
            return DefWindowProc(hWnd, message, wParam, lParam);  
        }  
        return 0;  
    }  
     
    // Message handler for about box.  
    INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)  
    {  
        UNREFERENCED_PARAMETER(lParam);  
        switch (message)  
        {  
        case WM_INITDIALOG:  
            return (INT_PTR)TRUE;  
     
        case WM_COMMAND:  
            if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)  
            {  
                EndDialog(hDlg, LOWORD(wParam));  
                return (INT_PTR)TRUE;  
            }  
            break;  
        }  
        return (INT_PTR)FALSE;  
    }  
     

    Note that this is just an example; it fails to do standard things like reacquire if it loses then gains focus, etc.
  • 10/22/2012 10:30 AM In reply to

    Re: What is the rationale for the buffered Direct Input methods not treating a keyboard like buttons?

    I lost another reply to this damn JS or whatever editor. I swear to god this website is awful. At any rate I really appreciate the legwork above Bob. I apologize I am not in the mood to write something more glowing after losing a a good long post to this infernal editor.

    So thanks to your example and encouragement it turns out that Unacquire was the culprit though it gave no issues in terms input from other devices. Which reminded me that I have no clue what Acquire and Unacquire even do thanks to the completely abominable documentation.

    I know Acquire is usually called in a loop, but that seems pretty gratuitous so I had just bookended the thing. I don't know what is required to recover from a lost device either DI wise... maybe someone has the patience to inform me. It's not as if I have not tried desperately to figure this stuff out in all my years.

    BTW: Another knock on DI's keyboard is it neglects HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout\Scancode Map. I've had to use this archaic thing for probably a decade in order to be able to write code. Ever since smaller (and weirder) formfactor keyboards became the norm. I like the smaller boards but they always remove the main programming keys (home/end rows and arrows) and anyway I don't play a lot of PC games but the few I can remember neglect the Scancode Map, which means they are surely using DI. Though some may be using RawInput, which according to this (http://molecularmusings.wordpress.com/2011/09/05/properly-handling-keyboard-input/) article I came across is actually a newer API even though it sounds like an older low-level thing. Probably just a newly exposed API. It looks like RawInput is the only decent way to go anyway. I was planning on getting around to going there eventually but I want to do the best by DI too.

    Anyway I tried to emulate the Scancode Map but it was hopeless without programming a scancode conversion table because MapVirtualKey is the most useless API I've ever come across. Completely pointless in its brokenness. The online docs say its been beefed up in Vista but I could not make any of those features manifest and would not rely on a Vista API regardless. I appreciated reacquainting myself with scancodes though and it might come in handy later as RawInput looks like that's what you get to work with.

    PS: Thanks again Bob!


    EDITED: Just a thought. If DI really did just piggy back on the other APIs then it would almost definitely go through the Scancode Map. It kind of suggests that it is doing it's own thing somehow. It definitely suggests that it isn't translating virtual keys like any old WM_KEYDOWN handler.
  • 10/22/2012 10:50 AM In reply to

    Re: What is the rationale for the buffered Direct Input methods not treating a keyboard like buttons?

    ^I am inclined to mark this thread answered. It's good to have this stuff out on the web BTW...

    Except that the workaround I have works (for me anyway) and I really have no clue what to do Acquire and Unacquire wise. I have some idea as I have a project that hooks into another apps DI business. But I have no concrete understanding of it. So if I can't get some answers in here I will close this thread up and make a new one in not long.

    But I want to go ahead and see if this can be a twofer first.
  • 10/23/2012 9:16 AM In reply to

    Re: What is the rationale for the buffered Direct Input methods not treating a keyboard like buttons?

    For a post of any length on here, it's become a force of habit for me to press Ctrl-A, Ctrl-C every so often. The issue has been around for years and they've never fixed it.

    This here describes acquire: http://msdn.microsoft.com/en-us/library/ee415221(VS.85).aspx . Basically, since DI can (depending on the mode) seize control of the input, then in certain circumstances (menu clicks, backgrounding your window, etc.) Windows will need to retake control and thus your device will be automatically unacquired. Calls to acquire are not ref counted so you don't need to keep track of them; a single call to unacquire will release it.

    DI skips all Windows-based interpretations of key codes (see: http://msdn.microsoft.com/en-us/library/ee418998(VS.85).aspx ). It works directly with the device drivers so all mappings are ignored and it even treats things like the Shift key as just another key. It will register Alt, but Windows will typically also pay attention to Alt such that you wouldn't want to use it for anything of note.

    The Raw Input docs are here: http://msdn.microsoft.com/en-us/library/ms645536(VS.85).aspx .

    MapVirtualKey works just fine. Find the similar code above and replace it with this:

                    auto item = rgdod[i];  
                    wchar_t ch = static_cast<wchar_t>(MapVirtualKey(MapVirtualKey(item.dwOfs, MAPVK_VSC_TO_VK), MAPVK_VK_TO_CHAR));  
                    diKeyPressAndReleaseMsgs.append(L" The following key was " 
                        ).append((item.dwData & 0x80) ? L"pressed: " : L"released: " 
                        ).append(std::to_wstring(item.dwOfs)  
                        ).append(L" '" 
                        ).append(std::wstring(1, ch)  
                        ).append(L"'.\n" 
                        );  
     

    Note that this will just give you letters (in caps regardless of shift or capslock) and then only for characters that can be represented as letters (i.e you'll get nothing useful for a shift keypress). Note that if you want to differentiate left shift vs right shift and other left-right keys, pass MAPVK_VSC_TO_VK_EX instead of MAPVK_VSC_TO_VK in the first call to MapVirtualKey.

    ---

    The example in my previous post (the whole program post) should, in WndProc, also have a call to acquire right after checking for a null dInputKeyboardDevice, e.g.

        if (dInputDeviceKeyboard != nullptr)  
        {  
            ThrowIfFailed(  
                dInputDeviceKeyboard->Acquire()  
                );  
     

    That will generally handle making sure the device is acquired. It'll throw if you switch to a DISCL_FOREGROUND | DISCL_EXCLUSIVE cooperative level and then try to switch away from the application, though. You can note the HR if you need that and rather than just throwing you can check HR's for known values and handle the ones you can handle appropriately (and otherwise throw).
  • 10/25/2012 11:25 AM In reply to

    Re: What is the rationale for the buffered Direct Input methods not treating a keyboard like buttons?

    For anyone searching for DI info out on the web. It's pretty scarce after all. What I ended up doing is just never calling Unacquire unless it is required for some reason such as SetProperty, which does not seem so unreasonable if you are doing things in non-exclusive background mode, which to be honest I don't understand why any software would not do so; though it may not be best practice. And that said without knowing what to do I left things as is, so that Acquire is simply aggressively called before doing anything with the device. The docs say Acquire is inexpensive. I am assuming doing so will recover from a "lost" state though I do not know if you can be lost in non-exclusive background mode or not.

    At any rate it came time to publish some of the code in question here. It can be found here (http://svn.swordofmoonlight.net/code/Somplayer.dll/Somcontrol.cpp) however the Direct Input stuff will eventually be moved into a separate library following a modular specification. I would appreciate to know if the patterns (around thread::main) look bad if anyone looking at it feels that any do.

    PS: It turns out most of the DIK constants are actually scancodes. The code implements "Scancode Map" (thread::scancodemap) which IMO is a must if you are developing with the Direct Input keyboard. Most products do not honor the map. I usually pull off a 4th of my keyboard's keys and shuffle them around to my liking so not following the map can be really obnoxious. It might be less of a problem if control config is done by key down detection but still you would be naming the wrong keys than what the end user is looking at. To be honest "Scancode Map" is really old and inflexible. Windows really needs an appropriate way to remap keyboards.

    Now if you don't mind I am through interfacing with this very poorly implemented forum for a little while... :)
  • 10/25/2012 5:26 PM In reply to

    Re: What is the rationale for the buffered Direct Input methods not treating a keyboard like buttons?

    Answer
    Reply Quote
    That comment is presumably there to discourage novice programmers from using Direct Input to do things that would normally be done with the win32 message APIs. Obviously it's intended for game use and the other APIs are not well suited to games


    Actually that comment is there because you should use Windows messages instead of DirectInput.

    Once upon a time (i.e. back in the days of Windows 95, Windows 98, and Windows ME), DirectInput provided low-level access to the mouse and keyboard. However, starting with Windows NT it just uses the Windows message queue to 'fake' the original design. As such, you are better off cutting out the complexity of DirectInput and just use those messages directly on any modern version of Windows.

    This is why none of the DirectX SDKs released in 2009 and 2010 include samples for keyboard and mouse usage of DirectInput, and why the MSDN Code Gallery DirectInput samples pack also doesn't include samples for keyboard and mouse usage of DirectInput. The only scenarios where DirectInput use remains relevant (and why we continue to ship the headers and libraries in the Windows 8.0 SDK) is to support legacy joysticks, custom HID devices, and HID-based Force Feedback devices.

    DirectInput's continued support for keyboard and mice is only there for backcompat with older programs. You should really not use it for keyboard and mice in new apps which is why MSDN says "The use of DirectInput for keyboard and mouse input is not recommended. You should use Windows messages instead." because that's what we actually mean.
Page 1 of 1 (14 posts) Previous Discussion Next Discussion