WIP games are booting in Qt now

This commit is contained in:
987123879113 2022-07-19 23:11:01 +09:00
parent 1e01001af4
commit 084628acc2
90 changed files with 3883 additions and 8032 deletions

View File

@ -50,25 +50,25 @@ jobs:
detail: " nopch"
secrets: inherit
# build_linux_qt_sse4:
# name: "AppImage"
# uses: ./.github/workflows/linux_build_qt.yml
# with:
# jobName: "Qt SSE4"
# compiler: clang
# cmakeflags: ""
# simd: "SSE4"
# buildAppImage: true
# secrets: inherit
build_linux_qt_sse4:
name: "AppImage"
uses: ./.github/workflows/linux_build_qt.yml
with:
jobName: "Qt SSE4"
compiler: clang
cmakeflags: ""
simd: "SSE4"
buildAppImage: true
secrets: inherit
# build_linux_qt_avx2:
# name: "AppImage"
# uses: ./.github/workflows/linux_build_qt.yml
# with:
# jobName: "Qt AVX2"
# detail: ""
# compiler: clang
# cmakeflags: "-DARCH_FLAG=-march=haswell"
# simd: "AVX2"
# buildAppImage: true
# secrets: inherit
build_linux_qt_avx2:
name: "AppImage"
uses: ./.github/workflows/linux_build_qt.yml
with:
jobName: "Qt AVX2"
detail: ""
compiler: clang
cmakeflags: "-DARCH_FLAG=-march=haswell"
simd: "AVX2"
buildAppImage: true
secrets: inherit

View File

@ -8,18 +8,18 @@ on:
branches:
- master
# jobs:
# build_macos_wx:
# name: "Defaults"
# uses: ./.github/workflows/macos_build.yml
# with:
# jobName: "wxWidgets"
# gui: "wxWidgets"
# secrets: inherit
# build_macos_qt:
# name: "Defaults"
# uses: ./.github/workflows/macos_build.yml
# with:
# jobName: "Qt"
# gui: "Qt"
# secrets: inherit
jobs:
# build_macos_wx:
# name: "Defaults"
# uses: ./.github/workflows/macos_build.yml
# with:
# jobName: "wxWidgets"
# gui: "wxWidgets"
# secrets: inherit
build_macos_qt:
name: "Defaults"
uses: ./.github/workflows/macos_build.yml
with:
jobName: "Qt"
gui: "Qt"
secrets: inherit

View File

@ -49,6 +49,7 @@ declare -a PCSX2_PACKAGES=(
"libsamplerate0-dev"
"libsoundtouch-dev"
"libudev-dev"
"libusb-1.0-0-dev"
"libx11-xcb-dev"
"pkg-config"
"zlib1g-dev"

View File

@ -26,8 +26,8 @@ declare -a PCSX2_PACKAGES=(
"librsvg2-dev"
"libsamplerate0-dev"
"libsoundtouch-dev"
"libusb-1.0-0-dev"
"libudev-dev"
"libusb-1.0-0-dev"
"libwxgtk3.0-gtk3-dev"
"libx11-xcb-dev"
"pkg-config"

View File

@ -15,6 +15,7 @@ JPG=9e
SAMPLERATE=libsamplerate-0.1.9
PORTAUDIO=pa_stable_v190700_20210406
SOUNDTOUCH=soundtouch-2.3.1
LIBUSB=1.0.26
WXWIDGETS=3.1.6
QT=6.3.1
@ -38,6 +39,7 @@ fe7cbf3127882e3fc7259a75a0cb585620272c51745d3852ab9dd87960697f2e $SDL.tar.gz
7b19f418e6f7b8e23344082dd04440aacf5da23c5a73980ba22ae4eba4f87df7 qtsvg-everywhere-src-$QT.tar.xz
c412750f2aa3beb93fce5f30517c607f55daaeb7d0407af206a8adf917e126c1 qttools-everywhere-src-$QT.tar.xz
d7bdd55e2908ded901dcc262157100af2a490bf04d31e32995f6d91d78dfdb97 qttranslations-everywhere-src-$QT.tar.xz
12ce7a61fc9854d1d2a1ffe095f7b5fac19ddba095c259e6067a46500381b5a5 libusb-$LIBUSB.tar.bz2
EOF
curl -L \
@ -52,6 +54,7 @@ curl -L \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtsvg-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qttools-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qttranslations-everywhere-src-$QT.tar.xz" \
-O "https://github.com/libusb/libusb/releases/download/v$LIBUSB/libusb-$LIBUSB.tar.bz2" \
shasum -a 256 --check SHASUMS
@ -104,6 +107,14 @@ make -C build "-j$NPROCS"
make -C build install
cd ..
echo "Installing libusb..."
tar xf "libusb-$LIBUSB.tar.bz2"
cd "libusb-$LIBUSB"
./configure --prefix "$INSTALLDIR" --enable-mac-universal=no
make "-j$NPROCS"
make install
cd ..
if [ "$GUI" == "wxWidgets" ]; then
echo "Installing wx..."
tar xf "wxWidgets-$WXWIDGETS.tar.bz2"

View File

@ -38,24 +38,24 @@ jobs:
configuration: Release AVX2
secrets: inherit
# build_qt_sse4:
# needs: lint_vs_proj_files
# name: "SSE4"
# uses: ./.github/workflows/windows_build_qt.yml
# with:
# jobName: Qt
# configuration: Release
# simd: "SSE4"
# secrets: inherit
build_qt_sse4:
needs: lint_vs_proj_files
name: "SSE4"
uses: ./.github/workflows/windows_build_qt.yml
with:
jobName: Qt
configuration: Release
simd: "SSE4"
secrets: inherit
# build_qt_avx2:
# needs: lint_vs_proj_files
# name: "AVX2"
# uses: ./.github/workflows/windows_build_qt.yml
# with:
# jobName: Qt
# configuration: Release AVX2
# secrets: inherit
build_qt_avx2:
needs: lint_vs_proj_files
name: "AVX2"
uses: ./.github/workflows/windows_build_qt.yml
with:
jobName: Qt
configuration: Release AVX2
secrets: inherit
# CMAKE
# build_wx_avx2_cmake:

3
.gitmodules vendored
View File

@ -39,3 +39,6 @@
[submodule "3rdparty/zstd/zstd"]
path = 3rdparty/zstd/zstd
url = https://github.com/facebook/zstd.git
[submodule "3rdparty/libusb/libusb"]
path = 3rdparty/libusb/libusb
url = https://github.com/libusb/libusb.git

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,61 +0,0 @@
libusb 1.0 Windows binary snapshot - README
*********************************************************************
* The latest version of this snapshot can always be downloaded at: *
* https://sourceforge.net/projects/libusb/files/ *
*********************************************************************
o Visual Studio:
- Open existing or create a new project for your application
- Copy libusb.h, from the include\libusb-1.0\ directory, into your project and
make sure that the location where the file reside appears in the 'Additional
Include Directories' section (Configuration Properties -> C/C++ -> General).
- Copy the relevant .lib file from MS32\ or MS64\ and add 'libusb-1.0.lib' to
your 'Additional Dependencies' (Configuration Properties -> Linker -> Input)
Also make sure that the directory where libusb-1.0.lib resides is added to
'Additional Library Directories' (Configuration Properties -> Linker
-> General)
- If you use the static version of the libusb library, make sure that
'Runtime Library' is set to 'Multi-threaded DLL (/MD)' (Configuration
Properties -> C/C++ -> Code Generation).
NB: If your application requires /MT (Multi-threaded/libCMT), you need to
recompile a static libusb 1.0 library from source.
- Compile and run your application. If you use the DLL version of libusb-1.0,
remember that you need to have a copy of the DLL either in the runtime
directory or in system32
o WDK/DDK:
- The following is an example of a sources files that you can use to compile
a libusb 1.0 based console application. In this sample ..\libusb\ is the
directory where you would have copied libusb.h as well as the relevant
libusb-1.0.lib
TARGETNAME=your_app
TARGETTYPE=PROGRAM
USE_MSVCRT=1
UMTYPE=console
INCLUDES=..\libusb;$(DDK_INC_PATH)
TARGETLIBS=..\libusb\libusb-1.0.lib
SOURCES=your_app.c
- Note that if you plan to use libCMT instead of MSVCRT (USE_LIBCMT=1 instead
of USE_MSVCRT=1), you will need to recompile libusb to use libCMT. This can
easily be achieved, in the DDK environment, by running 'ddk_build /MT'
o MinGW/cygwin
- Copy libusb.h, from include/libusb-1.0/ to your default include directory,
and copy the MinGW32/ or MinGW64/ .a files to your default library directory.
Or, if you don't want to use the default locations, make sure that you feed
the relevant -I and -L options to the compiler.
- Add the '-lusb-1.0' linker option when compiling.
o Additional information:
- The libusb 1.0 API documentation can be accessed at:
http://api.libusb.info
- For some libusb samples (including source), please have a look in examples/
- For additional information on the libusb 1.0 Windows backend please visit:
http://windows.libusb.info
- The MinGW and MS generated DLLs are fully interchangeable, provided that you
use the import libs provided or generate one from the .def also provided.
- If you find any issue, please visit http://libusb.info/ and check the
Support section

View File

@ -1,831 +0,0 @@
/*
* Copyright © 2001 Stephen Williams (steve@icarus.com)
* Copyright © 2001-2002 David Brownell (dbrownell@users.sourceforge.net)
* Copyright © 2008 Roger Williams (rawqux@users.sourceforge.net)
* Copyright © 2012 Pete Batard (pete@akeo.ie)
* Copyright © 2013 Federico Manzan (f.manzan@gmail.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "libusb.h"
#include "ezusb.h"
extern void logerror(const char *format, ...)
__attribute__ ((format(printf, 1, 2)));
/*
* This file contains functions for uploading firmware into Cypress
* EZ-USB microcontrollers. These chips use control endpoint 0 and vendor
* specific commands to support writing into the on-chip SRAM. They also
* support writing into the CPUCS register, which is how we reset the
* processor after loading firmware (including the reset vector).
*
* These Cypress devices are 8-bit 8051 based microcontrollers with
* special support for USB I/O. They come in several packages, and
* some can be set up with external memory when device costs allow.
* Note that the design was originally by AnchorChips, so you may find
* references to that vendor (which was later merged into Cypress).
* The Cypress FX parts are largely compatible with the Anchorhip ones.
*/
int verbose = 1;
/*
* return true if [addr,addr+len] includes external RAM
* for Anchorchips EZ-USB or Cypress EZ-USB FX
*/
static bool fx_is_external(uint32_t addr, size_t len)
{
/* with 8KB RAM, 0x0000-0x1b3f can be written
* we can't tell if it's a 4KB device here
*/
if (addr <= 0x1b3f)
return ((addr + len) > 0x1b40);
/* there may be more RAM; unclear if we can write it.
* some bulk buffers may be unused, 0x1b3f-0x1f3f
* firmware can set ISODISAB for 2KB at 0x2000-0x27ff
*/
return true;
}
/*
* return true if [addr,addr+len] includes external RAM
* for Cypress EZ-USB FX2
*/
static bool fx2_is_external(uint32_t addr, size_t len)
{
/* 1st 8KB for data/code, 0x0000-0x1fff */
if (addr <= 0x1fff)
return ((addr + len) > 0x2000);
/* and 512 for data, 0xe000-0xe1ff */
else if (addr >= 0xe000 && addr <= 0xe1ff)
return ((addr + len) > 0xe200);
/* otherwise, it's certainly external */
else
return true;
}
/*
* return true if [addr,addr+len] includes external RAM
* for Cypress EZ-USB FX2LP
*/
static bool fx2lp_is_external(uint32_t addr, size_t len)
{
/* 1st 16KB for data/code, 0x0000-0x3fff */
if (addr <= 0x3fff)
return ((addr + len) > 0x4000);
/* and 512 for data, 0xe000-0xe1ff */
else if (addr >= 0xe000 && addr <= 0xe1ff)
return ((addr + len) > 0xe200);
/* otherwise, it's certainly external */
else
return true;
}
/*****************************************************************************/
/*
* These are the requests (bRequest) that the bootstrap loader is expected
* to recognize. The codes are reserved by Cypress, and these values match
* what EZ-USB hardware, or "Vend_Ax" firmware (2nd stage loader) uses.
* Cypress' "a3load" is nice because it supports both FX and FX2, although
* it doesn't have the EEPROM support (subset of "Vend_Ax").
*/
#define RW_INTERNAL 0xA0 /* hardware implements this one */
#define RW_MEMORY 0xA3
/*
* Issues the specified vendor-specific write request.
*/
static int ezusb_write(libusb_device_handle *device, const char *label,
uint8_t opcode, uint32_t addr, const unsigned char *data, size_t len)
{
int status;
if (verbose > 1)
logerror("%s, addr 0x%08x len %4u (0x%04x)\n", label, addr, (unsigned)len, (unsigned)len);
status = libusb_control_transfer(device,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
opcode, addr & 0xFFFF, addr >> 16,
(unsigned char*)data, (uint16_t)len, 1000);
if (status != (signed)len) {
if (status < 0)
logerror("%s: %s\n", label, libusb_error_name(status));
else
logerror("%s ==> %d\n", label, status);
}
return (status < 0) ? -EIO : 0;
}
/*
* Issues the specified vendor-specific read request.
*/
static int ezusb_read(libusb_device_handle *device, const char *label,
uint8_t opcode, uint32_t addr, const unsigned char *data, size_t len)
{
int status;
if (verbose > 1)
logerror("%s, addr 0x%08x len %4u (0x%04x)\n", label, addr, (unsigned)len, (unsigned)len);
status = libusb_control_transfer(device,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
opcode, addr & 0xFFFF, addr >> 16,
(unsigned char*)data, (uint16_t)len, 1000);
if (status != (signed)len) {
if (status < 0)
logerror("%s: %s\n", label, libusb_error_name(status));
else
logerror("%s ==> %d\n", label, status);
}
return (status < 0) ? -EIO : 0;
}
/*
* Modifies the CPUCS register to stop or reset the CPU.
* Returns false on error.
*/
static bool ezusb_cpucs(libusb_device_handle *device, uint32_t addr, bool doRun)
{
int status;
uint8_t data = doRun ? 0x00 : 0x01;
if (verbose)
logerror("%s\n", data ? "stop CPU" : "reset CPU");
status = libusb_control_transfer(device,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
RW_INTERNAL, addr & 0xFFFF, addr >> 16,
&data, 1, 1000);
if ((status != 1) &&
/* We may get an I/O error from libusb as the device disappears */
((!doRun) || (status != LIBUSB_ERROR_IO)))
{
const char *mesg = "can't modify CPUCS";
if (status < 0)
logerror("%s: %s\n", mesg, libusb_error_name(status));
else
logerror("%s\n", mesg);
return false;
} else
return true;
}
/*
* Send an FX3 jumpt to address command
* Returns false on error.
*/
static bool ezusb_fx3_jump(libusb_device_handle *device, uint32_t addr)
{
int status;
if (verbose)
logerror("transfer execution to Program Entry at 0x%08x\n", addr);
status = libusb_control_transfer(device,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
RW_INTERNAL, addr & 0xFFFF, addr >> 16,
NULL, 0, 1000);
/* We may get an I/O error from libusb as the device disappears */
if ((status != 0) && (status != LIBUSB_ERROR_IO))
{
const char *mesg = "failed to send jump command";
if (status < 0)
logerror("%s: %s\n", mesg, libusb_error_name(status));
else
logerror("%s\n", mesg);
return false;
} else
return true;
}
/*****************************************************************************/
/*
* Parse an Intel HEX image file and invoke the poke() function on the
* various segments to implement policies such as writing to RAM (with
* a one or two stage loader setup, depending on the firmware) or to
* EEPROM (two stages required).
*
* image - the hex image file
* context - for use by poke()
* is_external - if non-null, used to check which segments go into
* external memory (writable only by software loader)
* poke - called with each memory segment; errors indicated
* by returning negative values.
*
* Caller is responsible for halting CPU as needed, such as when
* overwriting a second stage loader.
*/
static int parse_ihex(FILE *image, void *context,
bool (*is_external)(uint32_t addr, size_t len),
int (*poke) (void *context, uint32_t addr, bool external,
const unsigned char *data, size_t len))
{
unsigned char data[1023];
uint32_t data_addr = 0;
size_t data_len = 0;
int rc;
int first_line = 1;
bool external = false;
/* Read the input file as an IHEX file, and report the memory segments
* as we go. Each line holds a max of 16 bytes, but uploading is
* faster (and EEPROM space smaller) if we merge those lines into larger
* chunks. Most hex files keep memory segments together, which makes
* such merging all but free. (But it may still be worth sorting the
* hex files to make up for undesirable behavior from tools.)
*
* Note that EEPROM segments max out at 1023 bytes; the upload protocol
* allows segments of up to 64 KBytes (more than a loader could handle).
*/
for (;;) {
char buf[512], *cp;
char tmp, type;
size_t len;
unsigned idx, off;
cp = fgets(buf, sizeof(buf), image);
if (cp == NULL) {
logerror("EOF without EOF record!\n");
break;
}
/* EXTENSION: "# comment-till-end-of-line", for copyrights etc */
if (buf[0] == '#')
continue;
if (buf[0] != ':') {
logerror("not an ihex record: %s", buf);
return -2;
}
/* ignore any newline */
cp = strchr(buf, '\n');
if (cp)
*cp = 0;
if (verbose >= 3)
logerror("** LINE: %s\n", buf);
/* Read the length field (up to 16 bytes) */
tmp = buf[3];
buf[3] = 0;
len = strtoul(buf+1, NULL, 16);
buf[3] = tmp;
/* Read the target offset (address up to 64KB) */
tmp = buf[7];
buf[7] = 0;
off = (unsigned int)strtoul(buf+3, NULL, 16);
buf[7] = tmp;
/* Initialize data_addr */
if (first_line) {
data_addr = off;
first_line = 0;
}
/* Read the record type */
tmp = buf[9];
buf[9] = 0;
type = (char)strtoul(buf+7, NULL, 16);
buf[9] = tmp;
/* If this is an EOF record, then make it so. */
if (type == 1) {
if (verbose >= 2)
logerror("EOF on hexfile\n");
break;
}
if (type != 0) {
logerror("unsupported record type: %u\n", type);
return -3;
}
if ((len * 2) + 11 > strlen(buf)) {
logerror("record too short?\n");
return -4;
}
/* FIXME check for _physically_ contiguous not just virtually
* e.g. on FX2 0x1f00-0x2100 includes both on-chip and external
* memory so it's not really contiguous */
/* flush the saved data if it's not contiguous,
* or when we've buffered as much as we can.
*/
if (data_len != 0
&& (off != (data_addr + data_len)
/* || !merge */
|| (data_len + len) > sizeof(data))) {
if (is_external)
external = is_external(data_addr, data_len);
rc = poke(context, data_addr, external, data, data_len);
if (rc < 0)
return -1;
data_addr = off;
data_len = 0;
}
/* append to saved data, flush later */
for (idx = 0, cp = buf+9 ; idx < len ; idx += 1, cp += 2) {
tmp = cp[2];
cp[2] = 0;
data[data_len + idx] = (uint8_t)strtoul(cp, NULL, 16);
cp[2] = tmp;
}
data_len += len;
}
/* flush any data remaining */
if (data_len != 0) {
if (is_external)
external = is_external(data_addr, data_len);
rc = poke(context, data_addr, external, data, data_len);
if (rc < 0)
return -1;
}
return 0;
}
/*
* Parse a binary image file and write it as is to the target.
* Applies to Cypress BIX images for RAM or Cypress IIC images
* for EEPROM.
*
* image - the BIX image file
* context - for use by poke()
* is_external - if non-null, used to check which segments go into
* external memory (writable only by software loader)
* poke - called with each memory segment; errors indicated
* by returning negative values.
*
* Caller is responsible for halting CPU as needed, such as when
* overwriting a second stage loader.
*/
static int parse_bin(FILE *image, void *context,
bool (*is_external)(uint32_t addr, size_t len), int (*poke)(void *context,
uint32_t addr, bool external, const unsigned char *data, size_t len))
{
unsigned char data[4096];
uint32_t data_addr = 0;
size_t data_len = 0;
int rc;
bool external = false;
for (;;) {
data_len = fread(data, 1, 4096, image);
if (data_len == 0)
break;
if (is_external)
external = is_external(data_addr, data_len);
rc = poke(context, data_addr, external, data, data_len);
if (rc < 0)
return -1;
data_addr += (uint32_t)data_len;
}
return feof(image)?0:-1;
}
/*
* Parse a Cypress IIC image file and invoke the poke() function on the
* various segments for writing to RAM
*
* image - the IIC image file
* context - for use by poke()
* is_external - if non-null, used to check which segments go into
* external memory (writable only by software loader)
* poke - called with each memory segment; errors indicated
* by returning negative values.
*
* Caller is responsible for halting CPU as needed, such as when
* overwriting a second stage loader.
*/
static int parse_iic(FILE *image, void *context,
bool (*is_external)(uint32_t addr, size_t len),
int (*poke)(void *context, uint32_t addr, bool external, const unsigned char *data, size_t len))
{
unsigned char data[4096];
uint32_t data_addr = 0;
size_t data_len = 0, read_len;
uint8_t block_header[4];
int rc;
bool external = false;
long file_size, initial_pos;
initial_pos = ftell(image);
if (initial_pos < 0)
return -1;
if (fseek(image, 0L, SEEK_END) != 0)
return -1;
file_size = ftell(image);
if (fseek(image, initial_pos, SEEK_SET) != 0)
return -1;
for (;;) {
/* Ignore the trailing reset IIC data (5 bytes) */
if (ftell(image) >= (file_size - 5))
break;
if (fread(&block_header, 1, sizeof(block_header), image) != 4) {
logerror("unable to read IIC block header\n");
return -1;
}
data_len = (block_header[0] << 8) + block_header[1];
data_addr = (block_header[2] << 8) + block_header[3];
if (data_len > sizeof(data)) {
/* If this is ever reported as an error, switch to using malloc/realloc */
logerror("IIC data block too small - please report this error to libusb.info\n");
return -1;
}
read_len = fread(data, 1, data_len, image);
if (read_len != data_len) {
logerror("read error\n");
return -1;
}
if (is_external)
external = is_external(data_addr, data_len);
rc = poke(context, data_addr, external, data, data_len);
if (rc < 0)
return -1;
}
return 0;
}
/* the parse call will be selected according to the image type */
static int (*parse[IMG_TYPE_MAX])(FILE *image, void *context, bool (*is_external)(uint32_t addr, size_t len),
int (*poke)(void *context, uint32_t addr, bool external, const unsigned char *data, size_t len))
= { parse_ihex, parse_iic, parse_bin };
/*****************************************************************************/
/*
* For writing to RAM using a first (hardware) or second (software)
* stage loader and 0xA0 or 0xA3 vendor requests
*/
typedef enum {
_undef = 0,
internal_only, /* hardware first-stage loader */
skip_internal, /* first phase, second-stage loader */
skip_external /* second phase, second-stage loader */
} ram_mode;
struct ram_poke_context {
libusb_device_handle *device;
ram_mode mode;
size_t total, count;
};
#define RETRY_LIMIT 5
static int ram_poke(void *context, uint32_t addr, bool external,
const unsigned char *data, size_t len)
{
struct ram_poke_context *ctx = (struct ram_poke_context*)context;
int rc;
unsigned retry = 0;
switch (ctx->mode) {
case internal_only: /* CPU should be stopped */
if (external) {
logerror("can't write %u bytes external memory at 0x%08x\n",
(unsigned)len, addr);
return -EINVAL;
}
break;
case skip_internal: /* CPU must be running */
if (!external) {
if (verbose >= 2) {
logerror("SKIP on-chip RAM, %u bytes at 0x%08x\n",
(unsigned)len, addr);
}
return 0;
}
break;
case skip_external: /* CPU should be stopped */
if (external) {
if (verbose >= 2) {
logerror("SKIP external RAM, %u bytes at 0x%08x\n",
(unsigned)len, addr);
}
return 0;
}
break;
case _undef:
default:
logerror("bug\n");
return -EDOM;
}
ctx->total += len;
ctx->count++;
/* Retry this till we get a real error. Control messages are not
* NAKed (just dropped) so time out means is a real problem.
*/
while ((rc = ezusb_write(ctx->device,
external ? "write external" : "write on-chip",
external ? RW_MEMORY : RW_INTERNAL,
addr, data, len)) < 0
&& retry < RETRY_LIMIT) {
if (rc != LIBUSB_ERROR_TIMEOUT)
break;
retry += 1;
}
return rc;
}
/*
* Load a Cypress Image file into target RAM.
* See http://www.cypress.com/?docID=41351 (AN76405 PDF) for more info.
*/
static int fx3_load_ram(libusb_device_handle *device, const char *path)
{
uint32_t dCheckSum, dExpectedCheckSum, dAddress, i, dLen, dLength;
uint32_t* dImageBuf;
unsigned char *bBuf, hBuf[4], blBuf[4], rBuf[4096];
FILE *image;
int ret = 0;
image = fopen(path, "rb");
if (image == NULL) {
logerror("unable to open '%s' for input\n", path);
return -2;
} else if (verbose)
logerror("open firmware image %s for RAM upload\n", path);
// Read header
if (fread(hBuf, sizeof(char), sizeof(hBuf), image) != sizeof(hBuf)) {
logerror("could not read image header");
ret = -3;
goto exit;
}
// check "CY" signature byte and format
if ((hBuf[0] != 'C') || (hBuf[1] != 'Y')) {
logerror("image doesn't have a CYpress signature\n");
ret = -3;
goto exit;
}
// Check bImageType
switch(hBuf[3]) {
case 0xB0:
if (verbose)
logerror("normal FW binary %s image with checksum\n", (hBuf[2]&0x01)?"data":"executable");
break;
case 0xB1:
logerror("security binary image is not currently supported\n");
ret = -3;
goto exit;
case 0xB2:
logerror("VID:PID image is not currently supported\n");
ret = -3;
goto exit;
default:
logerror("invalid image type 0x%02X\n", hBuf[3]);
ret = -3;
goto exit;
}
// Read the bootloader version
if (verbose) {
if ((ezusb_read(device, "read bootloader version", RW_INTERNAL, 0xFFFF0020, blBuf, 4) < 0)) {
logerror("Could not read bootloader version\n");
ret = -8;
goto exit;
}
logerror("FX3 bootloader version: 0x%02X%02X%02X%02X\n", blBuf[3], blBuf[2], blBuf[1], blBuf[0]);
}
dCheckSum = 0;
if (verbose)
logerror("writing image...\n");
while (1) {
if ((fread(&dLength, sizeof(uint32_t), 1, image) != 1) || // read dLength
(fread(&dAddress, sizeof(uint32_t), 1, image) != 1)) { // read dAddress
logerror("could not read image");
ret = -3;
goto exit;
}
if (dLength == 0)
break; // done
// coverity[tainted_data]
dImageBuf = (uint32_t*)calloc(dLength, sizeof(uint32_t));
if (dImageBuf == NULL) {
logerror("could not allocate buffer for image chunk\n");
ret = -4;
goto exit;
}
// read sections
if (fread(dImageBuf, sizeof(uint32_t), dLength, image) != dLength) {
logerror("could not read image");
free(dImageBuf);
ret = -3;
goto exit;
}
for (i = 0; i < dLength; i++)
dCheckSum += dImageBuf[i];
dLength <<= 2; // convert to Byte length
bBuf = (unsigned char*) dImageBuf;
while (dLength > 0) {
dLen = 4096; // 4K max
if (dLen > dLength)
dLen = dLength;
if ((ezusb_write(device, "write firmware", RW_INTERNAL, dAddress, bBuf, dLen) < 0) ||
(ezusb_read(device, "read firmware", RW_INTERNAL, dAddress, rBuf, dLen) < 0)) {
logerror("R/W error\n");
free(dImageBuf);
ret = -5;
goto exit;
}
// Verify data: rBuf with bBuf
for (i = 0; i < dLen; i++) {
if (rBuf[i] != bBuf[i]) {
logerror("verify error");
free(dImageBuf);
ret = -6;
goto exit;
}
}
dLength -= dLen;
bBuf += dLen;
dAddress += dLen;
}
free(dImageBuf);
}
// read pre-computed checksum data
if ((fread(&dExpectedCheckSum, sizeof(uint32_t), 1, image) != 1) ||
(dCheckSum != dExpectedCheckSum)) {
logerror("checksum error\n");
ret = -7;
goto exit;
}
// transfer execution to Program Entry
if (!ezusb_fx3_jump(device, dAddress)) {
ret = -6;
}
exit:
fclose(image);
return ret;
}
/*
* Load a firmware file into target RAM. device is the open libusb
* device, and the path is the name of the source file. Open the file,
* parse the bytes, and write them in one or two phases.
*
* If stage == 0, this uses the first stage loader, built into EZ-USB
* hardware but limited to writing on-chip memory or CPUCS. Everything
* is written during one stage, unless there's an error such as the image
* holding data that needs to be written to external memory.
*
* Otherwise, things are written in two stages. First the external
* memory is written, expecting a second stage loader to have already
* been loaded. Then file is re-parsed and on-chip memory is written.
*/
int ezusb_load_ram(libusb_device_handle *device, const char *path, int fx_type, int img_type, int stage)
{
FILE *image;
uint32_t cpucs_addr;
bool (*is_external)(uint32_t off, size_t len);
struct ram_poke_context ctx;
int status;
uint8_t iic_header[8] = { 0 };
int ret = 0;
if (fx_type == FX_TYPE_FX3)
return fx3_load_ram(device, path);
image = fopen(path, "rb");
if (image == NULL) {
logerror("%s: unable to open for input.\n", path);
return -2;
} else if (verbose > 1)
logerror("open firmware image %s for RAM upload\n", path);
if (img_type == IMG_TYPE_IIC) {
if ( (fread(iic_header, 1, sizeof(iic_header), image) != sizeof(iic_header))
|| (((fx_type == FX_TYPE_FX2LP) || (fx_type == FX_TYPE_FX2)) && (iic_header[0] != 0xC2))
|| ((fx_type == FX_TYPE_AN21) && (iic_header[0] != 0xB2))
|| ((fx_type == FX_TYPE_FX1) && (iic_header[0] != 0xB6)) ) {
logerror("IIC image does not contain executable code - cannot load to RAM.\n");
ret = -1;
goto exit;
}
}
/* EZ-USB original/FX and FX2 devices differ, apart from the 8051 core */
switch(fx_type) {
case FX_TYPE_FX2LP:
cpucs_addr = 0xe600;
is_external = fx2lp_is_external;
break;
case FX_TYPE_FX2:
cpucs_addr = 0xe600;
is_external = fx2_is_external;
break;
default:
cpucs_addr = 0x7f92;
is_external = fx_is_external;
break;
}
/* use only first stage loader? */
if (stage == 0) {
ctx.mode = internal_only;
/* if required, halt the CPU while we overwrite its code/data */
if (cpucs_addr && !ezusb_cpucs(device, cpucs_addr, false))
{
ret = -1;
goto exit;
}
/* 2nd stage, first part? loader was already uploaded */
} else {
ctx.mode = skip_internal;
/* let CPU run; overwrite the 2nd stage loader later */
if (verbose)
logerror("2nd stage: write external memory\n");
}
/* scan the image, first (maybe only) time */
ctx.device = device;
ctx.total = ctx.count = 0;
status = parse[img_type](image, &ctx, is_external, ram_poke);
if (status < 0) {
logerror("unable to upload %s\n", path);
ret = status;
goto exit;
}
/* second part of 2nd stage: rescan */
// TODO: what should we do for non HEX images there?
if (stage) {
ctx.mode = skip_external;
/* if needed, halt the CPU while we overwrite the 1st stage loader */
if (cpucs_addr && !ezusb_cpucs(device, cpucs_addr, false))
{
ret = -1;
goto exit;
}
/* at least write the interrupt vectors (at 0x0000) for reset! */
rewind(image);
if (verbose)
logerror("2nd stage: write on-chip memory\n");
status = parse_ihex(image, &ctx, is_external, ram_poke);
if (status < 0) {
logerror("unable to completely upload %s\n", path);
ret = status;
goto exit;
}
}
if (verbose && (ctx.count != 0)) {
logerror("... WROTE: %d bytes, %d segments, avg %d\n",
(int)ctx.total, (int)ctx.count, (int)(ctx.total/ctx.count));
}
/* if required, reset the CPU so it runs what we just uploaded */
if (cpucs_addr && !ezusb_cpucs(device, cpucs_addr, true))
ret = -1;
exit:
fclose(image);
return ret;
}

View File

@ -1,120 +0,0 @@
#ifndef ezusb_H
#define ezusb_H
/*
* Copyright © 2001 Stephen Williams (steve@icarus.com)
* Copyright © 2002 David Brownell (dbrownell@users.sourceforge.net)
* Copyright © 2013 Federico Manzan (f.manzan@gmail.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(_MSC_VER)
#include <stdbool.h>
#else
#define __attribute__(x)
#if !defined(bool)
#define bool int
#endif
#if !defined(true)
#define true (1 == 1)
#endif
#if !defined(false)
#define false (!true)
#endif
#if defined(_PREFAST_)
#pragma warning(disable:28193)
#endif
#endif
#define FX_TYPE_UNDEFINED -1
#define FX_TYPE_AN21 0 /* Original AnchorChips parts */
#define FX_TYPE_FX1 1 /* Updated Cypress versions */
#define FX_TYPE_FX2 2 /* USB 2.0 versions */
#define FX_TYPE_FX2LP 3 /* Updated FX2 */
#define FX_TYPE_FX3 4 /* USB 3.0 versions */
#define FX_TYPE_MAX 5
#define FX_TYPE_NAMES { "an21", "fx", "fx2", "fx2lp", "fx3" }
#define IMG_TYPE_UNDEFINED -1
#define IMG_TYPE_HEX 0 /* Intel HEX */
#define IMG_TYPE_IIC 1 /* Cypress 8051 IIC */
#define IMG_TYPE_BIX 2 /* Cypress 8051 BIX */
#define IMG_TYPE_IMG 3 /* Cypress IMG format */
#define IMG_TYPE_MAX 4
#define IMG_TYPE_NAMES { "Intel HEX", "Cypress 8051 IIC", "Cypress 8051 BIX", "Cypress IMG format" }
#ifdef __cplusplus
extern "C" {
#endif
/*
* Automatically identified devices (VID, PID, type, designation).
* TODO: Could use some validation. Also where's the FX2?
*/
typedef struct {
uint16_t vid;
uint16_t pid;
int type;
const char* designation;
} fx_known_device;
#define FX_KNOWN_DEVICES { \
{ 0x0547, 0x2122, FX_TYPE_AN21, "Cypress EZ-USB (2122S)" },\
{ 0x0547, 0x2125, FX_TYPE_AN21, "Cypress EZ-USB (2121S/2125S)" },\
{ 0x0547, 0x2126, FX_TYPE_AN21, "Cypress EZ-USB (2126S)" },\
{ 0x0547, 0x2131, FX_TYPE_AN21, "Cypress EZ-USB (2131Q/2131S/2135S)" },\
{ 0x0547, 0x2136, FX_TYPE_AN21, "Cypress EZ-USB (2136S)" },\
{ 0x0547, 0x2225, FX_TYPE_AN21, "Cypress EZ-USB (2225)" },\
{ 0x0547, 0x2226, FX_TYPE_AN21, "Cypress EZ-USB (2226)" },\
{ 0x0547, 0x2235, FX_TYPE_AN21, "Cypress EZ-USB (2235)" },\
{ 0x0547, 0x2236, FX_TYPE_AN21, "Cypress EZ-USB (2236)" },\
{ 0x04b4, 0x6473, FX_TYPE_FX1, "Cypress EZ-USB FX1" },\
{ 0x04b4, 0x8613, FX_TYPE_FX2LP, "Cypress EZ-USB FX2LP (68013A/68014A/68015A/68016A)" }, \
{ 0x04b4, 0x00f3, FX_TYPE_FX3, "Cypress FX3" },\
}
/*
* This function uploads the firmware from the given file into RAM.
* Stage == 0 means this is a single stage load (or the first of
* two stages). Otherwise it's the second of two stages; the
* caller having preloaded the second stage loader.
*
* The target processor is reset at the end of this upload.
*/
extern int ezusb_load_ram(libusb_device_handle *device,
const char *path, int fx_type, int img_type, int stage);
/*
* This function uploads the firmware from the given file into EEPROM.
* This uses the right CPUCS address to terminate the EEPROM load with
* a reset command where FX parts behave differently than FX2 ones.
* The configuration byte is as provided here (zero for an21xx parts)
* and the EEPROM type is set so that the microcontroller will boot
* from it.
*
* The caller must have preloaded a second stage loader that knows
* how to respond to the EEPROM write request.
*/
extern int ezusb_load_eeprom(libusb_device_handle *device,
const char *path, int fx_type, int img_type, int config);
/* Verbosity level (default 1). Can be increased or decreased with options v/q */
extern int verbose;
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,309 +0,0 @@
/*
* Copyright © 2001 Stephen Williams (steve@icarus.com)
* Copyright © 2001-2002 David Brownell (dbrownell@users.sourceforge.net)
* Copyright © 2008 Roger Williams (rawqux@users.sourceforge.net)
* Copyright © 2012 Pete Batard (pete@akeo.ie)
* Copyright © 2013 Federico Manzan (f.manzan@gmail.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdarg.h>
#include <sys/types.h>
#include <getopt.h>
#include "libusb.h"
#include "ezusb.h"
#if !defined(_WIN32) || defined(__CYGWIN__ )
#include <syslog.h>
static bool dosyslog = false;
#include <strings.h>
#define _stricmp strcasecmp
#endif
#ifndef FXLOAD_VERSION
#define FXLOAD_VERSION (__DATE__ " (libusb)")
#endif
#ifndef ARRAYSIZE
#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
#endif
void logerror(const char *format, ...)
__attribute__ ((format (__printf__, 1, 2)));
void logerror(const char *format, ...)
{
va_list ap;
va_start(ap, format);
#if !defined(_WIN32) || defined(__CYGWIN__ )
if (dosyslog)
vsyslog(LOG_ERR, format, ap);
else
#endif
vfprintf(stderr, format, ap);
va_end(ap);
}
static int print_usage(int error_code) {
fprintf(stderr, "\nUsage: fxload [-v] [-V] [-t type] [-d vid:pid] [-p bus,addr] [-s loader] -i firmware\n");
fprintf(stderr, " -i <path> -- Firmware to upload\n");
fprintf(stderr, " -s <path> -- Second stage loader\n");
fprintf(stderr, " -t <type> -- Target type: an21, fx, fx2, fx2lp, fx3\n");
fprintf(stderr, " -d <vid:pid> -- Target device, as an USB VID:PID\n");
fprintf(stderr, " -p <bus,addr> -- Target device, as a libusb bus number and device address path\n");
fprintf(stderr, " -v -- Increase verbosity\n");
fprintf(stderr, " -q -- Decrease verbosity (silent mode)\n");
fprintf(stderr, " -V -- Print program version\n");
return error_code;
}
#define FIRMWARE 0
#define LOADER 1
int main(int argc, char*argv[])
{
fx_known_device known_device[] = FX_KNOWN_DEVICES;
const char *path[] = { NULL, NULL };
const char *device_id = NULL;
const char *device_path = getenv("DEVICE");
const char *type = NULL;
const char *fx_name[FX_TYPE_MAX] = FX_TYPE_NAMES;
const char *ext, *img_name[] = IMG_TYPE_NAMES;
int fx_type = FX_TYPE_UNDEFINED, img_type[ARRAYSIZE(path)];
int opt, status;
unsigned int i, j;
unsigned vid = 0, pid = 0;
unsigned busnum = 0, devaddr = 0, _busnum, _devaddr;
libusb_device *dev, **devs;
libusb_device_handle *device = NULL;
struct libusb_device_descriptor desc;
while ((opt = getopt(argc, argv, "qvV?hd:p:i:I:s:S:t:")) != EOF)
switch (opt) {
case 'd':
device_id = optarg;
if (sscanf(device_id, "%x:%x" , &vid, &pid) != 2 ) {
fputs ("please specify VID & PID as \"vid:pid\" in hexadecimal format\n", stderr);
return -1;
}
break;
case 'p':
device_path = optarg;
if (sscanf(device_path, "%u,%u", &busnum, &devaddr) != 2 ) {
fputs ("please specify bus number & device number as \"bus,dev\" in decimal format\n", stderr);
return -1;
}
break;
case 'i':
case 'I':
path[FIRMWARE] = optarg;
break;
case 's':
case 'S':
path[LOADER] = optarg;
break;
case 'V':
puts(FXLOAD_VERSION);
return 0;
case 't':
type = optarg;
break;
case 'v':
verbose++;
break;
case 'q':
verbose--;
break;
case '?':
case 'h':
default:
return print_usage(-1);
}
if (path[FIRMWARE] == NULL) {
logerror("no firmware specified!\n");
return print_usage(-1);
}
if ((device_id != NULL) && (device_path != NULL)) {
logerror("only one of -d or -p can be specified\n");
return print_usage(-1);
}
/* determine the target type */
if (type != NULL) {
for (i=0; i<FX_TYPE_MAX; i++) {
if (strcmp(type, fx_name[i]) == 0) {
fx_type = i;
break;
}
}
if (i >= FX_TYPE_MAX) {
logerror("illegal microcontroller type: %s\n", type);
return print_usage(-1);
}
}
/* open the device using libusb */
status = libusb_init(NULL);
if (status < 0) {
logerror("libusb_init() failed: %s\n", libusb_error_name(status));
return -1;
}
libusb_set_option(NULL, LIBUSB_OPTION_LOG_LEVEL, verbose);
/* try to pick up missing parameters from known devices */
if ((type == NULL) || (device_id == NULL) || (device_path != NULL)) {
if (libusb_get_device_list(NULL, &devs) < 0) {
logerror("libusb_get_device_list() failed: %s\n", libusb_error_name(status));
goto err;
}
for (i=0; (dev=devs[i]) != NULL; i++) {
_busnum = libusb_get_bus_number(dev);
_devaddr = libusb_get_device_address(dev);
if ((type != NULL) && (device_path != NULL)) {
// if both a type and bus,addr were specified, we just need to find our match
if ((libusb_get_bus_number(dev) == busnum) && (libusb_get_device_address(dev) == devaddr))
break;
} else {
status = libusb_get_device_descriptor(dev, &desc);
if (status >= 0) {
if (verbose >= 3) {
logerror("examining %04x:%04x (%d,%d)\n",
desc.idVendor, desc.idProduct, _busnum, _devaddr);
}
for (j=0; j<ARRAYSIZE(known_device); j++) {
if ((desc.idVendor == known_device[j].vid)
&& (desc.idProduct == known_device[j].pid)) {
if (// nothing was specified
((type == NULL) && (device_id == NULL) && (device_path == NULL)) ||
// vid:pid was specified and we have a match
((type == NULL) && (device_id != NULL) && (vid == desc.idVendor) && (pid == desc.idProduct)) ||
// bus,addr was specified and we have a match
((type == NULL) && (device_path != NULL) && (busnum == _busnum) && (devaddr == _devaddr)) ||
// type was specified and we have a match
((type != NULL) && (device_id == NULL) && (device_path == NULL) && (fx_type == known_device[j].type)) ) {
fx_type = known_device[j].type;
vid = desc.idVendor;
pid = desc.idProduct;
busnum = _busnum;
devaddr = _devaddr;
break;
}
}
}
if (j < ARRAYSIZE(known_device)) {
if (verbose)
logerror("found device '%s' [%04x:%04x] (%d,%d)\n",
known_device[j].designation, vid, pid, busnum, devaddr);
break;
}
}
}
}
if (dev == NULL) {
libusb_free_device_list(devs, 1);
libusb_exit(NULL);
logerror("could not find a known device - please specify type and/or vid:pid and/or bus,dev\n");
return print_usage(-1);
}
status = libusb_open(dev, &device);
libusb_free_device_list(devs, 1);
if (status < 0) {
logerror("libusb_open() failed: %s\n", libusb_error_name(status));
goto err;
}
} else if (device_id != NULL) {
device = libusb_open_device_with_vid_pid(NULL, (uint16_t)vid, (uint16_t)pid);
if (device == NULL) {
logerror("libusb_open() failed\n");
goto err;
}
}
/* We need to claim the first interface */
libusb_set_auto_detach_kernel_driver(device, 1);
status = libusb_claim_interface(device, 0);
if (status != LIBUSB_SUCCESS) {
libusb_close(device);
logerror("libusb_claim_interface failed: %s\n", libusb_error_name(status));
goto err;
}
if (verbose)
logerror("microcontroller type: %s\n", fx_name[fx_type]);
for (i=0; i<ARRAYSIZE(path); i++) {
if (path[i] != NULL) {
ext = path[i] + strlen(path[i]) - 4;
if ((_stricmp(ext, ".hex") == 0) || (strcmp(ext, ".ihx") == 0))
img_type[i] = IMG_TYPE_HEX;
else if (_stricmp(ext, ".iic") == 0)
img_type[i] = IMG_TYPE_IIC;
else if (_stricmp(ext, ".bix") == 0)
img_type[i] = IMG_TYPE_BIX;
else if (_stricmp(ext, ".img") == 0)
img_type[i] = IMG_TYPE_IMG;
else {
logerror("%s is not a recognized image type\n", path[i]);
goto err;
}
}
if (verbose && path[i] != NULL)
logerror("%s: type %s\n", path[i], img_name[img_type[i]]);
}
if (path[LOADER] == NULL) {
/* single stage, put into internal memory */
if (verbose > 1)
logerror("single stage: load on-chip memory\n");
status = ezusb_load_ram(device, path[FIRMWARE], fx_type, img_type[FIRMWARE], 0);
} else {
/* two-stage, put loader into internal memory */
if (verbose > 1)
logerror("1st stage: load 2nd stage loader\n");
status = ezusb_load_ram(device, path[LOADER], fx_type, img_type[LOADER], 0);
if (status == 0) {
/* two-stage, put firmware into internal memory */
if (verbose > 1)
logerror("2nd state: load on-chip memory\n");
status = ezusb_load_ram(device, path[FIRMWARE], fx_type, img_type[FIRMWARE], 1);
}
}
libusb_release_interface(device, 0);
libusb_close(device);
libusb_exit(NULL);
return status;
err:
libusb_exit(NULL);
return -1;
}

View File

@ -1,73 +0,0 @@
/*
* libusb example program to list devices on the bus
* Copyright © 2007 Daniel Drake <dsd@gentoo.org>
*
* This library 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 Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include "libusb.h"
static void print_devs(libusb_device **devs)
{
libusb_device *dev;
int i = 0, j = 0;
uint8_t path[8];
while ((dev = devs[i++]) != NULL) {
struct libusb_device_descriptor desc;
int r = libusb_get_device_descriptor(dev, &desc);
if (r < 0) {
fprintf(stderr, "failed to get device descriptor");
return;
}
printf("%04x:%04x (bus %d, device %d)",
desc.idVendor, desc.idProduct,
libusb_get_bus_number(dev), libusb_get_device_address(dev));
r = libusb_get_port_numbers(dev, path, sizeof(path));
if (r > 0) {
printf(" path: %d", path[0]);
for (j = 1; j < r; j++)
printf(".%d", path[j]);
}
printf("\n");
}
}
int main(void)
{
libusb_device **devs;
int r;
ssize_t cnt;
r = libusb_init(NULL);
if (r < 0)
return r;
cnt = libusb_get_device_list(NULL, &devs);
if (cnt < 0){
libusb_exit(NULL);
return (int) cnt;
}
print_devs(devs);
libusb_free_device_list(devs, 1);
libusb_exit(NULL);
return 0;
}

View File

@ -1,256 +0,0 @@
/**
* This file has no copyright assigned and is placed in the Public Domain.
* This file was originally part of the w64 mingw-runtime package.
*/
/* ISO C9x 7.18 Integer types <stdint.h>
* Based on ISO/IEC SC22/WG14 9899 Committee draft (SC22 N2794)
*
* THIS SOFTWARE IS NOT COPYRIGHTED
*
* Contributor: Danny Smith <danny_r_smith_2001@yahoo.co.nz>
* Modified for libusb/MSVC: Pete Batard <pbatard@gmail.com>
*
* This source code is offered for use in the public domain. You may
* use, modify or distribute it freely.
*
* This code is distributed in the hope that it will be useful but
* WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
* DISCLAIMED. This includes but is not limited to warranties of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* Date: 2010-04-02
*/
#ifndef _MSC_VER
#error This header should only be used with Microsoft compilers
#endif
#ifndef _STDINT_H
#define _STDINT_H
#ifndef _INTPTR_T_DEFINED
#define _INTPTR_T_DEFINED
#ifndef __intptr_t_defined
#define __intptr_t_defined
#undef intptr_t
#ifdef _WIN64
typedef __int64 intptr_t;
#else
typedef int intptr_t;
#endif /* _WIN64 */
#endif /* __intptr_t_defined */
#endif /* _INTPTR_T_DEFINED */
#ifndef _UINTPTR_T_DEFINED
#define _UINTPTR_T_DEFINED
#ifndef __uintptr_t_defined
#define __uintptr_t_defined
#undef uintptr_t
#ifdef _WIN64
typedef unsigned __int64 uintptr_t;
#else
typedef unsigned int uintptr_t;
#endif /* _WIN64 */
#endif /* __uintptr_t_defined */
#endif /* _UINTPTR_T_DEFINED */
#ifndef _PTRDIFF_T_DEFINED
#define _PTRDIFF_T_DEFINED
#ifndef _PTRDIFF_T_
#define _PTRDIFF_T_
#undef ptrdiff_t
#ifdef _WIN64
typedef __int64 ptrdiff_t;
#else
typedef int ptrdiff_t;
#endif /* _WIN64 */
#endif /* _PTRDIFF_T_ */
#endif /* _PTRDIFF_T_DEFINED */
#ifndef _WCHAR_T_DEFINED
#define _WCHAR_T_DEFINED
#ifndef __cplusplus
typedef unsigned short wchar_t;
#endif /* C++ */
#endif /* _WCHAR_T_DEFINED */
#ifndef _WCTYPE_T_DEFINED
#define _WCTYPE_T_DEFINED
#ifndef _WINT_T
#define _WINT_T
typedef unsigned short wint_t;
typedef unsigned short wctype_t;
#endif /* _WINT_T */
#endif /* _WCTYPE_T_DEFINED */
/* 7.18.1.1 Exact-width integer types */
typedef __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef __int16 int16_t;
typedef unsigned __int16 uint16_t;
typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
/* 7.18.1.2 Minimum-width integer types */
typedef signed char int_least8_t;
typedef unsigned char uint_least8_t;
typedef short int_least16_t;
typedef unsigned short uint_least16_t;
typedef int int_least32_t;
typedef unsigned uint_least32_t;
typedef __int64 int_least64_t;
typedef unsigned __int64 uint_least64_t;
/* 7.18.1.3 Fastest minimum-width integer types
* Not actually guaranteed to be fastest for all purposes
* Here we use the exact-width types for 8 and 16-bit ints.
*/
typedef __int8 int_fast8_t;
typedef unsigned __int8 uint_fast8_t;
typedef __int16 int_fast16_t;
typedef unsigned __int16 uint_fast16_t;
typedef __int32 int_fast32_t;
typedef unsigned __int32 uint_fast32_t;
typedef __int64 int_fast64_t;
typedef unsigned __int64 uint_fast64_t;
/* 7.18.1.5 Greatest-width integer types */
typedef __int64 intmax_t;
typedef unsigned __int64 uintmax_t;
/* 7.18.2 Limits of specified-width integer types */
/* 7.18.2.1 Limits of exact-width integer types */
#define INT8_MIN (-128)
#define INT16_MIN (-32768)
#define INT32_MIN (-2147483647 - 1)
#define INT64_MIN (-9223372036854775807LL - 1)
#define INT8_MAX 127
#define INT16_MAX 32767
#define INT32_MAX 2147483647
#define INT64_MAX 9223372036854775807LL
#define UINT8_MAX 255
#define UINT16_MAX 65535
#define UINT32_MAX 0xffffffffU /* 4294967295U */
#define UINT64_MAX 0xffffffffffffffffULL /* 18446744073709551615ULL */
/* 7.18.2.2 Limits of minimum-width integer types */
#define INT_LEAST8_MIN INT8_MIN
#define INT_LEAST16_MIN INT16_MIN
#define INT_LEAST32_MIN INT32_MIN
#define INT_LEAST64_MIN INT64_MIN
#define INT_LEAST8_MAX INT8_MAX
#define INT_LEAST16_MAX INT16_MAX
#define INT_LEAST32_MAX INT32_MAX
#define INT_LEAST64_MAX INT64_MAX
#define UINT_LEAST8_MAX UINT8_MAX
#define UINT_LEAST16_MAX UINT16_MAX
#define UINT_LEAST32_MAX UINT32_MAX
#define UINT_LEAST64_MAX UINT64_MAX
/* 7.18.2.3 Limits of fastest minimum-width integer types */
#define INT_FAST8_MIN INT8_MIN
#define INT_FAST16_MIN INT16_MIN
#define INT_FAST32_MIN INT32_MIN
#define INT_FAST64_MIN INT64_MIN
#define INT_FAST8_MAX INT8_MAX
#define INT_FAST16_MAX INT16_MAX
#define INT_FAST32_MAX INT32_MAX
#define INT_FAST64_MAX INT64_MAX
#define UINT_FAST8_MAX UINT8_MAX
#define UINT_FAST16_MAX UINT16_MAX
#define UINT_FAST32_MAX UINT32_MAX
#define UINT_FAST64_MAX UINT64_MAX
/* 7.18.2.4 Limits of integer types capable of holding
object pointers */
#ifdef _WIN64
#define INTPTR_MIN INT64_MIN
#define INTPTR_MAX INT64_MAX
#define UINTPTR_MAX UINT64_MAX
#else
#define INTPTR_MIN INT32_MIN
#define INTPTR_MAX INT32_MAX
#define UINTPTR_MAX UINT32_MAX
#endif
/* 7.18.2.5 Limits of greatest-width integer types */
#define INTMAX_MIN INT64_MIN
#define INTMAX_MAX INT64_MAX
#define UINTMAX_MAX UINT64_MAX
/* 7.18.3 Limits of other integer types */
#ifdef _WIN64
#define PTRDIFF_MIN INT64_MIN
#define PTRDIFF_MAX INT64_MAX
#else
#define PTRDIFF_MIN INT32_MIN
#define PTRDIFF_MAX INT32_MAX
#endif
#define SIG_ATOMIC_MIN INT32_MIN
#define SIG_ATOMIC_MAX INT32_MAX
#ifndef SIZE_MAX
#ifdef _WIN64
#define SIZE_MAX UINT64_MAX
#else
#define SIZE_MAX UINT32_MAX
#endif
#endif
#ifndef WCHAR_MIN /* also in wchar.h */
#define WCHAR_MIN 0U
#define WCHAR_MAX 0xffffU
#endif
/*
* wint_t is unsigned short for compatibility with MS runtime
*/
#define WINT_MIN 0U
#define WINT_MAX 0xffffU
/* 7.18.4 Macros for integer constants */
/* 7.18.4.1 Macros for minimum-width integer constants
Accoding to Douglas Gwyn <gwyn@arl.mil>:
"This spec was changed in ISO/IEC 9899:1999 TC1; in ISO/IEC
9899:1999 as initially published, the expansion was required
to be an integer constant of precisely matching type, which
is impossible to accomplish for the shorter types on most
platforms, because C99 provides no standard way to designate
an integer constant with width less than that of type int.
TC1 changed this to require just an integer constant
*expression* with *promoted* type."
The trick used here is from Clive D W Feather.
*/
#define INT8_C(val) (INT_LEAST8_MAX-INT_LEAST8_MAX+(val))
#define INT16_C(val) (INT_LEAST16_MAX-INT_LEAST16_MAX+(val))
#define INT32_C(val) (INT_LEAST32_MAX-INT_LEAST32_MAX+(val))
/* The 'trick' doesn't work in C89 for long long because, without
suffix, (val) will be evaluated as int, not intmax_t */
#define INT64_C(val) val##i64
#define UINT8_C(val) (val)
#define UINT16_C(val) (val)
#define UINT32_C(val) (val##i32)
#define UINT64_C(val) val##ui64
/* 7.18.4.2 Macros for greatest-width integer constants */
#define INTMAX_C(val) val##i64
#define UINTMAX_C(val) val##ui64
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1
3rdparty/libusb/libusb vendored Submodule

@ -0,0 +1 @@
Subproject commit ff8fe9397d4c61f072d209703f854c9f62ed17e3

View File

@ -1,178 +0,0 @@
LIBRARY "libusb-1.0.dll"
EXPORTS
libusb_alloc_streams
libusb_alloc_streams@16 = libusb_alloc_streams
libusb_alloc_transfer
libusb_alloc_transfer@4 = libusb_alloc_transfer
libusb_attach_kernel_driver
libusb_attach_kernel_driver@8 = libusb_attach_kernel_driver
libusb_bulk_transfer
libusb_bulk_transfer@24 = libusb_bulk_transfer
libusb_cancel_transfer
libusb_cancel_transfer@4 = libusb_cancel_transfer
libusb_claim_interface
libusb_claim_interface@8 = libusb_claim_interface
libusb_clear_halt
libusb_clear_halt@8 = libusb_clear_halt
libusb_close
libusb_close@4 = libusb_close
libusb_control_transfer
libusb_control_transfer@32 = libusb_control_transfer
libusb_detach_kernel_driver
libusb_detach_kernel_driver@8 = libusb_detach_kernel_driver
libusb_dev_mem_alloc
libusb_dev_mem_alloc@8 = libusb_dev_mem_alloc
libusb_dev_mem_free
libusb_dev_mem_free@12 = libusb_dev_mem_free
libusb_error_name
libusb_error_name@4 = libusb_error_name
libusb_event_handler_active
libusb_event_handler_active@4 = libusb_event_handler_active
libusb_event_handling_ok
libusb_event_handling_ok@4 = libusb_event_handling_ok
libusb_exit
libusb_exit@4 = libusb_exit
libusb_free_bos_descriptor
libusb_free_bos_descriptor@4 = libusb_free_bos_descriptor
libusb_free_config_descriptor
libusb_free_config_descriptor@4 = libusb_free_config_descriptor
libusb_free_container_id_descriptor
libusb_free_container_id_descriptor@4 = libusb_free_container_id_descriptor
libusb_free_device_list
libusb_free_device_list@8 = libusb_free_device_list
libusb_free_pollfds
libusb_free_pollfds@4 = libusb_free_pollfds
libusb_free_ss_endpoint_companion_descriptor
libusb_free_ss_endpoint_companion_descriptor@4 = libusb_free_ss_endpoint_companion_descriptor
libusb_free_ss_usb_device_capability_descriptor
libusb_free_ss_usb_device_capability_descriptor@4 = libusb_free_ss_usb_device_capability_descriptor
libusb_free_streams
libusb_free_streams@12 = libusb_free_streams
libusb_free_transfer
libusb_free_transfer@4 = libusb_free_transfer
libusb_free_usb_2_0_extension_descriptor
libusb_free_usb_2_0_extension_descriptor@4 = libusb_free_usb_2_0_extension_descriptor
libusb_get_active_config_descriptor
libusb_get_active_config_descriptor@8 = libusb_get_active_config_descriptor
libusb_get_bos_descriptor
libusb_get_bos_descriptor@8 = libusb_get_bos_descriptor
libusb_get_bus_number
libusb_get_bus_number@4 = libusb_get_bus_number
libusb_get_config_descriptor
libusb_get_config_descriptor@12 = libusb_get_config_descriptor
libusb_get_config_descriptor_by_value
libusb_get_config_descriptor_by_value@12 = libusb_get_config_descriptor_by_value
libusb_get_configuration
libusb_get_configuration@8 = libusb_get_configuration
libusb_get_container_id_descriptor
libusb_get_container_id_descriptor@12 = libusb_get_container_id_descriptor
libusb_get_device
libusb_get_device@4 = libusb_get_device
libusb_get_device_address
libusb_get_device_address@4 = libusb_get_device_address
libusb_get_device_descriptor
libusb_get_device_descriptor@8 = libusb_get_device_descriptor
libusb_get_device_list
libusb_get_device_list@8 = libusb_get_device_list
libusb_get_device_speed
libusb_get_device_speed@4 = libusb_get_device_speed
libusb_get_max_iso_packet_size
libusb_get_max_iso_packet_size@8 = libusb_get_max_iso_packet_size
libusb_get_max_packet_size
libusb_get_max_packet_size@8 = libusb_get_max_packet_size
libusb_get_next_timeout
libusb_get_next_timeout@8 = libusb_get_next_timeout
libusb_get_parent
libusb_get_parent@4 = libusb_get_parent
libusb_get_pollfds
libusb_get_pollfds@4 = libusb_get_pollfds
libusb_get_port_number
libusb_get_port_number@4 = libusb_get_port_number
libusb_get_port_numbers
libusb_get_port_numbers@12 = libusb_get_port_numbers
libusb_get_port_path
libusb_get_port_path@16 = libusb_get_port_path
libusb_get_ss_endpoint_companion_descriptor
libusb_get_ss_endpoint_companion_descriptor@12 = libusb_get_ss_endpoint_companion_descriptor
libusb_get_ss_usb_device_capability_descriptor
libusb_get_ss_usb_device_capability_descriptor@12 = libusb_get_ss_usb_device_capability_descriptor
libusb_get_string_descriptor_ascii
libusb_get_string_descriptor_ascii@16 = libusb_get_string_descriptor_ascii
libusb_get_usb_2_0_extension_descriptor
libusb_get_usb_2_0_extension_descriptor@12 = libusb_get_usb_2_0_extension_descriptor
libusb_get_version
libusb_get_version@0 = libusb_get_version
libusb_handle_events
libusb_handle_events@4 = libusb_handle_events
libusb_handle_events_completed
libusb_handle_events_completed@8 = libusb_handle_events_completed
libusb_handle_events_locked
libusb_handle_events_locked@8 = libusb_handle_events_locked
libusb_handle_events_timeout
libusb_handle_events_timeout@8 = libusb_handle_events_timeout
libusb_handle_events_timeout_completed
libusb_handle_events_timeout_completed@12 = libusb_handle_events_timeout_completed
libusb_has_capability
libusb_has_capability@4 = libusb_has_capability
libusb_hotplug_deregister_callback
libusb_hotplug_deregister_callback@8 = libusb_hotplug_deregister_callback
libusb_hotplug_register_callback
libusb_hotplug_register_callback@36 = libusb_hotplug_register_callback
libusb_init
libusb_init@4 = libusb_init
libusb_interrupt_event_handler
libusb_interrupt_event_handler@4 = libusb_interrupt_event_handler
libusb_interrupt_transfer
libusb_interrupt_transfer@24 = libusb_interrupt_transfer
libusb_kernel_driver_active
libusb_kernel_driver_active@8 = libusb_kernel_driver_active
libusb_lock_event_waiters
libusb_lock_event_waiters@4 = libusb_lock_event_waiters
libusb_lock_events
libusb_lock_events@4 = libusb_lock_events
libusb_open
libusb_open@8 = libusb_open
libusb_open_device_with_vid_pid
libusb_open_device_with_vid_pid@12 = libusb_open_device_with_vid_pid
libusb_pollfds_handle_timeouts
libusb_pollfds_handle_timeouts@4 = libusb_pollfds_handle_timeouts
libusb_ref_device
libusb_ref_device@4 = libusb_ref_device
libusb_release_interface
libusb_release_interface@8 = libusb_release_interface
libusb_reset_device
libusb_reset_device@4 = libusb_reset_device
libusb_set_auto_detach_kernel_driver
libusb_set_auto_detach_kernel_driver@8 = libusb_set_auto_detach_kernel_driver
libusb_set_configuration
libusb_set_configuration@8 = libusb_set_configuration
libusb_set_debug
libusb_set_debug@8 = libusb_set_debug
libusb_set_log_cb
libusb_set_log_cb@12 = libusb_set_log_cb
libusb_set_interface_alt_setting
libusb_set_interface_alt_setting@12 = libusb_set_interface_alt_setting
libusb_set_option
_libusb_set_option = libusb_set_option
libusb_set_pollfd_notifiers
libusb_set_pollfd_notifiers@16 = libusb_set_pollfd_notifiers
libusb_setlocale
libusb_setlocale@4 = libusb_setlocale
libusb_strerror
libusb_strerror@4 = libusb_strerror
libusb_submit_transfer
libusb_submit_transfer@4 = libusb_submit_transfer
libusb_transfer_get_stream_id
libusb_transfer_get_stream_id@4 = libusb_transfer_get_stream_id
libusb_transfer_set_stream_id
libusb_transfer_set_stream_id@8 = libusb_transfer_set_stream_id
libusb_try_lock_events
libusb_try_lock_events@4 = libusb_try_lock_events
libusb_unlock_event_waiters
libusb_unlock_event_waiters@4 = libusb_unlock_event_waiters
libusb_unlock_events
libusb_unlock_events@4 = libusb_unlock_events
libusb_unref_device
libusb_unref_device@4 = libusb_unref_device
libusb_wait_for_event
libusb_wait_for_event@8 = libusb_wait_for_event

65
3rdparty/libusb/libusb.vcxproj vendored Normal file
View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(SolutionDir)common\vsprops\BaseProjectConfig.props" />
<Import Project="$(SolutionDir)common\vsprops\WinSDK.props" />
<PropertyGroup Label="Globals">
<ProjectGuid>{349EE8F9-7D25-4909-AAF5-FF3FADE72187}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<WholeProgramOptimization Condition="$(Configuration.Contains(Release))">true</WholeProgramOptimization>
<UseDebugLibraries Condition="$(Configuration.Contains(Debug))">true</UseDebugLibraries>
<UseDebugLibraries Condition="!$(Configuration.Contains(Debug))">false</UseDebugLibraries>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings" />
<ImportGroup Label="PropertySheets">
<Import Project="..\DefaultProjectRootDir.props" />
<Import Project="..\3rdparty.props" />
<Import Condition="$(Configuration.Contains(Debug))" Project="..\..\common\vsprops\CodeGen_Debug.props" />
<Import Condition="$(Configuration.Contains(Devel))" Project="..\..\common\vsprops\CodeGen_Devel.props" />
<Import Condition="$(Configuration.Contains(Release))" Project="..\..\common\vsprops\CodeGen_Release.props" />
<Import Condition="!$(Configuration.Contains(Release))" Project="..\..\common\vsprops\IncrementalLinking.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="libusb\libusb\core.c" />
<ClCompile Include="libusb\libusb\descriptor.c" />
<ClCompile Include="libusb\libusb\os\events_windows.c" />
<ClCompile Include="libusb\libusb\hotplug.c" />
<ClCompile Include="libusb\libusb\io.c" />
<ClCompile Include="libusb\libusb\strerror.c" />
<ClCompile Include="libusb\libusb\sync.c" />
<ClCompile Include="libusb\libusb\os\threads_windows.c" />
<ClCompile Include="libusb\libusb\os\windows_common.c" />
<ClCompile Include="libusb\libusb\os\windows_usbdk.c" />
<ClCompile Include="libusb\libusb\os\windows_winusb.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="libusb\msvc\config.h" />
<ClInclude Include="libusb\libusb\os\events_windows.h" />
<ClInclude Include="libusb\libusb\libusb.h" />
<ClInclude Include="libusb\libusb\libusbi.h" />
<ClInclude Include="libusb\libusb\os\threads_windows.h" />
<ClInclude Include="libusb\libusb\version.h" />
<ClInclude Include="libusb\libusb\version_nano.h" />
<ClInclude Include="libusb\libusb\os\windows_common.h" />
<ClInclude Include="libusb\libusb\os\windows_usbdk.h" />
<ClInclude Include="libusb\libusb\os\windows_winusb.h" />
</ItemGroup>
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions>
<WarningLevel>TurnOffAllWarnings</WarningLevel>
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\libusb\libusb\libusb;$(SolutionDir)3rdparty\libusb\libusb\msvc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets" />
</Project>

View File

@ -59,6 +59,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "updater", "updater\updater.
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cpuinfo", "3rdparty\cpuinfo\cpuinfo.vcxproj", "{7E183337-A7E9-460C-9D3D-568BC9F9BCC1}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libusb", "3rdparty\libusb\libusb.vcxproj", "{349EE8F9-7D25-4909-AAF5-FF3FADE72187}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug AVX2|x64 = Debug AVX2|x64
@ -393,6 +395,18 @@ Global
{7E183337-A7E9-460C-9D3D-568BC9F9BCC1}.Release AVX2|x64.Build.0 = Release|x64
{7E183337-A7E9-460C-9D3D-568BC9F9BCC1}.Release|x64.ActiveCfg = Release|x64
{7E183337-A7E9-460C-9D3D-568BC9F9BCC1}.Release|x64.Build.0 = Release|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug AVX2|x64.ActiveCfg = Debug|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug AVX2|x64.Build.0 = Debug|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.ActiveCfg = Debug|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.Build.0 = Debug|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Devel AVX2|x64.ActiveCfg = Debug|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Devel AVX2|x64.Build.0 = Debug|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Devel|x64.ActiveCfg = Devel|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Devel|x64.Build.0 = Devel|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release AVX2|x64.ActiveCfg = Release|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release AVX2|x64.Build.0 = Release|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|x64.ActiveCfg = Release|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -408,7 +422,6 @@ Global
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{EB12076D-4CEF-4D9D-8F34-5D0043798051} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{EB12076D-4CEF-4D9D-8F34-5D0043798051} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{88FB34EC-845E-4F21-A552-F1573B9ED167} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
@ -422,6 +435,7 @@ Global
{D45CEC7A-3171-40DD-975D-E1544CF16139} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{A4323327-3F2B-4271-83D9-7F9A3C66B6B2} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{7E183337-A7E9-460C-9D3D-568BC9F9BCC1} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{349EE8F9-7D25-4909-AAF5-FF3FADE72187} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0BC474EA-3628-45D3-9DBC-E22D0B7E0F77}

