Jump to content
  • Advertisement
Sign in to follow this  
  • entries
    14
  • comments
    9
  • views
    13145

Raw Input API

Sign in to follow this  
JD_Rushing

2424 views

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.
Sign in to follow this  


0 Comments


Recommended Comments

There are no comments to display.

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
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!