Jump to content

  • Log In with Google      Sign In   
  • Create Account

Banner advertising on our site currently available from just $5!


1. Learn about the promo. 2. Sign up for GDNet+. 3. Set up your advert!






Raw Input API

Posted by JD_Rushing, 05 December 2013 · 577 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
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;
}


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.

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];
}

}
}


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.




May 2015 »

S M T W T F S
     12
3 4 56789
10111213141516
17181920212223
24252627282930
31      

Recent Entries

Recent Comments

PARTNERS