This commit is contained in:
Fred Hallock 2025-05-21 03:07:48 +00:00 committed by GitHub
commit 76de1baf2c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 415 additions and 13 deletions

BIN
data/arcade_stick_mask.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

View File

@ -0,0 +1,83 @@
<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
<g class="layer">
<title>Layer 1</title>
<ellipse cx="61" cy="963" fill="#000000" id="svg_4" rx="58" ry="58" stroke="#ff0000" stroke-width="3"/>
<path d="m6,199c0,-91 4.5,-146 8.5,-167c4,-21 8.5,-28 28.5,-28c20,0 91,-1 117,-0.5c26,0.5 34.5,19.5 41,27.5c6.5,8 5.5,7 19.5,7c14,0 124,-0.5 131,-0.5c7,0 9.5,2.5 22.5,9c13,6.5 40.5,16 91,15.5c50.5,-0.5 81.5,-13.5 93.5,-18.5c12,-5 15.5,-6 22,-6c6.5,0 123.5,0 137.5,0c14,0 10,-1.5 17,-8.5c7,-7 13,-25 42,-26c29,-1 83,0 111,0c28,0 31,14.5 33.5,34.5c2.5,20 8.5,107.5 8.5,163.5c0,56 1,216 0,260c-1,44 -8,150 -10,160c-2,10 -2,30 -25,30c-23,0 -106,0.67 -121.67,0.67c-15.67,0 -16.83,3.33 -32.5,-15.33c-15.67,-18.67 -21,-14.67 -17.17,-14.67c3.83,0 -508.83,0.83 -513.33,0.83c-4.5,0 -9.83,6 -19.83,18.5c-10,12.5 -18.5,13 -34.5,13c-16,0 -102,0 -115,0c-13,0 -25,-5 -27,-30c-2,-25 -11,-130 -10,-168c1,-38 2,-257 2,-257z" fill="#000000" id="svg_2" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="3"/>
<path d="m27.33,38.67c2.17,-15.5 1.33,-20.67 20,-20.5c18.67,0.17 91.33,-0.83 107.33,-0.17c16,0.67 13.33,0.67 26.67,14c13.33,13.33 82.67,93.33 82.67,92.67c0,-0.67 408,-0.67 408,0c0,0.67 59.33,-72 75.33,-90c16,-18 20,-15.33 41.33,-15.33c21.33,0 88,-1.33 99.33,0.67c11.33,2 16,-2.67 20,18.67c4,21.33 12,133.33 11.33,161.33c-0.67,28 -1.33,234.67 -0.67,260.67c0.67,26 -6.67,140.67 -10.67,158.67c-4,18 -5.33,18.67 -19.33,18.67c-14,0 -97.33,-0.67 -111.33,-0.67c-14,0 -14,-0.67 -26,-13.33c-12,-12.67 -64,-70 -64,-70c0,0 -440,-0.67 -440,-0.67c0,0 -56,62.67 -66,74.67c-10,12 -10,13.33 -24,13.33c-14,0 -97,-0.17 -109,-0.17c-12,0 -21.33,-1.17 -23.33,-20.5c-2,-19.33 -9,-158 -9.67,-158c-0.67,0 2,-267.33 1.33,-267.33c-0.67,0 8.5,-141.17 10.67,-156.67l0.01,-0.01z" fill="#000000" fill-opacity="null" id="svg_5" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3" transform="matrix(1, 0, 0, 1, 0, 0)"/>
<line fill="none" fill-opacity="null" id="svg_55" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3" transform="matrix(1, 0, 0, 1, 0, 0)" x1="4.74" x2="928.87" y1="454.38" y2="454.38"/>
<line fill="none" fill-opacity="null" id="svg_53" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3" transform="matrix(1, 0, 0, 1, 0, 0)" x1="4.09" x2="929.51" y1="421.16" y2="421.16"/>
<line fill="none" fill-opacity="null" id="svg_47" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3" transform="matrix(1, 0, 0, 1, 0, 0)" x1="4.42" x2="928.54" y1="321.8" y2="321.8"/>
<line fill="none" fill-opacity="null" id="svg_46" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3" transform="matrix(1, 0, 0, 1, 0, 0)" x1="5.71" x2="929.19" y1="305.35" y2="305.35"/>
<line fill="none" fill-opacity="null" id="svg_43" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3" transform="matrix(1, 0, 0, 1, 0, 0)" x1="4.42" x2="928.54" y1="255.67" y2="255.67"/>
<line fill="none" fill-opacity="null" id="svg_42" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3" x1="4.45" x2="930.19" y1="238.58" y2="238.58"/>
<line fill="none" fill-opacity="null" id="svg_41" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3" transform="matrix(1, 0, 0, 1, 0, 0)" x1="5.38" x2="928.54" y1="222.13" y2="222.13"/>
<line fill="none" fill-opacity="null" id="svg_40" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3" transform="matrix(1, 0, 0, 1, 0, 0)" x1="6.84" x2="928.06" y1="204.39" y2="204.39"/>
<line fill="none" fill-opacity="null" id="svg_44" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3" transform="matrix(1, 0, 0, 1, 0, 0)" x1="5.71" x2="928.87" y1="272.13" y2="272.13"/>
<line fill="none" fill-opacity="null" id="svg_45" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3" transform="matrix(1, 0, 0, 1, 0, 0)" x1="6.03" x2="930.16" y1="288.26" y2="288.26"/>
<line fill="none" fill-opacity="null" id="svg_48" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3" x1="6.06" x2="929.22" y1="339.22" y2="339.22"/>
<line fill="none" fill-opacity="null" id="svg_49" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3" transform="matrix(1, 0, 0, 1, 0, 0) matrix(1, 0, 0, 1, 0, 0)" x1="5.71" x2="928.54" y1="354.71" y2="354.71"/>
<line fill="none" fill-opacity="null" id="svg_50" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3" transform="matrix(1, 0, 0, 1, 0, 0)" x1="5.06" x2="929.19" y1="370.51" y2="370.51"/>
<line fill="none" fill-opacity="null" id="svg_51" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3" transform="matrix(1, 0, 0, 1, 0, 0)" x1="4.42" x2="929.19" y1="387.93" y2="387.93"/>
<line fill="none" fill-opacity="null" id="svg_52" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3" transform="matrix(1, 0, 0, 1, 0, 0)" x1="5.38" x2="930.16" y1="404.06" y2="404.06"/>
<line fill="none" fill-opacity="null" id="svg_54" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3" transform="matrix(1, 0, 0, 1, 0, 0)" x1="4.74" x2="929.19" y1="437.93" y2="437.93"/>
<line fill="none" fill-opacity="null" id="svg_56" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3" x1="3.77" x2="928.23" y1="454.07" y2="454.07"/>
<line fill="none" fill-opacity="null" id="svg_32" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3" transform="matrix(1, 0, 0, 1, 0, 0)" x1="203" x2="401.5" y1="55.5" y2="55.5"/>
<line fill="none" fill-opacity="null" id="svg_33" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3" x1="522.5" x2="730.5" y1="55.5" y2="55.5"/>
<line fill="none" fill-opacity="null" id="svg_34" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3" transform="matrix(1, 0, 0, 1, 0, 0)" x1="208.33" x2="725.33" y1="603.5" y2="603.5"/>
<path d="m106.5,130c20,0 688.5,1.5 714.5,1.5c26,0 34.5,2 37,30.5c2.5,28.5 5.5,130 6,167c0.5,37 -3,174 -4,192c-1,18 -5,23 -19,23.5c-14,0.5 -729,0.5 -741,0c-12,-0.5 -25,-1 -27.5,-21.5c-2.5,-20.5 -4.5,-155 -4.5,-193c0,-38 4,-158 6,-175.5c2,-17.5 12.5,-24.5 32.5,-24.5z" fill="#000000" fill-opacity="null" id="svg_9" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3"/>
<rect fill="#000000" height="31" id="svg_35" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3" width="79.5" x="428" y="563"/>
<path d="m209.5,623c-2.5,-12 0.5,-20 0.5,-20c0,0 -2,-2 -3.17,-3.5" fill="#000000" fill-opacity="null" id="svg_36" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3"/>
<path d="m723.26,621.25c3.5,-11.5 -0.01,-19 0.49,-18l3.41,-4.58" fill="#000000" fill-opacity="null" id="svg_37" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3"/>
<path d="m203.27,56c-0.45,-11.36 4.55,-18.18 4.55,-18.64c0,-0.45 -4.55,18.64 -4.55,18.64" fill="#000000" fill-opacity="null" id="svg_7" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3"/>
<path d="m728.98,54.37c-0.45,-11.36 -3.09,-15.73 -2.69,-16.34c0.4,-0.6 2.69,16.34 2.69,16.34" fill="#000000" fill-opacity="null" id="svg_1" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3"/>
<rect fill="#000000" height="86.5" id="svg_24" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3" width="226.5" x="119" y="140.5"/>
<rect fill="#000000" fill-opacity="null" height="68.5" id="svg_25" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3" width="207" x="128.5" y="149.5"/>
<ellipse cx="94" cy="153.5" fill="#000000" fill-opacity="null" id="svg_26" rx="6" ry="6" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3"/>
<ellipse cx="359.5" cy="154" fill="#000000" fill-opacity="null" id="svg_27" rx="6" ry="6" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3"/>
<ellipse cx="839" cy="154" fill="#000000" fill-opacity="null" id="svg_28" rx="6" ry="6" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3"/>
<ellipse cx="94" cy="523.5" fill="#000000" fill-opacity="null" id="svg_29" rx="6" ry="6" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3"/>
<ellipse cx="467" cy="523.5" fill="#000000" fill-opacity="null" id="svg_30" rx="6" ry="6" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3"/>
<ellipse cx="839" cy="523.5" fill="#000000" fill-opacity="null" id="svg_31" rx="6" ry="6" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3" transform="matrix(1, 0, 0, 1, 0, 0)"/>
<path d="m822.82,46.54c37.44,0 37.49,56.95 0.21,56.67c-37.28,-0.28 -15.23,-0.41 -50.26,-0.18c-35.03,0.23 -35.49,-56.49 0.23,-56.49c35.72,0 12.38,0 49.82,0z" fill="#000000" fill-opacity="null" id="svg_8" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3"/>
<text fill="#ff0000" font-family="Helvetica" font-size="13" font-weight="bold" id="svg_62" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="0" text-anchor="middle" x="798" xml:space="preserve" y="121">BACK START</text>
<!-- Button A -->
<ellipse cx="467.75" cy="368.5" fill="#000000" fill-opacity="null" id="svg_10" rx="47.75" ry="49.5" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3"/>
<ellipse cx="468.5" cy="368.5" fill="#0000ff" id="svg_11" rx="36.5" ry="37" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3"/>
<text fill="#ff0000" font-family="Helvetica" font-size="43" font-weight="bold" id="svg_6" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="0" text-anchor="middle" x="468" xml:space="preserve" y="382">A</text>
<!-- Button B -->
<ellipse cx="484" cy="257" fill="#000000" fill-opacity="null" id="svg_13" rx="47.75" ry="49.5" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3"/>
<ellipse cx="484.75" cy="257" fill="#0000ff" id="svg_12" rx="36.5" ry="37" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3"/>
<text fill="#ff0000" font-family="Helvetica" font-size="43" font-weight="bold" id="svg_38" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="0" text-anchor="middle" transform="matrix(1, 0, 0, 1, 0, 0)" x="484.99" xml:space="preserve" y="272">B</text>
<!-- Button X -->
<ellipse cx="578.5" cy="208.5" fill="#000000" fill-opacity="null" id="svg_15" rx="47.75" ry="49.5" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3"/>
<ellipse cx="579.25" cy="208.5" fill="#0000ff" id="svg_14" rx="36.5" ry="37" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3"/>
<text fill="#ff0000" font-family="Helvetica" font-size="43" font-weight="bold" id="svg_39" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="0" text-anchor="middle" x="578.99" xml:space="preserve" y="224">X</text>
<!-- Button Y -->
<ellipse cx="681.5" cy="220.5" fill="#000000" fill-opacity="null" id="svg_17" rx="47.75" ry="49.5" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3" transform="matrix(1, 0, 0, 1, 0, 0)"/>
<ellipse cx="682.25" cy="220.5" fill="#0000ff" id="svg_16" rx="36.5" ry="37" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3" transform="matrix(1, 0, 0, 1, 0, 0)"/>
<text fill="#ff0000" font-family="Helvetica" font-size="43" font-weight="bold" id="svg_57" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="0" text-anchor="middle" x="681.99" xml:space="preserve" y="237">Y</text>
<!-- LRBW -->
<ellipse cx="160" cy="185" fill="#0000ff" id="svg_18" rx="19" ry="21" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3"/>
<text fill="#ff0000" font-family="Helvetica" font-size="33" font-weight="bold" id="svg_58" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="0" text-anchor="middle" x="159.99" xml:space="preserve" y="197">L</text>
<ellipse cx="206" cy="185" fill="#0000ff" id="svg_19" rx="19" ry="21" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3"/>
<text fill="#ff0000" font-family="Helvetica" font-size="33" font-weight="bold" id="svg_59" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="0" text-anchor="middle" transform="matrix(1, 0, 0, 1, 0, 0)" x="206" xml:space="preserve" y="197">R</text>
<ellipse cx="255" cy="185" fill="#0000ff" id="svg_20" rx="19" ry="21" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3" transform="matrix(1, 0, 0, 1, 0, 0)"/>
<text fill="#ff0000" font-family="Helvetica" font-size="33" font-weight="bold" id="svg_60" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="0" text-anchor="middle" transform="matrix(1, 0, 0, 1, 0, 0)" x="255" xml:space="preserve" y="197">W</text>
<ellipse cx="302" cy="185" fill="#0000ff" id="svg_21" rx="19" ry="21" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3" transform="matrix(1, 0, 0, 1, 0, 0)"/>
<text fill="#ff0000" font-family="Helvetica" font-size="33" font-weight="bold" id="svg_61" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="0" text-anchor="middle" transform="matrix(1, 0, 0, 1, 0, 0)" x="301" xml:space="preserve" y="197">K</text>
<!-- Back -->
<ellipse cx="774" cy="75" fill="#0000ff" id="svg_22" rx="19" ry="21" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3" transform="matrix(1, 0, 0, 1, 0, 0)"/>
<!-- Start -->
<ellipse cx="823" cy="75" fill="#0000ff" id="svg_23" rx="19" ry="21" stroke="#ff0000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="3" transform="matrix(1, 0, 0, 1, 0, 0)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -1,6 +1,7 @@
pfiles = [
'controller_mask.png',
'controller_mask_s.png',
'arcade_stick_mask.png',
'xmu_mask.png',
'logo_sdf.png',
'xemu_64x64.png',

View File

@ -17,6 +17,7 @@ specific_ss.add(files(
'xid.c',
'xblc.c',
'xid-gamepad.c',
'xid-arcade-stick.c',
))
subdir('nv2a')
subdir('mcpx')

192
hw/xbox/xid-arcade-stick.c Normal file
View File

@ -0,0 +1,192 @@
/*
* QEMU USB XID Devices
*
* Copyright (c) 2013 espes
* Copyright (c) 2017 Jannik Vogel
* Copyright (c) 2018-2021 Matt Borgerson
*
* 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 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, see <http://www.gnu.org/licenses/>.
*/
#include "xid.h"
// #define DEBUG_XID
#ifdef DEBUG_XID
#define DPRINTF printf
#else
#define DPRINTF(...)
#endif
#define USB_VENDOR_HORI 0x0F0D
#define ARCADE_STICK_IN_ENDPOINT_ID 0x01
#define USB_XID_FS(obj) \
OBJECT_CHECK(USBXIDGamepadState, (obj), TYPE_USB_XID_ARCADE_STICK)
static const USBDescIface desc_iface_arcade_stick = {
.bInterfaceNumber = 0,
.bNumEndpoints = 1,
.bInterfaceClass = USB_CLASS_XID,
.bInterfaceSubClass = 0x42,
.bInterfaceProtocol = 0x00,
.eps = (USBDescEndpoint[]){ {
.bEndpointAddress = USB_DIR_IN | ARCADE_STICK_IN_ENDPOINT_ID,
.bmAttributes = USB_ENDPOINT_XFER_INT,
.wMaxPacketSize = 0x40,
.bInterval = 4,
} },
};
static const USBDescDevice desc_device_xbox_arcade_stick = {
.bcdUSB = 0x0110,
.bMaxPacketSize0 = 0x08,
.bNumConfigurations = 1,
.confs =
(USBDescConfig[]){
{
.bNumInterfaces = 1,
.bConfigurationValue = 1,
.bmAttributes = USB_CFG_ATT_ONE,
.bMaxPower = 50,
.nif = 1,
.ifs = &desc_iface_arcade_stick,
},
},
};
static const USBDesc desc_xbox_arcade_stick = {
.id = {
.idVendor = USB_VENDOR_HORI,
.idProduct = 0x0001,
.bcdDevice = 0x0100,
.iManufacturer = STR_MANUFACTURER,
.iProduct = STR_PRODUCT,
.iSerialNumber = STR_SERIALNUMBER,
},
.full = &desc_device_xbox_arcade_stick,
.str = desc_strings,
};
static const XIDDesc desc_xid_xbox_arcade_stick = {
.bLength = 0x10,
.bDescriptorType = USB_DT_XID,
.bcdXid = 0x100,
.bType = XID_DEVICETYPE_GAMEPAD,
.bSubType = XID_DEVICESUBTYPE_ARCADE_STICK,
.bMaxInputReportSize = 20,
.bMaxOutputReportSize = 6,
.wAlternateProductIds = { 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF },
};
static void usb_xid_arcade_stick_handle_data(USBDevice *dev, USBPacket *p)
{
USBXIDGamepadState *s = DO_UPCAST(USBXIDGamepadState, dev, dev);
DPRINTF("xid handle_data 0x%x %d 0x%zx\n", p->pid, p->ep->nr, p->iov.size);
switch (p->pid) {
case USB_TOKEN_IN:
if (p->ep->nr == ARCADE_STICK_IN_ENDPOINT_ID) {
update_input(s);
usb_packet_copy(p, &s->in_state, s->in_state.bLength);
} else {
assert(false);
}
break;
default:
p->status = USB_RET_STALL;
assert(false);
break;
}
}
static void usb_xid_arcade_stick_class_initfn(ObjectClass *klass, void *data)
{
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
uc->handle_reset = usb_xid_handle_reset;
uc->handle_control = usb_xid_handle_control;
uc->handle_data = usb_xid_arcade_stick_handle_data;
// uc->handle_destroy = usb_xid_handle_destroy;
uc->handle_attach = usb_desc_attach;
}
static void usb_xbox_arcade_stick_realize(USBDevice *dev, Error **errp)
{
USBXIDGamepadState *s = USB_XID_FS(dev);
usb_desc_create_serial(dev);
usb_desc_init(dev);
s->intr = usb_ep_get(dev, USB_TOKEN_IN, 2);
s->in_state.bLength = sizeof(s->in_state);
s->in_state.bReportId = 0;
s->out_state.length = sizeof(s->out_state);
s->out_state.report_id = 0;
s->xid_desc = &desc_xid_xbox_arcade_stick;
memset(&s->in_state_capabilities, 0xFF, sizeof(s->in_state_capabilities));
s->in_state_capabilities.bLength = sizeof(s->in_state_capabilities);
s->in_state_capabilities.bReportId = 0;
memset(&s->out_state_capabilities, 0xFF, sizeof(s->out_state_capabilities));
s->out_state_capabilities.length = sizeof(s->out_state_capabilities);
s->out_state_capabilities.report_id = 0;
}
static Property xid_properties[] = {
DEFINE_PROP_UINT8("index", USBXIDGamepadState, device_index, 0),
DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription vmstate_usb_arcade_stick = {
.name = TYPE_USB_XID_ARCADE_STICK,
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]){ VMSTATE_USB_DEVICE(dev, USBXIDGamepadState),
// FIXME
VMSTATE_END_OF_LIST() },
};
static void usb_xbox_arcade_stick_class_initfn(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
uc->product_desc = "Xbox Arcade Stick";
uc->usb_desc = &desc_xbox_arcade_stick;
uc->realize = usb_xbox_arcade_stick_realize;
uc->unrealize = usb_xbox_gamepad_unrealize;
usb_xid_arcade_stick_class_initfn(klass, data);
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
dc->vmsd = &vmstate_usb_arcade_stick;
device_class_set_props(dc, xid_properties);
dc->desc = "Xbox Arcade Stick";
}
static const TypeInfo usb_xbox_arcade_stick_info = {
.name = TYPE_USB_XID_ARCADE_STICK,
.parent = TYPE_USB_DEVICE,
.instance_size = sizeof(USBXIDGamepadState),
.class_init = usb_xbox_arcade_stick_class_initfn,
};
static void usb_xid_register_types(void)
{
type_register_static(&usb_xbox_arcade_stick_info);
}
type_init(usb_xid_register_types)

