pcsx2: zzogl:onepad: gsdx: merge linux-gsopen2 branch (4730) into trunk

* Gsopen2 support for GS plugins => Support of the PCSX2 GS window configuration panel. Support of all PCSX2 shortcut.
* new shortcut: shift-f12 to stole the input. ZZogl shortcut must be prefixed with ctrl
* onepad: Support/fix/improve of configuration gui, multiple key, mouse/wiimote for analog joystick, dualshock3/sixaxis (basic), dual pad and experimental forcefeedback

Note: it is advices to delete OnePAD.ini


git-svn-id: http://pcsx2.googlecode.com/svn/trunk@4731 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
gregory.hainaut@gmail.com 2011-06-12 14:48:36 +00:00
parent 0543f24466
commit 35b9dfce3f
32 changed files with 1691 additions and 1160 deletions

View File

@ -512,7 +512,9 @@ X11_CreateWindow(_THIS, SDL_Window * window)
int
X11_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
{
Window w = (Window) data;
// For me it is a bug -- Gregory
// Window w = (Window) data;
Window w = *(Window*) data;
window->title = X11_GetWindowTitle(_this, w);
@ -537,8 +539,12 @@ X11_GetWindowTitle(_THIS, Window xwindow)
0L, 8192L, False, data->UTF8_STRING, &real_type, &real_format,
&items_read, &items_left, &propdata);
if (status == Success) {
title = SDL_strdup(SDL_static_cast(char*, propdata));
XFree(propdata);
// Propdata can be null I do not know if it normal or not.
// At least handle gracefully and dont crash. -- Gregory
if (propdata) {
title = SDL_strdup(SDL_static_cast(char*, propdata));
XFree(propdata);
}
} else {
status = XGetWindowProperty(display, xwindow, XA_WM_NAME,
0L, 8192L, False, XA_STRING, &real_type, &real_format,

View File

@ -322,6 +322,11 @@ u32 CALLBACK PADquery();
// have to be added to maintain data integrity.
void CALLBACK PADupdate(int pad);
// Send a key event from wx-gui to pad
// Note: On linux GSOpen2, wx-gui and pad share the same event buffer. Wx-gui reads and deletes event
// before the pad saw them. So the gui needs to send them back to the pad.
void CALLBACK PADWriteEvent(keyEvent &evt);
// extended funcs
void CALLBACK PADgsDriverInfo(GSdriverInfo *info);
@ -603,6 +608,7 @@ typedef keyEvent* (CALLBACK* _PADkeyEvent)();
typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info);
typedef s32 (CALLBACK* _PADsetSlot)(u8 port, u8 slot);
typedef s32 (CALLBACK* _PADqueryMtap)(u8 port);
typedef void (CALLBACK* _PADWriteEvent)(keyEvent &evt);
// SPU2
typedef s32 (CALLBACK* _SPU2open)(void *pDsp);
@ -755,6 +761,7 @@ extern _PADkeyEvent PADkeyEvent;
extern _PADgsDriverInfo PADgsDriverInfo;
extern _PADsetSlot PADsetSlot;
extern _PADqueryMtap PADqueryMtap;
extern _PADWriteEvent PADWriteEvent;
// SPU2
extern _SPU2open SPU2open;

View File

@ -188,9 +188,9 @@ void SysMtgsThread::OpenPlugin()
int result;
if( GSopen2 != NULL )
result = GSopen2( (void*)&pDsp, 1 | (renderswitch ? 4 : 0) );
result = GSopen2( (void*)pDsp, 1 | (renderswitch ? 4 : 0) );
else
result = GSopen( (void*)&pDsp, "PCSX2", renderswitch ? 2 : 1 );
result = GSopen( (void*)pDsp, "PCSX2", renderswitch ? 2 : 1 );
// Vsync on / off ?
if( renderswitch )

View File

@ -252,6 +252,7 @@ _PADupdate PADupdate;
_PADkeyEvent PADkeyEvent;
_PADsetSlot PADsetSlot;
_PADqueryMtap PADqueryMtap;
_PADWriteEvent PADWriteEvent;
static void PAD_update( u32 padslot ) { }
@ -323,7 +324,7 @@ _FWirqCallback FWirqCallback;
DEV9handler dev9Handler;
USBhandler usbHandler;
uptr pDsp;
uptr pDsp[2];
static s32 CALLBACK _hack_PADinit()
{
@ -417,6 +418,7 @@ static const LegacyApi_ReqMethod s_MethMessReq_PAD[] =
static const LegacyApi_OptMethod s_MethMessOpt_PAD[] =
{
{ "PADupdate", (vMeth**)&PADupdate },
{ "PADWriteEvent", (vMeth**)&PADWriteEvent },
{ NULL },
};
@ -1058,12 +1060,12 @@ bool SysCorePlugins::OpenPlugin_GS()
bool SysCorePlugins::OpenPlugin_PAD()
{
return !PADopen( (void*)&pDsp );
return !PADopen( (void*)pDsp );
}
bool SysCorePlugins::OpenPlugin_SPU2()
{
if( SPU2open((void*)&pDsp) ) return false;
if( SPU2open((void*)pDsp) ) return false;
#ifdef ENABLE_NEW_IOPDMA_SPU2
SPU2irqCallback( spu2Irq );
@ -1079,7 +1081,7 @@ bool SysCorePlugins::OpenPlugin_DEV9()
{
dev9Handler = NULL;
if( DEV9open( (void*)&pDsp ) ) return false;
if( DEV9open( (void*)pDsp ) ) return false;
DEV9irqCallback( dev9Irq );
dev9Handler = DEV9irqHandler();
return true;
@ -1089,7 +1091,7 @@ bool SysCorePlugins::OpenPlugin_USB()
{
usbHandler = NULL;
if( USBopen((void*)&pDsp) ) return false;
if( USBopen((void*)pDsp) ) return false;
USBirqCallback( usbIrq );
usbHandler = USBirqHandler();
if( USBsetRAM != NULL )
@ -1099,7 +1101,7 @@ bool SysCorePlugins::OpenPlugin_USB()
bool SysCorePlugins::OpenPlugin_FW()
{
if( FWopen((void*)&pDsp) ) return false;
if( FWopen((void*)pDsp) ) return false;
FWirqCallback( fwIrq );
return true;
}
@ -1159,7 +1161,15 @@ void SysCorePlugins::Open()
// If GS doesn't support GSopen2, need to wait until call to GSopen
// returns to populate pDsp. If it does, can initialize other plugins
// at same time as GS, as long as GSopen2 does not subclass its window.
#ifdef __LINUX__
// On linux, application have also a channel (named display) to communicate with the
// Xserver. The safe rule is 1 thread, 1 channel. In our case we use the display in
// several places. Save yourself of multithread headache. Wait few seconds the end of
// gsopen -- Gregory
if (pi->id == PluginId_GS) GetMTGS().WaitForOpen();
#else
if (pi->id == PluginId_GS && !GSopen2) GetMTGS().WaitForOpen();
#endif
} while( ++pi, pi->shortname != NULL );
if (GSopen2) GetMTGS().WaitForOpen();

View File

@ -392,5 +392,5 @@ extern "C" const PS2E_LibraryAPI* FileMcd_InitAPI( const PS2E_EmulatorInfo* emui
// Per ChickenLiver, this is being used to pass the GS plugins window handle to the Pad plugins.
// So a rename to pDisplay is in the works, but it will not, in fact, be removed.
extern uptr pDsp;
extern uptr pDsp[2];

View File

@ -36,6 +36,14 @@
# include <wx/msw/wrapwin.h> // needed to implement the app!
#endif
#ifdef __WXGTK__
// Need to tranform the GSPanel to a X11 window/display for the GS plugins
#include <wx/gtk/win_gtk.h> // GTK_PIZZA interface
#include <gdk/gdkx.h>
#include <gtk/gtk.h>
#endif
IMPLEMENT_APP(Pcsx2App)
DEFINE_EVENT_TYPE( pxEvt_LoadPluginsComplete );
@ -862,12 +870,30 @@ void Pcsx2App::OpenGsPanel()
}
pxAssertDev( !GetCorePlugins().IsOpen( PluginId_GS ), "GS Plugin must be closed prior to opening a new Gs Panel!" );
pDsp = (uptr)gsFrame->GetViewport()->GetHandle();
#ifdef __WXGTK__
// The x window/display are actually very deeper in the widget. You need both display and window
// because unlike window there are unrelated. One could think it would be easier to send directly the GdkWindow.
// Unfortunately there is a race condition between gui and gs threads when you called the
// GDK_WINDOW_* macro. To be safe I think it is best to do here. It only cost a slight
// extension (fully compatible) of the plugins API. -- Gregory
GtkWidget *child_window = gtk_bin_get_child(GTK_BIN(gsFrame->GetViewport()->GetHandle()));
gtk_widget_realize(child_window); // create the widget to allow to use GDK_WINDOW_* macro
gtk_widget_set_double_buffered(child_window, false); // Disable the widget double buffer, you will use the opengl one
GdkWindow* draw_window = GTK_PIZZA(child_window)->bin_window;
Window Xwindow = GDK_WINDOW_XWINDOW(draw_window);
Display* XDisplay = GDK_WINDOW_XDISPLAY(draw_window);
pDsp[0] = (uptr)XDisplay;
pDsp[1] = (uptr)Xwindow;
#else
pDsp[0] = (uptr)gsFrame->GetViewport()->GetHandle();
pDsp[1] = NULL;
#endif
gsFrame->ShowFullScreen( g_Conf->GSWindow.IsFullscreen );
// The "in the main window" quickie hack...
//pDsp = (uptr)m_MainFrame->m_background.GetHandle();
}
void Pcsx2App::CloseGsPanel()

View File

@ -48,11 +48,11 @@ void GSPanel::InitDefaultAccelerators()
m_Accels->Map( AAC( WXK_F6 ), "GSwindow_CycleAspectRatio" );
m_Accels->Map( AAC( WXK_NUMPAD_ADD ).Cmd(), "GSwindow_ZoomIn" ); //CTRL on Windows (probably linux too), CMD on OSX
m_Accels->Map( AAC( WXK_NUMPAD_ADD ).Cmd(), "GSwindow_ZoomIn" ); //CTRL on Windows/linux, CMD on OSX
m_Accels->Map( AAC( WXK_NUMPAD_SUBTRACT ).Cmd(), "GSwindow_ZoomOut" );
m_Accels->Map( AAC( WXK_NUMPAD_MULTIPLY ).Cmd(), "GSwindow_ZoomToggle" );
m_Accels->Map( AAC( WXK_NUMPAD_ADD ).Cmd().Alt(), "GSwindow_ZoomInY" ); //CTRL on Windows (probably linux too), CMD on OSX
m_Accels->Map( AAC( WXK_NUMPAD_ADD ).Cmd().Alt(), "GSwindow_ZoomInY" ); //CTRL on Windows/linux, CMD on OSX
m_Accels->Map( AAC( WXK_NUMPAD_SUBTRACT ).Cmd().Alt(), "GSwindow_ZoomOutY" );
m_Accels->Map( AAC( WXK_NUMPAD_MULTIPLY ).Cmd().Alt(), "GSwindow_ZoomResetY" );
@ -97,6 +97,7 @@ GSPanel::GSPanel( wxWindow* parent )
Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler (GSPanel::OnCloseWindow));
Connect(wxEVT_SIZE, wxSizeEventHandler (GSPanel::OnResize));
Connect(wxEVT_KEY_UP, wxKeyEventHandler (GSPanel::OnKeyDown));
Connect(wxEVT_KEY_DOWN, wxKeyEventHandler (GSPanel::OnKeyDown));
Connect(wxEVT_SET_FOCUS, wxFocusEventHandler (GSPanel::OnFocus));
@ -107,16 +108,18 @@ GSPanel::GSPanel( wxWindow* parent )
// Any and all events which should result in the mouse cursor being made visible
// are connected here. If I missed one, feel free to add it in! --air
Connect(wxEVT_MIDDLE_DOWN, wxMouseEventHandler (GSPanel::OnShowMouse));
Connect(wxEVT_MIDDLE_UP, wxMouseEventHandler (GSPanel::OnShowMouse));
Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler (GSPanel::OnShowMouse));
Connect(wxEVT_RIGHT_UP, wxMouseEventHandler (GSPanel::OnShowMouse));
Connect(wxEVT_MOTION, wxMouseEventHandler (GSPanel::OnShowMouse));
Connect(wxEVT_LEFT_DCLICK, wxMouseEventHandler (GSPanel::OnShowMouse));
Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler (GSPanel::OnMouseEvent));
Connect(wxEVT_LEFT_UP, wxMouseEventHandler (GSPanel::OnMouseEvent));
Connect(wxEVT_MIDDLE_DOWN, wxMouseEventHandler (GSPanel::OnMouseEvent));
Connect(wxEVT_MIDDLE_UP, wxMouseEventHandler (GSPanel::OnMouseEvent));
Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler (GSPanel::OnMouseEvent));
Connect(wxEVT_RIGHT_UP, wxMouseEventHandler (GSPanel::OnMouseEvent));
Connect(wxEVT_MOTION, wxMouseEventHandler (GSPanel::OnMouseEvent));
Connect(wxEVT_LEFT_DCLICK, wxMouseEventHandler (GSPanel::OnMouseEvent));
Connect(wxEVT_LEFT_DCLICK, wxMouseEventHandler (GSPanel::OnLeftDclick));
Connect(wxEVT_MIDDLE_DCLICK, wxMouseEventHandler (GSPanel::OnShowMouse));
Connect(wxEVT_RIGHT_DCLICK, wxMouseEventHandler (GSPanel::OnShowMouse));
Connect(wxEVT_MOUSEWHEEL, wxMouseEventHandler (GSPanel::OnShowMouse));
Connect(wxEVT_MIDDLE_DCLICK, wxMouseEventHandler (GSPanel::OnMouseEvent));
Connect(wxEVT_RIGHT_DCLICK, wxMouseEventHandler (GSPanel::OnMouseEvent));
Connect(wxEVT_MOUSEWHEEL, wxMouseEventHandler (GSPanel::OnMouseEvent));
}
GSPanel::~GSPanel() throw()
@ -188,11 +191,60 @@ void GSPanel::OnCloseWindow(wxCloseEvent& evt)
evt.Skip(); // and close it.
}
void GSPanel::OnShowMouse( wxMouseEvent& evt )
void GSPanel::OnMouseEvent( wxMouseEvent& evt )
{
if( IsBeingDeleted() ) return;
evt.Skip();
DoShowMouse();
// Do nothing for left-button event
if (!evt.Button(1)) {
evt.Skip();
DoShowMouse();
}
#ifdef __LINUX__
// HACK2: In gsopen2 there is one event buffer read by both wx/gui and pad plugin. Wx deletes
// the event before the pad see it. So you send key event directly to the pad.
if( (PADWriteEvent != NULL) && (GSopen2 != NULL) ) {
keyEvent event;
// FIXME how to handle double click ???
if (evt.ButtonDown()) {
event.evt = 4; // X equivalent of ButtonPress
event.key = evt.GetButton();
} else if (evt.ButtonUp()) {
event.evt = 5; // X equivalent of ButtonRelease
event.key = evt.GetButton();
} else if (evt.Moving() || evt.Dragging()) {
event.evt = 6; // X equivalent of MotionNotify
long x,y;
evt.GetPosition(&x, &y);
wxCoord w, h;
wxWindowDC dc( this );
dc.GetSize(&w, &h);
// Special case to allow continuous mouvement near the border
if (x < 10)
x = 0;
else if (x > (w-10))
x = 0xFFFF;
if (y < 10)
y = 0;
else if (y > (w-10))
y = 0xFFFF;
// For compatibility purpose with the existing structure. I decide to reduce
// the position to 16 bits.
event.key = ((y & 0xFFFF) << 16) | (x & 0xFFFF);
} else {
event.key = 0;
event.evt = 0;
}
PADWriteEvent(event);
}
#endif
}
void GSPanel::OnHideMouseTimeout( wxTimerEvent& evt )
@ -206,11 +258,29 @@ void GSPanel::OnHideMouseTimeout( wxTimerEvent& evt )
void GSPanel::OnKeyDown( wxKeyEvent& evt )
{
// HACK: Legacy PAD plugins expect PCSX2 to ignore keyboard messages on the GS Window while
// the PAD plugin is open, so ignore here (PCSX2 will direct messages routed from PAD directly
// to the APP level message handler, which in turn routes them right back here -- yes it's
// silly, but oh well).
#ifdef __LINUX__
// HACK2: In gsopen2 there is one event buffer read by both wx/gui and pad plugin. Wx deletes
// the event before the pad see it. So you send key event directly to the pad.
if( (PADWriteEvent != NULL) && (GSopen2 != NULL) ) {
keyEvent event;
event.key = evt.GetRawKeyCode();
if (evt.GetEventType() == wxEVT_KEY_UP)
event.evt = 3; // X equivalent of KEYRELEASE;
else if (evt.GetEventType() == wxEVT_KEY_DOWN)
event.evt = 2; // X equivalent of KEYPRESS;
else
event.evt = 0;
PADWriteEvent(event);
}
#endif
if( (PADopen != NULL) && CoreThread.IsOpen() ) return;
DirectKeyCommand( evt );
}
@ -246,6 +316,14 @@ void GSPanel::OnFocus( wxFocusEvent& evt )
else
DoShowMouse();
#ifdef __LINUX__
// HACK2: In gsopen2 there is one event buffer read by both wx/gui and pad plugin. Wx deletes
// the event before the pad see it. So you send key event directly to the pad.
if( (PADWriteEvent != NULL) && (GSopen2 != NULL) ) {
keyEvent event = {0, 9}; // X equivalent of FocusIn;
PADWriteEvent(event);
}
#endif
//Console.Warning("GS frame > focus set");
}
@ -254,6 +332,14 @@ void GSPanel::OnFocusLost( wxFocusEvent& evt )
evt.Skip();
m_HasFocus = false;
DoShowMouse();
#ifdef __LINUX__
// HACK2: In gsopen2 there is one event buffer read by both wx/gui and pad plugin. Wx deletes
// the event before the pad see it. So you send key event directly to the pad.
if( (PADWriteEvent != NULL) && (GSopen2 != NULL) ) {
keyEvent event = {0, 10}; // X equivalent of FocusOut
PADWriteEvent(event);
}
#endif
//Console.Warning("GS frame > focus lost");
}