View File

@ -72,6 +72,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "d3d12memalloc", "3rdparty\d
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lzma", "3rdparty\lzma\lzma.vcxproj", "{A4323327-3F2B-4271-83D9-7F9A3C66B6B2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libusb", "3rdparty\libusb\libusb.vcxproj", "{349EE8F9-7D25-4909-AAF5-FF3FADE72187}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug AVX2|x64 = Debug AVX2|x64
@ -430,6 +432,18 @@ Global
{A4323327-3F2B-4271-83D9-7F9A3C66B6B2}.Release AVX2|x64.Build.0 = Release|x64
{A4323327-3F2B-4271-83D9-7F9A3C66B6B2}.Release|x64.ActiveCfg = Release|x64
{A4323327-3F2B-4271-83D9-7F9A3C66B6B2}.Release|x64.Build.0 = Release|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug AVX2|x64.ActiveCfg = Debug|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug AVX2|x64.Build.0 = Debug|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.ActiveCfg = Debug|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.Build.0 = Debug|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Devel AVX2|x64.ActiveCfg = Debug|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Devel AVX2|x64.Build.0 = Debug|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Devel|x64.ActiveCfg = Devel|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Devel|x64.Build.0 = Devel|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release AVX2|x64.ActiveCfg = Release|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release AVX2|x64.Build.0 = Release|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|x64.ActiveCfg = Release|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -104,6 +104,12 @@ target_sources(pcsx2-qt PRIVATE
Settings/DEV9UiCommon.h
Settings/HddCreateQt.cpp
Settings/HddCreateQt.h
Settings/Python2BindingWidget.ui
Settings/Python2BindingWidget.cpp
Settings/Python2BindingWidget.h
Settings/Python2SettingsWidget.cpp
Settings/Python2SettingsWidget.h
Settings/Python2SettingsWidget.ui
Settings/SettingsDialog.cpp
Settings/SettingsDialog.h
Settings/SettingsDialog.ui

View File

@ -21,6 +21,7 @@
#include "Settings/ControllerGlobalSettingsWidget.h"
#include "Settings/ControllerBindingWidgets.h"
#include "Settings/HotkeySettingsWidget.h"
#include "Settings/Python2BindingWidget.h"
#include "pcsx2/Frontend/INISettingsInterface.h"
#include "pcsx2/PAD/Host/PAD.h"
@ -393,6 +394,15 @@ void ControllerSettingsDialog::createWidgets()
m_ui.settingsContainer->addWidget(m_hotkey_settings);
}
{
QListWidgetItem* item = new QListWidgetItem();
item->setText(tr("Python 2"));
item->setIcon(QIcon::fromTheme("gamepad-line"));
m_ui.settingsCategory->addItem(item);
m_python2_settings = new Python2BindingWidget(m_ui.settingsContainer, this);
m_ui.settingsContainer->addWidget(m_python2_settings);
}
m_ui.loadProfile->setEnabled(isEditingProfile());
m_ui.deleteProfile->setEnabled(isEditingProfile());
m_ui.restoreDefaults->setEnabled(isEditingGlobalSettings());

View File

@ -27,6 +27,7 @@
class ControllerGlobalSettingsWidget;
class ControllerBindingWidget;
class HotkeySettingsWidget;
class Python2BindingWidget;
class SettingsInterface;
@ -101,6 +102,7 @@ private:
ControllerGlobalSettingsWidget* m_global_settings = nullptr;
std::array<ControllerBindingWidget*, MAX_PORTS> m_port_bindings{};
HotkeySettingsWidget* m_hotkey_settings = nullptr;
Python2BindingWidget* m_python2_settings = nullptr;
QList<QPair<QString, QString>> m_device_list;
QStringList m_vibration_motors;

View File

@ -0,0 +1,770 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team, 987123879113
*
* 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/>.
*/
#include "PrecompiledHeader.h"
#include <QtCore/QTimer>
#include <QtGui/QKeyEvent>
#include <QtGui/QMouseEvent>
#include <QtGui/QWheelEvent>
#include <QtWidgets/QInputDialog>
#include <QtWidgets/QMenu>
#include <QtWidgets/QMessageBox>
#include <algorithm>
#include "Settings/Python2BindingWidget.h"
#include "Settings/ControllerSettingsDialog.h"
#include "Settings/ControllerSettingWidgetBinder.h"
#include "Settings/InputBindingWidget.h"
#include "Settings/SettingsDialog.h"
#include "EmuThread.h"
#include "QtUtils.h"
#include "SettingWidgetBinder.h"
#include "common/StringUtil.h"
#include "pcsx2/HostSettings.h"
#include "pcsx2/PAD/Host/PAD.h"
#include "pcsx2/GS/GSIntrin.h" // _BitScanForward
#include "pcsx2/USB/usb-python2/inputs/Python2QtInputManager.h"
Python2BindingWidget::Python2BindingWidget(QWidget* parent, ControllerSettingsDialog* dialog)
: QWidget(parent)
, m_dialog(dialog)
{
m_ui.setupUi(this);
Python2QtInputManager::LoadMapping();
connect(m_ui.gameTypeFilter, &QComboBox::currentIndexChanged, this, [this](int index) {
m_ui.inputList->clear();
if (s_python2_system_info[index].bindings == nullptr)
{
for (auto system_entry : s_python2_system_info)
{
if (system_entry.bindings == nullptr)
continue;
for (u32 i = 0; i < system_entry.num_bindings; i++)
{
auto entry = system_entry.bindings[i];
if (entry.type != PAD::ControllerBindingType::Button)
continue;
QListWidgetItem* item = new QListWidgetItem();
item->setText(tr("%1 - %2").arg(QString::fromStdString(system_entry.name)).arg(QString::fromStdString(entry.display_name)));
item->setData(Qt::UserRole, QString::fromStdString(entry.name));
m_ui.inputList->addItem(item);
}
}
}
else
{
for (u32 i = 0; i < s_python2_system_info[index].num_bindings; i++)
{
auto entry = s_python2_system_info[index].bindings[i];
if (entry.type != PAD::ControllerBindingType::Button)
continue;
QListWidgetItem* item = new QListWidgetItem();
item->setText(QString::fromStdString(entry.display_name));
item->setText(tr("%1 - %2").arg(QString::fromStdString(s_python2_system_info[index].name)).arg(QString::fromStdString(entry.display_name)));
item->setData(Qt::UserRole, QString::fromStdString(entry.name));
m_ui.inputList->addItem(item);
}
}
m_ui.inputList->setCurrentRow(0);
});
// Inputs tab
connect(m_ui.bindKey, &QPushButton::clicked, this, [this]() { startListeningForInput(TIMEOUT_FOR_SINGLE_BINDING, false); });
connect(m_ui.unbindKey, &QPushButton::clicked, this, [this]() { unbindKeyClicked(m_ui.keybindList); });
for (std::size_t i = 0; i < std::size(s_python2_system_info); i++)
{
auto input_entry = s_python2_system_info[i];
m_ui.gameTypeFilter->addItem(QString::fromStdString(input_entry.name), (int)i);
}
m_ui.gameTypeFilter->setCurrentIndex(0);
// Analog Inputs tab
connect(m_ui.bindKeyAnalog, &QPushButton::clicked, this, [this]() { startListeningForInput(TIMEOUT_FOR_SINGLE_BINDING, true); });
connect(m_ui.unbindKeyAnalog, &QPushButton::clicked, this, [this]() { unbindKeyClicked(m_ui.keybindListAnalogs); });
connect(m_ui.inputListAnalogs, &QListWidget::itemClicked, this, [this](QListWidgetItem* item) {
// Disable motor scale slider
m_ui.Deadzone->setDisabled(true);
m_ui.AxisScale->setDisabled(true);
m_ui.Deadzone->blockSignals(true);
m_ui.Deadzone->setValue(m_ui.Deadzone->minimum());
m_ui.Deadzone->blockSignals(false);
m_ui.AxisScale->blockSignals(true);
m_ui.AxisScale->setValue(m_ui.AxisScale->minimum());
m_ui.AxisScale->blockSignals(false);
});
connect(m_ui.keybindListAnalogs, &QTableWidget::itemClicked, this, [this](QTableWidgetItem* item) {
// Enable motor scale slider
auto currentRow = m_ui.keybindListAnalogs->currentRow();
if (currentRow == -1)
return;
auto deadzoneItem = m_ui.keybindListAnalogs->item(currentRow, 1);
auto axisScaleItem = m_ui.keybindListAnalogs->item(currentRow, 2);
m_ui.Deadzone->blockSignals(true);
m_ui.Deadzone->setValue(deadzoneItem->data(Qt::UserRole).toDouble() * static_cast<double>(m_ui.Deadzone->maximum()));
m_ui.Deadzone->blockSignals(false);
m_ui.AxisScale->blockSignals(true);
m_ui.AxisScale->setValue(axisScaleItem->data(Qt::UserRole).toDouble() * static_cast<double>(m_ui.AxisScale->maximum()));
m_ui.AxisScale->blockSignals(false);
m_ui.Deadzone->setDisabled(false);
m_ui.AxisScale->setDisabled(false);
});
connect(m_ui.Deadzone, &QSlider::valueChanged, this, [this](int value) {
auto currentRow = m_ui.keybindListAnalogs->currentRow();
if (currentRow == -1)
return;
auto selectedItem = m_ui.keybindListAnalogs->item(currentRow, 0);
uint uniqueId = selectedItem->data(Qt::UserRole).toUInt();
auto val = static_cast<double>(value) / static_cast<double>(m_ui.Deadzone->maximum());
for (auto &bind : Python2QtInputManager::GetCurrentMappings()) {
if (bind.uniqueId == uniqueId) {
bind.analogDeadzone = val;
}
}
saveAndRefresh();
m_ui.keybindListAnalogs->setCurrentItem(
m_ui.keybindListAnalogs->item(currentRow, 0)
);
});
connect(m_ui.AxisScale, &QSlider::valueChanged, this, [this](int value) {
auto currentRow = m_ui.keybindListAnalogs->currentRow();
if (currentRow == -1)
return;
auto selectedItem = m_ui.keybindListAnalogs->item(currentRow, 0);
uint uniqueId = selectedItem->data(Qt::UserRole).toUInt();
auto val = static_cast<double>(value) / static_cast<double>(m_ui.AxisScale->maximum());
for (auto &bind : Python2QtInputManager::GetCurrentMappings()) {
if (bind.uniqueId == uniqueId) {
bind.analogSensitivity = val;
}
}
saveAndRefresh();
m_ui.keybindListAnalogs->setCurrentItem(
m_ui.keybindListAnalogs->item(currentRow, 0)
);
});
for (auto system_entry : s_python2_system_info)
{
if (system_entry.bindings == nullptr)
continue;
for (u32 i = 0; i < system_entry.num_bindings; i++)
{
auto entry = system_entry.bindings[i];
if (entry.type != PAD::ControllerBindingType::Axis && entry.type != PAD::ControllerBindingType::HalfAxis)
continue;
QListWidgetItem* item = new QListWidgetItem();
item->setText(tr("%1 - %2").arg(QString::fromStdString(system_entry.name)).arg(QString::fromStdString(entry.display_name)));
item->setData(Qt::UserRole, QString::fromStdString(entry.name));
m_ui.inputListAnalogs->addItem(item);
}
}
m_ui.inputListAnalogs->setCurrentRow(0);
m_ui.Deadzone->setDisabled(true);
m_ui.AxisScale->setDisabled(true);
// Motors tab
connect(m_ui.bindKeyMotor, &QPushButton::clicked, this, &Python2BindingWidget::onBindKeyMotorClicked);
connect(m_ui.unbindKeyMotor, &QPushButton::clicked, this, [this]() { unbindKeyClicked(m_ui.keybindListMotors); });
connect(m_ui.motorList, &QListWidget::itemClicked, this, [this](QListWidgetItem* item) {
// Disable motor scale slider
m_ui.MotorScale->setDisabled(true);
m_ui.MotorScale->blockSignals(true);
m_ui.MotorScale->setValue(m_ui.MotorScale->minimum());
m_ui.MotorScale->blockSignals(false);
});
connect(m_ui.keybindListMotors, &QTableWidget::itemClicked, this, [this](QTableWidgetItem* item) {
// Enable motor scale slider
auto currentRow = m_ui.keybindListMotors->currentRow();
if (currentRow == -1)
return;
auto motorScaleItem = m_ui.keybindListMotors->item(currentRow, 1);
m_ui.MotorScale->blockSignals(true);
m_ui.MotorScale->setValue(motorScaleItem->data(Qt::UserRole).toDouble() * static_cast<double>(m_ui.MotorScale->maximum()));
m_ui.MotorScale->blockSignals(false);
m_ui.MotorScale->setDisabled(false);
});
connect(m_ui.MotorScale, &QSlider::valueChanged, this, [this](int value) {
auto currentRow = m_ui.keybindListMotors->currentRow();
if (currentRow == -1)
return;
auto selectedItem = m_ui.keybindListMotors->item(currentRow, 0);
uint uniqueId = selectedItem->data(Qt::UserRole).toUInt();
auto val = static_cast<double>(value) / static_cast<double>(m_ui.MotorScale->maximum());
for (auto &bind : Python2QtInputManager::GetCurrentMappings()) {
if (bind.uniqueId == uniqueId) {
bind.motorScale = val;
}
}
saveAndRefresh();
m_ui.keybindListMotors->setCurrentItem(
m_ui.keybindListMotors->item(currentRow, 0)
);
});
for (auto system_entry : s_python2_system_info)
{
if (system_entry.bindings == nullptr)
continue;
for (u32 i = 0; i < system_entry.num_bindings; i++)
{
auto entry = system_entry.bindings[i];
if (entry.type != PAD::ControllerBindingType::Motor)
continue;
QListWidgetItem* item = new QListWidgetItem();
item->setText(tr("%1 - %2").arg(QString::fromStdString(system_entry.name)).arg(QString::fromStdString(entry.display_name)));
item->setData(Qt::UserRole, QString::fromStdString(entry.name));
m_ui.motorList->addItem(item);
}
}
m_ui.motorList->setCurrentRow(0);
m_ui.MotorScale->setDisabled(true);
refreshUi();
}
Python2BindingWidget::~Python2BindingWidget() = default;
QIcon Python2BindingWidget::getIcon() const
{
return QIcon::fromTheme("artboard-2-line");
}
void Python2BindingWidget::unbindKeyClicked(QTableWidget* tableWidget)
{
auto currentSelectionRow = tableWidget->currentRow();
auto currentSelectionCol = tableWidget->currentColumn();
if (currentSelectionRow == -1)
return;
for (int i = 0; i < tableWidget->rowCount(); i++)
{
auto selectedItem = tableWidget->item(i, 0);
if (!selectedItem->isSelected())
continue;
uint uniqueId = selectedItem->data(Qt::UserRole).toUInt();
Python2QtInputManager::RemoveMappingByUniqueId(uniqueId);
}
if (currentSelectionRow - 1 >= 0 && currentSelectionRow - 1 < tableWidget->rowCount())
tableWidget->setCurrentCell(currentSelectionRow - 1, currentSelectionCol);
else if (tableWidget->rowCount() > 0)
tableWidget->setCurrentCell(0, currentSelectionCol);
saveAndRefresh();
}
void Python2BindingWidget::onBindKeyMotorClicked()
{
auto full_key = m_ui.motorList->currentItem()->data(Qt::UserRole).toString();
QInputDialog dialog(QtUtils::GetRootWidget(this));
QStringList input_options(m_dialog->getVibrationMotors());
if (input_options.isEmpty())
{
QMessageBox::critical(QtUtils::GetRootWidget(this), tr("Error"), tr("No devices with vibration motors were detected."));
return;
}
QInputDialog input_dialog(this);
input_dialog.setWindowTitle(full_key);
input_dialog.setLabelText(tr("Select vibration motor for %1.").arg(full_key));
input_dialog.setInputMode(QInputDialog::TextInput);
input_dialog.setOptions(QInputDialog::UseListViewForComboBoxItems);
input_dialog.setComboBoxEditable(false);
input_dialog.setComboBoxItems(std::move(input_options));
input_dialog.setTextValue(QString::fromStdString("Test Value"));
if (input_dialog.exec() == 0)
return;
auto new_binding = input_dialog.textValue().toStdString();
double motorScale = 0;
if (QSlider* widget = findChild<QSlider*>(QStringLiteral("MotorScale")); widget)
{
motorScale = static_cast<float>(widget->value()) / static_cast<float>(widget->maximum());
}
if (Python2QtInputManager::AddNewBinding(full_key.toStdString(), new_binding, 0, 0, motorScale)) {
saveAndRefresh();
}
}
void Python2BindingWidget::refreshUi()
{
refreshInputBindingList();
refreshInputAnalogBindingList();
refreshOutputMotorBindingList();
}
void Python2BindingWidget::saveAndRefresh()
{
saveMapping();
refreshUi();
}
std::string Python2BindingWidget::getKeybindDisplayName(std::string keybind)
{
for (auto system_entry : s_python2_system_info)
{
if (system_entry.bindings == nullptr)
continue;
for (u32 i = 0; i < system_entry.num_bindings; i++)
{
if (std::string(system_entry.bindings[i].name) == keybind)
return (tr("%1 - %2").arg(system_entry.name).arg(system_entry.bindings[i].display_name)).toStdString();
}
}
return keybind;
}
void Python2BindingWidget::refreshInputBindingList()
{
m_ui.keybindList->clearContents();
m_ui.keybindList->setSelectionBehavior(QAbstractItemView::SelectRows);
m_ui.keybindList->setAlternatingRowColors(true);
m_ui.keybindList->setShowGrid(false);
m_ui.keybindList->verticalHeader()->hide();
m_ui.keybindList->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
m_ui.keybindList->horizontalHeader()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
m_ui.keybindList->horizontalHeader()->setStretchLastSection(true);
m_ui.keybindList->setRowCount(0);
for (auto &entry : Python2QtInputManager::GetCurrentMappings())
{
if (entry.input_type != PAD::ControllerBindingType::Button)
continue;
const int row = m_ui.keybindList->rowCount();
m_ui.keybindList->insertRow(row);
QTableWidgetItem* item = new QTableWidgetItem();
item->setText(QString::fromStdString(getKeybindDisplayName(entry.keybind)));
item->setFlags(item->flags() & ~(Qt::ItemIsEditable));
item->setData(Qt::UserRole, entry.uniqueId);
m_ui.keybindList->setItem(row, 0, item);
QCheckBox* cb = new QCheckBox(m_ui.keybindList);
cb->setChecked(entry.isOneshot);
connect(cb, &QCheckBox::stateChanged, this, [this, &entry](int state) {
entry.isOneshot = state == Qt::Checked;
saveMapping();
});
QWidget* cbw = new QWidget();
QHBoxLayout* hbox = new QHBoxLayout(cbw);
hbox->addWidget(cb);
hbox->setAlignment(Qt::AlignCenter);
hbox->setContentsMargins(0, 0, 0, 0);
m_ui.keybindList->setCellWidget(row, 1, cbw);
QTableWidgetItem* item2 = new QTableWidgetItem();
item2->setText(QString::fromStdString(entry.inputKey));
item2->setFlags(item->flags() & ~(Qt::ItemIsEditable));
m_ui.keybindList->setItem(row, 2, item2);
}
}
void Python2BindingWidget::refreshInputAnalogBindingList()
{
m_ui.keybindListAnalogs->clearContents();
m_ui.keybindListAnalogs->setSelectionBehavior(QAbstractItemView::SelectRows);
m_ui.keybindListAnalogs->setAlternatingRowColors(true);
m_ui.keybindListAnalogs->setShowGrid(false);
m_ui.keybindListAnalogs->verticalHeader()->hide();
m_ui.keybindListAnalogs->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
m_ui.keybindListAnalogs->horizontalHeader()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
m_ui.keybindListAnalogs->horizontalHeader()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
m_ui.keybindListAnalogs->horizontalHeader()->setStretchLastSection(true);
m_ui.keybindListAnalogs->setRowCount(0);
for (auto entry : Python2QtInputManager::GetCurrentMappings())
{
if (entry.input_type != PAD::ControllerBindingType::Axis && entry.input_type != PAD::ControllerBindingType::HalfAxis)
continue;
const int row = m_ui.keybindListAnalogs->rowCount();
m_ui.keybindListAnalogs->insertRow(row);
QTableWidgetItem* item = new QTableWidgetItem();
item->setText(QString::fromStdString(getKeybindDisplayName(entry.keybind)));
item->setFlags(item->flags() & ~(Qt::ItemIsEditable));
item->setData(Qt::UserRole, entry.uniqueId);
m_ui.keybindListAnalogs->setItem(row, 0, item);
QTableWidgetItem* item2 = new QTableWidgetItem();
item2->setText(tr("%1%").arg(entry.analogDeadzone * 100));
item2->setData(Qt::UserRole, entry.analogDeadzone);
item2->setFlags(item->flags() & ~(Qt::ItemIsEditable));
m_ui.keybindListAnalogs->setItem(row, 1, item2);
QTableWidgetItem* item3 = new QTableWidgetItem();
item3->setText(tr("%1%").arg(entry.analogSensitivity * 100));
item3->setData(Qt::UserRole, entry.analogSensitivity);
item3->setFlags(item->flags() & ~(Qt::ItemIsEditable));
m_ui.keybindListAnalogs->setItem(row, 2, item3);
QTableWidgetItem* item4 = new QTableWidgetItem();
item4->setText(QString::fromStdString(entry.inputKey));
item4->setFlags(item->flags() & ~(Qt::ItemIsEditable));
m_ui.keybindListAnalogs->setItem(row, 3, item4);
}
}
void Python2BindingWidget::refreshOutputMotorBindingList()
{
m_ui.keybindListMotors->clearContents();
m_ui.keybindListMotors->setSelectionBehavior(QAbstractItemView::SelectRows);
m_ui.keybindListMotors->setAlternatingRowColors(true);
m_ui.keybindListMotors->setShowGrid(false);
m_ui.keybindListMotors->verticalHeader()->hide();
m_ui.keybindListMotors->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
m_ui.keybindListMotors->horizontalHeader()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
m_ui.keybindListMotors->horizontalHeader()->setStretchLastSection(true);
m_ui.keybindListMotors->setRowCount(0);
for (auto entry : Python2QtInputManager::GetCurrentMappings())
{
if (entry.input_type != PAD::ControllerBindingType::Motor)
continue;
const int row = m_ui.keybindListMotors->rowCount();
m_ui.keybindListMotors->insertRow(row);
QTableWidgetItem* item = new QTableWidgetItem();
item->setText(QString::fromStdString(getKeybindDisplayName(entry.keybind)));
item->setFlags(item->flags() & ~(Qt::ItemIsEditable));
item->setData(Qt::UserRole, entry.uniqueId);
m_ui.keybindListMotors->setItem(row, 0, item);
QTableWidgetItem* item2 = new QTableWidgetItem();
item2->setText(tr("%1%").arg(entry.motorScale * 100));
item2->setData(Qt::UserRole, entry.motorScale);
item2->setFlags(item->flags() & ~(Qt::ItemIsEditable));
m_ui.keybindListMotors->setItem(row, 1, item2);
QTableWidgetItem* item3 = new QTableWidgetItem();
item3->setText(QString::fromStdString(entry.inputKey));
item3->setFlags(item->flags() & ~(Qt::ItemIsEditable));
m_ui.keybindListMotors->setItem(row, 2, item3);
}
}
void Python2BindingWidget::onInputListenTimerTimeout()
{
m_input_listen_remaining_seconds--;
if (m_input_listen_remaining_seconds == 0)
{
stopListeningForInput();
return;
}
if (m_input_listen_analog)
{
m_ui.bindKeyAnalog->setText(tr("Press axis button... [%1]").arg(m_input_listen_remaining_seconds));
}
else
{
m_ui.bindKey->setText(tr("Press button... [%1]").arg(m_input_listen_remaining_seconds));
}
}
void Python2BindingWidget::startListeningForInput(u32 timeout_in_seconds, bool isAnalog)
{
if (isListeningForInput())
stopListeningForInput();
m_new_bindings.clear();
m_input_listen_analog = isAnalog;
m_input_listen_timer = new QTimer(this);
m_input_listen_timer->setSingleShot(false);
m_input_listen_timer->start(1000);
m_input_listen_timer->connect(m_input_listen_timer, &QTimer::timeout, this, &Python2BindingWidget::onInputListenTimerTimeout);
m_input_listen_remaining_seconds = timeout_in_seconds;
if (m_input_listen_analog)
{
m_ui.bindKeyAnalog->setText(tr("Press axis button... [%1]").arg(m_input_listen_remaining_seconds));
}
else
{
m_ui.bindKey->setText(tr("Press button... [%1]").arg(m_input_listen_remaining_seconds));
}
installEventFilter(this);
grabKeyboard();
grabMouse();
setMouseTracking(true);
hookInputManager();
}
void Python2BindingWidget::stopListeningForInput()
{
delete m_input_listen_timer;
m_input_listen_timer = nullptr;
std::vector<InputBindingKey>().swap(m_new_bindings);
unhookInputManager();
setMouseTracking(false);
releaseMouse();
releaseKeyboard();
removeEventFilter(this);
if (m_input_listen_analog)
{
m_ui.bindKeyAnalog->setText(tr("Bind"));
}
else
{
m_ui.bindKey->setText(tr("Bind"));
}
}
void Python2BindingWidget::inputManagerHookCallback(InputBindingKey key, float value)
{
const float abs_value = std::abs(value);
if (m_input_listen_analog && key.source_subtype != InputSubclass::PointerAxis && key.source_subtype != InputSubclass::ControllerAxis)
return;
for (InputBindingKey other_key : m_new_bindings)
{
if (other_key.MaskDirection() == key.MaskDirection())
{
if (abs_value < 0.5f)
{
// if this key is in our new binding list, it's a "release", and we're done
setNewInputBinding();
stopListeningForInput();
return;
}
// otherwise, keep waiting
return;
}
}
// new binding, add it to the list, but wait for a decent distance first, and then wait for release
if (abs_value >= 0.5f)
{
InputBindingKey key_to_add = key;
m_new_bindings.push_back(key_to_add);
}
}
void Python2BindingWidget::hookInputManager()
{
InputManager::SetHook([this](InputBindingKey key, float value) {
QMetaObject::invokeMethod(this, "inputManagerHookCallback", Qt::QueuedConnection, Q_ARG(InputBindingKey, key),
Q_ARG(float, value));
return InputInterceptHook::CallbackResult::StopProcessingEvent;
});
}
void Python2BindingWidget::unhookInputManager()
{
InputManager::RemoveHook();
}
bool Python2BindingWidget::eventFilter(QObject* watched, QEvent* event)
{
if (m_input_listen_analog)
return false;
const QEvent::Type event_type = event->type();
// if the key is being released, set the input
if (event_type == QEvent::KeyRelease || event_type == QEvent::MouseButtonRelease)
{
setNewInputBinding();
stopListeningForInput();
return true;
}
else if (event_type == QEvent::KeyPress)
{
const QKeyEvent* key_event = static_cast<const QKeyEvent*>(event);
m_new_bindings.push_back(InputManager::MakeHostKeyboardKey(QtUtils::KeyEventToCode(key_event)));
return true;
}
else if (event_type == QEvent::MouseButtonPress || event_type == QEvent::MouseButtonDblClick)
{
// double clicks get triggered if we click bind, then click again quickly.
unsigned long button_index;
if (_BitScanForward(&button_index, static_cast<u32>(static_cast<const QMouseEvent*>(event)->button())))
m_new_bindings.push_back(InputManager::MakePointerButtonKey(0, button_index));
return true;
}
else if (event_type == QEvent::Wheel)
{
const QPoint delta_angle(static_cast<QWheelEvent*>(event)->angleDelta());
const float dx = std::clamp(static_cast<float>(delta_angle.x()) / QtUtils::MOUSE_WHEEL_DELTA, -1.0f, 1.0f);
if (dx != 0.0f)
{
InputBindingKey key(InputManager::MakePointerAxisKey(0, InputPointerAxis::WheelX));
key.negative = (dx < 0.0f);
m_new_bindings.push_back(key);
}
const float dy = std::clamp(static_cast<float>(delta_angle.y()) / QtUtils::MOUSE_WHEEL_DELTA, -1.0f, 1.0f);
if (dy != 0.0f)
{
InputBindingKey key(InputManager::MakePointerAxisKey(0, InputPointerAxis::WheelY));
key.negative = (dy < 0.0f);
m_new_bindings.push_back(key);
}
if (dx != 0.0f || dy != 0.0f)
{
setNewInputBinding();
stopListeningForInput();
}
return true;
}
return false;
}
void Python2BindingWidget::setNewInputBinding()
{
if (m_new_bindings.empty())
return;
const std::string new_binding(InputManager::ConvertInputBindingKeysToString(m_new_bindings.data(), m_new_bindings.size()));
std::string full_key;
float analogDeadzone = 0;
float analogSensitivity = 0;
if (m_input_listen_analog)
{
full_key = m_ui.inputListAnalogs->currentItem()->data(Qt::UserRole).toString().toStdString();
if (QSlider* widget = findChild<QSlider*>(QStringLiteral("Deadzone")); widget)
{
analogDeadzone = static_cast<float>(widget->value()) / static_cast<float>(widget->maximum());
}
if (QSlider* widget = findChild<QSlider*>(QStringLiteral("AxisScale")); widget)
{
analogSensitivity = static_cast<float>(widget->value()) / static_cast<float>(widget->maximum());
}
}
else
{
full_key = m_ui.inputList->currentItem()->data(Qt::UserRole).toString().toStdString();
}
if (Python2QtInputManager::AddNewBinding(full_key, new_binding, analogDeadzone, analogSensitivity, 0)) {
saveAndRefresh();
}
}
void Python2BindingWidget::saveMapping()
{
auto lock = Host::GetSettingsLock();
SettingsInterface* si = Host::Internal::GetBaseSettingsLayer();
const std::string section = "Python2";
// Clear all keybinds in Python2 section
si->ClearSection(section.c_str());
// Recreate Python2 section
for (auto entry : Python2QtInputManager::GetCurrentMappings())
{
if (entry.input_type == PAD::ControllerBindingType::Button)
{
si->AddToStringList(
section.c_str(),
entry.keybind.c_str(),
StringUtil::StdStringFromFormat("%s|%d", entry.inputKey.c_str(), entry.isOneshot).c_str()
);
}
else if (entry.input_type == PAD::ControllerBindingType::Axis || entry.input_type == PAD::ControllerBindingType::HalfAxis)
{
si->AddToStringList(
section.c_str(),
entry.keybind.c_str(),
StringUtil::StdStringFromFormat("%s|%lf|%lf", entry.inputKey.c_str(), entry.analogDeadzone, entry.analogSensitivity).c_str()
);
}
else if (entry.input_type == PAD::ControllerBindingType::Motor)
{
si->AddToStringList(
section.c_str(),
entry.keybind.c_str(),
StringUtil::StdStringFromFormat("%s|%lf", entry.inputKey.c_str(), entry.motorScale).c_str()
);
}
}
QtHost::QueueSettingsSave();
}

View File

@ -0,0 +1,86 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team, 987123879113
*
* 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/>.
*/
#pragma once
#include <QtWidgets/QWidget>
#include "ui_Python2BindingWidget.h"
#include "pcsx2/Frontend/InputManager.h"
class InputBindingWidget;
class ControllerSettingsDialog;
struct Python2KeyMapping;
class Python2BindingWidget final : public QWidget
{
Q_OBJECT
public:
Python2BindingWidget(QWidget* parent, ControllerSettingsDialog* dialog);
~Python2BindingWidget();
QIcon getIcon() const;
__fi ControllerSettingsDialog* getDialog() const { return m_dialog; }
private Q_SLOTS:
void unbindKeyClicked(QTableWidget *tableWidget);
void onBindKeyMotorClicked();
void onInputListenTimerTimeout();
void inputManagerHookCallback(InputBindingKey key, float value);
protected:
enum : u32
{
TIMEOUT_FOR_SINGLE_BINDING = 5
};
void refreshUi();
void saveAndRefresh();
void refreshInputBindingList();
void refreshInputAnalogBindingList();
void refreshOutputMotorBindingList();
virtual bool eventFilter(QObject* watched, QEvent* event) override;
virtual void startListeningForInput(u32 timeout_in_seconds, bool isAnalog);
virtual void stopListeningForInput();
bool isListeningForInput() const { return m_input_listen_timer != nullptr; }
void setNewInputBinding();
void hookInputManager();
void unhookInputManager();
void saveMapping();
std::string getKeybindDisplayName(std::string keybind);
Ui::Python2BindingWidget m_ui;
ControllerSettingsDialog* m_dialog;
std::vector<std::string> m_bindings;
std::vector<InputBindingKey> m_new_bindings;
QTimer* m_input_listen_timer = nullptr;
u32 m_input_listen_remaining_seconds = 0;
bool m_input_listen_analog = false;
};

View File

@ -0,0 +1,346 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Python2BindingWidget</class>
<widget class="QWidget" name="Python2BindingWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>833</width>
<height>560</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QTabWidget" name="inputsTabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<property name="documentMode">
<bool>true</bool>
</property>
<widget class="QWidget" name="tabInputs">
<attribute name="title">
<string>Inputs</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout2">
<item>
<widget class="QGroupBox" name="groupBox3">
<property name="title">
<string>Game Type Filter</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout2">
<item>
<widget class="QComboBox" name="gameTypeFilter" />
</item>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item row="0" column="0" rowspan="6">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Available Inputs</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2">
<widget class="QListWidget" name="inputList" />
</item>
<item row="1" column="0" colspan="2">
<widget class="QPushButton" name="bindKey">
<property name="text">
<string>Bind</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="6" rowspan="6">
<widget class="QGroupBox" name="groupBox2">
<property name="title">
<string>Existing Keybinds</string>
</property>
<layout class="QGridLayout" name="gridLayout2">
<item row="0" column="0" colspan="2">
<widget class="QTableWidget" name="keybindList">
<column>
<property name="text">
<string>Keybind</string>
</property>
</column>
<column>
<property name="text">
<string>Oneshot</string>
</property>
</column>
<column>
<property name="text">
<string>Device</string>
</property>
</column>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QPushButton" name="unbindKey">
<property name="text">
<string>Unbind</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabAnalogInputs">
<attribute name="title">
<string>Analog Inputs</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout4">
<item>
<layout class="QHBoxLayout" name="horizontalLayout3">
<item row="0" column="0" rowspan="6">
<widget class="QGroupBox" name="groupBox4">
<property name="title">
<string>Available Analog Inputs</string>
</property>
<layout class="QGridLayout" name="gridLayout3">
<item row="0" column="0" colspan="2">
<widget class="QListWidget" name="inputListAnalogs" />
</item>
<item row="1" column="0" colspan="2">
<widget class="QPushButton" name="bindKeyAnalog">
<property name="text">
<string>Bind</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="6" rowspan="6">
<widget class="QGroupBox" name="groupBox5">
<property name="title">
<string>Existing Keybinds</string>
</property>
<layout class="QGridLayout" name="gridLayout4">
<item row="0" column="0" colspan="2">
<widget class="QTableWidget" name="keybindListAnalogs">
<column>
<property name="text">
<string>Keybind</string>
</property>
</column>
<column>
<property name="text">
<string>Deadzone</string>
</property>
</column>
<column>
<property name="text">
<string>Sensitivity</string>
</property>
</column>
<column>
<property name="text">
<string>Device</string>
</property>
</column>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QPushButton" name="unbindKeyAnalog">
<property name="text">
<string>Unbind</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout5">
<item row="0" column="0" colspan="2">
<widget class="QGroupBox" name="groupBox_33">
<property name="title">
<string>Analog Deadzone</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QSlider" name="Deadzone">
<property name="maximum">
<number>100</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="DeadzoneLabel">
<property name="text">
<string>0%</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="2" colspan="2">
<widget class="QGroupBox" name="groupBox_30">
<property name="title">
<string>Analog Sensitivity</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QSlider" name="AxisScale">
<property name="maximum">
<number>200</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="AxisScaleLabel">
<property name="text">
<string>100%</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabMotors">
<attribute name="title">
<string>Motors</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout3">
<item>
<layout class="QHBoxLayout" name="horizontalLayout4">
<item row="0" column="0" rowspan="6">
<widget class="QGroupBox" name="groupBox6">
<property name="title">
<string>Available Motor Outputs</string>
</property>
<layout class="QGridLayout" name="gridLayout5">
<item row="0" column="0" colspan="2">
<widget class="QListWidget" name="motorList" />
</item>
<item row="1" column="0" colspan="2">
<widget class="QPushButton" name="bindKeyMotor">
<property name="text">
<string>Bind</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="6" rowspan="6">
<widget class="QGroupBox" name="groupBox7">
<property name="title">
<string>Existing Keybinds</string>
</property>
<layout class="QGridLayout" name="gridLayout6">
<item row="0" column="0" colspan="2">
<widget class="QTableWidget" name="keybindListMotors">
<column>
<property name="text">
<string>Keybind</string>
</property>
</column>
<column>
<property name="text">
<string>Scale</string>
</property>
</column>
<column>
<property name="text">
<string>Device</string>
</property>
</column>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QPushButton" name="unbindKeyMotor">
<property name="text">
<string>Unbind</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="groupBox_31">
<property name="title">
<string>Motor Scale</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QSlider" name="MotorScale">
<property name="maximum">
<number>100</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="MotorScaleLabel">
<property name="text">
<string>100%</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../resources/resources.qrc" />
</resources>
<connections />
</ui>

View File

@ -0,0 +1,192 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* 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/>.
*/
#include "PrecompiledHeader.h"
#include "common/StringUtil.h"
#include "Frontend/GameList.h"
#include "PAD/Host/PAD.h"
#include "Python2SettingsWidget.h"
#include "SettingWidgetBinder.h"
#include "SettingsDialog.h"
#include "QtHost.h"
Python2SettingsWidget::Python2SettingsWidget(const GameList::Entry* entry, SettingsDialog* dialog, QWidget* parent)
: m_dialog(dialog)
{
SettingsInterface* sif = dialog->getSettingsInterface();
m_ui.setupUi(this);
const int gameTypeId = m_dialog->getIntValue("Python2/Game", "GameType", 0).value();
connect(m_ui.gameType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &Python2SettingsWidget::onGameTypeChanged);
m_ui.gameType->setCurrentIndex(gameTypeId);
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.hddIdPath, "DEV9/Hdd", "HddIdFile", "HDD_ID.bin");
m_ui.hddIdPath->setEnabled(true);
connect(m_ui.hddIdBrowse, &QPushButton::clicked, this, &Python2SettingsWidget::onHddIdBrowseClicked);
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.ilinkIdPath, "Python2/System", "IlinkIdFile", "ILINK_ID.bin");
m_ui.ilinkIdPath->setEnabled(true);
connect(m_ui.ilinkIdBrowse, &QPushButton::clicked, this, &Python2SettingsWidget::onIlinkIdBrowseClicked);
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.dongleBlackPath, "Python2/Game", "DongleBlackFile", "dongle_black.bin");
m_ui.dongleBlackPath->setEnabled(true);
connect(m_ui.dongleBlackBrowse, &QPushButton::clicked, this, &Python2SettingsWidget::onDongleBlackBrowseClicked);
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.dongleWhitePath, "Python2/Game", "DongleWhiteFile", "dongle_white.bin");
m_ui.dongleWhitePath->setEnabled(true);
connect(m_ui.dongleWhiteBrowse, &QPushButton::clicked, this, &Python2SettingsWidget::onDongleWhiteBrowseClicked);
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.player1CardPath, "Python2/Game", "Player1CardFile", "card1.txt");
m_ui.player1CardPath->setEnabled(true);
connect(m_ui.player1CardBrowse, &QPushButton::clicked, this, &Python2SettingsWidget::onPlayer1CardBrowseClicked);
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.player2CardPath, "Python2/Game", "Player2CardFile", "card2.txt");
m_ui.player2CardPath->setEnabled(true);
connect(m_ui.player2CardBrowse, &QPushButton::clicked, this, &Python2SettingsWidget::onPlayer2CardBrowseClicked);
// Nullable bools are weird so don't use BindWidgetToBoolSetting
const bool dipsw1Value = m_dialog->getBoolValue("Python2/Game", "DIPSW1", false).value();
connect(m_ui.dipsw1, QOverload<int>::of(&QCheckBox::stateChanged), this, [&](int state) { m_dialog->setBoolSettingValue("Python2/Game", "DIPSW1", state); });
m_ui.dipsw1->setCheckState(dipsw1Value ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
const bool dipsw2Value = m_dialog->getBoolValue("Python2/Game", "DIPSW2", false).value();
connect(m_ui.dipsw2, QOverload<int>::of(&QCheckBox::stateChanged), this, [&](int state) { m_dialog->setBoolSettingValue("Python2/Game", "DIPSW2", state); });
m_ui.dipsw2->setCheckState(dipsw2Value ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
const bool dipsw3Value = m_dialog->getBoolValue("Python2/Game", "DIPSW3", false).value();
connect(m_ui.dipsw3, QOverload<int>::of(&QCheckBox::stateChanged), this, [&](int state) { m_dialog->setBoolSettingValue("Python2/Game", "DIPSW3", state); });
m_ui.dipsw3->setCheckState(dipsw3Value ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
const bool dipsw4Value = m_dialog->getBoolValue("Python2/Game", "DIPSW4", false).value();
connect(m_ui.dipsw4, QOverload<int>::of(&QCheckBox::stateChanged), this, [&](int state) { m_dialog->setBoolSettingValue("Python2/Game", "DIPSW4", state); });
m_ui.dipsw4->setCheckState(dipsw4Value ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
const bool force31kHzValue = m_dialog->getBoolValue("Python2/Game", "Force31kHz", false).value();
connect(m_ui.force31khz, QOverload<int>::of(&QCheckBox::stateChanged), this, [&](int state) { m_dialog->setBoolSettingValue("Python2/Game", "Force31kHz", state); });
m_ui.force31khz->setCheckState(force31kHzValue ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.patchFilePath, "Python2/Game", "PatchFile", "patches.pnach");
m_ui.patchFilePath->setEnabled(true);
connect(m_ui.patchFileBrowse, &QPushButton::clicked, this, &Python2SettingsWidget::onPatchFileBrowseClicked);
}
void Python2SettingsWidget::onGameTypeChanged(int index)
{
m_dialog->setIntSettingValue("Python2/Game", "GameType", index);
}
void Python2SettingsWidget::onHddIdBrowseClicked()
{
QString path =
QDir::toNativeSeparators(QFileDialog::getOpenFileName(QtUtils::GetRootWidget(this), tr("HDD ID File"),
!m_ui.hddIdPath->text().isEmpty() ? m_ui.hddIdPath->text() : "HDD_ID.bin", tr("BIN (*.bin)"), nullptr,
QFileDialog::DontConfirmOverwrite));
if (path.isEmpty())
return;
m_ui.hddIdPath->setText(path);
m_ui.hddIdPath->editingFinished();
}
void Python2SettingsWidget::onIlinkIdBrowseClicked()
{
QString path =
QDir::toNativeSeparators(QFileDialog::getOpenFileName(QtUtils::GetRootWidget(this), tr("ILINK ID File"),
!m_ui.ilinkIdPath->text().isEmpty() ? m_ui.ilinkIdPath->text() : "ILINK_ID.bin", tr("BIN (*.bin)"), nullptr,
QFileDialog::DontConfirmOverwrite));
if (path.isEmpty())
return;
m_ui.ilinkIdPath->setText(path);
m_ui.ilinkIdPath->editingFinished();
}
void Python2SettingsWidget::onDongleBlackBrowseClicked()
{
QString path =
QDir::toNativeSeparators(QFileDialog::getOpenFileName(QtUtils::GetRootWidget(this), tr("Dongle File"),
!m_ui.dongleBlackPath->text().isEmpty() ? m_ui.dongleBlackPath->text() : "dongle_black.bin", tr("BIN (*.bin)"), nullptr,
QFileDialog::DontConfirmOverwrite));
if (path.isEmpty())
return;
m_ui.dongleBlackPath->setText(path);
m_ui.dongleBlackPath->editingFinished();
}
void Python2SettingsWidget::onDongleWhiteBrowseClicked()
{
QString path =
QDir::toNativeSeparators(QFileDialog::getOpenFileName(QtUtils::GetRootWidget(this), tr("Dongle File"),
!m_ui.dongleWhitePath->text().isEmpty() ? m_ui.dongleWhitePath->text() : "dongle_white.bin", tr("BIN (*.bin)"), nullptr,
QFileDialog::DontConfirmOverwrite));
if (path.isEmpty())
return;
m_ui.dongleWhitePath->setText(path);
m_ui.dongleWhitePath->editingFinished();
}
void Python2SettingsWidget::onPatchFileBrowseClicked()
{
QString path =
QDir::toNativeSeparators(QFileDialog::getOpenFileName(QtUtils::GetRootWidget(this), tr("Patch File"),
!m_ui.patchFilePath->text().isEmpty() ? m_ui.patchFilePath->text() : "patches.pnach", tr("Patch (*.pnach)"), nullptr,
QFileDialog::DontConfirmOverwrite));
if (path.isEmpty())
return;
m_ui.patchFilePath->setText(path);
m_ui.patchFilePath->editingFinished();
}
void Python2SettingsWidget::onPlayer1CardBrowseClicked()
{
QString path =
QDir::toNativeSeparators(QFileDialog::getOpenFileName(QtUtils::GetRootWidget(this), tr("Card File"),
!m_ui.player1CardPath->text().isEmpty() ? m_ui.player1CardPath->text() : "card1.txt", nullptr, nullptr,
QFileDialog::DontConfirmOverwrite));
if (path.isEmpty())
return;
m_ui.player1CardPath->setText(path);
m_ui.player1CardPath->editingFinished();
}
void Python2SettingsWidget::onPlayer2CardBrowseClicked()
{
QString path =
QDir::toNativeSeparators(QFileDialog::getOpenFileName(QtUtils::GetRootWidget(this), tr("Card File"),
!m_ui.player2CardPath->text().isEmpty() ? m_ui.player2CardPath->text() : "card2.txt", nullptr, nullptr,
QFileDialog::DontConfirmOverwrite));
if (path.isEmpty())
return;
m_ui.player2CardPath->setText(path);
m_ui.player2CardPath->editingFinished();
}
Python2SettingsWidget::~Python2SettingsWidget() = default;

View File

@ -0,0 +1,50 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* 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/>.
*/
#pragma once
#include <QtWidgets/QWidget>
#include "ui_Python2SettingsWidget.h"
namespace GameList
{
struct Entry;
}
class SettingsDialog;
class Python2SettingsWidget : public QWidget
{
Q_OBJECT
private Q_SLOTS:
void onGameTypeChanged(int index);
void onHddIdBrowseClicked();
void onIlinkIdBrowseClicked();
void onDongleBlackBrowseClicked();
void onDongleWhiteBrowseClicked();
void onPatchFileBrowseClicked();
void onPlayer1CardBrowseClicked();
void onPlayer2CardBrowseClicked();
public:
Python2SettingsWidget(const GameList::Entry* entry, SettingsDialog* dialog, QWidget* parent);
~Python2SettingsWidget();
private:
Ui::Python2SettingsWidget m_ui;
SettingsDialog* m_dialog;
};

View File

@ -0,0 +1,281 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Python2SettingsWidget</class>
<widget class="QWidget" name="Python2SettingsWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>692</width>
<height>562</height>
</rect>
</property>
<layout class="QFormLayout" name="formLayout">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::ExpandingFieldsGrow</enum>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_1">
<property name="text">
<string>Game Type:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="gameType">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="editable">
<bool>true</bool>
</property>
<item>
<property name="text">
<string>Drummania</string>
</property>
</item>
<item>
<property name="text">
<string>Guitar Freaks</string>
</property>
</item>
<item>
<property name="text">
<string>Dance Dance Revolution</string>
</property>
</item>
<item>
<property name="text">
<string>Toy's March</string>
</property>
</item>
<item>
<property name="text">
<string>Thrill Drive 3</string>
</property>
</item>
<item>
<property name="text">
<string>Dance 86.4</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0" colspan="3">
<layout class="QGridLayout" name="gridLayout_3_1">
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>HDD ID Path:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="hddIdPath" />
</item>
<item row="0" column="2">
<widget class="QPushButton" name="hddIdBrowse">
<property name="text">
<string>Browse</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0" colspan="3">
<layout class="QGridLayout" name="gridLayout_3_2">
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>ILINK ID Path:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="ilinkIdPath" />
</item>
<item row="0" column="2">
<widget class="QPushButton" name="ilinkIdBrowse">
<property name="text">
<string>Browse</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="0" colspan="3">
<layout class="QGridLayout" name="gridLayout_3_3">
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Black Dongle Path:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="dongleBlackPath" />
</item>
<item row="0" column="2">
<widget class="QPushButton" name="dongleBlackBrowse">
<property name="text">
<string>Browse</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="4" column="0" colspan="3">
<layout class="QGridLayout" name="gridLayout_3_4">
<item row="0" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>White Dongle Path:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="dongleWhitePath" />
</item>
<item row="0" column="2">
<widget class="QPushButton" name="dongleWhiteBrowse">
<property name="text">
<string>Browse</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Dipswitches:</string>
</property>
</widget>
</item>
<item row="5" column="1" colspan="4">
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<widget class="QCheckBox" name="dipsw1">
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="dipsw2">
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QCheckBox" name="dipsw3">
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QCheckBox" name="dipsw4">
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Force 31kHz:</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QCheckBox" name="force31khz" />
</item>
<item row="7" column="0" colspan="3">
<layout class="QGridLayout" name="gridLayout_3_5">
<item row="0" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Patch File:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="patchFilePath" />
</item>
<item row="0" column="2">
<widget class="QPushButton" name="patchFileBrowse">
<property name="text">
<string>Browse</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="8" column="0" colspan="3">
<layout class="QGridLayout" name="gridLayout_3_6">
<item row="0" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>P1 Card Path:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="player1CardPath" />
</item>
<item row="0" column="2">
<widget class="QPushButton" name="player1CardBrowse">
<property name="text">
<string>Browse</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="9" column="0" colspan="3">
<layout class="QGridLayout" name="gridLayout_3_7">
<item row="0" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>P2 Card Path:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="player2CardPath" />
</item>
<item row="0" column="2">
<widget class="QPushButton" name="player2CardBrowse">
<property name="text">
<string>Browse</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources>
<include location="../resources/resources.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -43,6 +43,7 @@
#include "InterfaceSettingsWidget.h"
#include "MemoryCardSettingsWidget.h"
#include "SystemSettingsWidget.h"
#include "Python2SettingsWidget.h"
#include <QtWidgets/QMessageBox>
#include <QtWidgets/QTextEdit>
@ -128,7 +129,7 @@ void SettingsDialog::setupUi(const GameList::Entry* game)
addWidget(m_memory_card_settings = new MemoryCardSettingsWidget(this, m_ui.settingsContainer), tr("Memory Cards"),
QStringLiteral("sd-card-line"), tr("<strong>Memory Card Settings</strong><hr>Create and configure Memory Cards here.<br><br>Mouse over an option for additional information."));
}
addWidget(m_dev9_settings = new DEV9SettingsWidget(this, m_ui.settingsContainer), tr("Network & HDD"), QStringLiteral("dashboard-line"),
tr("<strong>Network & HDD Settings</strong><hr>These options control the network connectivity and internal HDD storage of the console.<br><br>"
"Mouse over an option for additional information."));
@ -139,6 +140,11 @@ void SettingsDialog::setupUi(const GameList::Entry* game)
tr("<strong>Folder Settings</strong><hr>These options control where PCSX2 will save runtime data files."));
}
if (isPerGameSettings() && game->type == GameList::EntryType::Python2) {
addWidget(m_python2_settings = new Python2SettingsWidget(game, this, m_ui.settingsContainer), tr("Python 2"), QStringLiteral("dashboard-line"),
tr("<strong>Python 2 Settings</strong><hr>These options control the settings specific to Python 2 games."));
}
m_ui.settingsCategory->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
m_ui.settingsCategory->setCurrentRow(0);
m_ui.settingsContainer->setCurrentIndex(0);

