Raw Input API

posted in 2d Game Creation
Published December 05, 2013
Advertisement
A lot of research went into using Raw Input API on a gamepad.
I am using a Logitech Dual Action usb gamepad.
This is where I got the best example. But he obviously changed part of the code cause it didn't work.
http://forums.tigsource.com/index.php?topic=15004.0

So after more research and tweeking, got it to work. Right now it is 4 buttons, two analog sticks, and the directional pad. The others wont be hard, just haven't done them yet.

you have to include HidClass.h
This may require installing the WDK (windows driver kit)
It may not as I believe Mingw already had it.
I tried a bunch of stuff so I installed WDK along the way.

This is in the windows WndProc
[source=cpp]
case WM_CREATE:
{
RAWINPUTDEVICE rid[2];
rid[0].usUsagePage = 0x01;
rid[0].usUsage = 0x05;
rid[0].dwFlags = RIDEV_INPUTSINK;
rid[0].hwndTarget = hWnd;

rid[1].usUsagePage = 0x01;
rid[1].usUsage = 0x04;
rid[1].dwFlags = RIDEV_INPUTSINK;
rid[1].hwndTarget = hWnd;

if (!RegisterRawInputDevices(rid, 2, sizeof(rid[0])))
{
PostQuitMessage(0);
return 0;
}
}
case WM_INPUT:
{
UINT cbSize;
HRAWINPUT hRawInput = (HRAWINPUT)lParam;
GetRawInputData(hRawInput,RID_INPUT,0,&cbSize,sizeof(RAWINPUTHEADER));
LPBYTE lpbBuffer = new BYTE[cbSize];
GetRawInputData(hRawInput,RID_INPUT,lpbBuffer,&cbSize,sizeof(RAWINPUTHEADER));
RAWINPUT* raw = (RAWINPUT*)lpbBuffer;
if (lpbBuffer == NULL)
return 0;
if (raw->header.dwType == RIM_TYPEHID)
{
BYTE* test = new BYTE[raw->data.hid.dwCount * raw->data.hid.dwSizeHid];
test = &raw->data.hid.bRawData;

componentManager.gamepad.StateChange(0, test, raw->data.hid.dwCount * raw->data.hid.dwSizeHid);
}
return 0;
}
[/source]

This is my gamepad class:
Each byte of data held multiple values. I am sure there is a better way of getting the values, but this worked.
I subtracted 127 from the analog so I could have a +/- value versus a 0 to 255.
I also made 16 the deadzone radius for the analog.
They stored 4 button values and the directional pad in one byte.
The value was 8 when nothing was pressed.
The directional pad was a value 0-7 when pressed.
Button 1: 16
Button 2: 32
Button 3: 64
Button 4: 128
I divided by 16 and made that Byte b.
BYTE c = data[5] - b * 16.

This made c the remainder due to rounding.
If no direction button is held, c would be negative because 8 would round up when divided by 16 due to the variable being a BYTE. So when multiplied by 16, it would be a number greater than data[5].
Otherwise, c would be 0-7.

[source=cpp]
void Gamepad::StateChange(int aPlayer, BYTE* data, int aSize)
{
if (player[aPlayer].type == 0)
{
player[aPlayer].analog[0].x = data[1] - 127;
player[aPlayer].analog[0].y = data[2] - 127;
player[aPlayer].analog[1].x = data[3] - 127;
player[aPlayer].analog[1].y = data[4] - 127;
if (player[aPlayer].analog[0].x < 17 && player[aPlayer].analog[0].x > -17) player[aPlayer].analog[0].x = 0;
if (player[aPlayer].analog[0].y < 17 && player[aPlayer].analog[0].y > -17) player[aPlayer].analog[0].y = 0;
if (player[aPlayer].analog[1].x < 17 && player[aPlayer].analog[1].x > -17) player[aPlayer].analog[1].x = 0;
if (player[aPlayer].analog[1].y < 17 && player[aPlayer].analog[1].y > -17) player[aPlayer].analog[1].y = 0;
bool a[4];
BYTE b = data[5] / 16;
BYTE c = data[5] - b * 16;
a[3] = (b >= 8);
if (a[3]) b -= 8;
a[2] = (b >= 4);
if (a[2]) b -= 4;
a[1] = (b >= 2);
if (a[1]) b -= 2;
a[0] = (b >= 1);
if (a[0]) b -= 1;
player[aPlayer].button[0] = a[0];
player[aPlayer].button[1] = a[1];
player[aPlayer].button[2] = a[2];
player[aPlayer].button[3] = a[3];
switch (c)
{
case(0):
player[aPlayer].POV.x = 0;
player[aPlayer].POV.y = 1;
break;
case(1):
player[aPlayer].POV.x = 1;
player[aPlayer].POV.y = 1;
break;
case(2):
player[aPlayer].POV.x = 1;
player[aPlayer].POV.y = 0;
break;
case(3):
player[aPlayer].POV.x = 1;
player[aPlayer].POV.y = -1;
break;
case(4):
player[aPlayer].POV.x = 0;
player[aPlayer].POV.y = -1;
break;
case(5):
player[aPlayer].POV.x = -1;
player[aPlayer].POV.y = -1;
break;
case(6):
player[aPlayer].POV.x = -1;
player[aPlayer].POV.y = 0;
break;
case(7):
player[aPlayer].POV.x = -1;
player[aPlayer].POV.y = 1;
break;
case(8):
player[aPlayer].POV.x = 0;
player[aPlayer].POV.y = 0;
break;
}
}
}
void Gamepad::UpdateGamepad()
{
for (unsigned aPlayer = 0; aPlayer < 4; aPlayer++)
{

for (unsigned count = 0; count < 12; count++)
{
if (player[aPlayer].button[count] == true && player[aPlayer].prevButton[count] == false) player[aPlayer].buttonState[count] = 1; //just hit
else if (player[aPlayer].button[count] == true && player[aPlayer].prevButton[count] == true) player[aPlayer].buttonState[count] = 2; //held
else if (player[aPlayer].button[count] == false && player[aPlayer].prevButton[count] == true) player[aPlayer].buttonState[count] = 3; //just let go
else player[aPlayer].buttonState[count] = 0; //up
player[aPlayer].prevButton[count] = player[aPlayer].button[count];
}

}
}
[/source]

After all the windows messaging is completed, UpdateGamepad() is called. This updates the button state by comparing it to the previous button state. Then all the previous button states are made equal to the current. This is done for all 4 potential players.
2 likes 0 comments

Comments

Nobody has left a comment. You can be the first!
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement
Advertisement