View File

@ -64,7 +64,7 @@ protected:
void OnCloseWindow( wxCloseEvent& evt );
void OnResize(wxSizeEvent& event);
void OnShowMouse( wxMouseEvent& evt );
void OnMouseEvent( wxMouseEvent& evt );
void OnHideMouseTimeout( wxTimerEvent& evt );
void OnKeyDown( wxKeyEvent& evt );
void OnFocus( wxFocusEvent& evt );

View File

@ -281,7 +281,12 @@ static int _GSopen(void** dsp, char* title, int renderer, int threads = -1)
{
s_gs->SetMultithreaded(true);
#ifdef __LINUX__
// Get the Xwindow from dsp.
s_gs->m_wnd.Attach((void*)((uint32*)(dsp)+1), false);
#else
s_gs->m_wnd.Attach(*dsp, false);
#endif
}
if(!s_gs->CreateDevice(dev))
@ -298,8 +303,6 @@ static int _GSopen(void** dsp, char* title, int renderer, int threads = -1)
return 0;
}
#ifdef _WINDOWS
EXPORT_C_(int) GSopen2(void** dsp, uint32 flags)
{
int renderer = theApp.GetConfig("renderer", 0);
@ -320,8 +323,6 @@ EXPORT_C_(int) GSopen2(void** dsp, uint32 flags)
return retval;
}
#endif
EXPORT_C_(int) GSopen(void** dsp, char* title, int mt)
{
/*

View File

@ -50,20 +50,15 @@ GSDeviceSDL::~GSDeviceSDL()
bool GSDeviceSDL::Create(GSWnd* wnd)
{
void* handle = wnd->GetHandle();
if(handle == wnd->GetDisplay())
{
// HACK: no SDL window
m_window = SDL_CreateWindowFrom(handle);
m_free_window = true;
}
else
{
m_window = (SDL_Window*)handle;
if (m_window == NULL) {
m_window = SDL_CreateWindowFrom(wnd->GetHandle());
m_free_window = true;
}
#ifdef __LINUX__
// In GSopen2, sdl failed to received any resize event. GSWnd::GetClientRect need to manually
// set the window size... So we send the m_window to the wnd object to allow some manipulation on it.
wnd->SetWindow(m_window);
#endif
return GSDeviceSW::Create(wnd);
}

View File

@ -312,28 +312,44 @@ void GSWnd::HideFrame()
*/
GSWnd::GSWnd()
: m_window(NULL)
: m_window(NULL), m_Xwindow(0), m_XDisplay(NULL)
{
}
GSWnd::~GSWnd()
{
if(m_window != NULL)
if(m_window != NULL && m_managed)
{
SDL_DestroyWindow(m_window);
m_window = NULL;
}
if (m_XDisplay) {
XCloseDisplay(m_XDisplay);
m_XDisplay = NULL;
}
}
bool GSWnd::Attach(void* handle, bool managed)
{
m_Xwindow = *(Window*)handle;
m_managed = managed;
return true;
}
// Actually the destructor is not called when there is a GSclose or GSshutdown
// The window still need to be closed
void GSWnd::Detach()
{
if(m_window != NULL)
// Actually the destructor is not called when there is only a GSclose/GSshutdown
// The window still need to be closed
if(m_window != NULL && m_managed)
{
SDL_DestroyWindow(m_window);
m_window = NULL;
}
if (m_XDisplay) {
XCloseDisplay(m_XDisplay);
m_XDisplay = NULL;
}
}
bool GSWnd::Create(const string& title, int w, int h)
@ -359,8 +375,21 @@ bool GSWnd::Create(const string& title, int w, int h)
if (SDL_GetNumVideoDisplays() <= 0) return false;
#endif
m_managed = true;
m_window = SDL_CreateWindow(title.c_str(), 100, 100, w, h, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
// Get the X window from the newly created window
// It would be needed to get the current size
SDL_SysWMinfo wminfo;
memset(&wminfo, 0, sizeof(wminfo));
wminfo.version.major = SDL_MAJOR_VERSION;
wminfo.version.minor = SDL_MINOR_VERSION;
SDL_GetWindowWMInfo(m_window, &wminfo);
m_Xwindow = wminfo.info.x11.window;
return (m_window != NULL);
}
@ -380,16 +409,25 @@ Display* GSWnd::GetDisplay()
GSVector4i GSWnd::GetClientRect()
{
// Get all SDL events. It refreshes the window parameter do not ask why.
// Anyway it allow to properly resize the window surface
// FIXME: it does not feel a good solution -- Gregory
SDL_PumpEvents();
unsigned int h = 480;
unsigned int w = 640;
int h = 480;
int w = 640;
if (m_window) SDL_GetWindowSize(m_window, &w, &h);
unsigned int borderDummy;
unsigned int depthDummy;
Window winDummy;
int xDummy;
int yDummy;
return GSVector4i(0, 0, w, h);
// In gsopen2, pcsx2 stoles all event (including resize event). SDL is not able to update its structure
// so you must do it yourself
// In perfect world:
// if (m_window) SDL_GetWindowSize(m_window, &w, &h);
// In real world...:
if (!m_XDisplay) m_XDisplay = XOpenDisplay(NULL);
XGetGeometry(m_XDisplay, m_Xwindow, &winDummy, &xDummy, &yDummy, &w, &h, &borderDummy, &depthDummy);
SDL_SetWindowSize(m_window, w, h);
return GSVector4i(0, 0, (int)w, (int)h);
}
// Returns FALSE if the window has no title, or if th window title is under the strict
@ -397,17 +435,21 @@ GSVector4i GSWnd::GetClientRect()
bool GSWnd::SetWindowText(const char* title)
{
if (!m_managed) return true;
// Do not find anyway to check the current fullscreen status
// Better than nothing heuristic, check the window position. Fullscreen = (0,0)
// if(!(m_window->flags & SDL_WINDOW_FULLSCREEN) ) // Do not compile
//
// Same as GetClientRect. We call SDL_PumpEvents to refresh x and y value
// We call SDL_PumpEvents to refresh x and y value.
// but we not use this function anyway.
// FIXME: it does not feel a good solution -- Gregory
// NOte: it might be more thread safe to use a call to XGetGeometry
SDL_PumpEvents();
int x,y = 0;
SDL_GetWindowPosition(m_window, &x, &y);
if ( x && y )
SDL_SetWindowTitle(m_window, title);
SDL_SetWindowTitle(m_window, title);
return true;
}

View File

@ -94,20 +94,24 @@ public:
class GSWnd
{
SDL_Window* m_window;
Window m_Xwindow;
Display* m_XDisplay;
bool m_managed;
public:
GSWnd();
virtual ~GSWnd();
bool Create(const string& title, int w, int h);
bool Attach(void* handle, bool managed = true) {return false;}
bool Attach(void* handle, bool managed = true);
void Detach();
bool IsManaged() const {return true;}
bool IsManaged() const {return m_managed;}
Display* GetDisplay();
void* GetHandle() {return m_window;}
void* GetHandle() {return (void*)&m_Xwindow;}
GSVector4i GetClientRect();
bool SetWindowText(const char* title);
void SetWindow(SDL_Window* current_window) { if (current_window) m_window = current_window; }
void Show();
void Hide();

View File

@ -20,18 +20,16 @@
*/
#include "joystick.h"
#include "keyboard.h"
#include "onepad.h"
#include <gtk/gtk.h>
extern bool PollX11Keyboard(char* &temp, u32 &pkey);
extern string KeyName(int pad, int key);
void config_key(int pad, int key);
void on_conf_key(GtkButton *button, gpointer user_data);
void on_toggle_option(GtkToggleButton *togglebutton, gpointer user_data);
static int current_pad = 0;
static int current_joystick = -1;
GtkWidget *rev_lx_check, *rev_ly_check, *force_feedback_check, *rev_rx_check, *rev_ry_check;
static GtkComboBox *joy_choose_cbox;
const char* s_pGuiKeyMap[] =
{
@ -39,7 +37,6 @@ const char* s_pGuiKeyMap[] =
"Triangle", "Circle", "Cross", "Square",
"Select", "L3", "R3", "Start",
"Up", "Right", "Down", "Left",
"Lx", "Rx", "Ly", "Ry",
"L_Up", "L_Right", "L_Down", "L_Left",
"R_Up", "R_Right", "R_Down", "R_Left"
};
@ -51,71 +48,94 @@ enum
COL_KEY,
COL_PAD_NUM,
COL_VALUE,
COL_KEYSYM,
NUM_COLS
};
class keys_tree
{
private:
GtkTreeStore *treestore;
GtkTreeModel *model;
GtkTreeView *view;
GtkTreeView *view[2];
bool has_columns;
int show_pad;
bool show_keyboard_key[2];
bool show_joy_key[2];
void repopulate()
{
GtkTreeIter toplevel;
gtk_tree_store_clear(treestore);
for (int pad = 0; pad < 2 * MAX_SUB_KEYS; pad++)
{
string pad_value;
switch(show_pad) {
case 0: pad_value = "Pad 1"; break;
case 1: pad_value = "Pad 2"; break;
default: pad_value = "Invalid"; break;
}
// joystick key
if (show_joy_key[show_pad]) {
for (int key = 0; key < MAX_KEYS; key++)
{
if (get_key(pad, key) != 0)
if (get_key(show_pad, key) != 0)
{
string pad_value;
switch(pad)
{
case 0: pad_value = "Pad 1"; break;
case 2: pad_value = "Pad 1"; break;
case 1: pad_value = "Pad 2"; break;
case 3: pad_value = "Pad 2"; break;
default: pad_value = "Invalid"; break;
}
gtk_tree_store_append(treestore, &toplevel, NULL);
gtk_tree_store_set(treestore, &toplevel,
COL_PAD, pad_value.c_str(),
COL_BUTTON, s_pGuiKeyMap[key],
COL_KEY, KeyName(show_pad, key).c_str(),
COL_PAD_NUM, show_pad,
COL_VALUE, key,
COL_KEYSYM, 0,
-1);
}
}
}
// keyboard/mouse key
if (show_keyboard_key[show_pad]) {
map<u32,u32>::iterator it;
for (it = conf->keysym_map[show_pad].begin(); it != conf->keysym_map[show_pad].end(); ++it) {
int keysym = it->first;
int key = it->second;
gtk_tree_store_append(treestore, &toplevel, NULL);
gtk_tree_store_set(treestore, &toplevel,
COL_PAD, pad_value.c_str(),
COL_BUTTON, s_pGuiKeyMap[key],
COL_KEY, KeyName(pad, key).c_str(),
COL_PAD_NUM, pad,
COL_KEY, KeyName(show_pad, key, keysym).c_str(),
COL_PAD_NUM, show_pad,
COL_VALUE, key,
-1);
}
COL_KEYSYM, keysym,
-1);
}
}
}
void create_a_column(const char *name, int num, bool visible)
{
GtkCellRenderer *renderer;
GtkTreeViewColumn *col;
for (int i = 0; i < 2; i++) {
GtkCellRenderer *renderer;
GtkTreeViewColumn *col;
col = gtk_tree_view_column_new();
gtk_tree_view_column_set_title(col, name);
col = gtk_tree_view_column_new();
gtk_tree_view_column_set_title(col, name);
/* pack tree view column into tree view */
gtk_tree_view_append_column(view, col);
/* pack tree view column into tree view */
gtk_tree_view_append_column(view[i], col);
renderer = gtk_cell_renderer_text_new();
renderer = gtk_cell_renderer_text_new();
/* pack cell renderer into tree view column */
gtk_tree_view_column_pack_start(col, renderer, TRUE);
/* pack cell renderer into tree view column */
gtk_tree_view_column_pack_start(col, renderer, TRUE);
/* connect 'text' property of the cell renderer to
* model column that contains the first name */
gtk_tree_view_column_add_attribute(col, renderer, "text", num);
gtk_tree_view_column_set_visible(col, visible);
/* connect 'text' property of the cell renderer to
* model column that contains the first name */
gtk_tree_view_column_add_attribute(col, renderer, "text", num);
gtk_tree_view_column_set_visible(col, visible);
}
}
void create_columns()
@ -127,125 +147,126 @@ class keys_tree
create_a_column("Key Value", COL_KEY, true);
create_a_column("Pad Num", COL_PAD_NUM, false);
create_a_column("Internal", COL_VALUE, false);
create_a_column("Keysym", COL_KEYSYM, false);
has_columns = true;
}
}
public:
GtkWidget *view_widget()
GtkWidget *view_widget(int i)
{
return GTK_WIDGET(view);
return GTK_WIDGET(view[i]);
}
void init()
{
show_pad = 0;
has_columns = false;
view = GTK_TREE_VIEW(gtk_tree_view_new());
for (int i = 0; i < 2; i++)
show_keyboard_key[i] = show_joy_key[i] = true;
treestore = gtk_tree_store_new(NUM_COLS,
G_TYPE_STRING,
G_TYPE_STRING,
G_TYPE_STRING,
G_TYPE_UINT,
G_TYPE_UINT);
G_TYPE_STRING,
G_TYPE_STRING,
G_TYPE_STRING,
G_TYPE_UINT,
G_TYPE_UINT,
G_TYPE_UINT);
model = GTK_TREE_MODEL(treestore);
gtk_tree_view_set_model(view, model);
for (int i = 0; i < 2; i++) {
view[i] = GTK_TREE_VIEW(gtk_tree_view_new());
gtk_tree_view_set_model(view[i], model);
gtk_tree_selection_set_mode(gtk_tree_view_get_selection(view[i]), GTK_SELECTION_SINGLE);
}
g_object_unref(model); /* destroy model automatically with view */
gtk_tree_selection_set_mode(gtk_tree_view_get_selection(view), GTK_SELECTION_SINGLE);
}
void set_show_pad(int pad) { show_pad = pad; }
void set_show_joy(bool flag) { show_joy_key[show_pad] = flag; }
void set_show_key(bool flag) { show_keyboard_key[show_pad] = flag; }
void update()
{
create_columns();
repopulate();
}
void clear_all()
{
clearPAD();
clearPAD(show_pad);
update();
}
bool get_selected(int &pad, int &key)
bool get_selected(int &pad, int &key, int &keysym)
{
GtkTreeSelection *selection;
GtkTreeIter iter;
selection = gtk_tree_view_get_selection(view);
selection = gtk_tree_view_get_selection(view[show_pad&1]);
if (gtk_tree_selection_get_selected(selection, &model, &iter))
{
gtk_tree_model_get(model, &iter, COL_PAD_NUM, &pad, COL_VALUE, &key,-1);
gtk_tree_model_get(model, &iter, COL_PAD_NUM, &pad, COL_VALUE, &key, COL_KEYSYM, &keysym,-1);
return true;
}
return false;
}
void remove_selected()
{
int key, pad;
if (get_selected(pad, key))
int key, pad, keysym;
if (get_selected(pad, key, keysym))
{
set_key(pad, key, 0);
if (keysym)
conf->keysym_map[pad].erase(keysym);
else
set_key(pad, key, 0);
update();
}
}
void modify_selected()
{
int key, pad;
if (get_selected(pad, key))
int key, pad, keysym;
if (get_selected(pad, key, keysym))
{
remove_selected();
config_key(pad,key);
update();
}
}
};
keys_tree *fir;
int _GetJoystickId()
{
// select the right joystick id
u32 joyid = -1;
if (!JoystickIdWithinBounds(joyid))
{
// get first unused joystick
for (joyid = 0; joyid < s_vjoysticks.size(); ++joyid)
{
if (s_vjoysticks[joyid]->GetPAD() < 0) break;
}
}
return joyid;
}
int Get_Current_Joystick()
{
// check bounds
int joyid = _GetJoystickId();
if (JoystickIdWithinBounds(joyid))
return joyid + 1; // select the combo
else
return 0; //s_vjoysticks.size(); // no gamepad
}
keys_tree *key_tree_manager;
void populate_new_joysticks(GtkComboBox *box)
{
char str[255];
JoystickInfo::EnumerateJoysticks(s_vjoysticks);
gtk_combo_box_append_text(box, "No Gamepad");
gtk_combo_box_append_text(box, "Keyboard/mouse only");
vector<JoystickInfo*>::iterator it = s_vjoysticks.begin();
// Delete everything in the vector vjoysticks.
// Get everything in the vector vjoysticks.
while (it != s_vjoysticks.end())
{
sprintf(str, "%d: %s - but: %d, axes: %d, hats: %d", (*it)->GetId(), (*it)->GetName().c_str(),
sprintf(str, "Keyboard/mouse and %s - but: %d, axes: %d, hats: %d", (*it)->GetName().c_str(),
(*it)->GetNumButtons(), (*it)->GetNumAxes(), (*it)->GetNumHats());
gtk_combo_box_append_text(box, str);
it++;
}
current_joystick = Get_Current_Joystick();
}
void set_current_joy()
{
u32 joyid = conf->get_joyid(current_pad);
if (JoystickIdWithinBounds(joyid))
// 0 is special case for no gamepad. So you must increase of 1.
gtk_combo_box_set_active(joy_choose_cbox, joyid+1);
else
gtk_combo_box_set_active(joy_choose_cbox, 0);
}
typedef struct
@ -255,16 +276,33 @@ typedef struct
void put(const char* lbl, int i, GtkFixed *fix, int x, int y)
{
widget = gtk_button_new_with_label(lbl);
index = i;
gtk_fixed_put(fix, widget, x, y);
gtk_widget_set_size_request(widget, 64, 24);
index = i;
g_signal_connect(GTK_OBJECT (widget), "clicked", G_CALLBACK(on_conf_key), this);
}
} dialog_buttons;
typedef struct
{
GtkWidget *widget;
unsigned int mask;
void create(GtkWidget* area, const char* label, u32 x, u32 y, u32 mask_value)
{
widget = gtk_check_button_new_with_label(label);
mask = mask_value;
gtk_fixed_put(GTK_FIXED(area), widget, x, y);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), mask & conf->options);
g_signal_connect(GTK_OBJECT (widget), "toggled", G_CALLBACK(on_toggle_option), this);
}
} dialog_checkbox;
void config_key(int pad, int key)
{
bool captured = false;
u32 key_pressed = 0;
// save the joystick states
UpdateJoysticks();
@ -272,13 +310,14 @@ void config_key(int pad, int key)
while (!captured)
{
vector<JoystickInfo*>::iterator itjoy;
char *tmp;
u32 pkey = get_key(pad, key);
if (PollX11Keyboard(tmp, pkey))
if (PollX11KeyboardMouseEvent(key_pressed))
{
set_key(pad, key, pkey);
PAD_LOG("%s\n", KeyName(pad, key).c_str());
// special case for keyboard/mouse to handle multiple keys
// Note: key_pressed == 0 when ESC is hit to abort the capture
if (key_pressed > 0)
set_keyboad_key(pad, key_pressed, key);
captured = true;
break;
}
@ -288,53 +327,28 @@ void config_key(int pad, int key)
itjoy = s_vjoysticks.begin();
while ((itjoy != s_vjoysticks.end()) && (!captured))
{
int button_id, direction;
pkey = get_key(pad, key);
if ((*itjoy)->PollButtons(button_id, pkey))
{
set_key(pad, key, pkey);
PAD_LOG("%s\n", KeyName(pad, key).c_str());
if ((*itjoy)->PollButtons(key_pressed)) {
set_key(pad, key, key_pressed);
captured = true;
break;
}
bool sign = false;
bool pov = (!((key == PAD_RY) || (key == PAD_LY) || (key == PAD_RX) || (key == PAD_LX)));
int axis_id;
if (pov)
{
if ((*itjoy)->PollPOV(axis_id, sign, pkey))
{
set_key(pad, key, pkey);
PAD_LOG("%s\n", KeyName(pad, key).c_str());
captured = true;
break;
}
}
else
{
if ((*itjoy)->PollAxes(axis_id, pkey))
{
set_key(pad, key, pkey);
PAD_LOG("%s\n", KeyName(pad, key).c_str());
captured = true;
break;
}
if ((*itjoy)->PollAxes(key_pressed)) {
set_key(pad, key, key_pressed);
captured = true;
break;
}
if ((*itjoy)->PollHats(axis_id, direction, pkey))
{
set_key(pad, key, pkey);
PAD_LOG("%s\n", KeyName(pad, key).c_str());
if ((*itjoy)->PollHats(key_pressed)) {
set_key(pad, key, key_pressed);
captured = true;
break;
}
itjoy++;
}
}
PAD_LOG("%s\n", KeyName(pad, key).c_str());
}
void on_conf_key(GtkButton *button, gpointer user_data)
@ -345,93 +359,74 @@ void on_conf_key(GtkButton *button, gpointer user_data)
if (key == -1) return;
config_key(current_pad, key);
fir->update();
key_tree_manager->update();
}
void on_remove_clicked(GtkButton *button, gpointer user_data)
{
fir->remove_selected();
key_tree_manager->remove_selected();
}
void on_clear_clicked(GtkButton *button, gpointer user_data)
{
fir->clear_all();
key_tree_manager->clear_all();
}
void on_modify_clicked(GtkButton *button, gpointer user_data)
{
fir->modify_selected();
key_tree_manager->modify_selected();
}
void on_view_joy_clicked(GtkToggleButton *togglebutton, gpointer user_data)
{
key_tree_manager->set_show_joy(gtk_toggle_button_get_active(togglebutton));
key_tree_manager->update();
}
void on_view_key_clicked(GtkToggleButton *togglebutton, gpointer user_data)
{
key_tree_manager->set_show_key(gtk_toggle_button_get_active(togglebutton));
key_tree_manager->update();
}
void on_toggle_option(GtkToggleButton *togglebutton, gpointer user_data)
{
dialog_checkbox *checkbox = (dialog_checkbox*)user_data;
if (gtk_toggle_button_get_active(togglebutton))
conf->options |= checkbox->mask;
else
conf->options &= ~checkbox->mask;
}
void joy_changed(GtkComboBox *box, gpointer user_data)
{
int joyid = gtk_combo_box_get_active(box);
// Note position 0 of the combo box is no gamepad
joyid--;
// FIXME: might be a good idea to ask the user first ;)
// FIXME: do you need to clean the previous key association. or what the user want
// 1 : keep previous joy
// 2 : use new joy with old key binding
// 3 : use new joy with fresh key binding
// unassign every joystick with this pad
for (int i = 0; i < (int)s_vjoysticks.size(); ++i)
{
if (s_vjoysticks[i]->GetPAD() == current_pad) s_vjoysticks[i]->Assign(-1);
}
for (int i = 0; i < 2; ++i)
if (joyid == conf->get_joyid(i)) conf->set_joyid(i, -1);
if (joyid >= 0 && joyid < (int)s_vjoysticks.size()) s_vjoysticks[joyid]->Assign(current_pad);
conf->set_joyid(current_pad, joyid);
}
void pad_changed(GtkComboBox *box, gpointer user_data)
void pad_changed(GtkNotebook *notebook, GtkNotebookPage *notebook_page, int page, void *data)
{
int temp = gtk_combo_box_get_active(box);
if (temp >= 0) current_pad = temp;
fir->update();
int options = (conf.options >> (16 * current_pad));
current_pad = page;
key_tree_manager->set_show_pad(current_pad&1);
key_tree_manager->update();
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rev_lx_check), (options & PADOPTION_REVERSELX));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rev_ly_check), (options & PADOPTION_REVERSELY));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rev_rx_check), (options & PADOPTION_REVERSERX));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rev_ry_check), (options & PADOPTION_REVERSERY));
}
void update_option(int option, bool value)
{
int mask = (option << (16 * current_pad));
if (value)
conf.options |= mask;
else
conf.options &= ~mask;
}
void on_refresh(GtkComboBox *box, gpointer user_data)
{
GtkComboBox *joy_choose_cbox = (GtkComboBox*)user_data;
if (current_joystick < 0) current_joystick = Get_Current_Joystick();
for(int i=0; i <= (int)s_vjoysticks.size(); i++)
{
gtk_combo_box_remove_text(joy_choose_cbox, 0);
}
populate_new_joysticks(joy_choose_cbox);
if (gtk_combo_box_get_active(joy_choose_cbox) != current_joystick)
gtk_combo_box_set_active(joy_choose_cbox, current_joystick);
}
void on_rev_lx(GtkComboBox *box, gpointer user_data)
{
update_option(PADOPTION_REVERSELX, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(rev_lx_check)));
}
void on_rev_ly(GtkComboBox *box, gpointer user_data)
{
update_option(PADOPTION_REVERSELY, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(rev_ly_check)));
}
void on_rev_rx(GtkComboBox *box, gpointer user_data)
{
update_option(PADOPTION_REVERSERX, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(rev_rx_check)));
}
void on_rev_ry(GtkComboBox *box, gpointer user_data)
{
update_option(PADOPTION_REVERSERY, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(rev_ry_check)));
// update joy
set_current_joy();
}
//void on_forcefeedback_toggled(GtkToggleButton *togglebutton, gpointer user_data)
@ -440,106 +435,125 @@ void on_rev_ry(GtkComboBox *box, gpointer user_data)
//
// if (gtk_toggle_button_get_active(togglebutton))
// {
// conf.options |= mask;
// conf->options |= mask;
//
// int joyid = gtk_combo_box_get_active(GTK_COMBO_BOX(s_devicecombo));
//
// if (joyid >= 0 && joyid < (int)s_vjoysticks.size()) s_vjoysticks[joyid]->TestForce();
// u32 joyid = conf->get_joyid(current_pad);
// if (JoystickIdWithinBounds(joyid)) s_vjoysticks[joyid]->TestForce();
// }
// else
// {
// conf.options &= ~mask;
// conf->options &= ~mask;
// }
//}
void DisplayDialog()
struct button_positions
{
int return_value;
const char* label;
u32 x,y;
};
GtkWidget *dialog;
GtkWidget *main_frame, *main_box;
// Warning position is important and must match the order of the gamePadValues structure
button_positions b_pos[MAX_KEYS] =
{
{ "L2", 64, 8},
{ "R2", 392, 8},
{ "L1", 64, 32},
{ "R1", 392, 32},
{ "Triangle", 392, 80},
{ "Circle", 456, 104},
{ "Cross", 392, 128},
{ "Square", 328, 104},
{ "Select", 200, 48},
{ "L3", 64, 224},
{ "R3", 392, 224},
{ "Start", 272, 48},
// Arrow pad
{ "Up", 64, 80},
{ "Right", 128, 104},
{ "Down", 64, 128},
{ "Left", 0, 104},
// Left Analog joystick
{ "Up", 64, 200},
{ "Right", 128, 224},
{ "Down", 64, 248},
{ "Left", 0, 224},
// Right Analog joystick
{ "Up", 392, 200},
{ "Right", 456, 224},
{ "Down", 392, 248},
{ "Left", 328, 224}
};
GtkWidget *pad_choose_frame, *pad_choose_box;
GtkComboBox *pad_choose_cbox;
// Warning position is important and must match the order of the PadOptions structure
button_positions check_pos[7] =
{
{ "Enable force feedback", 40, 400},
{ "Reverse Lx", 40, 304},
{ "Reverse Ly", 40, 328},
{ "Reverse Rx", 368, 304},
{ "Reverse Ry", 368, 328},
{ "Use mouse for left analog joy", 40, 352},
{ "Use mouse for right analog joy", 368,352},
};
GtkWidget *create_notebook_page_dialog(int page, dialog_buttons btn[MAX_KEYS], dialog_checkbox checkbox[7])
{
GtkWidget *main_box;
GtkWidget *joy_choose_frame, *joy_choose_box;
GtkComboBox *joy_choose_cbox;
//GtkWidget *joy_refresh;
GtkWidget *keys_frame, *keys_box;
GtkWidget *keys_tree_frame, *keys_tree_box;
GtkWidget *keys_tree_clear_btn, *keys_tree_remove_btn, *keys_tree_modify_btn;
GtkWidget *keys_btn_box, *keys_btn_frame;
GtkWidget *keys_tree_box, *keys_tree_scroll;
GtkWidget *keys_tree_clear_btn, *keys_tree_remove_btn, *keys_tree_modify_btn, *keys_tree_show_key_btn, *keys_tree_show_joy_btn;
GtkWidget *keys_btn_box, *keys_filter_box;
GtkWidget *keys_static_frame, *keys_static_box;
GtkWidget *keys_static_area;
dialog_buttons btn[29];
LoadConfig();
fir = new keys_tree;
fir->init();
/* Create the widgets */
dialog = gtk_dialog_new_with_buttons (
"OnePAD Config",
NULL, /* parent window*/
(GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
GTK_STOCK_OK,
GTK_RESPONSE_ACCEPT,
GTK_STOCK_CANCEL,
GTK_RESPONSE_REJECT,
NULL);
pad_choose_cbox = GTK_COMBO_BOX(gtk_combo_box_new_text());
gtk_combo_box_append_text(pad_choose_cbox, "Pad 1");
gtk_combo_box_append_text(pad_choose_cbox, "Pad 2");
gtk_combo_box_append_text(pad_choose_cbox, "Pad 1 (alt)");
gtk_combo_box_append_text(pad_choose_cbox, "Pad 2 (alt)");
gtk_combo_box_set_active(pad_choose_cbox, current_pad);
g_signal_connect(GTK_OBJECT (pad_choose_cbox), "changed", G_CALLBACK(pad_changed), NULL);
if (current_joystick == -1) current_joystick = Get_Current_Joystick();
joy_choose_cbox = GTK_COMBO_BOX(gtk_combo_box_new_text());
populate_new_joysticks(joy_choose_cbox);
gtk_combo_box_set_active(joy_choose_cbox, current_joystick);
set_current_joy();
g_signal_connect(GTK_OBJECT (joy_choose_cbox), "changed", G_CALLBACK(joy_changed), NULL);
//joy_refresh = gtk_button_new_with_label("Refresh");
//g_signal_connect(GTK_OBJECT (joy_refresh), "clicked", G_CALLBACK(on_refresh), joy_choose_cbox);
//gtk_widget_set_size_request(joy_refresh, 64, 24);
keys_tree_scroll = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(keys_tree_scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_container_add (GTK_CONTAINER(keys_tree_scroll), key_tree_manager->view_widget(page));
gtk_widget_set_size_request(keys_tree_scroll, 300, 600);
keys_tree_clear_btn = gtk_button_new_with_label("Clear All");
g_signal_connect(GTK_OBJECT (keys_tree_clear_btn), "clicked", G_CALLBACK(on_clear_clicked), NULL);
gtk_widget_set_size_request(keys_tree_clear_btn, 64, 24);
gtk_widget_set_size_request(keys_tree_clear_btn, 70, 24);
keys_tree_remove_btn = gtk_button_new_with_label("Remove");
g_signal_connect(GTK_OBJECT (keys_tree_remove_btn), "clicked", G_CALLBACK(on_remove_clicked), NULL);
gtk_widget_set_size_request(keys_tree_remove_btn, 64, 24);
gtk_widget_set_size_request(keys_tree_remove_btn, 70, 24);
keys_tree_modify_btn = gtk_button_new_with_label("Modify");
g_signal_connect(GTK_OBJECT (keys_tree_modify_btn), "clicked", G_CALLBACK(on_modify_clicked), NULL);
gtk_widget_set_size_request(keys_tree_modify_btn, 64, 24);
main_box = gtk_vbox_new(false, 5);
main_frame = gtk_frame_new ("Onepad Config");
gtk_container_add (GTK_CONTAINER(main_frame), main_box);
gtk_widget_set_size_request(keys_tree_modify_btn, 70, 24);
pad_choose_box = gtk_vbox_new(false, 5);
pad_choose_frame = gtk_frame_new ("Choose a Pad to modify:");
gtk_container_add (GTK_CONTAINER(pad_choose_frame), pad_choose_box);
keys_tree_show_joy_btn = gtk_check_button_new_with_label("Show joy");
g_signal_connect(GTK_OBJECT (keys_tree_show_joy_btn), "toggled", G_CALLBACK(on_view_joy_clicked), NULL);
gtk_widget_set_size_request(keys_tree_show_joy_btn, 100, 24);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(keys_tree_show_joy_btn), true);
keys_tree_show_key_btn = gtk_check_button_new_with_label("Show key");
g_signal_connect(GTK_OBJECT (keys_tree_show_key_btn), "toggled", G_CALLBACK(on_view_key_clicked), NULL);
gtk_widget_set_size_request(keys_tree_show_key_btn, 100, 24);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(keys_tree_show_key_btn), true);
joy_choose_box = gtk_hbox_new(false, 5);
joy_choose_frame = gtk_frame_new ("Joystick to use for this pad");
gtk_container_add (GTK_CONTAINER(joy_choose_frame), joy_choose_box);
keys_btn_box = gtk_hbox_new(false, 5);
keys_btn_frame = gtk_frame_new ("");
gtk_container_add (GTK_CONTAINER(keys_btn_frame), keys_btn_box);
keys_filter_box = gtk_hbox_new(false, 5);
keys_tree_box = gtk_vbox_new(false, 5);
keys_tree_frame = gtk_frame_new ("");
gtk_container_add (GTK_CONTAINER(keys_tree_frame), keys_tree_box);
keys_static_box = gtk_hbox_new(false, 5);
keys_static_frame = gtk_frame_new ("");
@ -547,98 +561,96 @@ void DisplayDialog()
keys_static_area = gtk_fixed_new();
u32 static_offset = 0; //320
btn[0].put("L2", 0, GTK_FIXED(keys_static_area), static_offset + 64, 8);
btn[1].put("R2", 1, GTK_FIXED(keys_static_area), static_offset + 392, 8);
btn[2].put("L1", 2, GTK_FIXED(keys_static_area), static_offset + 64, 32);
btn[3].put("R1", 3, GTK_FIXED(keys_static_area), static_offset + 392, 32);
btn[4].put("Triangle", 4, GTK_FIXED(keys_static_area), static_offset + 392, 80);
btn[5].put("Circle", 5, GTK_FIXED(keys_static_area), static_offset + 456, 104);
btn[6].put("Cross", 6, GTK_FIXED(keys_static_area), static_offset + 392,128);
btn[7].put("Square", 7, GTK_FIXED(keys_static_area), static_offset + 328, 104);
btn[8].put("Select", 8, GTK_FIXED(keys_static_area), static_offset + 200, 48);
btn[9].put("L3", 9, GTK_FIXED(keys_static_area), static_offset + 200, 8);
btn[10].put("R3", 10, GTK_FIXED(keys_static_area), static_offset + 272, 8);
btn[11].put("Start", 11, GTK_FIXED(keys_static_area), static_offset + 272, 48);
// Arrow pad
btn[12].put("Up", 12, GTK_FIXED(keys_static_area), static_offset + 64, 80);
btn[13].put("Right", 13, GTK_FIXED(keys_static_area), static_offset + 128, 104);
btn[14].put("Down", 14, GTK_FIXED(keys_static_area), static_offset + 64, 128);
btn[15].put("Left", 15, GTK_FIXED(keys_static_area), static_offset + 0, 104);
//btn[xx].put("Analog", GTK_FIXED(keys_static_area), static_offset + 232, 104);
btn[16].put("Lx", 16, GTK_FIXED(keys_static_area), static_offset + 64, 264);
btn[17].put("Rx", 17, GTK_FIXED(keys_static_area), static_offset + 392, 264);
btn[18].put("Ly", 18, GTK_FIXED(keys_static_area), static_offset + 64, 288);
btn[19].put("Ry", 19, GTK_FIXED(keys_static_area), static_offset + 392, 288);
// Left Joystick
btn[20].put("Up", 20, GTK_FIXED(keys_static_area), static_offset + 64, 240);
btn[21].put("Right", 21, GTK_FIXED(keys_static_area), static_offset + 128, 272);
btn[22].put("Down", 22, GTK_FIXED(keys_static_area), static_offset + 64, 312);
btn[23].put("Left", 23, GTK_FIXED(keys_static_area), static_offset + 0, 272);
// Right Joystick
btn[24].put("Up", 24, GTK_FIXED(keys_static_area), static_offset + 392, 240);
btn[25].put("Right", 25, GTK_FIXED(keys_static_area), static_offset + 456, 272);
btn[26].put("Down", 26, GTK_FIXED(keys_static_area), static_offset + 392, 312);
btn[27].put("Left", 27, GTK_FIXED(keys_static_area), static_offset + 328, 272);
int options = (conf.options >> (16 * current_pad));
rev_lx_check = gtk_check_button_new_with_label("Reverse Lx");
gtk_fixed_put(GTK_FIXED(keys_static_area), rev_lx_check, static_offset + 40, 344);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rev_lx_check), (options & PADOPTION_REVERSELX));
g_signal_connect(GTK_OBJECT (rev_lx_check), "toggled", G_CALLBACK(on_rev_lx), NULL);
rev_ly_check = gtk_check_button_new_with_label("Reverse Ly");
gtk_fixed_put(GTK_FIXED(keys_static_area), rev_ly_check, static_offset + 40, 368);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rev_ly_check), (options & PADOPTION_REVERSELY));
g_signal_connect(GTK_OBJECT (rev_ly_check), "toggled", G_CALLBACK(on_rev_ly), NULL);
rev_rx_check = gtk_check_button_new_with_label("Reverse Rx");
gtk_fixed_put(GTK_FIXED(keys_static_area), rev_rx_check, static_offset + 368, 344);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rev_rx_check), (options & PADOPTION_REVERSERX));
g_signal_connect(GTK_OBJECT (rev_rx_check), "toggled", G_CALLBACK(on_rev_rx), NULL);
rev_ry_check = gtk_check_button_new_with_label("Reverse Ry");
gtk_fixed_put(GTK_FIXED(keys_static_area), rev_ry_check, static_offset + 368, 368);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rev_ry_check), (options & PADOPTION_REVERSERY));
g_signal_connect(GTK_OBJECT (rev_ry_check), "toggled", G_CALLBACK(on_rev_ry), NULL);
for(int i = 0; i < MAX_KEYS; i++)
{
btn[i].put(b_pos[i].label, i, GTK_FIXED(keys_static_area), b_pos[i].x, b_pos[i].y);
}
u32 mask = 1 << (16*page);
for(int i = 0; i < 7; i++) {
checkbox[i].create(keys_static_area, check_pos[i].label, check_pos[i].x, check_pos[i].y, mask);
mask = mask << 1;
}
keys_box = gtk_hbox_new(false, 5);
keys_frame = gtk_frame_new ("Key Settings");
gtk_container_add (GTK_CONTAINER(keys_frame), keys_box);
gtk_box_pack_start (GTK_BOX (keys_tree_box), fir->view_widget(), true, true, 0);
gtk_box_pack_end (GTK_BOX (keys_btn_box), keys_tree_clear_btn, false, false, 0);
gtk_box_pack_end (GTK_BOX (keys_btn_box), keys_tree_remove_btn, false, false, 0);
gtk_box_pack_end (GTK_BOX (keys_btn_box), keys_tree_modify_btn, false, false, 0);
gtk_box_pack_start (GTK_BOX (keys_tree_box), keys_tree_scroll, true, true, 0);
gtk_box_pack_start (GTK_BOX (keys_tree_box), keys_btn_box, false, false, 0);
gtk_box_pack_start (GTK_BOX (keys_tree_box), keys_filter_box, false, false, 0);
gtk_box_pack_start (GTK_BOX (keys_filter_box), keys_tree_show_joy_btn, false, false, 0);
gtk_box_pack_start (GTK_BOX (keys_filter_box), keys_tree_show_key_btn, false, false, 0);
gtk_box_pack_start (GTK_BOX (keys_btn_box), keys_tree_clear_btn, false, false, 0);
gtk_box_pack_start (GTK_BOX (keys_btn_box), keys_tree_remove_btn, false, false, 0);
gtk_box_pack_start (GTK_BOX (keys_btn_box), keys_tree_modify_btn, false, false, 0);
gtk_container_add(GTK_CONTAINER(pad_choose_box), GTK_WIDGET(pad_choose_cbox));
gtk_container_add(GTK_CONTAINER(joy_choose_box), GTK_WIDGET(joy_choose_cbox));
//gtk_container_add(GTK_CONTAINER(joy_choose_box), joy_refresh);
gtk_container_add(GTK_CONTAINER(keys_tree_box), keys_btn_frame);
gtk_box_pack_start (GTK_BOX (keys_box), keys_tree_frame, true, true, 0);
gtk_box_pack_start(GTK_BOX (keys_box), keys_tree_box, false, false, 0);
gtk_container_add(GTK_CONTAINER(keys_box), keys_static_area);
gtk_container_add(GTK_CONTAINER(main_box), pad_choose_frame);
main_box = gtk_vbox_new(false, 5);
gtk_container_add(GTK_CONTAINER(main_box), joy_choose_frame);
gtk_container_add(GTK_CONTAINER(main_box), keys_frame);
gtk_container_add (GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), main_frame);
return main_box;
}
void DisplayDialog()
{
int return_value;
GtkWidget *dialog;
GtkWidget *notebook, *page[2];
GtkWidget *page_label[2];
dialog_buttons btn[2][MAX_KEYS];
dialog_checkbox checkbox[2][7];
LoadConfig();
key_tree_manager = new keys_tree;
key_tree_manager->init();
/* Create the widgets */
dialog = gtk_dialog_new_with_buttons (
"OnePAD Config",
NULL, /* parent window*/
(GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
GTK_STOCK_OK,
GTK_RESPONSE_ACCEPT,
GTK_STOCK_APPLY,
GTK_RESPONSE_APPLY,
GTK_STOCK_CANCEL,
GTK_RESPONSE_REJECT,
NULL);
notebook = gtk_notebook_new();
page_label[0] = gtk_label_new("Pad 1");
page_label[1] = gtk_label_new("Pad 2");
for (int i = 0; i < 2; i++) {
page[i] = create_notebook_page_dialog(i, btn[i], checkbox[i]);
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page[i], page_label[i]);
}
g_signal_connect(GTK_OBJECT (notebook), "switch-page", G_CALLBACK(pad_changed), NULL);
gtk_container_add (GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), notebook);
fir->update();
key_tree_manager->update();
gtk_widget_show_all (dialog);
return_value = gtk_dialog_run (GTK_DIALOG (dialog));
if (return_value == GTK_RESPONSE_ACCEPT) SaveConfig();
do {
return_value = gtk_dialog_run (GTK_DIALOG (dialog));
if (return_value == GTK_RESPONSE_APPLY || return_value == GTK_RESPONSE_ACCEPT) {
SaveConfig();
}
} while (return_value == GTK_RESPONSE_APPLY);
LoadConfig();
delete fir;
delete key_tree_manager;
gtk_widget_destroy (dialog);
}