View File

@ -41,6 +41,7 @@ class AudioSettingsWidget;
class MemoryCardSettingsWidget;
class FolderSettingsWidget;
class DEV9SettingsWidget;
class Python2SettingsWidget;
class SettingsDialog final : public QDialog
{
@ -68,6 +69,7 @@ public:
__fi MemoryCardSettingsWidget* getMemoryCardSettingsWidget() const { return m_memory_card_settings; }
__fi FolderSettingsWidget* getFolderSettingsWidget() const { return m_folder_settings; }
__fi DEV9SettingsWidget* getDEV9SettingsWidget() const { return m_dev9_settings; }
__fi Python2SettingsWidget* getPython2SettingsWidget() const { return m_python2_settings; }
void registerWidgetHelp(QObject* object, QString title, QString recommended_value, QString text);
bool eventFilter(QObject* object, QEvent* event) override;
@ -126,6 +128,7 @@ private:
MemoryCardSettingsWidget* m_memory_card_settings = nullptr;
FolderSettingsWidget* m_folder_settings = nullptr;
DEV9SettingsWidget* m_dev9_settings = nullptr;
Python2SettingsWidget* m_python2_settings = nullptr;
std::array<QString, MAX_SETTINGS_WIDGETS> m_category_help_text;

View File

@ -129,6 +129,9 @@
<ProjectReference Include="..\3rdparty\lzma\lzma.vcxproj">
<Project>{a4323327-3f2b-4271-83d9-7f9a3c66b6b2}</Project>
</ProjectReference>
<ProjectReference Include="..\3rdparty\libusb\libusb.vcxproj">
<Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Manifest Include="..\pcsx2\windows\PCSX2.manifest" />
@ -160,6 +163,8 @@
<ClCompile Include="Settings\DEV9UiCommon.cpp" />
<ClCompile Include="Settings\HddCreateQt.cpp" />
<ClCompile Include="Settings\GameSummaryWidget.cpp" />
<ClCompile Include="Settings\Python2BindingWidget.cpp" />
<ClCompile Include="Settings\Python2SettingsWidget.cpp" />
<ClCompile Include="GameList\GameListModel.cpp" />
<ClCompile Include="GameList\GameListRefreshThread.cpp" />
<ClCompile Include="GameList\GameListWidget.cpp" />
@ -199,6 +204,8 @@
<ClInclude Include="Settings\HddCreateQt.h" />
<QtMoc Include="Settings\GameSummaryWidget.h" />
<QtMoc Include="Settings\CreateMemoryCardDialog.h" />
<QtMoc Include="Settings\Python2BindingWidget.h" />
<QtMoc Include="Settings\Python2SettingsWidget.h" />
<QtMoc Include="GameList\GameListModel.h" />
<QtMoc Include="GameList\GameListWidget.h" />
<QtMoc Include="GameList\GameListRefreshThread.h" />
@ -244,6 +251,8 @@
<ClCompile Include="$(IntDir)Settings\moc_DEV9SettingsWidget.cpp" />
<ClCompile Include="$(IntDir)Settings\moc_DEV9UiCommon.cpp" />
<ClCompile Include="$(IntDir)Settings\moc_GameSummaryWidget.cpp" />
<ClCompile Include="$(IntDir)Settings\moc_Python2BindingWidget.cpp" />
<ClCompile Include="$(IntDir)Settings\moc_Python2SettingsWidget.cpp" />
<ClCompile Include="$(IntDir)GameList\moc_GameListModel.cpp" />
<ClCompile Include="$(IntDir)GameList\moc_GameListRefreshThread.cpp" />
<ClCompile Include="$(IntDir)GameList\moc_GameListWidget.cpp" />
@ -327,6 +336,12 @@
<QtUi Include="Settings\GameSummaryWidget.ui">
<FileType>Document</FileType>
</QtUi>
<QtUi Include="Settings\Python2BindingWidget.ui">
<FileType>Document</FileType>
</QtUi>
<QtUi Include="Settings\Python2SettingsWidget.ui">
<FileType>Document</FileType>
</QtUi>
<QtUi Include="AutoUpdaterDialog.ui">
<FileType>Document</FileType>
</QtUi>

View File

@ -205,6 +205,12 @@
<ClCompile Include="Settings\HddCreateQt.cpp">
<Filter>Settings</Filter>
</ClCompile>
<ClCompile Include="Settings\Python2SettingsWidget.cpp">
<Filter>Settings</Filter>
</ClCompile>
<ClCompile Include="Settings\Python2BindingWidget.cpp">
<Filter>Settings</Filter>
</ClCompile>
<ClCompile Include="AutoUpdaterDialog.cpp" />
<ClCompile Include="$(IntDir)moc_AutoUpdaterDialog.cpp">
<Filter>moc</Filter>
@ -236,6 +242,12 @@
<ClInclude Include="Settings\HddCreateQt.h">
<Filter>Settings</Filter>
</ClInclude>
<ClInclude Include="Settings\Python2SettingsWidget.h">
<Filter>Settings</Filter>
</ClInclude>
<ClInclude Include="Settings\Python2BindingWidget.h">
<Filter>Settings</Filter>
</ClInclude>
<ClInclude Include="Settings\ControllerSettingWidgetBinder.h">
<Filter>Settings</Filter>
</ClInclude>
@ -395,6 +407,12 @@
<QtUi Include="Settings\DEV9SettingsWidget.ui">
<Filter>Settings</Filter>
</QtUi>
<QtUi Include="Settings\Python2SettingsWidget.ui">
<Filter>Settings</Filter>
</QtUi>
<QtUi Include="Settings\Python2BindingWidget.ui">
<Filter>Settings</Filter>
</QtUi>
<QtUi Include="GameList\EmptyGameListWidget.ui">
<Filter>GameList</Filter>
</QtUi>

View File

@ -484,13 +484,44 @@ set(pcsx2USBSources
USB/usb-python2/devices/thrilldrive_belt.cpp
USB/usb-python2/devices/thrilldrive_handle.cpp
USB/usb-python2/devices/toysmarch_drumpad.cpp
USB/usb-python2/passthrough/python2-config-passthrough.cpp
USB/usb-python2/passthrough/usb-python2-passthrough.cpp
USB/usb-python2/inputs/passthrough/python2-config-passthrough.cpp
USB/usb-python2/inputs/passthrough/usb-python2-passthrough.cpp
USB/usb-python2/patches.cpp
USB/usb-python2/api_init_linux.cpp
USB/usb-printer/usb-printer.cpp
)
set(pcsx2USBSourcesQt
USB/USB.cpp
USB/deviceproxy.cpp
USB/device_init.cpp
USB/qemu-usb/glib.cpp
USB/qemu-usb/vl.cpp
USB/qemu-usb/iov.cpp
USB/qemu-usb/desc.cpp
USB/qemu-usb/core.cpp
USB/qemu-usb/bus.cpp
USB/qemu-usb/usb-ohci.cpp
USB/qemu-usb/hid.cpp
USB/qemu-usb/input-keymap-qcode-to-qnum.cpp
USB/usb-hid/usb-hid.cpp
USB/shared/shared_usb.cpp
USB/shared/inifile_usb.cpp
USB/shared/ringbuffer.cpp
USB/usb-python2/usb-python2.cpp
USB/usb-python2/devices/acio.cpp
USB/usb-python2/devices/ddr_extio.cpp
USB/usb-python2/devices/icca.cpp
USB/usb-python2/devices/thrilldrive_belt.cpp
USB/usb-python2/devices/thrilldrive_handle.cpp
USB/usb-python2/devices/toysmarch_drumpad.cpp
USB/usb-python2/inputs/Python2QtInputManager.cpp
USB/usb-python2/inputs/passthrough/usb-python2-passthrough.cpp
USB/usb-python2/inputs/native/usb-python2-native.cpp
USB/usb-python2/patches.cpp
USB/usb-python2/api_init_linux.cpp
)
# USB headers
set(pcsx2USBHeaders
USB/USB.h
@ -541,11 +572,48 @@ set(pcsx2USBHeaders
USB/usb-python2/devices/thrilldrive_belt.h
USB/usb-python2/devices/thrilldrive_handle.h
USB/usb-python2/devices/toysmarch_drumpad.h
USB/usb-python2/passthrough/usb-python2-passthrough.h
USB/usb-python2/inputs/passthrough/usb-python2-passthrough.h
USB/usb-python2/patches.h
USB/usb-printer/usb-printer.h
)
set(pcsx2USBHeadersQt
USB/USB.h
USB/proxybase.h
USB/deviceproxy.h
USB/platcompat.h
USB/helpers.h
USB/readerwriterqueue/readerwriterqueue.h
USB/readerwriterqueue/atomicops.h
USB/qemu-usb/glib.h
USB/qemu-usb/vl.h
USB/qemu-usb/qusb.h
USB/qemu-usb/USBinternal.h
USB/qemu-usb/desc.h
USB/qemu-usb/iov.h
USB/qemu-usb/queue.h
USB/qemu-usb/hid.h
USB/qemu-usb/input-keymap.h
USB/usb-hid/hidproxy.h
USB/usb-hid/usb-hid.h
USB/usb-hid/noop.h
USB/shared/shared_usb.h
USB/shared/inifile_usb.h
USB/shared/ringbuffer.h
USB/usb-python2/noop.h
USB/usb-python2/devices/acio.h
USB/usb-python2/devices/ddr_extio.h
USB/usb-python2/devices/icca.h
USB/usb-python2/devices/input_device.h
USB/usb-python2/devices/thrilldrive_belt.h
USB/usb-python2/devices/thrilldrive_handle.h
USB/usb-python2/devices/toysmarch_drumpad.h
USB/usb-python2/inputs/Python2QtInputManager.h
USB/usb-python2/inputs/passthrough/usb-python2-passthrough.h
USB/usb-python2/inputs/native/usb-python2-native.h
USB/usb-python2/patches.h
)
if(TARGET PulseAudio::PulseAudio)
list(APPEND pcsx2USBSources USB/usb-mic/audiodev-pulse.cpp)
list(APPEND pcsx2USBHeaders USB/usb-mic/audiodev-pulse.h)
@ -1605,8 +1673,8 @@ if(UNIX AND NOT Linux)
target_sources(PCSX2 PRIVATE
${pcsx2OSXSources}
${pcsx2LinuxHeaders}
${pcsx2USBNullSources}
${pcsx2USBNullHeaders})
${pcsx2USBSourcesQt}
${pcsx2USBHeadersQt})
else()
if(NOT PCSX2_CORE)
target_sources(PCSX2 PRIVATE
@ -1614,8 +1682,8 @@ else()
${pcsx2USBHeaders})
else()
target_sources(PCSX2 PRIVATE
${pcsx2USBNullSources}
${pcsx2USBNullHeaders})
${pcsx2USBSourcesQt}
${pcsx2USBHeadersQt})
endif()
endif()

