mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-08-09 20:21:31 +00:00
From wxWidgets master 81570ae070b35c9d52de47b1f14897f3ff1a66c7. include/wx/defs.h -- __w64 warning disable patch by comex brought forward. include/wx/msw/window.h -- added GetContentScaleFactor() which was not implemented on Windows but is necessary for wxBitmap scaling on Mac OS X so it needs to work to avoid #ifdef-ing the code. src/gtk/window.cpp -- Modified DoSetClientSize() to direct call wxWindowGTK::DoSetSize() instead of using public wxWindowBase::SetSize() which now prevents derived classes (like wxAuiToolbar) intercepting the call and breaking it. This matches Windows which does NOT need to call DoSetSize internally. End result is this fixes Dolphin's debug tools toolbars on Linux. src/osx/window_osx.cpp -- Same fix as for GTK since it has the same issue. src/msw/radiobox.cpp -- Hacked to fix display in HiDPI (was clipping off end of text). Updated CMakeLists for Linux and Mac OS X. Small code changes to Dolphin to fix debug error boxes, deprecation warnings, and retain previous UI behavior on Windows.
541 lines
12 KiB
C++
541 lines
12 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: src/unix/joystick.cpp
|
|
// Purpose: wxJoystick class
|
|
// Author: Ported to Linux by Guilhem Lavaux
|
|
// Modified by:
|
|
// Created: 05/23/98
|
|
// Copyright: (c) Guilhem Lavaux
|
|
// Licence: wxWindows licence
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// for compilers that support precompilation, includes "wx.h".
|
|
#include "wx/wxprec.h"
|
|
|
|
#if wxUSE_JOYSTICK
|
|
|
|
#include "wx/joystick.h"
|
|
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/event.h"
|
|
#include "wx/window.h"
|
|
#include "wx/log.h"
|
|
#endif //WX_PRECOMP
|
|
|
|
#include "wx/thread.h"
|
|
|
|
#include <linux/joystick.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/time.h>
|
|
#include <sys/ioctl.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
|
|
#ifdef HAVE_SYS_SELECT_H
|
|
# include <sys/select.h>
|
|
#endif
|
|
|
|
#include "wx/unix/private.h"
|
|
|
|
enum {
|
|
wxJS_AXIS_X = 0,
|
|
wxJS_AXIS_Y,
|
|
wxJS_AXIS_Z,
|
|
wxJS_AXIS_RUDDER,
|
|
wxJS_AXIS_U,
|
|
wxJS_AXIS_V,
|
|
|
|
wxJS_AXIS_MAX = 32767,
|
|
wxJS_AXIS_MIN = -32767,
|
|
wxJS_MAX_AXES = 15,
|
|
wxJS_MAX_BUTTONS = sizeof(int) * 8
|
|
};
|
|
|
|
|
|
wxIMPLEMENT_DYNAMIC_CLASS(wxJoystick, wxObject);
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// Background thread for reading the joystick device
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
class wxJoystickThread : public wxThread
|
|
{
|
|
public:
|
|
wxJoystickThread(int device, int joystick);
|
|
void* Entry() wxOVERRIDE;
|
|
|
|
private:
|
|
void SendEvent(wxEventType type, long ts, int change = 0);
|
|
int m_device;
|
|
int m_joystick;
|
|
wxPoint m_lastposition;
|
|
int m_axe[wxJS_MAX_AXES];
|
|
int m_buttons;
|
|
wxWindow* m_catchwin;
|
|
int m_polling;
|
|
int m_threshold;
|
|
|
|
friend class wxJoystick;
|
|
};
|
|
|
|
|
|
wxJoystickThread::wxJoystickThread(int device, int joystick)
|
|
: m_device(device),
|
|
m_joystick(joystick),
|
|
m_lastposition(wxDefaultPosition),
|
|
m_buttons(0),
|
|
m_catchwin(NULL),
|
|
m_polling(0),
|
|
m_threshold(0)
|
|
{
|
|
memset(m_axe, 0, sizeof(m_axe));
|
|
}
|
|
|
|
void wxJoystickThread::SendEvent(wxEventType type, long ts, int change)
|
|
{
|
|
wxJoystickEvent jwx_event(type, m_buttons, m_joystick, change);
|
|
|
|
jwx_event.SetTimestamp(ts);
|
|
jwx_event.SetPosition(m_lastposition);
|
|
jwx_event.SetZPosition(m_axe[wxJS_AXIS_Z]);
|
|
jwx_event.SetEventObject(m_catchwin);
|
|
|
|
if (m_catchwin)
|
|
m_catchwin->GetEventHandler()->AddPendingEvent(jwx_event);
|
|
}
|
|
|
|
void* wxJoystickThread::Entry()
|
|
{
|
|
struct js_event j_evt;
|
|
fd_set read_fds;
|
|
struct timeval time_out = {0, 0};
|
|
|
|
wxFD_ZERO(&read_fds);
|
|
while (true)
|
|
{
|
|
if (TestDestroy())
|
|
break;
|
|
|
|
// We use select when either polling or 'blocking' as even in the
|
|
// blocking case we need to check TestDestroy periodically
|
|
if (m_polling)
|
|
time_out.tv_usec = m_polling * 1000;
|
|
else
|
|
time_out.tv_usec = 10 * 1000; // check at least every 10 msec in blocking case
|
|
|
|
wxFD_SET(m_device, &read_fds);
|
|
select(m_device+1, &read_fds, NULL, NULL, &time_out);
|
|
if (wxFD_ISSET(m_device, &read_fds))
|
|
{
|
|
memset(&j_evt, 0, sizeof(j_evt));
|
|
if ( read(m_device, &j_evt, sizeof(j_evt)) == -1 )
|
|
{
|
|
// We can hardly do anything other than ignoring the error and
|
|
// hope that we read the next event successfully.
|
|
continue;
|
|
}
|
|
|
|
//printf("time: %d\t value: %d\t type: %d\t number: %d\n",
|
|
// j_evt.time, j_evt.value, j_evt.type, j_evt.number);
|
|
|
|
if ((j_evt.type & JS_EVENT_AXIS) && (j_evt.number < wxJS_MAX_AXES))
|
|
{
|
|
// Ignore invalid axis.
|
|
if ( j_evt.number >= wxJS_MAX_AXES )
|
|
{
|
|
wxLogDebug(wxS("Invalid axis index %d in joystick message."),
|
|
j_evt.number);
|
|
continue;
|
|
}
|
|
|
|
if ( (m_axe[j_evt.number] + m_threshold < j_evt.value)
|
|
|| (m_axe[j_evt.number] - m_threshold > j_evt.value) )
|
|
{
|
|
m_axe[j_evt.number] = j_evt.value;
|
|
|
|
switch (j_evt.number)
|
|
{
|
|
case wxJS_AXIS_X:
|
|
m_lastposition.x = j_evt.value;
|
|
SendEvent(wxEVT_JOY_MOVE, j_evt.time);
|
|
break;
|
|
case wxJS_AXIS_Y:
|
|
m_lastposition.y = j_evt.value;
|
|
SendEvent(wxEVT_JOY_MOVE, j_evt.time);
|
|
break;
|
|
case wxJS_AXIS_Z:
|
|
SendEvent(wxEVT_JOY_ZMOVE, j_evt.time);
|
|
break;
|
|
default:
|
|
SendEvent(wxEVT_JOY_MOVE, j_evt.time);
|
|
// TODO: There should be a way to indicate that the event
|
|
// is for some other axes.
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( (j_evt.type & JS_EVENT_BUTTON) && (j_evt.number < wxJS_MAX_BUTTONS) )
|
|
{
|
|
if (j_evt.value)
|
|
{
|
|
m_buttons |= (1 << j_evt.number);
|
|
SendEvent(wxEVT_JOY_BUTTON_DOWN, j_evt.time, j_evt.number);
|
|
}
|
|
else
|
|
{
|
|
m_buttons &= ~(1 << j_evt.number);
|
|
SendEvent(wxEVT_JOY_BUTTON_UP, j_evt.time, j_evt.number);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
wxJoystick::wxJoystick(int joystick)
|
|
: m_device(-1),
|
|
m_joystick(joystick),
|
|
m_thread(NULL)
|
|
{
|
|
wxString dev_name;
|
|
|
|
// old /dev structure
|
|
dev_name.Printf( wxT("/dev/js%d"), joystick);
|
|
m_device = open(dev_name.fn_str(), O_RDONLY);
|
|
|
|
// new /dev structure with "input" subdirectory
|
|
if (m_device == -1)
|
|
{
|
|
dev_name.Printf( wxT("/dev/input/js%d"), joystick);
|
|
m_device = open(dev_name.fn_str(), O_RDONLY);
|
|
}
|
|
|
|
if (m_device != -1)
|
|
{
|
|
m_thread = new wxJoystickThread(m_device, m_joystick);
|
|
m_thread->Create();
|
|
m_thread->Run();
|
|
}
|
|
}
|
|
|
|
|
|
wxJoystick::~wxJoystick()
|
|
{
|
|
ReleaseCapture();
|
|
if (m_thread)
|
|
m_thread->Delete(); // It's detached so it will delete itself
|
|
if (m_device != -1)
|
|
close(m_device);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// State
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
wxPoint wxJoystick::GetPosition() const
|
|
{
|
|
wxPoint pos(wxDefaultPosition);
|
|
if (m_thread) pos = m_thread->m_lastposition;
|
|
return pos;
|
|
}
|
|
|
|
int wxJoystick::GetPosition(unsigned axis) const
|
|
{
|
|
if (m_thread && (axis < wxJS_MAX_AXES))
|
|
return m_thread->m_axe[axis];
|
|
return 0;
|
|
}
|
|
|
|
int wxJoystick::GetZPosition() const
|
|
{
|
|
if (m_thread)
|
|
return m_thread->m_axe[wxJS_AXIS_Z];
|
|
return 0;
|
|
}
|
|
|
|
int wxJoystick::GetButtonState() const
|
|
{
|
|
if (m_thread)
|
|
return m_thread->m_buttons;
|
|
return 0;
|
|
}
|
|
|
|
bool wxJoystick::GetButtonState(unsigned id) const
|
|
{
|
|
if (m_thread && (id < wxJS_MAX_BUTTONS))
|
|
return (m_thread->m_buttons & (1 << id)) != 0;
|
|
return false;
|
|
}
|
|
|
|
int wxJoystick::GetPOVPosition() const
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
int wxJoystick::GetPOVCTSPosition() const
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
int wxJoystick::GetRudderPosition() const
|
|
{
|
|
if (m_thread)
|
|
return m_thread->m_axe[wxJS_AXIS_RUDDER];
|
|
return 0;
|
|
}
|
|
|
|
int wxJoystick::GetUPosition() const
|
|
{
|
|
if (m_thread)
|
|
return m_thread->m_axe[wxJS_AXIS_U];
|
|
return 0;
|
|
}
|
|
|
|
int wxJoystick::GetVPosition() const
|
|
{
|
|
if (m_thread)
|
|
return m_thread->m_axe[wxJS_AXIS_V];
|
|
return 0;
|
|
}
|
|
|
|
int wxJoystick::GetMovementThreshold() const
|
|
{
|
|
if (m_thread)
|
|
return m_thread->m_threshold;
|
|
return 0;
|
|
}
|
|
|
|
void wxJoystick::SetMovementThreshold(int threshold)
|
|
{
|
|
if (m_thread)
|
|
m_thread->m_threshold = threshold;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// Capabilities
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool wxJoystick::IsOk() const
|
|
{
|
|
return (m_device != -1);
|
|
}
|
|
|
|
int wxJoystick::GetNumberJoysticks()
|
|
{
|
|
wxString dev_name;
|
|
int fd, j;
|
|
|
|
for (j=0; j<4; j++) {
|
|
dev_name.Printf(wxT("/dev/js%d"), j);
|
|
fd = open(dev_name.fn_str(), O_RDONLY);
|
|
if (fd == -1)
|
|
break;
|
|
close(fd);
|
|
}
|
|
|
|
if (j == 0) {
|
|
for (j=0; j<4; j++) {
|
|
dev_name.Printf(wxT("/dev/input/js%d"), j);
|
|
fd = open(dev_name.fn_str(), O_RDONLY);
|
|
if (fd == -1)
|
|
return j;
|
|
close(fd);
|
|
}
|
|
}
|
|
|
|
return j;
|
|
}
|
|
|
|
int wxJoystick::GetManufacturerId() const
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int wxJoystick::GetProductId() const
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
wxString wxJoystick::GetProductName() const
|
|
{
|
|
char name[128];
|
|
|
|
if (ioctl(m_device, JSIOCGNAME(sizeof(name)), name) < 0)
|
|
strcpy(name, "Unknown");
|
|
return wxString(name, wxConvLibc);
|
|
}
|
|
|
|
int wxJoystick::GetXMin() const
|
|
{
|
|
return wxJS_AXIS_MIN;
|
|
}
|
|
|
|
int wxJoystick::GetYMin() const
|
|
{
|
|
return wxJS_AXIS_MIN;
|
|
}
|
|
|
|
int wxJoystick::GetZMin() const
|
|
{
|
|
return wxJS_AXIS_MIN;
|
|
}
|
|
|
|
int wxJoystick::GetXMax() const
|
|
{
|
|
return wxJS_AXIS_MAX;
|
|
}
|
|
|
|
int wxJoystick::GetYMax() const
|
|
{
|
|
return wxJS_AXIS_MAX;
|
|
}
|
|
|
|
int wxJoystick::GetZMax() const
|
|
{
|
|
return wxJS_AXIS_MAX;
|
|
}
|
|
|
|
int wxJoystick::GetNumberButtons() const
|
|
{
|
|
char nb=0;
|
|
|
|
if (m_device != -1)
|
|
ioctl(m_device, JSIOCGBUTTONS, &nb);
|
|
|
|
if ((int)nb > wxJS_MAX_BUTTONS)
|
|
nb = wxJS_MAX_BUTTONS;
|
|
|
|
return nb;
|
|
}
|
|
|
|
int wxJoystick::GetNumberAxes() const
|
|
{
|
|
char nb=0;
|
|
|
|
if (m_device != -1)
|
|
ioctl(m_device, JSIOCGAXES, &nb);
|
|
|
|
if ((int)nb > wxJS_MAX_AXES)
|
|
nb = wxJS_MAX_AXES;
|
|
|
|
return nb;
|
|
}
|
|
|
|
int wxJoystick::GetMaxButtons() const
|
|
{
|
|
return wxJS_MAX_BUTTONS; // internal
|
|
}
|
|
|
|
int wxJoystick::GetMaxAxes() const
|
|
{
|
|
return wxJS_MAX_AXES; // internal
|
|
}
|
|
|
|
int wxJoystick::GetPollingMin() const
|
|
{
|
|
return 10;
|
|
}
|
|
|
|
int wxJoystick::GetPollingMax() const
|
|
{
|
|
return 1000;
|
|
}
|
|
|
|
int wxJoystick::GetRudderMin() const
|
|
{
|
|
return wxJS_AXIS_MIN;
|
|
}
|
|
|
|
int wxJoystick::GetRudderMax() const
|
|
{
|
|
return wxJS_AXIS_MAX;
|
|
}
|
|
|
|
int wxJoystick::GetUMin() const
|
|
{
|
|
return wxJS_AXIS_MIN;
|
|
}
|
|
|
|
int wxJoystick::GetUMax() const
|
|
{
|
|
return wxJS_AXIS_MAX;
|
|
}
|
|
|
|
int wxJoystick::GetVMin() const
|
|
{
|
|
return wxJS_AXIS_MIN;
|
|
}
|
|
|
|
int wxJoystick::GetVMax() const
|
|
{
|
|
return wxJS_AXIS_MAX;
|
|
}
|
|
|
|
bool wxJoystick::HasRudder() const
|
|
{
|
|
return GetNumberAxes() >= wxJS_AXIS_RUDDER;
|
|
}
|
|
|
|
bool wxJoystick::HasZ() const
|
|
{
|
|
return GetNumberAxes() >= wxJS_AXIS_Z;
|
|
}
|
|
|
|
bool wxJoystick::HasU() const
|
|
{
|
|
return GetNumberAxes() >= wxJS_AXIS_U;
|
|
}
|
|
|
|
bool wxJoystick::HasV() const
|
|
{
|
|
return GetNumberAxes() >= wxJS_AXIS_V;
|
|
}
|
|
|
|
bool wxJoystick::HasPOV() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool wxJoystick::HasPOV4Dir() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool wxJoystick::HasPOVCTS() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// Operations
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool wxJoystick::SetCapture(wxWindow* win, int pollingFreq)
|
|
{
|
|
if (m_thread)
|
|
{
|
|
m_thread->m_catchwin = win;
|
|
m_thread->m_polling = pollingFreq;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool wxJoystick::ReleaseCapture()
|
|
{
|
|
if (m_thread)
|
|
{
|
|
m_thread->m_catchwin = NULL;
|
|
m_thread->m_polling = 0;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
#endif // wxUSE_JOYSTICK
|