View File

@ -23,93 +23,97 @@
#include <gtk/gtk.h>
#include "joystick.h"
#include "keyboard.h"
#include "onepad.h"
#include "linux.h"
extern char* KeysymToChar(int keysym);
extern std::string s_strIniPath;
string KeyName(int pad, int key)
string KeyName(int pad, int key, int keysym)
{
string tmp;
KeyType k = type_of_key(pad, key);
tmp.resize(28);
switch (k)
if (keysym) {
if (keysym < 10) {
// mouse
switch (keysym) {
case 1: sprintf(&tmp[0], "Mouse Left"); break;
case 2: sprintf(&tmp[0], "Mouse Middle"); break;
case 3: sprintf(&tmp[0], "Mouse Right"); break;
default: // Use only number for extra button
sprintf(&tmp[0], "Mouse %d", keysym);
}
} else {
// keyboard
char* pstr = XKeysymToString(keysym);
if (pstr != NULL) tmp = pstr;
}
} else {
// joystick
KeyType k = type_of_joykey(pad, key);
switch (k)
{
case PAD_KEYBOARD:
{
char* pstr = KeysymToChar(pad_to_key(pad, key));
if (pstr != NULL) tmp = pstr;
break;
}
case PAD_JOYBUTTONS:
{
int button = key_to_button(pad, key);
tmp.resize(28);
sprintf(&tmp[0], "JBut %d", button);
break;
}
case PAD_JOYSTICK:
{
int axis = key_to_axis(pad, key);
tmp.resize(28);
sprintf(&tmp[0], "JAxis %d", axis);
break;
}
case PAD_HAT:
{
int axis = key_to_axis(pad, key);
tmp.resize(28);
switch(key_to_hat_dir(pad, key))
{
case SDL_HAT_UP:
sprintf(&tmp[0], "JPOVU-%d", axis);
break;
case SDL_HAT_RIGHT:
sprintf(&tmp[0], "JPOVR-%d", axis);
break;
case SDL_HAT_DOWN:
sprintf(&tmp[0], "JPOVD-%d", axis);
break;
case SDL_HAT_LEFT:
sprintf(&tmp[0], "JPOVL-%d", axis);
break;
int button = key_to_button(pad, key);
sprintf(&tmp[0], "JBut %d", button);
break;
}
case PAD_AXIS:
{
if (key_to_axis_type(pad,key))
sprintf(&tmp[0], "JAxis %d Full", key_to_axis(pad, key), key_to_axis_sign(pad, key) ? "-" : "+");
else
sprintf(&tmp[0], "JAxis %d Half%s", key_to_axis(pad, key), key_to_axis_sign(pad, key) ? "-" : "+");
break;
}
case PAD_HAT:
{
int axis = key_to_axis(pad, key);
switch(key_to_hat_dir(pad, key))
{
case SDL_HAT_UP:
sprintf(&tmp[0], "JPOVU-%d", axis);
break;
case SDL_HAT_RIGHT:
sprintf(&tmp[0], "JPOVR-%d", axis);
break;
case SDL_HAT_DOWN:
sprintf(&tmp[0], "JPOVD-%d", axis);
break;
case SDL_HAT_LEFT:
sprintf(&tmp[0], "JPOVL-%d", axis);
break;
}
break;
}
break;
}
case PAD_POV:
{
tmp.resize(28);
sprintf(&tmp[0], "JPOV %d%s", key_to_axis(pad, key), key_to_pov_sign(pad, key) ? "-" : "+");
break;
}
default: break;
}
}
return tmp;
}
void DefaultValues()
void DefaultKeyboardValues()
{
set_key(0, PAD_L2, XK_a);
set_key(0, PAD_R2, XK_semicolon);
set_key(0, PAD_L1, XK_w);
set_key(0, PAD_R1, XK_p);
set_key(0, PAD_TRIANGLE, XK_i);
set_key(0, PAD_CIRCLE, XK_l);
set_key(0, PAD_CROSS, XK_k);
set_key(0, PAD_SQUARE, XK_j);
set_key(0, PAD_SELECT, XK_v);
set_key(0, PAD_START, XK_n);
set_key(0, PAD_UP, XK_e);
set_key(0, PAD_RIGHT, XK_f);
set_key(0, PAD_DOWN, XK_d);
set_key(0, PAD_LEFT, XK_s);
set_keyboad_key(0, XK_a, PAD_L2);
set_keyboad_key(0, XK_semicolon, PAD_R2);
set_keyboad_key(0, XK_w, PAD_L1);
set_keyboad_key(0, XK_p, PAD_R1);
set_keyboad_key(0, XK_i, PAD_TRIANGLE);
set_keyboad_key(0, XK_l, PAD_CIRCLE);
set_keyboad_key(0, XK_k, PAD_CROSS);
set_keyboad_key(0, XK_j, PAD_SQUARE);
set_keyboad_key(0, XK_v, PAD_SELECT);
set_keyboad_key(0, XK_n, PAD_START);
set_keyboad_key(0, XK_e, PAD_UP);
set_keyboad_key(0, XK_f, PAD_RIGHT);
set_keyboad_key(0, XK_d, PAD_DOWN);
set_keyboad_key(0, XK_s, PAD_LEFT);
}
void SaveConfig()
@ -124,15 +128,24 @@ void SaveConfig()
return;
}
for (int pad = 0; pad < 2 * MAX_SUB_KEYS; pad++)
fprintf(f, "log = %d\n", conf->log);
fprintf(f, "options = %d\n", conf->options);
fprintf(f, "mouse_sensibility = %d\n", conf->sensibility);
fprintf(f, "joy_pad_map = %d\n", conf->joyid_map);
for (int pad = 0; pad < 2; pad++)
{
for (int key = 0; key < MAX_KEYS; key++)
{
fprintf(f, "[%d][%d] = 0x%lx\n", pad, key, get_key(pad,key));
fprintf(f, "[%d][%d] = 0x%x\n", pad, key, get_key(pad,key));
}
}
fprintf(f, "log = %d\n", conf.log);
fprintf(f, "options = %d\n", conf.options);
map<u32,u32>::iterator it;
for (int pad = 0; pad < 2 ; pad++)
for (it = conf->keysym_map[pad].begin(); it != conf->keysym_map[pad].end(); ++it)
fprintf(f, "PAD %d:KEYSYM 0x%x = %d\n", pad, it->first, it->second);
fclose(f);
}
@ -140,10 +153,12 @@ void LoadConfig()
{
FILE *f;
char str[256];
bool have_user_setting = false;
memset(&conf, 0, sizeof(conf));
DefaultValues();
conf.log = 0;
if (!conf)
conf = new PADconf;
conf->init();
const std::string iniFile(s_strIniPath + "OnePAD.ini");
f = fopen(iniFile.c_str(), "r");
@ -154,18 +169,33 @@ void LoadConfig()
return;
}
for (int pad = 0; pad < 2 * MAX_SUB_KEYS; pad++)
fscanf(f, "log = %d\n", &conf->log);
fscanf(f, "options = %d\n", &conf->options);
fscanf(f, "mouse_sensibility = %d\n", &conf->sensibility);
fscanf(f, "joy_pad_map = %d\n", &conf->joyid_map);
for (int pad = 0; pad < 2; pad++)
{
for (int key = 0; key < MAX_KEYS; key++)
{
sprintf(str, "[%d][%d] = 0x%%x\n", pad, key);
u32 temp;
u32 temp = 0;
if (fscanf(f, str, &temp) == 0) temp = 0;
set_key(pad, key, temp);
if (temp && pad == 0) have_user_setting = true;
}
}
fscanf(f, "log = %d\n", &conf.log);
fscanf(f, "options = %d\n", &conf.options);
u32 pad;
u32 keysym;
u32 index;
while( fscanf(f, "PAD %d:KEYSYM 0x%x = %d\n", &pad, &keysym, &index) != EOF ) {
set_keyboad_key(pad, keysym, index);
if(pad == 0) have_user_setting = true;
}
fclose(f);
if (!have_user_setting) DefaultKeyboardValues();
}