View File

@ -75,12 +75,9 @@ void ATA::SCE_IDENTIFY_DRIVE()
hddId[0x4f] = 0x01;
// 0x50 - 0x80 is a unique block of data
#ifndef PCSX2_CORE
// TODO: Rewrite this in a way to not use g_Conf for future Qt support
auto fp = FileSystem::OpenManagedCFile(EmuConfig.DEV9.HddIdFile.c_str(), "rb");
if (fp && FileSystem::FSize64(fp.get()) >= 128)
std::fread(hddId, 1, 128, fp.get());
#endif
pioDRQEndTransferFunc = nullptr;
DRQCmdPIODataToHost(hddId, 128, 0, 128, true);

View File

@ -36,6 +36,8 @@
#include "Elfheader.h"
#include "VMManager.h"
#include "Frontend/INISettingsInterface.h"
enum : u32
{
GAME_LIST_CACHE_SIGNATURE = 0x45434C47,
@ -50,6 +52,7 @@ namespace GameList
static bool GetElfListEntry(const std::string& path, GameList::Entry* entry);
static bool GetIsoListEntry(const std::string& path, GameList::Entry* entry);
static bool GetPython2ListEntry(const std::string& path, GameList::Entry* entry);
static bool GetGameListEntryFromCache(const std::string& path, GameList::Entry* entry);
static void ScanDirectory(
@ -81,13 +84,13 @@ bool GameList::IsGameListLoaded()
const char* GameList::EntryTypeToString(EntryType type)
{
static std::array<const char*, static_cast<int>(EntryType::Count)> names = {{"PS2Disc", "PS1Disc", "ELF", "Playlist"}};
static std::array<const char*, static_cast<int>(EntryType::Count)> names = {{"PS2Disc", "PS1Disc", "ELF", "Playlist", "Python 2"}};
return names[static_cast<int>(type)];
}
const char* GameList::EntryTypeToDisplayString(EntryType type)
{
static std::array<const char*, static_cast<int>(EntryType::Count)> names = {{"PS2 Disc", "PS1 Disc", "ELF", "Playlist"}};
static std::array<const char*, static_cast<int>(EntryType::Count)> names = {{"PS2 Disc", "PS1 Disc", "ELF", "Playlist", "Python 2"}};
return names[static_cast<int>(type)];
}
@ -119,7 +122,7 @@ const char* GameList::EntryCompatibilityRatingToString(CompatibilityRating ratin
bool GameList::IsScannableFilename(const std::string_view& path)
{
static const char* extensions[] = {".iso", ".mdf", ".nrg", ".bin", ".img", ".gz", ".cso", ".chd", ".elf", ".irx"};
static const char* extensions[] = {".iso", ".mdf", ".nrg", ".bin", ".img", ".gz", ".cso", ".chd", ".elf", ".irx", ".py2"};
for (const char* test_extension : extensions)
{
@ -144,6 +147,16 @@ void GameList::FillBootParametersForEntry(VMBootParameters* params, const Entry*
params->source_type = CDVD_SourceType::NoDisc;
params->elf_override = entry->path;
}
else if (entry->type == GameList::EntryType::Python2)
{
params->filename.clear();
params->source_type = CDVD_SourceType::NoDisc;
params->elf_override.clear();
params->is_python2 = true;
params->python2_crc = entry->crc;
params->python2_serial = entry->serial;
}
else
{
params->filename.clear();
@ -303,10 +316,218 @@ bool GameList::GetIsoListEntry(const std::string& path, GameList::Entry* entry)
return true;
}
// clang-format off
bool GameList::GetPython2ListEntry(const std::string& path, GameList::Entry* entry)
{
// TODO: Parse a .py2 entry file to read target image filename, HDD ID, ILINK ID, and other configurations
std::unique_ptr<INISettingsInterface> new_interface = std::make_unique<INISettingsInterface>(std::move(path));
if (!new_interface->Load())
{
Console.Error("Failed to parse Python 2 game entry ini '%s'", new_interface->GetFileName().c_str());
new_interface.reset();
return false;
}
std::string game_title;
new_interface->GetStringValue("Game", "Title", &game_title);
std::string hdd_id_path;
new_interface->GetStringValue("Game", "HddId", &hdd_id_path);
if (!hdd_id_path.empty() && !Path::IsAbsolute(hdd_id_path)) {
hdd_id_path = std::string(Path::Combine(Path::GetDirectory(path), hdd_id_path));
}
std::string ilink_id_path;
new_interface->GetStringValue("Game", "IlinkId", &ilink_id_path);
if (!ilink_id_path.empty() && !Path::IsAbsolute(ilink_id_path)) {
ilink_id_path = std::string(Path::Combine(Path::GetDirectory(path), ilink_id_path));
}
std::string hdd_image_path;
new_interface->GetStringValue("Game", "HddImage", &hdd_image_path);
if (!hdd_image_path.empty() && !Path::IsAbsolute(hdd_image_path)) {
hdd_image_path = std::string(Path::Combine(Path::GetDirectory(path), hdd_image_path));
}
std::string region;
new_interface->GetStringValue("Game", "Region", &region);
printf("game_title: %s\n", game_title.c_str());
printf("hdd_id_path: %s\n", hdd_id_path.c_str());
printf("ilink_id_path: %s\n", ilink_id_path.c_str());
printf("hdd_image_path: %s\n", hdd_image_path.c_str());
printf("region: %s\n", region.c_str());
entry->path = path;
entry->serial = "KNAC00001";
entry->crc = rand(); // There should be a better way to determine this but there's no reliable way without parsing the files on the HDD directly
entry->title = game_title;
entry->type = EntryType::Python2;
entry->compatibility_rating = CompatibilityRating::Unknown;
////// NTSC //////
//////////////////
if (StringUtil::StartsWith(region, "NTSC-B"))
entry->region = Region::NTSC_B;
else if (StringUtil::StartsWith(region, "NTSC-C"))
entry->region = Region::NTSC_C;
else if (StringUtil::StartsWith(region, "NTSC-HK"))
entry->region = Region::NTSC_HK;
else if (StringUtil::StartsWith(region, "NTSC-J"))
entry->region = Region::NTSC_J;
else if (StringUtil::StartsWith(region, "NTSC-K"))
entry->region = Region::NTSC_K;
else if (StringUtil::StartsWith(region, "NTSC-T"))
entry->region = Region::NTSC_T;
else if (StringUtil::StartsWith(region, "NTSC-U"))
entry->region = Region::NTSC_U;
////// PAL //////
//////////////////
else if (StringUtil::StartsWith(region, "PAL-AF"))
entry->region = Region::PAL_AF;
else if (StringUtil::StartsWith(region, "PAL-AU"))
entry->region = Region::PAL_AU;
else if (StringUtil::StartsWith(region, "PAL-A"))
entry->region = Region::PAL_A;
else if (StringUtil::StartsWith(region, "PAL-BE"))
entry->region = Region::PAL_BE;
else if (StringUtil::StartsWith(region, "PAL-E"))
entry->region = Region::PAL_E;
else if (StringUtil::StartsWith(region, "PAL-FI"))
entry->region = Region::PAL_FI;
else if (StringUtil::StartsWith(region, "PAL-F"))
entry->region = Region::PAL_F;
else if (StringUtil::StartsWith(region, "PAL-GR"))
entry->region = Region::PAL_GR;
else if (StringUtil::StartsWith(region, "PAL-G"))
entry->region = Region::PAL_G;
else if (StringUtil::StartsWith(region, "PAL-IN"))
entry->region = Region::PAL_IN;
else if (StringUtil::StartsWith(region, "PAL-I"))
entry->region = Region::PAL_I;
else if (StringUtil::StartsWith(region, "PAL-M"))
entry->region = Region::PAL_M;
else if (StringUtil::StartsWith(region, "PAL-NL"))
entry->region = Region::PAL_NL;
else if (StringUtil::StartsWith(region, "PAL-NO"))
entry->region = Region::PAL_NO;
else if (StringUtil::StartsWith(region, "PAL-P"))
entry->region = Region::PAL_P;
else if (StringUtil::StartsWith(region, "PAL-R"))
entry->region = Region::PAL_R;
else if (StringUtil::StartsWith(region, "PAL-SC"))
entry->region = Region::PAL_SC;
else if (StringUtil::StartsWith(region, "PAL-SWI"))
entry->region = Region::PAL_SWI;
else if (StringUtil::StartsWith(region, "PAL-SW"))
entry->region = Region::PAL_SW;
else if (StringUtil::StartsWith(region, "PAL-S"))
entry->region = Region::PAL_S;
else if (StringUtil::StartsWith(region, "PAL-UK"))
entry->region = Region::PAL_UK;
else
entry->region = Region::Other;
std::string filename(VMManager::GetGameSettingsPath(entry->serial, entry->crc));
std::unique_ptr<INISettingsInterface> sif = std::make_unique<INISettingsInterface>(std::move(filename));
if (FileSystem::FileExists(sif->GetFileName().c_str()))
sif->Load();
sif->SetBoolValue("DEV9/Hdd", "HddEnable", true);
sif->SetStringValue("DEV9/Hdd", "HddFile", hdd_image_path.c_str());
sif->SetStringValue("DEV9/Hdd", "HddIdFile", hdd_id_path.c_str());
sif->SetStringValue("DEV9/Hdd", "IlinkIdPath", ilink_id_path.c_str()); // TODO: Find better place
sif->SetBoolValue("DEV9/Eth", "EthEnable", true);
sif->SetBoolValue("EmuCore/Gamefixes", "OPHFlagHack", true);
if (!sif->ContainsValue("Python2/Game", "DongleBlackFile")) {
std::string dongleBlackFile;
new_interface->GetStringValue("Game", "DongleBlackFile", &dongleBlackFile);
if (!dongleBlackFile.empty() && !Path::IsAbsolute(dongleBlackFile)) {
dongleBlackFile = std::string(Path::Combine(Path::GetDirectory(path), dongleBlackFile));
}
if (!dongleBlackFile.empty())
sif->SetStringValue("Python2/Game", "DongleBlackFile", dongleBlackFile.c_str());
}
if (!sif->ContainsValue("Python2/Game", "DongleWhiteFile")) {
std::string dongleWhiteFile;
new_interface->GetStringValue("Game", "DongleWhiteFile", &dongleWhiteFile);
if (!dongleWhiteFile.empty() && !Path::IsAbsolute(dongleWhiteFile)) {
dongleWhiteFile = std::string(Path::Combine(Path::GetDirectory(path), dongleWhiteFile));
}
if (!dongleWhiteFile.empty())
sif->SetStringValue("Python2/Game", "DongleWhiteFile", dongleWhiteFile.c_str());
}
if (!sif->ContainsValue("Python2/Game", "Player1CardFile")) {
std::string player1CardFile;
new_interface->GetStringValue("Game", "Player1CardFile", &player1CardFile);
if (!player1CardFile.empty() && !Path::IsAbsolute(player1CardFile)) {
player1CardFile = std::string(Path::Combine(Path::GetDirectory(path), player1CardFile));
}
if (!player1CardFile.empty())
sif->SetStringValue("Python2/Game", "Player1CardFile", player1CardFile.c_str());
}
if (!sif->ContainsValue("Python2/Game", "Player2CardFile")) {
std::string player2CardFile;
new_interface->GetStringValue("Game", "Player2CardFile", &player2CardFile);
if (!player2CardFile.empty() && !Path::IsAbsolute(player2CardFile)) {
player2CardFile = std::string(Path::Combine(Path::GetDirectory(path), player2CardFile));
}
if (!player2CardFile.empty())
sif->SetStringValue("Python2/Game", "Player2CardFile", player2CardFile.c_str());
}
if (!sif->ContainsValue("Python2/Game", "PatchFile")) {
std::string patchFile;
new_interface->GetStringValue("Game", "PatchFile", &patchFile);
if (!patchFile.empty() && !Path::IsAbsolute(patchFile)) {
patchFile = std::string(Path::Combine(Path::GetDirectory(path), patchFile));
}
if (!patchFile.empty())
sif->SetStringValue("Python2/Game", "PatchFile", patchFile.c_str());
}
if (!sif->ContainsValue("Python2/Game", "DIPSW1"))
sif->SetBoolValue("Python2/Game", "DIPSW1", new_interface->GetBoolValue("Game", "DIPSW1", false));
if (!sif->ContainsValue("Python2/Game", "DIPSW2"))
sif->SetBoolValue("Python2/Game", "DIPSW2", new_interface->GetBoolValue("Game", "DIPSW2", false));
if (!sif->ContainsValue("Python2/Game", "DIPSW3"))
sif->SetBoolValue("Python2/Game", "DIPSW3", new_interface->GetBoolValue("Game", "DIPSW3", false));
if (!sif->ContainsValue("Python2/Game", "DIPSW4"))
sif->SetBoolValue("Python2/Game", "DIPSW4", new_interface->GetBoolValue("Game", "DIPSW4", false));
if (!sif->ContainsValue("Python2/Game", "Force31kHz"))
sif->SetBoolValue("Python2/Game", "Force31kHz", new_interface->GetBoolValue("Game", "Force31kHz", false));
sif->Save();
return true;
}
// clang-format off
bool GameList::PopulateEntryFromPath(const std::string& path, GameList::Entry* entry)
{
if (VMManager::IsElfFileName(path.c_str()))
return GetElfListEntry(path, entry);
else if (StringUtil::EndsWithNoCase(path.c_str(), ".py2"))
return GetPython2ListEntry(path, entry);
else
return GetIsoListEntry(path, entry);
}

View File

@ -37,6 +37,7 @@ namespace GameList
PS1Disc,
ELF,
Playlist,
Python2,
Count
};

View File

@ -26,7 +26,10 @@
#include "qemu-usb/desc.h"
#include "shared/shared_usb.h"
#include "deviceproxy.h"
#ifndef PCSX2_CORE
#include "configuration.h"
#endif
#define PSXCLK 36864000 /* 36.864 Mhz */
@ -70,12 +73,19 @@ s64 remaining = 0;
#if defined(_WIN32)
HWND gsWnd = nullptr;
#elif defined(__linux__)
#ifndef PCSX2_CORE
#include "gtk.h"
#include <gdk/gdkx.h>
#endif
#include <X11/X.h>
#ifndef PCSX2_CORE
Display* g_GSdsp = nullptr;
Window g_GSwin;
#endif
#endif
Config::Config()
: Log(0)
@ -198,17 +208,24 @@ void CreateDevices()
s32 USBinit()
{
#ifndef PCSX2_CORE
USBsetSettingsDir();
#endif
RegisterDevice::Register();
#ifndef PCSX2_CORE
LoadConfig();
#endif
if (conf.Log && !usbLog)
{
#ifndef PCSX2_CORE
#ifdef _WIN32
usbLog = wfopen(LogDir.c_str(), L"wb"); // L"wb,ccs=UNICODE");
#else
usbLog = wfopen(LogDir.c_str(), "wb"); // L"wb,ccs=UNICODE");
#endif
#endif
//if(usbLog) setvbuf(usbLog, NULL, _IONBF, 0);
}
@ -245,6 +262,9 @@ void USBshutdown()
s32 USBopen(const WindowInfo& wi)
{
#ifdef PCSX2_CORE
conf.Port[0] = "python2io";
#endif
if (conf.Log && !usbLog)
{
@ -262,9 +282,11 @@ s32 USBopen(const WindowInfo& wi)
#elif defined(__linux__)
if (wi.type == WindowInfo::Type::X11)
{
#ifndef PCSX2_CORE
g_GSdsp = static_cast<Display*>(wi.display_connection);
g_GSwin = reinterpret_cast<Window>(wi.window_handle);
window_handle_for_init = reinterpret_cast<void*>(g_GSwin);
#endif
}
#endif
@ -297,9 +319,12 @@ void USBclose()
#if defined(_WIN32)
gsWnd = {};
#elif defined(__linux__)
g_GSdsp = nullptr;
#ifndef PCSX2_CORE
g_GSdsp = nullptr;
g_GSwin = {};
#endif
#endif
}
u8 USBread8(u32 addr)

View File

@ -16,7 +16,11 @@
#pragma once
#include "platcompat.h"
#ifndef PCSX2_CORE
#include <wx/string.h>
#endif
#include <vector>
#include <string>
#include <map>

View File

@ -29,6 +29,8 @@ void RegisterDevice::Register()
auto& inst = RegisterDevice::instance();
if (inst.Map().size()) // FIXME Don't clear proxies, singstar keeps a copy to uninit audio
return;
#ifndef PCSX2_CORE
inst.Add(DEVTYPE_PAD, new DeviceProxy<usb_pad::PadDevice>());
inst.Add(DEVTYPE_MSD, new DeviceProxy<usb_msd::MsdDevice>());
inst.Add(DEVTYPE_SINGSTAR, new DeviceProxy<usb_mic::SingstarDevice>());
@ -47,6 +49,8 @@ void RegisterDevice::Register()
inst.Add(DEVTYPE_SEGA_SEAMIC, new DeviceProxy<usb_pad::SeamicDevice>());
inst.Add(DEVTYPE_PRINTER, new DeviceProxy<usb_printer::PrinterDevice>());
inst.Add(DEVTYPE_KEYBOARDMANIA, new DeviceProxy<usb_pad::KeyboardmaniaDevice>());
#endif
inst.Add(DEVTYPE_PYTHON2, new DeviceProxy<usb_python2::Python2Device>());
RegisterAPIs();

View File

@ -15,28 +15,38 @@
#include "PrecompiledHeader.h"
#include "deviceproxy.h"
#ifndef PCSX2_CORE
#include "usb-pad/padproxy.h"
#include "usb-mic/audiodeviceproxy.h"
#include "usb-hid/hidproxy.h"
#include "usb-eyetoy/videodeviceproxy.h"
#endif
#include "usb-python2/python2proxy.h"
RegisterDevice* RegisterDevice::registerDevice = nullptr;
void RegisterAPIs()
{
#ifndef PCSX2_CORE
usb_pad::RegisterPad::Register();
usb_mic::RegisterAudioDevice::Register();
usb_hid::RegisterUsbHID::Register();
usb_eyetoy::RegisterVideoDevice::Register();
#endif
usb_python2::RegisterUsbPython2::Register();
}
void UnregisterAPIs()
{
#ifndef PCSX2_CORE
usb_pad::RegisterPad::instance().Clear();
usb_mic::RegisterAudioDevice::instance().Clear();
usb_hid::RegisterUsbHID::instance().Clear();
usb_eyetoy::RegisterVideoDevice::instance().Clear();
#endif
usb_python2::RegisterUsbPython2::instance().Clear();
}

View File

@ -15,6 +15,13 @@
#pragma once
#if defined(_MSC_VER)
#include <basetsd.h>
#ifndef HAVE_SSIZE_T
typedef SSIZE_T ssize_t;
#endif
#endif
// Annoying defines
// ---------------------------------------------------------------------
// make sure __POSIX__ is defined for all systems where we assume POSIX
@ -36,26 +43,40 @@
#endif
#endif
#ifdef _WIN32
#if defined(_WIN32)
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#ifdef PCSX2_CORE
#define wfopen _wfopen
#define fseeko64 _fseeki64
#define ftello64 _ftelli64
#define TSTDSTRING std::string
#define TSTDSTRINGSTREAM std::stringstream
#define TSTDTOSTRING std::to_string
#define P2TEXT(x) x
void SysMessage(const char* fmt, ...);
#else
#define wfopen _wfopen
#define fseeko64 _fseeki64
#define ftello64 _ftelli64
#define TSTDSTRING std::wstring
#define TSTDSTRINGSTREAM std::wstringstream
#define TSTDTOSTRING std::to_wstring
#define P2TEXT(x) L##x
void SysMessageW(const wchar_t* fmt, ...);
#define SysMessage SysMessageW
#endif
//FIXME narrow string fmt
#define SFMTs "S"
#define __builtin_constant_p(p) false
void SysMessageW(const wchar_t* fmt, ...);
#define SysMessage SysMessageW
#else //_WIN32
#define MAX_PATH PATH_MAX
@ -67,6 +88,7 @@ void SysMessageW(const wchar_t* fmt, ...);
//FIXME narrow string fmt
#define SFMTs "s"
#define TEXT(val) val
#define P2TEXT(val) val
#define TCHAR char
#define wfopen fopen
#define TSTDSTRING std::string

View File

@ -17,7 +17,7 @@
#include "shared_usb.h"
#include <stdexcept>
#ifdef _WIN32
#if defined(_WIN32) && !defined(PCSX2_CORE)
#include "rawinput_usb.h"
#endif
@ -26,7 +26,7 @@ namespace shared
void Initialize(void* ptr)
{
#ifdef _WIN32
#if defined(_WIN32) && !defined(PCSX2_CORE)
if (!shared::rawinput::Initialize(ptr))
throw std::runtime_error("Failed to initialize raw input!");
#endif
@ -34,7 +34,7 @@ namespace shared
void Uninitialize(/*void *ptr*/)
{
#ifdef _WIN32
#if defined(_WIN32) && !defined(PCSX2_CORE)
shared::rawinput::Uninitialize(/*ptr*/);
#endif
}

View File

@ -1,10 +1,18 @@
#include "python2proxy.h"
#include "noop.h"
#include "passthrough/usb-python2-passthrough.h"
#include "inputs/passthrough/usb-python2-passthrough.h"
#ifdef PCSX2_CORE
#include "inputs/native/usb-python2-native.h"
#endif
void usb_python2::RegisterUsbPython2::Register()
{
auto& inst = RegisterUsbPython2::instance();
inst.Add(usb_python2::passthrough::APINAME, new UsbPython2Proxy<usb_python2::passthrough::PassthroughInput>());
#ifdef PCSX2_CORE
inst.Add(usb_python2::native::APINAME, new UsbPython2Proxy<usb_python2::native::NativeInput>());
#else
inst.Add(usb_python2::noop::APINAME, new UsbPython2Proxy<usb_python2::noop::NOOP>());
}
#endif
inst.Add(usb_python2::passthrough::APINAME, new UsbPython2Proxy<usb_python2::passthrough::PassthroughInput>());
}

View File

@ -1,16 +1,28 @@
#include "PrecompiledHeader.h"
#include "python2proxy.h"
#include "raw/usb-python2-raw.h"
#include "passthrough/usb-python2-passthrough.h"
#include "btools/usb-python2-btools.h"
#ifdef PCSX2_CORE
#include "inputs/native/usb-python2-native.h"
#else
#include "inputs/raw/usb-python2-raw.h"
#include "inputs/btools/usb-python2-btools.h"
#endif
#include "inputs/passthrough/usb-python2-passthrough.h"
void usb_python2::RegisterUsbPython2::Register()
{
auto& inst = RegisterUsbPython2::instance();
#ifdef PCSX2_CORE
inst.Add(usb_python2::native::APINAME, new UsbPython2Proxy<usb_python2::native::NativeInput>());
#else
inst.Add(usb_python2::APINAME, new UsbPython2Proxy<usb_python2::raw::RawInputPad>());
#endif
inst.Add(usb_python2::passthrough::APINAME, new UsbPython2Proxy<usb_python2::passthrough::PassthroughInput>());
#ifdef INCLUDE_BTOOLS
#if defined(INCLUDE_BTOOLS) && !defined(PCSX2_CORE)
inst.Add(usb_python2::btools::APINAME, new UsbPython2Proxy<usb_python2::btools::BToolsInput>());
#endif
#endif
}

View File

@ -21,31 +21,31 @@ namespace usb_python2
uint8_t cardId[8] = {0};
std::string cardFilename = "";
std::wstring keypadIdsByDeviceId[2][12] = {
{L"KeypadP1_0",
L"KeypadP1_1",
L"KeypadP1_2",
L"KeypadP1_3",
L"KeypadP1_4",
L"KeypadP1_5",
L"KeypadP1_6",
L"KeypadP1_7",
L"KeypadP1_8",
L"KeypadP1_9",
L"KeypadP1_00",
L"KeypadP1InsertEject"},
{L"KeypadP2_0",
L"KeypadP2_1",
L"KeypadP2_2",
L"KeypadP2_3",
L"KeypadP2_4",
L"KeypadP2_5",
L"KeypadP2_6",
L"KeypadP2_7",
L"KeypadP2_8",
L"KeypadP2_9",
L"KeypadP2_00",
L"KeypadP2InsertEject"},
TSTDSTRING keypadIdsByDeviceId[2][12] = {
{P2TEXT("KeypadP1_0"),
P2TEXT("KeypadP1_1"),
P2TEXT("KeypadP1_2"),
P2TEXT("KeypadP1_3"),
P2TEXT("KeypadP1_4"),
P2TEXT("KeypadP1_5"),
P2TEXT("KeypadP1_6"),
P2TEXT("KeypadP1_7"),
P2TEXT("KeypadP1_8"),
P2TEXT("KeypadP1_9"),
P2TEXT("KeypadP1_00"),
P2TEXT("KeypadP1InsertEject")},
{P2TEXT("KeypadP2_0"),
P2TEXT("KeypadP2_1"),
P2TEXT("KeypadP2_2"),
P2TEXT("KeypadP2_3"),
P2TEXT("KeypadP2_4"),
P2TEXT("KeypadP2_5"),
P2TEXT("KeypadP2_6"),
P2TEXT("KeypadP2_7"),
P2TEXT("KeypadP2_8"),
P2TEXT("KeypadP2_9"),
P2TEXT("KeypadP2_00"),
P2TEXT("KeypadP2InsertEject")},
};
void write(std::vector<uint8_t>& packet) {}

View File

@ -7,7 +7,7 @@ namespace usb_python2
const auto header = (ACIO_PACKET_HEADER*)packet.data();
const auto code = BigEndian16(header->code);
if (p2dev->GetKeyState(L"ThrillDriveSeatbelt") != 0)
if (p2dev->GetKeyState(P2TEXT("ThrillDriveSeatbelt")) != 0)
{
if (!seatBeltButtonPressed)
seatBeltStatus = !seatBeltStatus;

View File

@ -15,13 +15,13 @@ namespace usb_python2
// If this packet can't be read then the game will throw a drum I/O error
uint8_t state[9] = {
stateIdx,
uint8_t(p2dev->GetKeyStateOneShot(L"ToysMarchP1Cymbal") * 128),
uint8_t(p2dev->GetKeyStateOneShot(L"ToysMarchP1DrumL") * 128),
uint8_t(p2dev->GetKeyStateOneShot(L"ToysMarchP1DrumR") * 128),
uint8_t(p2dev->GetKeyStateOneShot(P2TEXT("ToysMarchP1Cymbal")) * 128),
uint8_t(p2dev->GetKeyStateOneShot(P2TEXT("ToysMarchP1DrumL")) * 128),
uint8_t(p2dev->GetKeyStateOneShot(P2TEXT("ToysMarchP1DrumR")) * 128),
0,
uint8_t(p2dev->GetKeyStateOneShot(L"ToysMarchP2Cymbal") * 128),
uint8_t(p2dev->GetKeyStateOneShot(L"ToysMarchP2DrumL") * 128),
uint8_t(p2dev->GetKeyStateOneShot(L"ToysMarchP2DrumR") * 128),
uint8_t(p2dev->GetKeyStateOneShot(P2TEXT("ToysMarchP2Cymbal")) * 128),
uint8_t(p2dev->GetKeyStateOneShot(P2TEXT("ToysMarchP2DrumL")) * 128),
uint8_t(p2dev->GetKeyStateOneShot(P2TEXT("ToysMarchP2DrumR")) * 128),
0
};
stateIdx = (stateIdx + 1) % 8;

View File

@ -0,0 +1,161 @@
#include "Python2QtInputManager.h"
#include <map>
#include "pcsx2/HostSettings.h"
#include "common/SettingsInterface.h"
#include "common/StringUtil.h"
static std::vector<Python2KeyMapping> s_python2_current_mappings;
static std::map<std::string, std::vector<Python2KeyMapping>> mappingsByInputKey;
std::vector<Python2KeyMapping> Python2QtInputManager::GetCurrentMappings()
{
return s_python2_current_mappings;
}
std::vector<Python2KeyMapping> Python2QtInputManager::GetMappingsByInputKey(std::string keyBindStr)
{
if (mappingsByInputKey.find(keyBindStr) != mappingsByInputKey.end())
return mappingsByInputKey[keyBindStr];
return std::vector<Python2KeyMapping>();
}
bool Python2QtInputManager::AddNewBinding(std::string full_key, std::string new_binding, double analogDeadzone, double analogSensitivity, double motorScale)
{
uint32_t nextUniqueId = 0;
for (auto mapping : s_python2_current_mappings)
{
if (mapping.uniqueId + 1 > nextUniqueId)
nextUniqueId = mapping.uniqueId + 1;
}
for (auto system_entry : s_python2_system_info)
{
if (system_entry.bindings == nullptr)
continue;
for (u32 i = 0; i < system_entry.num_bindings; i++)
{
auto entry = system_entry.bindings[i];
if (std::string(entry.name) != full_key)
continue;
Python2KeyMapping keybindMapping = {
nextUniqueId,
new_binding,
entry.name,
entry.type,
analogDeadzone,
analogSensitivity,
motorScale,
entry.is_oneshot,
};
s_python2_current_mappings.push_back(keybindMapping);
mappingsByInputKey[new_binding].push_back(keybindMapping);
return true;
}
}
return false;
}
void Python2QtInputManager::RemoveMappingByUniqueId(uint32_t uniqueId)
{
s_python2_current_mappings.erase(
std::remove_if(
s_python2_current_mappings.begin(),
s_python2_current_mappings.end(),
[uniqueId](const Python2KeyMapping& x) { return x.uniqueId == uniqueId; }),
s_python2_current_mappings.end());
for (auto x : mappingsByInputKey) {
x.second.erase(
std::remove_if(
x.second.begin(),
x.second.end(),
[uniqueId](const Python2KeyMapping& x) { return x.uniqueId == uniqueId; }),
x.second.end());
}
}
void Python2QtInputManager::LoadMapping()
{
SettingsInterface* si = Host::GetSettingsInterfaceForBindings();
const std::string section = "Python2";
uint32_t uniqueKeybindIdx = 0;
s_python2_current_mappings.clear();
for (auto system_entry : s_python2_system_info)
{
if (system_entry.bindings == nullptr)
continue;
for (u32 i = 0; i < system_entry.num_bindings; i++)
{
auto entry = system_entry.bindings[i];
const std::vector<std::string> bindings(si->GetStringList(section.c_str(), entry.name));
printf("button: %s\n", entry.name);
for (auto bind : bindings)
{
int isOneshot = 0;
double analogDeadzone = 0;
double analogSensitivity = 0;
double motorScale = 0;
auto idx = bind.find_first_of(L'|');
if (idx != std::string::npos)
{
auto substr = std::string(bind.begin() + idx + 1, bind.end());
if (entry.type == PAD::ControllerBindingType::Button)
{
isOneshot = std::stoi(substr);
}
else if (entry.type == PAD::ControllerBindingType::Axis || entry.type == PAD::ControllerBindingType::HalfAxis)
{
analogDeadzone = std::stod(substr);
analogSensitivity = std::stod(substr.substr(substr.find_first_of('|') + 1));
}
else if (entry.type == PAD::ControllerBindingType::Motor)
{
motorScale = std::stod(substr);
}
}
auto input_key = std::string(bind.begin(), bind.begin() + idx);
Python2KeyMapping keybindMapping = {
uniqueKeybindIdx++,
input_key,
std::string(entry.name),
entry.type,
analogDeadzone,
analogSensitivity,
motorScale,
isOneshot == 1,
};
s_python2_current_mappings.push_back(keybindMapping);
mappingsByInputKey[input_key].push_back(keybindMapping);
if (entry.type == PAD::ControllerBindingType::Button)
printf("\tbind: %s, oneshot = %d\n", input_key.c_str(), isOneshot);
else if (entry.type == PAD::ControllerBindingType::Axis || entry.type == PAD::ControllerBindingType::HalfAxis)
printf("\tbind: %s, deadzone = %lf, sensitivity = %lf\n", input_key.c_str(), analogDeadzone, analogSensitivity);
else if (entry.type == PAD::ControllerBindingType::Motor)
printf("\tbind: %s, motor scale = %lf\n", input_key.c_str(), motorScale);
}
}
}
}

View File

@ -0,0 +1,189 @@
#pragma once
#include <vector>
#include "pcsx2/PAD/Host/PAD.h"
struct Python2KeyMapping
{
uint32_t uniqueId;
std::string inputKey;
std::string keybind;
PAD::ControllerBindingType input_type;
double analogDeadzone;
double analogSensitivity;
double motorScale;
bool isOneshot; // Immediately trigger an off after on
};
struct Python2BindingInfo
{
const char* name;
const char* display_name;
PAD::ControllerBindingType type;
bool is_oneshot;
};
struct Python2SystemInfo
{
const char* name;
const Python2BindingInfo* bindings;
u32 num_bindings;
};
static const Python2BindingInfo s_python2_system_binds[] = {
{"Test", "Test", PAD::ControllerBindingType::Button, false},
{"Service", "Service", PAD::ControllerBindingType::Button, false},
{"Coin1", "Coin 1", PAD::ControllerBindingType::Button, false},
{"Coin2", "Coin 2", PAD::ControllerBindingType::Button, false},
};
static const Python2BindingInfo s_python2_guitarfreaks_binds[] = {
{"GfP1Start", "P1 Start", PAD::ControllerBindingType::Button, false},
{"GfP1Pick", "P1 Pick", PAD::ControllerBindingType::Button, true},
{"GfP1Wail", "P1 Wail", PAD::ControllerBindingType::Button, false},
{"GfP1EffectInc", "P1 Effect+", PAD::ControllerBindingType::Button, false},
{"GfP1EffectDec", "P1 Effect-", PAD::ControllerBindingType::Button, false},
{"GfP1NeckR", "P1 Neck R", PAD::ControllerBindingType::Button, false},
{"GfP1NeckG", "P1 Neck G", PAD::ControllerBindingType::Button, false},
{"GfP1NeckB", "P1 Neck B", PAD::ControllerBindingType::Button, false},
{"GfP2Start", "P2 Start", PAD::ControllerBindingType::Button, false},
{"GfP2Pick", "P2 Pick", PAD::ControllerBindingType::Button, true},
{"GfP2Wail", "P2 Wail", PAD::ControllerBindingType::Button, false},
{"GfP2EffectInc", "P2 Effect+", PAD::ControllerBindingType::Button, false},
{"GfP2EffectDec", "P2 Effect-", PAD::ControllerBindingType::Button, false},
{"GfP2NeckR", "P2 Neck R", PAD::ControllerBindingType::Button, false},
{"GfP2NeckG", "P2 Neck G", PAD::ControllerBindingType::Button, false},
{"GfP2NeckB", "P2 Neck B", PAD::ControllerBindingType::Button, false},
};
static const Python2BindingInfo s_python2_drummania_binds[] = {
{"DmStart", "Start", PAD::ControllerBindingType::Button, false},
{"DmSelectL", "Select L", PAD::ControllerBindingType::Button, false},
{"DmSelectR", "Select R", PAD::ControllerBindingType::Button, false},
{"DmHihat", "Hihat", PAD::ControllerBindingType::Button, true},
{"DmSnare", "Snare", PAD::ControllerBindingType::Button, true},
{"DmHighTom", "High Tom", PAD::ControllerBindingType::Button, true},
{"DmLowTom", "Low Tom", PAD::ControllerBindingType::Button, true},
{"DmCymbal", "Cymbal", PAD::ControllerBindingType::Button, true},
{"DmBassDrum", "Bass Drum", PAD::ControllerBindingType::Button, true},
};
static const Python2BindingInfo s_python2_ddr_binds[] = {
{"DdrP1Start", "P1 Start", PAD::ControllerBindingType::Button, false},
{"DdrP1SelectL", "P1 Select L", PAD::ControllerBindingType::Button, false},
{"DdrP1SelectR", "P1 Select R", PAD::ControllerBindingType::Button, false},
{"DdrP1FootLeft", "P1 Left", PAD::ControllerBindingType::Button, false},
{"DdrP1FootDown", "P1 Down", PAD::ControllerBindingType::Button, false},
{"DdrP1FootUp", "P1 Up", PAD::ControllerBindingType::Button, false},
{"DdrP1FootRight", "P1 Right", PAD::ControllerBindingType::Button, false},
{"DdrP2Start", "P2 Start", PAD::ControllerBindingType::Button, false},
{"DdrP2SelectL", "P2 Select L", PAD::ControllerBindingType::Button, false},
{"DdrP2SelectR", "P2 Select R", PAD::ControllerBindingType::Button, false},
{"DdrP2FootLeft", "P2 Left", PAD::ControllerBindingType::Button, false},
{"DdrP2FootDown", "P2 Down", PAD::ControllerBindingType::Button, false},
{"DdrP2FootUp", "P2 Up", PAD::ControllerBindingType::Button, false},
{"DdrP2FootRight", "P2 Right", PAD::ControllerBindingType::Button, false},
};
static const Python2BindingInfo s_python2_thrilldrive_binds[] = {
{"ThrillDriveStart", "Start", PAD::ControllerBindingType::Button, false},
{"ThrillDriveGearUp", "Gear Up", PAD::ControllerBindingType::Button, false},
{"ThrillDriveGearDown", "Gear Down", PAD::ControllerBindingType::Button, false},
{"ThrillDriveWheelAnalog", "Wheel", PAD::ControllerBindingType::Axis, false},
{"ThrillDriveWheelLeft", "Wheel Left", PAD::ControllerBindingType::Button, false},
{"ThrillDriveWheelRight", "Wheel Right", PAD::ControllerBindingType::Button, false},
{"ThrillDriveAccelAnalog", "Acceleration", PAD::ControllerBindingType::HalfAxis, false},
{"ThrillDriveAccel", "Acceleration", PAD::ControllerBindingType::Button, false},
{"ThrillDriveBrake", "Brake", PAD::ControllerBindingType::Button, false},
{"ThrillDriveBrakeAnalog", "Brake", PAD::ControllerBindingType::HalfAxis, false},
{"ThrillDriveSeatbelt", "Seatbelt", PAD::ControllerBindingType::Button, false},
{"ThrillDriveSeatbeltMotor", "Seatbelt", PAD::ControllerBindingType::Motor, false},
{"ThrillDriveWheelMotor", "Wheel", PAD::ControllerBindingType::Motor, false},
};
static const Python2BindingInfo s_python2_dance864_binds[] = {
{"Dance864P1Start", "P1 Start", PAD::ControllerBindingType::Button, false},
{"Dance864P1Left", "P1 Select L", PAD::ControllerBindingType::Button, false},
{"Dance864P1Right", "P1 Select R", PAD::ControllerBindingType::Button, false},
{"Dance864P1PadLeft", "P1 Left", PAD::ControllerBindingType::Button, false},
{"Dance864P1PadCenter", "P1 Center", PAD::ControllerBindingType::Button, false},
{"Dance864P1PadRight", "P1 Right", PAD::ControllerBindingType::Button, false},
{"Dance864P2Start", "P2 Start", PAD::ControllerBindingType::Button, false},
{"Dance864P2Left", "P2 Select L", PAD::ControllerBindingType::Button, false},
{"Dance864P2Right", "P2 Select R", PAD::ControllerBindingType::Button, false},
{"Dance864P2PadLeft", "P2 Left", PAD::ControllerBindingType::Button, false},
{"Dance864P2PadCenter", "P2 Center", PAD::ControllerBindingType::Button, false},
{"Dance864P2PadRight", "P2 Right", PAD::ControllerBindingType::Button, false},
};
static const Python2BindingInfo s_python2_toysmarch_binds[] = {
{"ToysMarchP1Start", "P1 Start", PAD::ControllerBindingType::Button, false},
{"ToysMarchP1SelectL", "P1 Select L", PAD::ControllerBindingType::Button, false},
{"ToysMarchP1SelectR", "P1 Select R", PAD::ControllerBindingType::Button, false},
{"ToysMarchP1DrumL", "P1 Drum L", PAD::ControllerBindingType::Button, false},
{"ToysMarchP1DrumR", "P1 Drum R", PAD::ControllerBindingType::Button, false},
{"ToysMarchP1Cymbal", "P1 Cymbal", PAD::ControllerBindingType::Button, false},
{"ToysMarchP2Start", "P2 Start", PAD::ControllerBindingType::Button, false},
{"ToysMarchP2SelectL", "P2 Select L", PAD::ControllerBindingType::Button, false},
{"ToysMarchP2SelectR", "P2 Select R", PAD::ControllerBindingType::Button, false},
{"ToysMarchP2DrumL", "P2 Drum L", PAD::ControllerBindingType::Button, false},
{"ToysMarchP2DrumR", "P2 Drum R", PAD::ControllerBindingType::Button, false},
{"ToysMarchP2Cymbal", "P2 Cymbal", PAD::ControllerBindingType::Button, false},
};
static const Python2BindingInfo s_python2_icca_binds[] = {
{"KeypadP1_0", "P1 Keypad 0", PAD::ControllerBindingType::Button, false},
{"KeypadP1_1", "P1 Keypad 1", PAD::ControllerBindingType::Button, false},
{"KeypadP1_2", "P1 Keypad 2", PAD::ControllerBindingType::Button, false},
{"KeypadP1_3", "P1 Keypad 3", PAD::ControllerBindingType::Button, false},
{"KeypadP1_4", "P1 Keypad 4", PAD::ControllerBindingType::Button, false},
{"KeypadP1_5", "P1 Keypad 5", PAD::ControllerBindingType::Button, false},
{"KeypadP1_6", "P1 Keypad 6", PAD::ControllerBindingType::Button, false},
{"KeypadP1_7", "P1 Keypad 7", PAD::ControllerBindingType::Button, false},
{"KeypadP1_8", "P1 Keypad 8", PAD::ControllerBindingType::Button, false},
{"KeypadP1_9", "P1 Keypad 9", PAD::ControllerBindingType::Button, false},
{"KeypadP1_00", "P1 Keypad 00", PAD::ControllerBindingType::Button, false},
{"KeypadP1InsertEject", "P1 Insert/Eject Card", PAD::ControllerBindingType::Button, false},
{"KeypadP2_0", "P2 Keypad 0", PAD::ControllerBindingType::Button, false},
{"KeypadP2_1", "P2 Keypad 1", PAD::ControllerBindingType::Button, false},
{"KeypadP2_2", "P2 Keypad 2", PAD::ControllerBindingType::Button, false},
{"KeypadP2_3", "P2 Keypad 3", PAD::ControllerBindingType::Button, false},
{"KeypadP2_4", "P2 Keypad 4", PAD::ControllerBindingType::Button, false},
{"KeypadP2_5", "P2 Keypad 5", PAD::ControllerBindingType::Button, false},
{"KeypadP2_6", "P2 Keypad 6", PAD::ControllerBindingType::Button, false},
{"KeypadP2_7", "P2 Keypad 7", PAD::ControllerBindingType::Button, false},
{"KeypadP2_8", "P2 Keypad 8", PAD::ControllerBindingType::Button, false},
{"KeypadP2_9", "P2 Keypad 9", PAD::ControllerBindingType::Button, false},
{"KeypadP2_00", "P2 Keypad 00", PAD::ControllerBindingType::Button, false},
{"KeypadP2InsertEject", "P2 Insert/Eject Card", PAD::ControllerBindingType::Button, false},
};
static const Python2SystemInfo s_python2_system_info[] = {
{"All", nullptr, 0},
{"System", s_python2_system_binds, std::size(s_python2_system_binds)},
{"Dance 86.4", s_python2_dance864_binds, std::size(s_python2_dance864_binds)},
{"Dance Dance Revolution", s_python2_ddr_binds, std::size(s_python2_ddr_binds)},
{"Drummania", s_python2_drummania_binds, std::size(s_python2_drummania_binds)},
{"Guitar Freaks", s_python2_guitarfreaks_binds, std::size(s_python2_guitarfreaks_binds)},
{"Thrill Drive", s_python2_thrilldrive_binds, std::size(s_python2_thrilldrive_binds)},
{"Toy's March", s_python2_toysmarch_binds, std::size(s_python2_toysmarch_binds)},
{"Card Reader", s_python2_icca_binds, std::size(s_python2_icca_binds)},
};
namespace Python2QtInputManager
{
std::vector<Python2KeyMapping> GetCurrentMappings();
std::vector<Python2KeyMapping> GetMappingsByInputKey(std::string keyBindStr);
bool AddNewBinding(std::string full_key, std::string new_binding, double analogDeadzone, double analogSensitivity, double motorScale);
void RemoveMappingByUniqueId(uint32_t uniqueId);
void LoadMapping();
}

View File

@ -1,18 +1,3 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2020 PCSX2 Dev Team
*
* 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/>.
*/
#include "PrecompiledHeader.h"
#include <stdio.h>
@ -105,13 +90,8 @@ namespace usb_python2
{
const auto selectedIdx = dialog.GetSelectedGame();
#ifdef _WIN32
std::wstring selectedGameEntry = config.devListGroups[selectedIdx].ToStdWstring();
SaveSetting<std::wstring>(Python2Device::TypeName(), config.port, "python2", N_DEVICE, selectedGameEntry);
#else
std::string selectedGameEntry = config.devListGroups[selectedIdx].ToStdString();
SaveSetting<std::string>(Python2Device::TypeName(), config.port, "python2", N_DEVICE, selectedGameEntry);
#endif
SaveSetting(Python2Device::TypeName(), config.port, "python2", N_DEVICE, selectedGameEntry);
}
paused_core.AllowResume();

View File

@ -2,10 +2,12 @@
#include "USB/USB.h"
#include "usb-python2-btools.h"
#ifndef PCSX2_CORE
#include <wx/fileconf.h>
#include "gui/AppConfig.h"
#include "gui/StringHelpers.h"
#include "USB/shared/inifile_usb.h"
#endif
#include <algorithm>
#include <chrono>
@ -131,53 +133,57 @@ namespace usb_python2
return 0;
}
bool BToolsInput::GetKeyState(std::wstring keybind)
bool BToolsInput::GetKeyState(TSTDSTRING keybind)
{
if (keybind == L"Test")
if (keybind == "Test")
return ddrioState & (1 << DDR_TEST);
if (keybind == L"Service")
if (keybind == "Service")
return ddrioState & (1 << DDR_SERVICE);
if (keybind == L"Coin1")
if (keybind == "Coin1")
return ddrioState & (1 << DDR_COIN);
if (keybind == L"DdrP1Start")
if (keybind == "DdrP1Start")
return ddrioState & (1 << DDR_P1_START);
if (keybind == L"DdrP1SelectL")
if (keybind == "DdrP1Select")
return ddrioState & (1 << DDR_P1_MENU_LEFT);
if (keybind == L"DdrP1SelectR")
if (keybind == "DdrP1SelectR")
return ddrioState & (1 << DDR_P1_MENU_RIGHT);
if (keybind == L"DdrP1FootUp")
if (keybind == "DdrP1FootUp")
return ddrioState & (1 << DDR_P1_UP);
if (keybind == L"DdrP1FootDown")
if (keybind == "DdrP1FootDown")
return ddrioState & (1 << DDR_P1_DOWN);
if (keybind == L"DdrP1FootLeft")
if (keybind == "DdrP1FootLeft")
return ddrioState & (1 << DDR_P1_LEFT);
if (keybind == L"DdrP1FootRight")
if (keybind == "DdrP1FootRight")
return ddrioState & (1 << DDR_P1_RIGHT);
if (keybind == L"DdrP2Start")
if (keybind == "DdrP2Start")
return ddrioState & (1 << DDR_P2_START);
if (keybind == L"DdrP2SelectL")
if (keybind == "DdrP2Select")
return ddrioState & (1 << DDR_P2_MENU_LEFT);
if (keybind == L"DdrP2SelectR")
if (keybind == "DdrP2SelectR")
return ddrioState & (1 << DDR_P2_MENU_RIGHT);
if (keybind == L"DdrP2FootUp")
if (keybind == "DdrP2FootUp")
return ddrioState & (1 << DDR_P2_UP);
if (keybind == L"DdrP2FootDown")
if (keybind == "DdrP2FootDown")
return ddrioState & (1 << DDR_P2_DOWN);
if (keybind == L"DdrP2FootLeft")
if (keybind == "DdrP2FootLeft")
return ddrioState & (1 << DDR_P2_LEFT);
if (keybind == L"DdrP2FootRight")
if (keybind == "DdrP2FootRight")
return ddrioState & (1 << DDR_P2_RIGHT);
return false;
}
#ifndef PCSX2_CORE
void ConfigurePython2Btools(Python2DlgConfig& config);
#endif
int BToolsInput::Configure(int port, const char* dev_type, void* data)
{
#ifndef PCSX2_CORE
std::vector<wxString> devList;
std::vector<wxString> devListGroups;
@ -191,11 +197,11 @@ namespace usb_python2
for (auto itr = sections.begin(); itr != sections.end(); itr++)
{
auto groupName = (*itr)->GetSectionName();
if (groupName.find(L"GameEntry ") == 0)
if (groupName.find(TEXT("GameEntry ")) == 0)
{
devListGroups.push_back(wxString(groupName));
auto gameName = (*itr)->GetKeyValue(L"Name");
auto gameName = (*itr)->GetKeyValue(TEXT("Name"));
if (!gameName.empty())
devList.push_back(wxString(gameName));
}
@ -203,6 +209,7 @@ namespace usb_python2
Python2DlgConfig config(port, dev_type, devList, devListGroups);
ConfigurePython2Btools(config);
#endif
return 0;
}

View File

@ -14,6 +14,7 @@ namespace usb_python2
{
static const char* APINAME = "btools";
#ifndef PCSX2_CORE
struct Python2DlgConfig
{
int port;
@ -30,6 +31,7 @@ namespace usb_python2
{
}
};
#endif
class BToolsInput : public Python2Input
{
@ -58,12 +60,11 @@ namespace usb_python2
bool isPassthrough() override { return false; }
void UpdateKeyStates(std::wstring keybind) override {}
bool GetKeyState(std::wstring keybind);
bool GetKeyStateOneShot(std::wstring keybind) override { return false; }
double GetKeyStateAnalog(std::wstring keybind) override { return 0; }
bool IsKeybindAvailable(std::wstring keybind) override { return false; }
bool IsAnalogKeybindAvailable(std::wstring keybind) override { return false; }
void UpdateKeyStates(TSTDSTRING keybind) override {}
bool GetKeyState(TSTDSTRING keybind);
bool GetKeyStateOneShot(TSTDSTRING keybind) override { return false; }
double GetKeyStateAnalog(TSTDSTRING keybind) override { return 0; }
bool IsAnalogKeybindAvailable(TSTDSTRING keybind) override { return false; }
bool set_p3io_lights(uint8_t stateFromGame);

View File

@ -0,0 +1,195 @@
#include "PrecompiledHeader.h"
#include "USB/USB.h"
#include "usb-python2-native.h"
#include "pcsx2/HostSettings.h"
#include "common/SettingsInterface.h"
#include "common/StringUtil.h"
#include "PAD/Host/PAD.h"
#include "USB/usb-python2/inputs/Python2QtInputManager.h"
namespace usb_python2
{
namespace native
{
InputInterceptHook::CallbackResult NativeInput::ParseInput(InputBindingKey key, float value)
{
// TODO: Fix sticky input issue. Hold button, tab out, then tab back in. The button will be held until it's pressed again.
std::map<std::string, int> updatedInputState;
auto keyBindStr = InputManager::ConvertInputBindingKeyToString(key);
if (key.source_subtype != InputSubclass::PointerAxis && key.source_subtype != InputSubclass::ControllerAxis)
printf("Pressed button! %d %f %s\n", key.data, value, keyBindStr.c_str());
for (auto mappedKey : Python2QtInputManager::GetMappingsByInputKey(keyBindStr))
{
printf("\t%s %d\n", mappedKey.keybind.c_str(), mappedKey.isOneshot);
if (key.source_type == InputSourceType::Keyboard)
{
if (value == 0)
{
if (updatedInputState.find(mappedKey.keybind) == updatedInputState.end() || updatedInputState[mappedKey.keybind] == 0) // Only reset value if it wasn't set by a button already
updatedInputState[mappedKey.keybind] = keyboardButtonIsPressed[keyBindStr] ? 2 : 0;
}
else
{
if (!keyboardButtonIsPressed[keyBindStr])
updatedInputState[mappedKey.keybind] = 1 | (mappedKey.isOneshot ? 0x80 : 0);
}
}
else if (key.source_subtype == InputSubclass::ControllerAxis || key.source_subtype == InputSubclass::PointerAxis)
{
currentInputStateAnalog[mappedKey.keybind] = value;
}
else if (key.source_subtype == InputSubclass::ControllerButton || key.source_subtype == InputSubclass::PointerButton)
{
if (value == 0)
{
if (updatedInputState.find(mappedKey.keybind) == updatedInputState.end() || updatedInputState[mappedKey.keybind] == 0) // Only reset value if it wasn't set by a button already
updatedInputState[mappedKey.keybind] = gamepadButtonIsPressed[key.data | ((int)key.source_subtype << 28)] ? 2 : 0;
}
else
{
if (!gamepadButtonIsPressed[key.data | ((int)key.source_subtype << 28)])
updatedInputState[mappedKey.keybind] = 1 | (mappedKey.isOneshot ? 0x80 : 0);
}
}
}
if (key.source_type == InputSourceType::Keyboard)
{
keyboardButtonIsPressed[keyBindStr] = value != 0;
}
else if (key.source_subtype == InputSubclass::ControllerButton || key.source_subtype == InputSubclass::PointerButton)
{
gamepadButtonIsPressed[key.data | ((int)key.source_subtype << 28)] = value != 0;
}
for (auto& k : updatedInputState)
{
currentInputStatePad[k.first] = k.second;
if ((k.second & 3) == 1)
{
keyStateUpdates[k.first].push_back({std::chrono::steady_clock::now(), true});
if (k.second & 0x80)
{
// Oneshot
keyStateUpdates[k.first].push_back({std::chrono::steady_clock::now(), false});
}
}
else if ((k.second & 3) == 2)
{
keyStateUpdates[k.first].push_back({std::chrono::steady_clock::now(), false});
}
}
return InputInterceptHook::CallbackResult::ContinueProcessingEvent;
}
int NativeInput::Open()
{
Reset();
return 0;
}
int NativeInput::Close()
{
InputManager::RemoveHook();
return 0;
}
int NativeInput::Reset()
{
Close();
currentInputStateAnalog.clear();
currentKeyStates.clear();
keyStateUpdates.clear();
keyboardButtonIsPressed.clear();
gamepadButtonIsPressed.clear();
Python2QtInputManager::LoadMapping();
InputManager::SetHook([this](InputBindingKey key, float value) {
return this->ParseInput(key, value);
});
return 0;
}
void NativeInput::UpdateKeyStates(TSTDSTRING keybind)
{
if (!InputManager::HasHook()) {
// Input configuration menu also uses hooks so the I/O gets overwritten.
// If ParseInput is ever called while there is no hook set, it most likely means that the user just changed keybinds.
Reset();
}
const auto currentTimestamp = std::chrono::steady_clock::now();
while (keyStateUpdates[keybind].size() > 0)
{
auto curState = keyStateUpdates[keybind].front();
keyStateUpdates[keybind].pop_front();
// Remove stale inputs that occur during times where the game can't query for inputs.
// The timeout value is based on what felt ok to me so just adjust as needed.
const std::chrono::duration<double, std::milli> timestampDiff = currentTimestamp - curState.timestamp;
if (timestampDiff.count() > 50)
{
Console.WriteLn("Dropping delayed input... %s %ld ms late", keybind.c_str(), timestampDiff.count());
continue;
}
Console.WriteLn("Keystate update %s %d", keybind.c_str(), curState.state);
currentKeyStates[keybind] = curState.state;
break;
}
}
bool NativeInput::GetKeyState(TSTDSTRING keybind)
{
UpdateKeyStates(keybind);
auto it = currentKeyStates.find(keybind);
if (it != currentKeyStates.end())
return it->second;
return false;
}
bool NativeInput::GetKeyStateOneShot(TSTDSTRING keybind)
{
UpdateKeyStates(keybind);
auto isPressed = false;
auto it = currentKeyStates.find(keybind);
if (it != currentKeyStates.end())
{
isPressed = it->second;
it->second = false;
}
return isPressed;
}
double NativeInput::GetKeyStateAnalog(TSTDSTRING keybind)
{
const auto it = currentInputStateAnalog.find(keybind);
if (it == currentInputStateAnalog.end())
return 0;
return it->second;
}
bool NativeInput::IsAnalogKeybindAvailable(TSTDSTRING keybind)
{
return currentInputStateAnalog.find(keybind) != currentInputStateAnalog.end();
}
} // namespace native
} // namespace usb_python2

View File

@ -0,0 +1,93 @@
#ifndef USBPYTHON2NATIVE_H
#define USBPYTHON2NATIVE_H
#include <thread>
#include <array>
#include <atomic>
#include <chrono>
#include "Frontend/InputManager.h"
#include "USB/usb-python2/python2proxy.h"
#include "USB/usb-python2/usb-python2.h"
namespace usb_python2
{
namespace native
{
static const char* APINAME = "native";
struct InputStateUpdate
{
std::chrono::steady_clock::time_point timestamp;
bool state;
};
class NativeInput : public Python2Input
{
public:
NativeInput(int port, const char* dev_type)
: Python2Input(port, dev_type)
{
}
~NativeInput()
{
Close();
}
int Open() override;
int Close() override;
int ReadPacket(std::vector<uint8_t>& data) override { return 0; }
int WritePacket(const std::vector<uint8_t>& data) override { return 0; }
void ReadIo(std::vector<uint8_t>& data) override {}
int Reset() override;
bool isPassthrough() override { return false; }
InputInterceptHook::CallbackResult ParseInput(InputBindingKey key, float value);
static const TCHAR* Name()
{
return TEXT("Raw Input");
}
void UpdateKeyStates(TSTDSTRING keybind) override;
bool GetKeyState(TSTDSTRING keybind) override;
bool GetKeyStateOneShot(TSTDSTRING keybind) override;
double GetKeyStateAnalog(TSTDSTRING keybind) override;
bool IsAnalogKeybindAvailable(TSTDSTRING keybind) override;
static int Configure(int port, const char* dev_type, void* data) { return 0; }
protected:
private:
};
enum KeybindType
{
KeybindType_Button = 0,
KeybindType_Axis,
KeybindType_Hat,
KeybindType_Keyboard,
KeybindType_Motor,
};
struct KeyMapping
{
TSTDSTRING inputKey;
TSTDSTRING keybind;
double analogDeadzone;
double analogSensitivity;
double motorScale;
bool isOneshot; // Immediately trigger an off after on
};
static std::map<TSTDSTRING, std::deque<InputStateUpdate>> keyStateUpdates;
static std::map<TSTDSTRING, bool> isOneshotState;
static std::map<TSTDSTRING, bool> currentKeyStates;
static std::map<TSTDSTRING, int> currentInputStateKeyboard;
static std::map<TSTDSTRING, int> currentInputStatePad;
static std::map<TSTDSTRING, double> currentInputStateAnalog;
static std::map<TSTDSTRING, bool> keyboardButtonIsPressed;
static std::map<uint32_t, bool> gamepadButtonIsPressed;
} // namespace native
} // namespace usb_python2
#endif

View File

@ -2,10 +2,12 @@
#include "USB/USB.h"
#include "usb-python2-passthrough.h"
#ifndef PCSX2_CORE
#include <wx/fileconf.h>
#include "gui/AppConfig.h"
#include "gui/StringHelpers.h"
#include "USB/shared/inifile_usb.h"
#endif
#include <algorithm>
#include <chrono>
@ -102,34 +104,39 @@ namespace usb_python2
return 0;
}
#ifndef PCSX2_CORE
void ConfigurePython2Passthrough(Python2DlgConfig& config);
#endif
int PassthroughInput::Configure(int port, const char* dev_type, void* data)
{
#ifndef PCSX2_CORE
std::vector<wxString> devList;
std::vector<wxString> devListGroups;
const wxString iniPath = StringUtil::UTF8StringToWxString(Path::Combine(EmuFolders::Settings, "Python2.ini"));
CIniFile ciniFile;
CIniFileA ciniFile;
if (!ciniFile.Load(iniPath.ToStdWstring()))
if (!ciniFile.Load(iniPath.ToStdString()))
return 0;
auto sections = ciniFile.GetSections();
for (auto itr = sections.begin(); itr != sections.end(); itr++)
{
auto groupName = (*itr)->GetSectionName();
if (groupName.find(L"GameEntry ") == 0)
if (groupName.find("GameEntry ") == 0)
{
devListGroups.push_back(wxString(groupName));
devListGroups.push_back(StringUtil::UTF8StringToWxString(groupName));
auto gameName = (*itr)->GetKeyValue(L"Name");
auto gameName = (*itr)->GetKeyValue("Name");
if (!gameName.empty())
devList.push_back(wxString(gameName));
devList.push_back(StringUtil::UTF8StringToWxString(gameName));
}
}
Python2DlgConfig config(port, dev_type, devList, devListGroups);
ConfigurePython2Passthrough(config);
#endif
return 0;
}

View File

@ -5,9 +5,8 @@
#include <atomic>
#include "USB/usb-python2/python2proxy.h"
#include "USB/usb-python2/usb-python2.h"
#include "USB/readerwriterqueue/readerwriterqueue.h"
#include "libusb-1.0/libusb.h"
#include <libusb.h>
namespace usb_python2
@ -16,6 +15,7 @@ namespace usb_python2
{
static const char* APINAME = "passthrough";
#ifndef PCSX2_CORE
struct Python2DlgConfig
{
int port;
@ -32,6 +32,7 @@ namespace usb_python2
{
}
};
#endif
class PassthroughInput : public Python2Input
{
@ -58,12 +59,11 @@ namespace usb_python2
bool isPassthrough() override { return true; }
void UpdateKeyStates(std::wstring keybind) override {}
bool GetKeyState(std::wstring keybind) override { return false; }
bool GetKeyStateOneShot(std::wstring keybind) override { return false; }
double GetKeyStateAnalog(std::wstring keybind) override { return 0; }
bool IsKeybindAvailable(std::wstring keybind) override { return false; }
bool IsAnalogKeybindAvailable(std::wstring keybind) override { return false; }
void UpdateKeyStates(TSTDSTRING keybind) override {}
bool GetKeyState(TSTDSTRING keybind) override { return false; }
bool GetKeyStateOneShot(TSTDSTRING keybind) override { return false; }
double GetKeyStateAnalog(TSTDSTRING keybind) override { return 0; }
bool IsAnalogKeybindAvailable(TSTDSTRING keybind) override { return false; }
static const TCHAR* Name()
{

View File

@ -1,20 +1,3 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2020 PCSX2 Dev Team
*
* 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/>.
*/
// Used OBS as example
#include "PrecompiledHeader.h"
#include <windows.h>
@ -31,7 +14,7 @@
#include <windowsx.h>
#define MSG_PRESS_ESC(wnd) SendDlgItemMessageW(wnd, IDC_STATIC_CAP, WM_SETTEXT, 0, (LPARAM)L"Capturing, press ESC to cancel")
#define MSG_PRESS_ESC(wnd) SendDlgItemMessageW(wnd, IDC_STATIC_CAP, WM_SETTEXT, 0, (LPARAM)TEXT("Capturing, press ESC to cancel"))
namespace usb_python2
{
@ -58,7 +41,7 @@ namespace usb_python2
return std::wstring(tmp);
}
inline bool MapExists(const MapVector& maps, const std::wstring& hid)
inline bool MapExists(const MapVector& maps, const TSTDSTRING& hid)
{
for (auto& it : maps)
if (!it.hidPath.compare(hid))
@ -76,7 +59,7 @@ namespace usb_python2
int v = 0;
for (int j = 0; j < 25; j++)
{
std::wstring hid, tmp;
TSTDSTRING hid, tmp;
if (LoadSetting(dev_type, j, "RAW DEVICE", TEXT("HID"), hid) && !hid.empty() && !MapExists(maps, hid))
{
@ -96,15 +79,15 @@ namespace usb_python2
{
auto idx = tmp.find_first_of(L',');
if (idx == std::wstring::npos)
if (idx == std::string::npos)
idx = tmp.size();
auto substr = std::wstring(tmp.begin(), tmp.begin() + idx);
auto substr = std::string(tmp.begin(), tmp.begin() + idx);
uint32_t buttonType = 0;
uint32_t value = 0;
int isOneshot = 0;
swscanf_s(substr.c_str(), L"%02X|%08X|%d", &buttonType, &value, &isOneshot);
sscanf_s(substr.c_str(), "%02X|%08X|%d", &buttonType, &value, &isOneshot);
KeyMapping keybindMapping = {
uniqueKeybindIdx++,
@ -139,7 +122,7 @@ namespace usb_python2
{
if (it.mappings.size() > 0)
{
SaveSetting<std::wstring>(dev_type, numDevice, "RAW DEVICE", TEXT("HID"), it.hidPath);
SaveSetting(dev_type, numDevice, "RAW DEVICE", TEXT("HID"), it.hidPath);
std::map<int, std::vector<KeyMapping>> mapByKeybind;
@ -148,20 +131,20 @@ namespace usb_python2
for (auto& bindIt : mapByKeybind)
{
std::wstring val;
TSTDSTRING val;
for (auto& keymap : bindIt.second)
{
WCHAR tmp[255] = {0};
swprintf_s(tmp, 255, L"%02X|%08X|%d", keymap.bindType, keymap.value, keymap.isOneshot);
TCHAR tmp[255] = {0};
swprintf_s(tmp, 255, TEXT("%02X|%08X|%d"), keymap.bindType, keymap.value, keymap.isOneshot);
if (val.size() > 0)
val.append(L",");
val.append(TEXT(","));
val.append(std::wstring(tmp));
val.append(TSTDSTRING(tmp));
}
SaveSetting<std::wstring>(dev_type, numDevice, "RAW DEVICE", buttonLabelList[bindIt.first], val.c_str());
SaveSetting(dev_type, numDevice, "RAW DEVICE", buttonLabelList[bindIt.first], val.c_str());
}
}
@ -285,7 +268,7 @@ namespace usb_python2
UINT nameSize = 1024;
UINT pSize;
RID_DEVICE_INFO devInfo;
std::wstring devName;
TSTDSTRING devName;
//DevInfo_t mapDevInfo;
Mappings* mapping = NULL;
TCHAR buf[256];
@ -534,7 +517,7 @@ namespace usb_python2
LoadMappings(Python2Device::TypeName(), mapVector);
SendDlgItemMessage(hW, IDC_COMBO1, CB_RESETCONTENT, 0, 0);
std::wstring selectedDevice;
TSTDSTRING selectedDevice;
LoadSetting(Python2Device::TypeName(), cfg->port, APINAME, N_DEVICE, selectedDevice);
for (auto i = 0; i != cfg->devList.size(); i++)
{
@ -565,7 +548,7 @@ namespace usb_python2
// Save machine configuration selection
auto deviceIdx = ComboBox_GetCurSel(GetDlgItem(hW, IDC_COMBO1));
if (!SaveSetting<std::wstring>(Python2Device::TypeName(), cfg->port, APINAME, N_DEVICE, cfg->devListGroups[deviceIdx]))
if (!SaveSetting(Python2Device::TypeName(), cfg->port, APINAME, N_DEVICE, cfg->devListGroups[deviceIdx]))
res = RESULT_FAILED;
SaveMappings(Python2Device::TypeName(), mapVector);

View File

@ -1,35 +1,20 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2020 PCSX2 Dev Team
*
* 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/>.
*/
#include "PrecompiledHeader.h"
#include "USB/USB.h"
#include "USB/Win32/Config_usb.h"
#include "usb-python2-raw.h"
#ifndef PCSX2_CORE
#include <wx/fileconf.h>
#include "gui/AppConfig.h"
#include "gui/StringHelpers.h"
#include "USB/shared/inifile_usb.h"
#include "DEV9/DEV9.h"
#endif
namespace usb_python2
{
namespace raw
{
std::wstring getKeyLabel(const KeyMapping key);
TSTDSTRING getKeyLabel(const KeyMapping key);
uint32_t axisDiff2[32]; //previous axes values
bool axisPass22 = false;
@ -47,14 +32,14 @@ namespace usb_python2
TCHAR name[1024] = {0};
UINT nameSize = 1024;
RID_DEVICE_INFO devInfo = {0};
std::wstring devName;
TSTDSTRING devName;
USHORT capsLength = 0;
USAGE usage[32] = {0};
Mappings* mapping = NULL;
std::vector<uint32_t> usageCountButtons(countof(usage));
std::vector<uint32_t> usageCountHats(8);
std::map<wchar_t*, int> updatedInputState;
std::map<TCHAR*, int> updatedInputState;
auto iter = mappings.find(pRawInput->header.hDevice);
if (iter != mappings.end())
@ -197,8 +182,6 @@ namespace usb_python2
for (auto& k : updatedInputState)
{
currentInputStatePad[k.first] = k.second;
if ((k.second & 3) == 1)
{
keyStateUpdates[k.first].push_back({wxDateTime::UNow(), true});
@ -275,8 +258,6 @@ namespace usb_python2
Close();
mappings.clear();
currentInputStateKeyboard.clear();
currentInputStatePad.clear();
currentInputStateAnalog.clear();
currentKeyStates.clear();
keyStateUpdates.clear();
@ -286,7 +267,7 @@ namespace usb_python2
LoadMappings(mDevType, mapVector);
std::wstring selectedDevice;
TSTDSTRING selectedDevice;
LoadSetting(Python2Device::TypeName(), mPort, APINAME, N_DEVICE, selectedDevice);
shared::rawinput::RegisterCallback(this);
@ -299,7 +280,7 @@ namespace usb_python2
return 0;
}
void RawInputPad::UpdateKeyStates(std::wstring keybind)
void RawInputPad::UpdateKeyStates(TSTDSTRING keybind)
{
const auto currentTimestamp = wxDateTime::UNow();
while (keyStateUpdates[keybind].size() > 0)
@ -312,11 +293,11 @@ namespace usb_python2
const auto timestampDiff = currentTimestamp - curState.timestamp;
if (timestampDiff.GetMilliseconds() > 150)
{
//Console.WriteLn(L"Dropping delayed input... %s %ld ms late", keybind, timestampDiff);
//Console.WriteLn("Dropping delayed input... %s %ld ms late", keybind, timestampDiff);
continue;
}
//Console.WriteLn(L"Keystate update %s %d", keybind, curState.state);
//Console.WriteLn("Keystate update %s %d", keybind, curState.state);
currentKeyStates[keybind] = curState.state;
@ -324,7 +305,7 @@ namespace usb_python2
}
}
bool RawInputPad::GetKeyState(std::wstring keybind)
bool RawInputPad::GetKeyState(TSTDSTRING keybind)
{
UpdateKeyStates(keybind);
@ -335,7 +316,7 @@ namespace usb_python2
return false;
}
bool RawInputPad::GetKeyStateOneShot(std::wstring keybind)
bool RawInputPad::GetKeyStateOneShot(TSTDSTRING keybind)
{
UpdateKeyStates(keybind);
@ -350,7 +331,7 @@ namespace usb_python2
return isPressed;
}
double RawInputPad::GetKeyStateAnalog(std::wstring keybind)
double RawInputPad::GetKeyStateAnalog(TSTDSTRING keybind)
{
const auto it = currentInputStateAnalog.find(keybind);
if (it == currentInputStateAnalog.end())
@ -358,28 +339,27 @@ namespace usb_python2
return it->second;
}
bool RawInputPad::IsKeybindAvailable(std::wstring keybind)
{
return currentInputStateKeyboard.find(keybind) != currentInputStateKeyboard.end() || currentInputStatePad.find(keybind) != currentInputStatePad.end();
}
bool RawInputPad::IsAnalogKeybindAvailable(std::wstring keybind)
bool RawInputPad::IsAnalogKeybindAvailable(TSTDSTRING keybind)
{
return currentInputStateAnalog.find(keybind) != currentInputStateAnalog.end();
}
// ---------
#ifndef PCSX2_CORE
#include "python2-config-raw-res.h"
INT_PTR CALLBACK ConfigurePython2DlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam);
#endif
int RawInputPad::Configure(int port, const char* dev_type, void* data)
{
#ifndef PCSX2_CORE
Win32Handles* h = (Win32Handles*)data;
INT_PTR res = RESULT_FAILED;
if (shared::rawinput::Initialize(h->hWnd))
{
std::vector<std::wstring> devList;
std::vector<std::wstring> devListGroups;
std::vector<TSTDSTRING> devList;
std::vector<TSTDSTRING> devListGroups;
const wxString iniPath = StringUtil::UTF8StringToWxString(Path::Combine(EmuFolders::Settings, "Python2.ini"));
CIniFile ciniFile;
@ -391,11 +371,11 @@ namespace usb_python2
for (auto itr = sections.begin(); itr != sections.end(); itr++)
{
auto groupName = (*itr)->GetSectionName();
if (groupName.find(L"GameEntry ") == 0)
if (groupName.find(TEXT("GameEntry ")) == 0)
{
devListGroups.push_back(groupName);
auto gameName = (*itr)->GetKeyValue(L"Name");
auto gameName = (*itr)->GetKeyValue(TEXT("Name"));
if (!gameName.empty())
devList.push_back(gameName);
}
@ -406,7 +386,10 @@ namespace usb_python2
shared::rawinput::Uninitialize();
}
return (int)res;
#else
return 0;
#endif
}
} // namespace raw
} // namespace usb_pad
} // namespace usb_python2

View File

@ -0,0 +1,282 @@
#ifndef USBPYTHON2RAW_H
#define USBPYTHON2RAW_H
#include <thread>
#include <array>
#include <atomic>
#include "USB/usb-python2/python2proxy.h"
#include "USB/usb-python2/usb-python2.h"
#include "USB/shared/rawinput_usb.h"
namespace usb_python2
{
#define CHECK(exp) \
do \
{ \
if (!(exp)) \
goto Error; \
} while (0)
#define SAFE_FREE(p) \
do \
{ \
if (p) \
{ \
free(p); \
(p) = NULL; \
} \
} while (0)
namespace raw
{
struct InputStateUpdate
{
wxDateTime timestamp;
bool state;
};
const std::vector<TCHAR*> axisLabelList = {
TEXT("X"),
TEXT("Y"),
TEXT("Z"),
TEXT("RX"),
TEXT("RY"),
TEXT("RZ")};
const std::vector<TCHAR*> buttonDefaultOneshotList = {
TEXT("DmHihat"),
TEXT("DmSnare"),
TEXT("DmHighTom"),
TEXT("DmLowTom"),
TEXT("DmCymbal"),
TEXT("DmBassDrum"),
TEXT("GfP1Pick"),
TEXT("GfP2Pick")};
const std::vector<TCHAR*> buttonLabelList = {
// Machine
TEXT("Test"),
TEXT("Service"),
TEXT("Coin1"),
TEXT("Coin2"),
// Guitar Freaks
TEXT("GfP1Start"),
TEXT("GfP1Pick"),
TEXT("GfP1Wail"),
TEXT("GfP1EffectInc"),
TEXT("GfP1EffectDec"),
TEXT("GfP1NeckR"),
TEXT("GfP1NeckG"),
TEXT("GfP1NeckB"),
TEXT("GfP2Start"),
TEXT("GfP2Pick"),
TEXT("GfP2Wail"),
TEXT("GfP2EffectInc"),
TEXT("GfP2EffectDec"),
TEXT("GfP2NeckR"),
TEXT("GfP2NeckG"),
TEXT("GfP2NeckB"),
// Drummania
TEXT("DmStart"),
TEXT("DmSelectL"),
TEXT("DmSelectR"),
TEXT("DmHihat"),
TEXT("DmSnare"),
TEXT("DmHighTom"),
TEXT("DmLowTom"),
TEXT("DmCymbal"),
TEXT("DmBassDrum"),
// DDR
TEXT("DdrP1Start"),
TEXT("DdrP1SelectL"),
TEXT("DdrP1SelectR"),
TEXT("DdrP1FootLeft"),
TEXT("DdrP1FootDown"),
TEXT("DdrP1FootUp"),
TEXT("DdrP1FootRight"),
TEXT("DdrP2Start"),
TEXT("DdrP2SelectL"),
TEXT("DdrP2SelectR"),
TEXT("DdrP2FootLeft"),
TEXT("DdrP2FootDown"),
TEXT("DdrP2FootUp"),
TEXT("DdrP2FootRight"),
// Thrill Drive
TEXT("ThrillDriveStart"),
TEXT("ThrillDriveGearUp"),
TEXT("ThrillDriveGearDown"),
TEXT("ThrillDriveWheelAnalog"),
TEXT("ThrillDriveWheelLeft"),
TEXT("ThrillDriveWheelRight"),
TEXT("ThrillDriveAccelAnalog"),
TEXT("ThrillDriveAccel"),
TEXT("ThrillDriveBrake"),
TEXT("ThrillDriveBrakeAnalog"),
TEXT("ThrillDriveSeatbelt"),
// Toy's March
TEXT("ToysMarchP1Start"),
TEXT("ToysMarchP1SelectL"),
TEXT("ToysMarchP1SelectR"),
TEXT("ToysMarchP1DrumL"),
TEXT("ToysMarchP1DrumR"),
TEXT("ToysMarchP1Cymbal"),
TEXT("ToysMarchP2Start"),
TEXT("ToysMarchP2SelectL"),
TEXT("ToysMarchP2SelectR"),
TEXT("ToysMarchP2DrumL"),
TEXT("ToysMarchP2DrumR"),
TEXT("ToysMarchP2Cymbal"),
// Dance 86.4
TEXT("Dance864P1Start"),
TEXT("Dance864P1Left"),
TEXT("Dance864P1Right"),
TEXT("Dance864P1PadLeft"),
TEXT("Dance864P1PadCenter"),
TEXT("Dance864P1PadRight"),
TEXT("Dance864P2Start"),
TEXT("Dance864P2Left"),
TEXT("Dance864P2Right"),
TEXT("Dance864P2PadLeft"),
TEXT("Dance864P2PadCenter"),
TEXT("Dance864P2PadRight"),
// ICCA Card Reader
TEXT("KeypadP1_0"),
TEXT("KeypadP1_1"),
TEXT("KeypadP1_2"),
TEXT("KeypadP1_3"),
TEXT("KeypadP1_4"),
TEXT("KeypadP1_5"),
TEXT("KeypadP1_6"),
TEXT("KeypadP1_7"),
TEXT("KeypadP1_8"),
TEXT("KeypadP1_9"),
TEXT("KeypadP1_00"),
TEXT("KeypadP1InsertEject"),
TEXT("KeypadP2_0"),
TEXT("KeypadP2_1"),
TEXT("KeypadP2_2"),
TEXT("KeypadP2_3"),
TEXT("KeypadP2_4"),
TEXT("KeypadP2_5"),
TEXT("KeypadP2_6"),
TEXT("KeypadP2_7"),
TEXT("KeypadP2_8"),
TEXT("KeypadP2_9"),
TEXT("KeypadP2_00"),
TEXT("KeypadP2InsertEject"),
};
class RawInputPad : public Python2Input, shared::rawinput::ParseRawInputCB
{
public:
RawInputPad(int port, const char* dev_type)
: Python2Input(port, dev_type)
{
if (!InitHid())
throw UsbPython2Error("InitHid() failed!");
}
~RawInputPad()
{
Close();
}
int Open() override;
int Close() override;
int ReadPacket(std::vector<uint8_t>& data) override { return 0; };
int WritePacket(const std::vector<uint8_t>& data) override { return 0; };
void ReadIo(std::vector<uint8_t>& data) override {}
int Reset() override { return 0; }
void ParseRawInput(PRAWINPUT pRawInput);
bool isPassthrough() override { return false; }
static const TCHAR* Name()
{
return TEXT("Raw Input");
}
void UpdateKeyStates(TSTDSTRING keybind) override;
bool GetKeyState(TSTDSTRING keybind) override;
bool GetKeyStateOneShot(TSTDSTRING keybind) override;
double GetKeyStateAnalog(TSTDSTRING keybind) override;
bool IsAnalogKeybindAvailable(TSTDSTRING keybind) override;
static int Configure(int port, const char* dev_type, void* data);
protected:
private:
};
enum KeybindType
{
KeybindType_Button = 0,
KeybindType_Axis,
KeybindType_Hat,
KeybindType_Keyboard
};
struct KeyMapping
{
uint32_t uniqueId;
uint32_t keybindId;
uint32_t bindType; // 0 = button, 1 = axis, 2 = hat, 3 = keyboard
uint32_t value;
bool isOneshot; // Immediately trigger an off after on
};
struct Mappings
{
std::vector<KeyMapping> mappings;
TSTDSTRING devName;
#if _WIN32
TSTDSTRING hidPath;
#endif
};
#ifndef PCSX2_CORE
struct Python2DlgConfig
{
int port;
const char* dev_type;
const std::vector<TSTDSTRING> devList;
const std::vector<TSTDSTRING> devListGroups;
Python2DlgConfig(int p, const char* dev_type_, const std::vector<TSTDSTRING>& devList, const std::vector<TSTDSTRING>& devListGroups)
: port(p)
, dev_type(dev_type_)
, devList(devList)
, devListGroups(devListGroups)
{
}
};
#endif
typedef std::vector<Mappings> MapVector;
static MapVector mapVector;
static std::map<HANDLE, Mappings*> mappings;
static std::map<TSTDSTRING, std::deque<InputStateUpdate>> keyStateUpdates;
static std::map<TSTDSTRING, bool> isOneshotState;
static std::map<TSTDSTRING, bool> currentKeyStates;
static std::map<TSTDSTRING, double> currentInputStateAnalog;
static std::map<uint16_t, bool> keyboardButtonIsPressed;
static std::map<TSTDSTRING, std::map<uint32_t, bool>> gamepadButtonIsPressed;
void LoadMappings(const char* dev_type, MapVector& maps);
void SaveMappings(const char* dev_type, MapVector& maps);
} // namespace raw
} // namespace usb_python2
#endif

View File

@ -1,18 +1,3 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2020 PCSX2 Dev Team
*
* 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/>.
*/
#include "usb-python2.h"
#include "python2proxy.h"
@ -40,12 +25,11 @@ namespace usb_python2
int Reset() { return 0; }
bool isPassthrough() { return false; }
void UpdateKeyStates(std::wstring keybind) {};
bool GetKeyState(std::wstring keybind) { return false; };
bool GetKeyStateOneShot(std::wstring keybind) { return false; };
double GetKeyStateAnalog(std::wstring keybind) { return 0; };
bool IsKeybindAvailable(std::wstring keybind) { return false; };
bool IsAnalogKeybindAvailable(std::wstring keybind) { return false; };
void UpdateKeyStates(std::string keybind) {};
bool GetKeyState(std::string keybind) { return false; };
bool GetKeyStateOneShot(std::string keybind) { return false; };
double GetKeyStateAnalog(std::string keybind) { return 0; };
bool IsAnalogKeybindAvailable(std::string keybind) { return false; };
static const TCHAR* Name()
{
@ -59,4 +43,4 @@ namespace usb_python2
};
} // namespace noop
} // namespace usb_hid
} // namespace usb_python2

View File

@ -11,21 +11,20 @@
#include "IopMem.h"
#include "Patch.h"
#include <wx/ffile.h>
#include <wx/fileconf.h>
namespace usb_python2
{
std::thread mPatchSpdifAudioThread;
std::atomic<bool> mPatchSpdifAudioThreadIsRunning;
uint32_t mTargetWriteCmd = 0;
uint32_t mTargetPatchAddr = 0;
uint32_t mTargetIgnoreAddr = 0;
void Python2Patch::PatchSpdifAudioThread(void* ptr)
{
mPatchSpdifAudioThreadIsRunning = true;
mTargetWriteCmd = 0;
mTargetPatchAddr = 0;
mTargetIgnoreAddr = 0;
ForgetLoadedPatches();
@ -37,7 +36,7 @@ namespace usb_python2
#ifndef PCSX2_CORE
!GetCoreThread().IsOpen() || GetCoreThread().IsPaused()
#else
VMManager::GetState() != Running /* Untested */
VMManager::GetState() != VMState::Running
#endif
|| psxMemRLUT == NULL || psxMemWLUT == NULL)
continue;
@ -47,13 +46,14 @@ namespace usb_python2
// The GF games I looked all had the required code in this range, but it's possible there exists
// code in other places.
for (int i = 0x100000; i < 0x120000; i += 4)
for (uint32_t i = 0x100000; i < 0x120000; i += 4)
{
if (
#ifndef PCSX2_CORE
!GetCoreThread().IsOpen() || GetCoreThread().IsPaused()
#else
VMManager::GetState() != Running /* Untested */
VMManager::GetState() != VMState::Running
#endif
|| psxMemRLUT == NULL || psxMemWLUT == NULL)
break;
@ -64,17 +64,19 @@ namespace usb_python2
{
Console.WriteLn("Patching write @ %08x...", i);
// Patch write
IniPatch iPatch = {0};
iPatch.placetopatch = PPT_CONTINUOUSLY;
iPatch.cpu = CPU_IOP;
iPatch.addr = i;
iPatch.type = WORD_T;
iPatch.data = 0;
iPatch.oldData = iopMemRead32(iPatch.addr);
iPatch.hasOldData = true;
iPatch.enabled = 1;
LoadPatchFromMemory(iPatch);
if (i != mTargetIgnoreAddr) {
// Patch write
IniPatch iPatch = {0};
iPatch.placetopatch = PPT_CONTINUOUSLY;
iPatch.cpu = CPU_IOP;
iPatch.addr = i;
iPatch.type = WORD_T;
iPatch.data = 0;
iPatch.oldData = iopMemRead32(iPatch.addr);
iPatch.hasOldData = true;
iPatch.enabled = 1;
LoadPatchFromMemory(iPatch);
}
}
else if (
x == 0x00000000 &&
@ -82,7 +84,7 @@ namespace usb_python2
iopMemRead32(i + 12) == 0x24020001 &&
(iopMemRead32(i + 16) & 0xffffff00) == 0x3c010000 &&
(iopMemRead32(i + 20) & 0xffff0000) == 0xac220000 &&
(iopMemRead32(i + 24) & 0xffff0000) == 0x08040000 &&
(iopMemRead32(i + 24) & 0xff000000) == 0x08000000 &&
iopMemRead32(i + 28) == 0x00000000 &&
(iopMemRead32(i + 32) & 0xffffff00) == 0x3c010000)
{
@ -96,11 +98,9 @@ namespace usb_python2
mTargetWriteCmd = writeCmd;
mTargetPatchAddr = addr;
mTargetIgnoreAddr = i + 20;
// Find other writes along the way and patch those out
i += 28;
// Patch jump
// Patch jump so that we'll always write analog (1) into the variable at least once
IniPatch iPatch = {0};
iPatch.placetopatch = PPT_CONTINUOUSLY;
iPatch.cpu = CPU_IOP;
@ -124,6 +124,9 @@ namespace usb_python2
iPatch.enabled = 1;
LoadPatchFromMemory(iPatch);
// Find other writes along the way and patch those out
i += 28;
lastLoop = true;
}
}

View File

@ -1,18 +1,3 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2020 PCSX2 Dev Team
*
* 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/>.
*/
#ifndef USBPYTHON2PROXY_H
#define USBPYTHON2PROXY_H
#include <string>

View File

@ -1,299 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2020 PCSX2 Dev Team
*
* 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/>.
*/
#ifndef USBPYTHON2RAW_H
#define USBPYTHON2RAW_H
#include <thread>
#include <array>
#include <atomic>
#include "USB/usb-python2/python2proxy.h"
#include "USB/usb-python2/usb-python2.h"
#include "USB/shared/rawinput_usb.h"
#include "USB/readerwriterqueue/readerwriterqueue.h"
namespace usb_python2
{
#define CHECK(exp) \
do \
{ \
if (!(exp)) \
goto Error; \
} while (0)
#define SAFE_FREE(p) \
do \
{ \
if (p) \
{ \
free(p); \
(p) = NULL; \
} \
} while (0)
namespace raw
{
struct InputStateUpdate
{
wxDateTime timestamp;
bool state;
};
const std::vector<wchar_t*> axisLabelList = {
L"X",
L"Y",
L"Z",
L"RX",
L"RY",
L"RZ"};
const std::vector<wchar_t*> buttonDefaultOneshotList = {
L"DmHihat",
L"DmSnare",
L"DmHighTom",
L"DmLowTom",
L"DmCymbal",
L"DmBassDrum",
L"GfP1Pick",
L"GfP2Pick"};
const std::vector<wchar_t*> buttonLabelList = {
// Machine
L"Test",
L"Service",
L"Coin1",
L"Coin2",
// Guitar Freaks
L"GfP1Start",
L"GfP1Pick",
L"GfP1Wail",
L"GfP1EffectInc",
L"GfP1EffectDec",
L"GfP1NeckR",
L"GfP1NeckG",
L"GfP1NeckB",
L"GfP2Start",
L"GfP2Pick",
L"GfP2Wail",
L"GfP2EffectInc",
L"GfP2EffectDec",
L"GfP2NeckR",
L"GfP2NeckG",
L"GfP2NeckB",
// Drummania
L"DmStart",
L"DmSelectL",
L"DmSelectR",
L"DmHihat",
L"DmSnare",
L"DmHighTom",
L"DmLowTom",
L"DmCymbal",
L"DmBassDrum",
// DDR
L"DdrP1Start",
L"DdrP1SelectL",
L"DdrP1SelectR",
L"DdrP1FootLeft",
L"DdrP1FootDown",
L"DdrP1FootUp",
L"DdrP1FootRight",
L"DdrP2Start",
L"DdrP2SelectL",
L"DdrP2SelectR",
L"DdrP2FootLeft",
L"DdrP2FootDown",
L"DdrP2FootUp",
L"DdrP2FootRight",
// Thrill Drive
L"ThrillDriveStart",
L"ThrillDriveGearUp",
L"ThrillDriveGearDown",
L"ThrillDriveWheelAnalog",
L"ThrillDriveWheelLeft",
L"ThrillDriveWheelRight",
L"ThrillDriveAccelAnalog",
L"ThrillDriveAccel",
L"ThrillDriveBrake",
L"ThrillDriveBrakeAnalog",
L"ThrillDriveSeatbelt",
// Toy's March
L"ToysMarchP1Start",
L"ToysMarchP1SelectL",
L"ToysMarchP1SelectR",
L"ToysMarchP1DrumL",
L"ToysMarchP1DrumR",
L"ToysMarchP1Cymbal",
L"ToysMarchP2Start",
L"ToysMarchP2SelectL",
L"ToysMarchP2SelectR",
L"ToysMarchP2DrumL",
L"ToysMarchP2DrumR",
L"ToysMarchP2Cymbal",
// Dance 86.4
L"Dance864P1Start",
L"Dance864P1Left",
L"Dance864P1Right",
L"Dance864P1PadLeft",
L"Dance864P1PadCenter",
L"Dance864P1PadRight",
L"Dance864P2Start",
L"Dance864P2Left",
L"Dance864P2Right",
L"Dance864P2PadLeft",
L"Dance864P2PadCenter",
L"Dance864P2PadRight",
// ICCA Card Reader
L"KeypadP1_0",
L"KeypadP1_1",
L"KeypadP1_2",
L"KeypadP1_3",
L"KeypadP1_4",
L"KeypadP1_5",
L"KeypadP1_6",
L"KeypadP1_7",
L"KeypadP1_8",
L"KeypadP1_9",
L"KeypadP1_00",
L"KeypadP1InsertEject",
L"KeypadP2_0",
L"KeypadP2_1",
L"KeypadP2_2",
L"KeypadP2_3",
L"KeypadP2_4",
L"KeypadP2_5",
L"KeypadP2_6",
L"KeypadP2_7",
L"KeypadP2_8",
L"KeypadP2_9",
L"KeypadP2_00",
L"KeypadP2InsertEject",
};
class RawInputPad : public Python2Input, shared::rawinput::ParseRawInputCB
{
public:
RawInputPad(int port, const char* dev_type)
: Python2Input(port, dev_type)
{
if (!InitHid())
throw UsbPython2Error("InitHid() failed!");
}
~RawInputPad()
{
Close();
}
int Open() override;
int Close() override;
int ReadPacket(std::vector<uint8_t>& data) override { return 0; };
int WritePacket(const std::vector<uint8_t>& data) override { return 0; };
void ReadIo(std::vector<uint8_t>& data) override {}
int Reset() override { return 0; }
void ParseRawInput(PRAWINPUT pRawInput);
bool isPassthrough() override { return false; }
static const TCHAR* Name()
{
return TEXT("Raw Input");
}
void UpdateKeyStates(std::wstring keybind) override;
bool GetKeyState(std::wstring keybind) override;
bool GetKeyStateOneShot(std::wstring keybind) override;
double GetKeyStateAnalog(std::wstring keybind) override;
bool IsKeybindAvailable(std::wstring keybind) override;
bool IsAnalogKeybindAvailable(std::wstring keybind) override;
static int Configure(int port, const char* dev_type, void* data);
protected:
private:
};
enum KeybindType
{
KeybindType_Button = 0,
KeybindType_Axis,
KeybindType_Hat,
KeybindType_Keyboard
};
struct KeyMapping
{
uint32_t uniqueId;
uint32_t keybindId;
uint32_t bindType; // 0 = button, 1 = axis, 2 = hat, 3 = keyboard
uint32_t value;
bool isOneshot; // Immediately trigger an off after on
};
struct Mappings
{
std::vector<KeyMapping> mappings;
std::wstring devName;
#if _WIN32
std::wstring hidPath;
#endif
};
struct Python2DlgConfig
{
int port;
const char* dev_type;
const std::vector<std::wstring> devList;
const std::vector<std::wstring> devListGroups;
Python2DlgConfig(int p, const char* dev_type_, const std::vector<std::wstring>& devList, const std::vector<std::wstring>& devListGroups)
: port(p)
, dev_type(dev_type_)
, devList(devList)
, devListGroups(devListGroups)
{
}
};
typedef std::vector<Mappings> MapVector;
static MapVector mapVector;
static std::map<HANDLE, Mappings*> mappings;
static std::map<std::wstring, std::deque<InputStateUpdate>> keyStateUpdates;
static std::map<std::wstring, bool> isOneshotState;
static std::map<std::wstring, bool> currentKeyStates;
static std::map<std::wstring, int> currentInputStateKeyboard;
static std::map<std::wstring, int> currentInputStatePad;
static std::map<std::wstring, double> currentInputStateAnalog;
static std::map<USHORT, bool> keyboardButtonIsPressed;
static std::map<std::wstring, std::map<uint32_t, bool>> gamepadButtonIsPressed;
void LoadMappings(const char* dev_type, MapVector& maps);
void SaveMappings(const char* dev_type, MapVector& maps);
} // namespace raw
} // namespace usb_python2
#endif

View File

@ -1,40 +1,22 @@
/*
* QEMU USB HID devices
*
* Copyright (c) 2005 Fabrice Bellard
* Copyright (c) 2007 OpenMoko, Inc. (andrew@openedhand.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "PrecompiledHeader.h"
#include <algorithm>
#include <numeric>
#include <queue>
#include "common/FileSystem.h"
#include "common/Path.h"
#include "Config.h"
#ifndef PCSX2_CORE
#include "gui/AppConfig.h"
#include "gui/StringHelpers.h"
#include "gui/AppConfig.h"
#endif
#ifdef PCSX2_CORE
#include "pcsx2/HostSettings.h"
#include "common/SettingsInterface.h"
#include "Frontend/InputManager.h"
#endif
#include "USB/deviceproxy.h"
@ -50,9 +32,7 @@
#include "USB/usb-python2/devices/toysmarch_drumpad.h"
#include "USB/usb-python2/devices/icca.h"
#ifndef PCSX2_CORE
#include "patches.h"
#endif
#ifdef INCLUDE_MINIMAID
#include <mmmagic.h>
@ -60,7 +40,7 @@
#ifdef INCLUDE_BTOOLS
#include <bemanitools/ddrio.h>
#include <pcsx2/USB/usb-python2/btools/usb-python2-btools.h>
#include "USB/usb-python2/inputs/btools/usb-python2-btools.h"
HINSTANCE hDDRIO = nullptr;
@ -324,9 +304,78 @@ namespace usb_python2
void load_configuration(USBDevice* dev)
{
#ifndef PCSX2_CORE
auto s = reinterpret_cast<UsbPython2State*>(dev);
#ifdef PCSX2_CORE
SettingsInterface* si = Host::GetSettingsInterface(); // TODO: Fix this to load the appropriate config file
s->f.dipSwitch[0] = si->GetBoolValue("Python2/Game", "DIPSW1", false) ? '1' : '0';
s->f.dipSwitch[1] = si->GetBoolValue("Python2/Game", "DIPSW2", false) ? '1' : '0';
s->f.dipSwitch[2] = si->GetBoolValue("Python2/Game", "DIPSW3", false) ? '1' : '0';
s->f.dipSwitch[3] = si->GetBoolValue("Python2/Game", "DIPSW4", false) ? '1' : '0';
s->f.force31khz = si->GetBoolValue("Python2/Game", "Force31kHz", false);
Console.WriteLn("dipswitches: %c %c %c %c\n", s->f.dipSwitch[0], s->f.dipSwitch[1], s->f.dipSwitch[2], s->f.dipSwitch[3]);
Console.WriteLn("force31khz: %d\n", s->f.force31khz);
IlinkIdPath = si->GetStringValue("Python2/System", "IlinkIdFile", "");
Console.WriteLn("IlinkIdPath: %s", IlinkIdPath.c_str());
// PatchFileOverridePath = si->GetStringValue("Python2/Game", "PatchFile", "");
// Console.WriteLn("PatchFileOverridePath: %s", PatchFileOverridePath.c_str());
s->f.cardFilenames[0] = si->GetStringValue("Python2/Game", "Player1CardFile", "card1.txt");
Console.WriteLn("Player 1 card filename: %s", s->f.cardFilenames[0].c_str());
s->f.cardFilenames[1] = si->GetStringValue("Python2/Game", "Player2CardFile", "card2.txt");
Console.WriteLn("Player 2 card filename: %s", s->f.cardFilenames[0].c_str());
s->f.gameType = si->GetIntValue("Python2/Game", "GameType", 0);
Console.WriteLn("GameType: %d", s->f.gameType);
const std::string hddIdPath = si->GetStringValue("DEV9/Hdd", "HddIdFile", "");
Console.WriteLn("HddIdPath: %s", hddIdPath.c_str());
if (!hddIdPath.empty())
{
if (FileSystem::FileExists(hddIdPath.c_str()))
EmuConfig.DEV9.HddIdFile = hddIdPath;
}
auto dongleBlackPath = si->GetStringValue("Python2/Game", "DongleBlackFile", "");
Console.WriteLn("DongleBlackPath: %s", dongleBlackPath.c_str());
if (!dongleBlackPath.empty())
{
auto dongleFile = FileSystem::OpenManagedCFile(dongleBlackPath.c_str(), "rb");
if (dongleFile && FileSystem::FSize64(dongleFile.get()) >= 40)
{
std::fread(&s->f.dongleSlotPayload[0][0], 1, 40, dongleFile.get());
s->f.isDongleSlotLoaded[0] = true;
}
else
{
std::fill(std::begin(s->f.dongleSlotPayload[0]), std::end(s->f.dongleSlotPayload[0]), 0);
s->f.isDongleSlotLoaded[0] = false;
}
}
auto dongleWhitePath = si->GetStringValue("Python2/Game", "DongleWhiteFile", "");
Console.WriteLn("DongleWhitePath: %s", dongleWhitePath.c_str());
if (!dongleWhitePath.empty())
{
auto dongleFile = FileSystem::OpenManagedCFile(dongleWhitePath.c_str(), "rb");
if (dongleFile && FileSystem::FSize64(dongleFile.get()) >= 40)
{
std::fread(&s->f.dongleSlotPayload[1][0], 1, 40, dongleFile.get());
s->f.isDongleSlotLoaded[1] = true;
}
else
{
std::fill(std::begin(s->f.dongleSlotPayload[1]), std::end(s->f.dongleSlotPayload[1]), 0);
s->f.isDongleSlotLoaded[1] = false;
}
}
#else
// Called when the device is initialized so just load settings here
const wxString iniPath = StringUtil::UTF8StringToWxString(Path::Combine(EmuFolders::Settings, "Python2.ini"));
CIniFile ciniFile;
@ -343,10 +392,10 @@ namespace usb_python2
#endif
{
s->f.cardFilenames[0] = wstr_to_str(ciniFile.GetKeyValue(L"CardReader", L"Player1Card"));
s->f.cardFilenames[0] = wxString(ciniFile.GetKeyValue(L"CardReader", L"Player1Card")).ToStdString();
Console.WriteLn("Player 1 card filename: %s", s->f.cardFilenames[0].c_str());
s->f.cardFilenames[1] = wstr_to_str(ciniFile.GetKeyValue(L"CardReader", L"Player2Card"));
s->f.cardFilenames[1] = wxString(ciniFile.GetKeyValue(L"CardReader", L"Player2Card")).ToStdString();
Console.WriteLn("Player 2 card filename: %s", s->f.cardFilenames[1].c_str());
}
@ -354,10 +403,10 @@ namespace usb_python2
auto section = ciniFile.GetSection(selectedDevice);
if (section)
{
auto gameName = wstr_to_str(section->GetKeyValue(L"Name"));
auto gameName = wxString(section->GetKeyValue(L"Name")).ToStdString();
Console.WriteLn("Game Name: %s", gameName.c_str());
auto dongleBlackPath = wstr_to_str(section->GetKeyValue(L"DongleBlackPath"));
auto dongleBlackPath = wxString(section->GetKeyValue(L"DongleBlackPath")).ToStdString();
Console.WriteLn("DongleBlackPath: %s", dongleBlackPath.c_str());
if (!dongleBlackPath.empty())
{
@ -374,7 +423,7 @@ namespace usb_python2
}
}
auto dongleWhitePath = wstr_to_str(section->GetKeyValue(L"DongleWhitePath"));
auto dongleWhitePath = wxString(section->GetKeyValue(L"DongleWhitePath")).ToStdString();
Console.WriteLn("DongleWhitePath: %s", dongleWhitePath.c_str());
if (!dongleWhitePath.empty())
{
@ -391,19 +440,19 @@ namespace usb_python2
}
}
auto inputType = wstr_to_str(section->GetKeyValue(L"InputType"));
auto inputType = wxString(section->GetKeyValue(L"InputType")).ToStdString();
Console.WriteLn("InputType: %s", inputType.c_str());
s->f.gameType = 0;
if (!inputType.empty())
s->f.gameType = atoi(inputType.c_str());
auto dipSwitch = wstr_to_str(section->GetKeyValue(L"DipSwitch"));
auto dipSwitch = wxString(section->GetKeyValue(L"DipSwitch")).ToStdString();
Console.WriteLn("DipSwitch: %s", dipSwitch.c_str());
std::fill(std::begin(s->f.dipSwitch), std::end(s->f.dipSwitch), 0);
for (size_t j = 0; j < 4 && j < dipSwitch.size(); j++)
s->f.dipSwitch[j] = dipSwitch[j];
auto hddImagePath = wstr_to_str(section->GetKeyValue(L"HddImagePath"));
auto hddImagePath = wxString(section->GetKeyValue(L"HddImagePath")).ToStdString();
Console.WriteLn("HddImagePath: %s", hddImagePath.c_str());
EmuConfig.DEV9.HddFile = "";
if (!hddImagePath.empty())
@ -412,7 +461,7 @@ namespace usb_python2
EmuConfig.DEV9.HddFile = hddImagePath;
}
auto hddIdPath = wstr_to_str(section->GetKeyValue(L"HddIdPath"));
auto hddIdPath = wxString(section->GetKeyValue(L"HddIdPath")).ToStdString();
Console.WriteLn("HddIdPath: %s", hddIdPath.c_str());
EmuConfig.DEV9.HddIdFile = "";
if (!hddIdPath.empty())
@ -421,15 +470,15 @@ namespace usb_python2
EmuConfig.DEV9.HddIdFile = hddIdPath;
}
auto ilinkIdPath = wstr_to_str(section->GetKeyValue(L"IlinkIdPath"));
auto ilinkIdPath = wxString(section->GetKeyValue(L"IlinkIdPath")).ToStdString();
Console.WriteLn("IlinkIdPath: %s", ilinkIdPath.c_str());
IlinkIdPath = ilinkIdPath;
auto force31kHz = wstr_to_str(section->GetKeyValue(L"Force31kHz"));
auto force31kHz = wxString(section->GetKeyValue(L"Force31kHz")).ToStdString();
Console.WriteLn("Force31kHz: %s", force31kHz.c_str());
s->f.force31khz = force31kHz == "1";
auto patchFile = wstr_to_str(section->GetKeyValue(L"PatchFile"));
auto patchFile = wxString(section->GetKeyValue(L"PatchFile")).ToStdString();
Console.WriteLn("PatchFile: %s", patchFile.c_str());
PatchFileOverridePath = patchFile;
}
@ -471,7 +520,7 @@ namespace usb_python2
const uint8_t resp[] = {
'D', '4', '4', '\0', // product code
1, // major
6, // minor
6, // minor
4 // revision
};
data.insert(data.end(), std::begin(resp), std::end(resp));
@ -529,7 +578,7 @@ namespace usb_python2
else if (header->cmd == P2IO_CMD_COIN_STOCK)
{
Python2ConVerbose.WriteLn("P2IO_CMD_COIN_STOCK");
// Python2ConVerbose.WriteLn("P2IO_CMD_COIN_STOCK");
const uint8_t resp[] = {
0, // If this is non-zero then the following 4 bytes are not processed
@ -823,7 +872,7 @@ namespace usb_python2
#define CheckKeyState(key, val) \
{ \
if (s->p2dev->GetKeyState((key))) \
if (s->p2dev->GetKeyState(P2TEXT(key))) \
s->f.jammaIoStatus &= ~(val); \
else \
s->f.jammaIoStatus |= (val); \
@ -831,7 +880,7 @@ namespace usb_python2
#define CheckKeyStateOneShot(key, val) \
{ \
if (s->p2dev->GetKeyStateOneShot((key))) \
if (s->p2dev->GetKeyStateOneShot(P2TEXT(key))) \
s->f.jammaIoStatus &= ~(val); \
else \
s->f.jammaIoStatus |= (val); \
@ -839,13 +888,13 @@ namespace usb_python2
#define KnobStateInc(key, val, playerId) \
{ \
if (s->p2dev->GetKeyStateOneShot((key))) \
if (s->p2dev->GetKeyStateOneShot(P2TEXT(key))) \
s->f.knobs[(playerId)] = (s->f.knobs[(playerId)] + 1) % 4; \
}
#define KnobStateDec(key, val, playerId) \
{ \
if (s->p2dev->GetKeyStateOneShot((key))) \
if (s->p2dev->GetKeyStateOneShot(P2TEXT(key))) \
s->f.knobs[(playerId)] = (s->f.knobs[(playerId)] - 1) < 0 ? 3 : (s->f.knobs[(playerId)] - 1); \
}
@ -866,10 +915,10 @@ namespace usb_python2
}
// Handle inputs that shouldn't be oneshots typically on every update
CheckKeyState(L"Test", P2IO_JAMMA_IO_TEST);
CheckKeyState(L"Service", P2IO_JAMMA_IO_SERVICE);
CheckKeyState(L"Coin1", P2IO_JAMMA_IO_COIN1);
CheckKeyState(L"Coin2", P2IO_JAMMA_IO_COIN2);
CheckKeyState("Test", P2IO_JAMMA_IO_TEST);
CheckKeyState("Service", P2IO_JAMMA_IO_SERVICE);
CheckKeyState("Coin1", P2IO_JAMMA_IO_COIN1);
CheckKeyState("Coin2", P2IO_JAMMA_IO_COIN2);
// Python 2 games only accept coins via the P2IO directly, even though the game sees the JAMMA coin buttons returned here(?)
CoinInc(P2IO_JAMMA_IO_COIN1, 0);
@ -877,52 +926,52 @@ namespace usb_python2
if (s->f.gameType == GAMETYPE_DDR)
{
CheckKeyState(L"DdrP1Start", P2IO_JAMMA_DDR_P1_START);
CheckKeyState(L"DdrP1SelectL", P2IO_JAMMA_DDR_P1_LEFT);
CheckKeyState(L"DdrP1SelectR", P2IO_JAMMA_DDR_P1_RIGHT);
CheckKeyState(L"DdrP1FootLeft", P2IO_JAMMA_DDR_P1_FOOT_LEFT);
CheckKeyState(L"DdrP1FootDown", P2IO_JAMMA_DDR_P1_FOOT_DOWN);
CheckKeyState(L"DdrP1FootUp", P2IO_JAMMA_DDR_P1_FOOT_UP);
CheckKeyState(L"DdrP1FootRight", P2IO_JAMMA_DDR_P1_FOOT_RIGHT);
CheckKeyState("DdrP1Start", P2IO_JAMMA_DDR_P1_START);
CheckKeyState("DdrP1SelectL", P2IO_JAMMA_DDR_P1_LEFT);
CheckKeyState("DdrP1SelectR", P2IO_JAMMA_DDR_P1_RIGHT);
CheckKeyState("DdrP1FootLeft", P2IO_JAMMA_DDR_P1_FOOT_LEFT);
CheckKeyState("DdrP1FootDown", P2IO_JAMMA_DDR_P1_FOOT_DOWN);
CheckKeyState("DdrP1FootUp", P2IO_JAMMA_DDR_P1_FOOT_UP);
CheckKeyState("DdrP1FootRight", P2IO_JAMMA_DDR_P1_FOOT_RIGHT);
CheckKeyState(L"DdrP2Start", P2IO_JAMMA_DDR_P2_START);
CheckKeyState(L"DdrP2SelectL", P2IO_JAMMA_DDR_P2_LEFT);
CheckKeyState(L"DdrP2SelectR", P2IO_JAMMA_DDR_P2_RIGHT);
CheckKeyState(L"DdrP2FootLeft", P2IO_JAMMA_DDR_P2_FOOT_LEFT);
CheckKeyState(L"DdrP2FootDown", P2IO_JAMMA_DDR_P2_FOOT_DOWN);
CheckKeyState(L"DdrP2FootUp", P2IO_JAMMA_DDR_P2_FOOT_UP);
CheckKeyState(L"DdrP2FootRight", P2IO_JAMMA_DDR_P2_FOOT_RIGHT);
CheckKeyState("DdrP2Start", P2IO_JAMMA_DDR_P2_START);
CheckKeyState("DdrP2SelectL", P2IO_JAMMA_DDR_P2_LEFT);
CheckKeyState("DdrP2SelectR", P2IO_JAMMA_DDR_P2_RIGHT);
CheckKeyState("DdrP2FootLeft", P2IO_JAMMA_DDR_P2_FOOT_LEFT);
CheckKeyState("DdrP2FootDown", P2IO_JAMMA_DDR_P2_FOOT_DOWN);
CheckKeyState("DdrP2FootUp", P2IO_JAMMA_DDR_P2_FOOT_UP);
CheckKeyState("DdrP2FootRight", P2IO_JAMMA_DDR_P2_FOOT_RIGHT);
}
else if (s->f.gameType == GAMETYPE_THRILLDRIVE)
{
CheckKeyState(L"ThrillDriveStart", P2IO_JAMMA_THRILLDRIVE_START);
CheckKeyState("ThrillDriveStart", P2IO_JAMMA_THRILLDRIVE_START);
CheckKeyState(L"ThrillDriveGearUp", P2IO_JAMMA_THRILLDRIVE_GEARSHIFT_UP);
CheckKeyState(L"ThrillDriveGearDown", P2IO_JAMMA_THRILLDRIVE_GEARSHIFT_DOWN);
CheckKeyState("ThrillDriveGearUp", P2IO_JAMMA_THRILLDRIVE_GEARSHIFT_UP);
CheckKeyState("ThrillDriveGearDown", P2IO_JAMMA_THRILLDRIVE_GEARSHIFT_DOWN);
const auto isBrakePressed = s->p2dev->GetKeyState(L"ThrillDriveBrake");
const auto isBrakePressed = s->p2dev->GetKeyState(P2TEXT("ThrillDriveBrake"));
if (isBrakePressed)
s->f.brake = 0xffff;
else
s->f.brake = s->p2dev->GetKeyStateAnalog(L"ThrillDriveBrakeAnalog");
s->f.brake = s->p2dev->GetKeyStateAnalog(P2TEXT("ThrillDriveBrakeAnalog"));
const auto isAccelerationPressed = s->p2dev->GetKeyState(L"ThrillDriveAccel");
const auto isAccelerationPressed = s->p2dev->GetKeyState(P2TEXT("ThrillDriveAccel"));
if (isAccelerationPressed)
{
if (!isBrakePressed)
s->f.accel = 0xffff;
}
else
s->f.accel = s->p2dev->GetKeyStateAnalog(L"ThrillDriveAccelAnalog");
s->f.accel = s->p2dev->GetKeyStateAnalog(P2TEXT("ThrillDriveAccelAnalog"));
const auto isLeftWheelTurned = s->p2dev->GetKeyState(L"ThrillDriveWheelLeft");
const auto isRightWheelTurned = s->p2dev->GetKeyState(L"ThrillDriveWheelRight");
const auto isLeftWheelTurned = s->p2dev->GetKeyState(P2TEXT("ThrillDriveWheelLeft"));
const auto isRightWheelTurned = s->p2dev->GetKeyState(P2TEXT("ThrillDriveWheelRight"));
if (isLeftWheelTurned)
s->f.wheel = 0xffff;
else if (isRightWheelTurned)
s->f.wheel = 0;
else if (s->p2dev->IsAnalogKeybindAvailable(L"ThrillDriveWheelAnalog"))
s->f.wheel = uint16_t(0xffff - (0xffff * s->p2dev->GetKeyStateAnalog(L"ThrillDriveWheelAnalog")));
else if (s->p2dev->IsAnalogKeybindAvailable(P2TEXT("ThrillDriveWheelAnalog")))
s->f.wheel = uint16_t(0xffff - (0xffff * s->p2dev->GetKeyStateAnalog(P2TEXT("ThrillDriveWheelAnalog"))));
else
s->f.wheel = s->wheelCenter;
@ -944,51 +993,51 @@ namespace usb_python2
}
else if (s->f.gameType == GAMETYPE_DM)
{
CheckKeyState(L"DmSelectL", P2IO_JAMMA_DM_SELECT_L);
CheckKeyState(L"DmSelectR", P2IO_JAMMA_DM_SELECT_R);
CheckKeyState(L"DmStart", P2IO_JAMMA_DM_START);
CheckKeyState("DmSelectL", P2IO_JAMMA_DM_SELECT_L);
CheckKeyState("DmSelectR", P2IO_JAMMA_DM_SELECT_R);
CheckKeyState("DmStart", P2IO_JAMMA_DM_START);
}
else if (s->f.gameType == GAMETYPE_GF)
{
CheckKeyState(L"GfP1Start", P2IO_JAMMA_GF_P1_START);
CheckKeyState(L"GfP1NeckR", P2IO_JAMMA_GF_P1_R);
CheckKeyState(L"GfP1NeckG", P2IO_JAMMA_GF_P1_G);
CheckKeyState(L"GfP1NeckB", P2IO_JAMMA_GF_P1_B);
CheckKeyState(L"GfP1Wail", P2IO_JAMMA_GF_P1_WAILING);
CheckKeyState("GfP1Start", P2IO_JAMMA_GF_P1_START);
CheckKeyState("GfP1NeckR", P2IO_JAMMA_GF_P1_R);
CheckKeyState("GfP1NeckG", P2IO_JAMMA_GF_P1_G);
CheckKeyState("GfP1NeckB", P2IO_JAMMA_GF_P1_B);
CheckKeyState("GfP1Wail", P2IO_JAMMA_GF_P1_WAILING);
CheckKeyState(L"GfP2Start", P2IO_JAMMA_GF_P2_START);
CheckKeyState(L"GfP2NeckR", P2IO_JAMMA_GF_P2_R);
CheckKeyState(L"GfP2NeckG", P2IO_JAMMA_GF_P2_G);
CheckKeyState(L"GfP2NeckB", P2IO_JAMMA_GF_P2_B);
CheckKeyState(L"GfP2Wail", P2IO_JAMMA_GF_P2_WAILING);
CheckKeyState("GfP2Start", P2IO_JAMMA_GF_P2_START);
CheckKeyState("GfP2NeckR", P2IO_JAMMA_GF_P2_R);
CheckKeyState("GfP2NeckG", P2IO_JAMMA_GF_P2_G);
CheckKeyState("GfP2NeckB", P2IO_JAMMA_GF_P2_B);
CheckKeyState("GfP2Wail", P2IO_JAMMA_GF_P2_WAILING);
}
else if (s->f.gameType == GAMETYPE_TOYSMARCH)
{
CheckKeyState(L"ToysMarchP1Start", P2IO_JAMMA_TOYSMARCH_P1_START);
CheckKeyState(L"ToysMarchP1SelectL", P2IO_JAMMA_TOYSMARCH_P1_LEFT);
CheckKeyState(L"ToysMarchP1SelectR", P2IO_JAMMA_TOYSMARCH_P1_RIGHT);
CheckKeyState(L"ToysMarchP2Start", P2IO_JAMMA_TOYSMARCH_P2_START);
CheckKeyState(L"ToysMarchP2SelectL", P2IO_JAMMA_TOYSMARCH_P2_LEFT);
CheckKeyState(L"ToysMarchP2SelectR", P2IO_JAMMA_TOYSMARCH_P2_RIGHT);
CheckKeyState("ToysMarchP1Start", P2IO_JAMMA_TOYSMARCH_P1_START);
CheckKeyState("ToysMarchP1SelectL", P2IO_JAMMA_TOYSMARCH_P1_LEFT);
CheckKeyState("ToysMarchP1SelectR", P2IO_JAMMA_TOYSMARCH_P1_RIGHT);
CheckKeyState("ToysMarchP2Start", P2IO_JAMMA_TOYSMARCH_P2_START);
CheckKeyState("ToysMarchP2SelectL", P2IO_JAMMA_TOYSMARCH_P2_LEFT);
CheckKeyState("ToysMarchP2SelectR", P2IO_JAMMA_TOYSMARCH_P2_RIGHT);
}
else if (s->f.gameType == GAMETYPE_DANCE864)
{
CheckKeyState(L"Dance864P1Start", P2IO_JAMMA_DANCE864_P1_START);
CheckKeyState(L"Dance864P1Left", P2IO_JAMMA_DANCE864_P1_LEFT);
CheckKeyState(L"Dance864P1Right", P2IO_JAMMA_DANCE864_P1_RIGHT);
CheckKeyState(L"Dance864P2Start", P2IO_JAMMA_DANCE864_P2_START);
CheckKeyState(L"Dance864P2Left", P2IO_JAMMA_DANCE864_P2_LEFT);
CheckKeyState(L"Dance864P2Right", P2IO_JAMMA_DANCE864_P2_RIGHT);
CheckKeyState("Dance864P1Start", P2IO_JAMMA_DANCE864_P1_START);
CheckKeyState("Dance864P1Left", P2IO_JAMMA_DANCE864_P1_LEFT);
CheckKeyState("Dance864P1Right", P2IO_JAMMA_DANCE864_P1_RIGHT);
CheckKeyState("Dance864P2Start", P2IO_JAMMA_DANCE864_P2_START);
CheckKeyState("Dance864P2Left", P2IO_JAMMA_DANCE864_P2_LEFT);
CheckKeyState("Dance864P2Right", P2IO_JAMMA_DANCE864_P2_RIGHT);
if (s->f.footPanelIoCheckHack < 0)
{
CheckKeyState(L"Dance864P1PadLeft", P2IO_JAMMA_DANCE864_P1_PAD_LEFT);
CheckKeyState(L"Dance864P1PadCenter", P2IO_JAMMA_DANCE864_P1_PAD_CENTER);
CheckKeyState(L"Dance864P1PadRight", P2IO_JAMMA_DANCE864_P1_PAD_RIGHT);
CheckKeyState("Dance864P1PadLeft", P2IO_JAMMA_DANCE864_P1_PAD_LEFT);
CheckKeyState("Dance864P1PadCenter", P2IO_JAMMA_DANCE864_P1_PAD_CENTER);
CheckKeyState("Dance864P1PadRight", P2IO_JAMMA_DANCE864_P1_PAD_RIGHT);
CheckKeyState(L"Dance864P2PadLeft", P2IO_JAMMA_DANCE864_P2_PAD_LEFT);
CheckKeyState(L"Dance864P2PadCenter", P2IO_JAMMA_DANCE864_P2_PAD_CENTER);
CheckKeyState(L"Dance864P2PadRight", P2IO_JAMMA_DANCE864_P2_PAD_RIGHT);
CheckKeyState("Dance864P2PadLeft", P2IO_JAMMA_DANCE864_P2_PAD_LEFT);
CheckKeyState("Dance864P2PadCenter", P2IO_JAMMA_DANCE864_P2_PAD_CENTER);
CheckKeyState("Dance864P2PadRight", P2IO_JAMMA_DANCE864_P2_PAD_RIGHT);
}
}
@ -1000,25 +1049,25 @@ namespace usb_python2
{
if (s->f.gameType == GAMETYPE_DM)
{
CheckKeyStateOneShot(L"DmHihat", P2IO_JAMMA_DM_HIHAT);
CheckKeyStateOneShot(L"DmSnare", P2IO_JAMMA_DM_SNARE);
CheckKeyStateOneShot(L"DmHighTom", P2IO_JAMMA_DM_HIGH_TOM);
CheckKeyStateOneShot(L"DmLowTom", P2IO_JAMMA_DM_LOW_TOM);
CheckKeyStateOneShot(L"DmCymbal", P2IO_JAMMA_DM_CYMBAL);
CheckKeyStateOneShot("DmHihat", P2IO_JAMMA_DM_HIHAT);
CheckKeyStateOneShot("DmSnare", P2IO_JAMMA_DM_SNARE);
CheckKeyStateOneShot("DmHighTom", P2IO_JAMMA_DM_HIGH_TOM);
CheckKeyStateOneShot("DmLowTom", P2IO_JAMMA_DM_LOW_TOM);
CheckKeyStateOneShot("DmCymbal", P2IO_JAMMA_DM_CYMBAL);
// Bass pedal is not a one shot and can be held techically
CheckKeyStateOneShot(L"DmBassDrum", P2IO_JAMMA_DM_BASS_DRUM);
CheckKeyStateOneShot("DmBassDrum", P2IO_JAMMA_DM_BASS_DRUM);
}
else if (s->f.gameType == GAMETYPE_GF)
{
CheckKeyState(L"GfP1Pick", P2IO_JAMMA_GF_P1_PICK);
CheckKeyState(L"GfP2Pick", P2IO_JAMMA_GF_P2_PICK);
CheckKeyState("GfP1Pick", P2IO_JAMMA_GF_P1_PICK);
CheckKeyState("GfP2Pick", P2IO_JAMMA_GF_P2_PICK);
KnobStateInc(L"GfP1EffectInc", P2IO_JAMMA_GF_P1_EFFECT1, 0);
KnobStateDec(L"GfP1EffectDec", P2IO_JAMMA_GF_P1_EFFECT2, 0);
KnobStateInc("GfP1EffectInc", P2IO_JAMMA_GF_P1_EFFECT1, 0);
KnobStateDec("GfP1EffectDec", P2IO_JAMMA_GF_P1_EFFECT2, 0);
KnobStateInc(L"GfP2EffectInc", P2IO_JAMMA_GF_P2_EFFECT1, 1);
KnobStateDec(L"GfP2EffectDec", P2IO_JAMMA_GF_P2_EFFECT2, 1);
KnobStateInc("GfP2EffectInc", P2IO_JAMMA_GF_P2_EFFECT1, 1);
KnobStateDec("GfP2EffectDec", P2IO_JAMMA_GF_P2_EFFECT2, 1);
s->f.jammaIoStatus |= P2IO_JAMMA_GF_P1_EFFECT3;
if (s->f.knobs[0] == 1)
@ -1150,7 +1199,6 @@ namespace usb_python2
if (s)
{
#ifndef PCSX2_CORE
// Load the configuration and start SPDIF patcher thread every time a game is started
load_configuration(dev);
@ -1160,7 +1208,6 @@ namespace usb_python2
mPatchSpdifAudioThread.join();
mPatchSpdifAudioThread = std::thread(Python2Patch::PatchSpdifAudioThread, s->p2dev);
}
#endif
initialize_device(dev);
@ -1182,7 +1229,10 @@ namespace usb_python2
DevCon.WriteLn("%s\n", __func__);
std::string varApi;
#ifndef PCSX2_CORE
#ifdef PCSX2_CORE
varApi = "native";
#else
#ifdef _WIN32
std::wstring tmp;
LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, tmp);
@ -1190,8 +1240,6 @@ namespace usb_python2
#else
LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, varApi);
#endif
#else
varApi = "noop";
#endif
const UsbPython2ProxyBase* proxy = RegisterUsbPython2::instance().Proxy(varApi);

View File

@ -1,18 +1,3 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2020 PCSX2 Dev Team
*
* 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/>.
*/
#pragma once
#include <thread>
#include <atomic>
@ -180,12 +165,11 @@ namespace usb_python2
virtual int Port() { return mPort; }
virtual void Port(int port) { mPort = port; }
virtual void UpdateKeyStates(std::wstring keybind) = 0;
virtual bool GetKeyState(std::wstring keybind) = 0;
virtual bool GetKeyStateOneShot(std::wstring keybind) = 0;
virtual double GetKeyStateAnalog(std::wstring keybind) = 0;
virtual bool IsKeybindAvailable(std::wstring keybind) = 0;
virtual bool IsAnalogKeybindAvailable(std::wstring keybind) = 0;
virtual void UpdateKeyStates(TSTDSTRING keybind) = 0;
virtual bool GetKeyState(TSTDSTRING keybind) = 0;
virtual bool GetKeyStateOneShot(TSTDSTRING keybind) = 0;
virtual double GetKeyStateAnalog(TSTDSTRING keybind) = 0;
virtual bool IsAnalogKeybindAvailable(TSTDSTRING keybind) = 0;
protected:
int mPort;

View File

@ -137,6 +137,10 @@ static u32 s_frame_advance_count = 0;
static u32 s_mxcsr_saved;
static std::optional<LimiterModeType> s_limiter_mode_prior_to_hold_interaction;
static bool s_is_python2 = false;
static u32 s_python2_crc = 0;
static std::string s_python2_serial;
bool VMManager::PerformEarlyHardwareChecks(const char** error)
{
#define COMMON_DOWNLOAD_MESSAGE \
@ -630,6 +634,11 @@ void VMManager::UpdateRunningGame(bool resetting, bool game_starting)
new_serial = GSDumpReplayer::GetDumpSerial();
}
if (s_is_python2) {
new_crc = ElfCRC = s_python2_crc;
new_serial = s_python2_serial;
}
if (!resetting && s_game_crc == new_crc && s_game_serial == new_serial)
return;
@ -791,6 +800,16 @@ bool VMManager::ApplyBootParameters(const VMBootParameters& params, std::string*
EmuConfig.UseBOOT2Injection = true;
}
s_is_python2 = params.is_python2.has_value() && params.is_python2.value();
if (s_is_python2) {
// Set parameters for Python 2
s_python2_crc = params.python2_crc.has_value() ? params.python2_crc.value() : 0;
s_python2_serial = params.python2_serial.has_value() ? params.python2_serial.value() : "";
} else {
s_python2_crc = 0;
s_python2_serial = "";
}
return true;
}
@ -839,6 +858,8 @@ bool VMManager::Initialize(const VMBootParameters& boot_params)
if (!ApplyBootParameters(boot_params, &state_to_load))
return false;
UpdateRunningGame(true, false); // Add this here so we can get the loaded settings in the Python 2 USB code
EmuConfig.LimiterMode = GetInitialLimiterMode();
// early out if we don't have a bios
@ -889,17 +910,6 @@ bool VMManager::Initialize(const VMBootParameters& boot_params)
PADshutdown();
};
Console.WriteLn("Opening DEV9...");
if (DEV9init() != 0 || DEV9open() != 0)
{
Host::ReportErrorAsync("Startup Error", "Failed to initialize DEV9.");
return false;
}
ScopedGuard close_dev9 = []() {
DEV9close();
DEV9shutdown();
};
Console.WriteLn("Opening USB...");
if (USBinit() != 0 || USBopen(Host::GetHostDisplay()->GetWindowInfo()) != 0)
{
@ -911,6 +921,17 @@ bool VMManager::Initialize(const VMBootParameters& boot_params)
USBshutdown();
};
Console.WriteLn("Opening DEV9...");
if (DEV9init() != 0 || DEV9open() != 0)
{
Host::ReportErrorAsync("Startup Error", "Failed to initialize DEV9.");
return false;
}
ScopedGuard close_dev9 = []() {
DEV9close();
DEV9shutdown();
};
Console.WriteLn("Opening FW...");
if (FWopen() != 0)
{

View File

@ -48,6 +48,11 @@ struct VMBootParameters
std::optional<bool> fast_boot;
std::optional<bool> fullscreen;
// For Python 2
std::optional<bool> is_python2;
std::optional<u32> python2_crc;
std::optional<std::string> python2_serial;
};
namespace VMManager

View File

@ -33,52 +33,52 @@
<TargetName>$(EXEString)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LibraryPath>$(SolutionDir)3rdparty\libmmmagic\lib\windows-64bit;$(SolutionDir)3rdparty\bemanitools;$(SolutionDir)3rdparty\libusb\MS64\dll;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64)</LibraryPath>
<IncludePath>$(SolutionDir)3rdparty\libmmmagic\include;$(SolutionDir)3rdparty\libusb\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
<LibraryPath>$(SolutionDir)3rdparty\libmmmagic\lib\windows-64bit;$(SolutionDir)3rdparty\bemanitools;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64)</LibraryPath>
<IncludePath>$(SolutionDir)\3rdparty\libusb\libusb\libusb;$(SolutionDir)3rdparty\libmmmagic\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug AVX2|x64'">
<LibraryPath>$(SolutionDir)3rdparty\libmmmagic\lib\windows-64bit;$(SolutionDir)3rdparty\bemanitools;$(SolutionDir)3rdparty\libusb\MS64\dll;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64)</LibraryPath>
<IncludePath>$(SolutionDir)3rdparty\libmmmagic\include;$(SolutionDir)3rdparty\libusb\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
<LibraryPath>$(SolutionDir)3rdparty\libmmmagic\lib\windows-64bit;$(SolutionDir)3rdparty\bemanitools;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64)</LibraryPath>
<IncludePath>$(SolutionDir)\3rdparty\libusb\libusb\libusb;$(SolutionDir)3rdparty\libmmmagic\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Devel|x64'">
<LibraryPath>$(SolutionDir)3rdparty\libmmmagic\lib\windows-64bit;$(SolutionDir)3rdparty\bemanitools;$(SolutionDir)3rdparty\libusb\MS64\dll;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64)</LibraryPath>
<IncludePath>$(SolutionDir)3rdparty\libmmmagic\include;$(SolutionDir)3rdparty\libusb\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
<LibraryPath>$(SolutionDir)3rdparty\libmmmagic\lib\windows-64bit;$(SolutionDir)3rdparty\bemanitools;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64)</LibraryPath>
<IncludePath>$(SolutionDir)\3rdparty\libusb\libusb\libusb;$(SolutionDir)3rdparty\libmmmagic\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Devel AVX2|x64'">
<LibraryPath>$(SolutionDir)3rdparty\libmmmagic\lib\windows-64bit;$(SolutionDir)3rdparty\bemanitools;$(SolutionDir)3rdparty\libusb\MS64\dll;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64)</LibraryPath>
<IncludePath>$(SolutionDir)3rdparty\libmmmagic\include;$(SolutionDir)3rdparty\libusb\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
<LibraryPath>$(SolutionDir)3rdparty\libmmmagic\lib\windows-64bit;$(SolutionDir)3rdparty\bemanitools;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64)</LibraryPath>
<IncludePath>$(SolutionDir)\3rdparty\libusb\libusb\libusb;$(SolutionDir)3rdparty\libmmmagic\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LibraryPath>$(SolutionDir)3rdparty\libmmmagic\lib\windows-64bit;$(SolutionDir)3rdparty\bemanitools;$(SolutionDir)3rdparty\libusb\MS64\dll;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64)</LibraryPath>
<IncludePath>$(SolutionDir)3rdparty\libmmmagic\include;$(SolutionDir)3rdparty\libusb\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
<LibraryPath>$(SolutionDir)3rdparty\libmmmagic\lib\windows-64bit;$(SolutionDir)3rdparty\bemanitools;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64)</LibraryPath>
<IncludePath>$(SolutionDir)\3rdparty\libusb\libusb\libusb;$(SolutionDir)3rdparty\libmmmagic\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release AVX2|x64'">
<LibraryPath>$(SolutionDir)3rdparty\libmmmagic\lib\windows-64bit;$(SolutionDir)3rdparty\bemanitools;$(SolutionDir)3rdparty\libusb\MS64\dll;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64)</LibraryPath>
<IncludePath>$(SolutionDir)3rdparty\libmmmagic\include;$(SolutionDir)3rdparty\libusb\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
<LibraryPath>$(SolutionDir)3rdparty\libmmmagic\lib\windows-64bit;$(SolutionDir)3rdparty\bemanitools;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64)</LibraryPath>
<IncludePath>$(SolutionDir)\3rdparty\libusb\libusb\libusb;$(SolutionDir)3rdparty\libmmmagic\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LibraryPath>$(SolutionDir)3rdparty\libmmmagic\lib\windows-32bit;$(SolutionDir)3rdparty\bemanitools;$(SolutionDir)3rdparty\libusb\MS32\dll;$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86)</LibraryPath>
<IncludePath>$(SolutionDir)3rdparty\libmmmagic\include;$(SolutionDir)3rdparty\libusb\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
<LibraryPath>$(SolutionDir)3rdparty\libmmmagic\lib\windows-32bit;$(SolutionDir)3rdparty\bemanitools;$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86)</LibraryPath>
<IncludePath>$(SolutionDir)3rdparty\libmmmagic\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug AVX2|Win32'">
<LibraryPath>$(SolutionDir)3rdparty\libmmmagic\lib\windows-32bit;$(SolutionDir)3rdparty\bemanitools;$(SolutionDir)3rdparty\libusb\MS32\dll;$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86)</LibraryPath>
<IncludePath>$(SolutionDir)3rdparty\libmmmagic\include;$(SolutionDir)3rdparty\libusb\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
<LibraryPath>$(SolutionDir)3rdparty\libmmmagic\lib\windows-32bit;$(SolutionDir)3rdparty\bemanitools;$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86)</LibraryPath>
<IncludePath>$(SolutionDir)3rdparty\libmmmagic\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Devel|Win32'">
<LibraryPath>$(SolutionDir)3rdparty\libmmmagic\lib\windows-32bit;$(SolutionDir)3rdparty\bemanitools;$(SolutionDir)3rdparty\libusb\MS32\dll;$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86)</LibraryPath>
<IncludePath>$(SolutionDir)3rdparty\libmmmagic\include;$(SolutionDir)3rdparty\libusb\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
<LibraryPath>$(SolutionDir)3rdparty\libmmmagic\lib\windows-32bit;$(SolutionDir)3rdparty\bemanitools;$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86)</LibraryPath>
<IncludePath>$(SolutionDir)3rdparty\libmmmagic\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Devel AVX2|Win32'">
<LibraryPath>$(SolutionDir)3rdparty\libmmmagic\lib\windows-32bit;$(SolutionDir)3rdparty\bemanitools;$(SolutionDir)3rdparty\libusb\MS32\dll;$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86)</LibraryPath>
<IncludePath>$(SolutionDir)3rdparty\libmmmagic\include;$(SolutionDir)3rdparty\libusb\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
<LibraryPath>$(SolutionDir)3rdparty\libmmmagic\lib\windows-32bit;$(SolutionDir)3rdparty\bemanitools;$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86)</LibraryPath>
<IncludePath>$(SolutionDir)3rdparty\libmmmagic\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LibraryPath>$(SolutionDir)3rdparty\libmmmagic\lib\windows-32bit;$(SolutionDir)3rdparty\bemanitools;$(SolutionDir)3rdparty\libusb\MS32\dll;$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86)</LibraryPath>
<IncludePath>$(SolutionDir)3rdparty\libmmmagic\include;$(SolutionDir)3rdparty\libusb\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
<LibraryPath>$(SolutionDir)3rdparty\libmmmagic\lib\windows-32bit;$(SolutionDir)3rdparty\bemanitools;$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86)</LibraryPath>
<IncludePath>$(SolutionDir)3rdparty\libmmmagic\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release AVX2|Win32'">
<LibraryPath>$(SolutionDir)3rdparty\libmmmagic\lib\windows-32bit;$(SolutionDir)3rdparty\bemanitools;$(SolutionDir)3rdparty\libusb\MS32\dll;$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86)</LibraryPath>
<IncludePath>$(SolutionDir)3rdparty\libmmmagic\include;$(SolutionDir)3rdparty\libusb\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
<LibraryPath>$(SolutionDir)3rdparty\libmmmagic\lib\windows-32bit;$(SolutionDir)3rdparty\bemanitools;$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86)</LibraryPath>
<IncludePath>$(SolutionDir)3rdparty\libmmmagic\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
@ -120,7 +120,7 @@
<Link>
<LargeAddressAware>Yes</LargeAddressAware>
<AdditionalDependencies>comctl32.lib;ws2_32.lib;shlwapi.lib;winmm.lib;rpcrt4.lib;iphlpapi.lib;dsound.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>libmmmagic.a;libusb-1.0.lib;dxguid.lib;dinput8.lib;hid.lib;PowrProf.lib;d3dcompiler.lib;d3d11.lib;dxgi.lib;strmiids.lib;opengl32.lib;comsuppw.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>libmmmagic.a;dxguid.lib;dinput8.lib;hid.lib;PowrProf.lib;d3dcompiler.lib;d3d11.lib;dxgi.lib;strmiids.lib;opengl32.lib;comsuppw.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ImageHasSafeExceptionHandlers Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ImageHasSafeExceptionHandlers>
<ImageHasSafeExceptionHandlers Condition="'$(Configuration)|$(Platform)'=='Debug AVX2|x64'">false</ImageHasSafeExceptionHandlers>
<ImageHasSafeExceptionHandlers Condition="'$(Configuration)|$(Platform)'=='Devel|x64'">false</ImageHasSafeExceptionHandlers>
@ -134,42 +134,6 @@
<ImageHasSafeExceptionHandlers Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ImageHasSafeExceptionHandlers>
<ImageHasSafeExceptionHandlers Condition="'$(Configuration)|$(Platform)'=='Release AVX2|Win32'">false</ImageHasSafeExceptionHandlers>
</Link>
<PostBuildEvent>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">xcopy /y $(SolutionDir)3rdparty\libusb\MS64\dll\libusb-1.0.dll $(OutDirFullPath)</Command>
</PostBuildEvent>
<PostBuildEvent>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug AVX2|x64'">xcopy /y $(SolutionDir)3rdparty\libusb\MS64\dll\libusb-1.0.dll $(OutDirFullPath)</Command>
</PostBuildEvent>
<PostBuildEvent>
<Command Condition="'$(Configuration)|$(Platform)'=='Devel|x64'">xcopy /y $(SolutionDir)3rdparty\libusb\MS64\dll\libusb-1.0.dll $(OutDirFullPath)</Command>
</PostBuildEvent>
<PostBuildEvent>
<Command Condition="'$(Configuration)|$(Platform)'=='Devel AVX2|x64'">xcopy /y $(SolutionDir)3rdparty\libusb\MS64\dll\libusb-1.0.dll $(OutDirFullPath)</Command>
</PostBuildEvent>
<PostBuildEvent>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">xcopy /y $(SolutionDir)3rdparty\libusb\MS64\dll\libusb-1.0.dll $(OutDirFullPath)</Command>
</PostBuildEvent>
<PostBuildEvent>
<Command Condition="'$(Configuration)|$(Platform)'=='Release AVX2|x64'">xcopy /y $(SolutionDir)3rdparty\libusb\MS64\dll\libusb-1.0.dll $(OutDirFullPath)</Command>
</PostBuildEvent>
<PostBuildEvent>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">xcopy /y $(SolutionDir)3rdparty\libusb\MS32\dll\libusb-1.0.dll $(OutDirFullPath)</Command>
</PostBuildEvent>
<PostBuildEvent>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug AVX2|Win32'">xcopy /y $(SolutionDir)3rdparty\libusb\MS32\dll\libusb-1.0.dll $(OutDirFullPath)</Command>
</PostBuildEvent>
<PostBuildEvent>
<Command Condition="'$(Configuration)|$(Platform)'=='Devel|Win32'">xcopy /y $(SolutionDir)3rdparty\libusb\MS32\dll\libusb-1.0.dll $(OutDirFullPath)</Command>
</PostBuildEvent>
<PostBuildEvent>
<Command Condition="'$(Configuration)|$(Platform)'=='Devel AVX2|Win32'">xcopy /y $(SolutionDir)3rdparty\libusb\MS32\dll\libusb-1.0.dll $(OutDirFullPath)</Command>
</PostBuildEvent>
<PostBuildEvent>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">xcopy /y $(SolutionDir)3rdparty\libusb\MS32\dll\libusb-1.0.dll $(OutDirFullPath)</Command>
</PostBuildEvent>
<PostBuildEvent>
<Command Condition="'$(Configuration)|$(Platform)'=='Release AVX2|Win32'">xcopy /y $(SolutionDir)3rdparty\libusb\MS32\dll\libusb-1.0.dll $(OutDirFullPath)</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<None Include="..\bin\resources\shaders\vulkan\convert.glsl" />
@ -595,19 +559,19 @@
<ClCompile Include="USB\usb-pad\usb-pad.cpp" />
<ClCompile Include="USB\usb-pad\usb-seamic.cpp" />
<ClCompile Include="USB\usb-python2\api_init_win32_hid.cpp" />
<ClCompile Include="USB\usb-python2\btools\python2-config-btools.cpp" />
<ClCompile Include="USB\usb-python2\btools\usb-python2-btools.cpp" />
<ClCompile Include="USB\usb-python2\devices\acio.cpp" />
<ClCompile Include="USB\usb-python2\devices\ddr_extio.cpp" />
<ClCompile Include="USB\usb-python2\devices\icca.cpp" />
<ClCompile Include="USB\usb-python2\devices\thrilldrive_belt.cpp" />
<ClCompile Include="USB\usb-python2\devices\thrilldrive_handle.cpp" />
<ClCompile Include="USB\usb-python2\devices\toysmarch_drumpad.cpp" />
<ClCompile Include="USB\usb-python2\passthrough\python2-config-passthrough.cpp" />
<ClCompile Include="USB\usb-python2\passthrough\usb-python2-passthrough.cpp" />
<ClCompile Include="USB\usb-python2\inputs\btools\python2-config-btools.cpp" />
<ClCompile Include="USB\usb-python2\inputs\btools\usb-python2-btools.cpp" />
<ClCompile Include="USB\usb-python2\inputs\passthrough\python2-config-passthrough.cpp" />
<ClCompile Include="USB\usb-python2\inputs\passthrough\usb-python2-passthrough.cpp" />
<ClCompile Include="USB\usb-python2\inputs\raw\python2-config-raw.cpp" />
<ClCompile Include="USB\usb-python2\inputs\raw\usb-python2-raw.cpp" />
<ClCompile Include="USB\usb-python2\patches.cpp" />
<ClCompile Include="USB\usb-python2\raw\python2-config-raw.cpp" />
<ClCompile Include="USB\usb-python2\raw\usb-python2-raw.cpp" />
<ClCompile Include="USB\usb-python2\usb-python2.cpp" />
<ClCompile Include="USB\usb-printer\usb-printer.cpp" />
<ClCompile Include="USB\USB.cpp" />
@ -1125,7 +1089,6 @@
<ClInclude Include="USB\usb-pad\raw\raw-config-res.h" />
<ClInclude Include="USB\usb-pad\raw\usb-pad-raw.h" />
<ClInclude Include="USB\usb-pad\usb-pad.h" />
<ClInclude Include="USB\usb-python2\btools\usb-python2-btools.h" />
<ClInclude Include="USB\usb-python2\devices\acio.h" />
<ClInclude Include="USB\usb-python2\devices\icca.h" />
<ClInclude Include="USB\usb-python2\devices\thrilldrive_belt.h" />
@ -1133,11 +1096,12 @@
<ClInclude Include="USB\usb-python2\devices\thrilldrive_handle.h" />
<ClInclude Include="USB\usb-python2\devices\input_device.h" />
<ClInclude Include="USB\usb-python2\devices\toysmarch_drumpad.h" />
<ClInclude Include="USB\usb-python2\passthrough\usb-python2-passthrough.h" />
<ClInclude Include="USB\usb-python2\inputs\btools\usb-python2-btools.h" />
<ClInclude Include="USB\usb-python2\inputs\passthrough\usb-python2-passthrough.h" />
<ClInclude Include="USB\usb-python2\inputs\raw\python2-config-raw-res.h" />
<ClInclude Include="USB\usb-python2\inputs\raw\usb-python2-raw.h" />
<ClInclude Include="USB\usb-python2\patches.h" />
<ClInclude Include="USB\usb-python2\python2proxy.h" />
<ClInclude Include="USB\usb-python2\raw\python2-config-raw-res.h" />
<ClInclude Include="USB\usb-python2\raw\usb-python2-raw.h" />
<ClInclude Include="USB\usb-python2\usb-python2.h" />
<ClInclude Include="USB\usb-printer\usb-printer.h" />
<ClInclude Include="USB\USB.h" />
@ -1291,7 +1255,7 @@
<ResourceCompile Include="SPU2\Windows\SPU2.rc" />
<ResourceCompile Include="USB\usb-pad\dx\versionproxy.rc" />
<ResourceCompile Include="USB\usb-pad\raw\raw-config.rc" />
<ResourceCompile Include="USB\usb-python2\raw\python2-config-raw.rc" />
<ResourceCompile Include="USB\usb-python2\inputs\raw\python2-config-raw.rc" />
<ResourceCompile Include="USB\Win32\USBDialog.rc" />
<ResourceCompile Include="windows\wxResources.rc" />
</ItemGroup>
@ -1356,6 +1320,9 @@
<ProjectReference Include="$(SolutionDir)3rdparty\imgui\imgui.vcxproj">
<Project>{88fb34ec-845e-4f21-a552-f1573b9ed167}</Project>
</ProjectReference>
<ProjectReference Include="..\3rdparty\libusb\libusb.vcxproj">
<Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project>
</ProjectReference>
<ProjectReference Include="..\3rdparty\libzip\libzip.vcxproj">
<Project>{20b2e9fe-f020-42a0-b324-956f5b06ea68}</Project>
</ProjectReference>

