Sign in to follow this  
impulsionaudio

Abstracting Input in Win32

Recommended Posts

impulsionaudio    136
I am trying to get keyboard and mouse input from the Win32 message pump to update my data, graphics and audio nicely. I figured I should create a library for the input classes (mouse, keyboard, etc) and have the message handlers, called by WndProc, update the input classes. Afterward, the data could query the input classes for the results to get updated. Does this sound reasonable? Are there any design patterns that might help accomplish this (e.g. command, visitor, etc.)? Is there another more standard way I should know about? I haven't implemented anything like this for a game/tool in Win32 and would like to know "the right way." Thanks

Share this post


Link to post
Share on other sites
impulsionaudio    136
Quote:
Original post by nfnm

why you don't want to use direct input instead of win32 messages? it gives more power.


I am making a game tool, not a game, so the input will be interacting with buttons, menus, etc. as well as the D3D window. I have heard using DirectInput in combination with the Win32 message pump is a real head ache. Can you bypass the Win32 message pump and just use DirectInput?

Share this post


Link to post
Share on other sites
bzroom    647
Win32 applications receive input via message callbacks. As you know these are processed by the WndProc. My WndProc is a static function member of my win32 window object (Window), the Window pointer is stored in the win32 user data.

The Window allows the user to store an IWindowInput interface pointer. It is this IWindowInput which receives the keyboard and mouse inputs from win32.


class IWindowInput
{
public:
virtual ~IWindowInput() = 0;

enum KeyCodes { KEY_ESCAPE, /*include rest here*/ };
enum Button { BUTTON_LEFT, BUTTON_RIGHT, BUTTON_CENTER };

//these return true if handled
virtual bool KeyDown(KeyCodes keycode){ return false; }
virtual bool KeyUp(KeyCodes keycode){ return false; }
virtual bool MouseDown(Button button, int x, int y){ return false; }
virtual bool MouseUp(Button button, int x, int y){ return false; }
};


//Example usage:
class Application : public IWindowInput
{
public:
Application() { window.SetInputHandler(this); }

virtual bool KeyDown(IWindowInput::Keycodes keycode)
{
if (keycode == IWindowInput::KEY_ESCAPE)
{
exit();
return true;
}

return false;
}

private:
Win32Window window;
};


So that explains the low level abstraction, pushing messages into the system. The next step is efficiently sharing and using the current state of the input devices.

My input system is a member of the Application, and all the input messages are basically passed directly into this system. Internally the input system may acquire additional input devices such as joysticks, gamepads, anything else that isn't a window message. It could even acquire the mice and keyboards directly via directinput or something.

Anyways, there is 1 major method of the input system. I call it "LockInput." LockInput takes the current state of the input devices, either updated via messages or polling the devices directly, and it applys logic based on the previous state of the devices to generate a couple output structures includeing Pressed, Held, Released, Current. These are child objects to each input device, for example:

inputManager.LockInput();
const Mouse::State &mouse_held = inputManager.GetMouse(0).GetHeld();
const Keyboard::State &keys_pressed = inputManager.GetKeyboard(0).GetPressed();

You could do all kinds of things with how you actually retrieve the input devices but you get the idea I think.

(for ex: inputManager.GetDevice<Mouse>(0)... )

If you implement boolean operators for your State structures then you can do this pretty easily.


void Device::LockInput()
{
pressed_state = !prev_state && current_state;
released_state = prev_state && !current_state;
held_state = prev_state && current_state;
prev_state = current_state;
}


[Edited by - bzroom on December 20, 2008 3:02:22 PM]

Share this post


Link to post
Share on other sites
bzroom    647
Quote:
I have heard using DirectInput in combination with the Win32 message pump is a real head ache.

There's no reason why this should be overly difficult, you just need to have a common denominator that these two systems boil into.

Quote:
Can you bypass the Win32 message pump and just use DirectInput?

Definitely. You'll need the message pump to keep your window alive and respond to other system events. But for input, you can ignore the win32 messages completely. In this case, ignore the first half of my previous post.

Quote:
I am making a game tool, not a game, so the input will be interacting with buttons, menus, etc. as well as the D3D window.

I hope for this you'd decide to use .NET or wxWidgets or something. If you're going to roll your own then the win32 messages / direct input will set you right.. Your input handler from one of those gui libraries would be a reasonable place to inject your messages into the application from. Wether it's a win32 wndproc or a MouseDownEvent handler in .net, it's going to be the same after that.

Share this post


Link to post
Share on other sites
Mike2343    1202
Direct Input, is longer supported by Microsoft and it just wraps the Win32 messages anyways. Using it is just putting another layer thats pretty much useless and can actually slow you down slightly.

Just use Win32 or make your own OS independent class that handles input and write OS specific code, like a lot of people do (who support multiple platforms).

Share this post


Link to post
Share on other sites
impulsionaudio    136
Quote:
I hope for this you'd decide to use .NET or wxWidgets or something.