View File

@ -21,17 +21,15 @@
#include "joystick.h"
#include "onepad.h"
#include "keyboard.h"
#include <string.h>
#include <gtk/gtk.h>
#include "linux.h"
#include <gdk/gdkx.h>
extern void PollForKeyboardInput(int pad);
extern void SetAutoRepeat(bool autorep);
Display *GSdsp;
extern string KeyName(int pad, int key);
Window GSwin;
void SysMessage(const char *fmt, ...)
{
@ -66,22 +64,8 @@ EXPORT_C_(s32) PADtest()
s32 _PADopen(void *pDsp)
{
GtkScrolledWindow *win;
win = *(GtkScrolledWindow**) pDsp;
if (GTK_IS_WIDGET(win))
{
// Since we have a GtkScrolledWindow, for now we'll grab whatever display
// comes along instead. Later, we can fiddle with this, but I'm not sure the
// best way to get a Display* out of a GtkScrolledWindow. A GtkWindow I might
// be able to manage... --arcum42
GSdsp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
}
else
{
GSdsp = *(Display**)pDsp;
}
GSdsp = *(Display**)pDsp;
GSwin = (Window)*(((u32*)pDsp)+1);
SetAutoRepeat(false);
return 0;
@ -103,98 +87,105 @@ void _PADclose()
s_vjoysticks.clear();
}
static bool used_by_keyboard = false;
EXPORT_C_(void) PADupdate(int pad)
{
// Poll keyboard.
PollForKeyboardInput(pad);
// FIXME joystick directly update the status variable
// Keyboard does a nice roadtrip (with semaphore in the middle)
// s_keyRelease (by UpdateKeys) -> status (by _PADupdate -> by _PADpoll)
// If we need semaphore, joy part must be updated
// joystick info
SDL_JoystickUpdate();
// Actually PADupdate is always call with pad == 0. So you need to update both
// pads -- Gregory
for (int cpad = 0; cpad < 2; cpad++) {
int keyPress = 0, keyRelease = 0;
for (int i = 0; i < MAX_KEYS; i++)
{
int cpad = PadEnum[pad][0];
// Poll keyboard.
PollForX11KeyboardInput(cpad, keyPress, keyRelease, used_by_keyboard);
if (JoystickIdWithinBounds(key_to_joystick_id(cpad, i)))
{
JoystickInfo* pjoy = s_vjoysticks[key_to_joystick_id(cpad, i)];
int pad = (pjoy)->GetPAD();
UpdateKeys(pad, keyPress, keyRelease);
switch (type_of_key(cpad, i))
// joystick info
SDL_JoystickUpdate();
int joyid = conf->get_joyid(cpad);
if (JoystickIdWithinBounds(joyid)) {
for (int i = 0; i < MAX_KEYS; i++)
{
case PAD_JOYBUTTONS:
{
int value = SDL_JoystickGetButton((pjoy)->GetJoy(), key_to_button(cpad, i));
JoystickInfo* pjoy = s_vjoysticks[joyid];
if (value)
clear_bit(status[pad], i); // released
else
set_bit(status[pad], i); // pressed
break;
}
case PAD_HAT:
switch (type_of_joykey(cpad, i))
{
int value = SDL_JoystickGetHat((pjoy)->GetJoy(), key_to_axis(cpad, i));
case PAD_JOYBUTTONS:
{
if (key_to_hat_dir(cpad, i) == value)
{
clear_bit(status[pad], i);
//PAD_LOG("Registered %s\n", HatName(value), i);
//PAD_LOG("%s\n", KeyName(cpad, i).c_str());
}
else
{
set_bit(status[pad], i);
}
break;
}
case PAD_POV:
{
int value = pjoy->GetAxisFromKey(cpad, i);
PAD_LOG("%s: %d (%d)\n", KeyName(cpad, i).c_str(), value, key_to_pov_sign(cpad, i));
if (key_to_pov_sign(cpad, i) && (value < -2048))
{
//PAD_LOG("%s Released+.\n", KeyName(cpad, i).c_str());
clear_bit(status[pad], i);
}
else if (!key_to_pov_sign(cpad, i) && (value > 2048))
{
//PAD_LOG("%s Released-\n", KeyName(cpad, i).c_str());
clear_bit(status[pad], i);
}
else
{
//PAD_LOG("%s Pressed.\n", KeyName(cpad, i).c_str());
set_bit(status[pad], i);
}
break;
}
case PAD_JOYSTICK:
{
int value = pjoy->GetAxisFromKey(cpad, i);
switch (i)
{
case PAD_LX:
case PAD_LY:
case PAD_RX:
case PAD_RY:
if (abs(value) > (pjoy)->GetDeadzone(/*value*/))
Analog::ConfigurePad(pad, i, value);
int value = SDL_JoystickGetButton((pjoy)->GetJoy(), key_to_button(cpad, i));
if (value)
clear_bit(status[cpad], i); // released
else
Analog::ResetPad(pad, i);
set_bit(status[cpad], i); // pressed
break;
}
break;
}
case PAD_HAT:
{
int value = SDL_JoystickGetHat((pjoy)->GetJoy(), key_to_axis(cpad, i));
if (key_to_hat_dir(cpad, i) == value)
clear_bit(status[cpad], i);
else
set_bit(status[cpad], i);
break;
}
case PAD_AXIS:
{
int value = pjoy->GetAxisFromKey(cpad, i);
bool sign = key_to_axis_sign(cpad, i);
bool full_axis = key_to_axis_type(cpad, i);
if (IsAnalogKey(i)) {
if (abs(value) > (pjoy)->GetDeadzone())
Analog::ConfigurePad(cpad, i, value);
else if (! (conf->options & ((PADOPTION_MOUSE_R|PADOPTION_MOUSE_L) << 16 * cpad ))
&& !(used_by_keyboard) )
// There is a conflict between keyboard/mouse and joystick configuration.
// Do nothing when either the mouse or the keyboad is pressed/enabled.
// It avoid to be stuck in reset mode --Gregory
Analog::ResetPad(cpad, i);
} else {
if (full_axis) {
value += 0x8000;
if (value > 2048) {
clear_bit(status[cpad], i);
status_pressure[cpad][i] = min(value/256 , 0xFF); // Max pressure is 255
} else {
set_bit(status[cpad], i);
status_pressure[cpad][i] = 0; // no pressure
}
} else {
if (sign && (value < -2048)) {
clear_bit(status[cpad], i);
status_pressure[cpad][i] = min(-value /128, 0xFF); // Max pressure is 255
} else if (!sign && (value > 2048)) {
clear_bit(status[cpad], i);
status_pressure[cpad][i] = min(value /128, 0xFF); // Max pressure is 255
} else {
set_bit(status[cpad], i);
status_pressure[cpad][i] = 0; // no pressure
}
}
}
}
default: break;
}
default: break;
}
}
}
}
EXPORT_C_(void) PADconfigure()
{
LoadConfig();

View File

@ -18,14 +18,9 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
//
//#include "joystick.h"
//#include "keyboard.h"
//#include "onepad.h"
//
//#include <string.h>
//#include <gtk/gtk.h>
//#include <gdk/gdkkeysyms.h>
//#include <pthread.h>
#ifndef __LINUX_H__
#define __LINUX_H__
extern void DisplayDialog();
extern string KeyName(int pad, int key, int keysym = 0);
#endif

View File

@ -19,8 +19,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "analog.h"
PADAnalog g_lanalog[NUM_OF_PADS], g_ranalog[NUM_OF_PADS];
#include "analog.h"
static PADAnalog g_lanalog[NUM_OF_PADS], g_ranalog[NUM_OF_PADS];
namespace Analog
{
@ -28,58 +28,42 @@ namespace Analog
{
switch (index)
{
case PAD_LX:
return g_lanalog[pad].x;
break;
case PAD_R_LEFT:
case PAD_R_RIGHT: return g_ranalog[pad].x;
case PAD_RX:
return g_ranalog[pad].x;
break;
case PAD_R_DOWN:
case PAD_R_UP: return g_ranalog[pad].y;
case PAD_LY:
return g_lanalog[pad].y;
break;
case PAD_L_LEFT:
case PAD_L_RIGHT: return g_lanalog[pad].x;
case PAD_RY:
return g_ranalog[pad].y;
break;
case PAD_L_DOWN:
case PAD_L_UP: return g_lanalog[pad].y;
default:
return 0;
break;
default: return 0;
}
}
void SetPad(u8 pad, int index, u8 value)
static void SetPad(u8 pad, int index, u8 value)
{
switch (index)
{
case PAD_LX:
g_lanalog[pad].x = value;
break;
case PAD_R_LEFT:
case PAD_R_RIGHT: g_ranalog[pad].x = value; break;
case PAD_RX:
g_ranalog[ pad].x = value;
break;
case PAD_R_DOWN:
case PAD_R_UP: g_ranalog[pad].y = value; break;
case PAD_LY:
g_lanalog[ pad].y = value;
break;
case PAD_L_LEFT:
case PAD_L_RIGHT: g_lanalog[pad].x = value; break;
case PAD_RY:
g_ranalog[pad].y = value;
break;
case PAD_L_DOWN:
case PAD_L_UP: g_lanalog[pad].y = value; break;
default:
break;
default: break;
}
}
void InvertPad(u8 pad, int key)
{
SetPad(pad, key, -Pad(pad, key));
}
void ResetPad( u8 pad, int key)
{
SetPad(pad, key, 0x80);
@ -89,76 +73,47 @@ namespace Analog
{
for (u8 pad = 0; pad < 2; ++pad)
{
ResetPad(pad, PAD_LX);
ResetPad(pad, PAD_LY);
ResetPad(pad, PAD_RX);
ResetPad(pad, PAD_RY);
// no need to put the 2 part of the axis
ResetPad(pad, PAD_R_LEFT);
ResetPad(pad, PAD_R_DOWN);
ResetPad(pad, PAD_L_LEFT);
ResetPad(pad, PAD_L_DOWN);
}
}
bool ReversePad(u8 index)
static bool ReversePad(u8 index)
{
switch (index)
{
case PAD_LX:
return ((conf.options & PADOPTION_REVERSELX) != 0);
break;
case PAD_L_RIGHT:
case PAD_L_LEFT:
return ((conf->options & PADOPTION_REVERSELX) != 0);
case PAD_RX:
return ((conf.options & PADOPTION_REVERSERX) != 0);
break;
case PAD_R_LEFT:
case PAD_R_RIGHT:
return ((conf->options & PADOPTION_REVERSERX) != 0);
case PAD_LY:
return ((conf.options & PADOPTION_REVERSELY) != 0);
break;
case PAD_L_UP:
case PAD_L_DOWN:
return ((conf->options & PADOPTION_REVERSELY) != 0);
case PAD_RY:
return ((conf.options & PADOPTION_REVERSERY) != 0);
break;
case PAD_R_DOWN:
case PAD_R_UP:
return ((conf->options & PADOPTION_REVERSERY) != 0);
default:
return false;
break;
default: return false;
}
}
void ConfigurePad( u8 pad, int index, int value)
{
Pad(pad, index);
SetPad(pad, index, value / 256);
if (ReversePad(index)) InvertPad(pad,index);
SetPad(pad, index, Pad(pad, index) + 0x80);
}
int AnalogToPad(int index)
{
switch (index)
{
case PAD_R_LEFT:
return PAD_RX;
break;
case PAD_R_UP:
return PAD_RY;
break;
case PAD_L_LEFT:
return PAD_LX;
break;
case PAD_L_UP:
return PAD_LY;
break;
case PAD_R_DOWN:
return PAD_RY;
break;
case PAD_R_RIGHT:
return PAD_RX;
break;
case PAD_L_DOWN:
return PAD_LY;
break;
case PAD_L_RIGHT:
return PAD_LX;
break;
}
return 0;
// Left -> -- -> Right
// Value range : FFFF8002 -> 0 -> 7FFE
// Force range : 80 -> 0 -> 7F
// Normal mode : expect value 0 -> 80 -> FF
// Reverse mode: expect value FF -> 7F -> 0
u8 force = (value / 256);
if (ReversePad(index)) SetPad(pad, index, 0x7F - force);
else SetPad(pad, index, 0x80 + force);
}
}

View File

@ -19,18 +19,14 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#define NUM_OF_PADS 2
#define NUM_OF_PADS 2
#include "onepad.h"
namespace Analog
#include "onepad.h"
namespace Analog
{
extern void Init();
extern u8 Pad(int pad, u8 index);
extern void SetPad(u8 pad, int index, u8 value);
extern void InvertPad(u8 pad, int key);
extern bool ReversePad(u8 index);
extern void ResetPad( u8 pad, int key);
extern void ConfigurePad( u8 pad, int index, int value);
extern int KeypadToPad(u8 keypress);
extern int AnalogToPad(int index);
}

View File

@ -24,74 +24,89 @@
HatPins hat_position = {false, false, false, false};
__forceinline void set_keyboad_key(int pad, int keysym, int index)
{
conf->keysym_map[pad][keysym] = index;
}
__forceinline int get_keyboard_key(int pad, int keysym)
{
// You must use find instead of []
// [] will create an element if the key does not exist and return 0
map<u32,u32>::iterator it = conf->keysym_map[pad].find(keysym);
if (it != conf->keysym_map[pad].end())
return it->second;
else
return -1;
}
__forceinline void set_key(int pad, int index, int value)
{
conf.keys[pad][index] = value;
conf->keys[pad][index] = value;
}
__forceinline int get_key(int pad, int index)
{
return conf.keys[pad][index];
return conf->keys[pad][index];
}
__forceinline KeyType type_of_key(int pad, int index)
{
int key = conf.keys[pad][index];
if (key < 0x10000) return PAD_KEYBOARD;
else if (key >= 0x10000 && key < 0x20000) return PAD_JOYBUTTONS;
else if (key >= 0x20000 && key < 0x30000) return PAD_JOYSTICK;
else if (key >= 0x30000 && key < 0x40000) return PAD_POV;
else if (key >= 0x40000 && key < 0x50000) return PAD_HAT;
else return PAD_NULL;
}
__forceinline int pad_to_key(int pad, int index)
{
return ((conf.keys[pad][index]) & 0xffff);
}
__forceinline int key_to_joystick_id(int pad, int index)
__forceinline KeyType type_of_joykey(int pad, int index)
{
return (((conf.keys[pad][index]) & 0xf000) >> 12);
int key = get_key(pad, index);
if (key >= 0x10000 && key < 0x20000) return PAD_JOYBUTTONS;
else if (key >= 0x20000 && key < 0x30000) return PAD_AXIS;
else if (key >= 0x30000 && key < 0x40000) return PAD_HAT;
else return PAD_NULL;
}
__forceinline bool IsAnalogKey(int index)
{
return ((index >= PAD_L_UP) && (index <= PAD_R_LEFT));
}
//*******************************************************
// onepad key -> joy input
//*******************************************************
__forceinline int key_to_button(int pad, int index)
{
return ((conf.keys[pad][index]) & 0xff);
return (get_key(pad, index) & 0xff);
}
__forceinline int key_to_axis(int pad, int index)
{
return ((conf.keys[pad][index]) & 0xff);
return (get_key(pad, index) & 0xff);
}
__forceinline int button_to_key(int joy_id, int button_id)
__forceinline bool key_to_axis_sign(int pad, int index)
{
return (0x10000 | ((joy_id) << 12) | (button_id));
return ((get_key(pad, index) >> 8) & 0x1);
}
__forceinline int joystick_to_key(int joy_id, int axis_id)
__forceinline bool key_to_axis_type(int pad, int index)
{
return (0x20000 | ((joy_id) << 12) | (axis_id));
}
__forceinline int pov_to_key(int joy_id, int sign, int axis_id)
{
return (0x30000 | ((joy_id) << 12) | ((sign) << 8) | (axis_id));
}
__forceinline int hat_to_key(int joy_id, int dir, int axis_id)
{
return (0x40000 | ((joy_id) << 12) | ((dir) << 8) | (axis_id));
}
__forceinline int key_to_pov_sign(int pad, int index)
{
return (((conf.keys[pad][index]) & 0x100) >> 8);
return ((get_key(pad, index) >> 9) & 0x1);
}
__forceinline int key_to_hat_dir(int pad, int index)
{
return (((conf.keys[pad][index]) & 0xF00) >> 8);
return ((get_key(pad, index) >> 8) & 0xF);
}
//*******************************************************
// joy input -> onepad key
//*******************************************************
__forceinline int button_to_key(int button_id)
{
return (0x10000 | button_id);
}
__forceinline int axis_to_key(int full_axis, int sign, int axis_id)
{
return (0x20000 | (full_axis << 9) | (sign << 8) | axis_id);
}
__forceinline int hat_to_key(int dir, int axis_id)
{
return (0x30000 | (dir << 8) | axis_id);
}

View File

@ -23,42 +23,35 @@
#define __CONTROLLER_H__
#ifdef __LINUX__
#define MAX_KEYS 28
#define MAX_KEYS 24
#else
#define MAX_KEYS 20
#endif
#ifdef _WIN32
#define MAX_SUB_KEYS 1
#else
#define MAX_SUB_KEYS 2
#endif
enum KeyType
{
PAD_KEYBOARD = 0,
PAD_JOYBUTTONS,
PAD_JOYSTICK,
PAD_POV,
PAD_JOYBUTTONS = 0,
PAD_AXIS,
PAD_HAT,
PAD_NULL = -1
};
extern void set_keyboad_key(int pad, int keysym, int index);
extern int get_keyboard_key(int pad, int keysym);
extern void set_key(int pad, int index, int value);
extern int get_key(int pad, int index);
extern bool IsAnalogKey(int index);
extern KeyType type_of_key(int pad, int index);
extern int pad_to_key(int pad, int index);
extern int key_to_joystick_id(int pad, int index);
extern KeyType type_of_joykey(int pad, int index);
extern int key_to_button(int pad, int index);
extern int key_to_axis(int pad, int index);
extern int key_to_pov_sign(int pad, int index);
extern bool key_to_axis_sign(int pad, int index);
extern bool key_to_axis_type(int pad, int index);
extern int key_to_hat_dir(int pad, int index);
extern int button_to_key(int joy_id, int button_id);
extern int joystick_to_key(int joy_id, int axis_id);
extern int pov_to_key(int joy_id, int sign, int axis_id);
extern int hat_to_key(int joy_id, int dir, int axis_id);
extern int button_to_key(int button_id);
extern int axis_to_key(int full_axis, int sign, int axis_id);
extern int hat_to_key(int dir, int axis_id);
extern int PadEnum[2][2];
@ -111,19 +104,41 @@ static __forceinline void set_hat_pins(int tilt_o_the_hat)
}
}
typedef struct
struct PADconf
{
u32 keys[2 * MAX_SUB_KEYS][MAX_KEYS];
public:
u32 keys[2][MAX_KEYS];
u32 log;
u32 options; // upper 16 bits are for pad2
} PADconf;
u32 sensibility;
u32 joyid_map;
map<u32,u32> keysym_map[2];
PADconf() { init(); }
void init() {
memset(&keys, 0, sizeof(keys));
log = options = joyid_map = 0;
sensibility = 500;
for (int pad = 0; pad < 2 ; pad++)
keysym_map[pad].clear();
}
void set_joyid(u32 pad, u32 joy_id) {
int shift = 8 * pad;
joyid_map &= ~(0xFF << shift); // clear
joyid_map |= (joy_id & 0xFF) << shift; // set
}
u32 get_joyid(u32 pad) {
int shift = 8 * pad;
return ((joyid_map >> shift) & 0xFF);
}
};
extern PADconf *conf;
typedef struct
{
u8 x, y;
} PADAnalog;
extern PADconf conf;
extern PADAnalog g_lanalog[2], g_ranalog[2];
#endif

View File

@ -65,6 +65,7 @@ bool JoystickIdWithinBounds(int joyid)
{
return ((joyid >= 0) && (joyid < (int)s_vjoysticks.size()));
}
// opens handles to all possible joysticks
void JoystickInfo::EnumerateJoysticks(vector<JoystickInfo*>& vjoysticks)
{
@ -75,9 +76,7 @@ void JoystickInfo::EnumerateJoysticks(vector<JoystickInfo*>& vjoysticks)
// SDL in 3rdparty wrap X11 call. In order to get x11 symbols loaded
// video must be loaded too.
// Example of X11 symbol are XAutoRepeatOn/XAutoRepeatOff
// Just to play it safe I separate 1.2 and 1.3 but I think it will be
// fine in 1.2 too -- greg
if (SDL_Init(SDL_INIT_JOYSTICK|SDL_INIT_VIDEO) < 0) return;
if (SDL_Init(SDL_INIT_JOYSTICK|SDL_INIT_VIDEO|SDL_INIT_HAPTIC) < 0) return;
#else
if (SDL_Init(SDL_INIT_JOYSTICK) < 0) return;
#endif
@ -101,32 +100,118 @@ void JoystickInfo::EnumerateJoysticks(vector<JoystickInfo*>& vjoysticks)
vjoysticks[i] = new JoystickInfo();
vjoysticks[i]->Init(i);
}
}
// set the pads
for (int pad = 0; pad < 2; ++pad)
{
// select the right joystick id
int joyid = -1;
void JoystickInfo::InitHapticEffect()
{
#if SDL_VERSION_ATLEAST(1,3,0)
if (haptic == NULL) return;
for (int i = 0; i < MAX_KEYS; ++i)
{
KeyType k = type_of_key(pad,i);
if (k == PAD_JOYSTICK || k == PAD_JOYBUTTONS)
{
joyid = key_to_joystick_id(pad,i);
break;
}
}
#if 0
additional field of the effect
/* Trigger */
Uint16 button; /**< Button that triggers the effect. */
Uint16 interval; /**< How soon it can be triggered again after button. */
if ((joyid >= 0) && (joyid < (int)s_vjoysticks.size())) s_vjoysticks[joyid]->Assign(pad);
// periodic parameter
Sint16 offset; /**< Mean value of the wave. */
Uint16 phase; /**< Horizontal shift given by hundredth of a cycle. */
#endif
/*******************************************************************/
/* Effect small */
/*******************************************************************/
haptic_effect_data[0].type = SDL_HAPTIC_SQUARE;
// Direction of the effect SDL_HapticDirection
haptic_effect_data[0].periodic.direction.type = SDL_HAPTIC_POLAR; // Polar coordinates
haptic_effect_data[0].periodic.direction.dir[0] = 18000; // Force comes from south
// periodic parameter
haptic_effect_data[0].periodic.period = 1000; // 1000 ms
haptic_effect_data[0].periodic.magnitude = 2000; // 2000/32767 strength
// Replay
haptic_effect_data[0].periodic.length = 2000; // 2 seconds long
haptic_effect_data[0].periodic.delay = 0; // start 0 second after the upload
// enveloppe
haptic_effect_data[0].periodic.attack_length = 500;// Takes 0.5 second to get max strength
haptic_effect_data[0].periodic.attack_level = 0; // start at 0
haptic_effect_data[0].periodic.fade_length = 500; // Takes 0.5 second to fade away
haptic_effect_data[0].periodic.fade_level = 0; // finish at 0
/*******************************************************************/
/* Effect big */
/*******************************************************************/
haptic_effect_data[1].type = SDL_HAPTIC_TRIANGLE;
// Direction of the effect SDL_HapticDirection
haptic_effect_data[1].periodic.direction.type = SDL_HAPTIC_POLAR; // Polar coordinates
haptic_effect_data[1].periodic.direction.dir[0] = 18000; // Force comes from south
// periodic parameter
haptic_effect_data[1].periodic.period = 1000; // 1000 ms
haptic_effect_data[1].periodic.magnitude = 2000; // 2000/32767 strength
// Replay
haptic_effect_data[1].periodic.length = 2000; // 2 seconds long
haptic_effect_data[1].periodic.delay = 0; // start 0 second after the upload
// enveloppe
haptic_effect_data[1].periodic.attack_length = 500;// Takes 0.5 second to get max strength
haptic_effect_data[1].periodic.attack_level = 0; // start at 0
haptic_effect_data[1].periodic.fade_length = 500; // Takes 0.5 second to fade away
haptic_effect_data[1].periodic.fade_level = 0; // finish at 0
/*******************************************************************/
/* Upload effect to the device */
/*******************************************************************/
for (int i = 0 ; i < 2 ; i++)
haptic_effect_id[i] = SDL_HapticNewEffect(haptic, &haptic_effect_data[i]);
#endif
}
void JoystickInfo::DoHapticEffect(int type, int pad, int force)
{
if (type > 1) return;
if ( !(conf->options & (PADOPTION_FORCEFEEDBACK << 16 * pad)) ) return;
#if SDL_VERSION_ATLEAST(1,3,0)
// first search the joy associated to the pad
vector<JoystickInfo*>::iterator itjoy = s_vjoysticks.begin();
while (itjoy != s_vjoysticks.end()) {
if ((*itjoy)->GetPAD() == pad) break;
itjoy++;
}
if (itjoy == s_vjoysticks.end()) return;
if ((*itjoy)->haptic == NULL) return;
if ((*itjoy)->haptic_effect_id[type] < 0) return;
// FIXME: might need to multiply force
(*itjoy)->haptic_effect_data[type].periodic.magnitude = force; // force/32767 strength
// Upload the new effect
SDL_HapticUpdateEffect((*itjoy)->haptic, (*itjoy)->haptic_effect_id[type], &(*itjoy)->haptic_effect_data[type]);
// run the effect once
SDL_HapticRunEffect( (*itjoy)->haptic, (*itjoy)->haptic_effect_id[type], 1 );
#endif
}
void JoystickInfo::Destroy()
{
if (joy != NULL)
{
#if SDL_VERSION_ATLEAST(1,3,0)
// Haptic must be closed before the joystick
if (haptic != NULL) {
SDL_HapticClose(haptic);
haptic = NULL;
}
#endif
if (SDL_JoystickOpened(_id)) SDL_JoystickClose(joy);
joy = NULL;
}
@ -153,32 +238,20 @@ bool JoystickInfo::Init(int id)
vbuttonstate.resize(numbuttons);
vhatstate.resize(numhats);
//PAD_LOG("There are %d buttons, %d axises, and %d hats.\n", numbuttons, numaxes, numhats);
return true;
}
// assigns a joystick to a pad
void JoystickInfo::Assign(int newpad)
{
if (pad == newpad) return;
pad = newpad;
if (pad >= 0)
{
for (int i = 0; i < MAX_KEYS; ++i)
{
KeyType k = type_of_key(pad,i);
if (k == PAD_JOYBUTTONS)
{
set_key(pad, i, button_to_key(_id, key_to_button(pad,i)));
}
else if (k == PAD_JOYSTICK)
{
set_key(pad, i, joystick_to_key(_id, key_to_button(pad,i)));
}
#if SDL_VERSION_ATLEAST(1,3,0)
if ( haptic == NULL ) {
if (!SDL_JoystickIsHaptic(joy)) {
PAD_LOG("Haptic devices not supported!\n");
} else {
haptic = SDL_HapticOpenFromJoystick(joy);
// upload some default effect
InitHapticEffect();
}
}
#endif
//PAD_LOG("There are %d buttons, %d axises, and %d hats.\n", numbuttons, numaxes, numhats);
return true;
}
void JoystickInfo::SaveState()
@ -195,7 +268,7 @@ void JoystickInfo::TestForce()
{
}
bool JoystickInfo::PollButtons(int &jbutton, u32 &pkey)
bool JoystickInfo::PollButtons(u32 &pkey)
{
// MAKE sure to look for changes in the state!!
for (int i = 0; i < GetNumButtons(); ++i)
@ -206,12 +279,21 @@ bool JoystickInfo::PollButtons(int &jbutton, u32 &pkey)
{
if (!but) // released, we don't really want this
{
SetButtonState(i, 0);
break;
continue;
}
// Pressure sensitive button are detected as both button (digital) and axe (analog). So better
// drop the button to emulate the pressure sensiblity of the ds2 :) -- Gregory
for (int j = 0; j < GetNumAxes(); ++j) {
int value = SDL_JoystickGetAxis(GetJoy(), j);
int old_value = GetAxisState(j);
bool full_axis = (old_value < -0x3FFF) ? true : false;
if (value != old_value && ((full_axis && value > -0x6FFF ) || (!full_axis && abs(value) > old_value))) {
return false;
}
}
pkey = button_to_key(GetId(), i);
jbutton = i;
pkey = button_to_key(i);
return true;
}
}
@ -219,29 +301,33 @@ bool JoystickInfo::PollButtons(int &jbutton, u32 &pkey)
return false;
}
bool JoystickInfo::PollPOV(int &axis_id, bool &sign, u32 &pkey)
bool JoystickInfo::PollAxes(u32 &pkey)
{
for (int i = 0; i < GetNumAxes(); ++i)
{
int value = SDL_JoystickGetAxis(GetJoy(), i);
int old_value = GetAxisState(i);
if (value != GetAxisState(i))
if (value != old_value)
{
PAD_LOG("Change in joystick %d: %d.\n", i, value);
// There is several kinds of axes
// Half+: 0 (release) -> 32768
// Half-: 0 (release) -> -32768
// Full (like dualshock 3): -32768 (release) ->32768
bool full_axis = (old_value < -0x2FFF) ? true : false;
if (abs(value) <= GetAxisState(i)) // we don't want this
if ((!full_axis && abs(value) <= 0x1FFF)
|| (full_axis && value <= -0x6FFF)) // we don't want this
{
// released, we don't really want this
SetAxisState(i, value);
break;
continue;
}
if (abs(value) > 0x3fff)
if ((!full_axis && abs(value) > 0x3FFF)
|| (full_axis && value > -0x6FFF))
{
axis_id = i;
sign = (value < 0);
pkey = pov_to_key(GetId(), sign, i);
bool sign = (value < 0);
pkey = axis_to_key(full_axis, sign, i);
return true;
}
@ -250,36 +336,7 @@ bool JoystickInfo::PollPOV(int &axis_id, bool &sign, u32 &pkey)
return false;
}
bool JoystickInfo::PollAxes(int &axis_id, u32 &pkey)
{
for (int i = 0; i < GetNumAxes(); ++i)
{
int value = SDL_JoystickGetAxis(GetJoy(), i);
if (value != GetAxisState(i))
{
PAD_LOG("Change in joystick %d: %d.\n", i, value);
if (abs(value) <= GetAxisState(i)) // we don't want this
{
// released, we don't really want this
SetAxisState(i, value);
break;
}
if (abs(value) > 0x3fff)
{
axis_id = i;
pkey = joystick_to_key(GetId(), i);
return true;
}
}
}
return false;
}
bool JoystickInfo::PollHats(int &jbutton, int &dir, u32 &pkey)
bool JoystickInfo::PollHats(u32 &pkey)
{
for (int i = 0; i < GetNumHats(); ++i)
{
@ -293,9 +350,7 @@ bool JoystickInfo::PollHats(int &jbutton, int &dir, u32 &pkey)
case SDL_HAT_RIGHT:
case SDL_HAT_DOWN:
case SDL_HAT_LEFT:
pkey = hat_to_key(GetId(), value, i);
jbutton = i;
dir = value;
pkey = hat_to_key(value, i);
PAD_LOG("Hat Pressed!");
return true;
default:

View File

@ -22,10 +22,9 @@
#ifndef __JOYSTICK_H__
#define __JOYSTICK_H__
#ifdef __LINUX__
#include <SDL/SDL.h>
#else
#include <SDL.h>
#include "SDL.h"
#if SDL_VERSION_ATLEAST(1,3,0)
#include "SDL_haptic.h"
#endif
#include "onepad.h"
@ -36,7 +35,17 @@ class JoystickInfo
{
public:
JoystickInfo() : devname(""), _id(-1), numbuttons(0), numaxes(0), numhats(0), axisrange(0x7fff),
deadzone(2000), pad(-1), vbuttonstate(NULL), vaxisstate(NULL), vhatstate(NULL), joy(NULL) {}
deadzone(2000), pad(-1), joy(NULL) {
vbuttonstate.clear();
vaxisstate.clear();
vhatstate.clear();
#if SDL_VERSION_ATLEAST(1,3,0)
haptic = NULL;
for (int i = 0 ; i < 2 ; i++)
haptic_effect_id[i] = -1;
#endif
}
~JoystickInfo()
{
Destroy();
@ -49,15 +58,16 @@ class JoystickInfo
// opens handles to all possible joysticks
static void EnumerateJoysticks(vector<JoystickInfo*>& vjoysticks);
void InitHapticEffect();
static void DoHapticEffect(int type, int pad, int force);
bool Init(int id); // opens a handle and gets information
void Assign(int pad); // assigns a joystick to a pad
void TestForce();
bool PollButtons(int &jbutton, u32 &pkey);
bool PollAxes(int &axis_id, u32 &pkey);
bool PollHats(int &jbutton, int &dir, u32 &pkey);
bool PollPOV(int &axis_id, bool &sign, u32 &pkey);
bool PollButtons(u32 &pkey);
bool PollAxes(u32 &pkey);
bool PollHats(u32 &pkey);
const string& GetName()
{
@ -79,11 +89,6 @@ class JoystickInfo
return numhats;
}
int GetId()
{
return _id;
}
int GetPAD()
{
return pad;
@ -145,7 +150,12 @@ class JoystickInfo
vector<int> vbuttonstate, vaxisstate, vhatstate;
SDL_Joystick* joy;
SDL_Joystick* joy;
#if SDL_VERSION_ATLEAST(1,3,0)
SDL_Haptic* haptic;
SDL_HapticEffect haptic_effect_data[2];
int haptic_effect_id[2];
#endif
};

View File

@ -28,32 +28,15 @@
#include <gdk/gdkkeysyms.h>
#include "keyboard.h"
int FindKey(int key, int pad)
{
for (int p = 0; p < MAX_SUB_KEYS; p++)
for (int i = 0; i < MAX_KEYS; i++)
if (key == get_key(PadEnum[pad][p], i)) return i;
return -1;
}
#ifndef __LINUX__
char* KeysymToChar(int keysym)
{
#ifdef __LINUX__
return XKeysymToString(keysym);
#else
LPWORD temp;
ToAscii((UINT) keysym, NULL, NULL, temp, NULL);
return (char*)temp;
#endif
}
void PollForKeyboardInput(int pad)
{
#ifdef __LINUX__
PollForX11KeyboardInput(pad);
#endif
}
void SetAutoRepeat(bool autorep)
{
@ -69,117 +52,232 @@ void SetAutoRepeat(bool autorep)
}
#ifdef __LINUX__
void PollForX11KeyboardInput(int pad)
static bool s_grab_input = false;
static bool s_Shift = false;
static unsigned int s_previous_mouse_x = 0;
static unsigned int s_previous_mouse_y = 0;
void AnalyzeKeyEvent(int pad, keyEvent &evt, int& keyPress, int& keyRelease, bool& used_by_keyboard)
{
XEvent E;
KeySym key;
int keyPress = 0, keyRelease = 0;
int i;
KeySym key = (KeySym)evt.key;
// keyboard input
while (XPending(GSdsp) > 0)
switch (evt.evt)
{
XNextEvent(GSdsp, &E);
switch (E.type)
{
case KeyPress:
key = XLookupKeysym((XKeyEvent *) & E, 0);
case KeyPress:
// Shift F12 is not yet use by pcsx2. So keep it to grab/ungrab input
// I found it very handy vs the automatic fullscreen detection
// 1/ Does not need to detect full-screen
// 2/ Can use a debugger in full-screen
// 3/ Can grab input in window without the need of a pixelated full-screen
if (key == XK_Shift_R || key == XK_Shift_L) s_Shift = true;
if (key == XK_F12 && s_Shift) {
if(!s_grab_input) {
s_grab_input = true;
XGrabPointer(GSdsp, GSwin, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, GSwin, None, CurrentTime);
XGrabKeyboard(GSdsp, GSwin, True, GrabModeAsync, GrabModeAsync, CurrentTime);
} else {
s_grab_input = false;
XUngrabPointer(GSdsp, CurrentTime);
XUngrabKeyboard(GSdsp, CurrentTime);
}
}
i = FindKey(key, pad);
i = get_keyboard_key(pad, key);
// Analog controls.
if ((i > PAD_RY) && (i <= PAD_R_LEFT))
{
// Analog controls.
if (IsAnalogKey(i))
{
used_by_keyboard = true; // avoid the joystick to reset the analog pad...
switch (i)
{
case PAD_R_LEFT:
case PAD_R_UP:
case PAD_L_LEFT:
case PAD_L_UP:
Analog::ConfigurePad(pad, Analog::AnalogToPad(i), DEF_VALUE);
Analog::ConfigurePad(pad, i, -DEF_VALUE);
break;
case PAD_R_RIGHT:
case PAD_R_DOWN:
case PAD_L_RIGHT:
case PAD_L_DOWN:
Analog::ConfigurePad(pad, Analog::AnalogToPad(i), -DEF_VALUE);
Analog::ConfigurePad(pad, i, DEF_VALUE);
break;
}
i += 0xff00;
}
if (i != -1)
{
clear_bit(keyRelease, i);
set_bit(keyPress, i);
}
//PAD_LOG("Key pressed:%d\n", i);
event.evt = KEYPRESS;
event.key = key;
break;
case KeyRelease:
if (key == XK_Shift_R || key == XK_Shift_L) s_Shift = false;
i = get_keyboard_key(pad, key);
// Analog Controls.
if (IsAnalogKey(i))
{
used_by_keyboard = false; // allow the joystick to reset the analog pad...
Analog::ResetPad(pad, i);
i += 0xff00;
}
if (i != -1)
{
clear_bit(keyPress, i);
set_bit(keyRelease, i);
}
event.evt = KEYRELEASE;
event.key = key;
break;
case FocusIn:
XAutoRepeatOff(GSdsp);
break;
case FocusOut:
XAutoRepeatOn(GSdsp);
break;
case ButtonPress:
i = get_keyboard_key(pad, evt.key);
if (i != -1)
{
clear_bit(keyRelease, i);
set_bit(keyPress, i);
}
break;
case ButtonRelease:
i = get_keyboard_key(pad, evt.key);
if (i != -1)
{
clear_bit(keyPress, i);
set_bit(keyRelease, i);
}
break;
case MotionNotify:
// FIXME: How to handle when the mouse does not move, no event generated!!!
// 1/ small move == no move. Cons : can not do small movement
// 2/ use a watchdog timer thread
// 3/ ??? idea welcome ;)
if (conf->options & ((PADOPTION_MOUSE_L|PADOPTION_MOUSE_R) << 16 * pad )) {
unsigned int pad_x;
unsigned int pad_y;
// Note when both PADOPTION_MOUSE_R and PADOPTION_MOUSE_L are set, take only the right one
if (conf->options & (PADOPTION_MOUSE_R << 16 * pad)) {
pad_x = PAD_R_RIGHT;
pad_y = PAD_R_UP;
} else {
pad_x = PAD_L_RIGHT;
pad_y = PAD_L_UP;
}
if (i != -1)
{
clear_bit(keyRelease, i);
set_bit(keyPress, i);
}
//PAD_LOG("Key pressed:%d\n", i);
unsigned x = evt.key & 0xFFFF;
unsigned int value = abs(s_previous_mouse_x - x) * conf->sensibility;
value = max(value, (unsigned int)DEF_VALUE);
event.evt = KEYPRESS;
event.key = key;
break;
if (x == 0)
Analog::ConfigurePad(pad, pad_x, -DEF_VALUE);
else if (x == 0xFFFF)
Analog::ConfigurePad(pad, pad_x, DEF_VALUE);
else if (x < (s_previous_mouse_x -2))
Analog::ConfigurePad(pad, pad_x, -value);
else if (x > (s_previous_mouse_x +2))
Analog::ConfigurePad(pad, pad_x, value);
else
Analog::ResetPad(pad, pad_x);
case KeyRelease:
key = XLookupKeysym((XKeyEvent *) & E, 0);
i = FindKey(key, pad);
unsigned y = evt.key >> 16;
value = abs(s_previous_mouse_y - y) * conf->sensibility;
value = max(value, (unsigned int)DEF_VALUE);
// Analog Controls.
if ((i > PAD_RY) && (i <= PAD_R_LEFT))
{
Analog::ResetPad(pad, Analog::AnalogToPad(i));
i += 0xff00;
}
if (y == 0)
Analog::ConfigurePad(pad, pad_y, -DEF_VALUE);
else if (y == 0xFFFF)
Analog::ConfigurePad(pad, pad_y, DEF_VALUE);
else if (y < (s_previous_mouse_y -2))
Analog::ConfigurePad(pad, pad_y, -value);
else if (y > (s_previous_mouse_y +2))
Analog::ConfigurePad(pad, pad_y, value);
else
Analog::ResetPad(pad, pad_y);
if (i != -1)
{
clear_bit(keyPress, i);
set_bit(keyRelease, i);
}
s_previous_mouse_x = x;
s_previous_mouse_y = y;
}
event.evt = KEYRELEASE;
event.key = key;
break;
case FocusIn:
XAutoRepeatOff(GSdsp);
break;
case FocusOut:
XAutoRepeatOn(GSdsp);
break;
}
break;
}
UpdateKeys(pad, keyPress, keyRelease);
}
bool PollX11Keyboard(char* &temp, u32 &pkey)
void PollForX11KeyboardInput(int pad, int& keyPress, int& keyRelease, bool& used_by_keyboard)
{
keyEvent evt;
XEvent E;
XButtonEvent* BE;
// Keyboard input send by PCSX2
while (!ev_fifo.empty()) {
AnalyzeKeyEvent(pad, ev_fifo.front(), keyPress, keyRelease, used_by_keyboard);
pthread_mutex_lock(&mutex_KeyEvent);
ev_fifo.pop();
pthread_mutex_unlock(&mutex_KeyEvent);
}
// keyboard input
while (XPending(GSdsp) > 0)
{
XNextEvent(GSdsp, &E);
evt.evt = E.type;
evt.key = (int)XLookupKeysym((XKeyEvent *) & E, 0);
// Change the format of the structure to be compatible with GSOpen2
// mode (event come from pcsx2 not X)
BE = (XButtonEvent*)&E;
switch (evt.evt) {
case MotionNotify: evt.key = (BE->x & 0xFFFF) | (BE->y << 16); break;
case ButtonRelease:
case ButtonPress: evt.key = BE->button; break;
default: break;
}
AnalyzeKeyEvent(pad, evt, keyPress, keyRelease, used_by_keyboard);
}
}
bool PollX11KeyboardMouseEvent(u32 &pkey)
{
GdkEvent *ev = gdk_event_get();
if (ev != NULL)
{
if (ev->type == GDK_KEY_PRESS)
{
if (ev->type == GDK_KEY_PRESS) {
if (ev->key.keyval == GDK_Escape)
{
temp = "Unknown";
pkey = NULL;
}
pkey = 0;
else
{
temp = KeysymToChar(ev->key.keyval);
pkey = ev->key.keyval;
}
return true;
} else if(ev->type == GDK_BUTTON_PRESS) {
pkey = ev->button.button;
return true;
}
}
return false;
}
#else
LRESULT WINAPI PADwndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{

View File

@ -29,19 +29,18 @@
#include "Linux/linux.h"
extern Display *GSdsp;
extern void PollForX11KeyboardInput(int pad);
extern bool PollX11Keyboard(char* &temp, u32 &pkey);
extern void PollForX11KeyboardInput(int pad, int& keyPress, int& keyRelease, bool& used_by_keyboard);
extern bool PollX11KeyboardMouseEvent(u32 &pkey);
extern Window GSwin;
#else
extern char* KeysymToChar(int keysym);
extern WNDPROC GSwndProc;
extern HWND GShwnd;
#endif
extern char* KeysymToChar(int keysym);
extern void PollForKeyboardInput(int pad);
extern void SetAutoRepeat(bool autorep);
extern int FindKey(int key, int pad);
#endif
#endif

View File

@ -34,14 +34,13 @@
#include "svnrev.h"
#endif
PADconf* conf;
char libraryName[256];
PADconf conf;
keyEvent event;
u16 status[2];
int pressure;
int status_pressure[2][MAX_KEYS];
static keyEvent s_event;
std::string s_strIniPath("inis/");
std::string s_strLogPath("logs/");
@ -125,7 +124,15 @@ int ds2mode = 0; // DS Mode at start
FILE *padLog = NULL;
pthread_spinlock_t s_mutexStatus;
u32 s_keyPress[2], s_keyRelease[2];
pthread_mutex_t mutex_KeyEvent;
static u32 s_keyPress[2], s_keyRelease[2];
queue<keyEvent> ev_fifo;
static int padVib0[2];
static int padVib1[2];
static int padVibC[2];
static int padVibF[2][4];
static void InitLibraryName()
{
@ -239,15 +246,11 @@ void CloseLogging()
#endif
}
void clearPAD()
void clearPAD(int pad)
{
for (int pad = 0; pad < MAX_SUB_KEYS; pad++)
{
for (int key= 0; key < MAX_KEYS; ++key)
{
set_key(pad, key, 0);
}
}
conf->keysym_map[pad].clear();
for (int key= 0; key < MAX_KEYS; ++key)
set_key(pad, key, 0);
}
EXPORT_C_(s32) PADinit(u32 flags)
@ -255,15 +258,17 @@ EXPORT_C_(s32) PADinit(u32 flags)
initLogging();
pads |= flags;
status[0] = 0xffff;
status[1] = 0xffff;
for (int i = 0 ; i < 2 ; i++) {
status[i] = 0xffff;
for (int j = 0 ; j < MAX_KEYS ; j++)
status_pressure[i][j] = 255;
}
LoadConfig();
PADsetMode(0, 0);
PADsetMode(1, 0);
pressure = 100;
Analog::Init();
return 0;
@ -272,13 +277,16 @@ EXPORT_C_(s32) PADinit(u32 flags)
EXPORT_C_(void) PADshutdown()
{
CloseLogging();
if (conf) delete conf;
}
EXPORT_C_(s32) PADopen(void *pDsp)
{
memset(&event, 0, sizeof(event));
while (!ev_fifo.empty()) ev_fifo.pop();
pthread_spin_init(&s_mutexStatus, PTHREAD_PROCESS_PRIVATE);
pthread_mutex_init(&mutex_KeyEvent, NULL);
s_keyPress[0] = s_keyPress[1] = 0;
s_keyRelease[0] = s_keyRelease[1] = 0;
@ -306,7 +314,9 @@ EXPORT_C_(void) PADsetLogDir(const char* dir)
EXPORT_C_(void) PADclose()
{
while (!ev_fifo.empty()) ev_fifo.pop();
pthread_spin_destroy(&s_mutexStatus);
pthread_mutex_destroy(&mutex_KeyEvent);
_PADclose();
}
@ -338,6 +348,11 @@ EXPORT_C_(u32) PADquery()
void PADsetMode(int pad, int mode)
{
padMode[pad] = mode;
// FIXME FEEDBACK
padVib0[pad] = 0;
padVib1[pad] = 0;
padVibF[pad][0] = 0;
padVibF[pad][1] = 0;
switch (ds2mode)
{
case 0: // dualshock
@ -381,7 +396,8 @@ EXPORT_C_(u8) PADstartPoll(int pad)
u8 _PADpoll(u8 value)
{
u8 button_check = 0;
const int avg_pressure = (pressure * 255) / 100;
int vib_small;
int vib_big;
if (curByte == 0)
{
@ -408,10 +424,10 @@ u8 _PADpoll(u8 value)
stdpar[curPad][2] = status[curPad] >> 8;
stdpar[curPad][3] = status[curPad] & 0xff;
stdpar[curPad][4] = Analog::Pad(curPad, PAD_RX);
stdpar[curPad][5] = Analog::Pad(curPad, PAD_RY);
stdpar[curPad][6] = Analog::Pad(curPad, PAD_LX);
stdpar[curPad][7] = Analog::Pad(curPad, PAD_LY);
stdpar[curPad][4] = Analog::Pad(curPad, PAD_R_RIGHT);
stdpar[curPad][5] = Analog::Pad(curPad, PAD_R_UP);
stdpar[curPad][6] = Analog::Pad(curPad, PAD_L_RIGHT);
stdpar[curPad][7] = Analog::Pad(curPad, PAD_L_UP);
if (padMode[curPad] == 1)
cmdLen = 20;
@ -422,35 +438,35 @@ u8 _PADpoll(u8 value)
switch (stdpar[curPad][3])
{
case 0xBF: // X
stdpar[curPad][14] = avg_pressure;
stdpar[curPad][14] = status_pressure[curPad][PAD_CROSS];
break;
case 0xDF: // Circle
stdpar[curPad][13] = avg_pressure;
stdpar[curPad][13] = status_pressure[curPad][PAD_CIRCLE];
break;
case 0xEF: // Triangle
stdpar[curPad][12] = avg_pressure;
stdpar[curPad][12] = status_pressure[curPad][PAD_TRIANGLE];
break;
case 0x7F: // Square
stdpar[curPad][15] = avg_pressure;
stdpar[curPad][15] = status_pressure[curPad][PAD_SQUARE];
break;
case 0xFB: // L1
stdpar[curPad][16] = avg_pressure;
stdpar[curPad][16] = status_pressure[curPad][PAD_L1];
break;
case 0xF7: // R1
stdpar[curPad][17] = avg_pressure;
stdpar[curPad][17] = status_pressure[curPad][PAD_R1];
break;
case 0xFE: // L2
stdpar[curPad][18] = avg_pressure;
stdpar[curPad][18] = status_pressure[curPad][PAD_L2];
break;
case 0xFD: // R2
stdpar[curPad][19] = avg_pressure;
stdpar[curPad][19] = status_pressure[curPad][PAD_R2];
break;
default:
@ -467,19 +483,19 @@ u8 _PADpoll(u8 value)
switch (button_check)
{
case 0xE: // UP
stdpar[curPad][10] = avg_pressure;
stdpar[curPad][10] = status_pressure[curPad][PAD_UP];
break;
case 0xB: // DOWN
stdpar[curPad][11] = avg_pressure;
stdpar[curPad][11] =status_pressure[curPad][PAD_DOWN];
break;
case 0x7: // LEFT
stdpar[curPad][9] = avg_pressure;
stdpar[curPad][9] = status_pressure[curPad][PAD_LEFT];
break;
case 0xD: // RIGHT
stdpar[curPad][8] = avg_pressure;
stdpar[curPad][8] = status_pressure[curPad][PAD_RIGHT];
break;
default:
@ -490,6 +506,28 @@ u8 _PADpoll(u8 value)
break;
}
buf = stdpar[curPad];
// FIXME FEEDBACK. Set effect here
/* Small Motor */
vib_small = padVibF[curPad][0] ? 2000 : 0;
// if ((padVibF[curPad][2] != vib_small) && (padVibC[curPad] >= 0))
if (padVibF[curPad][2] != vib_small)
{
padVibF[curPad][2] = vib_small;
// SetDeviceForceS (padVibC[curPad], vib_small);
JoystickInfo::DoHapticEffect(0, curPad, vib_small);
}
/* Big Motor */
vib_big = padVibF[curPad][1] ? 500 + 37*padVibF[curPad][1] : 0;
// if ((padVibF[curPad][3] != vib_big) && (padVibC[curPad] >= 0))
if (padVibF[curPad][3] != vib_big)
{
padVibF[curPad][3] = vib_big;
// SetDeviceForceB (padVibC[curPad], vib_big);
JoystickInfo::DoHapticEffect(1, curPad, vib_big);
}
return padID[curPad];
case CMD_CONFIG_MODE: // CONFIG_MODE
@ -546,6 +584,13 @@ u8 _PADpoll(u8 value)
switch (curCmd)
{
case CMD_READ_DATA_AND_VIBRATE:
// FIXME FEEDBACK
if (curByte == padVib0[curPad])
padVibF[curPad][0] = value;
if (curByte == padVib1[curPad])
padVibF[curPad][1] = value;
break;
case CMD_CONFIG_MODE:
if (curByte == 2)
{
@ -604,6 +649,31 @@ u8 _PADpoll(u8 value)
}
}
break;
case CMD_VIBRATION_TOGGLE:
// FIXME FEEDBACK
if (curByte >= 2)
{
if (curByte == padVib0[curPad])
buf[curByte] = 0x00;
if (curByte == padVib1[curPad])
buf[curByte] = 0x01;
if (value == 0x00)
{
padVib0[curPad] = curByte;
// FIXME: code from SSSXPAD I'm not sure we need this part
// if ((padID[curPad] & 0x0f) < (curByte - 1) / 2)
// padID[curPad] = (padID[curPad] & 0xf0) + (curByte - 1) / 2;
}
else if (value == 0x01)
{
padVib1[curPad] = curByte;
// FIXME: code from SSSXPAD I'm not sure we need this part
// if ((padID[curPad] & 0x0f) < (curByte - 1) / 2)
// padID[curPad] = (padID[curPad] & 0xf0) + (curByte - 1) / 2;
}
}
break;
}
if (curByte >= cmdLen) return 0;
@ -627,3 +697,12 @@ EXPORT_C_(keyEvent*) PADkeyEvent()
event.key = 0;
return &s_event;
}
#ifdef __LINUX__
EXPORT_C_(void) PADWriteEvent(keyEvent &evt)
{
pthread_mutex_lock(&mutex_KeyEvent);
ev_fifo.push(evt);
pthread_mutex_unlock(&mutex_KeyEvent);
}
#endif

View File

@ -24,6 +24,7 @@
#include <stdio.h>
#include <assert.h>
#include <queue>
#ifdef _WIN32
#include <windows.h>
@ -67,7 +68,9 @@ enum PadOptions
PADOPTION_REVERSELX = 0x2,
PADOPTION_REVERSELY = 0x4,
PADOPTION_REVERSERX = 0x8,
PADOPTION_REVERSERY = 0x10
PADOPTION_REVERSERY = 0x10,
PADOPTION_MOUSE_L = 0x20,
PADOPTION_MOUSE_R = 0x40
};
extern FILE *padLog;
@ -94,34 +97,30 @@ enum PadCommands
enum gamePadValues
{
PAD_R_LEFT = 27,
PAD_R_DOWN = 26,
PAD_R_RIGHT = 25,
PAD_R_UP = 24,
PAD_L_LEFT = 23,
PAD_L_DOWN = 22,
PAD_L_RIGHT = 21,
PAD_L_UP = 20,
PAD_RY = 19,
PAD_LY = 18,
PAD_RX = 17,
PAD_LX = 16,
PAD_LEFT = 15,
PAD_DOWN = 14,
PAD_RIGHT = 13,
PAD_UP = 12,
PAD_START = 11,
PAD_R3 = 10,
PAD_L3 = 9,
PAD_SELECT = 8,
PAD_SQUARE = 7,
PAD_CROSS = 6,
PAD_CIRCLE = 5,
PAD_TRIANGLE = 4,
PAD_R1 = 3,
PAD_L1 = 2,
PAD_R2 = 1,
PAD_L2 = 0
PAD_L2 = 0,
PAD_R2,
PAD_L1,
PAD_R1,
PAD_TRIANGLE,
PAD_CIRCLE,
PAD_CROSS,
PAD_SQUARE,
PAD_SELECT,
PAD_L3,
PAD_R3,
PAD_START,
PAD_UP,
PAD_RIGHT,
PAD_DOWN,
PAD_LEFT,
PAD_L_UP,
PAD_L_RIGHT,
PAD_L_DOWN,
PAD_L_LEFT,
PAD_R_UP,
PAD_R_RIGHT,
PAD_R_DOWN,
PAD_R_LEFT
};
// Activate bolche's analog controls hack
@ -134,10 +133,14 @@ enum gamePadValues
extern keyEvent event;
extern queue<keyEvent> ev_fifo;
extern pthread_mutex_t mutex_KeyEvent;
extern u16 status[2];
extern int status_pressure[2][MAX_KEYS];
extern u32 pads;
void clearPAD();
void clearPAD(int pad);
int POV(u32 direction, u32 angle);
s32 _PADopen(void *pDsp);
void _PADclose();

View File

@ -20,10 +20,10 @@
#ifndef GLWIN_H_INCLUDED
#define GLWIN_H_INCLUDED
#ifdef _WIN32
#define GL_WIN32_WINDOW
#else
#define USE_GSOPEN2
#define GL_X11_WINDOW
#endif
@ -37,7 +37,6 @@ class GLWindow
private:
#ifdef GL_X11_WINDOW
Display *glDisplay;
int glScreen;
GLXContext context;
XVisualInfo *vi;
@ -49,6 +48,7 @@ class GLWindow
void GetWindowSize();
void UpdateGrabKey();
void Force43Ratio();
void CreateContextGL();
#endif
bool fullScreen, doubleBuffered;
u32 width, height, depth;

View File

@ -25,14 +25,24 @@
#include <X11/Xlib.h>
#include <stdlib.h>
#ifdef USE_GSOPEN2
bool GLWindow::CreateWindow(void *pDisplay)
{
glWindow = (Window)*((u32*)(pDisplay)+1);
// Do not take the display which come from pcsx2 neither change it.
// You need a new one to do the operation in the GS thread
glDisplay = XOpenDisplay(NULL);
return true;
}
#else
bool GLWindow::CreateWindow(void *pDisplay)
{
// init support of multi thread
if (!XInitThreads())
ZZLog::Error_Log("Failed to init the xlib concurent threads");
glDisplay = XOpenDisplay(0);
glScreen = DefaultScreen(glDisplay);
glDisplay = XOpenDisplay(NULL);
if (pDisplay == NULL)
{
@ -40,10 +50,15 @@ bool GLWindow::CreateWindow(void *pDisplay)
return false;
}
// Allow pad to use the display
*(Display**)pDisplay = glDisplay;
// Pad can use the window to grab the input. For the moment just set to 0 to avoid
// to grab an unknow window... Anyway GSopen1 might be dropped in the future
*((u32*)(pDisplay)+1) = 0;
return true;
}
#endif
bool GLWindow::ReleaseContext()
{
@ -102,11 +117,11 @@ bool GLWindow::CreateVisual()
};
/* get an appropriate visual */
vi = glXChooseVisual(glDisplay, glScreen, attrListDbl);
vi = glXChooseVisual(glDisplay, DefaultScreen(glDisplay), attrListDbl);
if (vi == NULL)
{
vi = glXChooseVisual(glDisplay, glScreen, attrListSgl);
vi = glXChooseVisual(glDisplay, DefaultScreen(glDisplay), attrListSgl);
doubleBuffered = false;
ZZLog::Error_Log("Only Singlebuffered Visual!");
}
@ -140,7 +155,10 @@ void GLWindow::GetWindowSize()
// update the gl buffer size
UpdateWindowSize(width, height);
#ifndef USE_GSOPEN2
// too verbose!
ZZLog::Dev_Log("Resolution %dx%d. Depth %d bpp. Position (%d,%d)", width, height, depth, conf.x, conf.y);
#endif
}
void GLWindow::GetGLXVersion()
@ -149,7 +167,184 @@ void GLWindow::GetGLXVersion()
glXQueryVersion(glDisplay, &glxMajorVersion, &glxMinorVersion);
ZZLog::Error_Log("glX-Version %d.%d", glxMajorVersion, glxMinorVersion);
if (glXIsDirect(glDisplay, context))
ZZLog::Error_Log("glX-Version %d.%d with Direct Rendering", glxMajorVersion, glxMinorVersion);
else
ZZLog::Error_Log("glX-Version %d.%d with Indirect Rendering !!! It will be slow", glxMajorVersion, glxMinorVersion);
}
void GLWindow::CreateContextGL()
{
if (!glDisplay) return;
// Create a 2.0 opengl context. My understanding, you need it to call the gl function to get the 3.0 context
context = glXCreateContext(glDisplay, vi, NULL, GL_TRUE);
PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC) glXGetProcAddress((GLubyte *) "glXCreateContextAttribsARB");
PFNGLXCHOOSEFBCONFIGPROC glXChooseFBConfig = (PFNGLXCHOOSEFBCONFIGPROC) glXGetProcAddress((GLubyte *) "glXChooseFBConfig");
if (!glXCreateContextAttribsARB or !glXChooseFBConfig) {
ZZLog::Error_Log("No support of OpenGL 3.0\n");
return;
}
// Note this part seems linux specific
int fbcount = 0;
GLXFBConfig *framebuffer_config = glXChooseFBConfig(glDisplay, DefaultScreen(glDisplay), NULL, &fbcount);
if (!framebuffer_config or !fbcount) return;
// At least create a 3.0 context with compatibility profile
int attribs[] = {
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_VERSION_ARB, 0,
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
0
};
GLXContext context_temp = glXCreateContextAttribsARB(glDisplay, framebuffer_config[0], NULL, true, attribs);
if (context_temp) {
ZZLog::Error_Log("Create a 3.0 opengl context");
glXDestroyContext(glDisplay, context);
context = context_temp;
}
}
#ifdef USE_GSOPEN2
bool GLWindow::DisplayWindow(int _width, int _height)
{
GetWindowSize();
if (!CreateVisual()) return false;
// connect the glx-context to the window
CreateContextGL();
glXMakeCurrent(glDisplay, glWindow, context);
GetGLXVersion();
return true;
}
#else
bool GLWindow::DisplayWindow(int _width, int _height)
{
backbuffer.w = _width;
backbuffer.h = _height;
if (!CreateVisual()) return false;
/* create a color map */
attr.colormap = XCreateColormap(glDisplay, RootWindow(glDisplay, vi->screen),
vi->visual, AllocNone);
attr.border_pixel = 0;
attr.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask |
StructureNotifyMask | SubstructureRedirectMask | SubstructureNotifyMask |
EnterWindowMask | LeaveWindowMask | FocusChangeMask ;
// Create a window at the last position/size
glWindow = XCreateWindow(glDisplay, RootWindow(glDisplay, vi->screen),
conf.x , conf.y , _width, _height, 0, vi->depth, InputOutput, vi->visual,
CWBorderPixel | CWColormap | CWEventMask,
&attr);
/* Allow to kill properly the window */
Atom wmDelete = XInternAtom(glDisplay, "WM_DELETE_WINDOW", True);
XSetWMProtocols(glDisplay, glWindow, &wmDelete, 1);
// Set icon name
XSetIconName(glDisplay, glWindow, "ZZogl-pg");
// Draw the window
XMapRaised(glDisplay, glWindow);
XSync(glDisplay, false);
// connect the glx-context to the window
CreateContextGL();
glXMakeCurrent(glDisplay, glWindow, context);
GetGLXVersion();
// Always start in window mode
fullScreen = 0;
GetWindowSize();
return true;
}
#endif
void GLWindow::SwapGLBuffers()
{
if (glGetError() != GL_NO_ERROR) ZZLog::Debug_Log("glError before swap!");
// FIXME I think we need to flush when there is only 1 visual buffer
glXSwapBuffers(glDisplay, glWindow);
// glClear(GL_COLOR_BUFFER_BIT);
}
u32 THR_KeyEvent = 0; // Value for key event processing between threads
bool THR_bShift = false;
bool THR_bCtrl = false;
void GLWindow::ProcessEvents()
{
FUNCLOG
#ifdef USE_GSOPEN2
GetWindowSize();
#else
ResizeCheck();
#endif
if (THR_KeyEvent) // This value was passed from GSKeyEvents which could be in another thread
{
int my_KeyEvent = THR_KeyEvent;
bool my_bShift = THR_bShift;
bool my_bCtrl = THR_bCtrl;
THR_KeyEvent = 0;
switch (my_KeyEvent)
{
case XK_F5:
case XK_F6:
case XK_F7:
case XK_F9:
// Note: to avoid some clash with PCSX2 shortcut in GSOpen2.
// GS shortcut will only be activated when ctrl is press
if (my_bCtrl)
OnFKey(my_KeyEvent - XK_F1 + 1, my_bShift);
break;
}
}
}
// ************************** Function that are either stub or useless in GSOPEN2
#define _NET_WM_STATE_REMOVE 0
#define _NET_WM_STATE_ADD 1
#define _NET_WM_STATE_TOGGLE 2
void GLWindow::Force43Ratio()
{
#ifndef USE_GSOPEN2
// avoid black border in fullscreen
if (fullScreen && conf.isWideScreen) {
conf.width = width;
conf.height = height;
}
if(!fullScreen && !conf.isWideScreen) {
// Compute the width based on height
s32 new_width = (4*height)/3;
// do not bother to resize for 5 pixels. Avoid a loop
// due to round value
if ( abs(new_width - width) > 5) {
width = new_width;
conf.width = new_width;
// resize the window
XLockDisplay(glDisplay);
XResizeWindow(glDisplay, glWindow, new_width, height);
XSync(glDisplay, False);
XUnlockDisplay(glDisplay);
}
}
#endif
}
void GLWindow::UpdateGrabKey()
@ -168,37 +363,9 @@ void GLWindow::UpdateGrabKey()
#endif
}
void GLWindow::Force43Ratio()
{
// avoid black border in fullscreen
if (fullScreen && conf.isWideScreen) {
conf.width = width;
conf.height = height;
}
if(!fullScreen && !conf.isWideScreen) {
// Compute the width based on height
s32 new_width = (4*height)/3;
// do not bother to resize for 5 pixels. Avoid a loop
// due to round value
if ( abs(new_width - width) > 5) {
width = new_width;
conf.width = new_width;
// resize the window
XLockDisplay(glDisplay);
XResizeWindow(glDisplay, glWindow, new_width, height);
XSync(glDisplay, False);
XUnlockDisplay(glDisplay);
}
}
}
#define _NET_WM_STATE_REMOVE 0
#define _NET_WM_STATE_ADD 1
#define _NET_WM_STATE_TOGGLE 2
void GLWindow::ToggleFullscreen()
{
#ifndef USE_GSOPEN2
if (!glDisplay or !glWindow) return;
Force43Ratio();
@ -239,7 +406,7 @@ void GLWindow::ToggleFullscreen()
// update info structure
GetWindowSize();
UpdateGrabKey();
UpdateGrabKey();
// avoid black border in widescreen fullscreen
if (fullScreen && conf.isWideScreen) {
@ -251,82 +418,7 @@ void GLWindow::ToggleFullscreen()
if(fullScreen)
XWarpPointer(glDisplay, None, glWindow, 0, 0, 0, 0, 2*width, 2*height);
}
bool GLWindow::DisplayWindow(int _width, int _height)
{
backbuffer.w = _width;
backbuffer.h = _height;
if (!CreateVisual()) return false;
/* create a GLX context */
context = glXCreateContext(glDisplay, vi, NULL, GL_TRUE);
/* create a color map */
attr.colormap = XCreateColormap(glDisplay, RootWindow(glDisplay, vi->screen),
vi->visual, AllocNone);
attr.border_pixel = 0;
attr.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask |
StructureNotifyMask | SubstructureRedirectMask | SubstructureNotifyMask |
EnterWindowMask | LeaveWindowMask | FocusChangeMask ;
GetGLXVersion();
// Create a window at the last position/size
glWindow = XCreateWindow(glDisplay, RootWindow(glDisplay, vi->screen),
conf.x , conf.y , _width, _height, 0, vi->depth, InputOutput, vi->visual,
CWBorderPixel | CWColormap | CWEventMask,
&attr);
/* Allow to kill properly the window */
Atom wmDelete = XInternAtom(glDisplay, "WM_DELETE_WINDOW", True);
XSetWMProtocols(glDisplay, glWindow, &wmDelete, 1);
// Set icon name
XSetIconName(glDisplay, glWindow, "ZZogl-pg");
// Draw the window
XMapRaised(glDisplay, glWindow);
XSync(glDisplay, false);
// connect the glx-context to the window
glXMakeCurrent(glDisplay, glWindow, context);
if (glXIsDirect(glDisplay, context))
ZZLog::Error_Log("You have Direct Rendering!");
else
ZZLog::Error_Log("No Direct Rendering possible!");
// Always start in window mode
fullScreen = 0;
GetWindowSize();
return true;
}
void GLWindow::SwapGLBuffers()
{
if (glGetError() != GL_NO_ERROR) ZZLog::Debug_Log("glError before swap!");
glXSwapBuffers(glDisplay, glWindow);
}
void GLWindow::SetTitle(char *strtitle)
{
if (!glDisplay or !glWindow) return;
if (fullScreen) return;
XTextProperty prop;
memset(&prop, 0, sizeof(prop));
char* ptitle = strtitle;
if (XStringListToTextProperty(&ptitle, 1, &prop)) {
XLockDisplay(glDisplay);
XSetWMName(glDisplay, glWindow, &prop);
XUnlockDisplay(glDisplay);
}
XFree(prop.value);
#endif
}
void GLWindow::ResizeCheck()
@ -358,32 +450,24 @@ void GLWindow::ResizeCheck()
XUnlockDisplay(glDisplay);
}
u32 THR_KeyEvent = 0; // Value for key event processing between threads
bool THR_bShift = false;
void GLWindow::ProcessEvents()
void GLWindow::SetTitle(char *strtitle)
{
FUNCLOG
#ifndef USE_GSOPEN2
if (!glDisplay or !glWindow) return;
if (fullScreen) return;
// check resizing
ResizeCheck();
XTextProperty prop;
memset(&prop, 0, sizeof(prop));
if (THR_KeyEvent) // This value was passed from GSKeyEvents which could be in another thread
{
int my_KeyEvent = THR_KeyEvent;
bool my_bShift = THR_bShift;
THR_KeyEvent = 0;
char* ptitle = strtitle;
if (XStringListToTextProperty(&ptitle, 1, &prop)) {
XLockDisplay(glDisplay);
XSetWMName(glDisplay, glWindow, &prop);
XUnlockDisplay(glDisplay);
}
switch (my_KeyEvent)
{
case XK_F5:
case XK_F6:
case XK_F7:
case XK_F9:
OnFKey(my_KeyEvent - XK_F1 + 1, my_bShift);
break;
}
}
XFree(prop.value);
#endif
}
#endif

View File

@ -31,6 +31,12 @@ using namespace std;
extern float fFPS;
#ifdef _MSC_VER
#define EXPORT_C_(type) extern "C" type CALLBACK
#else
#define EXPORT_C_(type) extern "C" __attribute__((externally_visible,visibility("default"))) type
#endif
extern int g_LastCRC;
struct Vector_16F

View File

@ -307,8 +307,8 @@ s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread)
return 0;
}
#ifdef USE_GOPEN2
s32 CALLBACK GSopen2( void* pDsp, INT32 flags )
#ifdef USE_GSOPEN2
EXPORT_C_(s32) GSopen2( void* pDsp, u32 flags )
{
FUNCLOG
@ -327,7 +327,7 @@ s32 CALLBACK GSopen2( void* pDsp, INT32 flags )
ZZLog::GS_Log("Using %s:%d.%d.%d.", libraryName, zgsrevision, zgsbuild, zgsminor);
ZZLog::WriteLn("Capturing ZZOgl window.");
if ((!GLWin.GetWindow(pDsp)) || (!ZZCreate2(conf.width, conf.height))) return -1;// Needs to be added.
if ((!GLWin.CreateWindow(pDsp)) || (!ZZCreate(conf.width, conf.height))) return -1;
ZZLog::WriteLn("Initialization successful.");
@ -492,7 +492,10 @@ void CALLBACK GSvsync(int interlace)
fFPS = UPDATE_FRAMES * 1000.0f / (float)max(d - dwTime, (u32)1);
dwTime = d;
g_nFrame += UPDATE_FRAMES;
#ifndef USE_GSOPEN2
// let PCSX2 manage the title
SetGSTitle();
#endif
// if( g_nFrame > 100 && fFPS > 60.0f ) {
// ZZLog::Debug_Log("Set profile.");

View File

@ -30,13 +30,13 @@
extern u32 THR_KeyEvent; // value for passing out key events beetwen threads
extern bool THR_bShift;
extern bool THR_bCtrl;
static map<string, confOptsStruct> mapConfOpts;
static gameHacks tempHacks;
void CALLBACK GSkeyEvent(keyEvent *ev)
{
//static bool bShift = false;
static bool bAlt = false;
switch (ev->evt)
@ -57,10 +57,14 @@ void CALLBACK GSkeyEvent(keyEvent *ev)
case XK_Shift_L:
case XK_Shift_R:
//bShift = true;
THR_bShift = true;
break;
case XK_Control_L:
case XK_Control_R:
THR_bCtrl = true;
break;
case XK_Alt_L:
case XK_Alt_R:
bAlt = true;
@ -77,10 +81,14 @@ void CALLBACK GSkeyEvent(keyEvent *ev)
{
case XK_Shift_L:
case XK_Shift_R:
//bShift = false;
THR_bShift = false;
break;
case XK_Control_L:
case XK_Control_R:
THR_bCtrl = false;
break;
case XK_Alt_L:
case XK_Alt_R:
bAlt = false;

View File

@ -379,10 +379,10 @@ inline bool CreateFillExtensionsMap()
PFNGLGETSTRINGIPROC glGetStringi = 0;
glGetStringi = (PFNGLGETSTRINGIPROC)wglGetProcAddress("glGetStringi");
glGetIntegerv(GL_NUM_EXTENSIONS, &max_ext);
if (glGetStringi) {
if (glGetStringi && max_ext) {
// Get opengl extension (opengl3)
glGetIntegerv(GL_NUM_EXTENSIONS, &max_ext);
for (GLint i = 0; i < max_ext; i++)
{
string extension((const char*)glGetStringi(GL_EXTENSIONS, i));
@ -392,14 +392,14 @@ inline bool CreateFillExtensionsMap()
if (i != (max_ext - 1)) all_ext += ", ";
}
} else {
// fallback to old method (pre opengl3, intel gma ...)
// fallback to old method (pre opengl3, intel gma, geforce 7 ...)
ZZLog::Error_Log("glGetStringi opengl 3 interface not supported, fallback to opengl 2");
const char* ptoken = (const char*)glGetString(GL_EXTENSIONS);
all_ext = string(ptoken); // save the string to print a nice debug message
if (ptoken == NULL) return false;
all_ext = string(ptoken); // save the string to print a nice debug message
const char* pend = NULL;
while (ptoken != NULL)
{