View File

@ -289,9 +289,6 @@
<Filter Include="System\Ps2\USB\usb-python2">
<UniqueIdentifier>{bb0f1450-811a-47f7-9224-af7979108bea}</UniqueIdentifier>
</Filter>
<Filter Include="System\Ps2\USB\usb-python2\raw">
<UniqueIdentifier>{6e7cffc4-c6a0-4b63-8672-ad561a0fc19a}</UniqueIdentifier>
</Filter>
<Filter Include="System\Ps2\USB\usb-python2\devices">
<UniqueIdentifier>{bc0b7c38-447a-4cfc-a13d-f135eed7338a}</UniqueIdentifier>
</Filter>
@ -304,12 +301,6 @@
<Filter Include="System\Ps2\USB\usb-python2\devices\toysmarch">
<UniqueIdentifier>{02363106-af40-450a-9ec4-d28177b58106}</UniqueIdentifier>
</Filter>
<Filter Include="System\Ps2\USB\usb-python2\passthrough">
<UniqueIdentifier>{05dcd9a6-e244-49b2-aa3e-d5b1513cd2ca}</UniqueIdentifier>
</Filter>
<Filter Include="System\Ps2\USB\usb-python2\btools">
<UniqueIdentifier>{5f3a7bab-b96f-4123-8e5c-1c447c0403f4}</UniqueIdentifier>
</Filter>
<Filter Include="System\Ps2\GS\GIF">
<UniqueIdentifier>{78f5077b-255e-435e-9a51-352171dfaee8}</UniqueIdentifier>
</Filter>
@ -1736,9 +1727,6 @@
<ClCompile Include="USB\usb-python2\usb-python2.cpp">
<Filter>System\Ps2\USB\usb-python2</Filter>
</ClCompile>
<ClCompile Include="USB\usb-python2\raw\usb-python2-raw.cpp">
<Filter>System\Ps2\USB\usb-python2\raw</Filter>
</ClCompile>
<ClCompile Include="USB\usb-python2\devices\acio.cpp">
<Filter>System\Ps2\USB\usb-python2\devices</Filter>
</ClCompile>
@ -1760,15 +1748,6 @@
<ClCompile Include="USB\usb-python2\devices\toysmarch_drumpad.cpp">
<Filter>System\Ps2\USB\usb-python2\devices\toysmarch</Filter>
</ClCompile>
<ClCompile Include="USB\usb-python2\passthrough\usb-python2-passthrough.cpp">
<Filter>System\Ps2\USB\usb-python2\passthrough</Filter>
</ClCompile>
<ClCompile Include="USB\usb-python2\raw\python2-config-raw.cpp">
<Filter>System\Ps2\USB\usb-python2\raw</Filter>
</ClCompile>
<ClCompile Include="USB\usb-python2\passthrough\python2-config-passthrough.cpp">
<Filter>System\Ps2\USB\usb-python2\passthrough</Filter>
</ClCompile>
<ClCompile Include="gui\AppHost.cpp">
<Filter>AppHost</Filter>
</ClCompile>
@ -1811,12 +1790,6 @@
<ClCompile Include="GS\Renderers\HW\GSTextureReplacementLoaders.cpp">
<Filter>System\Ps2\GS\Renderers\Hardware</Filter>
</ClCompile>
<ClCompile Include="USB\usb-python2\btools\python2-config-btools.cpp">
<Filter>System\Ps2\USB\usb-python2\btools</Filter>
</ClCompile>
<ClCompile Include="USB\usb-python2\btools\usb-python2-btools.cpp">
<Filter>System\Ps2\USB\usb-python2\btools</Filter>
</ClCompile>
<ClCompile Include="x86\iR5900Analysis.cpp">
<Filter>System\Ps2\EmotionEngine\EE\Dynarec</Filter>
</ClCompile>
@ -1865,6 +1838,12 @@
<ClCompile Include="gui\PathUtils.cpp">
<Filter>AppHost</Filter>
</ClCompile>
<ClCompile Include="USB\usb-python2\inputs\btools\python2-config-btools.cpp" />
<ClCompile Include="USB\usb-python2\inputs\btools\usb-python2-btools.cpp" />
<ClCompile Include="USB\usb-python2\inputs\passthrough\python2-config-passthrough.cpp" />
<ClCompile Include="USB\usb-python2\inputs\passthrough\usb-python2-passthrough.cpp" />
<ClCompile Include="USB\usb-python2\inputs\raw\python2-config-raw.cpp" />
<ClCompile Include="USB\usb-python2\inputs\raw\usb-python2-raw.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="Patch.h">
@ -2995,9 +2974,6 @@
<ClInclude Include="USB\usb-python2\usb-python2.h">
<Filter>System\Ps2\USB\usb-python2</Filter>
</ClInclude>
<ClInclude Include="USB\usb-python2\raw\usb-python2-raw.h">
<Filter>System\Ps2\USB\usb-python2\raw</Filter>
</ClInclude>
<ClInclude Include="USB\usb-python2\devices\acio.h">
<Filter>System\Ps2\USB\usb-python2\devices</Filter>
</ClInclude>
@ -3022,15 +2998,6 @@
<ClInclude Include="USB\usb-python2\devices\toysmarch_drumpad.h">
<Filter>System\Ps2\USB\usb-python2\devices\toysmarch</Filter>
</ClInclude>
<ClInclude Include="USB\usb-python2\btools\usb-python2-btools.h">
<Filter>System\Ps2\USB\usb-python2\btools</Filter>
</ClInclude>
<ClInclude Include="USB\usb-python2\passthrough\usb-python2-passthrough.h">
<Filter>System\Ps2\USB\usb-python2\passthrough</Filter>
</ClInclude>
<ClInclude Include="USB\usb-python2\raw\python2-config-raw-res.h">
<Filter>System\Ps2\USB\usb-python2\raw</Filter>
</ClInclude>
<ClInclude Include="PAD\Gamepad.h">
<Filter>System\Ps2\PAD</Filter>
</ClInclude>
@ -3102,6 +3069,10 @@
<ClInclude Include="gui\StringHelpers.h">
<Filter>AppHost</Filter>
</ClInclude>
<ClInclude Include="USB\usb-python2\inputs\btools\usb-python2-btools.h" />
<ClInclude Include="USB\usb-python2\inputs\passthrough\usb-python2-passthrough.h" />
<ClInclude Include="USB\usb-python2\inputs\raw\python2-config-raw-res.h" />
<ClInclude Include="USB\usb-python2\inputs\raw\usb-python2-raw.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="windows\wxResources.rc">
@ -3131,9 +3102,7 @@
<ResourceCompile Include="GS\GS.rc">
<Filter>System\Ps2\GS</Filter>
</ResourceCompile>
<ResourceCompile Include="USB\usb-python2\raw\python2-config-raw.rc">
<Filter>System\Ps2\USB\usb-python2\raw</Filter>
</ResourceCompile>
<ResourceCompile Include="USB\usb-python2\inputs\raw\python2-config-raw.rc" />
</ItemGroup>
<ItemGroup>
<CustomBuildStep Include="rdebug\deci2.h">

