on 28-04-2012 05:40 PM
The simulator's input layout and limitations weren't to my taste, so I made myself a way around it:
Run a TCP server that reads PC's gamepad state and sends it back on a client request. And add a simple utility class/lib to connect to that server + decode data transparently from within the game. With a one-line change to revert-back to using the native input on real devices.
Uploaded here: http://dl.dropbox.com/u/1969613/openglForum/PadSer
Code to use:
static ILXPAD pad1 = new ILXPAD_Net(); //static ILXPAD pad1 = new ILXPAD_Vita(); ... pad1.start(); ... pad1.update(); ... camera.roty -= pad1.RStick.X; bool jump = pad1.Cur.CROSS;
Cheers. ![]()
on 28-04-2012 07:02 PM
Nice!
on 18-05-2012 02:42 AM
I as well have written something to make my 360 controller work with the emulator.
It's a simple app which translates a button press on the controller to a keyboard press in the emulator, no code changes to the game required.
But this is a quite interesting solution as well!
on 03-06-2012 04:56 PM
Hey guys. I modified this to work out of the box with a 360 controller for Cobalt Runner.
Needed some small changes to both the server binary and the C# side of things. Figured I'd drop it off here so if anyone else needs it they can use it ![]()
on 08-06-2012 08:43 PM
Thanks to the guys who wrote this. I finally got a good Windows driver for my DualShock and had a chance to use this code.
I rewrote the C# side to produce the same GamePadData output as the native GetData() method. My version doesn't deal with the Pressed and Released states yet but it seems to work well.
I included translators for two different DS3 drivers using the original c++ padserver exe from the original poster. I'd like to include the XBox 360 at some point as well. It would be great if someone who's good with C++ could rewrite the server to compile with VS2010.
usage:
private GamepadReader gpadReader; gpadReader = new GamepadReader(ControllerTypes.SonySixaxis); gpadReader.OpenChannel(); GamePadData data = gpadReader.GetData(); gpadReader.CloseChannel(); gpadReader.Dispose();
c# code:
using System;
using System.Net;
using System.Net.Sockets;
using Sce.Pss.Core.Input;
namespace PsmFramework.Engines.PadServer
{
public class GamepadReader : IDisposable
{
#region Constructor, Dispose
public GamepadReader(ControllerTypes controllerType)
{
Initialize(controllerType);
}
public void Dispose()
{
Cleanup();
}
#endregion
#region Initialize, Cleanup
private void Initialize(ControllerTypes controllerType)
{
InitializeControllerType(controllerType);
InitializeTcpip();
InitializeChannel();
}
private void Cleanup()
{
CleanupChannel();
CleanupTcpip();
CleanupControllerType();
}
#endregion
#region Controller Type
private void InitializeControllerType(ControllerTypes controllerType)
{
ControllerType = controllerType;
}
private void CleanupControllerType()
{
}
public ControllerTypes ControllerType { get; set; }
#endregion
#region TcpIp
private void InitializeTcpip()
{
TcpipAddress = IPAddress.Parse(TcpipAddressStr);
TcpipEndPoint = new IPEndPoint(TcpipAddress, TcpipPort);
}
private void CleanupTcpip()
{
TcpipAddress = null;
TcpipEndPoint = null;
}
public static String TcpipAddressStr = "127.0.0.1";
private IPAddress TcpipAddress;
public static Int32 TcpipPort = 1777;
private IPEndPoint TcpipEndPoint;
protected Socket TcpipSocket;
#endregion
#region Channel
private void InitializeChannel()
{
ChannelState = ChannelStates.Closed;
RequestMessage = new Byte[] { (Byte)'i' };
CloseMessage = new Byte[1] { (Byte)'s' };
IncomingDataBuffer = new Byte[IncomingMessageLength];
}
private void CleanupChannel()
{
if(ChannelState != ChannelStates.Closed)
CloseChannel();
RequestMessage = new Byte[0];
CloseMessage = new Byte[0];
}
public void OpenChannel()
{
if(ChannelState != ChannelStates.Closed)
throw new InvalidOperationException();
TcpipSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
TcpipSocket.Connect(TcpipEndPoint);
ChannelState = ChannelStates.Open;
}
catch(SocketException e)
{
TcpipSocket = null;
throw new InvalidOperationException("Unable to access PadServer over TCP/IP.", e);
}
}
public void CloseChannel()
{
if(ChannelState != ChannelStates.Open)
throw new InvalidOperationException();
if(TcpipSocket != null)
{
TcpipSocket.Send(CloseMessage);
TcpipSocket.Shutdown(SocketShutdown.Both);
TcpipSocket.Close();
TcpipSocket.Dispose();
TcpipSocket = null;
}
ChannelState = ChannelStates.Closed;
}
private void ReadDataFromChannel()
{
if(ChannelState != ChannelStates.Open)
throw new InvalidOperationException();
if(TcpipSocket == null)
throw new InvalidOperationException();
TcpipSocket.Send(RequestMessage);
TcpipSocket.Receive(IncomingDataBuffer);
Int32 incomingDataSize = BitConverter.ToInt32(IncomingDataBuffer, 0);
if(incomingDataSize != IncomingMessageLength)
throw new InvalidOperationException("Invalid data received from PadServer.");
}
public ChannelStates ChannelState { get; private set; }
private Byte[] RequestMessage;
private Byte[] IncomingDataBuffer;
private Byte[] CloseMessage;
private const Int32 IncomingMessageLength = 24;
#endregion
#region GetData
public GamePadData GetData()
{
ReadDataFromChannel();
GamePadData gpd = new GamePadData();
gpd.AnalogLeftX = BitConverter.ToSingle(IncomingDataBuffer, 4);
gpd.AnalogLeftY = BitConverter.ToSingle(IncomingDataBuffer, 8);
gpd.AnalogRightX = BitConverter.ToSingle(IncomingDataBuffer, 12);
gpd.AnalogRightY = BitConverter.ToSingle(IncomingDataBuffer, 16);
RawButtonData = BitConverter.ToUInt32(IncomingDataBuffer, 20);
//The order of button decoding is important here.
switch(ControllerType)
{
case ControllerTypes.SonySixaxis:
if(ReadNextRawButtonValue())
gpd.Buttons = GamePadButtons.Triangle;
if(ReadNextRawButtonValue())
gpd.Buttons = GamePadButtons.Circle;
if(ReadNextRawButtonValue())
gpd.Buttons = GamePadButtons.Cross;
if(ReadNextRawButtonValue())
gpd.Buttons = GamePadButtons.Square;
if(ReadNextRawButtonValue())
{
//L2, do nothing.
}
if(ReadNextRawButtonValue())
{
//R2, do nothing.
throw new InvalidOperationException();
}
if(ReadNextRawButtonValue())
gpd.Buttons = GamePadButtons.L;
if(ReadNextRawButtonValue())
gpd.Buttons = GamePadButtons.R;
if(ReadNextRawButtonValue())
gpd.Buttons = GamePadButtons.Start;
if(ReadNextRawButtonValue())
gpd.Buttons = GamePadButtons.Select;
if(ReadNextRawButtonValue())
{
//L3, do nothing.
}
if(ReadNextRawButtonValue())
{
//R3, do nothing.
}
if(ReadNextRawButtonValue())
gpd.Buttons = GamePadButtons.Left;
if(ReadNextRawButtonValue())
gpd.Buttons = GamePadButtons.Right;
if(ReadNextRawButtonValue())
gpd.Buttons = GamePadButtons.Up;
if(ReadNextRawButtonValue())
gpd.Buttons = GamePadButtons.Down;
break;
case ControllerTypes.MotionInJoy:
if(ReadNextRawButtonValue())
gpd.Buttons = GamePadButtons.Triangle;
if(ReadNextRawButtonValue())
gpd.Buttons = GamePadButtons.Circle;
if(ReadNextRawButtonValue())
gpd.Buttons = GamePadButtons.Cross;
if(ReadNextRawButtonValue())
gpd.Buttons = GamePadButtons.Square;
if(ReadNextRawButtonValue())
{
//L2, do nothing.
}
if(ReadNextRawButtonValue())
{
//R2, do nothing.
throw new InvalidOperationException();
}
if(ReadNextRawButtonValue())
gpd.Buttons = GamePadButtons.L;
if(ReadNextRawButtonValue())
gpd.Buttons = GamePadButtons.R;
if(ReadNextRawButtonValue())
gpd.Buttons = GamePadButtons.Select;
if(ReadNextRawButtonValue())
gpd.Buttons = GamePadButtons.Start;
if(ReadNextRawButtonValue())
{
//L3, do nothing.
}
if(ReadNextRawButtonValue())
{
//R3, do nothing.
}
if(ReadNextRawButtonValue())
gpd.Buttons = GamePadButtons.Left;
if(ReadNextRawButtonValue())
gpd.Buttons = GamePadButtons.Right;
if(ReadNextRawButtonValue())
gpd.Buttons = GamePadButtons.Up;
if(ReadNextRawButtonValue())
gpd.Buttons = GamePadButtons.Down;
break;
default:
throw new InvalidProgramException("Unknown controller type.");
break;
}
return gpd;
}
private Boolean ReadNextRawButtonValue()
{
Boolean pressed = (RawButtonData & 1) != 0;
RawButtonData >>= 1;
return pressed;
}
private UInt32 RawButtonData;
#endregion
}
public enum ControllerTypes
{
SonySixaxis,
MotionInJoy,
Xbox360
}
public enum ChannelStates
{
Open,
Closed
}
}
on 08-06-2012 09:59 PM
All of the if statements in the GetData() code above should be changed to add "gpd.Buttons |":
if(ReadNextRawButtonValue()) gpd.Buttons = gpd.Buttons | GamePadButtons.Down;
Sorry for the confusion.
on 11-06-2012 03:31 PM
My server build works with the 360 pad. What else do you need?
In any case, here's the main.cpp with some slight modifications. This should compile under VS2010.
The important stuff is the first few lines that include libs and change the order of the header file inclusion. I can't remember if this is my main.cpp that is designed to support the 360 pad or not.
/*
Gamepad server for PSS
By ultrano#ho tma il#com
Requires a connected gamepad to the PC, and preferably it's a dualshock2 with PS2->USB converter,
or a dualshock3 (didn't try with the latter).
Supplies more buttons than the Vita, for more freedom of control when developing. Extend on this when you need.
Compile with:
g++ -c -o main.o ..\main.cpp
g++ -o PadServer.exe main.o -lws2_32 -lwinmm
*/
#pragma comment(lib, "Winmm.lib")
#pragma comment(lib, "Ws2_32.lib")
#include <WinSock2.h>
#include <windows.h>
#include <stdio.h>
bool exitserver=false;
SOCKET server;
typedef unsigned char U8;
typedef unsigned int U32;
struct vec2{
float x,y;
};
enum ILXGPBUTTONS{
TRIANGLE,CIRCLE,CROSS,SQUARE,L2,R2,L1,R1,SELECT,ST ART,L3,R3,LEFT,RIGHT,UP,DOWN
};
struct PAD{
int size;
vec2 LStick;
vec2 RStick;
U32 buttons;
};
PAD ILXPad1 ={0};
static void ILXUpdateGamepad(){
JOYINFOEX t;
PAD j;
memset(&t,0,sizeof(t));
memset(&j,0,sizeof(j));
t.dwSize=sizeof(JOYINFOEX);
t.dwFlags=JOY_RETURNALL;
if(JOYERR_NOERROR==joyGetPosEx(JOYSTICKID1,&t)){
j.size = sizeof(j);
j.LStick.x = (t.dwXpos - 32767.0f)/32767.0f;
j.LStick.y = (t.dwYpos - 32767.0f)/32767.0f;
j.RStick.y = (t.dwRpos - 32767.0f)/32767.0f;
j.RStick.x = (t.dwUpos - 32767.0f)/32767.0f;
j.buttons = t.dwButtons;
#define fixup(what) if(what> -0.2f && what<0.2f)what=0; else if(what<-1.0f)what= -1.0f; else if(what>1.0f)what= 1.0f;
fixup(j.LStick.x);
fixup(j.LStick.y);
fixup(j.RStick.x);
fixup(j.RStick.y);
#undef fixup
if(t.dwPOV==27000)j.buttons |= 1 << LEFT;
if(t.dwPOV==9000 )j.buttons |= 1 << RIGHT;
if(t.dwPOV==0 )j.buttons |= 1 << UP;
if(t.dwPOV==18000)j.buttons |= 1 << DOWN;
}
#if 0
for(int i=0;i<16;i++){
U8 b1,b2,b3;
b1 = ILXPad1.buttons[i];
b2 = j.buttons[i];
b3 = ILXPad1.repeat[i];
if(b1 && b2){
if(b3<255)b3++;
j.repeat[i]=b3;
}
j.newbuttons[i] = (b1^b2)&b2;
j.buttons[i]=b2;
}
#endif
memcpy(&ILXPad1,&j,sizeof(j));
}
DWORD WINAPI ServerThread(LPVOID pParam)
{
WSADATA wsaData;
sockaddr_in local;
int wsaret=WSAStartup(0x101,&wsaData);
if(wsaret!=0){
return 0;
}
local.sin_family=AF_INET; //Address family
local.sin_addr.s_addr=INADDR_ANY; //Wild card IP address
local.sin_port=htons((u_short)1777); //port to use
server=socket(AF_INET,SOCK_STREAM,0);
if(server==INVALID_SOCKET)
{
return 0;
}
if(bind(server,(sockaddr*)&local,sizeof(local))!=0 )
{
return 0;
}
if(listen(server,10)!=0)
{
return 0;
}
SOCKET client;
sockaddr_in from;
int fromlen=sizeof(from);
printf("server started\n");
fflush(stdout);
while(!exitserver)
{
char indata;
client=accept(server, (struct sockaddr*)&from,&fromlen);
printf("client connected. Press q to exit, s to stop\n");
fflush(stdout);
for(;
{
indata = 0;
recv(client,&indata,1,0);
if(!indata)break;
if(indata=='s')break;
if(indata=='q'){ exitserver=true; break;}
ILXUpdateGamepad();
send(client,(char*)&ILXPad1,sizeof(ILXPad1),0);
}
closesocket(client);
printf("client gone\n");
fflush(stdout);
}
return 0;
}
int main(){
printf("Starting server at port 1777...\n");
#if 0
DWORD tid;
CreateThread(0,0,ServerThread,0,0,&tid);
for(;
{
printf("Press q to exit:\n");
char c = getchar();
if(c=='q')break;
}
#else
ServerThread(0);
#endif
exitserver = true;
closesocket(server);
WSACleanup();
return 0;
}
on 11-06-2012 04:20 PM
Hey, mainly I need a xbox controller to test it with.
Thanks for your code. The forum software replaced some bits with emoticons. Any chance you could fix those?
Hopefully Sony's going to bake gamepad support directly in the PSS in the future.
on 12-06-2012 02:03 AM
The main changes to make it compile on VS2010 are right here:
#pragma comment(lib, "Winmm.lib") #pragma comment(lib, "Ws2_32.lib") #include <WinSock2.h> #include <windows.h> #include <stdio.h>
Just copy and paste that, replacing the old include directives, into the OP's source (For the old layout) or my downloadable source (For the 360 layout).
on 08-02-2013 07:48 PM
that's great but.. how can i make it run with my PS Mobile studio??? what should i do?
PSM Developer Registration (for free) on PSM DevPortal is required to post on the forum.
Please sign out then sign in again to the forum and PSM DevPortal after you have completed the registration.
フォーラムへ投稿をするにはPSM DevPortalへの登録(無料)が必要です。
登録後はフォーラムと
PSM DevPortalを一度ログアウトし、再度ログインしてください。


Website ©2013 Sony Computer Entertainment Europe
All content, game titles, trade names and/or trade dress, trademarks, artwork and associated imagery are trademarks and/or copyright material of their respective owners. All rights reserved. [more info]
%%http://community.eu.playstation.com/t5/Announcements/Beta-Trial-Information/td-p/11386362
best_shooter.png%%http://community.eu.playstation.com/t5/Announcements/Introducing-Best-of-PlayStation/td-p/13741979
best_driver.png%%http://community.eu.playstation.com/t5/Announcements/Introducing-Best-of-PlayStation/td-p/13741979
best_performer.png%%http://community.eu.playstation.com/t5/Announcements/Introducing-Best-of-PlayStation/td-p/13741979
best_footballer.png%%http://community.eu.playstation.com/t5/Announcements/Introducing-Best-of-PlayStation/td-p/13741979
best_fighter.png%%http://community.eu.playstation.com/t5/Announcements/Introducing-Best-of-PlayStation/td-p/13741979
best_creator.png%%http://community.eu.playstation.com/t5/Announcements/Introducing-Best-of-PlayStation/td-p/13741979
best_action_player.png%%http://community.eu.playstation.com/t5/Announcements/Introducing-Best-of-PlayStation/td-p/13741979
dev2.png%%http://community.eu.playstation.com/t5/Website-and-Forum-Help-Feedback/Producer-and-Developer-Ranks/td-p/18407352
trophy.gif%%http://community.eu.playstation.com/t5/Website-and-Forum-Help-Feedback/The-Community-Awards-FAQ/td-p/18407096
PSlogoSM.png%%http://community.eu.playstation.com/t5/Website-and-Forum-Help-Feedback/Online-Support-Coordinator-rank/td-p/18414870