Cleaned up the parallel port emulation, added IRQ support, and made enabling/disabling per port; Added the Award 430NX and the Intel Classic/PCI (Alfredo, 420TX); Finished the 586MC1; Added 8087 emulation; Moved Cyrix 6x86'es to the Dev branch; Sanitized/cleaned up memregs.c/h and intel.c/h; Split the chipsets from machines and sanitized Port 92 emulation; Added support for the 15bpp mode to the Compaq ATI 28800; Moved the MR 386DX and 486 machines to the Dev branch; Ported the new dynamic recompiler from PCem, but it remains in Dev branch until after v2.00; Ported the new timer code from PCem; Cleaned up the CPU table of unused stuff and better optimized its structure; Ported the Open-XT and Open-AT from VARCem, the Open-AT is in the Dev branch; Ported the XT MFM controller rewrite and adding of more controllers (incl. two RLL ones), from VARCem; Added the AHA-1540A and the BusTek BT-542B; Moved the Sumo SCSI-AT to the Dev branch; Minor IDE, FDC, and floppy drive code clean-ups; Made NCR 5380/53C400-based cards' BIOS address configurable; Got rid of the legacy romset variable; Unified (video) buffer and buffer32 into one and make the unified buffer 32-bit; Added the Amstead PPC512 per PCem patch by John Elliott; Switched memory mapping granularity from 16k to 4k (less than 1k not possible due to internal pages); Rewrote the CL-GD 54xx blitter, fixes Win-OS/2 on the 54x6 among other thing; Added the Image Manager 1024 and Professional Graphics Controller per PCem patch by John Elliott and work done on VARCem; Added Headland HT-216, GC-205 and Video 7 VGA 1024i emulation based on PCem commit; Implemented the fuction keys for the Toshiba T1000/T1200/T3100 enhancement; Amstrad MegaPC does now works correctly with non-internal graphics card; The SLiRP code no longer casts a packed struct type to a non-packed struct type; The Xi8088 and PB410a no longer hang on 86Box when PS/2 mouse is not present; The S3 Virge on BeOS is no longer broken (was broken by build #1591); OS/2 2.0 build 6.167 now sees key presses again; Xi8088 now work on CGA again; 86F images converted from either the old or new variants of the HxC MFM format now work correctly; Hardware interrupts with a vector of 0xFF are now handled correctly; OPTi 495SX boards no longer incorrectly have 64 MB maximum RAM when 32 MB is correct; Fixed VNC keyboard input bugs; Fixed AT RTC periodic interrupt - Chicago 58s / 73f / 73g / 81 MIDI play no longer hangs with the build's own VTD driver; Fixed mouse polling with internal mice - Amstrad and Olivetti mice now work correctly; Triones ATAPI DMA driver now correctly reads a file at the end of a CD image with a sectors number not divisible by 4; Compaq Portable now works with all graphics cards; Fixed various MDSI Genius bugs; Added segment limit checks and improved page fault checks for several CPU instructions - Memphis 15xx WINSETUP and Chicago 58s WINDISK.CPL no longer issue a GPF, and some S3 drivers that used to have glitches, now work correctly; Further improved the 808x emulation, also fixes the noticably choppy sound when using 808x CPU's, also fixes #355; OS/2 installer no logner locks up on splash screen on PS/2 Model 70 and 80, fixes #400. Fixed several Amstead bugs, GEM no longer crashes on the Amstrad 1640, fixes #391. Ported John Elliott's Amstrad fixes and improvement from PCem, and fixed the default language so it's correctly Engliish, fixes #278, fixes #389. Fixed a minor IDE timing bug, fixes #388. Fixed Toshiba T1000 RAM issues, fixes #379. Fixed EGA/(S)VGA overscan border handling, fixes #378; Got rid of the now long useless IDE channel 2 auto-removal, fixes #370; Fixed the BIOS files used by the AMSTRAD PC1512, fixes #366; Ported the Unicode CD image file name fix from VARCem, fixes #365; Fixed high density floppy disks on the Xi8088, fixes #359; Fixed some bugs in the Hercules emulation, fixes #346, fixes #358; Fixed the SCSI hard disk mode sense pages, fixes #356; Removed the AMI Unknown 386SX because of impossibility to identify the chipset, closes #349; Fixed bugs in the serial mouse emulation, fixes #344; Compiled 86Box binaries now include all the required .DLL's, fixes #341; Made some combo boxes in the Settings dialog slightly wider, fixes #276.
263 lines
11 KiB
C++
263 lines
11 KiB
C++
/*
|
|
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
|
* running old operating systems and software designed for IBM
|
|
* PC systems and compatibles from 1981 through fairly recent
|
|
* system designs based on the PCI bus.
|
|
*
|
|
* This file is part of the 86Box distribution.
|
|
*
|
|
* Xinput joystick interface.
|
|
*
|
|
* Version: @(#)win_joystick_xinput.cpp 1.0.0 2019/3/19
|
|
*
|
|
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
|
* Miran Grca, <mgrca8@gmail.com>
|
|
* GH Cao, <driver1998.ms@outlook.com>
|
|
*
|
|
* Copyright 2008-2018 Sarah Walker.
|
|
* Copyright 2016-2018 Miran Grca.
|
|
* Copyright 2019 GH Cao.
|
|
*/
|
|
#include <Xinput.h>
|
|
#include <math.h>
|
|
#include <stdarg.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#define HAVE_STDARG_H
|
|
#include "../86box.h"
|
|
#include "../device.h"
|
|
#include "../plat.h"
|
|
#include "../game/gameport.h"
|
|
#include "win.h"
|
|
|
|
#define XINPUT_MAX_JOYSTICKS 4
|
|
#define XINPUT_NAME "Xinput compatiable controller"
|
|
#define XINPUT_NAME_LX "Left Stick X"
|
|
#define XINPUT_NAME_LY "Left Stick Y"
|
|
#define XINPUT_NAME_RX "Right Stick X"
|
|
#define XINPUT_NAME_RY "Right Stick Y"
|
|
#define XINPUT_NAME_DPAD_X "D-pad X"
|
|
#define XINPUT_NAME_DPAD_Y "D-pad Y"
|
|
#define XINPUT_NAME_LB "LB"
|
|
#define XINPUT_NAME_RB "RB"
|
|
#define XINPUT_NAME_LT "LT"
|
|
#define XINPUT_NAME_RT "RT"
|
|
#define XINPUT_NAME_A "A"
|
|
#define XINPUT_NAME_B "B"
|
|
#define XINPUT_NAME_X "X"
|
|
#define XINPUT_NAME_Y "Y"
|
|
#define XINPUT_NAME_BACK "Back/View"
|
|
#define XINPUT_NAME_START "Start/Menu"
|
|
#define XINPUT_NAME_LS "Left Stick"
|
|
#define XINPUT_NAME_RS "Right Stick"
|
|
|
|
#ifdef ENABLE_JOYSTICK_LOG
|
|
int joystick_do_log = ENABLE_JOYSTICK_LOG;
|
|
|
|
|
|
static void
|
|
joystick_log(const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
if (joystick_do_log) {
|
|
va_start(ap, fmt);
|
|
pclog_ex(fmt, ap);
|
|
va_end(ap);
|
|
}
|
|
}
|
|
#else
|
|
#define joystick_log(fmt, ...)
|
|
#endif
|
|
|
|
plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS];
|
|
joystick_t joystick_state[MAX_JOYSTICKS];
|
|
int joysticks_present = 0;
|
|
|
|
XINPUT_STATE controllers[XINPUT_MAX_JOYSTICKS];
|
|
|
|
void joystick_init()
|
|
{
|
|
int c;
|
|
|
|
atexit(joystick_close);
|
|
|
|
joysticks_present = 0;
|
|
|
|
memset(controllers, 0, sizeof(XINPUT_STATE) * XINPUT_MAX_JOYSTICKS);
|
|
|
|
for (c=0; c<XINPUT_MAX_JOYSTICKS; c++) {
|
|
int value = XInputGetState(c, &controllers[c]);
|
|
if (value != ERROR_SUCCESS) continue;
|
|
memcpy(plat_joystick_state[c].name, XINPUT_NAME, sizeof(XINPUT_NAME));
|
|
|
|
plat_joystick_state[c].nr_axes = 8;
|
|
|
|
/* analog stick */
|
|
memcpy(plat_joystick_state[c].axis[0].name, XINPUT_NAME_LX, sizeof(XINPUT_NAME_LX));
|
|
plat_joystick_state[c].axis[0].id = 0; /* X axis */
|
|
memcpy(plat_joystick_state[c].axis[1].name, XINPUT_NAME_LY, sizeof(XINPUT_NAME_LY));
|
|
plat_joystick_state[c].axis[1].id = 1; /* Y axis */
|
|
memcpy(plat_joystick_state[c].axis[2].name, XINPUT_NAME_RX, sizeof(XINPUT_NAME_RX));
|
|
plat_joystick_state[c].axis[2].id = 3; /* RX axis */
|
|
memcpy(plat_joystick_state[c].axis[3].name, XINPUT_NAME_RY, sizeof(XINPUT_NAME_RY));
|
|
plat_joystick_state[c].axis[3].id = 4; /* RY axis */
|
|
|
|
/* d-pad, assigned to Z and RZ */
|
|
memcpy(plat_joystick_state[c].axis[4].name, XINPUT_NAME_DPAD_X, sizeof(XINPUT_NAME_DPAD_X));
|
|
plat_joystick_state[c].axis[4].id = 2;
|
|
memcpy(plat_joystick_state[c].axis[5].name, XINPUT_NAME_DPAD_Y, sizeof(XINPUT_NAME_DPAD_Y));
|
|
plat_joystick_state[c].axis[5].id = 5;
|
|
|
|
/* Analog trigger */
|
|
memcpy(plat_joystick_state[c].axis[6].name, XINPUT_NAME_LT, sizeof(XINPUT_NAME_LT));
|
|
plat_joystick_state[c].axis[6].id = 6;
|
|
memcpy(plat_joystick_state[c].axis[7].name, XINPUT_NAME_RT, sizeof(XINPUT_NAME_RT));
|
|
plat_joystick_state[c].axis[7].id = 7;
|
|
|
|
plat_joystick_state[c].nr_buttons = 12;
|
|
memcpy(plat_joystick_state[c].button[0].name, XINPUT_NAME_A, sizeof(XINPUT_NAME_A));
|
|
memcpy(plat_joystick_state[c].button[1].name, XINPUT_NAME_B, sizeof(XINPUT_NAME_B));
|
|
memcpy(plat_joystick_state[c].button[2].name, XINPUT_NAME_X, sizeof(XINPUT_NAME_X));
|
|
memcpy(plat_joystick_state[c].button[3].name, XINPUT_NAME_Y, sizeof(XINPUT_NAME_Y));
|
|
memcpy(plat_joystick_state[c].button[4].name, XINPUT_NAME_LB, sizeof(XINPUT_NAME_LB));
|
|
memcpy(plat_joystick_state[c].button[5].name, XINPUT_NAME_RB, sizeof(XINPUT_NAME_RB));
|
|
memcpy(plat_joystick_state[c].button[6].name, XINPUT_NAME_LT, sizeof(XINPUT_NAME_LT));
|
|
memcpy(plat_joystick_state[c].button[7].name, XINPUT_NAME_RT, sizeof(XINPUT_NAME_RT));
|
|
memcpy(plat_joystick_state[c].button[8].name, XINPUT_NAME_BACK, sizeof(XINPUT_NAME_BACK));
|
|
memcpy(plat_joystick_state[c].button[9].name, XINPUT_NAME_START, sizeof(XINPUT_NAME_START));
|
|
memcpy(plat_joystick_state[c].button[10].name, XINPUT_NAME_LS, sizeof(XINPUT_NAME_LS));
|
|
memcpy(plat_joystick_state[c].button[11].name, XINPUT_NAME_RS, sizeof(XINPUT_NAME_RS));
|
|
|
|
plat_joystick_state[c].nr_povs = 0;
|
|
|
|
joysticks_present++;
|
|
}
|
|
joystick_log("joystick_init: joysticks_present=%i\n", joysticks_present);
|
|
}
|
|
|
|
void joystick_close()
|
|
{
|
|
}
|
|
|
|
void joystick_poll(void)
|
|
{
|
|
for (int c=0; c<joysticks_present; c++) {
|
|
int value = XInputGetState(c, &controllers[c]);
|
|
if (value != ERROR_SUCCESS) continue;
|
|
|
|
plat_joystick_state[c].a[0] = controllers[c].Gamepad.sThumbLX;
|
|
plat_joystick_state[c].a[1] = - controllers[c].Gamepad.sThumbLY;
|
|
plat_joystick_state[c].a[3] = controllers[c].Gamepad.sThumbRX;
|
|
plat_joystick_state[c].a[4] = - controllers[c].Gamepad.sThumbRY;
|
|
plat_joystick_state[c].a[6] = (double)controllers[c].Gamepad.bLeftTrigger / 255 * 32767;
|
|
plat_joystick_state[c].a[7] = (double)controllers[c].Gamepad.bRightTrigger / 255 * 32767;
|
|
|
|
plat_joystick_state[c].b[0] = (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_A) ? 128 : 0;
|
|
plat_joystick_state[c].b[1] = (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_B) ? 128 : 0;
|
|
plat_joystick_state[c].b[2] = (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_X) ? 128 : 0;
|
|
plat_joystick_state[c].b[3] = (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_Y) ? 128 : 0;
|
|
plat_joystick_state[c].b[4] = (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) ? 128 : 0;
|
|
plat_joystick_state[c].b[5] = (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) ? 128 : 0;
|
|
plat_joystick_state[c].b[6] = (controllers[c].Gamepad.bLeftTrigger > 127) ? 128 : 0;
|
|
plat_joystick_state[c].b[7] = (controllers[c].Gamepad.bRightTrigger > 127) ? 128 : 0;
|
|
plat_joystick_state[c].b[8] = (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_BACK) ? 128 : 0;
|
|
plat_joystick_state[c].b[9] = (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_START) ? 128 : 0;
|
|
plat_joystick_state[c].b[10] = (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB) ? 128 : 0;
|
|
plat_joystick_state[c].b[11] = (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB) ? 128 : 0;
|
|
|
|
int dpad_x = 0, dpad_y = 0;
|
|
if (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP)
|
|
dpad_y-=32767;
|
|
if (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN)
|
|
dpad_y+=32767;
|
|
if (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT)
|
|
dpad_x-=32767;
|
|
if (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT)
|
|
dpad_x+=32767;
|
|
|
|
plat_joystick_state[c].a[2] = dpad_x;
|
|
plat_joystick_state[c].a[5] = dpad_y;
|
|
|
|
for (int a=0; a<8; a++) {
|
|
if (plat_joystick_state[c].a[a] == -32768)
|
|
plat_joystick_state[c].a[a] = -32767;
|
|
if (plat_joystick_state[c].a[a] == 32768)
|
|
plat_joystick_state[c].a[a] = 32767;
|
|
}
|
|
}
|
|
}
|
|
|
|
static int joystick_get_axis(int joystick_nr, int mapping)
|
|
{
|
|
if (mapping & POV_X)
|
|
{
|
|
int pov = plat_joystick_state[joystick_nr].p[mapping & 3];
|
|
|
|
if (LOWORD(pov) == 0xFFFF)
|
|
return 0;
|
|
else
|
|
return sin((2*M_PI * (double)pov) / 36000.0) * 32767;
|
|
}
|
|
else if (mapping & POV_Y)
|
|
{
|
|
int pov = plat_joystick_state[joystick_nr].p[mapping & 3];
|
|
|
|
if (LOWORD(pov) == 0xFFFF)
|
|
return 0;
|
|
else
|
|
return -cos((2*M_PI * (double)pov) / 36000.0) * 32767;
|
|
}
|
|
else
|
|
return plat_joystick_state[joystick_nr].a[plat_joystick_state[joystick_nr].axis[mapping].id];
|
|
}
|
|
|
|
void joystick_process(void)
|
|
{
|
|
int c, d;
|
|
|
|
if (joystick_type == 7) return;
|
|
|
|
joystick_poll();
|
|
|
|
for (c = 0; c < joystick_get_max_joysticks(joystick_type); c++)
|
|
{
|
|
if (joystick_state[c].plat_joystick_nr)
|
|
{
|
|
int joystick_nr = joystick_state[c].plat_joystick_nr - 1;
|
|
|
|
for (d = 0; d < joystick_get_axis_count(joystick_type); d++)
|
|
joystick_state[c].axis[d] = joystick_get_axis(joystick_nr, joystick_state[c].axis_mapping[d]);
|
|
for (d = 0; d < joystick_get_button_count(joystick_type); d++)
|
|
joystick_state[c].button[d] = plat_joystick_state[joystick_nr].b[joystick_state[c].button_mapping[d]];
|
|
|
|
for (d = 0; d < joystick_get_pov_count(joystick_type); d++)
|
|
{
|
|
int x, y;
|
|
double angle, magnitude;
|
|
|
|
x = joystick_get_axis(joystick_nr, joystick_state[c].pov_mapping[d][0]);
|
|
y = joystick_get_axis(joystick_nr, joystick_state[c].pov_mapping[d][1]);
|
|
|
|
angle = (atan2((double)y, (double)x) * 360.0) / (2*M_PI);
|
|
magnitude = sqrt((double)x*(double)x + (double)y*(double)y);
|
|
|
|
if (magnitude < 16384)
|
|
joystick_state[c].pov[d] = -1;
|
|
else
|
|
joystick_state[c].pov[d] = ((int)angle + 90 + 360) % 360;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (d = 0; d < joystick_get_axis_count(joystick_type); d++)
|
|
joystick_state[c].axis[d] = 0;
|
|
for (d = 0; d < joystick_get_button_count(joystick_type); d++)
|
|
joystick_state[c].button[d] = 0;
|
|
for (d = 0; d < joystick_get_pov_count(joystick_type); d++)
|
|
joystick_state[c].pov[d] = -1;
|
|
}
|
|
}
|
|
}
|
|
|