View File

@ -46,6 +46,7 @@
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\sdl2\include;$(SolutionDir)3rdparty\sdl2\SDL\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\libzip;$(SolutionDir)3rdparty\libzip\libzip\lib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\d3d12memalloc\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\libusb\libusb\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\zstd\zstd\lib</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\cpuinfo\include</AdditionalIncludeDirectories>
<ExceptionHandling>Async</ExceptionHandling>
@ -317,7 +318,6 @@
<ClCompile Include="GS\Renderers\SW\GSVertexSW.cpp" />
<ClCompile Include="GS\Renderers\Common\GSVertexTrace.cpp" />
<ClCompile Include="SPU2\Windows\SndOut_XAudio2.cpp" />
<ClCompile Include="USB\USBNull.cpp" />
<ClCompile Include="Dump.cpp" />
<ClCompile Include="VMManager.cpp" />
<ClCompile Include="windows\Optimus.cpp" />
@ -446,6 +446,34 @@
<ClCompile Include="CDVD\IsoFS\IsoFile.cpp" />
<ClCompile Include="CDVD\IsoFS\IsoFS.cpp" />
<ClCompile Include="CDVD\IsoFS\IsoFSCDVD.cpp" />
<ClCompile Include="USB\USB.cpp" />
<ClCompile Include="USB\deviceproxy.cpp" />
<ClCompile Include="USB\device_init.cpp" />
<ClCompile Include="USB\qemu-usb\bus.cpp" />
<ClCompile Include="USB\qemu-usb\core.cpp" />
<ClCompile Include="USB\qemu-usb\desc.cpp" />
<ClCompile Include="USB\qemu-usb\glib.cpp" />
<ClCompile Include="USB\qemu-usb\hid.cpp" />
<ClCompile Include="USB\qemu-usb\input-keymap-qcode-to-qnum.cpp" />
<ClCompile Include="USB\qemu-usb\input-keymap-win32-to-qcode.cpp" />
<ClCompile Include="USB\qemu-usb\iov.cpp" />
<ClCompile Include="USB\qemu-usb\usb-ohci.cpp" />
<ClCompile Include="USB\qemu-usb\vl.cpp" />
<ClCompile Include="USB\shared\shared_usb.cpp" />
<ClCompile Include="USB\shared\inifile_usb.cpp" />
<ClCompile Include="USB\shared\ringbuffer.cpp" />
<ClCompile Include="USB\usb-python2\usb-python2.cpp" />
<ClCompile Include="USB\usb-python2\devices\acio.cpp" />
<ClCompile Include="USB\usb-python2\devices\ddr_extio.cpp" />
<ClCompile Include="USB\usb-python2\devices\icca.cpp" />
<ClCompile Include="USB\usb-python2\devices\thrilldrive_belt.cpp" />
<ClCompile Include="USB\usb-python2\devices\thrilldrive_handle.cpp" />
<ClCompile Include="USB\usb-python2\devices\toysmarch_drumpad.cpp" />
<ClCompile Include="USB\usb-python2\inputs\passthrough\usb-python2-passthrough.cpp" />
<ClCompile Include="USB\usb-python2\inputs\native\usb-python2-native.cpp" />
<ClCompile Include="USB\usb-python2\inputs\Python2QtInputManager.cpp" />
<ClCompile Include="USB\usb-python2\patches.cpp" />
<ClCompile Include="USB\usb-python2\api_init_win32_hid.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="AsyncFileReader.h" />
@ -637,7 +665,6 @@
<ClInclude Include="PrecompiledHeader.h" />
<ClInclude Include="sio_internal.h" />
<ClInclude Include="ps2\pgif.h" />
<ClInclude Include="USB\USB.h" />
<ClInclude Include="Utilities\AsciiFile.h" />
<ClInclude Include="Elfheader.h" />
<ClInclude Include="CDVD\IsoFileFormats.h" />
@ -751,6 +778,39 @@
<ClInclude Include="CDVD\IsoFS\IsoFS.h" />
<ClInclude Include="CDVD\IsoFS\IsoFSCDVD.h" />
<ClInclude Include="CDVD\IsoFS\SectorSource.h" />
<ClInclude Include="USB\USB.h" />
<ClInclude Include="USB\deviceproxy.h" />
<ClInclude Include="USB\helpers.h" />
<ClInclude Include="USB\platcompat.h" />
<ClInclude Include="USB\proxybase.h" />
<ClInclude Include="USB\qemu-usb\desc.h" />
<ClInclude Include="USB\qemu-usb\glib.h" />
<ClInclude Include="USB\qemu-usb\hid.h" />
<ClInclude Include="USB\qemu-usb\input-keymap-win32-to-qcode.h" />
<ClInclude Include="USB\qemu-usb\input-keymap.h" />
<ClInclude Include="USB\qemu-usb\iov.h" />
<ClInclude Include="USB\qemu-usb\queue.h" />
<ClInclude Include="USB\qemu-usb\qusb.h" />
<ClInclude Include="USB\qemu-usb\USBinternal.h" />
<ClInclude Include="USB\qemu-usb\vl.h" />
<ClInclude Include="USB\readerwriterqueue\atomicops.h" />
<ClInclude Include="USB\readerwriterqueue\readerwriterqueue.h" />
<ClInclude Include="USB\shared\inifile_usb.h" />
<ClInclude Include="USB\shared\ringbuffer.h" />
<ClInclude Include="USB\shared\shared_usb.h" />
<ClInclude Include="USB\usb-python2\devices\acio.h" />
<ClInclude Include="USB\usb-python2\devices\icca.h" />
<ClInclude Include="USB\usb-python2\devices\thrilldrive_belt.h" />
<ClInclude Include="USB\usb-python2\devices\ddr_extio.h" />
<ClInclude Include="USB\usb-python2\devices\thrilldrive_handle.h" />
<ClInclude Include="USB\usb-python2\devices\input_device.h" />
<ClInclude Include="USB\usb-python2\devices\toysmarch_drumpad.h" />
<ClInclude Include="USB\usb-python2\inputs\passthrough\usb-python2-passthrough.h" />
<ClInclude Include="USB\usb-python2\inputs\native\usb-python2-native.h" />
<ClInclude Include="USB\usb-python2\inputs\Python2QtInputManager.h" />
<ClInclude Include="USB\usb-python2\patches.h" />
<ClInclude Include="USB\usb-python2\python2proxy.h" />
<ClInclude Include="USB\usb-python2\usb-python2.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(SolutionDir)3rdparty\baseclasses\baseclasses.vcxproj">
@ -796,6 +856,9 @@
<ProjectReference Include="$(SolutionDir)3rdparty\imgui\imgui.vcxproj">
<Project>{88fb34ec-845e-4f21-a552-f1573b9ed167}</Project>
</ProjectReference>
<ProjectReference Include="..\3rdparty\libusb\libusb.vcxproj">
<Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project>
</ProjectReference>
<ProjectReference Include="..\3rdparty\libzip\libzip.vcxproj">
<Project>{20b2e9fe-f020-42a0-b324-956f5b06ea68}</Project>
</ProjectReference>

