Jump to content

XInput / Gamepad support? [Solved]


Kraxie
 Share

Recommended Posts

Hi!

 

So, I have been looking around for a way to make a controller or gamepad work in Leadwerks, but most of the posts here seems to be outdated...

 

Have anyone actually got this working right?

 

Thanks!

Regards, KraXarN

Windows 7 | Intel Core i7-4790K | 16 GB RAM | Nvidia GTX 980

Link to comment
Share on other sites

I've been writing a c++ class using SDL in the last few days and it's almost finished. There were issues with my xbox controller, keys aren't mapped the same as regular controllers but i managed to fix it and implement a button mapping feature and now it behaves like normal controllers. It can automatically re-acquire controllers that are unplugged/replugged.

 

I will post the code once i'ts done, after that, i'll add lua support.

  • Upvote 1
Link to comment
Share on other sites

Here's the game controller class i just finished. Copy the SDL folder in your source directory (currently SDL2-2.0.3). Include SDL2.lib in your project and copy SDL2.DLL in the same folder as your executable.

 

Edit:

Added 2 parameters in the init method to enable/disable auto reacquire.

 

 

App.h

#pragma once
#include "Leadwerks.h"
#include "Game_Controller.h"


using namespace Leadwerks;

class App
{
public:
Leadwerks::Window* window;
Context* context;
World* world;
Camera* camera;

Game_Controller* joysticks[8];

App();
virtual ~App();

virtual bool Start();
virtual bool Loop();
};

 

 

 

App.cpp

#include "App.h"

using namespace Leadwerks;
App::App() : window(NULL), context(NULL), world(NULL), camera(NULL) {}
App::~App() { delete world; delete window; }

bool App::Start()
{
window = Leadwerks::Window::Create("Joystick");
context = Context::Create(window);
world = World::Create();
camera = Camera::Create();
window->HideMouse();

if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
{
System::Print("Unable to init joystick system");
}
else
{
joysticks[0] = new Game_Controller();
if (joysticks[0]->Init(0, 15000, true, true))
{
System::Print("** Using joystick : " + joysticks[0]->GetName());
}
}

window->ShowMouse();

return true;
}

bool App::Loop()
{
//Close the window to end the program
if (window->KeyDown(Key::Escape))
return false;


if (joysticks[0])
{
joysticks[0]->ProcessEvents();

if (joysticks[0]->AXIS_UP) System::Print("AXIS UP ; " + std::to_string(joysticks[0]->axis_y));
if (joysticks[0]->AXIS_DOWN) System::Print("AXIS DOWN ; " + std::to_string(joysticks[0]->axis_y));
if (joysticks[0]->AXIS_LEFT) System::Print("AXIS LEFT ; " + std::to_string(joysticks[0]->axis_x));
if (joysticks[0]->AXIS_RIGHT) System::Print("AXIS RIGHT ; " + std::to_string(joysticks[0]->axis_x));
if (joysticks[0]->DPAD_UP) System::Print("DPAD UP");
if (joysticks[0]->DPAD_DOWN) System::Print("DPAD DOWN");
if (joysticks[0]->DPAD_LEFT) System::Print("DPAD LEFT");
if (joysticks[0]->DPAD_RIGHT) System::Print("DPAD RIGHT");

for (int b = 0; b < sizeof(joysticks[0]->Button) / sizeof(*joysticks[0]->Button); b++) {
if (joysticks[0]->Button[b] == true) {
System::Print("Button pressed: " + std::to_string(B));
}
}

if (joysticks[0]->trigger_left > 0)
System::Print("Trigger left: " + std::to_string(joysticks[0]->trigger_left));
if (joysticks[0]->trigger_right > 0)
System::Print("Trigger right: " + std::to_string(joysticks[0]->trigger_right));

}




Leadwerks::Time::Update();
world->Update();
world->Render();
context->Sync(false);

return true;
}

 

 

 

Game_Controller.h

/*
Game controller class using SDL2
- Added better support for XInput.
- Button remapping.
- Automatic re-acquiring when controller is unplugged/replugged.

Download SDL2 and copy the SDL2-2.0.3 folder in your Source directory.
Add SDL2.lib to your project and copy SDL2.dll where your executable is.
*/



