Using this code in Ruby I've managed to get the XINPUT_STATE while an Xbox 360 controller is plugged in. I've done several tests while moving the left and right analog sticks and pressing several buttons.
require "Win32API"
module GamePad
@set = Win32API.new("xinput1_3", "XInputSetState", "IP", "V")
def self.test
@get = Win32API.new("xinput1_3", "XInputGetState", "IP", "L")
state = "\0" * 256
@get.call(0, state)
p state.unpack("C*")
end
end
GamePad.test
gets
exit
After unpacking the pointer, I discovered that the first slot in the array seems to be the Left analog stick. I've also discovered that the Start and Back button share the 5th slot. Start's value is 16 while Back's value is 32. Hold both of them together the value becomes 48. The 6th slot are the left and right bumpers. Left being 1 and Right being 2. In fact I'm positive all buttons besides the Start and Select are on the 6th slot. So I've managed to successfully use the GetState but now I want to use the SetState function to be able to use the Vibration control. And since I need to pass an actual Vibration structure as a parameter I'm completely lost.
As far as my experimenting is going, it seems to be going well. My overall goal is to see how well I can get the xbox controller to work with Ruby.
Also discovered the directional pad is in the 5 slot. It seems the XINPUT_STATE only has 16 values. It doesn't seem to be generating anything past that.
Dude! Baller.
So I created a dynamic library. Here's the main file.
#include "stdafx.h"
#include <cstdlib>
#include <ctime>
#include <ctype.h>
#include <math.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include "XboxC.h"
CXBOXController* controller;
extern "C" _declspec (dllexport) BOOL Vibrate(int player, long left, long right)
{
controller = new CXBOXController(player);
controller->Vibrate(left, right);
return true;
}
extern "C" _declspec (dllexport) BOOL Connected(int player)
{
controller = new CXBOXController(player);
return controller->IsConnected();
}
Then I have my CXBOXController header and class files with simple functions to handle XInput and its structures, making it easy to use with Ruby. In order to actually use this you need the DirectX SDK installed since it has the XInput.dll. Oh and this ruby snippet set off the vibration in my controller.
module GamePad
@vibrate = Win32API.new("RGSSXbox.dll", "Vibrate", "ILL", "V")
def self.vibrate(left, right)
@vibrate.call(1, left, right)
end
end
GamePad.vibrate(65355, 65355)
*scratches head* Why don't you look up on the Internet how XInput works and it used? I've implemented XInput in C++ 2 months ago and it took me a day with the proper documentation I found online.
I have been. I was trying to implement it into Ruby using Win32API calls. Which really wasn't going to work in the long run so I realized I needed to create my own library to basically manage things between XInput and Ruby using exported functions. And the fact C++ is finally making some sense to me. Its sill confusing to me in every aspect but bits and pieces are coming.
That sounds great. :) Keep working. Though, it'd be a lot more useful if you would work on the Python portion of ARC right now as I have most of the C++ code done already. >_>
Quote from: Blizzard on September 17, 2011, 03:28:29 am
That sounds great. :) Keep working. Though, it'd be a lot more useful if you would work on the Python portion of ARC right now as I have most of the C++ code done already. >_>
Always ruining my fun...:V I'll do some python work tomorrow and have Ryex set me on some tasks. I'm probably the most useless member right now. xD
Quote from: game_guy on September 17, 2011, 03:32:23 am
I'll do some python work tomorrow and have Ryex set me on some tasks. I'm probably the most useless member right now. xD
you said it not me. I've actually been
wanting to say that but didn't want to be a hypocrite. after all I basically didn't work on it for 4 months.
So I was messing around with this even more. I managed to get Input.press? done and Input.trigger? done for gamepad input. The trigger was tricky but I did finally get it. However, I'm curious if the way I did it is efficient so if someone could maybe over look this? Basically XInput doesn't have a trigger. It just tells you if the button is being pressed or not. What I basically did was check to see if the button has been pressed. It then won't update until its been released.
Here's the variables I have.
module GamePad
@vibrate = Win32API.new("RGSSXbox.dll", "Vibrate", "ILL", "V")
@connected = Win32API.new("RGSSXbox.dll", "Connected", "I", "L")
@pressed = Win32API.new("RGSSXbox.dll", "Pressed", "II", "L")
@duration = [0, 0, 0, 0]
@triggered = {}
end
Here's the trigger code.
def self.trigger?(player, button)
return false if @triggered[button] == true
press = @pressed.call(player, button)
if press > 0
@triggered[button] = true
return true
end
return false
end
Then here's the update method.
def self.update
@duration.each_index{|i|
if @duration[i] >= 0
@duration[i] -= 1
self.stop(i + 1) if @duration[i] <= 0
end}
@triggered.each_key {|button|
if @triggered[button] == true
trigger = @pressed.call(1, button)
@triggered[button] = false if trigger == 0
end}
end
But all in all, this works. :naughty:
if GamePad.trigger?(GamePad::A)
# insert naughty stuff here
end
Here's the full GamePad module + a modified Input module.
module GamePad
DPAD_UP = 0x00000001
DPAD_DOWN = 0x00000002
DPAD_LEFT = 0x00000004
DPAD_RIGHT = 0x00000008
START = 0x00000010
BACK = 0x00000020
LEFT_THUMB = 0x00000040
RIGHT_THUMB = 0x00000080
LEFT_SHOULDER = 0x0100
RIGHT_SHOULDER = 0x0200
A = 0x1000
B = 0x2000
X = 0x4000
Y = 0x8000
Keys = {
Input::C => GamePad::A,
Input::B => GamePad::B,
Input::DOWN => GamePad::DPAD_DOWN,
}
@vibrate = Win32API.new("RGSSXbox.dll", "Vibrate", "ILL", "V")
@connected = Win32API.new("RGSSXbox.dll", "Connected", "I", "L")
@pressed = Win32API.new("RGSSXbox.dll", "Pressed", "II", "L")
@duration = [0, 0, 0, 0]
@triggered = {}
def self.vibrate(player, left, right, duration = 0)
player = player.clamp(1, 4)
@vibrate.call(player, left, right)
@duration[player - 1] = duration * 40 if duration > 0
end
def self.stop(player)
player = player.clamp(1, 4)
@vibrate.call(player, 0, 0)
end
def self.update
@duration.each_index{|i|
if @duration[i] >= 0
@duration[i] -= 1
self.stop(i + 1) if @duration[i] <= 0
end}
@triggered.each_key {|button|
if @triggered[button] == true
trigger = @pressed.call(1, button)
@triggered[button] = false if trigger == 0
end}
end
def self.pressed?(player, button)
bool = @pressed.call(player, button)
if bool == 0
return false
else
return true
end
end
def self.trigger?(player, button)
return false if @triggered[button] == true
press = @pressed.call(player, button)
if press > 0
@triggered[button] = true
return true
end
return false
end
end
module Input
class << self
alias gg_upd_input_gamepad_lat update
alias gg_upd_input_dir4_lat dir4
alias gg_upd_input_trigger_lat trigger?
end
def self.trigger?(button)
if GamePad::Keys[button] != nil
return true if GamePad.trigger?(1, GamePad::Keys[button])
end
return gg_upd_input_trigger_lat(button)
end
def self.update
gg_upd_input_gamepad_lat
GamePad.update
end
def self.dir4
if GamePad.pressed?(1, GamePad::DPAD_DOWN)
return 2
elsif GamePad.pressed?(1, GamePad::DPAD_LEFT)
return 4
elsif GamePad.pressed?(1, GamePad::DPAD_RIGHT)
return 6
elsif GamePad.pressed?(1, GamePad::DPAD_UP)
return 8
end
return gg_upd_input_dir4_lat
end
end
This is pretty freaking awesome. I'm looking forward to you getting this done. ;)
Thanks! Oh and I just got multi-button presses figured out too. First I fixed a few mistakes I had with the button checking. But you can check multiple buttons like so.
if GamePad.trigger?(GamePad::A + GamePad::B)
#code here
end
It'll only execute if A and B are both pressed. Working in GamePad.repeat? right now. After that its analog sticks time. Been having trouble with those.