View File

@ -238,6 +238,15 @@
<Filter Include="Tools\Input Recording">
<UniqueIdentifier>{03ba2aa7-2cd9-48cb-93c6-fc93d5bdc938}</UniqueIdentifier>
</Filter>
<Filter Include="System\Ps2\USB\usb-python2">
<UniqueIdentifier>{95d253c7-cb70-49c4-b5ca-25817162d414}</UniqueIdentifier>
</Filter>
<Filter Include="System\Ps2\USB\usb-python2\devices">
<UniqueIdentifier>{32c6df0a-0683-4310-84e8-d2ced8721a0d}</UniqueIdentifier>
</Filter>
<Filter Include="System\Ps2\USB\usb-python2\inputs">
<UniqueIdentifier>{30f8041c-9171-4e12-bef0-2e2a6b5a4103}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<None Include="Utilities\folderdesc.txt">
@ -1202,9 +1211,6 @@
<ClCompile Include="SPU2\Host\Config.cpp">
<Filter>System\Ps2\SPU2</Filter>
</ClCompile>
<ClCompile Include="USB\USBNull.cpp">
<Filter>System\Ps2\USB</Filter>
</ClCompile>
<ClCompile Include="HostSettings.cpp">
<Filter>Host</Filter>
</ClCompile>
@ -1275,6 +1281,58 @@
<ClCompile Include="Frontend\LogSink.cpp">
<Filter>Host</Filter>
</ClCompile>
<ClCompile Include="USB\USB.cpp" />
<ClCompile Include="USB\deviceproxy.cpp" />
<ClCompile Include="USB\device_init.cpp" />
<ClCompile Include="USB\qemu-usb\bus.cpp" />
<ClCompile Include="USB\qemu-usb\core.cpp" />
<ClCompile Include="USB\qemu-usb\desc.cpp" />
<ClCompile Include="USB\qemu-usb\glib.cpp" />
<ClCompile Include="USB\qemu-usb\hid.cpp" />
<ClCompile Include="USB\qemu-usb\input-keymap-qcode-to-qnum.cpp" />
<ClCompile Include="USB\qemu-usb\input-keymap-win32-to-qcode.cpp" />
<ClCompile Include="USB\qemu-usb\iov.cpp" />
<ClCompile Include="USB\qemu-usb\usb-ohci.cpp" />
<ClCompile Include="USB\qemu-usb\vl.cpp" />
<ClCompile Include="USB\shared\shared_usb.cpp" />
<ClCompile Include="USB\shared\inifile_usb.cpp" />
<ClCompile Include="USB\shared\ringbuffer.cpp" />
<ClCompile Include="USB\usb-python2\devices\ddr_extio.cpp">
<Filter>System\Ps2\USB\usb-python2\devices</Filter>
</ClCompile>
<ClCompile Include="USB\usb-python2\devices\acio.cpp">
<Filter>System\Ps2\USB\usb-python2\devices</Filter>
</ClCompile>
<ClCompile Include="USB\usb-python2\devices\thrilldrive_belt.cpp">
<Filter>System\Ps2\USB\usb-python2\devices</Filter>
</ClCompile>
<ClCompile Include="USB\usb-python2\devices\thrilldrive_handle.cpp">
<Filter>System\Ps2\USB\usb-python2\devices</Filter>
</ClCompile>
<ClCompile Include="USB\usb-python2\devices\toysmarch_drumpad.cpp">
<Filter>System\Ps2\USB\usb-python2\devices</Filter>
</ClCompile>
<ClCompile Include="USB\usb-python2\inputs\native\usb-python2-native.cpp">
<Filter>System\Ps2\USB\usb-python2\inputs</Filter>
</ClCompile>
<ClCompile Include="USB\usb-python2\inputs\passthrough\usb-python2-passthrough.cpp">
<Filter>System\Ps2\USB\usb-python2\inputs</Filter>
</ClCompile>
<ClCompile Include="USB\usb-python2\inputs\Python2QtInputManager.cpp">
<Filter>System\Ps2\USB\usb-python2\inputs</Filter>
</ClCompile>
<ClCompile Include="USB\usb-python2\devices\icca.cpp">
<Filter>System\Ps2\USB\usb-python2\devices</Filter>
</ClCompile>
<ClCompile Include="USB\usb-python2\patches.cpp">
<Filter>System\Ps2\USB\usb-python2</Filter>
</ClCompile>
<ClCompile Include="USB\usb-python2\usb-python2.cpp">
<Filter>System\Ps2\USB\usb-python2</Filter>
</ClCompile>
<ClCompile Include="USB\usb-python2\api_init_win32_hid.cpp">
<Filter>System\Ps2\USB\usb-python2</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Patch.h">
@ -2119,6 +2177,66 @@
<ClInclude Include="Frontend\LogSink.h">
<Filter>Host</Filter>
</ClInclude>
<ClInclude Include="USB\deviceproxy.h" />
<ClInclude Include="USB\helpers.h" />
<ClInclude Include="USB\platcompat.h" />
<ClInclude Include="USB\qemu-usb\desc.h" />
<ClInclude Include="USB\qemu-usb\glib.h" />
<ClInclude Include="USB\qemu-usb\hid.h" />
<ClInclude Include="USB\qemu-usb\input-keymap-win32-to-qcode.h" />
<ClInclude Include="USB\qemu-usb\input-keymap.h" />
<ClInclude Include="USB\qemu-usb\iov.h" />
<ClInclude Include="USB\qemu-usb\queue.h" />
<ClInclude Include="USB\qemu-usb\qusb.h" />
<ClInclude Include="USB\qemu-usb\USBinternal.h" />
<ClInclude Include="USB\qemu-usb\vl.h" />
<ClInclude Include="USB\readerwriterqueue\atomicops.h" />
<ClInclude Include="USB\readerwriterqueue\readerwriterqueue.h" />
<ClInclude Include="USB\shared\inifile_usb.h" />
<ClInclude Include="USB\shared\ringbuffer.h" />
<ClInclude Include="USB\shared\shared_usb.h" />
<ClInclude Include="USB\usb-python2\devices\ddr_extio.h">
<Filter>System\Ps2\USB\usb-python2\devices</Filter>
</ClInclude>
<ClInclude Include="USB\usb-python2\devices\acio.h">
<Filter>System\Ps2\USB\usb-python2\devices</Filter>
</ClInclude>
<ClInclude Include="USB\usb-python2\devices\thrilldrive_belt.h">
<Filter>System\Ps2\USB\usb-python2\devices</Filter>
</ClInclude>
<ClInclude Include="USB\usb-python2\devices\thrilldrive_handle.h">
<Filter>System\Ps2\USB\usb-python2\devices</Filter>
</ClInclude>
<ClInclude Include="USB\usb-python2\devices\toysmarch_drumpad.h">
<Filter>System\Ps2\USB\usb-python2\devices</Filter>
</ClInclude>
<ClInclude Include="USB\usb-python2\inputs\passthrough\usb-python2-passthrough.h">
<Filter>System\Ps2\USB\usb-python2\inputs</Filter>
</ClInclude>
<ClInclude Include="USB\usb-python2\inputs\native\usb-python2-native.h">
<Filter>System\Ps2\USB\usb-python2\inputs</Filter>
</ClInclude>
<ClInclude Include="USB\usb-python2\inputs\Python2QtInputManager.h">
<Filter>System\Ps2\USB\usb-python2\inputs</Filter>
</ClInclude>
<ClInclude Include="USB\usb-python2\devices\icca.h">
<Filter>System\Ps2\USB\usb-python2\devices</Filter>
</ClInclude>
<ClInclude Include="USB\usb-python2\patches.h">
<Filter>System\Ps2\USB\usb-python2</Filter>
</ClInclude>
<ClInclude Include="USB\proxybase.h">
<Filter>System\Ps2\USB\usb-python2</Filter>
</ClInclude>
<ClInclude Include="USB\usb-python2\python2proxy.h">
<Filter>System\Ps2\USB\usb-python2</Filter>
</ClInclude>
<ClInclude Include="USB\usb-python2\usb-python2.h">
<Filter>System\Ps2\USB\usb-python2</Filter>
</ClInclude>
<ClInclude Include="USB\usb-python2\devices\input_device.h">
<Filter>System\Ps2\USB\usb-python2\devices</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<CustomBuildStep Include="rdebug\deci2.h">
@ -2143,4 +2261,4 @@
<Filter>System\Ps2\Debug\rdebug</Filter>
</CustomBuildStep>
</ItemGroup>
</Project>
</Project>