diff --git a/3rdparty/SDL-1.3.0-5387/src/video/x11/SDL_x11window.c b/3rdparty/SDL-1.3.0-5387/src/video/x11/SDL_x11window.c index cc01d0739b..5ca3350cc6 100644 --- a/3rdparty/SDL-1.3.0-5387/src/video/x11/SDL_x11window.c +++ b/3rdparty/SDL-1.3.0-5387/src/video/x11/SDL_x11window.c @@ -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, diff --git a/common/include/PS2Edefs.h b/common/include/PS2Edefs.h index 6d6119d4c7..e148f508fa 100644 --- a/common/include/PS2Edefs.h +++ b/common/include/PS2Edefs.h @@ -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; diff --git a/pcsx2/MTGS.cpp b/pcsx2/MTGS.cpp index 89b5ab8193..a1faa20e87 100644 --- a/pcsx2/MTGS.cpp +++ b/pcsx2/MTGS.cpp @@ -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 ) diff --git a/pcsx2/PluginManager.cpp b/pcsx2/PluginManager.cpp index a513d7ff4e..7441bdaf7e 100644 --- a/pcsx2/PluginManager.cpp +++ b/pcsx2/PluginManager.cpp @@ -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(); diff --git a/pcsx2/Plugins.h b/pcsx2/Plugins.h index f92999e704..6781989097 100644 --- a/pcsx2/Plugins.h +++ b/pcsx2/Plugins.h @@ -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]; diff --git a/pcsx2/gui/AppMain.cpp b/pcsx2/gui/AppMain.cpp index 9a9c05cbdc..7c99a90413 100644 --- a/pcsx2/gui/AppMain.cpp +++ b/pcsx2/gui/AppMain.cpp @@ -36,6 +36,14 @@ # include // needed to implement the app! #endif +#ifdef __WXGTK__ +// Need to tranform the GSPanel to a X11 window/display for the GS plugins +#include // GTK_PIZZA interface +#include +#include +#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() diff --git a/pcsx2/gui/FrameForGS.cpp b/pcsx2/gui/FrameForGS.cpp index 15fd56add2..1326ea3a99 100644 --- a/pcsx2/gui/FrameForGS.cpp +++ b/pcsx2/gui/FrameForGS.cpp @@ -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"); } diff --git a/pcsx2/gui/GSFrame.h b/pcsx2/gui/GSFrame.h index 877e141ee0..3563791a7d 100644 --- a/pcsx2/gui/GSFrame.h +++ b/pcsx2/gui/GSFrame.h @@ -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 ); diff --git a/plugins/GSdx/GS.cpp b/plugins/GSdx/GS.cpp index 5e5d792f44..bec85f679a 100644 --- a/plugins/GSdx/GS.cpp +++ b/plugins/GSdx/GS.cpp @@ -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) { /* diff --git a/plugins/GSdx/GSDeviceSDL.cpp b/plugins/GSdx/GSDeviceSDL.cpp index 3db0dc7f06..be0a15ecdf 100644 --- a/plugins/GSdx/GSDeviceSDL.cpp +++ b/plugins/GSdx/GSDeviceSDL.cpp @@ -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); } diff --git a/plugins/GSdx/GSWnd.cpp b/plugins/GSdx/GSWnd.cpp index 7f4c98088b..02afc92ad7 100644 --- a/plugins/GSdx/GSWnd.cpp +++ b/plugins/GSdx/GSWnd.cpp @@ -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; } diff --git a/plugins/GSdx/GSWnd.h b/plugins/GSdx/GSWnd.h index d2ba81934d..44369783e9 100644 --- a/plugins/GSdx/GSWnd.h +++ b/plugins/GSdx/GSWnd.h @@ -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(); diff --git a/plugins/onepad/Linux/dialog.cpp b/plugins/onepad/Linux/dialog.cpp index ab7ce76085..faeff3a062 100644 --- a/plugins/onepad/Linux/dialog.cpp +++ b/plugins/onepad/Linux/dialog.cpp @@ -20,18 +20,16 @@ */ #include "joystick.h" +#include "keyboard.h" #include "onepad.h" #include -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::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::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::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); } diff --git a/plugins/onepad/Linux/ini.cpp b/plugins/onepad/Linux/ini.cpp index 1a423c3587..1d14d6769c 100644 --- a/plugins/onepad/Linux/ini.cpp +++ b/plugins/onepad/Linux/ini.cpp @@ -23,93 +23,97 @@ #include #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::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(); } diff --git a/plugins/onepad/Linux/linux.cpp b/plugins/onepad/Linux/linux.cpp index b21effb719..f693b37d03 100644 --- a/plugins/onepad/Linux/linux.cpp +++ b/plugins/onepad/Linux/linux.cpp @@ -21,17 +21,15 @@ #include "joystick.h" #include "onepad.h" +#include "keyboard.h" #include #include #include "linux.h" #include -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(); diff --git a/plugins/onepad/Linux/linux.h b/plugins/onepad/Linux/linux.h index 133782a8ed..4671aff0ea 100644 --- a/plugins/onepad/Linux/linux.h +++ b/plugins/onepad/Linux/linux.h @@ -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 -//#include -//#include -//#include +#ifndef __LINUX_H__ +#define __LINUX_H__ extern void DisplayDialog(); +extern string KeyName(int pad, int key, int keysym = 0); +#endif diff --git a/plugins/onepad/analog.cpp b/plugins/onepad/analog.cpp index d06e4e5d9c..fed4673f80 100644 --- a/plugins/onepad/analog.cpp +++ b/plugins/onepad/analog.cpp @@ -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); } } diff --git a/plugins/onepad/analog.h b/plugins/onepad/analog.h index fd7c318ca1..0810de8b3f 100644 --- a/plugins/onepad/analog.h +++ b/plugins/onepad/analog.h @@ -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); } diff --git a/plugins/onepad/controller.cpp b/plugins/onepad/controller.cpp index d4935b33a7..5f45a5926f 100644 --- a/plugins/onepad/controller.cpp +++ b/plugins/onepad/controller.cpp @@ -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::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); } diff --git a/plugins/onepad/controller.h b/plugins/onepad/controller.h index bfc125eccf..b78f16b018 100644 --- a/plugins/onepad/controller.h +++ b/plugins/onepad/controller.h @@ -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 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 diff --git a/plugins/onepad/joystick.cpp b/plugins/onepad/joystick.cpp index 996071e9fa..3efcee784f 100644 --- a/plugins/onepad/joystick.cpp +++ b/plugins/onepad/joystick.cpp @@ -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& vjoysticks) { @@ -75,9 +76,7 @@ void JoystickInfo::EnumerateJoysticks(vector& 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& 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::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: diff --git a/plugins/onepad/joystick.h b/plugins/onepad/joystick.h index e62fd44530..9ed5c442c3 100644 --- a/plugins/onepad/joystick.h +++ b/plugins/onepad/joystick.h @@ -22,10 +22,9 @@ #ifndef __JOYSTICK_H__ #define __JOYSTICK_H__ -#ifdef __LINUX__ -#include -#else -#include +#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& 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 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 }; diff --git a/plugins/onepad/keyboard.cpp b/plugins/onepad/keyboard.cpp index c0454ff1db..d36a398ba0 100644 --- a/plugins/onepad/keyboard.cpp +++ b/plugins/onepad/keyboard.cpp @@ -28,32 +28,15 @@ #include #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) { diff --git a/plugins/onepad/keyboard.h b/plugins/onepad/keyboard.h index 8dca163904..6cc9466bc6 100644 --- a/plugins/onepad/keyboard.h +++ b/plugins/onepad/keyboard.h @@ -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 diff --git a/plugins/onepad/onepad.cpp b/plugins/onepad/onepad.cpp index 5ab1bcca02..a100c67b89 100644 --- a/plugins/onepad/onepad.cpp +++ b/plugins/onepad/onepad.cpp @@ -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 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 diff --git a/plugins/onepad/onepad.h b/plugins/onepad/onepad.h index a6403d5627..f61734dbeb 100644 --- a/plugins/onepad/onepad.h +++ b/plugins/onepad/onepad.h @@ -24,6 +24,7 @@ #include #include +#include #ifdef _WIN32 #include @@ -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 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(); diff --git a/plugins/zzogl-pg/opengl/GLWin.h b/plugins/zzogl-pg/opengl/GLWin.h index bab0833ba4..ccd9353a3c 100644 --- a/plugins/zzogl-pg/opengl/GLWin.h +++ b/plugins/zzogl-pg/opengl/GLWin.h @@ -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; diff --git a/plugins/zzogl-pg/opengl/GLWinX11.cpp b/plugins/zzogl-pg/opengl/GLWinX11.cpp index d71a41ab35..b57548b8cd 100644 --- a/plugins/zzogl-pg/opengl/GLWinX11.cpp +++ b/plugins/zzogl-pg/opengl/GLWinX11.cpp @@ -25,14 +25,24 @@ #include #include +#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 diff --git a/plugins/zzogl-pg/opengl/GS.h b/plugins/zzogl-pg/opengl/GS.h index f6a04bf14a..8bded3f4cc 100644 --- a/plugins/zzogl-pg/opengl/GS.h +++ b/plugins/zzogl-pg/opengl/GS.h @@ -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 diff --git a/plugins/zzogl-pg/opengl/GSmain.cpp b/plugins/zzogl-pg/opengl/GSmain.cpp index ef9751c1e2..39582596f8 100644 --- a/plugins/zzogl-pg/opengl/GSmain.cpp +++ b/plugins/zzogl-pg/opengl/GSmain.cpp @@ -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."); diff --git a/plugins/zzogl-pg/opengl/Linux/Linux.cpp b/plugins/zzogl-pg/opengl/Linux/Linux.cpp index 50ac223e85..3d5609f95f 100644 --- a/plugins/zzogl-pg/opengl/Linux/Linux.cpp +++ b/plugins/zzogl-pg/opengl/Linux/Linux.cpp @@ -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 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; diff --git a/plugins/zzogl-pg/opengl/ZZoglCreate.cpp b/plugins/zzogl-pg/opengl/ZZoglCreate.cpp index 6b949a0bf8..1ca3d15280 100644 --- a/plugins/zzogl-pg/opengl/ZZoglCreate.cpp +++ b/plugins/zzogl-pg/opengl/ZZoglCreate.cpp @@ -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) {