2014-04-12 10:44:38 +00:00
/* LilyPad - Pad plugin for PS2 Emulator
2017-01-26 16:02:20 +00:00
* Copyright ( C ) 2002 - 2017 PCSX2 Dev Team / ChickenLiver
2014-04-12 10:44:38 +00:00
*
* PCSX2 is free software : you can redistribute it and / or modify it under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Found - ation , either version 3 of the License , or ( at your option )
* any later version .
*
* PCSX2 is distributed in the hope that it will be useful , but WITHOUT ANY
* WARRANTY ; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE . See the GNU General Public License for more
* details .
*
* You should have received a copy of the GNU General Public License along
* with PCSX2 . If not , see < http : //www.gnu.org/licenses/>.
*/
2010-04-24 21:37:39 +00:00
# include "Global.h"
// For escape timer, so as not to break GSDX+DX9.
# include <time.h>
2016-02-14 12:29:05 +00:00
# include <fstream>
# include <iomanip>
# include <sstream>
2010-04-24 21:37:39 +00:00
# include "resource.h"
# include "InputManager.h"
# include "Config.h"
# define PADdefs
# include "DeviceEnumerator.h"
2015-02-04 21:20:58 +00:00
# ifdef _MSC_VER
2010-04-24 21:37:39 +00:00
# include "WndProcEater.h"
2016-05-28 22:30:28 +00:00
# include "HidDevice.h"
2015-02-04 21:20:58 +00:00
# endif
2010-04-24 21:37:39 +00:00
# include "KeyboardQueue.h"
# include "svnrev.h"
# include "DualShock3.h"
# define WMA_FORCE_UPDATE (WM_APP + 0x537)
# define FORCE_UPDATE_WPARAM ((WPARAM)0x74328943)
# define FORCE_UPDATE_LPARAM ((LPARAM)0x89437437)
// LilyPad version.
2017-02-01 11:23:14 +00:00
# define VERSION ((0 << 8) | 12 | (1 << 24))
2010-04-24 21:37:39 +00:00
2015-02-04 21:20:58 +00:00
# ifdef __linux__
Display * GSdsp ;
2016-09-04 12:16:34 +00:00
Window GSwin ;
2015-02-04 21:20:58 +00:00
# else
2010-04-24 21:37:39 +00:00
HINSTANCE hInst ;
HWND hWnd ;
HWND hWndTop ;
WndProcEater hWndGSProc ;
WndProcEater hWndTopProc ;
// ButtonProc is used mostly by the Config panel for eating the procedures of the
// button with keyboard focus.
WndProcEater hWndButtonProc ;
2015-02-04 21:20:58 +00:00
# endif
2010-04-24 21:37:39 +00:00
// Keeps the various sources for Update polling (PADpoll, PADupdate, etc) from wreaking
// havoc on each other...
2015-02-04 21:20:58 +00:00
# ifdef __linux__
static std : : mutex updateLock ;
# else
2010-04-24 21:37:39 +00:00
CRITICAL_SECTION updateLock ;
2015-02-04 21:20:58 +00:00
# endif
2010-04-24 21:37:39 +00:00
// Used to toggle mouse listening.
u8 miceEnabled ;
// 2 when both pads are initialized, 1 for one pad, etc.
int openCount = 0 ;
int activeWindow = 0 ;
2015-02-04 21:20:58 +00:00
# ifdef _MSC_VER
2010-04-24 21:37:39 +00:00
int windowThreadId = 0 ;
int updateQueued = 0 ;
2015-02-04 21:20:58 +00:00
# endif
2010-04-24 21:37:39 +00:00
2015-11-07 09:01:33 +00:00
u32 bufSize = 0 ;
2010-04-24 21:37:39 +00:00
unsigned char outBuf [ 50 ] ;
unsigned char inBuf [ 50 ] ;
// windowThreadId = GetWindowThreadProcessId(hWnd, 0);
2016-11-13 00:23:59 +00:00
# define MODE_PS1_MOUSE 0x12
2016-12-30 18:58:24 +00:00
# define MODE_NEGCON 0x23
2010-04-24 21:37:39 +00:00
# define MODE_DIGITAL 0x41
# define MODE_ANALOG 0x73
# define MODE_DS2_NATIVE 0x79
2015-02-04 21:20:58 +00:00
# ifdef _MSC_VER
2016-09-04 12:16:34 +00:00
int IsWindowMaximized ( HWND hWnd )
{
RECT rect ;
if ( GetWindowRect ( hWnd , & rect ) ) {
POINT p ;
p . x = rect . left ;
p . y = rect . top ;
MONITORINFO info ;
memset ( & info , 0 , sizeof ( info ) ) ;
info . cbSize = sizeof ( info ) ;
HMONITOR hMonitor ;
if ( ( hMonitor = MonitorFromPoint ( p , MONITOR_DEFAULTTOPRIMARY ) ) & &
GetMonitorInfo ( hMonitor , & info ) & &
memcmp ( & info . rcMonitor , & rect , sizeof ( rect ) ) = = 0 ) {
return 1 ;
}
}
return 0 ;
2010-04-24 21:37:39 +00:00
}
2015-02-04 21:20:58 +00:00
# endif
2010-04-24 21:37:39 +00:00
2016-09-04 12:16:34 +00:00
void DEBUG_TEXT_OUT ( const char * text )
{
if ( ! config . debug )
return ;
2016-02-14 12:29:05 +00:00
2016-09-04 12:16:34 +00:00
std : : ofstream file ( " logs/padLog.txt " , std : : ios : : app ) ;
if ( ! file . good ( ) )
return ;
file < < text ;
2010-04-24 21:37:39 +00:00
}
2016-09-04 12:16:34 +00:00
void DEBUG_NEW_SET ( )
{
if ( config . debug & & bufSize > 1 ) {
std : : ofstream file ( " logs/padLog.txt " , std : : ios : : app ) ;
if ( file . good ( ) ) {
std : : stringstream stream ;
stream . setf ( std : : ios : : hex , std : : ios : : basefield ) ;
stream . setf ( std : : ios : : uppercase ) ;
stream . fill ( ' 0 ' ) ;
unsigned char * buffer [ 2 ] = { inBuf , outBuf } ;
for ( const auto & buf : buffer ) {
// Port/FF
stream < < std : : setw ( 2 ) < < int ( buf [ 0 ] ) ;
// Active slots/Enabled (only relevant for multitap)
stream < < " ( " < < std : : setw ( 2 ) < < int ( buf [ 1 ] ) < < ' ) ' ;
// Command/Response
for ( u32 n = 2 ; n < bufSize ; + + n )
stream < < ' ' < < std : : setw ( 2 ) < < int ( buf [ n ] ) ;
stream < < ' \n ' ;
}
stream < < ' \n ' ;
file < < stream . rdbuf ( ) ;
}
}
bufSize = 0 ;
2010-04-24 21:37:39 +00:00
}
2016-09-04 12:16:34 +00:00
inline void DEBUG_IN ( unsigned char c )
{
if ( bufSize < sizeof ( inBuf ) )
inBuf [ bufSize ] = c ;
2010-04-24 21:37:39 +00:00
}
2016-09-04 12:16:34 +00:00
inline void DEBUG_OUT ( unsigned char c )
{
if ( bufSize < sizeof ( outBuf ) )
outBuf [ bufSize + + ] = c ;
2010-04-24 21:37:39 +00:00
}
2016-09-04 12:16:34 +00:00
struct Stick
{
int horiz ;
int vert ;
2010-04-24 21:37:39 +00:00
} ;
// Sum of states of all controls for a pad (Not including toggles).
2016-09-04 12:16:34 +00:00
struct ButtonSum
{
int buttons [ 16 ] ;
Stick sticks [ 2 ] ;
2010-04-24 21:37:39 +00:00
} ;
2017-02-01 11:23:14 +00:00
# define PAD_SAVE_STATE_VERSION 5
2010-04-24 21:37:39 +00:00
// Freeze data, for a single pad. Basically has all pad state that
// a PS2 can set.
2016-09-04 12:16:34 +00:00
struct PadFreezeData
{
// Digital / Analog / DS2 Native
u8 mode ;
2010-04-24 21:37:39 +00:00
2017-02-01 11:23:14 +00:00
u8 previousType ;
2016-09-04 12:16:34 +00:00
u8 modeLock ;
2010-04-24 21:37:39 +00:00
2016-09-04 12:16:34 +00:00
// In config mode
u8 config ;
2010-04-24 21:37:39 +00:00
2016-09-04 12:16:34 +00:00
u8 vibrate [ 8 ] ;
u8 umask [ 2 ] ;
2010-04-24 21:37:39 +00:00
2016-09-04 12:16:34 +00:00
// Vibration indices.
u8 vibrateI [ 2 ] ;
2010-04-24 21:37:39 +00:00
2016-09-04 12:16:34 +00:00
// Last vibration value sent to controller.
// Only used so as not to call vibration
// functions when old and new values are both 0.
u8 currentVibrate [ 2 ] ;
2010-04-24 21:37:39 +00:00
2016-09-04 12:16:34 +00:00
// Next vibrate val to send to controller. If next and current are
// both 0, nothing is sent to the controller. Otherwise, it's sent
// on every update.
u8 nextVibrate [ 2 ] ;
2010-04-24 21:37:39 +00:00
} ;
2016-09-04 12:16:34 +00:00
class Pad : public PadFreezeData
{
2010-04-24 21:37:39 +00:00
public :
2016-09-04 12:16:34 +00:00
// Current pad state.
ButtonSum sum ;
// State of locked buttons. Already included by sum, used
// as initial value of sum.
ButtonSum lockedSum ;
// Flags for which controls (buttons or axes) are locked, if any.
DWORD lockedState ;
// Used to keep track of which pads I'm running.
// Note that initialized pads *can* be disabled.
// I keep track of state of non-disabled non-initialized
// pads, but should never be asked for their state.
u8 initialized ;
// Set to 1 if the state of this pad has been updated since its state
// was last queried.
char stateUpdated ;
// initialized and not disabled (and mtap state for slots > 0).
u8 enabled ;
2010-04-24 21:37:39 +00:00
} pads [ 2 ] [ 4 ] ;
// Active slots for each port.
int slots [ 2 ] ;
// Which ports we're running on.
int portInitialized [ 2 ] ;
// Force value to be from 0 to 255.
2016-09-04 12:16:34 +00:00
u8 Cap ( int i )
{
if ( i < 0 )
return 0 ;
if ( i > 255 )
return 255 ;
return ( u8 ) i ;
2010-04-24 21:37:39 +00:00
}
2016-09-04 12:16:34 +00:00
inline void ReleaseModifierKeys ( )
{
QueueKeyEvent ( VK_SHIFT , KEYRELEASE ) ;
QueueKeyEvent ( VK_MENU , KEYRELEASE ) ;
QueueKeyEvent ( VK_CONTROL , KEYRELEASE ) ;
2010-04-24 21:37:39 +00:00
}
// RefreshEnabledDevices() enables everything that can potentially
// be bound to, as well as the "Ignore keyboard" device.
//
// This enables everything that input should be read from while the
// emulator is running. Takes into account mouse and focus state
// and which devices have bindings for enabled pads. Releases
// keyboards if window is not focused. Releases game devices if
// background monitoring is not checked.
// And releases games if not focused and config.background is not set.
2016-09-04 12:16:34 +00:00
void UpdateEnabledDevices ( int updateList = 0 )
{
// Enable all devices I might want. Can ignore the rest.
RefreshEnabledDevices ( updateList ) ;
// Figure out which pads I'm getting input for.
for ( int port = 0 ; port < 2 ; port + + ) {
for ( int slot = 0 ; slot < 4 ; slot + + ) {
2016-11-06 21:59:19 +00:00
if ( slot > 0 & & ! config . multitap [ port ] ) {
2016-09-04 12:16:34 +00:00
pads [ port ] [ slot ] . enabled = 0 ;
} else {
pads [ port ] [ slot ] . enabled = pads [ port ] [ slot ] . initialized & & config . padConfigs [ port ] [ slot ] . type ! = DisabledPad ;
}
}
}
for ( int i = 0 ; i < dm - > numDevices ; i + + ) {
Device * dev = dm - > devices [ i ] ;
if ( ! dev - > enabled )
continue ;
if ( ! dev - > attached ) {
dm - > DisableDevice ( i ) ;
continue ;
}
// Disable ignore keyboard if don't have focus or there are no keys to ignore.
if ( dev - > api = = IGNORE_KEYBOARD ) {
2016-11-06 21:59:19 +00:00
if ( ( config . keyboardApi = = NO_API | | ! dev - > pads [ 0 ] [ 0 ] [ 0 ] . numBindings ) | | ! activeWindow ) {
2016-09-04 12:16:34 +00:00
dm - > DisableDevice ( i ) ;
}
continue ;
}
// Keep for PCSX2 keyboard shotcuts, unless unfocused.
if ( dev - > type = = KEYBOARD ) {
if ( ! activeWindow )
dm - > DisableDevice ( i ) ;
}
// Keep for cursor hiding consistency, unless unfocused.
// miceEnabled tracks state of mouse enable/disable button, not if mouse API is set to disabled.
else if ( dev - > type = = MOUSE ) {
if ( ! miceEnabled | | ! activeWindow )
dm - > DisableDevice ( i ) ;
} else if ( ! activeWindow & & ! config . background )
dm - > DisableDevice ( i ) ;
else {
int numActiveBindings = 0 ;
for ( int port = 0 ; port < 2 ; port + + ) {
for ( int slot = 0 ; slot < 4 ; slot + + ) {
2016-11-06 21:59:19 +00:00
int padtype = config . padConfigs [ port ] [ slot ] . type ;
2016-09-04 12:16:34 +00:00
if ( pads [ port ] [ slot ] . enabled ) {
2016-11-06 21:59:19 +00:00
numActiveBindings + = dev - > pads [ port ] [ slot ] [ padtype ] . numBindings + dev - > pads [ port ] [ slot ] [ padtype ] . numFFBindings ;
2016-09-04 12:16:34 +00:00
}
}
}
if ( ! numActiveBindings )
dm - > DisableDevice ( i ) ;
}
}
2010-04-24 21:37:39 +00:00
}
2015-02-04 21:20:58 +00:00
# ifdef _MSC_VER
2016-09-04 12:16:34 +00:00
BOOL WINAPI DllMain ( HINSTANCE hInstance , DWORD fdwReason , void * lpvReserved )
{
hInst = hInstance ;
if ( fdwReason = = DLL_PROCESS_ATTACH ) {
InitializeCriticalSection ( & updateLock ) ;
DisableThreadLibraryCalls ( hInstance ) ;
} else if ( fdwReason = = DLL_PROCESS_DETACH ) {
while ( openCount )
PADclose ( ) ;
PADshutdown ( ) ;
UninitLibUsb ( ) ;
DeleteCriticalSection ( & updateLock ) ;
}
return 1 ;
2010-04-24 21:37:39 +00:00
}
2015-02-04 21:20:58 +00:00
# endif
2010-04-24 21:37:39 +00:00
2016-09-04 12:16:34 +00:00
void AddForce ( ButtonSum * sum , u8 cmd , int delta = 255 )
{
if ( ! delta )
return ;
if ( cmd < 0x14 ) {
sum - > buttons [ cmd - 0x10 ] + = delta ;
}
// D-pad. Command numbering is based on ordering of digital values.
else if ( cmd < 0x18 ) {
sum - > buttons [ cmd - 0x08 ] + = delta ;
} else if ( cmd < 0x20 ) {
sum - > buttons [ cmd - 0x10 - 4 ] + = delta ;
}
// Left stick.
else if ( cmd < 0x24 ) {
if ( cmd = = 32 ) {
sum - > sticks [ 1 ] . vert - = delta ;
} else if ( cmd = = 33 ) {
sum - > sticks [ 1 ] . horiz + = delta ;
} else if ( cmd = = 34 ) {
sum - > sticks [ 1 ] . vert + = delta ;
} else if ( cmd = = 35 ) {
sum - > sticks [ 1 ] . horiz - = delta ;
}
}
// Right stick.
else if ( cmd < 0x28 ) {
if ( cmd = = 36 ) {
sum - > sticks [ 0 ] . vert - = delta ;
} else if ( cmd = = 37 ) {
sum - > sticks [ 0 ] . horiz + = delta ;
} else if ( cmd = = 38 ) {
sum - > sticks [ 0 ] . vert + = delta ;
} else if ( cmd = = 39 ) {
sum - > sticks [ 0 ] . horiz - = delta ;
}
}
2010-04-24 21:37:39 +00:00
}
2016-09-04 12:16:34 +00:00
void ProcessButtonBinding ( Binding * b , ButtonSum * sum , int value )
{
2016-11-29 19:31:22 +00:00
if ( value < b - > deadZone | | value = = 0 ) {
2016-09-04 12:16:34 +00:00
return ;
2016-11-29 19:31:22 +00:00
}
if ( b - > skipDeadZone > b - > deadZone ) {
value = std : : min ( ( int ) ( ( ( __int64 ) value * ( FULLY_DOWN - ( __int64 ) b - > skipDeadZone ) ) / FULLY_DOWN ) + b - > skipDeadZone , FULLY_DOWN ) ;
}
2016-09-04 12:16:34 +00:00
2017-01-26 18:14:34 +00:00
if ( b - > command = = 0x2A ) { // Turbo key
static unsigned int LastCheck = 0 ;
unsigned int t = timeGetTime ( ) ;
if ( t - LastCheck < 300 )
return ;
QueueKeyEvent ( VK_TAB , KEYPRESS ) ;
LastCheck = t ;
2016-09-04 12:16:34 +00:00
}
int sensitivity = b - > sensitivity ;
if ( sensitivity < 0 ) {
sensitivity = - sensitivity ;
value = ( 1 < < 16 ) - value ;
}
if ( value < 0 )
return ;
/* Note: Value ranges of FULLY_DOWN, and sensitivity of
2010-04-24 21:37:39 +00:00
* BASE_SENSITIVITY corresponds to an axis / button being exactly fully down .
* Math in next line takes care of those two conditions , rounding as necessary .
* Done using __int64s because overflows will occur when
* sensitivity > BASE_SENSITIVITY and / or value > FULLY_DOWN . Latter only happens
* for relative axis .
*/
2016-09-04 12:16:34 +00:00
int force = ( int ) ( ( ( ( sensitivity * ( 255 * ( __int64 ) value ) ) + BASE_SENSITIVITY / 2 ) / BASE_SENSITIVITY + FULLY_DOWN / 2 ) / FULLY_DOWN ) ;
AddForce ( sum , b - > command , force ) ;
2010-04-24 21:37:39 +00:00
}
// Restricts d-pad/analog stick values to be from -255 to 255 and button values to be from 0 to 255.
// With D-pad in DS2 native mode, the negative and positive ranges are both independently from 0 to 255,
// which is why I use 9 bits of all sticks. For left and right sticks, I have to remove a bit before sending.
2016-09-04 12:16:34 +00:00
void CapSum ( ButtonSum * sum )
{
int i ;
for ( i = 0 ; i < 2 ; i + + ) {
int div = std : : max ( abs ( sum - > sticks [ i ] . horiz ) , abs ( sum - > sticks [ i ] . vert ) ) ;
if ( div > 255 ) {
sum - > sticks [ i ] . horiz = sum - > sticks [ i ] . horiz * 255 / div ;
sum - > sticks [ i ] . vert = sum - > sticks [ i ] . vert * 255 / div ;
}
}
for ( i = 0 ; i < 16 ; i + + ) {
sum - > buttons [ i ] = Cap ( sum - > buttons [ i ] ) ;
}
2010-04-24 21:37:39 +00:00
}
// Counter similar to stateUpdated for each pad, except used for PADkeyEvent instead.
// Only matters when GS thread updates is disabled (Just like summed pad values
// for pads beyond the first slot).
// Values, in order, correspond to PADkeyEvent, PADupdate(0), PADupdate(1), and
// WndProc(WMA_FORCE_UPDATE). Last is always 0.
char padReadKeyUpdated [ 4 ] = { 0 , 0 , 0 , 0 } ;
# define LOCK_DIRECTION 2
# define LOCK_BUTTONS 4
# define LOCK_BOTH 1
2015-02-04 21:20:58 +00:00
# ifdef _MSC_VER
2010-04-24 21:37:39 +00:00
struct EnterScopedSection
{
2016-09-04 12:16:34 +00:00
CRITICAL_SECTION & m_cs ;
2010-04-24 21:37:39 +00:00
2016-09-04 12:16:34 +00:00
EnterScopedSection ( CRITICAL_SECTION & cs )
: m_cs ( cs )
{
EnterCriticalSection ( & m_cs ) ;
}
2010-04-25 00:31:27 +00:00
2016-09-04 12:16:34 +00:00
~ EnterScopedSection ( )
{
LeaveCriticalSection ( & m_cs ) ;
}
2010-04-24 21:37:39 +00:00
} ;
2015-02-04 21:20:58 +00:00
# endif
2010-04-24 21:37:39 +00:00
2016-09-04 12:16:34 +00:00
void Update ( unsigned int port , unsigned int slot )
{
char * stateUpdated ;
if ( port < 2 ) {
stateUpdated = & pads [ port ] [ slot ] . stateUpdated ;
} else if ( port < 6 ) {
stateUpdated = padReadKeyUpdated + port - 2 ;
} else
return ;
if ( * stateUpdated > 0 ) {
stateUpdated [ 0 ] - - ;
return ;
}
// Lock prior to timecheck code to avoid pesky race conditions.
2015-02-04 21:20:58 +00:00
# ifdef __linux__
2016-09-04 12:16:34 +00:00
std : : lock_guard < std : : mutex > lock ( updateLock ) ;
2015-02-04 21:20:58 +00:00
# else
2016-09-04 12:16:34 +00:00
EnterScopedSection padlock ( updateLock ) ;
2015-02-04 21:20:58 +00:00
# endif
2010-04-24 21:37:39 +00:00
2016-09-04 12:16:34 +00:00
static unsigned int LastCheck = 0 ;
unsigned int t = timeGetTime ( ) ;
if ( t - LastCheck < 15 | | ! openCount )
return ;
2010-04-24 21:37:39 +00:00
2015-02-04 21:20:58 +00:00
# ifdef _MSC_VER
2016-09-04 12:16:34 +00:00
if ( windowThreadId ! = GetCurrentThreadId ( ) ) {
if ( stateUpdated [ 0 ] < 0 ) {
if ( ! updateQueued ) {
updateQueued = 1 ;
PostMessage ( hWnd , WMA_FORCE_UPDATE , FORCE_UPDATE_WPARAM , FORCE_UPDATE_LPARAM ) ;
}
} else {
stateUpdated [ 0 ] - - ;
}
return ;
}
2015-02-04 21:20:58 +00:00
# endif
2010-04-24 21:37:39 +00:00
2016-09-04 12:16:34 +00:00
LastCheck = t ;
2010-04-24 21:37:39 +00:00
2016-09-04 12:16:34 +00:00
int i ;
ButtonSum s [ 2 ] [ 4 ] ;
u8 lockStateChanged [ 2 ] [ 4 ] ;
memset ( lockStateChanged , 0 , sizeof ( lockStateChanged ) ) ;
2010-04-24 21:37:39 +00:00
2016-09-04 12:16:34 +00:00
for ( i = 0 ; i < 8 ; i + + ) {
s [ i & 1 ] [ i > > 1 ] = pads [ i & 1 ] [ i > > 1 ] . lockedSum ;
}
2015-02-04 21:20:58 +00:00
# ifdef __linux__
2016-09-04 12:16:34 +00:00
InitInfo info = {
0 , 0 , GSdsp , GSwin } ;
2015-02-04 21:20:58 +00:00
# else
2016-09-04 12:16:34 +00:00
InitInfo info = {
0 , 0 , hWndTop , & hWndGSProc } ;
2015-02-04 21:20:58 +00:00
# endif
2016-09-04 12:16:34 +00:00
dm - > Update ( & info ) ;
2017-01-26 18:14:34 +00:00
static int rapidFire = 0 ;
rapidFire + + ;
2016-09-04 12:16:34 +00:00
for ( i = 0 ; i < dm - > numDevices ; i + + ) {
Device * dev = dm - > devices [ i ] ;
// Skip both disabled devices and inactive enabled devices.
// Shouldn't be any of the latter, in general, but just in case...
if ( ! dev - > active )
continue ;
for ( int port = 0 ; port < 2 ; port + + ) {
for ( int slot = 0 ; slot < 4 ; slot + + ) {
2016-11-06 21:59:19 +00:00
int padtype = config . padConfigs [ port ] [ slot ] . type ;
if ( padtype = = DisabledPad | | ! pads [ port ] [ slot ] . initialized )
2016-09-04 12:16:34 +00:00
continue ;
2016-11-06 21:59:19 +00:00
for ( int j = 0 ; j < dev - > pads [ port ] [ slot ] [ padtype ] . numBindings ; j + + ) {
Binding * b = dev - > pads [ port ] [ slot ] [ padtype ] . bindings + j ;
2016-09-04 12:16:34 +00:00
int cmd = b - > command ;
int state = dev - > virtualControlState [ b - > controlIndex ] ;
2017-01-26 18:14:34 +00:00
if ( ! ( rapidFire & b - > rapidFire ) ) {
2016-09-04 12:16:34 +00:00
if ( cmd > 0x0F & & cmd ! = 0x28 ) {
ProcessButtonBinding ( b , & s [ port ] [ slot ] , state ) ;
} else if ( ( state > > 15 ) & & ! ( dev - > oldVirtualControlState [ b - > controlIndex ] > > 15 ) ) {
if ( cmd = = 0x0F ) {
miceEnabled = ! miceEnabled ;
UpdateEnabledDevices ( ) ;
} else if ( cmd = = 0x0C ) {
lockStateChanged [ port ] [ slot ] | = LOCK_BUTTONS ;
} else if ( cmd = = 0x0E ) {
lockStateChanged [ port ] [ slot ] | = LOCK_DIRECTION ;
} else if ( cmd = = 0x0D ) {
lockStateChanged [ port ] [ slot ] | = LOCK_BOTH ;
2017-02-01 11:23:14 +00:00
} else if ( cmd = = 0x28 & & ! pads [ port ] [ slot ] . modeLock & & padtype = = Dualshock2Pad ) {
if ( pads [ port ] [ slot ] . mode = = MODE_ANALOG )
pads [ port ] [ slot ] . mode = MODE_DIGITAL ;
else if ( pads [ port ] [ slot ] . mode = = MODE_DIGITAL )
pads [ port ] [ slot ] . mode = MODE_ANALOG ;
2016-09-04 12:16:34 +00:00
}
}
}
}
}
}
}
dm - > PostRead ( ) ;
{
for ( int port = 0 ; port < 2 ; port + + ) {
for ( int slot = 0 ; slot < 4 ; slot + + ) {
for ( int motor = 0 ; motor < 2 ; motor + + ) {
// TODO: Probably be better to send all of these at once.
if ( pads [ port ] [ slot ] . nextVibrate [ motor ] | pads [ port ] [ slot ] . currentVibrate [ motor ] ) {
pads [ port ] [ slot ] . currentVibrate [ motor ] = pads [ port ] [ slot ] . nextVibrate [ motor ] ;
dm - > SetEffect ( port , slot , motor , pads [ port ] [ slot ] . nextVibrate [ motor ] ) ;
}
}
}
}
for ( int port = 0 ; port < 2 ; port + + ) {
for ( int slot = 0 ; slot < 4 ; slot + + ) {
pads [ port ] [ slot ] . stateUpdated = 1 ;
if ( config . padConfigs [ port ] [ slot ] . type = = DisabledPad | | ! pads [ port ] [ slot ] . initialized )
continue ;
if ( config . padConfigs [ port ] [ slot ] . type = = GuitarPad ) {
if ( ! config . GH2 ) {
s [ port ] [ slot ] . sticks [ 0 ] . vert = - s [ port ] [ slot ] . sticks [ 0 ] . vert ;
}
// GH2 hack.
else if ( config . GH2 ) {
const unsigned int oldIdList [ 5 ] = { ID_R2 , ID_CIRCLE , ID_TRIANGLE , ID_CROSS , ID_SQUARE } ;
const unsigned int idList [ 5 ] = { ID_L2 , ID_L1 , ID_R1 , ID_R2 , ID_CROSS } ;
int values [ 5 ] ;
int i ;
for ( i = 0 ; i < 5 ; i + + ) {
int id = oldIdList [ i ] - 0x1104 ;
values [ i ] = s [ port ] [ slot ] . buttons [ id ] ;
s [ port ] [ slot ] . buttons [ id ] = 0 ;
}
s [ port ] [ slot ] . buttons [ ID_TRIANGLE - 0x1104 ] = values [ 1 ] ;
for ( i = 0 ; i < 5 ; i + + ) {
int id = idList [ i ] - 0x1104 ;
s [ port ] [ slot ] . buttons [ id ] = values [ i ] ;
}
if ( s [ port ] [ slot ] . buttons [ 14 ] < = 48 & & s [ port ] [ slot ] . buttons [ 12 ] < = 48 ) {
for ( int i = 0 ; i < 5 ; i + + ) {
unsigned int id = idList [ i ] - 0x1104 ;
if ( pads [ port ] [ slot ] . sum . buttons [ id ] < s [ port ] [ slot ] . buttons [ id ] ) {
s [ port ] [ slot ] . buttons [ id ] = pads [ port ] [ slot ] . sum . buttons [ id ] ;
}
}
} else if ( pads [ port ] [ slot ] . sum . buttons [ 14 ] < = 48 & & pads [ port ] [ slot ] . sum . buttons [ 12 ] < = 48 ) {
for ( int i = 0 ; i < 5 ; i + + ) {
unsigned int id = idList [ i ] - 0x1104 ;
if ( pads [ port ] [ slot ] . sum . buttons [ id ] ) {
s [ port ] [ slot ] . buttons [ id ] = 0 ;
}
}
}
}
}
2017-01-26 16:02:20 +00:00
if ( pads [ port ] [ slot ] . mode = = MODE_DIGITAL ) {
2016-09-04 12:16:34 +00:00
for ( int i = 0 ; i < = 1 ; i + + ) {
if ( s [ port ] [ slot ] . sticks [ i ] . horiz > = 100 )
s [ port ] [ slot ] . buttons [ 13 ] + = s [ port ] [ slot ] . sticks [ i ] . horiz ;
if ( s [ port ] [ slot ] . sticks [ i ] . horiz < = - 100 )
s [ port ] [ slot ] . buttons [ 15 ] - = s [ port ] [ slot ] . sticks [ i ] . horiz ;
if ( s [ port ] [ slot ] . sticks [ i ] . vert > = 100 )
s [ port ] [ slot ] . buttons [ 14 ] + = s [ port ] [ slot ] . sticks [ i ] . vert ;
if ( s [ port ] [ slot ] . sticks [ i ] . vert < = - 100 )
s [ port ] [ slot ] . buttons [ 12 ] - = s [ port ] [ slot ] . sticks [ i ] . vert ;
}
}
CapSum ( & s [ port ] [ slot ] ) ;
if ( lockStateChanged [ port ] [ slot ] ) {
if ( lockStateChanged [ port ] [ slot ] & LOCK_BOTH ) {
if ( pads [ port ] [ slot ] . lockedState ! = ( LOCK_DIRECTION | LOCK_BUTTONS ) ) {
// Enable the one that's not enabled.
lockStateChanged [ port ] [ slot ] ^ = pads [ port ] [ slot ] . lockedState ^ ( LOCK_DIRECTION | LOCK_BUTTONS ) ;
} else {
// Disable both
lockStateChanged [ port ] [ slot ] ^ = LOCK_DIRECTION | LOCK_BUTTONS ;
}
}
if ( lockStateChanged [ port ] [ slot ] & LOCK_DIRECTION ) {
if ( pads [ port ] [ slot ] . lockedState & LOCK_DIRECTION ) {
memset ( pads [ port ] [ slot ] . lockedSum . sticks , 0 , sizeof ( pads [ port ] [ slot ] . lockedSum . sticks ) ) ;
} else {
memcpy ( pads [ port ] [ slot ] . lockedSum . sticks , s [ port ] [ slot ] . sticks , sizeof ( pads [ port ] [ slot ] . lockedSum . sticks ) ) ;
}
pads [ port ] [ slot ] . lockedState ^ = LOCK_DIRECTION ;
}
if ( lockStateChanged [ port ] [ slot ] & LOCK_BUTTONS ) {
if ( pads [ port ] [ slot ] . lockedState & LOCK_BUTTONS ) {
memset ( pads [ port ] [ slot ] . lockedSum . buttons , 0 , sizeof ( pads [ port ] [ slot ] . lockedSum . buttons ) ) ;
} else {
memcpy ( pads [ port ] [ slot ] . lockedSum . buttons , s [ port ] [ slot ] . buttons , sizeof ( pads [ port ] [ slot ] . lockedSum . buttons ) ) ;
}
pads [ port ] [ slot ] . lockedState ^ = LOCK_BUTTONS ;
}
for ( i = 0 ; i < ( int ) sizeof ( pads [ port ] [ slot ] . lockedSum ) / 4 ; i + + ) {
if ( ( ( int * ) & pads [ port ] [ slot ] . lockedSum ) [ i ] )
break ;
}
if ( i = = sizeof ( pads [ port ] [ slot ] . lockedSum ) / 4 ) {
pads [ port ] [ slot ] . lockedState = 0 ;
}
}
}
}
}
for ( i = 0 ; i < 8 ; i + + ) {
pads [ i & 1 ] [ i > > 1 ] . sum = s [ i & 1 ] [ i > > 1 ] ;
}
padReadKeyUpdated [ 0 ] = padReadKeyUpdated [ 1 ] = padReadKeyUpdated [ 2 ] = 1 ;
if ( stateUpdated [ 0 ] > 0 )
- - stateUpdated [ 0 ] ;
2010-04-24 21:37:39 +00:00
}
2016-09-04 12:16:34 +00:00
void CALLBACK PADupdate ( int port )
{
Update ( port + 3 , 0 ) ;
2010-04-24 21:37:39 +00:00
}
2016-09-04 12:16:34 +00:00
inline void SetVibrate ( int port , int slot , int motor , u8 val )
{
pads [ port ] [ slot ] . nextVibrate [ motor ] = val ;
2010-04-24 21:37:39 +00:00
}
2016-09-04 12:16:34 +00:00
u32 CALLBACK PS2EgetLibType ( void )
{
ps2e = 1 ;
return PS2E_LT_PAD ;
2010-04-24 21:37:39 +00:00
}
2016-09-04 12:16:34 +00:00
u32 CALLBACK PS2EgetLibVersion2 ( u32 type )
{
ps2e = 1 ;
if ( type = = PS2E_LT_PAD )
return ( PS2E_PAD_VERSION < < 16 ) | VERSION ;
return 0 ;
2010-04-24 21:37:39 +00:00
}
2015-02-04 21:20:58 +00:00
# ifdef _MSC_VER
2010-04-24 21:37:39 +00:00
// Used in about and config screens.
2016-09-04 12:16:34 +00:00
void GetNameAndVersionString ( wchar_t * out )
{
2016-02-13 01:47:43 +00:00
# if defined(PCSX2_DEBUG)
2016-09-04 12:16:34 +00:00
wsprintfW ( out , L " LilyPad Debug %i.%i.%i (%lld) " , ( VERSION > > 8 ) & 0xFF , VERSION & 0xFF , ( VERSION > > 24 ) & 0xFF , SVN_REV ) ;
2010-04-24 21:37:39 +00:00
# else
2016-09-04 12:16:34 +00:00
wsprintfW ( out , L " LilyPad %i.%i.%i (%lld) " , ( VERSION > > 8 ) & 0xFF , VERSION & 0xFF , ( VERSION > > 24 ) & 0xFF , SVN_REV ) ;
2010-04-24 21:37:39 +00:00
# endif
}
2015-02-04 21:20:58 +00:00
# endif
2010-04-24 21:37:39 +00:00
2016-09-04 12:16:34 +00:00
char * CALLBACK PSEgetLibName ( )
{
2016-02-13 01:47:43 +00:00
# if defined(PCSX2_DEBUG)
2016-09-04 12:16:34 +00:00
static char version [ 50 ] ;
sprintf ( version , " LilyPad Debug (%lld) " , SVN_REV ) ;
return version ;
2010-04-24 21:37:39 +00:00
# else
2016-09-04 12:16:34 +00:00
static char version [ 50 ] ;
sprintf ( version , " LilyPad (%lld) " , SVN_REV ) ;
return version ;
2010-04-24 21:37:39 +00:00
# endif
}
2016-09-04 12:16:34 +00:00
char * CALLBACK PS2EgetLibName ( void )
{
ps2e = 1 ;
return PSEgetLibName ( ) ;
2010-04-24 21:37:39 +00:00
}
//void CALLBACK PADgsDriverInfo(GSdriverInfo *info) {
// info=info;
//}
2016-09-04 12:16:34 +00:00
void CALLBACK PADshutdown ( )
{
DEBUG_TEXT_OUT ( " LilyPad shutdown. \n \n " ) ;
for ( int i = 0 ; i < 8 ; i + + )
pads [ i & 1 ] [ i > > 1 ] . initialized = 0 ;
portInitialized [ 0 ] = portInitialized [ 1 ] = 0 ;
UnloadConfigs ( ) ;
2010-04-24 21:37:39 +00:00
}
2016-09-04 12:16:34 +00:00
inline void StopVibrate ( )
{
for ( int i = 0 ; i < 8 ; i + + ) {
SetVibrate ( i & 1 , i > > 1 , 0 , 0 ) ;
SetVibrate ( i & 1 , i > > 1 , 1 , 0 ) ;
}
2010-04-24 21:37:39 +00:00
}
2016-09-04 12:16:34 +00:00
inline void ResetVibrate ( int port , int slot )
{
SetVibrate ( port , slot , 0 , 0 ) ;
SetVibrate ( port , slot , 1 , 0 ) ;
pads [ port ] [ slot ] . vibrate [ 0 ] = 0x5A ;
for ( int i = 1 ; i < 8 ; + + i )
pads [ port ] [ slot ] . vibrate [ i ] = 0xFF ;
2010-04-24 21:37:39 +00:00
}
2016-09-04 12:16:34 +00:00
void ResetPad ( int port , int slot )
{
// Lines before memset currently don't do anything useful,
// but allow this function to be called at any time.
2010-04-24 21:37:39 +00:00
2016-09-04 12:16:34 +00:00
// Need to backup, so can be called at any point.
u8 enabled = pads [ port ] [ slot ] . enabled ;
2010-04-24 21:37:39 +00:00
2016-09-04 12:16:34 +00:00
// Currently should never do anything.
SetVibrate ( port , slot , 0 , 0 ) ;
SetVibrate ( port , slot , 1 , 0 ) ;
2010-04-24 21:37:39 +00:00
2016-09-04 12:16:34 +00:00
memset ( & pads [ port ] [ slot ] , 0 , sizeof ( pads [ 0 ] [ 0 ] ) ) ;
2016-11-13 00:23:59 +00:00
if ( config . padConfigs [ port ] [ slot ] . type = = MousePad )
pads [ port ] [ slot ] . mode = MODE_PS1_MOUSE ;
2016-12-30 18:58:24 +00:00
else if ( config . padConfigs [ port ] [ slot ] . type = = neGconPad )
pads [ port ] [ slot ] . mode = MODE_NEGCON ;
2016-11-13 00:23:59 +00:00
else
pads [ port ] [ slot ] . mode = MODE_DIGITAL ;
2017-02-01 11:23:14 +00:00
2016-09-04 12:16:34 +00:00
pads [ port ] [ slot ] . umask [ 0 ] = pads [ port ] [ slot ] . umask [ 1 ] = 0xFF ;
// Sets up vibrate variable.
ResetVibrate ( port , slot ) ;
pads [ port ] [ slot ] . initialized = 1 ;
2010-04-24 21:37:39 +00:00
2016-09-04 12:16:34 +00:00
pads [ port ] [ slot ] . enabled = enabled ;
2017-02-01 11:23:14 +00:00
pads [ port ] [ slot ] . previousType = config . padConfigs [ port ] [ slot ] . type ;
pads [ port ] [ slot ] . config = 0 ;
2010-04-24 21:37:39 +00:00
}
2016-09-04 12:16:34 +00:00
struct QueryInfo
{
u8 port ;
u8 slot ;
u8 lastByte ;
u8 currentCommand ;
u8 numBytes ;
u8 queryDone ;
u8 response [ 42 ] ;
2016-02-14 14:20:37 +00:00
} query = { 0 , 0 , 0 , 0 , 0 , 0xFF , { 0xF3 } } ;
2010-04-24 21:37:39 +00:00
2015-02-04 21:20:58 +00:00
# ifdef _MSC_VER
2010-04-24 21:37:39 +00:00
int saveStateIndex = 0 ;
2015-02-04 21:20:58 +00:00
# endif
2010-04-24 21:37:39 +00:00
2016-09-04 12:16:34 +00:00
s32 CALLBACK PADinit ( u32 flags )
{
// Note: Won't load settings if already loaded.
if ( LoadSettings ( ) < 0 ) {
return - 1 ;
}
int port = ( flags & 3 ) ;
if ( port = = 3 ) {
if ( PADinit ( 1 ) = = - 1 )
return - 1 ;
return PADinit ( 2 ) ;
}
# if defined(PCSX2_DEBUG) && defined(_MSC_VER)
int tmpFlag = _CrtSetDbgFlag ( _CRTDBG_REPORT_FLAG ) ;
tmpFlag | = _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ;
_CrtSetDbgFlag ( tmpFlag ) ;
# endif
port - - ;
2016-11-06 21:59:19 +00:00
for ( int slot = 0 ; slot < 4 ; slot + + )
ResetPad ( port , slot ) ;
2016-09-04 12:16:34 +00:00
slots [ port ] = 0 ;
portInitialized [ port ] = 1 ;
query . lastByte = 1 ;
query . numBytes = 0 ;
ClearKeyQueue ( ) ;
2015-02-04 21:20:58 +00:00
# ifdef __linux__
2016-09-04 12:16:34 +00:00
R_ClearKeyQueue ( ) ;
2015-02-04 21:20:58 +00:00
# endif
2016-09-04 12:16:34 +00:00
// Just in case, when resuming emulation.
ReleaseModifierKeys ( ) ;
2010-04-24 21:37:39 +00:00
2016-09-04 12:16:34 +00:00
DEBUG_TEXT_OUT ( " LilyPad initialized \n \n " ) ;
return 0 ;
2010-04-24 21:37:39 +00:00
}
// Note to self: Has to be a define for the sizeof() to work right.
// Note to self 2: All are the same size, anyways, except for longer full DS2 response
// and shorter digital mode response.
2016-09-04 12:16:34 +00:00
# define SET_RESULT(a) \
{ \
memcpy ( query . response + 2 , a , sizeof ( a ) ) ; \
query . numBytes = 2 + sizeof ( a ) ; \
}
2010-04-24 21:37:39 +00:00
2016-09-04 12:16:34 +00:00
# define SET_FINAL_RESULT(a) \
{ \
memcpy ( query . response + 2 , a , sizeof ( a ) ) ; \
query . numBytes = 2 + sizeof ( a ) ; \
query . queryDone = 1 ; \
}
2010-04-24 21:37:39 +00:00
static const u8 ConfigExit [ 7 ] = { 0x5A , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } ;
//static const u8 ConfigExit[7] = {0x5A, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00};
2016-09-04 12:16:34 +00:00
static const u8 noclue [ 7 ] = { 0x5A , 0x00 , 0x00 , 0x02 , 0x00 , 0x00 , 0x5A } ;
static u8 queryMaskMode [ 7 ] = { 0x5A , 0xFF , 0xFF , 0x00 , 0x00 , 0x00 , 0x5A } ;
2010-04-24 21:37:39 +00:00
//static const u8 DSNonNativeMode[7] = {0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
2016-09-04 12:16:34 +00:00
static const u8 setMode [ 7 ] = { 0x5A , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } ;
2010-04-24 21:37:39 +00:00
// DS2
2016-09-04 12:16:34 +00:00
static const u8 queryModelDS2 [ 7 ] = { 0x5A , 0x03 , 0x02 , 0x00 , 0x02 , 0x01 , 0x00 } ;
2010-04-24 21:37:39 +00:00
// DS1
2016-09-04 12:16:34 +00:00
static const u8 queryModelDS1 [ 7 ] = { 0x5A , 0x01 , 0x02 , 0x00 , 0x02 , 0x01 , 0x00 } ;
2010-04-24 21:37:39 +00:00
2016-09-04 12:16:34 +00:00
static const u8 queryAct [ 2 ] [ 7 ] = { { 0x5A , 0x00 , 0x00 , 0x01 , 0x02 , 0x00 , 0x0A } ,
{ 0x5A , 0x00 , 0x00 , 0x01 , 0x01 , 0x01 , 0x14 } } ;
2010-04-24 21:37:39 +00:00
2016-09-04 12:16:34 +00:00
static const u8 queryComb [ 7 ] = { 0x5A , 0x00 , 0x00 , 0x02 , 0x00 , 0x01 , 0x00 } ;
2010-04-24 21:37:39 +00:00
2016-09-04 12:16:34 +00:00
static const u8 queryMode [ 7 ] = { 0x5A , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } ;
2010-04-24 21:37:39 +00:00
2016-09-04 12:16:34 +00:00
static const u8 setNativeMode [ 7 ] = { 0x5A , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x5A } ;
2010-04-24 21:37:39 +00:00
2015-02-04 21:20:58 +00:00
# ifdef _MSC_VER
2010-04-24 21:37:39 +00:00
// Implements a couple of the hacks that affect whatever top-level window
// the GS viewport belongs to (title, screensaver)
2016-09-04 12:16:34 +00:00
ExtraWndProcResult TitleHackWndProc ( HWND hWndTop , UINT uMsg , WPARAM wParam , LPARAM lParam , LRESULT * output )
{
switch ( uMsg ) {
case WM_SETTEXT :
if ( config . saveStateTitle ) {
wchar_t text [ 200 ] ;
int len ;
if ( IsWindowUnicode ( hWndTop ) ) {
len = wcslen ( ( wchar_t * ) lParam ) ;
if ( len < sizeof ( text ) / sizeof ( wchar_t ) )
wcscpy ( text , ( wchar_t * ) lParam ) ;
} else {
len = MultiByteToWideChar ( CP_ACP , 0 , ( char * ) lParam , - 1 , text , sizeof ( text ) / sizeof ( wchar_t ) ) ;
}
if ( len > 0 & & len < 150 & & ! wcsstr ( text , L " | State(Lilypad) " ) ) {
wsprintfW ( text + len , L " | State(Lilypad) %i " , saveStateIndex ) ;
SetWindowText ( hWndTop , text ) ;
return NO_WND_PROC ;
}
}
break ;
case WM_SYSCOMMAND :
if ( ( wParam = = SC_SCREENSAVE | | wParam = = SC_MONITORPOWER ) & & config . disableScreenSaver )
return NO_WND_PROC ;
break ;
default :
break ;
}
return CONTINUE_BLISSFULLY ;
2010-04-24 21:37:39 +00:00
}
2014-04-16 15:39:07 +00:00
// Useful sequence before changing into active/inactive state.
// Handles hooking/unhooking of mouse and KB and also mouse cursor visibility.
// towardsActive==true indicates we're gaining activity (on focus etc), false is for losing activity (on close, kill focus, etc).
2016-09-04 12:16:34 +00:00
void PrepareActivityState ( bool towardsActive )
{
if ( ! towardsActive )
ReleaseModifierKeys ( ) ;
activeWindow = towardsActive ;
UpdateEnabledDevices ( ) ;
2014-04-16 15:39:07 +00:00
}
2010-04-24 21:37:39 +00:00
// responsible for monitoring device addition/removal, focus changes, and viewport closures.
2016-09-04 12:16:34 +00:00
ExtraWndProcResult StatusWndProc ( HWND hWnd , UINT uMsg , WPARAM wParam , LPARAM lParam , LRESULT * output )
{
switch ( uMsg ) {
case WMA_FORCE_UPDATE :
if ( wParam = = FORCE_UPDATE_WPARAM & & lParam = = FORCE_UPDATE_LPARAM ) {
if ( updateQueued ) {
updateQueued = 0 ;
Update ( 5 , 0 ) ;
}
return NO_WND_PROC ;
}
case WM_DEVICECHANGE :
if ( wParam = = DBT_DEVNODES_CHANGED ) {
UpdateEnabledDevices ( 1 ) ;
}
break ;
case WM_ACTIVATE :
// Release any buttons PCSX2 may think are down when
// losing/gaining focus.
// Note - I never managed to see this case entered, but SET/KILLFOCUS are entered. - avih 2014-04-16
PrepareActivityState ( LOWORD ( wParam ) ! = WA_INACTIVE ) ;
break ;
case WM_CLOSE :
2017-01-26 18:13:05 +00:00
if ( config . closeHack ) {
2016-09-04 12:16:34 +00:00
ExitProcess ( 0 ) ;
return NO_WND_PROC ;
}
break ;
case WM_DESTROY :
QueueKeyEvent ( VK_ESCAPE , KEYPRESS ) ;
break ;
case WM_KILLFOCUS :
PrepareActivityState ( false ) ;
break ;
case WM_SETFOCUS :
PrepareActivityState ( true ) ;
break ;
default :
break ;
}
return CONTINUE_BLISSFULLY ;
2010-04-24 21:37:39 +00:00
}
// All that's needed to force hiding the cursor in the proper thread.
// Could have a special case elsewhere, but this make sure it's called
// only once, rather than repeatedly.
2016-09-04 12:16:34 +00:00
ExtraWndProcResult HideCursorProc ( HWND hWnd , UINT uMsg , WPARAM wParam , LPARAM lParam , LRESULT * output )
{
ShowCursor ( 0 ) ;
return CONTINUE_BLISSFULLY_AND_RELEASE_PROC ;
2010-04-24 21:37:39 +00:00
}
char restoreFullScreen = 0 ;
2015-10-06 22:22:47 +00:00
// This hack sends ALT+ENTER to the window to toggle fullscreen.
// PCSX2 doesn't need it (it exits full screen on ESC on its own).
2016-09-04 12:16:34 +00:00
DWORD WINAPI MaximizeWindowThreadProc ( void * lpParameter )
{
Sleep ( 100 ) ;
keybd_event ( VK_LMENU , MapVirtualKey ( VK_LMENU , MAPVK_VK_TO_VSC ) , 0 , 0 ) ;
keybd_event ( VK_RETURN , MapVirtualKey ( VK_RETURN , MAPVK_VK_TO_VSC ) , 0 , 0 ) ;
Sleep ( 10 ) ;
keybd_event ( VK_RETURN , MapVirtualKey ( VK_RETURN , MAPVK_VK_TO_VSC ) , KEYEVENTF_KEYUP , 0 ) ;
keybd_event ( VK_LMENU , MapVirtualKey ( VK_LMENU , MAPVK_VK_TO_VSC ) , KEYEVENTF_KEYUP , 0 ) ;
return 0 ;
2010-04-24 21:37:39 +00:00
}
2015-02-04 21:20:58 +00:00
# endif
2010-04-24 21:37:39 +00:00
2016-09-04 12:16:34 +00:00
void CALLBACK PADconfigure ( )
{
if ( openCount ) {
return ;
}
Configure ( ) ;
2010-04-24 21:37:39 +00:00
}
2015-02-04 21:20:58 +00:00
# ifdef _MSC_VER
2016-09-04 12:16:34 +00:00
DWORD WINAPI RenameWindowThreadProc ( void * lpParameter )
{
wchar_t newTitle [ 200 ] ;
if ( hWndTop ) {
int len = GetWindowTextW ( hWndTop , newTitle , 200 ) ;
if ( len > 0 & & len < 199 ) {
wchar_t * end ;
if ( end = wcsstr ( newTitle , L " | State " ) )
* end = 0 ;
SetWindowTextW ( hWndTop , newTitle ) ;
}
}
return 0 ;
2010-04-24 21:37:39 +00:00
}
2016-09-04 12:16:34 +00:00
void SaveStateChanged ( )
{
if ( config . saveStateTitle ) {
// GSDX only checks its window's message queue at certain points or something, so
// have to do this in another thread to prevent deadlock.
HANDLE hThread = CreateThread ( 0 , 0 , RenameWindowThreadProc , 0 , 0 , 0 ) ;
if ( hThread )
CloseHandle ( hThread ) ;
}
2010-04-24 21:37:39 +00:00
}
2015-02-04 21:20:58 +00:00
# endif
2010-04-24 21:37:39 +00:00
2016-09-04 12:16:34 +00:00
s32 CALLBACK PADopen ( void * pDsp )
{
if ( openCount + + )
return 0 ;
DEBUG_TEXT_OUT ( " LilyPad opened \n \n " ) ;
2010-04-24 21:37:39 +00:00
2016-09-04 12:16:34 +00:00
miceEnabled = ! config . mouseUnfocus ;
2015-02-04 21:20:58 +00:00
# ifdef _MSC_VER
2016-09-04 12:16:34 +00:00
if ( ! hWnd ) {
if ( IsWindow ( ( HWND ) pDsp ) ) {
hWnd = ( HWND ) pDsp ;
} else if ( pDsp & & ! IsBadReadPtr ( pDsp , 4 ) & & IsWindow ( * ( HWND * ) pDsp ) ) {
hWnd = * ( HWND * ) pDsp ;
} else {
openCount = 0 ;
MessageBoxA ( GetActiveWindow ( ) ,
" Invalid Window handle passed to LilyPad. \n "
" \n "
" Either your emulator or gs plugin is buggy, \n "
" Despite the fact the emulator is about to \n "
" blame LilyPad for failing to initialize. " ,
" Non-LilyPad Error " , MB_OK | MB_ICONERROR ) ;
return - 1 ;
}
hWndTop = hWnd ;
while ( GetWindowLong ( hWndTop , GWL_STYLE ) & WS_CHILD )
hWndTop = GetParent ( hWndTop ) ;
if ( ! hWndGSProc . SetWndHandle ( hWnd ) ) {
openCount = 0 ;
return - 1 ;
}
// Implements most hacks, as well as enabling/disabling mouse
// capture when focus changes.
updateQueued = 0 ;
hWndGSProc . Eat ( StatusWndProc , 0 ) ;
if ( hWnd ! = hWndTop ) {
if ( ! hWndTopProc . SetWndHandle ( hWndTop ) ) {
openCount = 0 ;
return - 1 ;
}
hWndTopProc . Eat ( TitleHackWndProc , 0 ) ;
} else
hWndGSProc . Eat ( TitleHackWndProc , 0 ) ;
if ( config . forceHide ) {
hWndGSProc . Eat ( HideCursorProc , 0 ) ;
}
SaveStateChanged ( ) ;
windowThreadId = GetWindowThreadProcessId ( hWndTop , 0 ) ;
}
if ( restoreFullScreen ) {
if ( ! IsWindowMaximized ( hWndTop ) ) {
HANDLE hThread = CreateThread ( 0 , 0 , MaximizeWindowThreadProc , hWndTop , 0 , 0 ) ;
if ( hThread )
CloseHandle ( hThread ) ;
}
restoreFullScreen = 0 ;
}
2015-02-04 21:20:58 +00:00
# endif
2016-09-04 12:16:34 +00:00
for ( int port = 0 ; port < 2 ; port + + ) {
for ( int slot = 0 ; slot < 4 ; slot + + ) {
memset ( & pads [ port ] [ slot ] . sum , 0 , sizeof ( pads [ port ] [ slot ] . sum ) ) ;
memset ( & pads [ port ] [ slot ] . lockedSum , 0 , sizeof ( pads [ port ] [ slot ] . lockedSum ) ) ;
pads [ port ] [ slot ] . lockedState = 0 ;
2017-02-01 11:23:14 +00:00
if ( config . padConfigs [ port ] [ slot ] . type ! = pads [ port ] [ slot ] . previousType ) {
ResetPad ( port , slot ) ;
}
2016-09-04 12:16:34 +00:00
}
}
2010-04-24 21:37:39 +00:00
2015-02-04 21:20:58 +00:00
# ifdef _MSC_VER
2016-09-04 12:16:34 +00:00
// I'd really rather use this line, but GetActiveWindow() does not have complete specs.
// It *seems* to return null when no window from this thread has focus, but the
// Microsoft specs seem to imply it returns the window from this thread that would have focus,
// if any window did (topmost in this thread?). Which isn't what I want, and doesn't seem
// to be what it actually does.
// activeWindow = GetActiveWindow() == hWnd;
// activeWindow = (GetAncestor(hWnd, GA_ROOT) == GetAncestor(GetForegroundWindow(), GA_ROOT));
2015-02-04 21:20:58 +00:00
# else
2016-09-04 12:16:34 +00:00
// Not used so far
GSdsp = * ( Display * * ) pDsp ;
GSwin = ( Window ) * ( ( ( uptr * ) pDsp ) + 1 ) ;
2015-02-04 21:20:58 +00:00
# endif
2016-09-04 12:16:34 +00:00
activeWindow = 1 ;
UpdateEnabledDevices ( ) ;
return 0 ;
2010-04-24 21:37:39 +00:00
}
2016-09-04 12:16:34 +00:00
void CALLBACK PADclose ( )
{
if ( openCount & & ! - - openCount ) {
DEBUG_TEXT_OUT ( " LilyPad closed \n \n " ) ;
2015-02-04 21:20:58 +00:00
# ifdef _MSC_VER
2016-09-04 12:16:34 +00:00
updateQueued = 0 ;
hWndGSProc . Release ( ) ;
hWndTopProc . Release ( ) ;
dm - > ReleaseInput ( ) ;
hWnd = 0 ;
hWndTop = 0 ;
2015-02-04 21:20:58 +00:00
# else
2016-09-04 12:16:34 +00:00
R_ClearKeyQueue ( ) ;
2015-02-04 21:20:58 +00:00
# endif
2016-09-04 12:16:34 +00:00
ClearKeyQueue ( ) ;
}
2010-04-24 21:37:39 +00:00
}
2016-09-04 12:16:34 +00:00
u8 CALLBACK PADstartPoll ( int port )
{
DEBUG_NEW_SET ( ) ;
port - - ;
if ( ( unsigned int ) port < = 1 & & pads [ port ] [ slots [ port ] ] . enabled ) {
query . queryDone = 0 ;
query . port = port ;
query . slot = slots [ port ] ;
query . numBytes = 2 ;
query . lastByte = 0 ;
DEBUG_IN ( port ) ;
DEBUG_OUT ( 0xFF ) ;
DEBUG_IN ( slots [ port ] ) ;
DEBUG_OUT ( pads [ port ] [ slots [ port ] ] . enabled ) ;
return 0xFF ;
} else {
query . queryDone = 1 ;
query . numBytes = 0 ;
query . lastByte = 1 ;
DEBUG_IN ( 0 ) ;
DEBUG_OUT ( 0 ) ;
DEBUG_IN ( port ) ;
DEBUG_OUT ( 0 ) ;
return 0 ;
}
2010-04-24 21:37:39 +00:00
}
2016-09-04 12:16:34 +00:00
inline int IsDualshock2 ( u8 port , u8 slot )
{
return config . padConfigs [ query . port ] [ query . slot ] . type = = Dualshock2Pad | |
( config . padConfigs [ query . port ] [ query . slot ] . type = = GuitarPad & & config . GH2 ) ;
2010-04-24 21:37:39 +00:00
}
2016-09-04 12:16:34 +00:00
u8 CALLBACK PADpoll ( u8 value )
{
DEBUG_IN ( value ) ;
if ( query . lastByte + 1 > = query . numBytes ) {
DEBUG_OUT ( 0 ) ;
return 0 ;
}
if ( query . lastByte & & query . queryDone ) {
DEBUG_OUT ( query . response [ 1 + query . lastByte ] ) ;
return query . response [ + + query . lastByte ] ;
}
Pad * pad = & pads [ query . port ] [ query . slot ] ;
2017-02-01 11:23:14 +00:00
int padtype = config . padConfigs [ query . port ] [ query . slot ] . type ;
2016-09-04 12:16:34 +00:00
if ( query . lastByte = = 0 ) {
query . lastByte + + ;
query . currentCommand = value ;
2016-12-30 18:58:24 +00:00
// Only the 0x42(read input and vibration) and 0x43(enter or exit config mode) command cases work outside of config mode, the other cases will be avoided.
2017-02-01 11:23:14 +00:00
if ( ( ! pad - > config & & value ! = 0x42 & & value ! = 0x43 ) | | ( padtype = = neGconPad & & ( value < 0x40 | | value > 0x45 ) ) ) {
2016-12-30 18:58:24 +00:00
query . numBytes = 0 ;
query . queryDone = 1 ;
DEBUG_OUT ( 0xF3 ) ;
return 0xF3 ;
}
2016-09-04 12:16:34 +00:00
switch ( value ) {
// CONFIG_MODE
case 0x43 :
2017-02-01 11:23:14 +00:00
if ( pad - > config & & padtype ! = neGconPad ) {
if ( pad - > mode = = MODE_DIGITAL & & padtype = = Dualshock2Pad & & config . padConfigs [ query . port ] [ query . slot ] . autoAnalog ) {
2016-09-04 12:16:34 +00:00
pad - > mode = MODE_ANALOG ;
}
// In config mode. Might not actually be leaving it.
SET_RESULT ( ConfigExit ) ;
DEBUG_OUT ( 0xF3 ) ;
return 0xF3 ;
}
// READ_DATA_AND_VIBRATE
case 0x42 :
query . response [ 2 ] = 0x5A ;
{
Update ( query . port , query . slot ) ;
ButtonSum * sum = & pad - > sum ;
2016-12-30 18:58:24 +00:00
if ( padtype = = MousePad ) {
2016-11-13 00:23:59 +00:00
u8 b1 = 0xFC ;
2016-11-14 12:55:55 +00:00
if ( sum - > buttons [ 9 ] > 0 ) // Left button
b1 - = 8 ;
if ( sum - > buttons [ 10 ] > 0 ) // Right button
b1 - = 4 ;
2016-11-13 00:23:59 +00:00
query . response [ 3 ] = 0xFF ;
query . response [ 4 ] = b1 ;
query . response [ 5 ] = sum - > sticks [ 1 ] . horiz / 2 ;
query . response [ 6 ] = sum - > sticks [ 1 ] . vert / 2 ;
query . numBytes = 7 ;
query . lastByte = 1 ;
2016-12-30 18:58:24 +00:00
DEBUG_OUT ( MODE_PS1_MOUSE ) ;
return MODE_PS1_MOUSE ;
}
if ( padtype = = neGconPad ) {
u8 b1 = 0xFF , b2 = 0xFF ;
b1 - = ( sum - > buttons [ 3 ] > 0 ) < < 3 ; // Start
for ( int i = 3 ; i < 6 ; i + + ) {
b2 - = ( sum - > buttons [ i + 4 ] > 0 ) < < i ; // R, A, B
}
for ( int i = 4 ; i < 8 ; i + + ) {
b1 - = ( sum - > buttons [ i + 8 ] > 0 ) < < i ; // D-pad Up, Right, Down, Left
}
query . response [ 3 ] = b1 ;
query . response [ 4 ] = b2 ;
query . response [ 5 ] = Cap ( ( sum - > sticks [ 1 ] . horiz + 255 ) / 2 ) ; // Swivel
query . response [ 6 ] = ( unsigned char ) sum - > buttons [ 10 ] ; // I
query . response [ 7 ] = ( unsigned char ) sum - > buttons [ 11 ] ; // II
query . response [ 8 ] = ( unsigned char ) sum - > buttons [ 6 ] ; // L
query . numBytes = 9 ;
query . lastByte = 1 ;
DEBUG_OUT ( MODE_NEGCON ) ;
return MODE_NEGCON ;
2016-11-13 00:23:59 +00:00
}
2016-09-04 12:16:34 +00:00
u8 b1 = 0xFF , b2 = 0xFF ;
2017-02-01 11:23:14 +00:00
for ( int i = 0 ; i < 4 ; i + + ) {
2016-09-04 12:16:34 +00:00
b1 - = ( sum - > buttons [ i ] > 0 ) < < i ;
}
2017-02-01 11:23:14 +00:00
for ( int i = 0 ; i < 8 ; i + + ) {
2016-09-04 12:16:34 +00:00
b2 - = ( sum - > buttons [ i + 4 ] > 0 ) < < i ;
}
2016-12-30 18:58:24 +00:00
if ( padtype = = GuitarPad & & ! config . GH2 ) {
2016-09-04 12:16:34 +00:00
sum - > buttons [ 15 ] = 255 ;
// Not sure about this. Forces wammy to be from 0 to 0x7F.
// if (sum->sticks[2].vert > 0) sum->sticks[2].vert = 0;
}
2017-02-01 11:23:14 +00:00
for ( int i = 4 ; i < 8 ; i + + ) {
2016-09-04 12:16:34 +00:00
b1 - = ( sum - > buttons [ i + 8 ] > 0 ) < < i ;
}
//Left, Right and Down are always pressed on Pop'n Music controller.
2016-12-30 18:58:24 +00:00
if ( padtype = = PopnPad )
2016-09-04 12:16:34 +00:00
b1 = b1 & 0x1f ;
query . response [ 3 ] = b1 ;
query . response [ 4 ] = b2 ;
query . numBytes = 5 ;
if ( pad - > mode ! = MODE_DIGITAL ) {
2017-01-26 16:02:20 +00:00
query . response [ 5 ] = Cap ( ( sum - > sticks [ 0 ] . horiz + 255 ) / 2 ) ; // Right stick: left & right
query . response [ 6 ] = Cap ( ( sum - > sticks [ 0 ] . vert + 255 ) / 2 ) ; // Right stick: up & down
query . response [ 7 ] = Cap ( ( sum - > sticks [ 1 ] . horiz + 255 ) / 2 ) ; // Left stick: left & right
query . response [ 8 ] = Cap ( ( sum - > sticks [ 1 ] . vert + 255 ) / 2 ) ; // Left stick: up & down
2016-09-04 12:16:34 +00:00
query . numBytes = 9 ;
2017-02-01 11:23:14 +00:00
if ( pad - > mode ! = MODE_ANALOG & & ! pad - > config ) {
2016-09-04 12:16:34 +00:00
// Good idea? No clue.
//query.response[3] &= pad->mask[0];
//query.response[4] &= pad->mask[1];
// No need to cap these, already done int CapSum().
2016-10-16 19:39:56 +00:00
query . response [ 9 ] = ( unsigned char ) sum - > buttons [ 13 ] ; //D-pad right
query . response [ 10 ] = ( unsigned char ) sum - > buttons [ 15 ] ; //D-pad left
query . response [ 11 ] = ( unsigned char ) sum - > buttons [ 12 ] ; //D-pad up
query . response [ 12 ] = ( unsigned char ) sum - > buttons [ 14 ] ; //D-pad down
2016-09-04 12:16:34 +00:00
2017-01-26 16:02:20 +00:00
query . response [ 13 ] = ( unsigned char ) sum - > buttons [ 8 ] ; // Triangle
query . response [ 14 ] = ( unsigned char ) sum - > buttons [ 9 ] ; // Circle
query . response [ 15 ] = ( unsigned char ) sum - > buttons [ 10 ] ; // Cross
query . response [ 16 ] = ( unsigned char ) sum - > buttons [ 11 ] ; // Square
query . response [ 17 ] = ( unsigned char ) sum - > buttons [ 6 ] ; // L1
query . response [ 18 ] = ( unsigned char ) sum - > buttons [ 7 ] ; // R1
query . response [ 19 ] = ( unsigned char ) sum - > buttons [ 4 ] ; // L2
query . response [ 20 ] = ( unsigned char ) sum - > buttons [ 5 ] ; // R2
2016-09-04 12:16:34 +00:00
query . numBytes = 21 ;
}
}
}
query . lastByte = 1 ;
DEBUG_OUT ( pad - > mode ) ;
return pad - > mode ;
// SET_VREF_PARAM
case 0x40 :
SET_FINAL_RESULT ( noclue ) ;
break ;
// QUERY_DS2_ANALOG_MODE
case 0x41 :
// Right? Wrong? No clue.
2017-02-01 11:23:14 +00:00
if ( pad - > mode = = MODE_PS1_MOUSE | | pad - > mode = = MODE_NEGCON ) {
2016-09-04 12:16:34 +00:00
queryMaskMode [ 1 ] = queryMaskMode [ 2 ] = queryMaskMode [ 3 ] = 0 ;
queryMaskMode [ 6 ] = 0x00 ;
} else {
queryMaskMode [ 1 ] = pad - > umask [ 0 ] ;
queryMaskMode [ 2 ] = pad - > umask [ 1 ] ;
queryMaskMode [ 3 ] = 0x03 ;
// Not entirely sure about this.
//queryMaskMode[3] = 0x01 | (pad->mode == MODE_DS2_NATIVE)*2;
queryMaskMode [ 6 ] = 0x5A ;
}
SET_FINAL_RESULT ( queryMaskMode ) ;
break ;
// SET_MODE_AND_LOCK
case 0x44 :
SET_RESULT ( setMode ) ;
ResetVibrate ( query . port , query . slot ) ;
break ;
// QUERY_MODEL_AND_MODE
case 0x45 :
if ( IsDualshock2 ( query . port , query . slot ) ) {
2017-02-01 11:23:14 +00:00
SET_FINAL_RESULT ( queryModelDS2 ) ;
2016-09-04 12:16:34 +00:00
} else {
SET_FINAL_RESULT ( queryModelDS1 ) ;
}
// Not digital mode.
query . response [ 5 ] = ( pad - > mode & 0xF ) ! = 1 ;
break ;
// QUERY_ACT
case 0x46 :
SET_RESULT ( queryAct [ 0 ] ) ;
break ;
// QUERY_COMB
case 0x47 :
SET_FINAL_RESULT ( queryComb ) ;
break ;
// QUERY_MODE
case 0x4C :
SET_RESULT ( queryMode ) ;
break ;
// VIBRATION_TOGGLE
case 0x4D :
memcpy ( query . response + 2 , pad - > vibrate , 7 ) ;
query . numBytes = 9 ;
ResetVibrate ( query . port , query . slot ) ;
break ;
// SET_DS2_NATIVE_MODE
case 0x4F :
if ( IsDualshock2 ( query . port , query . slot ) ) {
SET_RESULT ( setNativeMode ) ;
} else {
SET_FINAL_RESULT ( setNativeMode ) ;
}
break ;
default :
query . numBytes = 0 ;
query . queryDone = 1 ;
break ;
}
DEBUG_OUT ( 0xF3 ) ;
return 0xF3 ;
} else {
query . lastByte + + ;
2016-12-30 18:58:24 +00:00
// Only the 0x42(read input and vibration) and 0x43(enter or exit config mode) command cases work outside of config mode, the other cases will be avoided.
2017-02-01 11:23:14 +00:00
if ( ( ! pad - > config & & query . currentCommand ! = 0x42 & & query . currentCommand ! = 0x43 ) | | ( padtype = = neGconPad & & ( query . currentCommand < 0x40 | | query . currentCommand > 0x45 ) ) ) {
2016-12-30 18:58:24 +00:00
DEBUG_OUT ( query . response [ query . lastByte ] ) ;
return query . response [ query . lastByte ] ;
}
2016-09-04 12:16:34 +00:00
switch ( query . currentCommand ) {
// READ_DATA_AND_VIBRATE
case 0x42 :
if ( query . lastByte = = pad - > vibrateI [ 0 ] ) {
SetVibrate ( query . port , query . slot , 1 , 255 * ( value & 1 ) ) ;
} else if ( query . lastByte = = pad - > vibrateI [ 1 ] ) {
SetVibrate ( query . port , query . slot , 0 , value ) ;
}
break ;
// CONFIG_MODE
case 0x43 :
if ( query . lastByte = = 3 ) {
query . queryDone = 1 ;
2017-02-01 11:23:14 +00:00
pad - > config = value ;
2016-09-04 12:16:34 +00:00
}
break ;
// SET_MODE_AND_LOCK
case 0x44 :
if ( query . lastByte = = 3 & & value < 2 ) {
2016-12-30 18:58:24 +00:00
if ( padtype = = MousePad ) {
2016-11-13 00:23:59 +00:00
pad - > mode = MODE_PS1_MOUSE ;
2016-12-30 18:58:24 +00:00
} else if ( padtype = = neGconPad ) {
pad - > mode = MODE_NEGCON ;
2016-11-13 00:23:59 +00:00
} else {
static const u8 modes [ 2 ] = { MODE_DIGITAL , MODE_ANALOG } ;
pad - > mode = modes [ value ] ;
}
2016-09-04 12:16:34 +00:00
} else if ( query . lastByte = = 4 ) {
if ( value = = 3 ) {
pad - > modeLock = 3 ;
} else {
pad - > modeLock = 0 ;
2017-02-01 11:23:14 +00:00
if ( pad - > mode = = MODE_DIGITAL & & padtype = = Dualshock2Pad & & config . padConfigs [ query . port ] [ query . slot ] . autoAnalog ) {
2016-09-04 12:16:34 +00:00
pad - > mode = MODE_ANALOG ;
}
}
query . queryDone = 1 ;
}
break ;
// QUERY_ACT
case 0x46 :
if ( query . lastByte = = 3 ) {
if ( value < 2 )
SET_RESULT ( queryAct [ value ] )
// bunch of 0's
// else SET_RESULT(setMode);
query . queryDone = 1 ;
}
break ;
// QUERY_MODE
case 0x4C :
if ( query . lastByte = = 3 & & value < 2 ) {
query . response [ 6 ] = 4 + value * 3 ;
query . queryDone = 1 ;
}
// bunch of 0's
//else data = setMode;
break ;
// VIBRATION_TOGGLE
case 0x4D :
if ( query . lastByte > = 3 ) {
if ( value = = 0 ) {
pad - > vibrateI [ 0 ] = ( u8 ) query . lastByte ;
} else if ( value = = 1 ) {
pad - > vibrateI [ 1 ] = ( u8 ) query . lastByte ;
}
pad - > vibrate [ query . lastByte - 2 ] = value ;
}
break ;
// SET_DS2_NATIVE_MODE
case 0x4F :
if ( query . lastByte = = 3 | | query . lastByte = = 4 ) {
pad - > umask [ query . lastByte - 3 ] = value ;
} else if ( query . lastByte = = 5 ) {
if ( ! ( value & 1 ) ) {
pad - > mode = MODE_DIGITAL ;
} else if ( ! ( value & 2 ) ) {
pad - > mode = MODE_ANALOG ;
} else {
pad - > mode = MODE_DS2_NATIVE ;
}
}
break ;
default :
DEBUG_OUT ( 0 ) ;
return 0 ;
}
DEBUG_OUT ( query . response [ query . lastByte ] ) ;
return query . response [ query . lastByte ] ;
}
2010-04-24 21:37:39 +00:00
}
// returns: 1 if supports pad1
// 2 if supports pad2
// 3 if both are supported
2016-09-04 12:16:34 +00:00
u32 CALLBACK PADquery ( )
{
return 3 ;
2010-04-24 21:37:39 +00:00
}
2015-02-04 21:20:58 +00:00
# ifdef _MSC_VER
2016-09-04 12:16:34 +00:00
INT_PTR CALLBACK AboutDialogProc ( HWND hWndDlg , UINT uMsg , WPARAM wParam , LPARAM lParam )
{
if ( uMsg = = WM_INITDIALOG ) {
wchar_t idString [ 100 ] ;
GetNameAndVersionString ( idString ) ;
SetDlgItemTextW ( hWndDlg , IDC_VERSION , idString ) ;
} else if ( uMsg = = WM_COMMAND & & ( LOWORD ( wParam ) = = IDOK | | LOWORD ( wParam ) = = IDCANCEL ) ) {
EndDialog ( hWndDlg , 0 ) ;
return 1 ;
}
return 0 ;
2010-04-24 21:37:39 +00:00
}
2015-02-04 21:20:58 +00:00
# endif
2010-04-24 21:37:39 +00:00
2016-09-04 12:16:34 +00:00
void CALLBACK PADabout ( )
{
2015-02-04 21:20:58 +00:00
# ifdef _MSC_VER
2016-09-04 12:16:34 +00:00
DialogBox ( hInst , MAKEINTRESOURCE ( IDD_ABOUT ) , 0 , AboutDialogProc ) ;
2015-02-04 21:20:58 +00:00
# endif
2010-04-24 21:37:39 +00:00
}
2016-09-04 12:16:34 +00:00
s32 CALLBACK PADtest ( )
{
return 0 ;
2010-04-24 21:37:39 +00:00
}
2016-09-04 12:16:34 +00:00
keyEvent * CALLBACK PADkeyEvent ( )
{
// If running both pads, ignore every other call. So if two keys pressed in same interval...
static char eventCount = 0 ;
eventCount + + ;
if ( eventCount < openCount ) {
return 0 ;
}
eventCount = 0 ;
2010-04-24 21:37:39 +00:00
2016-09-04 12:16:34 +00:00
Update ( 2 , 0 ) ;
static keyEvent ev ;
if ( ! GetQueuedKeyEvent ( & ev ) )
return 0 ;
2014-04-16 15:39:07 +00:00
2015-02-04 21:20:58 +00:00
# ifdef _MSC_VER
2016-09-04 12:16:34 +00:00
static char shiftDown = 0 ;
static char altDown = 0 ;
if ( miceEnabled & & ( ev . key = = VK_ESCAPE | | ( int ) ev . key = = - 2 ) & & ev . evt = = KEYPRESS ) {
// Disable mouse/KB hooks on escape (before going into paused mode).
// This is a hack, since PADclose (which is called on pause) should enevtually also deactivate the
// mouse/kb capture. In practice, WindowsMessagingMouse::Deactivate is called from PADclose, but doesn't
// manage to release the mouse, maybe due to the thread from which it's called or some
// state or somehow being too late.
// This explicitly triggers inactivity (releasing mouse/kb hooks) before PCSX2 starts to close the plugins.
// Regardless, the mouse/kb hooks will get re-enabled on resume if required without need for further hacks.
PrepareActivityState ( false ) ;
}
if ( ( ev . key = = VK_ESCAPE | | ( int ) ev . key = = - 2 ) & & ev . evt = = KEYPRESS & & config . escapeFullscreenHack ) {
static int t ;
if ( ( int ) ev . key ! = - 2 & & IsWindowMaximized ( hWndTop ) ) {
t = timeGetTime ( ) ;
QueueKeyEvent ( - 2 , KEYPRESS ) ;
HANDLE hThread = CreateThread ( 0 , 0 , MaximizeWindowThreadProc , 0 , 0 , 0 ) ;
if ( hThread )
CloseHandle ( hThread ) ;
restoreFullScreen = 1 ;
return 0 ;
}
if ( ev . key ! = VK_ESCAPE ) {
if ( timeGetTime ( ) - t < 1000 ) {
QueueKeyEvent ( - 2 , KEYPRESS ) ;
return 0 ;
}
}
ev . key = VK_ESCAPE ;
}
if ( ev . key = = VK_F2 & & ev . evt = = KEYPRESS ) {
saveStateIndex + = 1 - 2 * shiftDown ;
saveStateIndex = ( saveStateIndex + 10 ) % 10 ;
SaveStateChanged ( ) ;
}
// So don't change skip mode on alt-F4.
if ( ev . key = = VK_F4 & & altDown ) {
return 0 ;
}
if ( ev . key = = VK_LSHIFT | | ev . key = = VK_RSHIFT | | ev . key = = VK_SHIFT ) {
ev . key = VK_SHIFT ;
shiftDown = ( ev . evt = = KEYPRESS ) ;
} else if ( ev . key = = VK_LCONTROL | | ev . key = = VK_RCONTROL ) {
ev . key = VK_CONTROL ;
} else if ( ev . key = = VK_LMENU | | ev . key = = VK_RMENU | | ev . key = = VK_SHIFT ) {
ev . key = VK_MENU ;
altDown = ( ev . evt = = KEYPRESS ) ;
}
2015-02-04 21:20:58 +00:00
# endif
2016-09-04 12:16:34 +00:00
return & ev ;
2010-04-24 21:37:39 +00:00
}
2016-09-04 12:16:34 +00:00
struct PadPluginFreezeData
{
2011-11-07 09:29:36 +00:00
char format [ 8 ] ;
// Currently all different versions are incompatible.
// May split into major/minor with some compatibility rules.
u32 version ;
// So when loading, know which plugin's settings I'm loading.
// Not a big deal. Use a static variable when saving to figure it out.
u8 port ;
// active slot for port
u8 slot [ 2 ] ;
PadFreezeData padData [ 2 ] [ 4 ] ;
QueryInfo query ;
2010-04-24 21:37:39 +00:00
} ;
2016-09-04 12:16:34 +00:00
s32 CALLBACK PADfreeze ( int mode , freezeData * data )
{
if ( ! data ) {
printf ( " LilyPad savestate null pointer! \n " ) ;
return - 1 ;
2011-11-07 09:29:36 +00:00
}
2016-09-04 12:16:34 +00:00
if ( mode = = FREEZE_SIZE ) {
data - > size = sizeof ( PadPluginFreezeData ) ;
} else if ( mode = = FREEZE_LOAD ) {
PadPluginFreezeData & pdata = * ( PadPluginFreezeData * ) ( data - > data ) ;
2011-11-07 09:29:36 +00:00
StopVibrate ( ) ;
if ( data - > size ! = sizeof ( PadPluginFreezeData ) | |
pdata . version ! = PAD_SAVE_STATE_VERSION | |
2016-09-04 12:16:34 +00:00
strcmp ( pdata . format , " PadMode " ) )
return 0 ;
if ( pdata . port > = 2 )
return 0 ;
2011-11-07 09:29:36 +00:00
query = pdata . query ;
if ( pdata . query . slot < 4 ) {
query = pdata . query ;
}
// Tales of the Abyss - pad fix
// - restore data for both ports
2016-09-04 12:16:34 +00:00
for ( int port = 0 ; port < 2 ; port + + ) {
for ( int slot = 0 ; slot < 4 ; slot + + ) {
2011-11-07 09:29:36 +00:00
u8 mode = pdata . padData [ port ] [ slot ] . mode ;
2016-12-30 18:58:24 +00:00
if ( mode ! = MODE_DIGITAL & & mode ! = MODE_ANALOG & & mode ! = MODE_DS2_NATIVE & & mode ! = MODE_PS1_MOUSE & & mode ! = MODE_NEGCON ) {
2011-11-07 09:29:36 +00:00
break ;
}
// Not sure if the cast is strictly necessary, but feel safest with it there...
2016-09-04 12:16:34 +00:00
* ( PadFreezeData * ) & pads [ port ] [ slot ] = pdata . padData [ port ] [ slot ] ;
2011-11-07 09:29:36 +00:00
}
if ( pdata . slot [ port ] < 4 )
2016-09-04 12:16:34 +00:00
slots [ port ] = pdata . slot [ port ] ;
2011-11-07 09:29:36 +00:00
}
2016-09-04 12:16:34 +00:00
} else if ( mode = = FREEZE_SAVE ) {
if ( data - > size ! = sizeof ( PadPluginFreezeData ) )
return 0 ;
PadPluginFreezeData & pdata = * ( PadPluginFreezeData * ) ( data - > data ) ;
2011-11-07 09:29:36 +00:00
// Tales of the Abyss - pad fix
// - PCSX2 only saves port0 (save #1), then port1 (save #2)
memset ( & pdata , 0 , sizeof ( pdata ) ) ;
strcpy ( pdata . format , " PadMode " ) ;
pdata . version = PAD_SAVE_STATE_VERSION ;
pdata . port = 0 ;
pdata . query = query ;
2016-09-04 12:16:34 +00:00
for ( int port = 0 ; port < 2 ; port + + ) {
for ( int slot = 0 ; slot < 4 ; slot + + ) {
2011-11-07 09:29:36 +00:00
pdata . padData [ port ] [ slot ] = pads [ port ] [ slot ] ;
}
pdata . slot [ port ] = slots [ port ] ;
}
2016-09-04 12:16:34 +00:00
} else
return - 1 ;
2011-11-07 09:29:36 +00:00
return 0 ;
}
2010-04-24 21:37:39 +00:00
2016-09-04 12:16:34 +00:00
u32 CALLBACK PADreadPort1 ( PadDataS * pads )
{
PADstartPoll ( 1 ) ;
PADpoll ( 0x42 ) ;
memcpy ( pads , query . response + 1 , 7 ) ;
pads - > controllerType = pads [ 0 ] . controllerType > > 4 ;
memset ( pads + 7 , 0 , sizeof ( PadDataS ) - 7 ) ;
return 0 ;
2010-04-24 21:37:39 +00:00
}
2016-09-04 12:16:34 +00:00
u32 CALLBACK PADreadPort2 ( PadDataS * pads )
{
PADstartPoll ( 2 ) ;
PADpoll ( 0x42 ) ;
memcpy ( pads , query . response + 1 , 7 ) ;
pads - > controllerType = pads - > controllerType > > 4 ;
memset ( pads + 7 , 0 , sizeof ( PadDataS ) - 7 ) ;
return 0 ;
2010-04-24 21:37:39 +00:00
}
2016-09-04 12:16:34 +00:00
u32 CALLBACK PSEgetLibType ( )
{
return 8 ;
2010-04-24 21:37:39 +00:00
}
2016-09-04 12:16:34 +00:00
u32 CALLBACK PSEgetLibVersion ( )
{
return ( VERSION & 0xFFFFFF ) ;
2010-04-24 21:37:39 +00:00
}
2016-09-04 12:16:34 +00:00
s32 CALLBACK PADqueryMtap ( u8 port )
{
port - - ;
if ( port > 1 )
return 0 ;
return config . multitap [ port ] ;
2010-04-24 21:37:39 +00:00
}
2016-09-04 12:16:34 +00:00
s32 CALLBACK PADsetSlot ( u8 port , u8 slot )
{
port - - ;
slot - - ;
if ( port > 1 | | slot > 3 ) {
return 0 ;
}
// Even if no pad there, record the slot, as it is the active slot regardless.
slots [ port ] = slot ;
// First slot always allowed.
// return pads[port][slot].enabled | !slot;
return 1 ;
2010-04-24 21:37:39 +00:00
}