#include "Leadwerks.h"
#include "SDL2-2.0.3/include/SDL.h"
#undef main



class Game_Controller {
private:
SDL_Joystick*	 m_joy;
SDL_Event		 m_event;
uint8			 m_total_joysticks;
uint8			 m_index;
std::string	 m_name;
int16			 m_threshold;
bool			 m_xinput;
uint8			 m_mapped_buttons[32];
bool			 m_auto_reacquire;
bool			 m_reacquire_alternate_controller;


uint8 FindControllerByName(std::string controller_name) {
SDL_JoystickUpdate();

int8 alternate_controller = -1;
for (int c = 0; c < SDL_NumJoysticks(); c++) {
SDL_Joystick* joy = SDL_JoystickOpen(c);
if (joy) {
if (SDL_JoystickName(joy) == m_name || controller_name == "") {
//System::Print("Joystick found, reacquiring " + m_name);
return c;
}
else if (m_reacquire_alternate_controller == true) {
if (alternate_controller == -1)
alternate_controller = c; // Use another controller if the one we're looking for can't be found //
}
SDL_JoystickClose(joy);
}
joy = NULL;
}

return alternate_controller;
}


public:
Game_Controller() { m_index = -1; }
~Game_Controller() { Close(); }

bool DPAD_UP, DPAD_DOWN, DPAD_LEFT, DPAD_RIGHT;
bool AXIS_UP, AXIS_DOWN, AXIS_LEFT, AXIS_RIGHT;
int16 axis_x, axis_y;
uint8 trigger_left, trigger_right;
bool Button[32];

bool Init(uint8 index, int16 axis_threshold, bool auto_require, bool reacquire_alternate_controller) {
if (index < 0 || index > SDL_NumJoysticks() - 1)
return false;

m_total_joysticks = SDL_NumJoysticks();
m_index = index;
m_threshold = axis_threshold;
m_xinput = false;
m_auto_reacquire = auto_require;
m_reacquire_alternate_controller = reacquire_alternate_controller;

DPAD_UP = false, DPAD_DOWN = false, DPAD_LEFT = false, DPAD_RIGHT = false;
AXIS_UP = false, AXIS_DOWN = false, AXIS_LEFT = false, AXIS_RIGHT = false;

for (int b = 0; b < sizeof(Button) / sizeof(*Button); b++) {
Button[b] = false;
m_mapped_buttons[b] = b;
}

trigger_left = 0;
trigger_right = 0;
axis_x = 0;
axis_y = 0;

if (m_joy)
m_joy = NULL;

SDL_JoystickEventState(SDL_ENABLE);
m_joy = SDL_JoystickOpen(index);
if (m_joy) {
m_name = SDL_JoystickName(m_joy);
if (m_name.length() > 0) {
if (m_name.find("XInput") == 0) { // XInput devices have different button mapping //
m_xinput = true;
m_mapped_buttons[5] = 8; // select
m_mapped_buttons[4] = 9; // start
m_mapped_buttons[8] = 4;
m_mapped_buttons[9] = 5;
m_mapped_buttons[10] = 0;
m_mapped_buttons[11] = 1;
m_mapped_buttons[13] = 2;
m_mapped_buttons[12] = 3;
}

}
return true;
}

return false;
}

bool Reacquire() {
m_total_joysticks = SDL_NumJoysticks();
Close();

if (m_auto_reacquire == true && m_total_joysticks > 0 && m_name.length() > 0) {
uint8 index = FindControllerByName(m_name);
if (index > -1) {
Init(index, m_threshold, m_auto_reacquire, m_reacquire_alternate_controller);
return true;
}
}
return false;
}

void Close() {
if (m_index > -1) {
if (m_joy) {
SDL_JoystickClose(m_joy);
m_joy = NULL;
}
}
}

std::string GetName() {
return m_name;
}


void ProcessEvents() {
SDL_JoystickUpdate();
if (SDL_NumJoysticks() != m_total_joysticks) // Controller changes detected, attempt to re-acquire //
Reacquire();


if (m_joy) {
if (SDL_JoystickGetAttached(m_joy)) {

while (SDL_PollEvent(&m_event))
{
switch (m_event.type) {
case SDL_JOYAXISMOTION:

//if (m_event.jaxis.which == m_index) {
if (m_event.jaxis.axis == 0) {
if (m_event.jaxis.value < -m_threshold) AXIS_LEFT = true;
if (m_event.jaxis.value > m_threshold) AXIS_RIGHT = true;
if (m_event.jaxis.value > -m_threshold && m_event.jaxis.value < m_threshold) {
AXIS_LEFT = false;
AXIS_RIGHT = false;
}
axis_x = m_event.jaxis.value;
}
if (m_event.jaxis.axis == 1) {
if (m_event.jaxis.value < -m_threshold) AXIS_UP = true;
if (m_event.jaxis.value > m_threshold) AXIS_DOWN = true;
if (m_event.jaxis.value > -m_threshold && m_event.jaxis.value < m_threshold) {
AXIS_UP = false;
AXIS_DOWN = false;
}
axis_y = m_event.jaxis.value;
}

//if (m_event.cbutton.which == m_index) {
if (m_event.cbutton.button == 4) {
Button[m_mapped_buttons[6]] = (m_event.button.button > 0); // Left trigger
trigger_left = m_event.button.button;
}
if (m_event.cbutton.button == 5) {
Button[m_mapped_buttons[7]] = (m_event.button.button > 0); // Right trigger
trigger_right = m_event.button.button;
}
//}
break;
//}

case SDL_JOYHATMOTION:
//if (m_event.jaxis.which == m_index) {
DPAD_UP = false;
DPAD_DOWN = false;
DPAD_LEFT = false;
DPAD_RIGHT = false;
if (m_event.jhat.value & SDL_HAT_UP) DPAD_UP = true;
if (m_event.jhat.value & SDL_HAT_DOWN) DPAD_DOWN = true;
if (m_event.jhat.value & SDL_HAT_LEFT) DPAD_LEFT = true;
if (m_event.jhat.value & SDL_HAT_RIGHT) DPAD_RIGHT = true;
//}
break;

 case SDL_JOYBUTTONDOWN:
//if (m_event.jaxis.which == m_index) {
if (m_xinput) {
if (m_event.jbutton.button < 4) { // Directional pad (hat) on Xbox controllers are recognized as buttons //
if (m_event.jbutton.button == 0) DPAD_UP = true;
if (m_event.jbutton.button == 1) DPAD_DOWN = true;
if (m_event.jbutton.button == 2) DPAD_LEFT = true;
if (m_event.jbutton.button == 3) DPAD_RIGHT = true;
}
else {
Button[m_mapped_buttons[m_event.jbutton.button]] = true;
}
}
else {
Button[m_mapped_buttons[m_event.jbutton.button]] = true;
}
//}
break;


 case SDL_JOYBUTTONUP:
//if (m_event.jaxis.which == m_index) {
if (m_xinput) {
if (m_event.jbutton.button < 4) {
if (m_event.jbutton.button == 0) DPAD_UP = false;
if (m_event.jbutton.button == 1) DPAD_DOWN = false;
if (m_event.jbutton.button == 2) DPAD_LEFT = false;
if (m_event.jbutton.button == 3) DPAD_RIGHT = false;
}
else {
Button[m_mapped_buttons[m_event.jbutton.button]] = false;
}
}
else {
Button[m_mapped_buttons[m_event.jbutton.button]] = false;
}
//}
break;

}

}

}

}

}

};

Edited by Skrakle
Link to comment
Share on other sites

I've been writing a c++ class using SDL in the last few days and it's almost finished. There were issues with my xbox controller, keys aren't mapped the same as regular controllers but i managed to fix it and implement a button mapping feature and now it behaves like normal controllers. It can automatically re-acquire controllers that are unplugged/replugged.

 

I will post the code once i'ts done, after that, i'll add lua support.

 

Thanks, but I'm using Lua, yea...

When you get Lua working, let me know tongue.png

Windows 7 | Intel Core i7-4790K | 16 GB RAM | Nvidia GTX 980

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...