I would like to use .NET but I will be needing to embed D3D windows in the app and managed DirectX is no longer supported by Microsoft. AFAIK, apart from XNA (which is pretty high level from what I understand) there is no Microsoft supported method for integrating D3D windows in managed apps. There is SlimDX but that is contributed to by volunteers with day jobs, so the support can not be as complete as for strictly Microsoft libraries. Even the SlimDX wiki says this.

Share this post


Link to post
Share on other sites
anda    148
Is there a reason no one mentioned this?


BYTE keyState[256];
BYTE keyPrevState[256];
POINT cursor;

void init() {
ZeroMemory(keyState, sizeof(keyState));
ZeroMemory(keyPrevState, sizeof(keyPrevState));
ZeroMemory(&cursor, sizeof(cursor));
}
void update() {
RECT clientRect;
GetClientRect(window, &clientRect);

//
GetCursorPos(&cursor);
ScreenToClient(window, &cursor);
memcpy(&keyPrevState, &keyState, sizeof(keyPrevState));
GetKeyboardState(keyState);
}


bool keyDown(int k) {
return (keyState[k] & 0x80) && 1;
}
bool keyReleased(int k) {
return (!(keyState[k] & 0x80) && (keyPrevState[k] & 0x80));
}
bool keyTyped(int k) {
return ((keyState[k] & 0x80) && !(keyPrevState[k] & 0x80));
}


Share this post


Link to post
Share on other sites
bzroom    647
Quote:
Original post by impulsionaudio
I would like to use .NET but I will be needing to embed D3D windows in the app and managed DirectX is no longer supported by Microsoft. AFAIK, apart from XNA (which is pretty high level from what I understand) there is no Microsoft supported method for integrating D3D windows in managed apps.


This is not a problem. Using C++ CLI, managed C++, with unmanaged directx is fine. Say you want your rendering to be drawn to a picturebox in .net (C++ windows application). You'll use the myPictureBox->Handle.ToPointer() to create your d3d device. Basically, unmanaged and managed c++ can live happily along side each other. Having never tried it with a directx input library, i can't say it'll be as easy for input. But I'm going to have to believe it is.

But as mentioned Directinput is no more. I believe it is XInput these days.

Also anda pointed out a good way to use the win32 api in a polling method (without messages).

Share this post


Link to post
Share on other sites
impulsionaudio    136
Quote:
This is not a problem. Using C++ CLI, managed C++, with unmanaged directx is fine. Say you want your rendering to be drawn to a picturebox in .net (C++ windows application). You'll use the myPictureBox->Handle.ToPointer() to create your d3d device. Basically, unmanaged and managed c++ can live happily along side each other. Having never tried it with a directx input library, i can't say it'll be as easy for input. But I'm going to have to believe it is.


This is very interesting. I am going to have to give this a try.

Share this post


Link to post
Share on other sites
bzroom    647
A couple tips.

If you can't get your rendering device created. Try switching the "Common Runtime Language Support" project property from /clr:pure to /clr

Also, add an event handler to Application.Idle, repaint your picturebox from this handler.

If you need more continuous updating then you can either add a timer, or add some function call to the end of the idle handler which will kick off another idle call, like invalidating a control.

Share this post


Link to post
Share on other sites
impulsionaudio    136
Quote:
Original post by bzroom
A couple tips.

If you can't get your rendering device created. Try switching the "Common Runtime Language Support" project property from /clr:pure to /clr

Also, add an event handler to Application.Idle, repaint your picturebox from this handler.

If you need more continuous updating then you can either add a timer, or add some function call to the end of the idle handler which will kick off another idle call, like invalidating a control.


Thanks.

Share this post


Link to post
Share on other sites
MJP    19786
Quote:
Original post by impulsionaudio
Quote:
I hope for this you'd decide to use .NET or wxWidgets or something.


I would like to use .NET but I will be needing to embed D3D windows in the app and managed DirectX is no longer supported by Microsoft. AFAIK, apart from XNA (which is pretty high level from what I understand) there is no Microsoft supported method for integrating D3D windows in managed apps. There is SlimDX but that is contributed to by volunteers with day jobs, so the support can not be as complete as for strictly Microsoft libraries. Even the SlimDX wiki says this.


1. Using .NET and native D3D together isn't very hard to do. All D3D needs is a window handle, which you can get from any .NET Form or Control via the Handle property.

2. The XNA Framework Graphics namespace is not much more than just a wrapper of D3D9. A few things like render targets and surfaces are abstracted a bit more, but you're still directly working with vertex buffers/index buffers/shaders/etc. There are other optional components in XNA like the Game class and the Content Pipeline, but you can completely ignore them if you'd like. My map editor is a WinForms app that uses XNA, and I had no problems getting that to work.

Share this post


Link to post
Share on other sites
Evil Steve    2017

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this