View File

@ -85,7 +85,8 @@ void update_input(USBXIDGamepadState *s)
for (int i = 0; i < 6; i++) {
int pressed = state->buttons & button_map_analog[i][1];
s->in_state.bAnalogButtons[button_map_analog[i][0]] = pressed ? 0xff : 0;
s->in_state.bAnalogButtons[button_map_analog[i][0]] =
pressed ? 0xff : 0;
}
s->in_state.wButtons = 0;
@ -95,8 +96,10 @@ void update_input(USBXIDGamepadState *s)
}
}
s->in_state.bAnalogButtons[GAMEPAD_LEFT_TRIGGER] = state->axis[CONTROLLER_AXIS_LTRIG] >> 7;
s->in_state.bAnalogButtons[GAMEPAD_RIGHT_TRIGGER] = state->axis[CONTROLLER_AXIS_RTRIG] >> 7;
s->in_state.bAnalogButtons[GAMEPAD_LEFT_TRIGGER] =
state->axis[CONTROLLER_AXIS_LTRIG] >> 7;
s->in_state.bAnalogButtons[GAMEPAD_RIGHT_TRIGGER] =
state->axis[CONTROLLER_AXIS_RTRIG] >> 7;
s->in_state.sThumbLX = state->axis[CONTROLLER_AXIS_LSTICK_X];
s->in_state.sThumbLY = state->axis[CONTROLLER_AXIS_LSTICK_Y];
s->in_state.sThumbRX = state->axis[CONTROLLER_AXIS_RSTICK_X];
@ -108,14 +111,15 @@ void usb_xid_handle_reset(USBDevice *dev)
DPRINTF("xid reset\n");
}
void usb_xid_handle_control(USBDevice *dev, USBPacket *p,
int request, int value, int index, int length, uint8_t *data)
void usb_xid_handle_control(USBDevice *dev, USBPacket *p, int request,
int value, int index, int length, uint8_t *data)
{
USBXIDGamepadState *s = (USBXIDGamepadState *)dev;
DPRINTF("xid handle_control 0x%x 0x%x\n", request, value);
int ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
int ret =
usb_desc_handle_control(dev, p, request, value, index, length, data);
if (ret >= 0) {
DPRINTF("xid handled by usb_desc_handle_control: %d\n", ret);
return;
@ -216,7 +220,7 @@ void usb_xid_handle_control(USBDevice *dev, USBPacket *p,
}
#if 0
static void usb_xid_handle_destroy(USBDevice *dev)
void usb_xid_handle_destroy(USBDevice *dev)
{
USBXIDState *s = DO_UPCAST(USBXIDState, dev, dev);
DPRINTF("xid handle_destroy\n");

View File

@ -48,12 +48,16 @@
#define XID_GET_CAPABILITIES 0x01
#define XID_DEVICETYPE_GAMEPAD 0x01
#define XID_DEVICETYPE_STEEL_BATTALION 0x80
#define XID_DEVICESUBTYPE_GAMEPAD 0x01
#define XID_DEVICESUBTYPE_GAMEPAD_S 0x02
#define XID_DEVICESUBTYPE_ARCADE_STICK 0x20
#define XID_DEVICESUBTYPE_DIGITAL_ARCADE_STICK 0x21
#define TYPE_USB_XID_GAMEPAD "usb-xbox-gamepad"
#define TYPE_USB_XID_GAMEPAD_S "usb-xbox-gamepad-s"
#define TYPE_USB_XID_ARCADE_STICK "usb-xbox-arcade-stick"
#define GAMEPAD_A 0
#define GAMEPAD_B 1

View File

@ -143,6 +143,8 @@ static const char *get_bound_driver(int port)
return DRIVER_DUKE;
if (strcmp(driver, DRIVER_S) == 0)
return DRIVER_S;
if (strcmp(driver, DRIVER_ARCADE_STICK) == 0)
return DRIVER_ARCADE_STICK;
return DRIVER_DUKE;
}

View File

@ -32,9 +32,11 @@
#define DRIVER_DUKE "usb-xbox-gamepad"
#define DRIVER_S "usb-xbox-gamepad-s"
#define DRIVER_ARCADE_STICK "usb-xbox-arcade-stick"
#define DRIVER_DUKE_DISPLAY_NAME "Xbox Controller"
#define DRIVER_S_DISPLAY_NAME "Xbox Controller S"
#define DRIVER_ARCADE_STICK_DISPLAY_NAME "Arcade Stick"
enum controller_state_buttons_mask {
CONTROLLER_BUTTON_A = (1 << 0),

View File

@ -21,6 +21,7 @@
#include "common.hh"
#include "data/controller_mask.png.h"
#include "data/controller_mask_s.png.h"
#include "data/arcade_stick_mask.png.h"
#include "data/logo_sdf.png.h"
#include "data/xemu_64x64.png.h"
#include "data/xmu_mask.png.h"
@ -34,7 +35,8 @@
#include "ui/shader/xemu-logo-frag.h"
Fbo *controller_fbo, *xmu_fbo, *logo_fbo;
GLuint g_controller_duke_tex, g_controller_s_tex, g_logo_tex, g_icon_tex, g_xmu_tex;
GLuint g_controller_duke_tex, g_controller_s_tex, g_arcade_stick_tex,
g_logo_tex, g_icon_tex, g_xmu_tex;
enum class ShaderType {
Blit,
@ -425,6 +427,11 @@ static const struct rect tex_items[] = {
{ 0, 0, 512, 512 } // obj_xmu
};
static const struct rect arcade_stick_tex_items[] = {
{ 0, 183, 467, 329 }, // obj_controller
{ 0, 0, 60, 60 } // obj_stick
};
enum tex_item_names {
obj_controller,
obj_lstick,
@ -444,6 +451,8 @@ void InitCustomRendering(void)
LoadTextureFromMemory(controller_mask_data, controller_mask_size);
g_controller_s_tex =
LoadTextureFromMemory(controller_mask_s_data, controller_mask_s_size);
g_arcade_stick_tex =
LoadTextureFromMemory(arcade_stick_mask_data, arcade_stick_mask_size);
g_decal_shader = NewDecalShader(ShaderType::Mask);
controller_fbo = new Fbo(512, 512);
@ -793,12 +802,112 @@ static void RenderControllerS(float frame_x, float frame_y, uint32_t primary_col
glUseProgram(0);
}
void RenderArcadeStick(float frame_x, float frame_y, uint32_t primary_color,
uint32_t secondary_color, ControllerState *state)
{
// Location within the controller texture of masked button locations,
// relative to the origin of the controller
const struct rect stick_ctr = { 116, 161, 0, 0 };
const struct rect buttons[12] = {
{ 216, 126, 37, 39 }, // A
{ 224, 182, 37, 39 }, // B
{ 271, 206, 37, 39 }, // X
{ 322, 200, 37, 39 }, // Y
{ 0, 0, 0, 0 }, // D-Left
{ 0, 0, 0, 0 }, // D-Up
{ 0, 0, 0, 0 }, // D-Right
{ 0, 0, 0, 0 }, // D-Down
{ 378, 280, 21, 23 }, // Back
{ 402, 280, 21, 23 }, // Start
{ 118, 225, 21, 23 }, // White
{ 141, 225, 21, 23 }, // Black
};
const struct rect triggers[2] = {
{ 70, 225, 21, 23 }, // L
{ 93, 225, 21, 23 } // R
};
frame_x += 5;
glUseProgram(g_decal_shader->prog);
glBindVertexArray(g_decal_shader->vao);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, g_arcade_stick_tex);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ZERO);
// Render controller texture
RenderDecal(g_decal_shader, frame_x + 0, frame_y + 0,
arcade_stick_tex_items[obj_controller].w,
arcade_stick_tex_items[obj_controller].h,
arcade_stick_tex_items[obj_controller].x,
arcade_stick_tex_items[obj_controller].y,
arcade_stick_tex_items[obj_controller].w,
arcade_stick_tex_items[obj_controller].h, primary_color,
secondary_color, 0);
glBlendFunc(GL_ONE_MINUS_DST_ALPHA,
GL_ONE); // Blend with controller cutouts
// The controller has alpha cutouts where the buttons are. Draw a surface
// behind the buttons if they are activated
for (int i = 0; i < 12; i++) {
if (state->buttons & (1 << i)) {
RenderDecal(g_decal_shader, frame_x + buttons[i].x,
frame_y + buttons[i].y, buttons[i].w, buttons[i].h, 0,
0, 1, 1, 0, 0, primary_color + 0xff);
}
}
// Render trigger bars
float ltrig = state->axis[CONTROLLER_AXIS_LTRIG] / 32767.0;
float rtrig = state->axis[CONTROLLER_AXIS_RTRIG] / 32767.0;
if (ltrig > 0.5) {
RenderDecal(g_decal_shader, frame_x + triggers[0].x,
frame_y + triggers[0].y, triggers[0].w, triggers[0].h, 0, 0,
1, 1, 0, 0, primary_color + 0xff);
}
if (rtrig > 0.5) {
RenderDecal(g_decal_shader, frame_x + triggers[1].x,
frame_y + triggers[1].y, triggers[1].w, triggers[1].h, 0, 0,
1, 1, 0, 0, primary_color + 0xff);
}
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Blend with controller
// Render left thumbstick
float w = arcade_stick_tex_items[obj_lstick].w;
float h = arcade_stick_tex_items[obj_lstick].h;
float c_x = frame_x + stick_ctr.x;
float c_y = frame_y + stick_ctr.y;
float stick_x = (float)state->axis[CONTROLLER_AXIS_LSTICK_X] / 32768.0;
float stick_y = (float)state->axis[CONTROLLER_AXIS_LSTICK_Y] / 32768.0;
RenderDecal(
g_decal_shader, (int)(c_x - w / 2.0f + 10.0f * stick_x),
(int)(c_y - h / 2.0f + 10.0f * stick_y), w, h,
arcade_stick_tex_items[obj_lstick].x,
arcade_stick_tex_items[obj_lstick].y, w, h,
(state->buttons & CONTROLLER_BUTTON_LSTICK) ? secondary_color :
primary_color,
(state->buttons & CONTROLLER_BUTTON_LSTICK) ? primary_color :
secondary_color,
0);
glBindVertexArray(0);
glUseProgram(0);
}
void RenderController(float frame_x, float frame_y, uint32_t primary_color,
uint32_t secondary_color, ControllerState *state)
{
if (strcmp(bound_drivers[state->bound], DRIVER_S) == 0)
RenderControllerS(frame_x, frame_y, primary_color, secondary_color,
state);
else if (strcmp(bound_drivers[state->bound], DRIVER_ARCADE_STICK) == 0)
RenderArcadeStick(frame_x, frame_y, primary_color, secondary_color,
state);
else if (strcmp(bound_drivers[state->bound], DRIVER_DUKE) == 0)
RenderDukeController(frame_x, frame_y, primary_color, secondary_color,
state);

View File

@ -172,15 +172,19 @@ void MainMenuInputView::Draw()
driver = DRIVER_DUKE_DISPLAY_NAME;
else if (strcmp(driver, DRIVER_S) == 0)
driver = DRIVER_S_DISPLAY_NAME;
else if (strcmp(driver, DRIVER_ARCADE_STICK) == 0)
driver = DRIVER_ARCADE_STICK_DISPLAY_NAME;
ImGui::SetNextItemWidth(-FLT_MIN);
if (ImGui::BeginCombo("###InputDrivers", driver,
ImGuiComboFlags_NoArrowButton)) {
const char *available_drivers[] = { DRIVER_DUKE, DRIVER_S };
const char *driver_display_names[] = {
const char *available_drivers[] = { DRIVER_DUKE, DRIVER_S,
DRIVER_ARCADE_STICK };
const char *driver_display_names[] = {
DRIVER_DUKE_DISPLAY_NAME,
DRIVER_S_DISPLAY_NAME
};
DRIVER_S_DISPLAY_NAME,
DRIVER_ARCADE_STICK_DISPLAY_NAME
};
bool is_selected = false;
int num_drivers = sizeof(driver_display_names) / sizeof(driver_display_names[0]);
for (int i = 0; i < num_drivers; i++) {