mirror of https://github.com/xemu-project/xemu.git
Merge f364025694
into 5685a6290c
This commit is contained in:
commit
1a26d0a182
287
config_spec.yml
287
config_spec.yml
|
@ -23,12 +23,16 @@ input:
|
|||
bindings:
|
||||
port1_driver: string
|
||||
port1: string
|
||||
port1_dvd_firmware: string
|
||||
port2_driver: string
|
||||
port2: string
|
||||
port2_dvd_firmware: string
|
||||
port3_driver: string
|
||||
port3: string
|
||||
port3_dvd_firmware: string
|
||||
port4_driver: string
|
||||
port4: string
|
||||
port4_dvd_firmware: string
|
||||
peripherals:
|
||||
port1:
|
||||
peripheral_type_0: integer
|
||||
|
@ -56,7 +60,7 @@ input:
|
|||
default: true
|
||||
background_input_capture: bool
|
||||
keyboard_controller_scancode_map:
|
||||
# Scancode reference : https://github.com/libsdl-org/SDL/blob/main/include/SDL_scancode.h
|
||||
# Scancode reference : https://github.com/libsdl-org/SDL/blob/main/include/SDL3/SDL_scancode.h
|
||||
a:
|
||||
type: integer
|
||||
default: 4 # a
|
||||
|
@ -132,6 +136,287 @@ input:
|
|||
rtrigger:
|
||||
type: integer
|
||||
default: 18 # w
|
||||
keyboard_dvd_kit_scancode_map:
|
||||
up:
|
||||
type: integer
|
||||
default: 26 # W
|
||||
left:
|
||||
type: integer
|
||||
default: 4 # A
|
||||
select:
|
||||
type: integer
|
||||
default: 40 # Return
|
||||
right:
|
||||
type: integer
|
||||
default: 7 # D
|
||||
down:
|
||||
type: integer
|
||||
default: 22 # S
|
||||
display:
|
||||
type: integer
|
||||
default: 20 # Q
|
||||
reverse:
|
||||
type: integer
|
||||
default: 29 # Z
|
||||
play:
|
||||
type: integer
|
||||
default: 27 # X
|
||||
forward:
|
||||
type: integer
|
||||
default: 25 # V
|
||||
skip_down:
|
||||
type: integer
|
||||
default: 54 # Comma<
|
||||
stop:
|
||||
type: integer
|
||||
default: 19 # P
|
||||
pause:
|
||||
type: integer
|
||||
default: 6 # C
|
||||
skip_up:
|
||||
type: integer
|
||||
default: 55 # Period>
|
||||
title:
|
||||
type: integer
|
||||
default: 23 # T
|
||||
info:
|
||||
type: integer
|
||||
default: 12 # I
|
||||
menu:
|
||||
type: integer
|
||||
default: 16 # M
|
||||
back:
|
||||
type: integer
|
||||
default: 42 # Backspace
|
||||
button1:
|
||||
type: integer
|
||||
default: 30 # 1
|
||||
button2:
|
||||
type: integer
|
||||
default: 31 # 2
|
||||
button3:
|
||||
type: integer
|
||||
default: 32 # 3
|
||||
button4:
|
||||
type: integer
|
||||
default: 33 # 4
|
||||
button5:
|
||||
type: integer
|
||||
default: 34 # 5
|
||||
button6:
|
||||
type: integer
|
||||
default: 35 # 6
|
||||
button7:
|
||||
type: integer
|
||||
default: 36 # 7
|
||||
button8:
|
||||
type: integer
|
||||
default: 37 # 8
|
||||
button9:
|
||||
type: integer
|
||||
default: 38 # 9
|
||||
button0:
|
||||
type: integer
|
||||
default: 39 # 0
|
||||
power:
|
||||
type: integer
|
||||
default: 58 # F1
|
||||
my_tv:
|
||||
type: integer
|
||||
default: 59 # F2
|
||||
my_music:
|
||||
type: integer
|
||||
default: 60 # F3
|
||||
my_pictures:
|
||||
type: integer
|
||||
default: 61 # F4
|
||||
my_videos:
|
||||
type: integer
|
||||
default: 62 # F5
|
||||
record:
|
||||
type: integer
|
||||
default: 63 # F6
|
||||
start:
|
||||
type: integer
|
||||
default: 64 # F7
|
||||
volume_up:
|
||||
type: integer
|
||||
default: 65 # F8
|
||||
volume_down:
|
||||
type: integer
|
||||
default: 66 # F9
|
||||
mute:
|
||||
type: integer
|
||||
default: 67 # F10
|
||||
channel_up:
|
||||
type: integer
|
||||
default: 68 # F11
|
||||
channel_down:
|
||||
type: integer
|
||||
default: 69 # F12
|
||||
recorded_tv:
|
||||
type: integer
|
||||
default: 21 # R
|
||||
live_tv:
|
||||
type: integer
|
||||
default: 15 # L
|
||||
star:
|
||||
type: integer
|
||||
default: 45 # minus-
|
||||
pound:
|
||||
type: integer
|
||||
default: 46 # equal=
|
||||
clear:
|
||||
type: integer
|
||||
default: 49 # backslash\
|
||||
keyboard_sbc_scancode_map:
|
||||
eject:
|
||||
type: integer
|
||||
default: 41 # esc
|
||||
cockpit_hatch:
|
||||
type: integer
|
||||
default: 62 # F5
|
||||
ignition:
|
||||
type: integer
|
||||
default: 63 # F6
|
||||
start:
|
||||
type: integer
|
||||
default: 64 # F7
|
||||
open_close:
|
||||
type: integer
|
||||
default: 74 # home
|
||||
map_zoom_in_out:
|
||||
type: integer
|
||||
default: 77 # end
|
||||
mode_select:
|
||||
type: integer
|
||||
default: 73 # insert
|
||||
sub_monitor_mode_select:
|
||||
type: integer
|
||||
default: 76 # delete
|
||||
zoom_in:
|
||||
type: integer
|
||||
default: 75 # Page Up
|
||||
zoom_out:
|
||||
type: integer
|
||||
default: 78 # Page Down
|
||||
fss:
|
||||
type: integer
|
||||
default: 97 # numpad 9
|
||||
manipulator:
|
||||
type: integer
|
||||
default: 94 # numpad 6
|
||||
line_color_change:
|
||||
type: integer
|
||||
default: 91 # numpad 3
|
||||
washing:
|
||||
type: integer
|
||||
default: 45 # -
|
||||
extinguisher:
|
||||
type: integer
|
||||
default: 8 # e
|
||||
chaff:
|
||||
type: integer
|
||||
default: 6 # c
|
||||
tank_detach:
|
||||
type: integer
|
||||
default: 96 # numpad 8
|
||||
override:
|
||||
type: integer
|
||||
default: 93 # numpad 5
|
||||
night_scope:
|
||||
type: integer
|
||||
default: 90 # numpad 2
|
||||
func1:
|
||||
type: integer
|
||||
default: 95 # numpad 7
|
||||
func2:
|
||||
type: integer
|
||||
default: 92 # numpad 4
|
||||
func3:
|
||||
type: integer
|
||||
default: 89 # numpad 1
|
||||
main_weapon_control:
|
||||
type: integer
|
||||
default: 35 # 6
|
||||
sub_weapon_control:
|
||||
type: integer
|
||||
default: 36 # 7
|
||||
magazine_change:
|
||||
type: integer
|
||||
default: 21 # r
|
||||
com1:
|
||||
type: integer
|
||||
default: 30 # 1
|
||||
com2:
|
||||
type: integer
|
||||
default: 31 # 2
|
||||
com3:
|
||||
type: integer
|
||||
default: 32 # 3
|
||||
com4:
|
||||
type: integer
|
||||
default: 33 # 4
|
||||
com5:
|
||||
type: integer
|
||||
default: 34 # 5
|
||||
sight_change:
|
||||
type: integer
|
||||
default: 20 # q
|
||||
filt_control_system:
|
||||
type: integer
|
||||
default: 65 # F8
|
||||
oxygen_supply_system:
|
||||
type: integer
|
||||
default: 66 # F9
|
||||
fuel_flow_rate:
|
||||
type: integer
|
||||
default: 67 # F10
|
||||
buffer_material:
|
||||
type: integer
|
||||
default: 68 # F11
|
||||
vt_location_measurement:
|
||||
type: integer
|
||||
default: 69 # F12
|
||||
gear_up:
|
||||
type: integer
|
||||
default: 225 # lshift
|
||||
gear_down:
|
||||
type: integer
|
||||
default: 224 # lctrl
|
||||
tuner_left:
|
||||
type: integer
|
||||
default: 54 # <
|
||||
tuner_right:
|
||||
type: integer
|
||||
default: 55 # >
|
||||
sight_change_up:
|
||||
type: integer
|
||||
default: 82 # up
|
||||
sight_change_down:
|
||||
type: integer
|
||||
default: 81 # down
|
||||
sight_change_left:
|
||||
type: integer
|
||||
default: 80 # left
|
||||
sight_change_right:
|
||||
type: integer
|
||||
default: 79 # right
|
||||
rotation_left:
|
||||
type: integer
|
||||
default: 4 # a
|
||||
rotation_right:
|
||||
type: integer
|
||||
default: 7 # d
|
||||
left_pedal:
|
||||
type: integer
|
||||
default: 44 #space
|
||||
right_pedal:
|
||||
type: integer
|
||||
default: 26 # w
|
||||
middle_pedal:
|
||||
type: integer
|
||||
default: 22 # s
|
||||
|
||||
display:
|
||||
renderer:
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 29 KiB |
|
@ -0,0 +1,785 @@
|
|||
<svg
|
||||
viewBox="15 15 120 120">
|
||||
<style>
|
||||
.Border {
|
||||
fill: black;
|
||||
stroke: red;
|
||||
stroke-width: 1.5;
|
||||
stroke-miterlimit: 0;
|
||||
}
|
||||
.Btn {
|
||||
fill: blue;
|
||||
stroke: red;
|
||||
stroke-width: .8;
|
||||
stroke-miterlimit: 0;
|
||||
}
|
||||
.BtnLabel {
|
||||
fill: red;
|
||||
font: bold 2px sans-serif;
|
||||
text-anchor: middle;
|
||||
}
|
||||
.Label {
|
||||
fill: red;
|
||||
text-anchor: middle;
|
||||
}
|
||||
</style>
|
||||
<g
|
||||
id="Red border">
|
||||
<path
|
||||
id="Red border path"
|
||||
fill="none"
|
||||
stroke="red"
|
||||
stroke-width="1"
|
||||
d="m 0,0
|
||||
l 0,150
|
||||
l 150,0
|
||||
l 0,-150
|
||||
l -150,0"/>
|
||||
</g>
|
||||
<g
|
||||
id="DVD remote">
|
||||
<path
|
||||
class="Border"
|
||||
id="DVD border"
|
||||
d="m 40,20
|
||||
l -20,0
|
||||
l 0,95
|
||||
l 40,0
|
||||
l 0,-95
|
||||
l -20,0"/>
|
||||
<text x="40" y="24" class="Label" font-size="3px" id="DVD label">DVD</text>
|
||||
<text x="40" y="26" class="BtnLabel" id="DVD DISPLAY label">DISPLAY</text>
|
||||
<path
|
||||
class="Btn"
|
||||
id="DVD DISPLAY"
|
||||
d="m 40,27
|
||||
l -4,0
|
||||
l 0,4
|
||||
l 8,0
|
||||
l 0,-4
|
||||
l -4,0"/>
|
||||
<text x="30" y="34" class="BtnLabel" id="DVD REVERSE label">REVERSE</text>
|
||||
<text x="40" y="34" class="BtnLabel" id="DVD PLAY label">PLAY</text>
|
||||
<text x="50" y="34" class="BtnLabel" id="DVD FORWARD label">FORWARD</text>
|
||||
<path
|
||||
class="Btn"
|
||||
id="DVD REVERSE"
|
||||
d="m 30,35
|
||||
l -4,0
|
||||
l 0,4
|
||||
l 8,0
|
||||
l 0,-4
|
||||
l -4,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="DVD PLAY"
|
||||
d="m 40,35
|
||||
l -4,0
|
||||
l 0,4
|
||||
l 8,0
|
||||
l 0,-4
|
||||
l -4,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="DVD FORWARD"
|
||||
d="m 50,35
|
||||
l -4,0
|
||||
l 0,4
|
||||
l 8,0
|
||||
l 0,-4
|
||||
l -4,0"/>
|
||||
<text x="28" y="42" class="BtnLabel" id="DVD SKIP- label">SKIP-</text>
|
||||
<text x="36" y="42" class="BtnLabel" id="DVD STOP label">STOP</text>
|
||||
<text x="44" y="42" class="BtnLabel" id="DVD PAUSE label">PAUSE</text>
|
||||
<text x="52" y="42" class="BtnLabel" id="DVD SKIP+ label">SKIP+</text>
|
||||
<path
|
||||
class="Btn"
|
||||
id="DVD SKIP-"
|
||||
d="m 28,43
|
||||
l -2,0
|
||||
l 0,4
|
||||
l 4,0
|
||||
l 0,-4
|
||||
l -2,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="DVD STOP"
|
||||
d="m 36,43
|
||||
l -2,0
|
||||
l 0,4
|
||||
l 4,0
|
||||
l 0,-4
|
||||
l -2,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="DVD PAUSE"
|
||||
d="m 44,43
|
||||
l -2,0
|
||||
l 0,4
|
||||
l 4,0
|
||||
l 0,-4
|
||||
l -2,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="DVD SKIP+"
|
||||
d="m 52,43
|
||||
l -2,0
|
||||
l 0,4
|
||||
l 4,0
|
||||
l 0,-4
|
||||
l -2,0"/>
|
||||
<text x="28" y="50" class="BtnLabel" id="DVD TITLE label">TITLE</text>
|
||||
<text x="52" y="50" class="BtnLabel" id="DVD INFO label">INFO</text>
|
||||
<path
|
||||
class="Btn"
|
||||
id="DVD TITLE"
|
||||
d="m 28,51
|
||||
l -2,0
|
||||
l 0,4
|
||||
l 4,0
|
||||
l 0,-4
|
||||
l -2,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="DVD INFO"
|
||||
d="m 52,51
|
||||
l -2,0
|
||||
l 0,4
|
||||
l 4,0
|
||||
l 0,-4
|
||||
l -2,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="DVD UP"
|
||||
d="m 40,55
|
||||
l 4,0
|
||||
l -4,-4
|
||||
l -4,4
|
||||
l 4,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="DVD LEFT"
|
||||
d="m 34,60
|
||||
l 0,-2
|
||||
l -8,2
|
||||
l 8,2
|
||||
l 0,-2"/>
|
||||
<text x="40" y="57.3" class="BtnLabel" id="DVD SELECT label">SELECT</text>
|
||||
<path
|
||||
class="Btn"
|
||||
id="DVD SELECT"
|
||||
d="m 40,58
|
||||
l -4,0
|
||||
l 0,4
|
||||
l 8,0
|
||||
l 0,-4
|
||||
l -4,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="DVD RIGHT"
|
||||
d="m 46,60
|
||||
l 0,-2
|
||||
l 8,2
|
||||
l -8,2
|
||||
l 0,-2"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="DVD DOWN"
|
||||
d="m 40,65
|
||||
l 4,0
|
||||
l -4,4
|
||||
l -4,-4
|
||||
l 4,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="DVD MENU"
|
||||
d="m 28,65
|
||||
l -2,0
|
||||
l 0,4
|
||||
l 4,0
|
||||
l 0,-4
|
||||
l -2,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="DVD BACK"
|
||||
d="m 52,65
|
||||
l -2,0
|
||||
l 0,4
|
||||
l 4,0
|
||||
l 0,-4
|
||||
l -2,0"/>
|
||||
<text x="28" y="71.5" class="BtnLabel" id="DVD MENU label">MENU</text>
|
||||
<text x="52" y="71.5" class="BtnLabel" id="DVD BACK label">BACK</text>
|
||||
<path
|
||||
class="Btn"
|
||||
id="DVD 1"
|
||||
d="m 30,73
|
||||
l -2,0
|
||||
l 0,4
|
||||
l 4,0
|
||||
l 0,-4
|
||||
l -2,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="DVD 2"
|
||||
d="m 40,73
|
||||
l -2,0
|
||||
l 0,4
|
||||
l 4,0
|
||||
l 0,-4
|
||||
l -2,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="DVD 3"
|
||||
d="m 50,73
|
||||
l -2,0
|
||||
l 0,4
|
||||
l 4,0
|
||||
l 0,-4
|
||||
l -2,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="DVD 4"
|
||||
d="m 30,80
|
||||
l -2,0
|
||||
l 0,4
|
||||
l 4,0
|
||||
l 0,-4
|
||||
l -2,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="DVD 5"
|
||||
d="m 40,80
|
||||
l -2,0
|
||||
l 0,4
|
||||
l 4,0
|
||||
l 0,-4
|
||||
l -2,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="DVD 6"
|
||||
d="m 50,80
|
||||
l -2,0
|
||||
l 0,4
|
||||
l 4,0
|
||||
l 0,-4
|
||||
l -2,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="DVD 7"
|
||||
d="m 30,87
|
||||
l -2,0
|
||||
l 0,4
|
||||
l 4,0
|
||||
l 0,-4
|
||||
l -2,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="DVD 8"
|
||||
d="m 40,87
|
||||
l -2,0
|
||||
l 0,4
|
||||
l 4,0
|
||||
l 0,-4
|
||||
l -2,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="DVD 9"
|
||||
d="m 50,87
|
||||
l -2,0
|
||||
l 0,4
|
||||
l 4,0
|
||||
l 0,-4
|
||||
l -2,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="DVD 0"
|
||||
d="m 40,94
|
||||
l -2,0
|
||||
l 0,4
|
||||
l 4,0
|
||||
l 0,-4
|
||||
l -2,0"/>
|
||||
<text x="26" y="75" class="BtnLabel" id="DVD 1 label">1</text>
|
||||
<text x="36" y="75" class="BtnLabel" id="DVD 2 label">2</text>
|
||||
<text x="46" y="75" class="BtnLabel" id="DVD 3 label">3</text>
|
||||
<text x="26" y="82" class="BtnLabel" id="DVD 4 label">4</text>
|
||||
<text x="36" y="82" class="BtnLabel" id="DVD 5 label">5</text>
|
||||
<text x="46" y="82" class="BtnLabel" id="DVD 6 label">6</text>
|
||||
<text x="26" y="89" class="BtnLabel" id="DVD 7 label">7</text>
|
||||
<text x="36" y="89" class="BtnLabel" id="DVD 8 label">8</text>
|
||||
<text x="46" y="89" class="BtnLabel" id="DVD 9 label">9</text>
|
||||
<text x="36" y="96" class="BtnLabel" id="DVD 0 label">0</text>
|
||||
<text x="40" y="107" class="Label" font-size="9px" id="DVD X label">X</text>
|
||||
<text x="40" y="110" class="Label" font-size="3px" id="DVD XBOX label">XBOX</text>
|
||||
</g>
|
||||
|
||||
<g
|
||||
id="Media Center remote">
|
||||
<path
|
||||
class="Border"
|
||||
id="MCE border"
|
||||
d="m 110,20
|
||||
l -20,0
|
||||
l 0,110
|
||||
l 41,0
|
||||
l 0,-110
|
||||
l -21,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE POWER"
|
||||
d="m 126,23
|
||||
l -1,0
|
||||
l 0,3
|
||||
l 3,0
|
||||
l 0,-3
|
||||
l -2,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE MY TV"
|
||||
d="m 97,29
|
||||
l -1,0
|
||||
l 0,3
|
||||
l 3,0
|
||||
l 0,-3
|
||||
l -2,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE MY Music"
|
||||
d="m 105,26
|
||||
l -1,0
|
||||
l 0,3
|
||||
l 3,0
|
||||
l 0,-3
|
||||
l -2,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE MY Pictures"
|
||||
d="m 115,26
|
||||
l -1,0
|
||||
l 0,3
|
||||
l 3,0
|
||||
l 0,-3
|
||||
l -2,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE MY Videos"
|
||||
d="m 123,29
|
||||
l -1,0
|
||||
l 0,3
|
||||
l 3,0
|
||||
l 0,-3
|
||||
l -2,0"/>
|
||||
<text x="126.5" y="25.1" class="BtnLabel" id="MCE Power label">⏻</text>
|
||||
<text x="97.5" y="28.2" class="BtnLabel" id="MCE My TV label">My TV</text>
|
||||
<text x="104.5" y="25.2" class="BtnLabel" id="MCE My Music label">My Music</text>
|
||||
<text x="116.5" y="25.2" class="BtnLabel" id="MCE My Pictures label">My Pictures</text>
|
||||
<text x="123.5" y="28.2" class="BtnLabel" id="MCE My Videos label">My Videos</text>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE STOP"
|
||||
d="m 110,32
|
||||
l -1,0
|
||||
l 0,3
|
||||
l 3,0
|
||||
l 0,-3
|
||||
l -2,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE RECORD"
|
||||
d="m 103,34
|
||||
l -1,0
|
||||
l 0,3
|
||||
l 3,0
|
||||
l 0,-3
|
||||
l -2,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE PAUSE"
|
||||
d="m 117,34
|
||||
l -1,0
|
||||
l 0,3
|
||||
l 3,0
|
||||
l 0,-3
|
||||
l -2,0"/>
|
||||
<text x="110.5" y="31" class="BtnLabel" id="MCE STOP label">STOP</text>
|
||||
<text x="103.5" y="33" class="BtnLabel" id="MCE RECORD label">REC</text>
|
||||
<text x="117.5" y="33" class="BtnLabel" id="MCE PAUSE label">PAUSE</text>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE REW"
|
||||
d="m 96,34
|
||||
l -1,0
|
||||
l 0,3
|
||||
l 3,0
|
||||
l 0,-3
|
||||
l -2,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE FWD"
|
||||
d="m 124,34
|
||||
l -1,0
|
||||
l 0,3
|
||||
l 3,0
|
||||
l 0,-3
|
||||
l -2,0"/>
|
||||
<text x="96.5" y="39.2" class="BtnLabel" id="MCE REW label">REW</text>
|
||||
<text x="124.5" y="39.2" class="BtnLabel" id="MCE FWD label">FWD</text>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE REPLAY"
|
||||
d="m 103,39
|
||||
l -1,0
|
||||
l 0,3
|
||||
l 3,0
|
||||
l 0,-3
|
||||
l -2,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE PLAY"
|
||||
d="m 110,37
|
||||
l -2,0
|
||||
l 0,5
|
||||
l 5,0
|
||||
l 0,-5
|
||||
l -3,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE SKIP"
|
||||
d="m 117,39
|
||||
l -1,0
|
||||
l 0,3
|
||||
l 3,0
|
||||
l 0,-3
|
||||
l -2,0"/>
|
||||
<text x="103.5" y="44.2" class="BtnLabel" id="MCE REPLAY label">REPLAY</text>
|
||||
<text x="110.5" y="40.2" class="BtnLabel" id="MCE PLAY icon">▶</text>
|
||||
<text x="117.5" y="44.2" class="BtnLabel" id="MCE SKIP label">SKIP</text>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE BACK"
|
||||
d="m 97,45
|
||||
l -1,0
|
||||
l 0,3
|
||||
l 3,0
|
||||
l 0,-3
|
||||
l -2,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE MORE"
|
||||
d="m 123,45
|
||||
l -1,0
|
||||
l 0,3
|
||||
l 3,0
|
||||
l 0,-3
|
||||
l -2,0"/>
|
||||
<text x="97.5" y="50.2" class="BtnLabel" id="MCE BACK label">BACK</text>
|
||||
<text x="123.5" y="50.2" class="BtnLabel" id="MCE MORE label">MORE</text>
|
||||
<path
|
||||
class="Btn"
|
||||
stroke-width="2"
|
||||
id="MCE UP"
|
||||
d="m 110,49
|
||||
l 4,0
|
||||
l -3.5,-3
|
||||
l -3.5,3
|
||||
l 3,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE LEFT"
|
||||
d="m 105,53
|
||||
l 0,-2
|
||||
l -7,1.6
|
||||
l 7,1.6
|
||||
l 0,-2"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE OK"
|
||||
d="m 110,51
|
||||
l 4,0
|
||||
l 0,3
|
||||
l -7,0
|
||||
l 0,-3
|
||||
l 3,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE RIGHT"
|
||||
d="m 116,53
|
||||
l 0,-2
|
||||
l 7,1.5
|
||||
l -7,1.5
|
||||
l 0,-2"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE DOWN"
|
||||
d="m 110,56
|
||||
l 4,0
|
||||
l -3.5,3
|
||||
l -3.5,-3
|
||||
l 3,0"/>
|
||||
<text x="110.5" y="53.3" class="BtnLabel" id="MCE OK label">OK</text>
|
||||
<text x="110.5" y="61.2" class="BtnLabel" id="MCE START label">START</text>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE VOL UP"
|
||||
d="m 98,59
|
||||
l 4,0
|
||||
l 0,3
|
||||
l -7,0
|
||||
l 0,-3
|
||||
l 3,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE START"
|
||||
d="m 110,62
|
||||
l 4,0
|
||||
l 0,3
|
||||
l -7,0
|
||||
l 0,-3
|
||||
l 3,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE CH UP"
|
||||
d="m 122,59
|
||||
l 4,0
|
||||
l 0,3
|
||||
l -7,0
|
||||
l 0,-3
|
||||
l 3,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE VOL DOWN"
|
||||
d="m 100,65
|
||||
l 4,0
|
||||
l 0,3
|
||||
l -7,0
|
||||
l 0,-3
|
||||
l 3,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE MUTE"
|
||||
d="m 110,68
|
||||
l 4,0
|
||||
l 0,3
|
||||
l -7,0
|
||||
l 0,-3
|
||||
l 3,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE CH DOWN"
|
||||
d="m 120,65
|
||||
l 4,0
|
||||
l 0,3
|
||||
l -7,0
|
||||
l 0,-3
|
||||
l 3,0"/>
|
||||
<text x="99.5" y="64.2" class="BtnLabel" id="MCE VOL label">VOL</text>
|
||||
<text x="110.5" y="67.2" class="BtnLabel" id="MCE MUTE label">MUTE</text>
|
||||
<text x="121.5" y="64.2" class="BtnLabel" id="MCE CH label">CH/PG</text>
|
||||
<text x="98.5" y="61.3" class="Label" font-size="3px" id="MCE VOL+ label">+</text>
|
||||
<text x="122.5" y="61.3" class="Label" font-size="3px" id="MCE CH+ label">+</text>
|
||||
<text x="100.5" y="67.3" class="Label" font-size="3px" id="MCE VOL- label">-</text>
|
||||
<text x="120.5" y="67.3" class="Label" font-size="3px" id="MCE CH- label">-</text>
|
||||
<text x="98" y="71" class="BtnLabel" id="MCE RECORDED TV label">RECORDED</text>
|
||||
<text x="98" y="73" class="BtnLabel" id="MCE RECORDED TV2 label">TV</text>
|
||||
<text x="106" y="74" class="BtnLabel" id="MCE GUIDE label">GUIDE</text>
|
||||
<text x="115" y="74" class="BtnLabel" id="MCE LIVE TV label">LIVE TV</text>
|
||||
<text x="123" y="71" class="BtnLabel" id="MCE DVD MENU label">DVD</text>
|
||||
<text x="123" y="73" class="BtnLabel" id="MCE DVD MENU2 label">MENU</text>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE RECORDED TV"
|
||||
d="m 98,74
|
||||
l -2,0
|
||||
l 0,3
|
||||
l 4,0
|
||||
l 0,-3
|
||||
l -2,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE GUIDE"
|
||||
d="m 106,75
|
||||
l -2,0
|
||||
l 0,3
|
||||
l 4,0
|
||||
l 0,-3
|
||||
l -2,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE LIVE TV"
|
||||
d="m 115,75
|
||||
l -2,0
|
||||
l 0,3
|
||||
l 4,0
|
||||
l 0,-3
|
||||
l -2,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE DVD MENU"
|
||||
d="m 123,74
|
||||
l -2,0
|
||||
l 0,3
|
||||
l 4,0
|
||||
l 0,-3
|
||||
l -2,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE 1"
|
||||
d="m 100,81
|
||||
l -2,0
|
||||
l 0,3
|
||||
l 5,0
|
||||
l 0,-3
|
||||
l -3,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE 2"
|
||||
d="m 110,81
|
||||
l -2,0
|
||||
l 0,3
|
||||
l 5,0
|
||||
l 0,-3
|
||||
l -3,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE 3"
|
||||
d="m 120,81
|
||||
l -2,0
|
||||
l 0,3
|
||||
l 5,0
|
||||
l 0,-3
|
||||
l -3,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE 4"
|
||||
d="m 100,87
|
||||
l -2,0
|
||||
l 0,3
|
||||
l 5,0
|
||||
l 0,-3
|
||||
l -3,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE 5"
|
||||
d="m 110,87
|
||||
l -2,0
|
||||
l 0,3
|
||||
l 5,0
|
||||
l 0,-3
|
||||
l -3,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE 6"
|
||||
d="m 120,87
|
||||
l -2,0
|
||||
l 0,3
|
||||
l 5,0
|
||||
l 0,-3
|
||||
l -3,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE 7"
|
||||
d="m 100,93
|
||||
l -2,0
|
||||
l 0,3
|
||||
l 5,0
|
||||
l 0,-3
|
||||
l -3,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE 8"
|
||||
d="m 110,93
|
||||
l -2,0
|
||||
l 0,3
|
||||
l 5,0
|
||||
l 0,-3
|
||||
l -3,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE 9"
|
||||
d="m 120,93
|
||||
l -2,0
|
||||
l 0,3
|
||||
l 5,0
|
||||
l 0,-3
|
||||
l -3,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE *"
|
||||
d="m 100,99
|
||||
l -2,0
|
||||
l 0,3
|
||||
l 5,0
|
||||
l 0,-3
|
||||
l -3,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE 0"
|
||||
d="m 110,99
|
||||
l -2,0
|
||||
l 0,3
|
||||
l 5,0
|
||||
l 0,-3
|
||||
l -3,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE #"
|
||||
d="m 120,99
|
||||
l -2,0
|
||||
l 0,3
|
||||
l 5,0
|
||||
l 0,-3
|
||||
l -3,0"/>
|
||||
<text x="110.5" y="80.2" class="BtnLabel" id="MCE 1 label">ABC</text>
|
||||
<text x="120.5" y="80.2" class="BtnLabel" id="MCE 1 label">DEF</text>
|
||||
<text x="100.5" y="83.2" class="BtnLabel" id="MCE 1 label">1</text>
|
||||
<text x="110.5" y="83.2" class="BtnLabel" id="MCE 2 label">2</text>
|
||||
<text x="120.5" y="83.2" class="BtnLabel" id="MCE 3 label">3</text>
|
||||
<text x="100.5" y="86.2" class="BtnLabel" id="MCE 1 label">GHI</text>
|
||||
<text x="110.5" y="86.2" class="BtnLabel" id="MCE 1 label">JKL</text>
|
||||
<text x="120.5" y="86.2" class="BtnLabel" id="MCE 1 label">MNO</text>
|
||||
<text x="100.5" y="89.2" class="BtnLabel" id="MCE 4 label">4</text>
|
||||
<text x="110.5" y="89.2" class="BtnLabel" id="MCE 5 label">5</text>
|
||||
<text x="120.5" y="89.2" class="BtnLabel" id="MCE 6 label">6</text>
|
||||
<text x="100.5" y="92.2" class="BtnLabel" id="MCE 1 label">PQRS</text>
|
||||
<text x="110.5" y="92.2" class="BtnLabel" id="MCE 1 label">TUV</text>
|
||||
<text x="120.5" y="92.2" class="BtnLabel" id="MCE 1 label">WXYZ</text>
|
||||
<text x="100.5" y="95.2" class="BtnLabel" id="MCE 7 label">7</text>
|
||||
<text x="110.5" y="95.2" class="BtnLabel" id="MCE 8 label">8</text>
|
||||
<text x="120.5" y="95.2" class="BtnLabel" id="MCE 9 label">9</text>
|
||||
<text x="110.5" y="98.2" class="BtnLabel" id="MCE 1 label">⌴</text>
|
||||
<text x="100.5" y="101.2" class="BtnLabel" id="MCE * label">*</text>
|
||||
<text x="110.5" y="101.2" class="BtnLabel" id="MCE 0 label">0</text>
|
||||
<text x="120.5" y="101.2" class="BtnLabel" id="MCE # label">#</text>
|
||||
<text x="105.5" y="105" class="BtnLabel" id="MCE CLEAR label">CLEAR</text>
|
||||
<text x="115.5" y="105" class="BtnLabel" id="MCE ENTER label">ENTER</text>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE CLEAR"
|
||||
d="m 106,106
|
||||
l -2,0
|
||||
l 0,3
|
||||
l 4,0
|
||||
l 0,-3
|
||||
l -2,0"/>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE ENTER"
|
||||
d="m 115,106
|
||||
l -2,0
|
||||
l 0,3
|
||||
l 4,0
|
||||
l 0,-3
|
||||
l -2,0"/>
|
||||
<text x="110.5" y="115" class="Label" font-size="3px" id="MCE XBOX label">XBOX</text>
|
||||
<path
|
||||
class="Btn"
|
||||
id="MCE ENTER"
|
||||
d="m 110,116
|
||||
l -2,0
|
||||
l 0,3
|
||||
l 5,0
|
||||
l 0,-3
|
||||
l -3,0"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 17 KiB |
|
@ -1,6 +1,8 @@
|
|||
pfiles = [
|
||||
'sb_controller_mask.png',
|
||||
'controller_mask.png',
|
||||
'controller_mask_s.png',
|
||||
'dvd_remote_mask.png',
|
||||
'xmu_mask.png',
|
||||
'logo_sdf.png',
|
||||
'xemu_64x64.png',
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
|
@ -13,10 +13,12 @@ specific_ss.add(files(
|
|||
'smbus_storage.c',
|
||||
'smbus_xbox_smc.c',
|
||||
'xbox.c',
|
||||
'xbox_dvd_playback_kit.c',
|
||||
'xbox_pci.c',
|
||||
'xid.c',
|
||||
'xblc.c',
|
||||
'xid-gamepad.c',
|
||||
'xid-steel-battalion.c',
|
||||
))
|
||||
subdir('nv2a')
|
||||
subdir('mcpx')
|
||||
|
|
|
@ -0,0 +1,295 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Florin9doi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it 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, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "xid.h"
|
||||
|
||||
typedef struct XboxDVDPlaybackKitReport {
|
||||
uint8_t bReportId;
|
||||
uint8_t bLength;
|
||||
uint16_t wButton;
|
||||
uint16_t wTimer;
|
||||
} QEMU_PACKED XboxDVDPlaybackKitReport;
|
||||
|
||||
typedef struct XboxDVDPlaybackKitState {
|
||||
USBDevice dev;
|
||||
uint8_t device_index;
|
||||
char *firmware_path;
|
||||
uint32_t firmware_len;
|
||||
uint8_t firmware[0x40000];
|
||||
gint64 last_button;
|
||||
gint64 last_packet;
|
||||
XboxDVDPlaybackKitReport in_state;
|
||||
} XboxDVDPlaybackKitState;
|
||||
|
||||
enum {
|
||||
STR_EMPTY
|
||||
};
|
||||
|
||||
static const USBDescIface desc_iface[] = {
|
||||
{
|
||||
.bInterfaceNumber = 0,
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 1,
|
||||
.bInterfaceClass = 0x58, // USB_CLASS_XID,
|
||||
.bInterfaceSubClass = 0x42, // USB_DT_XID
|
||||
.bInterfaceProtocol = 0,
|
||||
.iInterface = STR_EMPTY,
|
||||
.eps = (USBDescEndpoint[]) {
|
||||
{
|
||||
.bEndpointAddress = USB_DIR_IN | 0x01,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = 8,
|
||||
.bInterval = 16,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
.bInterfaceNumber = 1,
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 0,
|
||||
.bInterfaceClass = 0x59,
|
||||
.bInterfaceSubClass = 0,
|
||||
.bInterfaceProtocol = 0,
|
||||
.iInterface = STR_EMPTY,
|
||||
},
|
||||
};
|
||||
|
||||
static const USBDescDevice desc_device = {
|
||||
.bcdUSB = 0x0110,
|
||||
.bDeviceClass = 0,
|
||||
.bDeviceSubClass = 0,
|
||||
.bDeviceProtocol = 0,
|
||||
.bMaxPacketSize0 = 64,
|
||||
.bNumConfigurations = 1,
|
||||
.confs = (USBDescConfig[]) {
|
||||
{
|
||||
.bNumInterfaces = 2,
|
||||
.bConfigurationValue = 1,
|
||||
.iConfiguration = STR_EMPTY,
|
||||
.bmAttributes = 0x00,
|
||||
.bMaxPower = 0x00,
|
||||
.nif = ARRAY_SIZE(desc_iface),
|
||||
.ifs = desc_iface,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static const USBDesc desc_xbox_dvd_playback_kit = {
|
||||
.id = {
|
||||
.idVendor = 0x045e,
|
||||
.idProduct = 0x0284,
|
||||
.bcdDevice = 0x0100,
|
||||
.iManufacturer = STR_EMPTY,
|
||||
.iProduct = STR_EMPTY,
|
||||
.iSerialNumber = STR_EMPTY,
|
||||
},
|
||||
.full = &desc_device,
|
||||
};
|
||||
|
||||
static const XIDDesc desc_xid_xbox_dvd_playback_kit = {
|
||||
.bLength = 0x08,
|
||||
.bDescriptorType = USB_DT_XID,
|
||||
.bcdXid = 0x0100,
|
||||
.bType = XID_DEVICETYPE_DVD_PLAYBACK_KIT,
|
||||
.bSubType = XID_DEVICESUBTYPE_DVD_PLAYBACK_KIT,
|
||||
.bMaxInputReportSize = 0x06,
|
||||
.bMaxOutputReportSize = 0x00,
|
||||
};
|
||||
|
||||
struct {
|
||||
uint64_t btn;
|
||||
uint16_t id;
|
||||
} static const dvd_button_ids[] = {
|
||||
{DVD_BUTTON_UP, 0x0AA6},
|
||||
{DVD_BUTTON_LEFT, 0x0AA9},
|
||||
{DVD_BUTTON_SELECT, 0x0A0B},
|
||||
{DVD_BUTTON_RIGHT, 0x0AA8},
|
||||
{DVD_BUTTON_DOWN, 0x0AA7},
|
||||
{DVD_BUTTON_DISPLAY, 0x0AD5},
|
||||
{DVD_BUTTON_REVERSE, 0x0AE2},
|
||||
{DVD_BUTTON_PLAY, 0x0AEA},
|
||||
{DVD_BUTTON_FORWARD, 0x0AE3},
|
||||
{DVD_BUTTON_SKIP_DOWN, 0x0ADD},
|
||||
{DVD_BUTTON_STOP, 0x0AE0},
|
||||
{DVD_BUTTON_PAUSE, 0x0AE6},
|
||||
{DVD_BUTTON_SKIP_UP, 0x0ADF},
|
||||
{DVD_BUTTON_TITLE, 0x0AE5},
|
||||
{DVD_BUTTON_INFO, 0x0AC3},
|
||||
{DVD_BUTTON_MENU, 0x0AF7},
|
||||
{DVD_BUTTON_BACK, 0x0AD8},
|
||||
{DVD_BUTTON_1, 0x0ACE},
|
||||
{DVD_BUTTON_2, 0x0ACD},
|
||||
{DVD_BUTTON_3, 0x0ACC},
|
||||
{DVD_BUTTON_4, 0x0ACB},
|
||||
{DVD_BUTTON_5, 0x0ACA},
|
||||
{DVD_BUTTON_6, 0x0AC9},
|
||||
{DVD_BUTTON_7, 0x0AC8},
|
||||
{DVD_BUTTON_8, 0x0AC7},
|
||||
{DVD_BUTTON_9, 0x0AC6},
|
||||
{DVD_BUTTON_0, 0x0ACF},
|
||||
// Media Center Extender Remote
|
||||
{MCE_BUTTON_POWER, 0x0AC4},
|
||||
{MCE_BUTTON_MY_TV, 0x0A31},
|
||||
{MCE_BUTTON_MY_MUSIC, 0x0A09},
|
||||
{MCE_BUTTON_MY_PICTURES, 0x0A06},
|
||||
{MCE_BUTTON_MY_VIDEOS, 0x0A07},
|
||||
{MCE_BUTTON_RECORD, 0x0AE8},
|
||||
{MCE_BUTTON_START, 0x0A25},
|
||||
{MCE_BUTTON_VOL_UP, 0x0AD0},
|
||||
{MCE_BUTTON_VOL_DOWN, 0x0AD1},
|
||||
{MCE_BUTTON_MUTE, 0x0AC0},
|
||||
{MCE_BUTTON_CH_UP, 0x0AD2},
|
||||
{MCE_BUTTON_CH_DOWN, 0x0AD3},
|
||||
{MCE_BUTTON_RECORDED_TV, 0x0A65},
|
||||
{MCE_BUTTON_LIVE_TV, 0x0A18},
|
||||
{MCE_BUTTON_STAR, 0x0A28},
|
||||
{MCE_BUTTON_POUND, 0x0A29},
|
||||
{MCE_BUTTON_CLEAR, 0x0AF9},
|
||||
};
|
||||
|
||||
static void xbox_dvd_playback_kit_realize(USBDevice *dev, Error **errp) {
|
||||
XboxDVDPlaybackKitState *s = (XboxDVDPlaybackKitState *) dev;
|
||||
|
||||
usb_desc_init(dev);
|
||||
if (!s->firmware_path) {
|
||||
fprintf(stderr, "Firmware file is required\n");
|
||||
s->firmware_len = 0;
|
||||
return;
|
||||
}
|
||||
int fd = open(s->firmware_path, O_RDONLY | O_BINARY);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "Unable to access \"%s\"\n", s->firmware_path);
|
||||
s->firmware_len = 0;
|
||||
return;
|
||||
}
|
||||
size_t size = lseek(fd, 0, SEEK_END);
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
s->firmware_len = read(fd, s->firmware, size);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void xbox_dvd_playback_kit_handle_control(USBDevice *dev, USBPacket *p,
|
||||
int request, int value, int index, int length, uint8_t *data) {
|
||||
XboxDVDPlaybackKitState *s = (XboxDVDPlaybackKitState *) dev;
|
||||
|
||||
int ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
|
||||
if (ret >= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (request) {
|
||||
case 0xc101:
|
||||
case 0xc102:
|
||||
{
|
||||
uint32_t offset = 0x400 * value;
|
||||
if (offset + length <= s->firmware_len) {
|
||||
memcpy(data, s->firmware + offset, length);
|
||||
p->actual_length = length;
|
||||
} else {
|
||||
p->actual_length = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0xc106: // GET_DESCRIPTOR
|
||||
memcpy(data, &desc_xid_xbox_dvd_playback_kit, desc_xid_xbox_dvd_playback_kit.bLength);
|
||||
p->actual_length = desc_xid_xbox_dvd_playback_kit.bLength;
|
||||
break;
|
||||
case 0xa101: // GET_REPORT
|
||||
default:
|
||||
p->actual_length = 0;
|
||||
p->status = USB_RET_STALL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void update_dvd_kit_input(XboxDVDPlaybackKitState *s)
|
||||
{
|
||||
if (xemu_input_get_test_mode()) {
|
||||
// Don't report changes if we are testing the controller while running
|
||||
return;
|
||||
}
|
||||
|
||||
ControllerState *state = xemu_input_get_bound(s->device_index);
|
||||
assert(state);
|
||||
xemu_input_update_controller(state);
|
||||
|
||||
s->in_state.bReportId = 0x00;
|
||||
s->in_state.bLength = 0x06;
|
||||
s->in_state.wButton = 0x0000;
|
||||
s->in_state.wTimer = MIN(g_get_monotonic_time() / 1000 - s->last_button, 0xffff);
|
||||
if (state->dvdKit.buttons) {
|
||||
for (int i = 0; i < sizeof(dvd_button_ids) / sizeof(dvd_button_ids[0]); i++) {
|
||||
if ((1ULL << i) & state->dvdKit.buttons) {
|
||||
s->in_state.wButton = dvd_button_ids[i].id;
|
||||
s->last_button = g_get_monotonic_time() / 1000;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void xbox_dvd_playback_kit_handle_data(USBDevice *dev, USBPacket *p) {
|
||||
XboxDVDPlaybackKitState *s = DO_UPCAST(XboxDVDPlaybackKitState, dev, dev);
|
||||
|
||||
switch (p->pid) {
|
||||
case USB_TOKEN_IN:
|
||||
if ((g_get_monotonic_time() / 1000 - s->last_packet) < 60) {
|
||||
p->status = USB_RET_NAK;
|
||||
return;
|
||||
}
|
||||
s->last_packet = g_get_monotonic_time() / 1000;
|
||||
update_dvd_kit_input(s);
|
||||
usb_packet_copy(p, &s->in_state, s->in_state.bLength);
|
||||
break;
|
||||
case USB_TOKEN_OUT:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static Property xid_properties[] = {
|
||||
DEFINE_PROP_UINT8("index", XboxDVDPlaybackKitState, device_index, 0),
|
||||
DEFINE_PROP_STRING("firmware", XboxDVDPlaybackKitState, firmware_path),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void xbox_dvd_playback_kit_class_init(ObjectClass *klass, void *class_data) {
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
|
||||
|
||||
uc->product_desc = "Microsoft Xbox DVD Playback Kit";
|
||||
uc->usb_desc = &desc_xbox_dvd_playback_kit;
|
||||
uc->realize = xbox_dvd_playback_kit_realize;
|
||||
uc->handle_control = xbox_dvd_playback_kit_handle_control;
|
||||
uc->handle_data = xbox_dvd_playback_kit_handle_data;
|
||||
|
||||
device_class_set_props(dc, xid_properties);
|
||||
dc->desc = "Microsoft Xbox DVD Playback Kit";
|
||||
}
|
||||
|
||||
static const TypeInfo xbox_dvd_playback_kit_info = {
|
||||
.name = TYPE_USB_XBOX_DVD_PLAYBACK_KIT,
|
||||
.parent = TYPE_USB_DEVICE,
|
||||
.instance_size = sizeof(XboxDVDPlaybackKitState),
|
||||
.class_init = xbox_dvd_playback_kit_class_init,
|
||||
};
|
||||
|
||||
static void usb_xbox_dvd_playback_kit_register_types(void) {
|
||||
type_register_static(&xbox_dvd_playback_kit_info);
|
||||
}
|
||||
|
||||
type_init(usb_xbox_dvd_playback_kit_register_types)
|
|
@ -0,0 +1,438 @@
|
|||
/*
|
||||
* 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_CAPCOM 0x0a7b
|
||||
|
||||
#define STEEL_BATTALION_IN_ENDPOINT_ID 0x02
|
||||
#define STEEL_BATTALION_OUT_ENDPOINT_ID 0x01
|
||||
|
||||
typedef struct XIDSteelBattalionReport {
|
||||
uint8_t bReportId;
|
||||
uint8_t bLength;
|
||||
uint32_t dwButtons;
|
||||
uint8_t bMoreButtons;
|
||||
uint16_t wPadding;
|
||||
uint8_t bAimingX;
|
||||
uint8_t bPadding;
|
||||
uint8_t bAimingY;
|
||||
int16_t sRotationLever; // only high byte is used
|
||||
int16_t sSightChangeX; // only high byte is used
|
||||
int16_t sSightChangeY; // only high byte is used
|
||||
uint16_t wLeftPedal; // only high byte is used
|
||||
uint16_t wMiddlePedal; // only high byte is used
|
||||
uint16_t wRightPedal; // only high byte is used
|
||||
uint8_t ucTunerDial; // low nibble, The 9 o'clock postion is 0, and the 6
|
||||
// o'clock position is 12
|
||||
uint8_t ucGearLever; // gear lever 1~5 for gear 1~5, 7~13 for gear R,N,1~5,
|
||||
// 15 for gear R
|
||||
} QEMU_PACKED XIDSteelBattalionReport;
|
||||
|
||||
// Based on:
|
||||
// https://github.com/Ryzee119/ogx360/blob/master/Firmware/src/usbd/usbd_xid.h:195
|
||||
typedef struct XIDSteelBattalionOutputReport {
|
||||
uint8_t report_id;
|
||||
uint8_t length;
|
||||
uint8_t EmergencyEject : 4;
|
||||
uint8_t CockpitHatch : 4;
|
||||
uint8_t Ignition : 4;
|
||||
uint8_t Start : 4;
|
||||
uint8_t OpenClose : 4;
|
||||
uint8_t MapZoomInOut : 4;
|
||||
uint8_t ModeSelect : 4;
|
||||
uint8_t SubMonitorModeSelect : 4;
|
||||
uint8_t MainMonitorZoomIn : 4;
|
||||
uint8_t MainMonitorZoomOut : 4;
|
||||
uint8_t ForecastShootingSystem : 4;
|
||||
uint8_t Manipulator : 4;
|
||||
uint8_t LineColorChange : 4;
|
||||
uint8_t Washing : 4;
|
||||
uint8_t Extinguisher : 4;
|
||||
uint8_t Chaff : 4;
|
||||
uint8_t TankDetach : 4;
|
||||
uint8_t Override : 4;
|
||||
uint8_t NightScope : 4;
|
||||
uint8_t F1 : 4;
|
||||
uint8_t F2 : 4;
|
||||
uint8_t F3 : 4;
|
||||
uint8_t MainWeaponControl : 4;
|
||||
uint8_t SubWeaponControl : 4;
|
||||
uint8_t MagazineChange : 4;
|
||||
uint8_t Comm1 : 4;
|
||||
uint8_t Comm2 : 4;
|
||||
uint8_t Comm3 : 4;
|
||||
uint8_t Comm4 : 4;
|
||||
uint8_t Comm5 : 4;
|
||||
uint8_t : 4;
|
||||
uint8_t GearR : 4;
|
||||
uint8_t GearN : 4;
|
||||
uint8_t Gear1 : 4;
|
||||
uint8_t Gear2 : 4;
|
||||
uint8_t Gear3 : 4;
|
||||
uint8_t Gear4 : 4;
|
||||
uint8_t Gear5 : 4;
|
||||
uint8_t not_used;
|
||||
} QEMU_PACKED XIDSteelBattalionOutputReport;
|
||||
|
||||
typedef struct USBXIDSteelBattalionState {
|
||||
USBDevice dev;
|
||||
USBEndpoint *intr;
|
||||
const XIDDesc *xid_desc;
|
||||
XIDSteelBattalionReport in_state;
|
||||
XIDSteelBattalionReport in_state_capabilities;
|
||||
XIDSteelBattalionOutputReport out_state;
|
||||
XIDSteelBattalionOutputReport out_state_capabilities;
|
||||
uint8_t device_index;
|
||||
} USBXIDSteelBattalionState;
|
||||
|
||||
#define USB_XID_SB(obj) \
|
||||
OBJECT_CHECK(USBXIDSteelBattalionState, (obj), TYPE_USB_XID_STEEL_BATTALION)
|
||||
|
||||
static const USBDescIface desc_iface_steel_battalion = {
|
||||
.bInterfaceNumber = 0,
|
||||
.bNumEndpoints = 2,
|
||||
.bInterfaceClass = USB_CLASS_XID,
|
||||
.bInterfaceSubClass = 0x42,
|
||||
.bInterfaceProtocol = 0x00,
|
||||
.eps =
|
||||
(USBDescEndpoint[]){
|
||||
{
|
||||
.bEndpointAddress = USB_DIR_IN | STEEL_BATTALION_IN_ENDPOINT_ID,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = 0x20,
|
||||
.bInterval = 4,
|
||||
},
|
||||
{
|
||||
.bEndpointAddress =
|
||||
USB_DIR_OUT | STEEL_BATTALION_OUT_ENDPOINT_ID,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = 0x20,
|
||||
.bInterval = 4,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static const USBDescDevice desc_device_steel_battalion = {
|
||||
.bcdUSB = 0x0110,
|
||||
.bMaxPacketSize0 = 0x40,
|
||||
.bNumConfigurations = 1,
|
||||
.confs =
|
||||
(USBDescConfig[]){
|
||||
{
|
||||
.bNumInterfaces = 1,
|
||||
.bConfigurationValue = 1,
|
||||
.bmAttributes = USB_CFG_ATT_ONE,
|
||||
.bMaxPower = 50,
|
||||
.nif = 1,
|
||||
.ifs = &desc_iface_steel_battalion,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static const USBDesc desc_xbox_steel_battalion = {
|
||||
.id = {
|
||||
.idVendor = USB_VENDOR_CAPCOM,
|
||||
.idProduct = 0xd000,
|
||||
.bcdDevice = 0x0100,
|
||||
.iManufacturer = STR_MANUFACTURER,
|
||||
.iProduct = STR_PRODUCT,
|
||||
.iSerialNumber = STR_SERIALNUMBER,
|
||||
},
|
||||
.full = &desc_device_steel_battalion,
|
||||
.str = desc_strings,
|
||||
};
|
||||
|
||||
static const XIDDesc desc_xid_steel_battalion = {
|
||||
.bLength = 0x10,
|
||||
.bDescriptorType = USB_DT_XID,
|
||||
.bcdXid = 0x100,
|
||||
.bType = XID_DEVICETYPE_STEEL_BATTALION,
|
||||
.bSubType = XID_DEVICESUBTYPE_GAMEPAD,
|
||||
.bMaxInputReportSize = 26,
|
||||
.bMaxOutputReportSize = 32,
|
||||
.wAlternateProductIds = { 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF },
|
||||
};
|
||||
|
||||
static void update_sbc_input(USBXIDSteelBattalionState *s)
|
||||
{
|
||||
if (xemu_input_get_test_mode()) {
|
||||
// Don't report changes if we are testing the controller while running
|
||||
return;
|
||||
}
|
||||
|
||||
ControllerState *state = xemu_input_get_bound(s->device_index);
|
||||
assert(state);
|
||||
xemu_input_update_controller(state);
|
||||
|
||||
s->in_state.dwButtons = (uint32_t)(state->sbc.buttons & 0xFFFFFFFF);
|
||||
s->in_state.bMoreButtons = (uint8_t)((state->sbc.buttons >> 32) & 0x7F);
|
||||
s->in_state.bMoreButtons |= state->sbc.toggleSwitches;
|
||||
|
||||
s->in_state.sSightChangeX = state->sbc.axis[SBC_AXIS_SIGHT_CHANGE_X];
|
||||
s->in_state.sSightChangeY = state->sbc.axis[SBC_AXIS_SIGHT_CHANGE_Y];
|
||||
s->in_state.bAimingX =
|
||||
(uint8_t)(128 + (state->sbc.axis[SBC_AXIS_AIMING_X] /
|
||||
256)); // Convert from int16_t to uint8_t
|
||||
s->in_state.bAimingY =
|
||||
(uint8_t)(128 + (state->sbc.axis[SBC_AXIS_AIMING_Y] /
|
||||
256)); // Convert from int16_t to uint8_t
|
||||
s->in_state.sRotationLever = state->sbc.axis[SBC_AXIS_ROTATION_LEVER];
|
||||
s->in_state.wLeftPedal = (uint16_t)state->sbc.axis[SBC_AXIS_LEFT_PEDAL];
|
||||
s->in_state.wMiddlePedal = (uint16_t)state->sbc.axis[SBC_AXIS_MIDDLE_PEDAL];
|
||||
s->in_state.wRightPedal = (uint16_t)state->sbc.axis[SBC_AXIS_RIGHT_PEDAL];
|
||||
|
||||
s->in_state.ucGearLever = state->sbc.gearLever;
|
||||
s->in_state.ucTunerDial = state->sbc.tunerDial;
|
||||
}
|
||||
|
||||
static void usb_xid_steel_battalion_handle_control(USBDevice *dev, USBPacket *p,
|
||||
int request, int value,
|
||||
int index, int length,
|
||||
uint8_t *data)
|
||||
{
|
||||
USBXIDSteelBattalionState *s =
|
||||
DO_UPCAST(USBXIDSteelBattalionState, dev, 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);
|
||||
if (ret >= 0) {
|
||||
DPRINTF("xid handled by usb_desc_handle_control: %d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (request) {
|
||||
/* HID requests */
|
||||
case ClassInterfaceRequest | HID_GET_REPORT:
|
||||
DPRINTF("xid GET_REPORT 0x%x\n", value);
|
||||
update_sbc_input(s);
|
||||
if (value == 0x0100) { /* input */
|
||||
if (length <= s->in_state.bLength) {
|
||||
memcpy(data, &s->in_state, s->in_state.bLength);
|
||||
p->actual_length = length;
|
||||
} else {
|
||||
p->status = USB_RET_STALL;
|
||||
}
|
||||
} else {
|
||||
p->status = USB_RET_STALL;
|
||||
assert(false);
|
||||
}
|
||||
break;
|
||||
case ClassInterfaceOutRequest | HID_SET_REPORT:
|
||||
DPRINTF("xid SET_REPORT 0x%x\n", value);
|
||||
if (value == 0x0200) { /* output */
|
||||
/* Read length, then the entire packet */
|
||||
if (length == s->out_state.length) {
|
||||
memcpy(&s->out_state, data, sizeof(s->out_state));
|
||||
|
||||
/* FIXME: This should also be a STALL */
|
||||
assert(s->out_state.length == sizeof(s->out_state));
|
||||
|
||||
p->actual_length = length;
|
||||
} else {
|
||||
p->status = USB_RET_STALL;
|
||||
}
|
||||
// update_output(s);
|
||||
} else {
|
||||
p->status = USB_RET_STALL;
|
||||
assert(false);
|
||||
}
|
||||
break;
|
||||
/* XID requests */
|
||||
case VendorInterfaceRequest | USB_REQ_GET_DESCRIPTOR:
|
||||
DPRINTF("xid GET_DESCRIPTOR 0x%x\n", value);
|
||||
if (value == 0x4200) {
|
||||
assert(s->xid_desc->bLength <= length);
|
||||
memcpy(data, s->xid_desc, s->xid_desc->bLength);
|
||||
p->actual_length = s->xid_desc->bLength;
|
||||
} else {
|
||||
p->status = USB_RET_STALL;
|
||||
assert(false);
|
||||
}
|
||||
break;
|
||||
case VendorInterfaceRequest | XID_GET_CAPABILITIES:
|
||||
DPRINTF("xid XID_GET_CAPABILITIES 0x%x\n", value);
|
||||
if (value == 0x0100) {
|
||||
if (length > s->in_state_capabilities.bLength) {
|
||||
length = s->in_state_capabilities.bLength;
|
||||
}
|
||||
memcpy(data, &s->in_state_capabilities, length);
|
||||
p->actual_length = length;
|
||||
} else if (value == 0x0200) {
|
||||
if (length > s->out_state_capabilities.length) {
|
||||
length = s->out_state_capabilities.length;
|
||||
}
|
||||
memcpy(data, &s->out_state_capabilities, length);
|
||||
p->actual_length = length;
|
||||
} else {
|
||||
p->status = USB_RET_STALL;
|
||||
assert(false);
|
||||
}
|
||||
break;
|
||||
case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE) << 8) |
|
||||
USB_REQ_GET_DESCRIPTOR:
|
||||
/* FIXME: ! */
|
||||
DPRINTF("xid unknown xpad request 0x%x: value = 0x%x\n", request,
|
||||
value);
|
||||
memset(data, 0x00, length);
|
||||
// FIXME: Intended for the hub: usbd_get_hub_descriptor, UT_READ_CLASS?!
|
||||
p->status = USB_RET_STALL;
|
||||
// assert(false);
|
||||
break;
|
||||
case ((USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_ENDPOINT) << 8) |
|
||||
USB_REQ_CLEAR_FEATURE:
|
||||
/* FIXME: ! */
|
||||
DPRINTF("xid unknown xpad request 0x%x: value = 0x%x\n", request,
|
||||
value);
|
||||
memset(data, 0x00, length);
|
||||
p->status = USB_RET_STALL;
|
||||
break;
|
||||
default:
|
||||
DPRINTF("xid USB stalled on request 0x%x value 0x%x\n", request, value);
|
||||
p->status = USB_RET_STALL;
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void usb_xid_steel_battalion_handle_data(USBDevice *dev, USBPacket *p)
|
||||
{
|
||||
USBXIDSteelBattalionState *s =
|
||||
DO_UPCAST(USBXIDSteelBattalionState, dev, dev);
|
||||
|
||||
DPRINTF("xid handle_steel_battalion_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 == STEEL_BATTALION_IN_ENDPOINT_ID) {
|
||||
update_sbc_input(s);
|
||||
usb_packet_copy(p, &s->in_state, s->in_state.bLength);
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
break;
|
||||
case USB_TOKEN_OUT:
|
||||
if (p->ep->nr == STEEL_BATTALION_OUT_ENDPOINT_ID) {
|
||||
usb_packet_copy(p, &s->out_state, s->out_state.length);
|
||||
// TODO: Update output for Steel Battalion Controller here, if we
|
||||
// want to. It's LED data, so, maybe use it for RGB integration with
|
||||
// RGB Keyboards?
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
p->status = USB_RET_STALL;
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void usb_xid_steel_battalion_class_initfn(ObjectClass *klass, void *data)
|
||||
{
|
||||
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
|
||||
|
||||
uc->handle_reset = usb_xid_handle_reset;
|
||||
uc->handle_control = usb_xid_steel_battalion_handle_control;
|
||||
uc->handle_data = usb_xid_steel_battalion_handle_data;
|
||||
// uc->handle_destroy = usb_xid_handle_destroy;
|
||||
uc->handle_attach = usb_desc_attach;
|
||||
}
|
||||
|
||||
static void usb_steel_battalion_realize(USBDevice *dev, Error **errp)
|
||||
{
|
||||
USBXIDSteelBattalionState *s = USB_XID_SB(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_steel_battalion;
|
||||
|
||||
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", USBXIDSteelBattalionState, device_index, 0),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_usb_sb = {
|
||||
.name = TYPE_USB_XID_STEEL_BATTALION,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields =
|
||||
(VMStateField[]){ VMSTATE_USB_DEVICE(dev, USBXIDSteelBattalionState),
|
||||
// FIXME
|
||||
VMSTATE_END_OF_LIST() },
|
||||
};
|
||||
|
||||
static void usb_steel_battalion_class_initfn(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
|
||||
|
||||
uc->product_desc = "Steel Battalion Controller";
|
||||
uc->usb_desc = &desc_xbox_steel_battalion;
|
||||
uc->realize = usb_steel_battalion_realize;
|
||||
uc->unrealize = usb_xbox_gamepad_unrealize;
|
||||
usb_xid_steel_battalion_class_initfn(klass, data);
|
||||
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
|
||||
dc->vmsd = &vmstate_usb_sb;
|
||||
device_class_set_props(dc, xid_properties);
|
||||
dc->desc = "Steel Battalion Controller";
|
||||
}
|
||||
|
||||
static const TypeInfo usb_steel_battalion_info = {
|
||||
.name = TYPE_USB_XID_STEEL_BATTALION,
|
||||
.parent = TYPE_USB_DEVICE,
|
||||
.instance_size = sizeof(USBXIDSteelBattalionState),
|
||||
.class_init = usb_steel_battalion_class_initfn,
|
||||
};
|
||||
|
||||
static void usb_xid_register_types(void)
|
||||
{
|
||||
type_register_static(&usb_steel_battalion_info);
|
||||
}
|
||||
|
||||
type_init(usb_xid_register_types)
|
|
@ -47,8 +47,8 @@ void update_output(USBXIDGamepadState *s)
|
|||
|
||||
ControllerState *state = xemu_input_get_bound(s->device_index);
|
||||
assert(state);
|
||||
state->rumble_l = s->out_state.left_actuator_strength;
|
||||
state->rumble_r = s->out_state.right_actuator_strength;
|
||||
state->gp.rumble_l = s->out_state.left_actuator_strength;
|
||||
state->gp.rumble_r = s->out_state.right_actuator_strength;
|
||||
xemu_input_update_rumble(state);
|
||||
}
|
||||
|
||||
|
@ -84,23 +84,23 @@ void update_input(USBXIDGamepadState *s)
|
|||
};
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
int pressed = state->buttons & button_map_analog[i][1];
|
||||
int pressed = state->gp.buttons & button_map_analog[i][1];
|
||||
s->in_state.bAnalogButtons[button_map_analog[i][0]] = pressed ? 0xff : 0;
|
||||
}
|
||||
|
||||
s->in_state.wButtons = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (state->buttons & button_map_binary[i][1]) {
|
||||
if (state->gp.buttons & button_map_binary[i][1]) {
|
||||
s->in_state.wButtons |= BUTTON_MASK(button_map_binary[i][0]);
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
s->in_state.sThumbRY = state->axis[CONTROLLER_AXIS_RSTICK_Y];
|
||||
s->in_state.bAnalogButtons[GAMEPAD_LEFT_TRIGGER] = state->gp.axis[CONTROLLER_AXIS_LTRIG] >> 7;
|
||||
s->in_state.bAnalogButtons[GAMEPAD_RIGHT_TRIGGER] = state->gp.axis[CONTROLLER_AXIS_RTRIG] >> 7;
|
||||
s->in_state.sThumbLX = state->gp.axis[CONTROLLER_AXIS_LSTICK_X];
|
||||
s->in_state.sThumbLY = state->gp.axis[CONTROLLER_AXIS_LSTICK_Y];
|
||||
s->in_state.sThumbRX = state->gp.axis[CONTROLLER_AXIS_RSTICK_X];
|
||||
s->in_state.sThumbRY = state->gp.axis[CONTROLLER_AXIS_RSTICK_Y];
|
||||
}
|
||||
|
||||
void usb_xid_handle_reset(USBDevice *dev)
|
||||
|
|
|
@ -48,12 +48,17 @@
|
|||
#define XID_GET_CAPABILITIES 0x01
|
||||
|
||||
#define XID_DEVICETYPE_GAMEPAD 0x01
|
||||
#define XID_DEVICETYPE_DVD_PLAYBACK_KIT 0x03
|
||||
#define XID_DEVICETYPE_STEEL_BATTALION 0x80
|
||||
|
||||
#define XID_DEVICESUBTYPE_DVD_PLAYBACK_KIT 0x00
|
||||
#define XID_DEVICESUBTYPE_GAMEPAD 0x01
|
||||
#define XID_DEVICESUBTYPE_GAMEPAD_S 0x02
|
||||
|
||||
#define TYPE_USB_XID_GAMEPAD "usb-xbox-gamepad"
|
||||
#define TYPE_USB_XID_GAMEPAD_S "usb-xbox-gamepad-s"
|
||||
#define TYPE_USB_XID_STEEL_BATTALION "usb-steel-battalion"
|
||||
#define TYPE_USB_XBOX_DVD_PLAYBACK_KIT "xbox-dvd-playback-kit"
|
||||
|
||||
#define GAMEPAD_A 0
|
||||
#define GAMEPAD_B 1
|
||||
|
|
663
ui/xemu-input.c
663
ui/xemu-input.c
|
@ -34,6 +34,9 @@
|
|||
|
||||
#include "sysemu/blockdev.h"
|
||||
|
||||
extern SDL_Window *m_window;
|
||||
extern int viewport_coords[4];
|
||||
|
||||
// #define DEBUG_INPUT
|
||||
|
||||
#ifdef DEBUG_INPUT
|
||||
|
@ -58,33 +61,34 @@ static void xemu_input_print_controller_state(ControllerState *state)
|
|||
"LTrig = %.3f, RTrig = %.3f\n"
|
||||
"LStickX = %.3f, RStickX = %.3f\n"
|
||||
"LStickY = %.3f, RStickY = %.3f\n\n",
|
||||
!!(state->buttons & CONTROLLER_BUTTON_A),
|
||||
!!(state->buttons & CONTROLLER_BUTTON_B),
|
||||
!!(state->buttons & CONTROLLER_BUTTON_X),
|
||||
!!(state->buttons & CONTROLLER_BUTTON_Y),
|
||||
!!(state->buttons & CONTROLLER_BUTTON_DPAD_LEFT),
|
||||
!!(state->buttons & CONTROLLER_BUTTON_DPAD_UP),
|
||||
!!(state->buttons & CONTROLLER_BUTTON_DPAD_RIGHT),
|
||||
!!(state->buttons & CONTROLLER_BUTTON_DPAD_DOWN),
|
||||
!!(state->buttons & CONTROLLER_BUTTON_BACK),
|
||||
!!(state->buttons & CONTROLLER_BUTTON_START),
|
||||
!!(state->buttons & CONTROLLER_BUTTON_WHITE),
|
||||
!!(state->buttons & CONTROLLER_BUTTON_BLACK),
|
||||
!!(state->buttons & CONTROLLER_BUTTON_LSTICK),
|
||||
!!(state->buttons & CONTROLLER_BUTTON_RSTICK),
|
||||
!!(state->buttons & CONTROLLER_BUTTON_GUIDE),
|
||||
state->axis[CONTROLLER_AXIS_LTRIG],
|
||||
state->axis[CONTROLLER_AXIS_RTRIG],
|
||||
state->axis[CONTROLLER_AXIS_LSTICK_X],
|
||||
state->axis[CONTROLLER_AXIS_RSTICK_X],
|
||||
state->axis[CONTROLLER_AXIS_LSTICK_Y],
|
||||
state->axis[CONTROLLER_AXIS_RSTICK_Y]
|
||||
!!(state->gp.buttons & CONTROLLER_BUTTON_A),
|
||||
!!(state->gp.buttons & CONTROLLER_BUTTON_B),
|
||||
!!(state->gp.buttons & CONTROLLER_BUTTON_X),
|
||||
!!(state->gp.buttons & CONTROLLER_BUTTON_Y),
|
||||
!!(state->gp.buttons & CONTROLLER_BUTTON_DPAD_LEFT),
|
||||
!!(state->gp.buttons & CONTROLLER_BUTTON_DPAD_UP),
|
||||
!!(state->gp.buttons & CONTROLLER_BUTTON_DPAD_RIGHT),
|
||||
!!(state->gp.buttons & CONTROLLER_BUTTON_DPAD_DOWN),
|
||||
!!(state->gp.buttons & CONTROLLER_BUTTON_BACK),
|
||||
!!(state->gp.buttons & CONTROLLER_BUTTON_START),
|
||||
!!(state->gp.buttons & CONTROLLER_BUTTON_WHITE),
|
||||
!!(state->gp.buttons & CONTROLLER_BUTTON_BLACK),
|
||||
!!(state->gp.buttons & CONTROLLER_BUTTON_LSTICK),
|
||||
!!(state->gp.buttons & CONTROLLER_BUTTON_RSTICK),
|
||||
!!(state->gp.buttons & CONTROLLER_BUTTON_GUIDE),
|
||||
state->gp.axis[CONTROLLER_AXIS_LTRIG],
|
||||
state->gp.axis[CONTROLLER_AXIS_RTRIG],
|
||||
state->gp.axis[CONTROLLER_AXIS_LSTICK_X],
|
||||
state->gp.axis[CONTROLLER_AXIS_RSTICK_X],
|
||||
state->gp.axis[CONTROLLER_AXIS_LSTICK_Y],
|
||||
state->gp.axis[CONTROLLER_AXIS_RSTICK_Y]
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
ControllerStateList available_controllers =
|
||||
QTAILQ_HEAD_INITIALIZER(available_controllers);
|
||||
|
||||
ControllerState *bound_controllers[4] = { NULL, NULL, NULL, NULL };
|
||||
const char *bound_drivers[4] = { DRIVER_DUKE, DRIVER_DUKE, DRIVER_DUKE,
|
||||
DRIVER_DUKE };
|
||||
|
@ -100,10 +104,17 @@ static const char **port_index_to_settings_key_map[] = {
|
|||
static const char **port_index_to_driver_settings_key_map[] = {
|
||||
&g_config.input.bindings.port1_driver,
|
||||
&g_config.input.bindings.port2_driver,
|
||||
&g_config.input.bindings.port3_driver,
|
||||
&g_config.input.bindings.port3_driver,
|
||||
&g_config.input.bindings.port4_driver
|
||||
};
|
||||
|
||||
static const char **port_index_to_dvd_firmware_key_map[] = {
|
||||
&g_config.input.bindings.port1_dvd_firmware,
|
||||
&g_config.input.bindings.port2_dvd_firmware,
|
||||
&g_config.input.bindings.port3_dvd_firmware,
|
||||
&g_config.input.bindings.port4_dvd_firmware,
|
||||
};
|
||||
|
||||
static int *peripheral_types_settings_map[4][2] = {
|
||||
{ &g_config.input.peripherals.port1.peripheral_type_0,
|
||||
&g_config.input.peripherals.port1.peripheral_type_1 },
|
||||
|
@ -127,6 +138,8 @@ static const char **peripheral_params_settings_map[4][2] = {
|
|||
};
|
||||
|
||||
static int sdl_kbd_scancode_map[25];
|
||||
static int sdl_sbc_kbd_scancode_map[52];
|
||||
static int sdl_dvd_kit_kbd_scancode_map[44];
|
||||
|
||||
static const char *get_bound_driver(int port)
|
||||
{
|
||||
|
@ -136,13 +149,17 @@ static const char *get_bound_driver(int port)
|
|||
// If the driver in the config is NULL, empty, or unrecognized
|
||||
// then default to DRIVER_DUKE
|
||||
if (driver == NULL)
|
||||
return DRIVER_DUKE;
|
||||
return DRIVER_DUKE;
|
||||
if (strlen(driver) == 0)
|
||||
return DRIVER_DUKE;
|
||||
if (strcmp(driver, DRIVER_DUKE) == 0)
|
||||
return DRIVER_DUKE;
|
||||
if (strcmp(driver, DRIVER_S) == 0)
|
||||
return DRIVER_S;
|
||||
if (strcmp(driver, DRIVER_STEEL_BATTALION) == 0)
|
||||
return DRIVER_STEEL_BATTALION;
|
||||
if (strcmp(driver, DRIVER_DVD_PLAYBACK_KIT) == 0)
|
||||
return DRIVER_DVD_PLAYBACK_KIT;
|
||||
|
||||
return DRIVER_DUKE;
|
||||
}
|
||||
|
@ -204,6 +221,163 @@ void xemu_input_init(void)
|
|||
sdl_kbd_scancode_map[i] = SDL_SCANCODE_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
sdl_sbc_kbd_scancode_map[3] =
|
||||
g_config.input.keyboard_sbc_scancode_map.eject;
|
||||
sdl_sbc_kbd_scancode_map[4] =
|
||||
g_config.input.keyboard_sbc_scancode_map.cockpit_hatch;
|
||||
sdl_sbc_kbd_scancode_map[5] =
|
||||
g_config.input.keyboard_sbc_scancode_map.ignition;
|
||||
sdl_sbc_kbd_scancode_map[6] =
|
||||
g_config.input.keyboard_sbc_scancode_map.start;
|
||||
sdl_sbc_kbd_scancode_map[7] =
|
||||
g_config.input.keyboard_sbc_scancode_map.open_close;
|
||||
sdl_sbc_kbd_scancode_map[8] =
|
||||
g_config.input.keyboard_sbc_scancode_map.map_zoom_in_out;
|
||||
sdl_sbc_kbd_scancode_map[9] =
|
||||
g_config.input.keyboard_sbc_scancode_map.mode_select;
|
||||
sdl_sbc_kbd_scancode_map[10] =
|
||||
g_config.input.keyboard_sbc_scancode_map.sub_monitor_mode_select;
|
||||
sdl_sbc_kbd_scancode_map[11] =
|
||||
g_config.input.keyboard_sbc_scancode_map.zoom_in;
|
||||
sdl_sbc_kbd_scancode_map[12] =
|
||||
g_config.input.keyboard_sbc_scancode_map.zoom_out;
|
||||
sdl_sbc_kbd_scancode_map[13] = g_config.input.keyboard_sbc_scancode_map.fss;
|
||||
sdl_sbc_kbd_scancode_map[14] =
|
||||
g_config.input.keyboard_sbc_scancode_map.manipulator;
|
||||
sdl_sbc_kbd_scancode_map[15] =
|
||||
g_config.input.keyboard_sbc_scancode_map.line_color_change;
|
||||
sdl_sbc_kbd_scancode_map[16] =
|
||||
g_config.input.keyboard_sbc_scancode_map.washing;
|
||||
sdl_sbc_kbd_scancode_map[17] =
|
||||
g_config.input.keyboard_sbc_scancode_map.extinguisher;
|
||||
sdl_sbc_kbd_scancode_map[18] =
|
||||
g_config.input.keyboard_sbc_scancode_map.chaff;
|
||||
sdl_sbc_kbd_scancode_map[19] =
|
||||
g_config.input.keyboard_sbc_scancode_map.tank_detach;
|
||||
sdl_sbc_kbd_scancode_map[20] =
|
||||
g_config.input.keyboard_sbc_scancode_map.override;
|
||||
sdl_sbc_kbd_scancode_map[21] =
|
||||
g_config.input.keyboard_sbc_scancode_map.night_scope;
|
||||
sdl_sbc_kbd_scancode_map[22] =
|
||||
g_config.input.keyboard_sbc_scancode_map.func1;
|
||||
sdl_sbc_kbd_scancode_map[23] =
|
||||
g_config.input.keyboard_sbc_scancode_map.func2;
|
||||
sdl_sbc_kbd_scancode_map[24] =
|
||||
g_config.input.keyboard_sbc_scancode_map.func3;
|
||||
sdl_sbc_kbd_scancode_map[25] =
|
||||
g_config.input.keyboard_sbc_scancode_map.main_weapon_control;
|
||||
sdl_sbc_kbd_scancode_map[26] =
|
||||
g_config.input.keyboard_sbc_scancode_map.sub_weapon_control;
|
||||
sdl_sbc_kbd_scancode_map[27] =
|
||||
g_config.input.keyboard_sbc_scancode_map.magazine_change;
|
||||
sdl_sbc_kbd_scancode_map[28] =
|
||||
g_config.input.keyboard_sbc_scancode_map.com1;
|
||||
sdl_sbc_kbd_scancode_map[29] =
|
||||
g_config.input.keyboard_sbc_scancode_map.com2;
|
||||
sdl_sbc_kbd_scancode_map[30] =
|
||||
g_config.input.keyboard_sbc_scancode_map.com3;
|
||||
sdl_sbc_kbd_scancode_map[31] =
|
||||
g_config.input.keyboard_sbc_scancode_map.com4;
|
||||
sdl_sbc_kbd_scancode_map[32] =
|
||||
g_config.input.keyboard_sbc_scancode_map.com5;
|
||||
sdl_sbc_kbd_scancode_map[33] =
|
||||
g_config.input.keyboard_sbc_scancode_map.sight_change;
|
||||
sdl_sbc_kbd_scancode_map[34] =
|
||||
g_config.input.keyboard_sbc_scancode_map.filt_control_system;
|
||||
sdl_sbc_kbd_scancode_map[35] =
|
||||
g_config.input.keyboard_sbc_scancode_map.oxygen_supply_system;
|
||||
sdl_sbc_kbd_scancode_map[36] =
|
||||
g_config.input.keyboard_sbc_scancode_map.fuel_flow_rate;
|
||||
sdl_sbc_kbd_scancode_map[37] =
|
||||
g_config.input.keyboard_sbc_scancode_map.buffer_material;
|
||||
sdl_sbc_kbd_scancode_map[38] =
|
||||
g_config.input.keyboard_sbc_scancode_map.vt_location_measurement;
|
||||
sdl_sbc_kbd_scancode_map[39] =
|
||||
g_config.input.keyboard_sbc_scancode_map.gear_up;
|
||||
sdl_sbc_kbd_scancode_map[40] =
|
||||
g_config.input.keyboard_sbc_scancode_map.gear_down;
|
||||
sdl_sbc_kbd_scancode_map[41] =
|
||||
g_config.input.keyboard_sbc_scancode_map.tuner_left;
|
||||
sdl_sbc_kbd_scancode_map[42] =
|
||||
g_config.input.keyboard_sbc_scancode_map.tuner_right;
|
||||
sdl_sbc_kbd_scancode_map[43] =
|
||||
g_config.input.keyboard_sbc_scancode_map.sight_change_up;
|
||||
sdl_sbc_kbd_scancode_map[44] =
|
||||
g_config.input.keyboard_sbc_scancode_map.sight_change_down;
|
||||
sdl_sbc_kbd_scancode_map[45] =
|
||||
g_config.input.keyboard_sbc_scancode_map.sight_change_left;
|
||||
sdl_sbc_kbd_scancode_map[46] =
|
||||
g_config.input.keyboard_sbc_scancode_map.sight_change_right;
|
||||
sdl_sbc_kbd_scancode_map[47] =
|
||||
g_config.input.keyboard_sbc_scancode_map.rotation_left;
|
||||
sdl_sbc_kbd_scancode_map[48] =
|
||||
g_config.input.keyboard_sbc_scancode_map.rotation_right;
|
||||
sdl_sbc_kbd_scancode_map[49] =
|
||||
g_config.input.keyboard_sbc_scancode_map.left_pedal;
|
||||
sdl_sbc_kbd_scancode_map[50] =
|
||||
g_config.input.keyboard_sbc_scancode_map.right_pedal;
|
||||
sdl_sbc_kbd_scancode_map[51] =
|
||||
g_config.input.keyboard_sbc_scancode_map.middle_pedal;
|
||||
|
||||
for (int i = 0; i < 49; i++) {
|
||||
if ((sdl_sbc_kbd_scancode_map[i] < SDL_SCANCODE_UNKNOWN) ||
|
||||
(sdl_sbc_kbd_scancode_map[i] >= SDL_NUM_SCANCODES)) {
|
||||
fprintf(stderr,
|
||||
"WARNING: Keyboard steel battalion controller map scancode "
|
||||
"out of range (%d) : Disabled\n",
|
||||
sdl_sbc_kbd_scancode_map[i]);
|
||||
sdl_sbc_kbd_scancode_map[i] = SDL_SCANCODE_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
int i = 0;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.up;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.left;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.select;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.right;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.down;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.display;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.reverse;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.play;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.forward;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.skip_down;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.stop;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.pause;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.skip_up;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.title;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.info;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.menu;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.back;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.button1;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.button2;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.button3;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.button4;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.button5;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.button6;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.button7;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.button8;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.button9;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.button0;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.power;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.my_tv;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.my_music;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.my_pictures;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.my_videos;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.record;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.start;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.volume_up;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.volume_down;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.mute;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.channel_up;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.channel_down;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.recorded_tv;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.live_tv;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.star;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.pound;
|
||||
sdl_dvd_kit_kbd_scancode_map[i++] = g_config.input.keyboard_dvd_kit_scancode_map.clear;
|
||||
}
|
||||
|
||||
bound_drivers[0] = get_bound_driver(0);
|
||||
bound_drivers[1] = get_bound_driver(1);
|
||||
|
@ -259,6 +433,14 @@ void xemu_save_peripheral_settings(int player_index, int peripheral_index,
|
|||
peripheral_parameter == NULL ? "" : peripheral_parameter);
|
||||
}
|
||||
|
||||
void xemu_save_dvd_firmware_settings(int player_index, const char *firmware)
|
||||
{
|
||||
ControllerState *state = bound_controllers[player_index];
|
||||
state->dvdKit.firmware = g_strdup(firmware);
|
||||
xemu_settings_set_string(port_index_to_dvd_firmware_key_map[player_index],
|
||||
firmware);
|
||||
}
|
||||
|
||||
void xemu_input_process_sdl_events(const SDL_Event *event)
|
||||
{
|
||||
if (event->type == SDL_CONTROLLERDEVICEADDED) {
|
||||
|
@ -277,7 +459,7 @@ void xemu_input_process_sdl_events(const SDL_Event *event)
|
|||
memset(new_con, 0, sizeof(ControllerState));
|
||||
new_con->type = INPUT_DEVICE_SDL_GAMECONTROLLER;
|
||||
new_con->name = SDL_GameControllerName(sdl_con);
|
||||
new_con->rumble_enabled = true;
|
||||
new_con->gp.rumble_enabled = true;
|
||||
new_con->sdl_gamecontroller = sdl_con;
|
||||
new_con->sdl_joystick = SDL_GameControllerGetJoystick(new_con->sdl_gamecontroller);
|
||||
new_con->sdl_joystick_id = SDL_JoystickInstanceID(new_con->sdl_joystick);
|
||||
|
@ -287,6 +469,7 @@ void xemu_input_process_sdl_events(const SDL_Event *event)
|
|||
new_con->peripheral_types[1] = PERIPHERAL_NONE;
|
||||
new_con->peripherals[0] = NULL;
|
||||
new_con->peripherals[1] = NULL;
|
||||
new_con->dvdKit.firmware = NULL;
|
||||
|
||||
char guid_buf[35] = { 0 };
|
||||
SDL_JoystickGetGUIDString(new_con->sdl_joystick_guid, guid_buf, sizeof(guid_buf));
|
||||
|
@ -422,75 +605,345 @@ void xemu_input_update_controllers(void)
|
|||
|
||||
void xemu_input_update_sdl_kbd_controller_state(ControllerState *state)
|
||||
{
|
||||
state->buttons = 0;
|
||||
memset(state->axis, 0, sizeof(state->axis));
|
||||
state->gp.buttons = 0;
|
||||
state->sbc.buttons = 0;
|
||||
state->dvdKit.buttons = 0;
|
||||
memset(state->gp.axis, 0, sizeof(state->gp.axis));
|
||||
memset(state->sbc.axis, 0, sizeof(state->sbc.axis));
|
||||
|
||||
const uint8_t *kbd = SDL_GetKeyboardState(NULL);
|
||||
|
||||
for (int i = 0; i < 15; i++) {
|
||||
state->buttons |= kbd[sdl_kbd_scancode_map[i]] << i;
|
||||
if (state->bound < 0)
|
||||
return;
|
||||
|
||||
const char *bound_driver = get_bound_driver(state->bound);
|
||||
if (strcmp(bound_driver, DRIVER_STEEL_BATTALION) == 0) {
|
||||
state->sbc.buttons = 0;
|
||||
|
||||
if (state->sbc.gearLever == 0)
|
||||
state->sbc.gearLever = 255;
|
||||
|
||||
// Update SBC Buttons
|
||||
for (int i = 3; i < 43; i++) {
|
||||
if (kbd[sdl_sbc_kbd_scancode_map[i]])
|
||||
state->sbc.buttons |= (1ULL << i);
|
||||
}
|
||||
|
||||
const uint64_t toggles[5] = { SBC_BUTTON_FILT_CONTROL_SYSTEM,
|
||||
SBC_BUTTON_OXYGEN_SUPPLY_SYSTEM,
|
||||
SBC_BUTTON_FUEL_FLOW_RATE,
|
||||
SBC_BUTTON_BUFFER_MATERIAL,
|
||||
SBC_BUTTON_VT_LOCATION_MEASUREMENT };
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
if ((state->sbc.buttons & toggles[i]) &&
|
||||
!(state->sbc.previousButtons &
|
||||
toggles[i])) { // When the for the toggle is pressed
|
||||
uint8_t byteMask = (uint8_t)(toggles[i] >> 32);
|
||||
// Toggle the toggle switch
|
||||
state->sbc.toggleSwitches ^= byteMask;
|
||||
}
|
||||
}
|
||||
|
||||
// Tuner Dial Left
|
||||
if ((state->sbc.buttons & SBC_BUTTON_TUNER_LEFT) &&
|
||||
!(state->sbc.previousButtons & SBC_BUTTON_TUNER_LEFT)) {
|
||||
if (state->sbc.tunerDial == 0)
|
||||
state->sbc.tunerDial = 15;
|
||||
else
|
||||
state->sbc.tunerDial--;
|
||||
}
|
||||
|
||||
// Tuner Dial Right
|
||||
if ((state->sbc.buttons & SBC_BUTTON_TUNER_RIGHT) &&
|
||||
!(state->sbc.previousButtons & SBC_BUTTON_TUNER_RIGHT)) {
|
||||
if (state->sbc.tunerDial == 15)
|
||||
state->sbc.tunerDial = 0;
|
||||
else
|
||||
state->sbc.tunerDial++;
|
||||
}
|
||||
|
||||
// Gear Lever Up
|
||||
if ((state->sbc.buttons & SBC_BUTTON_GEAR_UP) &&
|
||||
!(state->sbc.previousButtons & SBC_BUTTON_GEAR_UP)) {
|
||||
if (state->sbc.gearLever != 5) {
|
||||
if (state->sbc.gearLever == 255)
|
||||
state->sbc.gearLever = 1;
|
||||
else
|
||||
state->sbc.gearLever++;
|
||||
}
|
||||
}
|
||||
|
||||
// Gear Lever Down
|
||||
if ((state->sbc.buttons & SBC_BUTTON_GEAR_DOWN) &&
|
||||
!(state->sbc.previousButtons & SBC_BUTTON_GEAR_DOWN)) {
|
||||
if (state->sbc.gearLever != 254) {
|
||||
if (state->sbc.gearLever == 1)
|
||||
state->sbc.gearLever = 255;
|
||||
else
|
||||
state->sbc.gearLever--;
|
||||
}
|
||||
}
|
||||
|
||||
// Update SBC Axes
|
||||
int mouseX, mouseY;
|
||||
uint32_t mouseBtn = SDL_GetMouseState(&mouseX, &mouseY);
|
||||
|
||||
if (mouseBtn & SDL_BUTTON(SDL_BUTTON_LEFT)) {
|
||||
state->sbc.buttons |= SBC_BUTTON_MAIN_WEAPON;
|
||||
}
|
||||
if (mouseBtn & SDL_BUTTON(SDL_BUTTON_RIGHT)) {
|
||||
state->sbc.buttons |= SBC_BUTTON_LOCK_ON;
|
||||
}
|
||||
if(mouseBtn & SDL_BUTTON(SDL_BUTTON_X1) ||
|
||||
mouseBtn & SDL_BUTTON(SDL_BUTTON_X2)) {
|
||||
state->sbc.buttons |= SBC_BUTTON_SUB_WEAPON;
|
||||
}
|
||||
|
||||
int32_t windowWidth, windowHeight;
|
||||
SDL_GL_GetDrawableSize(
|
||||
m_window, &windowWidth,
|
||||
&windowHeight); // get the mouse location relative to the Viewport,
|
||||
// not the Window
|
||||
|
||||
// Calculate the position of the mouse coordinates in [-32768,32768]
|
||||
DPRINTF("[Steel Battalion] Window Coordinates: %d, %d\n", mouseX, mouseY);
|
||||
|
||||
// Check that the mouse position is within the window coordinates
|
||||
if (mouseX >= 0 && mouseX <= windowWidth && mouseY >= 0 &&
|
||||
mouseY <= windowHeight) {
|
||||
if (viewport_coords[2] > 0 && viewport_coords[3] > 0) {
|
||||
// Switch from Window coordinates to Viewport Coordinates
|
||||
mouseX -= viewport_coords[0];
|
||||
mouseY -= viewport_coords[1];
|
||||
windowWidth = viewport_coords[2];
|
||||
windowHeight = viewport_coords[3];
|
||||
}
|
||||
|
||||
DPRINTF("[Steel Battalion] Viewport Coordinates: %d, %d\n", mouseX, mouseY);
|
||||
int32_t x = (int32_t)((mouseX - (windowWidth / 2)) *
|
||||
65535 / windowWidth);
|
||||
int32_t y = (int32_t)((mouseY - (windowHeight / 2)) *
|
||||
65535 / windowHeight);
|
||||
|
||||
state->sbc.axis[SBC_AXIS_AIMING_X] =
|
||||
(int16_t)MIN(MAX(x, -32768), 32767);
|
||||
state->sbc.axis[SBC_AXIS_AIMING_Y] =
|
||||
(int16_t)MIN(MAX(y, -32768), 32767);
|
||||
|
||||
DPRINTF("[Steel Battalion] X: %d, Y: %d",
|
||||
state->sbc.axis[SBC_AXIS_AIMING_X],
|
||||
state->sbc.axis[SBC_AXIS_AIMING_Y]);
|
||||
}
|
||||
|
||||
if (kbd[sdl_sbc_kbd_scancode_map[43]])
|
||||
state->sbc.axis[SBC_AXIS_SIGHT_CHANGE_Y] = -32768;
|
||||
if (kbd[sdl_sbc_kbd_scancode_map[44]])
|
||||
state->sbc.axis[SBC_AXIS_SIGHT_CHANGE_Y] = 32767;
|
||||
if (kbd[sdl_sbc_kbd_scancode_map[45]])
|
||||
state->sbc.axis[SBC_AXIS_SIGHT_CHANGE_X] = -32768;
|
||||
if (kbd[sdl_sbc_kbd_scancode_map[46]])
|
||||
state->sbc.axis[SBC_AXIS_SIGHT_CHANGE_X] = 32767;
|
||||
|
||||
if (kbd[sdl_sbc_kbd_scancode_map[47]])
|
||||
state->sbc.axis[SBC_AXIS_ROTATION_LEVER] = -32768;
|
||||
if (kbd[sdl_sbc_kbd_scancode_map[48]])
|
||||
state->sbc.axis[SBC_AXIS_ROTATION_LEVER] = 32767;
|
||||
|
||||
if (kbd[sdl_sbc_kbd_scancode_map[49]])
|
||||
state->sbc.axis[SBC_AXIS_LEFT_PEDAL] = 32767;
|
||||
if (kbd[sdl_sbc_kbd_scancode_map[50]])
|
||||
state->sbc.axis[SBC_AXIS_RIGHT_PEDAL] = 32767;
|
||||
if (kbd[sdl_sbc_kbd_scancode_map[51]])
|
||||
state->sbc.axis[SBC_AXIS_MIDDLE_PEDAL] = 32767;
|
||||
|
||||
state->sbc.previousButtons = state->sbc.buttons;
|
||||
} else if (strcmp(bound_driver, DRIVER_DVD_PLAYBACK_KIT) == 0) {
|
||||
for (int i = 0; i < 44; i++) {
|
||||
state->dvdKit.buttons |= (unsigned long long)kbd[sdl_dvd_kit_kbd_scancode_map[i]] << i;
|
||||
}
|
||||
} else {
|
||||
// Update Gamepad Buttons
|
||||
for (int i = 0; i < 15; i++) {
|
||||
state->gp.buttons |= kbd[sdl_kbd_scancode_map[i]] << i;
|
||||
}
|
||||
|
||||
// Update Gamepad Axes
|
||||
if (kbd[sdl_kbd_scancode_map[15]])
|
||||
state->gp.axis[CONTROLLER_AXIS_LSTICK_Y] = 32767;
|
||||
if (kbd[sdl_kbd_scancode_map[16]])
|
||||
state->gp.axis[CONTROLLER_AXIS_LSTICK_X] = -32768;
|
||||
if (kbd[sdl_kbd_scancode_map[17]])
|
||||
state->gp.axis[CONTROLLER_AXIS_LSTICK_X] = 32767;
|
||||
if (kbd[sdl_kbd_scancode_map[18]])
|
||||
state->gp.axis[CONTROLLER_AXIS_LSTICK_Y] = -32768;
|
||||
if (kbd[sdl_kbd_scancode_map[19]])
|
||||
state->gp.axis[CONTROLLER_AXIS_LTRIG] = 32767;
|
||||
if (kbd[sdl_kbd_scancode_map[20]])
|
||||
state->gp.axis[CONTROLLER_AXIS_RSTICK_Y] = 32767;
|
||||
if (kbd[sdl_kbd_scancode_map[21]])
|
||||
state->gp.axis[CONTROLLER_AXIS_RSTICK_X] = -32768;
|
||||
if (kbd[sdl_kbd_scancode_map[22]])
|
||||
state->gp.axis[CONTROLLER_AXIS_RSTICK_X] = 32767;
|
||||
if (kbd[sdl_kbd_scancode_map[23]])
|
||||
state->gp.axis[CONTROLLER_AXIS_RSTICK_Y] = -32768;
|
||||
if (kbd[sdl_kbd_scancode_map[24]])
|
||||
state->gp.axis[CONTROLLER_AXIS_RTRIG] = 32767;
|
||||
}
|
||||
|
||||
if (kbd[sdl_kbd_scancode_map[15]]) state->axis[CONTROLLER_AXIS_LSTICK_Y] = 32767;
|
||||
if (kbd[sdl_kbd_scancode_map[16]]) state->axis[CONTROLLER_AXIS_LSTICK_X] = -32768;
|
||||
if (kbd[sdl_kbd_scancode_map[17]]) state->axis[CONTROLLER_AXIS_LSTICK_X] = 32767;
|
||||
if (kbd[sdl_kbd_scancode_map[18]]) state->axis[CONTROLLER_AXIS_LSTICK_Y] = -32768;
|
||||
if (kbd[sdl_kbd_scancode_map[19]]) state->axis[CONTROLLER_AXIS_LTRIG] = 32767;
|
||||
|
||||
if (kbd[sdl_kbd_scancode_map[20]]) state->axis[CONTROLLER_AXIS_RSTICK_Y] = 32767;
|
||||
if (kbd[sdl_kbd_scancode_map[21]]) state->axis[CONTROLLER_AXIS_RSTICK_X] = -32768;
|
||||
if (kbd[sdl_kbd_scancode_map[22]]) state->axis[CONTROLLER_AXIS_RSTICK_X] = 32767;
|
||||
if (kbd[sdl_kbd_scancode_map[23]]) state->axis[CONTROLLER_AXIS_RSTICK_Y] = -32768;
|
||||
if (kbd[sdl_kbd_scancode_map[24]]) state->axis[CONTROLLER_AXIS_RTRIG] = 32767;
|
||||
}
|
||||
|
||||
void xemu_input_update_sdl_controller_state(ControllerState *state)
|
||||
{
|
||||
state->buttons = 0;
|
||||
memset(state->axis, 0, sizeof(state->axis));
|
||||
state->gp.buttons = 0;
|
||||
state->sbc.buttons = 0;
|
||||
memset(state->gp.axis, 0, sizeof(state->gp.axis));
|
||||
memset(state->sbc.axis, 0, sizeof(state->sbc.axis));
|
||||
|
||||
const SDL_GameControllerButton sdl_button_map[15] = {
|
||||
SDL_CONTROLLER_BUTTON_A,
|
||||
SDL_CONTROLLER_BUTTON_B,
|
||||
SDL_CONTROLLER_BUTTON_X,
|
||||
SDL_CONTROLLER_BUTTON_Y,
|
||||
SDL_CONTROLLER_BUTTON_DPAD_LEFT,
|
||||
SDL_CONTROLLER_BUTTON_DPAD_UP,
|
||||
SDL_CONTROLLER_BUTTON_DPAD_RIGHT,
|
||||
SDL_CONTROLLER_BUTTON_DPAD_DOWN,
|
||||
SDL_CONTROLLER_BUTTON_BACK,
|
||||
SDL_CONTROLLER_BUTTON_START,
|
||||
SDL_CONTROLLER_BUTTON_LEFTSHOULDER,
|
||||
SDL_CONTROLLER_BUTTON_RIGHTSHOULDER,
|
||||
SDL_CONTROLLER_BUTTON_LEFTSTICK,
|
||||
SDL_CONTROLLER_BUTTON_RIGHTSTICK,
|
||||
SDL_CONTROLLER_BUTTON_GUIDE
|
||||
};
|
||||
if (state->bound < 0)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < 15; i++) {
|
||||
state->buttons |= SDL_GameControllerGetButton(state->sdl_gamecontroller, sdl_button_map[i]) << i;
|
||||
const char *bound_driver = get_bound_driver(state->bound);
|
||||
if (strcmp(bound_driver, DRIVER_STEEL_BATTALION) == 0) {
|
||||
state->sbc.buttons = 0;
|
||||
|
||||
const uint64_t sdl_button_map_sbc[8][2] = {
|
||||
{ SDL_CONTROLLER_BUTTON_A, SBC_BUTTON_MAIN_WEAPON },
|
||||
{ SDL_CONTROLLER_BUTTON_B, SBC_BUTTON_LOCK_ON },
|
||||
{ SDL_CONTROLLER_BUTTON_LEFTSHOULDER, SBC_BUTTON_FUNC1 },
|
||||
{ SDL_CONTROLLER_BUTTON_LEFTSTICK, SBC_BUTTON_SIGHT_CHANGE },
|
||||
{ SDL_CONTROLLER_BUTTON_DPAD_UP, SBC_BUTTON_GEAR_UP },
|
||||
{ SDL_CONTROLLER_BUTTON_DPAD_DOWN, SBC_BUTTON_GEAR_DOWN },
|
||||
{ SDL_CONTROLLER_BUTTON_DPAD_LEFT, SBC_BUTTON_TUNER_LEFT },
|
||||
{ SDL_CONTROLLER_BUTTON_DPAD_RIGHT, SBC_BUTTON_TUNER_RIGHT }
|
||||
};
|
||||
|
||||
if (state->sbc.gearLever == 0)
|
||||
state->sbc.gearLever = 255;
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (SDL_GameControllerGetButton(state->sdl_gamecontroller,
|
||||
sdl_button_map_sbc[i][0]))
|
||||
state->sbc.buttons |= sdl_button_map_sbc[i][1];
|
||||
}
|
||||
|
||||
const uint64_t toggles[5] = { SBC_BUTTON_FILT_CONTROL_SYSTEM,
|
||||
SBC_BUTTON_OXYGEN_SUPPLY_SYSTEM,
|
||||
SBC_BUTTON_FUEL_FLOW_RATE,
|
||||
SBC_BUTTON_BUFFER_MATERIAL,
|
||||
SBC_BUTTON_VT_LOCATION_MEASUREMENT };
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
if ((state->sbc.buttons & toggles[i]) &&
|
||||
!(state->sbc.previousButtons &
|
||||
toggles[i])) { // When the for the toggle is pressed
|
||||
uint8_t byteMask = (uint8_t)(toggles[i] >> 32);
|
||||
// Toggle the toggle switch
|
||||
state->sbc.toggleSwitches ^= byteMask;
|
||||
}
|
||||
}
|
||||
|
||||
// Tuner Dial Left
|
||||
if ((state->sbc.buttons & SBC_BUTTON_TUNER_LEFT) &&
|
||||
!(state->sbc.previousButtons & SBC_BUTTON_TUNER_LEFT)) {
|
||||
if (state->sbc.tunerDial == 0)
|
||||
state->sbc.tunerDial = 15;
|
||||
else
|
||||
state->sbc.tunerDial--;
|
||||
}
|
||||
|
||||
// Tuner Dial Right
|
||||
if ((state->sbc.buttons & SBC_BUTTON_TUNER_RIGHT) &&
|
||||
!(state->sbc.previousButtons & SBC_BUTTON_TUNER_RIGHT)) {
|
||||
if (state->sbc.tunerDial == 15)
|
||||
state->sbc.tunerDial = 0;
|
||||
else
|
||||
state->sbc.tunerDial++;
|
||||
}
|
||||
|
||||
// Gear Lever Up
|
||||
if ((state->sbc.buttons & SBC_BUTTON_GEAR_UP) &&
|
||||
!(state->sbc.previousButtons & SBC_BUTTON_GEAR_UP)) {
|
||||
if (state->sbc.gearLever != 5) {
|
||||
if (state->sbc.gearLever == 255)
|
||||
state->sbc.gearLever = 1;
|
||||
else
|
||||
state->sbc.gearLever++;
|
||||
}
|
||||
}
|
||||
|
||||
// Gear Lever Down
|
||||
if ((state->sbc.buttons & SBC_BUTTON_GEAR_DOWN) &&
|
||||
!(state->sbc.previousButtons & SBC_BUTTON_GEAR_DOWN)) {
|
||||
if (state->sbc.gearLever != 254) {
|
||||
if (state->sbc.gearLever == 1)
|
||||
state->sbc.gearLever = 255;
|
||||
else
|
||||
state->sbc.gearLever--;
|
||||
}
|
||||
}
|
||||
|
||||
state->sbc.axis[SBC_AXIS_SIGHT_CHANGE_X] = SDL_GameControllerGetAxis(
|
||||
state->sdl_gamecontroller, SDL_CONTROLLER_AXIS_LEFTX);
|
||||
state->sbc.axis[SBC_AXIS_SIGHT_CHANGE_Y] = SDL_GameControllerGetAxis(
|
||||
state->sdl_gamecontroller, SDL_CONTROLLER_AXIS_LEFTY);
|
||||
state->sbc.axis[SBC_AXIS_AIMING_X] = SDL_GameControllerGetAxis(
|
||||
state->sdl_gamecontroller, SDL_CONTROLLER_AXIS_RIGHTX);
|
||||
state->sbc.axis[SBC_AXIS_AIMING_Y] = SDL_GameControllerGetAxis(
|
||||
state->sdl_gamecontroller, SDL_CONTROLLER_AXIS_RIGHTY);
|
||||
state->sbc.axis[SBC_AXIS_MIDDLE_PEDAL] = SDL_GameControllerGetAxis(
|
||||
state->sdl_gamecontroller, SDL_CONTROLLER_AXIS_TRIGGERLEFT);
|
||||
state->sbc.axis[SBC_AXIS_RIGHT_PEDAL] = SDL_GameControllerGetAxis(
|
||||
state->sdl_gamecontroller, SDL_CONTROLLER_AXIS_TRIGGERRIGHT);
|
||||
|
||||
state->sbc.previousButtons = state->sbc.buttons;
|
||||
} else {
|
||||
const SDL_GameControllerButton sdl_button_map[15] = {
|
||||
SDL_CONTROLLER_BUTTON_A,
|
||||
SDL_CONTROLLER_BUTTON_B,
|
||||
SDL_CONTROLLER_BUTTON_X,
|
||||
SDL_CONTROLLER_BUTTON_Y,
|
||||
SDL_CONTROLLER_BUTTON_DPAD_LEFT,
|
||||
SDL_CONTROLLER_BUTTON_DPAD_UP,
|
||||
SDL_CONTROLLER_BUTTON_DPAD_RIGHT,
|
||||
SDL_CONTROLLER_BUTTON_DPAD_DOWN,
|
||||
SDL_CONTROLLER_BUTTON_BACK,
|
||||
SDL_CONTROLLER_BUTTON_START,
|
||||
SDL_CONTROLLER_BUTTON_LEFTSHOULDER,
|
||||
SDL_CONTROLLER_BUTTON_RIGHTSHOULDER,
|
||||
SDL_CONTROLLER_BUTTON_LEFTSTICK,
|
||||
SDL_CONTROLLER_BUTTON_RIGHTSTICK,
|
||||
SDL_CONTROLLER_BUTTON_GUIDE
|
||||
};
|
||||
|
||||
for (int i = 0; i < 15; i++) {
|
||||
state->gp.buttons |=
|
||||
SDL_GameControllerGetButton(state->sdl_gamecontroller, sdl_button_map[i]) << i;
|
||||
}
|
||||
|
||||
const SDL_GameControllerAxis sdl_axis_map[6] = {
|
||||
SDL_CONTROLLER_AXIS_TRIGGERLEFT, SDL_CONTROLLER_AXIS_TRIGGERRIGHT,
|
||||
SDL_CONTROLLER_AXIS_LEFTX, SDL_CONTROLLER_AXIS_LEFTY,
|
||||
SDL_CONTROLLER_AXIS_RIGHTX, SDL_CONTROLLER_AXIS_RIGHTY,
|
||||
};
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
state->gp.axis[i] =
|
||||
SDL_GameControllerGetAxis(state->sdl_gamecontroller, sdl_axis_map[i]);
|
||||
}
|
||||
|
||||
// FIXME: Check range
|
||||
state->gp.axis[CONTROLLER_AXIS_LSTICK_Y] =
|
||||
-1 - state->gp.axis[CONTROLLER_AXIS_LSTICK_Y];
|
||||
state->gp.axis[CONTROLLER_AXIS_RSTICK_Y] =
|
||||
-1 - state->gp.axis[CONTROLLER_AXIS_RSTICK_Y];
|
||||
|
||||
// xemu_input_print_controller_state(state);
|
||||
}
|
||||
|
||||
const SDL_GameControllerAxis sdl_axis_map[6] = {
|
||||
SDL_CONTROLLER_AXIS_TRIGGERLEFT, SDL_CONTROLLER_AXIS_TRIGGERRIGHT,
|
||||
SDL_CONTROLLER_AXIS_LEFTX, SDL_CONTROLLER_AXIS_LEFTY,
|
||||
SDL_CONTROLLER_AXIS_RIGHTX, SDL_CONTROLLER_AXIS_RIGHTY,
|
||||
};
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
state->axis[i] = SDL_GameControllerGetAxis(state->sdl_gamecontroller, sdl_axis_map[i]);
|
||||
}
|
||||
|
||||
// FIXME: Check range
|
||||
state->axis[CONTROLLER_AXIS_LSTICK_Y] = -1 - state->axis[CONTROLLER_AXIS_LSTICK_Y];
|
||||
state->axis[CONTROLLER_AXIS_RSTICK_Y] = -1 - state->axis[CONTROLLER_AXIS_RSTICK_Y];
|
||||
|
||||
// xemu_input_print_controller_state(state);
|
||||
}
|
||||
|
||||
void xemu_input_update_rumble(ControllerState *state)
|
||||
{
|
||||
if (!state->rumble_enabled) {
|
||||
if (!state->gp.rumble_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -500,7 +953,7 @@ void xemu_input_update_rumble(ControllerState *state)
|
|||
return;
|
||||
}
|
||||
|
||||
SDL_GameControllerRumble(state->sdl_gamecontroller, state->rumble_l, state->rumble_r, 250);
|
||||
SDL_GameControllerRumble(state->sdl_gamecontroller, state->gp.rumble_l, state->gp.rumble_r, 250);
|
||||
state->last_rumble_updated_ts = qemu_clock_get_us(QEMU_CLOCK_REALTIME);
|
||||
}
|
||||
|
||||
|
@ -568,16 +1021,24 @@ void xemu_input_bind(int index, ControllerState *state, int save)
|
|||
bound_controllers[index]->bound = index;
|
||||
|
||||
char *tmp;
|
||||
QDict *usbhub_qdict = NULL;
|
||||
DeviceState *usbhub_dev = NULL;
|
||||
|
||||
// Create controller's internal USB hub.
|
||||
QDict *usbhub_qdict = qdict_new();
|
||||
qdict_put_str(usbhub_qdict, "driver", "usb-hub");
|
||||
tmp = g_strdup_printf("1.%d", port_map[index]);
|
||||
qdict_put_str(usbhub_qdict, "port", tmp);
|
||||
qdict_put_int(usbhub_qdict, "ports", 3);
|
||||
QemuOpts *usbhub_opts = qemu_opts_from_qdict(qemu_find_opts("device"), usbhub_qdict, &error_abort);
|
||||
DeviceState *usbhub_dev = qdev_device_add(usbhub_opts, &error_abort);
|
||||
g_free(tmp);
|
||||
bool hasInternalHub = strcmp(bound_drivers[index], DRIVER_STEEL_BATTALION) != 0
|
||||
&& strcmp(bound_drivers[index], DRIVER_DVD_PLAYBACK_KIT) != 0;
|
||||
bool hasFirmware = strcmp(bound_drivers[index], DRIVER_DVD_PLAYBACK_KIT) == 0;
|
||||
|
||||
if (hasInternalHub) {
|
||||
// Create controller's internal USB hub.
|
||||
usbhub_qdict = qdict_new();
|
||||
qdict_put_str(usbhub_qdict, "driver", "usb-hub");
|
||||
tmp = g_strdup_printf("1.%d", port_map[index]);
|
||||
qdict_put_str(usbhub_qdict, "port", tmp);
|
||||
qdict_put_int(usbhub_qdict, "ports", 3);
|
||||
QemuOpts *usbhub_opts = qemu_opts_from_qdict(qemu_find_opts("device"), usbhub_qdict, &error_abort);
|
||||
usbhub_dev = qdev_device_add(usbhub_opts, &error_abort);
|
||||
g_free(tmp);
|
||||
}
|
||||
|
||||
// Create XID controller. This is connected to Port 1 of the controller's internal USB Hub
|
||||
QDict *qdict = qdict_new();
|
||||
|
@ -593,22 +1054,31 @@ void xemu_input_bind(int index, ControllerState *state, int save)
|
|||
|
||||
// Specify index/port
|
||||
qdict_put_int(qdict, "index", index);
|
||||
tmp = g_strdup_printf("1.%d.1", port_map[index]);
|
||||
const char *fmt = hasInternalHub ? "1.%d.1" : "1.%d";
|
||||
tmp = g_strdup_printf(fmt, port_map[index]);
|
||||
qdict_put_str(qdict, "port", tmp);
|
||||
g_free(tmp);
|
||||
|
||||
// Specify DVD firmware
|
||||
if (hasFirmware) {
|
||||
qdict_put_str(qdict, "firmware", *port_index_to_dvd_firmware_key_map[index]);
|
||||
state->dvdKit.firmware = (char*) *port_index_to_dvd_firmware_key_map[index];
|
||||
}
|
||||
|
||||
// Create the device
|
||||
QemuOpts *opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict, &error_abort);
|
||||
DeviceState *dev = qdev_device_add(opts, &error_abort);
|
||||
assert(dev);
|
||||
|
||||
// Unref for eventual cleanup
|
||||
qobject_unref(usbhub_qdict);
|
||||
object_unref(OBJECT(usbhub_dev));
|
||||
if (usbhub_qdict != NULL)
|
||||
qobject_unref(usbhub_qdict);
|
||||
if (usbhub_dev != NULL)
|
||||
object_unref(OBJECT(usbhub_dev));
|
||||
qobject_unref(qdict);
|
||||
object_unref(OBJECT(dev));
|
||||
|
||||
state->device = usbhub_dev;
|
||||
state->device = hasInternalHub ? usbhub_dev : dev;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -618,6 +1088,10 @@ bool xemu_input_bind_xmu(int player_index, int expansion_slot_index,
|
|||
assert(player_index >= 0 && player_index < 4);
|
||||
assert(expansion_slot_index >= 0 && expansion_slot_index < 2);
|
||||
|
||||
bool hasInternalHub = strcmp(bound_drivers[player_index], DRIVER_STEEL_BATTALION) != 0
|
||||
&& strcmp(bound_drivers[player_index], DRIVER_DVD_PLAYBACK_KIT) != 0;
|
||||
assert(hasInternalHub);
|
||||
|
||||
ControllerState *player = bound_controllers[player_index];
|
||||
enum peripheral_type peripheral_type =
|
||||
player->peripheral_types[expansion_slot_index];
|
||||
|
@ -740,6 +1214,11 @@ void xemu_input_unbind_xmu(int player_index, int expansion_slot_index)
|
|||
|
||||
void xemu_input_rebind_xmu(int port)
|
||||
{
|
||||
bool hasInternalHub = strcmp(bound_drivers[port], DRIVER_STEEL_BATTALION) != 0
|
||||
&& strcmp(bound_drivers[port], DRIVER_DVD_PLAYBACK_KIT) != 0;
|
||||
if (!hasInternalHub)
|
||||
return;
|
||||
|
||||
// Try to bind peripherals back to controller
|
||||
for (int i = 0; i < 2; i++) {
|
||||
enum peripheral_type peripheral_type =
|
||||
|
|
148
ui/xemu-input.h
148
ui/xemu-input.h
|
@ -32,9 +32,13 @@
|
|||
|
||||
#define DRIVER_DUKE "usb-xbox-gamepad"
|
||||
#define DRIVER_S "usb-xbox-gamepad-s"
|
||||
#define DRIVER_STEEL_BATTALION "usb-steel-battalion"
|
||||
#define DRIVER_DVD_PLAYBACK_KIT "xbox-dvd-playback-kit"
|
||||
|
||||
#define DRIVER_DUKE_DISPLAY_NAME "Xbox Controller"
|
||||
#define DRIVER_S_DISPLAY_NAME "Xbox Controller S"
|
||||
#define DRIVER_STEEL_BATTALION_DISPLAY_NAME "Steel Battalion Controller"
|
||||
#define DRIVER_DVD_PLAYBACK_KIT_DISPLAY_NAME "Xbox DVD Playback Kit"
|
||||
|
||||
enum controller_state_buttons_mask {
|
||||
CONTROLLER_BUTTON_A = (1 << 0),
|
||||
|
@ -56,6 +60,102 @@ enum controller_state_buttons_mask {
|
|||
|
||||
#define CONTROLLER_STATE_BUTTON_ID_TO_MASK(x) (1<<x)
|
||||
|
||||
enum steel_battalion_controller_state_buttons_mask {
|
||||
SBC_BUTTON_MAIN_WEAPON = 0x01,
|
||||
SBC_BUTTON_SUB_WEAPON = 0x02,
|
||||
SBC_BUTTON_LOCK_ON = 0x04,
|
||||
SBC_BUTTON_EJECT = 0x08,
|
||||
SBC_BUTTON_COCKPIT_HATCH = 0x10,
|
||||
SBC_BUTTON_IGNITION = 0x20,
|
||||
SBC_BUTTON_START = 0x40,
|
||||
SBC_BUTTON_OPEN_CLOSE = 0x80,
|
||||
SBC_BUTTON_MAP_ZOOM_IN_OUT = 0x100,
|
||||
SBC_BUTTON_MODE_SELECT = 0x200,
|
||||
SBC_BUTTON_SUB_MONITOR_MODE_SELECT = 0x400,
|
||||
SBC_BUTTON_ZOOM_IN = 0x800,
|
||||
SBC_BUTTON_ZOOM_OUT = 0x1000,
|
||||
SBC_BUTTON_FSS = 0x2000,
|
||||
SBC_BUTTON_MANIPULATOR = 0x4000,
|
||||
SBC_BUTTON_LINE_COLOR_CHANGE = 0x8000,
|
||||
SBC_BUTTON_WASHING = 0x10000,
|
||||
SBC_BUTTON_EXTINGUISHER = 0x20000,
|
||||
SBC_BUTTON_CHAFF = 0x40000,
|
||||
SBC_BUTTON_TANK_DETACH = 0x80000,
|
||||
SBC_BUTTON_OVERRIDE = 0x100000,
|
||||
SBC_BUTTON_NIGHT_SCOPE = 0x200000,
|
||||
SBC_BUTTON_FUNC1 = 0x400000,
|
||||
SBC_BUTTON_FUNC2 = 0x800000,
|
||||
SBC_BUTTON_FUNC3 = 0x1000000,
|
||||
SBC_BUTTON_MAIN_WEAPON_CONTROL = 0x2000000,
|
||||
SBC_BUTTON_SUB_WEAPON_CONTROL = 0x4000000,
|
||||
SBC_BUTTON_MAGAZINE_CHANGE = 0x8000000,
|
||||
SBC_BUTTON_COM1 = 0x10000000,
|
||||
SBC_BUTTON_COM2 = 0x20000000,
|
||||
SBC_BUTTON_COM3 = 0x40000000,
|
||||
SBC_BUTTON_COM4 = 0x80000000
|
||||
};
|
||||
|
||||
#define SBC_BUTTON_COM5 \
|
||||
0x100000000ULL // These last 7 buttons are in bMoreButtons
|
||||
#define SBC_BUTTON_SIGHT_CHANGE 0x200000000ULL
|
||||
#define SBC_BUTTON_FILT_CONTROL_SYSTEM 0x400000000ULL
|
||||
#define SBC_BUTTON_OXYGEN_SUPPLY_SYSTEM 0x800000000ULL
|
||||
#define SBC_BUTTON_FUEL_FLOW_RATE 0x1000000000ULL
|
||||
#define SBC_BUTTON_BUFFER_MATERIAL 0x2000000000ULL
|
||||
#define SBC_BUTTON_VT_LOCATION_MEASUREMENT 0x4000000000ULL
|
||||
#define SBC_BUTTON_GEAR_UP 0x8000000000ULL
|
||||
#define SBC_BUTTON_GEAR_DOWN 0x10000000000ULL
|
||||
#define SBC_BUTTON_TUNER_LEFT 0x20000000000ULL
|
||||
#define SBC_BUTTON_TUNER_RIGHT 0x40000000000ULL
|
||||
|
||||
enum dvd_playback_kit_state_buttons_mask {
|
||||
DVD_BUTTON_UP = (1 << 0),
|
||||
DVD_BUTTON_LEFT = (1 << 1),
|
||||
DVD_BUTTON_SELECT = (1 << 2),
|
||||
DVD_BUTTON_RIGHT = (1 << 3),
|
||||
DVD_BUTTON_DOWN = (1 << 4),
|
||||
DVD_BUTTON_DISPLAY = (1 << 5),
|
||||
DVD_BUTTON_REVERSE = (1 << 6),
|
||||
DVD_BUTTON_PLAY = (1 << 7),
|
||||
DVD_BUTTON_FORWARD = (1 << 8),
|
||||
DVD_BUTTON_SKIP_DOWN = (1 << 9),
|
||||
DVD_BUTTON_STOP = (1 << 10),
|
||||
DVD_BUTTON_PAUSE = (1 << 11),
|
||||
DVD_BUTTON_SKIP_UP = (1 << 12),
|
||||
DVD_BUTTON_TITLE = (1 << 13),
|
||||
DVD_BUTTON_INFO = (1 << 14),
|
||||
DVD_BUTTON_MENU = (1 << 15),
|
||||
DVD_BUTTON_BACK = (1 << 16),
|
||||
DVD_BUTTON_1 = (1 << 17),
|
||||
DVD_BUTTON_2 = (1 << 18),
|
||||
DVD_BUTTON_3 = (1 << 19),
|
||||
DVD_BUTTON_4 = (1 << 20),
|
||||
DVD_BUTTON_5 = (1 << 21),
|
||||
DVD_BUTTON_6 = (1 << 22),
|
||||
DVD_BUTTON_7 = (1 << 23),
|
||||
DVD_BUTTON_8 = (1 << 24),
|
||||
DVD_BUTTON_9 = (1 << 25),
|
||||
DVD_BUTTON_0 = (1 << 26),
|
||||
// Media Center Extender Remote
|
||||
MCE_BUTTON_POWER = (1 << 27),
|
||||
MCE_BUTTON_MY_TV = (1 << 28),
|
||||
MCE_BUTTON_MY_MUSIC = (1 << 29),
|
||||
MCE_BUTTON_MY_PICTURES = (1 << 30),
|
||||
MCE_BUTTON_MY_VIDEOS = (1 << 31),
|
||||
MCE_BUTTON_RECORD = (1ULL << 32),
|
||||
MCE_BUTTON_START = (1ULL << 33),
|
||||
MCE_BUTTON_VOL_UP = (1ULL << 34),
|
||||
MCE_BUTTON_VOL_DOWN = (1ULL << 35),
|
||||
MCE_BUTTON_MUTE = (1ULL << 36),
|
||||
MCE_BUTTON_CH_UP = (1ULL << 37),
|
||||
MCE_BUTTON_CH_DOWN = (1ULL << 38),
|
||||
MCE_BUTTON_RECORDED_TV = (1ULL << 39),
|
||||
MCE_BUTTON_LIVE_TV = (1ULL << 40),
|
||||
MCE_BUTTON_STAR = (1ULL << 41),
|
||||
MCE_BUTTON_POUND = (1ULL << 42),
|
||||
MCE_BUTTON_CLEAR = (1ULL << 43),
|
||||
};
|
||||
|
||||
enum controller_state_axis_index {
|
||||
CONTROLLER_AXIS_LTRIG,
|
||||
CONTROLLER_AXIS_RTRIG,
|
||||
|
@ -66,6 +166,18 @@ enum controller_state_axis_index {
|
|||
CONTROLLER_AXIS__COUNT,
|
||||
};
|
||||
|
||||
enum steel_battalion_state_axis_index {
|
||||
SBC_AXIS_AIMING_X,
|
||||
SBC_AXIS_AIMING_Y,
|
||||
SBC_AXIS_ROTATION_LEVER,
|
||||
SBC_AXIS_LEFT_PEDAL,
|
||||
SBC_AXIS_MIDDLE_PEDAL,
|
||||
SBC_AXIS_RIGHT_PEDAL,
|
||||
SBC_AXIS_SIGHT_CHANGE_X,
|
||||
SBC_AXIS_SIGHT_CHANGE_Y,
|
||||
SBC_AXIS__COUNT
|
||||
};
|
||||
|
||||
enum controller_input_device_type {
|
||||
INPUT_DEVICE_SDL_KEYBOARD,
|
||||
INPUT_DEVICE_SDL_GAMECONTROLLER,
|
||||
|
@ -78,23 +190,44 @@ typedef struct XmuState {
|
|||
void *dev;
|
||||
} XmuState;
|
||||
|
||||
typedef struct ControllerState {
|
||||
QTAILQ_ENTRY(ControllerState) entry;
|
||||
|
||||
int64_t last_input_updated_ts;
|
||||
int64_t last_rumble_updated_ts;
|
||||
|
||||
typedef struct GamepadState {
|
||||
// Input state
|
||||
uint16_t buttons;
|
||||
int16_t axis[CONTROLLER_AXIS__COUNT];
|
||||
|
||||
// Rendering state hacked on here for convenience but needs to be moved (FIXME)
|
||||
// Rendering state hacked on here for convenience but needs to be moved
|
||||
// (FIXME)
|
||||
uint32_t animate_guide_button_end;
|
||||
uint32_t animate_trigger_end;
|
||||
|
||||
// Rumble state
|
||||
bool rumble_enabled;
|
||||
uint16_t rumble_l, rumble_r;
|
||||
} GamepadState;
|
||||
|
||||
typedef struct SteelBattalionState {
|
||||
uint64_t buttons;
|
||||
uint64_t previousButtons;
|
||||
int16_t axis[SBC_AXIS__COUNT];
|
||||
uint8_t gearLever;
|
||||
uint8_t tunerDial;
|
||||
uint8_t toggleSwitches;
|
||||
} SteelBattalionState;
|
||||
|
||||
typedef struct {
|
||||
char *firmware;
|
||||
uint64_t buttons;
|
||||
} DVDPlaybackKitState;
|
||||
|
||||
typedef struct ControllerState {
|
||||
QTAILQ_ENTRY(ControllerState) entry;
|
||||
|
||||
int64_t last_input_updated_ts;
|
||||
int64_t last_rumble_updated_ts;
|
||||
|
||||
GamepadState gp;
|
||||
SteelBattalionState sbc;
|
||||
DVDPlaybackKitState dvdKit;
|
||||
|
||||
enum controller_input_device_type type;
|
||||
const char *name;
|
||||
|
@ -136,6 +269,7 @@ int xemu_input_get_controller_default_bind_port(ControllerState *state, int star
|
|||
void xemu_save_peripheral_settings(int player_index, int peripheral_index,
|
||||
int peripheral_type,
|
||||
const char *peripheral_parameter);
|
||||
void xemu_save_dvd_firmware_settings(int player_index, const char *firmware);
|
||||
|
||||
void xemu_input_set_test_mode(int enabled);
|
||||
int xemu_input_get_test_mode(void);
|
||||
|
|
|
@ -112,7 +112,8 @@ static int guest_cursor;
|
|||
static int guest_x, guest_y;
|
||||
static SDL_Cursor *guest_sprite;
|
||||
static Notifier mouse_mode_notifier;
|
||||
static SDL_Window *m_window;
|
||||
SDL_Window *m_window;
|
||||
int viewport_coords[4];
|
||||
static SDL_GLContext m_context;
|
||||
// struct decal_shader *blit;
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include "common.hh"
|
||||
#include "data/controller_mask.png.h"
|
||||
#include "data/controller_mask_s.png.h"
|
||||
#include "data/dvd_remote_mask.png.h"
|
||||
#include "data/sb_controller_mask.png.h"
|
||||
#include "data/logo_sdf.png.h"
|
||||
#include "data/xemu_64x64.png.h"
|
||||
#include "data/xmu_mask.png.h"
|
||||
|
@ -33,8 +35,10 @@
|
|||
|
||||
#include "ui/shader/xemu-logo-frag.h"
|
||||
|
||||
extern int viewport_coords[4];
|
||||
|
||||
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_sb_controller_tex, g_dvd_remote_tex, g_logo_tex, g_icon_tex, g_xmu_tex;
|
||||
|
||||
enum class ShaderType {
|
||||
Blit,
|
||||
|
@ -425,6 +429,19 @@ static const struct rect tex_items[] = {
|
|||
{ 0, 0, 512, 512 } // obj_xmu
|
||||
};
|
||||
|
||||
static const struct rect sb_tex_items[] = {
|
||||
{ 0, 148, 467, 364 }, // obj_controller
|
||||
{ 2, 79, 7, 7 }, // radio_dial
|
||||
{ 21, 55, 48, 29 }, // transmission lever
|
||||
{ 70, 0, 50, 79 }, // Slide Step Pedal
|
||||
{ 121, 4, 39, 63 }, // Brake Pedal
|
||||
{ 160, 2, 40, 74 }, // Accel Pedal
|
||||
{ 1, 55, 20, 22 }, // Sight Change Stick
|
||||
{ 0, 0, 34, 55 }, // Left Stick
|
||||
{ 34, 0, 33, 55 }, // Right Stick
|
||||
{ 21, 2, 3, 3 } // Toggle
|
||||
};
|
||||
|
||||
enum tex_item_names {
|
||||
obj_controller,
|
||||
obj_lstick,
|
||||
|
@ -437,6 +454,18 @@ enum tex_item_names {
|
|||
obj_xmu
|
||||
};
|
||||
|
||||
enum sb_tex_item_names {
|
||||
obj_radio_dial = 1,
|
||||
obj_transmission_lever,
|
||||
obj_slide_step_pedal,
|
||||
obj_brake_pedal,
|
||||
obj_accel_pedal,
|
||||
obj_sight_change_stick,
|
||||
obj_left_stick,
|
||||
obj_right_stick,
|
||||
obj_toggle
|
||||
};
|
||||
|
||||
void InitCustomRendering(void)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
@ -444,6 +473,10 @@ void InitCustomRendering(void)
|
|||
LoadTextureFromMemory(controller_mask_data, controller_mask_size);
|
||||
g_controller_s_tex =
|
||||
LoadTextureFromMemory(controller_mask_s_data, controller_mask_s_size);
|
||||
g_sb_controller_tex =
|
||||
LoadTextureFromMemory(sb_controller_mask_data, sb_controller_mask_size);
|
||||
g_dvd_remote_tex =
|
||||
LoadTextureFromMemory(dvd_remote_mask_data, dvd_remote_mask_size);
|
||||
g_decal_shader = NewDecalShader(ShaderType::Mask);
|
||||
controller_fbo = new Fbo(512, 512);
|
||||
|
||||
|
@ -517,12 +550,12 @@ static void RenderDukeController(float frame_x, float frame_y, uint32_t primary_
|
|||
|
||||
// Check to see if the guide button is pressed
|
||||
const uint32_t animate_guide_button_duration = 2000;
|
||||
if (state->buttons & CONTROLLER_BUTTON_GUIDE) {
|
||||
state->animate_guide_button_end = now + animate_guide_button_duration;
|
||||
if (state->gp.buttons & CONTROLLER_BUTTON_GUIDE) {
|
||||
state->gp.animate_guide_button_end = now + animate_guide_button_duration;
|
||||
}
|
||||
|
||||
if (now < state->animate_guide_button_end) {
|
||||
t = 1.0f - (float)(state->animate_guide_button_end-now)/(float)animate_guide_button_duration;
|
||||
if (now < state->gp.animate_guide_button_end) {
|
||||
t = 1.0f - (float)(state->gp.animate_guide_button_end-now)/(float)animate_guide_button_duration;
|
||||
float sin_wav = (1-sin(M_PI * t / 2.0f));
|
||||
|
||||
// Animate guide button by highlighting logo jewel and fading out over time
|
||||
|
@ -549,7 +582,7 @@ static void RenderDukeController(float frame_x, float frame_y, uint32_t primary_
|
|||
// 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)) {
|
||||
if (state->gp.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);
|
||||
|
@ -563,14 +596,14 @@ static void RenderDukeController(float frame_x, float frame_y, uint32_t primary_
|
|||
float h = tex_items[obj_lstick].h;
|
||||
float c_x = frame_x+lstick_ctr.x;
|
||||
float c_y = frame_y+lstick_ctr.y;
|
||||
float lstick_x = (float)state->axis[CONTROLLER_AXIS_LSTICK_X]/32768.0;
|
||||
float lstick_y = (float)state->axis[CONTROLLER_AXIS_LSTICK_Y]/32768.0;
|
||||
float lstick_x = (float)state->gp.axis[CONTROLLER_AXIS_LSTICK_X]/32768.0;
|
||||
float lstick_y = (float)state->gp.axis[CONTROLLER_AXIS_LSTICK_Y]/32768.0;
|
||||
RenderDecal(g_decal_shader, (int)(c_x - w / 2.0f + 10.0f * lstick_x),
|
||||
(int)(c_y - h / 2.0f + 10.0f * lstick_y), w, h,
|
||||
tex_items[obj_lstick].x, tex_items[obj_lstick].y, w, h,
|
||||
(state->buttons & CONTROLLER_BUTTON_LSTICK) ? secondary_color :
|
||||
(state->gp.buttons & CONTROLLER_BUTTON_LSTICK) ? secondary_color :
|
||||
primary_color,
|
||||
(state->buttons & CONTROLLER_BUTTON_LSTICK) ? primary_color :
|
||||
(state->gp.buttons & CONTROLLER_BUTTON_LSTICK) ? primary_color :
|
||||
secondary_color,
|
||||
0);
|
||||
|
||||
|
@ -579,33 +612,33 @@ static void RenderDukeController(float frame_x, float frame_y, uint32_t primary_
|
|||
h = tex_items[obj_rstick].h;
|
||||
c_x = frame_x+rstick_ctr.x;
|
||||
c_y = frame_y+rstick_ctr.y;
|
||||
float rstick_x = (float)state->axis[CONTROLLER_AXIS_RSTICK_X]/32768.0;
|
||||
float rstick_y = (float)state->axis[CONTROLLER_AXIS_RSTICK_Y]/32768.0;
|
||||
float rstick_x = (float)state->gp.axis[CONTROLLER_AXIS_RSTICK_X]/32768.0;
|
||||
float rstick_y = (float)state->gp.axis[CONTROLLER_AXIS_RSTICK_Y]/32768.0;
|
||||
RenderDecal(g_decal_shader, (int)(c_x - w / 2.0f + 10.0f * rstick_x),
|
||||
(int)(c_y - h / 2.0f + 10.0f * rstick_y), w, h,
|
||||
tex_items[obj_rstick].x, tex_items[obj_rstick].y, w, h,
|
||||
(state->buttons & CONTROLLER_BUTTON_RSTICK) ? secondary_color :
|
||||
(state->gp.buttons & CONTROLLER_BUTTON_RSTICK) ? secondary_color :
|
||||
primary_color,
|
||||
(state->buttons & CONTROLLER_BUTTON_RSTICK) ? primary_color :
|
||||
(state->gp.buttons & CONTROLLER_BUTTON_RSTICK) ? primary_color :
|
||||
secondary_color,
|
||||
0);
|
||||
|
||||
glBlendFunc(GL_ONE, GL_ZERO); // Don't blend, just overwrite values in buffer
|
||||
|
||||
// Render trigger bars
|
||||
float ltrig = state->axis[CONTROLLER_AXIS_LTRIG] / 32767.0;
|
||||
float rtrig = state->axis[CONTROLLER_AXIS_RTRIG] / 32767.0;
|
||||
float ltrig = state->gp.axis[CONTROLLER_AXIS_LTRIG] / 32767.0;
|
||||
float rtrig = state->gp.axis[CONTROLLER_AXIS_RTRIG] / 32767.0;
|
||||
const uint32_t animate_trigger_duration = 1000;
|
||||
if ((ltrig > 0) || (rtrig > 0)) {
|
||||
state->animate_trigger_end = now + animate_trigger_duration;
|
||||
state->gp.animate_trigger_end = now + animate_trigger_duration;
|
||||
rumble_l = fmax(rumble_l, ltrig);
|
||||
rumble_r = fmax(rumble_r, rtrig);
|
||||
}
|
||||
|
||||
// Animate trigger alpha down after a period of inactivity
|
||||
alpha = 0x80;
|
||||
if (state->animate_trigger_end > now) {
|
||||
t = 1.0f - (float)(state->animate_trigger_end-now)/(float)animate_trigger_duration;
|
||||
if (state->gp.animate_trigger_end > now) {
|
||||
t = 1.0f - (float)(state->gp.animate_trigger_end-now)/(float)animate_trigger_duration;
|
||||
float sin_wav = (1-sin(M_PI * t / 2.0f));
|
||||
alpha += fmin(sin_wav * 0x40, 0x80);
|
||||
}
|
||||
|
@ -619,8 +652,8 @@ static void RenderDukeController(float frame_x, float frame_y, uint32_t primary_
|
|||
rtrig, primary_color + alpha, primary_color + 0xff);
|
||||
|
||||
// Apply rumble updates
|
||||
state->rumble_l = (int)(rumble_l * (float)0xffff);
|
||||
state->rumble_r = (int)(rumble_r * (float)0xffff);
|
||||
state->gp.rumble_l = (int)(rumble_l * (float)0xffff);
|
||||
state->gp.rumble_r = (int)(rumble_r * (float)0xffff);
|
||||
|
||||
glBindVertexArray(0);
|
||||
glUseProgram(0);
|
||||
|
@ -676,13 +709,13 @@ static void RenderControllerS(float frame_x, float frame_y, uint32_t primary_col
|
|||
|
||||
// Check to see if the guide button is pressed
|
||||
const uint32_t animate_guide_button_duration = 2000;
|
||||
if (state->buttons & CONTROLLER_BUTTON_GUIDE) {
|
||||
state->animate_guide_button_end =
|
||||
if (state->gp.buttons & CONTROLLER_BUTTON_GUIDE) {
|
||||
state->gp.animate_guide_button_end =
|
||||
now + animate_guide_button_duration;
|
||||
}
|
||||
|
||||
if (now < state->animate_guide_button_end) {
|
||||
t = 1.0f - (float)(state->animate_guide_button_end - now) /
|
||||
if (now < state->gp.animate_guide_button_end) {
|
||||
t = 1.0f - (float)(state->gp.animate_guide_button_end - now) /
|
||||
(float)animate_guide_button_duration;
|
||||
float sin_wav = (1 - sin(M_PI * t / 2.0f));
|
||||
|
||||
|
@ -712,7 +745,7 @@ static void RenderControllerS(float frame_x, float frame_y, uint32_t primary_col
|
|||
// 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)) {
|
||||
if (state->gp.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);
|
||||
|
@ -726,15 +759,15 @@ static void RenderControllerS(float frame_x, float frame_y, uint32_t primary_col
|
|||
float h = tex_items[obj_lstick].h;
|
||||
float c_x = frame_x + lstick_ctr.x;
|
||||
float c_y = frame_y + lstick_ctr.y;
|
||||
float lstick_x = (float)state->axis[CONTROLLER_AXIS_LSTICK_X] / 32768.0;
|
||||
float lstick_y = (float)state->axis[CONTROLLER_AXIS_LSTICK_Y] / 32768.0;
|
||||
float lstick_x = (float)state->gp.axis[CONTROLLER_AXIS_LSTICK_X] / 32768.0;
|
||||
float lstick_y = (float)state->gp.axis[CONTROLLER_AXIS_LSTICK_Y] / 32768.0;
|
||||
RenderDecal(
|
||||
g_decal_shader, (int)(c_x - w / 2.0f + 10.0f * lstick_x),
|
||||
(int)(c_y - h / 2.0f + 10.0f * lstick_y), w, h, tex_items[obj_lstick].x,
|
||||
tex_items[obj_lstick].y, w, h,
|
||||
(state->buttons & CONTROLLER_BUTTON_LSTICK) ? secondary_color :
|
||||
(state->gp.buttons & CONTROLLER_BUTTON_LSTICK) ? secondary_color :
|
||||
primary_color,
|
||||
(state->buttons & CONTROLLER_BUTTON_LSTICK) ? primary_color :
|
||||
(state->gp.buttons & CONTROLLER_BUTTON_LSTICK) ? primary_color :
|
||||
secondary_color,
|
||||
0);
|
||||
|
||||
|
@ -743,15 +776,15 @@ static void RenderControllerS(float frame_x, float frame_y, uint32_t primary_col
|
|||
h = tex_items[obj_rstick].h;
|
||||
c_x = frame_x + rstick_ctr.x;
|
||||
c_y = frame_y + rstick_ctr.y;
|
||||
float rstick_x = (float)state->axis[CONTROLLER_AXIS_RSTICK_X] / 32768.0;
|
||||
float rstick_y = (float)state->axis[CONTROLLER_AXIS_RSTICK_Y] / 32768.0;
|
||||
float rstick_x = (float)state->gp.axis[CONTROLLER_AXIS_RSTICK_X] / 32768.0;
|
||||
float rstick_y = (float)state->gp.axis[CONTROLLER_AXIS_RSTICK_Y] / 32768.0;
|
||||
RenderDecal(
|
||||
g_decal_shader, (int)(c_x - w / 2.0f + 10.0f * rstick_x),
|
||||
(int)(c_y - h / 2.0f + 10.0f * rstick_y), w, h, tex_items[obj_rstick].x,
|
||||
tex_items[obj_rstick].y, w, h,
|
||||
(state->buttons & CONTROLLER_BUTTON_RSTICK) ? secondary_color :
|
||||
(state->gp.buttons & CONTROLLER_BUTTON_RSTICK) ? secondary_color :
|
||||
primary_color,
|
||||
(state->buttons & CONTROLLER_BUTTON_RSTICK) ? primary_color :
|
||||
(state->gp.buttons & CONTROLLER_BUTTON_RSTICK) ? primary_color :
|
||||
secondary_color,
|
||||
0);
|
||||
|
||||
|
@ -759,19 +792,19 @@ static void RenderControllerS(float frame_x, float frame_y, uint32_t primary_col
|
|||
GL_ZERO); // Don't blend, just overwrite values in buffer
|
||||
|
||||
// Render trigger bars
|
||||
float ltrig = state->axis[CONTROLLER_AXIS_LTRIG] / 32767.0;
|
||||
float rtrig = state->axis[CONTROLLER_AXIS_RTRIG] / 32767.0;
|
||||
float ltrig = state->gp.axis[CONTROLLER_AXIS_LTRIG] / 32767.0;
|
||||
float rtrig = state->gp.axis[CONTROLLER_AXIS_RTRIG] / 32767.0;
|
||||
const uint32_t animate_trigger_duration = 1000;
|
||||
if ((ltrig > 0) || (rtrig > 0)) {
|
||||
state->animate_trigger_end = now + animate_trigger_duration;
|
||||
state->gp.animate_trigger_end = now + animate_trigger_duration;
|
||||
rumble_l = fmax(rumble_l, ltrig);
|
||||
rumble_r = fmax(rumble_r, rtrig);
|
||||
}
|
||||
|
||||
// Animate trigger alpha down after a period of inactivity
|
||||
alpha = 0x80;
|
||||
if (state->animate_trigger_end > now) {
|
||||
t = 1.0f - (float)(state->animate_trigger_end - now) /
|
||||
if (state->gp.animate_trigger_end > now) {
|
||||
t = 1.0f - (float)(state->gp.animate_trigger_end - now) /
|
||||
(float)animate_trigger_duration;
|
||||
float sin_wav = (1 - sin(M_PI * t / 2.0f));
|
||||
alpha += fmin(sin_wav * 0x40, 0x80);
|
||||
|
@ -786,8 +819,429 @@ static void RenderControllerS(float frame_x, float frame_y, uint32_t primary_col
|
|||
rtrig, primary_color + alpha, primary_color + 0xff);
|
||||
|
||||
// Apply rumble updates
|
||||
state->rumble_l = (int)(rumble_l * (float)0xffff);
|
||||
state->rumble_r = (int)(rumble_r * (float)0xffff);
|
||||
state->gp.rumble_l = (int)(rumble_l * (float)0xffff);
|
||||
state->gp.rumble_r = (int)(rumble_r * (float)0xffff);
|
||||
|
||||
glBindVertexArray(0);
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
void RenderSteelBattalionController(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 lstick_ctr = { 122, 263, 0, 0 };
|
||||
const struct rect rstick_ctr = { 349, 263, 0, 0 };
|
||||
const struct rect accel_pedal = { 281, 92, 0, 0 };
|
||||
const struct rect brake_pedal = { 216, 96, 0, 0 };
|
||||
const struct rect slide_step_pedal = { 133, 92, 0, 0 };
|
||||
const struct rect radio_dial_ctr = { 205, 243, 0, 0 };
|
||||
const struct rect sight_change_ctr = { 123, 329, 0, 0 };
|
||||
const struct rect transmission_lever_ctr_R = { 44, 210, 0, 0 };
|
||||
const struct rect transmission_lever_ctr_N = { 44, 219, 0, 0 };
|
||||
const struct rect transmission_lever_ctr_1 = { 44, 228, 0, 0 };
|
||||
const struct rect transmission_lever_ctr_2 = { 44, 238, 0, 0 };
|
||||
const struct rect transmission_lever_ctr_3 = { 44, 248, 0, 0 };
|
||||
const struct rect transmission_lever_ctr_4 = { 44, 258, 0, 0 };
|
||||
const struct rect transmission_lever_ctr_5 = { 44, 268, 0, 0 };
|
||||
const struct rect filt_ctrl_sys_ctr = { 103, 194, 0, 0 };
|
||||
const struct rect oxygen_supply_system_ctr = { 112, 205, 0, 0 };
|
||||
const struct rect fuel_flow_rate_ctr = { 126, 188, 0, 0 };
|
||||
const struct rect buffer_material_ctr = { 135, 200, 0, 0 };
|
||||
const struct rect vt_location_measurement_ctr = { 145, 210, 0, 0 };
|
||||
const struct rect buttons[33] = {
|
||||
{ 350, 309, 11, 29 }, // SBC_BUTTON_MAIN_WEAPON
|
||||
{ 380, 308, 9, 35 }, // SBC_BUTTON_SUB_WEAPON
|
||||
{ 336, 316, 12, 12 }, // SBC_BUTTON_LOCK_ON
|
||||
{ 418, 263, 16, 15 }, // SBC_BUTTON_EJECT
|
||||
{ 418, 228, 16, 15 }, // SBC_BUTTON_COCKPIT_HATCH
|
||||
{ 418, 206, 16, 15 }, // SBC_BUTTON_IGNITION
|
||||
{ 418, 184, 16, 15 }, // SBC_BUTTON_START
|
||||
{ 339, 209, 22, 6 }, // SBC_BUTTON_OPEN_CLOSE
|
||||
{ 375, 209, 22, 6 }, // SBC_BUTTON_MAP_ZOOM_IN_OUT
|
||||
{ 339, 198, 22, 6 }, // SBC_BUTTON_MODE_SELECT
|
||||
{ 375, 198, 22, 6 }, // SBC_BUTTON_SUB_MONITOR_MODE_SELECT
|
||||
{ 339, 186, 22, 6 }, // SBC_BUTTON_ZOOM_IN
|
||||
{ 375, 186, 22, 6 }, // SBC_BUTTON_ZOOM_OUT
|
||||
{ 279, 274, 7, 13 }, // SBC_BUTTON_FSS
|
||||
{ 279, 252, 7, 13 }, // SBC_BUTTON_MANIPULATOR
|
||||
{ 279, 230, 7, 13 }, // SBC_BUTTON_LINE_COLOR_CHANGE
|
||||
{ 190, 204, 22, 6 }, // SBC_BUTTON_WASHING
|
||||
{ 223, 204, 22, 6 }, // SBC_BUTTON_EXTINGUISHER
|
||||
{ 256, 204, 22, 6 }, // SBC_BUTTON_CHAFF
|
||||
{ 268, 274, 7, 13 }, // SBC_BUTTON_TANK_DETACH
|
||||
{ 268, 252, 7, 13 }, // SBC_BUTTON_OVERRIDE
|
||||
{ 268, 230, 7, 13 }, // SBC_BUTTON_NIGHT_SCOPE
|
||||
{ 257, 274, 7, 13 }, // SBC_BUTTON_FUNC1
|
||||
{ 257, 252, 7, 13 }, // SBC_BUTTON_FUNC2
|
||||
{ 257, 230, 7, 13 }, // SBC_BUTTON_FUNC3
|
||||
{ 190, 189, 22, 6 }, // SBC_BUTTON_MAIN_WEAPON_CONTROL
|
||||
{ 223, 189, 22, 6 }, // SBC_BUTTON_SUB_WEAPON_CONTROL
|
||||
{ 256, 189, 22, 6 }, // SBC_BUTTON_MAGAZINE_CHANGE
|
||||
{ 181, 272, 7, 13 }, // SBC_BUTTON_COM1
|
||||
{ 192, 272, 7, 13 }, // SBC_BUTTON_COM2
|
||||
{ 202, 272, 7, 13 }, // SBC_BUTTON_COM3
|
||||
{ 213, 272, 7, 13 }, // SBC_BUTTON_COM4
|
||||
{ 223, 272, 7, 13 } // SBC_BUTTON_COM5
|
||||
};
|
||||
|
||||
glUseProgram(g_decal_shader->prog);
|
||||
glBindVertexArray(g_decal_shader->vao);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, g_sb_controller_tex);
|
||||
|
||||
// Add a 5 pixel space around the controller so we can wiggle the controller
|
||||
// around to visualize rumble in action
|
||||
frame_x += 5;
|
||||
frame_y += 5;
|
||||
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFunc(GL_ONE, GL_ZERO);
|
||||
|
||||
// Render controller texture
|
||||
RenderDecal(g_decal_shader, frame_x + 0, frame_y + 0,
|
||||
sb_tex_items[obj_controller].w, sb_tex_items[obj_controller].h,
|
||||
sb_tex_items[obj_controller].x, sb_tex_items[obj_controller].y,
|
||||
sb_tex_items[obj_controller].w, sb_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 < 33; i++) {
|
||||
if (state->sbc.buttons & (1ULL << 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);
|
||||
}
|
||||
}
|
||||
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Blend with controller
|
||||
|
||||
// Render sight change joystick
|
||||
float w = sb_tex_items[obj_sight_change_stick].w;
|
||||
float h = sb_tex_items[obj_sight_change_stick].h;
|
||||
float c_x = frame_x + sight_change_ctr.x;
|
||||
float c_y = frame_y + sight_change_ctr.y;
|
||||
float scstick_x = (float)state->sbc.axis[SBC_AXIS_SIGHT_CHANGE_X] / 32768.0;
|
||||
float scstick_y = (float)state->sbc.axis[SBC_AXIS_SIGHT_CHANGE_Y] / 32768.0;
|
||||
RenderDecal(
|
||||
g_decal_shader, (int)(c_x - w / 2.0f + 5.0f * scstick_x),
|
||||
(int)(c_y - h / 2.0f - 5.0f * scstick_y), w, h,
|
||||
sb_tex_items[obj_sight_change_stick].x,
|
||||
sb_tex_items[obj_sight_change_stick].y, w, h,
|
||||
(state->sbc.buttons & SBC_BUTTON_SIGHT_CHANGE) ? secondary_color :
|
||||
primary_color,
|
||||
(state->sbc.buttons & SBC_BUTTON_SIGHT_CHANGE) ? primary_color :
|
||||
secondary_color,
|
||||
0);
|
||||
|
||||
// Render left joystick
|
||||
w = sb_tex_items[obj_left_stick].w;
|
||||
h = sb_tex_items[obj_left_stick].h;
|
||||
c_x = frame_x + lstick_ctr.x;
|
||||
c_y = frame_y + lstick_ctr.y;
|
||||
float lstick_x = (float)state->sbc.axis[SBC_AXIS_ROTATION_LEVER] / 32768.0;
|
||||
RenderDecal(g_decal_shader, (int)(c_x - w / 2.0f + 23.0f * lstick_x),
|
||||
(int)(c_y - h / 2.0f), w, h, sb_tex_items[obj_left_stick].x,
|
||||
sb_tex_items[obj_left_stick].y, w, h, primary_color,
|
||||
secondary_color, 0);
|
||||
|
||||
// Render right joystick
|
||||
w = sb_tex_items[obj_right_stick].w;
|
||||
h = sb_tex_items[obj_right_stick].h;
|
||||
c_x = frame_x + rstick_ctr.x;
|
||||
c_y = frame_y + rstick_ctr.y;
|
||||
float rstick_x = (float)state->sbc.axis[SBC_AXIS_AIMING_X] / 32768.0;
|
||||
float rstick_y = (float)state->sbc.axis[SBC_AXIS_AIMING_Y] / 32768.0;
|
||||
RenderDecal(g_decal_shader, (int)(c_x - w / 2.0f + 23.0f * rstick_x),
|
||||
(int)(c_y - h / 2.0f - 20.0f * rstick_y), w, h,
|
||||
sb_tex_items[obj_right_stick].x,
|
||||
sb_tex_items[obj_right_stick].y, w, h, primary_color,
|
||||
secondary_color, 0);
|
||||
|
||||
// Render accel pedal
|
||||
w = sb_tex_items[obj_accel_pedal].w;
|
||||
h = sb_tex_items[obj_accel_pedal].h;
|
||||
c_x = frame_x + accel_pedal.x;
|
||||
c_y = frame_y + accel_pedal.y;
|
||||
RenderDecal(g_decal_shader, c_x,
|
||||
c_y + 10.0f * state->sbc.axis[SBC_AXIS_RIGHT_PEDAL] / 32768.0f,
|
||||
w, h, sb_tex_items[obj_accel_pedal].x,
|
||||
sb_tex_items[obj_accel_pedal].y, w, h, primary_color,
|
||||
secondary_color, 0);
|
||||
|
||||
// Brake accel pedal
|
||||
w = sb_tex_items[obj_brake_pedal].w;
|
||||
h = sb_tex_items[obj_brake_pedal].h;
|
||||
c_x = frame_x + brake_pedal.x;
|
||||
c_y = frame_y + brake_pedal.y;
|
||||
RenderDecal(g_decal_shader, c_x,
|
||||
c_y + 10.0f * state->sbc.axis[SBC_AXIS_MIDDLE_PEDAL] / 32768.0f,
|
||||
w, h, sb_tex_items[obj_brake_pedal].x,
|
||||
sb_tex_items[obj_brake_pedal].y, w, h, primary_color,
|
||||
secondary_color, 0);
|
||||
|
||||
// Slide step pedal
|
||||
w = sb_tex_items[obj_slide_step_pedal].w;
|
||||
h = sb_tex_items[obj_slide_step_pedal].h;
|
||||
c_x = frame_x + slide_step_pedal.x;
|
||||
c_y = frame_y + slide_step_pedal.y;
|
||||
RenderDecal(g_decal_shader, c_x,
|
||||
c_y + 10.0f * state->sbc.axis[SBC_AXIS_LEFT_PEDAL] / 32768.0f,
|
||||
w, h, sb_tex_items[obj_slide_step_pedal].x,
|
||||
sb_tex_items[obj_slide_step_pedal].y, w, h, primary_color,
|
||||
secondary_color, 0);
|
||||
|
||||
// Render the radio dial
|
||||
w = sb_tex_items[obj_radio_dial].w;
|
||||
h = sb_tex_items[obj_radio_dial].h;
|
||||
c_x = frame_x + radio_dial_ctr.x;
|
||||
c_y = frame_x + radio_dial_ctr.y;
|
||||
float tunerStep = 0.125f * 3.14159f;
|
||||
// TODO: Figure out a way to either rotate the decal or remove the dot and
|
||||
// move the dot based on current radio channel
|
||||
RenderDecal(
|
||||
g_decal_shader,
|
||||
(int)(c_x - w / 2.0f - 9 * cosf(tunerStep * state->sbc.tunerDial)),
|
||||
(int)(c_y - h / 2.0f + 11 * sinf(tunerStep * state->sbc.tunerDial)), w,
|
||||
h, sb_tex_items[obj_radio_dial].x, sb_tex_items[obj_radio_dial].y, w, h,
|
||||
primary_color, secondary_color, 0);
|
||||
|
||||
// Render the transmission lever
|
||||
w = sb_tex_items[obj_transmission_lever].w;
|
||||
h = sb_tex_items[obj_transmission_lever].h;
|
||||
c_x = frame_x + transmission_lever_ctr_1.x;
|
||||
c_y = frame_x + transmission_lever_ctr_1.y;
|
||||
switch (state->sbc.gearLever) {
|
||||
case 254:
|
||||
c_y = frame_y + transmission_lever_ctr_R.y;
|
||||
break;
|
||||
case 255:
|
||||
c_y = frame_y + transmission_lever_ctr_N.y;
|
||||
break;
|
||||
case 1:
|
||||
c_y = frame_y + transmission_lever_ctr_1.y;
|
||||
break;
|
||||
case 2:
|
||||
c_y = frame_y + transmission_lever_ctr_2.y;
|
||||
break;
|
||||
case 3:
|
||||
c_y = frame_y + transmission_lever_ctr_3.y;
|
||||
break;
|
||||
case 4:
|
||||
c_y = frame_y + transmission_lever_ctr_4.y;
|
||||
break;
|
||||
case 5:
|
||||
c_y = frame_y + transmission_lever_ctr_5.y;
|
||||
break;
|
||||
}
|
||||
// Determine the correct value for c_y based on the currently selected gear
|
||||
RenderDecal(g_decal_shader, (int)(c_x - w / 2.0f), (int)(c_y - h / 2.0f), w,
|
||||
h, sb_tex_items[obj_transmission_lever].x,
|
||||
sb_tex_items[obj_transmission_lever].y, w, h, primary_color,
|
||||
secondary_color, 0);
|
||||
|
||||
// Filter Control System
|
||||
w = sb_tex_items[obj_toggle].w;
|
||||
h = sb_tex_items[obj_toggle].h;
|
||||
c_x = frame_x + filt_ctrl_sys_ctr.x;
|
||||
c_y = frame_y + filt_ctrl_sys_ctr.y;
|
||||
if (state->sbc.toggleSwitches & (SBC_BUTTON_FILT_CONTROL_SYSTEM >> 32)) {
|
||||
c_x -= 3;
|
||||
c_y += 4;
|
||||
}
|
||||
RenderDecal(g_decal_shader, (int)(c_x - w / 2.0f), (int)(c_y - h / 2.0f), w,
|
||||
h, sb_tex_items[obj_toggle].x, sb_tex_items[obj_toggle].y, w, h,
|
||||
primary_color, secondary_color, 0);
|
||||
|
||||
// Oxygen Supply System
|
||||
w = sb_tex_items[obj_toggle].w;
|
||||
h = sb_tex_items[obj_toggle].h;
|
||||
c_x = frame_x + oxygen_supply_system_ctr.x;
|
||||
c_y = frame_y + oxygen_supply_system_ctr.y;
|
||||
if (state->sbc.toggleSwitches & (SBC_BUTTON_OXYGEN_SUPPLY_SYSTEM >> 32)) {
|
||||
c_x -= 3;
|
||||
c_y += 4;
|
||||
}
|
||||
RenderDecal(g_decal_shader, (int)(c_x - w / 2.0f), (int)(c_y - h / 2.0f), w,
|
||||
h, sb_tex_items[obj_toggle].x, sb_tex_items[obj_toggle].y, w, h,
|
||||
primary_color, secondary_color, 0);
|
||||
|
||||
// Fuel Flow Rate
|
||||
w = sb_tex_items[obj_toggle].w;
|
||||
h = sb_tex_items[obj_toggle].h;
|
||||
c_x = frame_x + fuel_flow_rate_ctr.x;
|
||||
c_y = frame_y + fuel_flow_rate_ctr.y;
|
||||
if (state->sbc.toggleSwitches & (SBC_BUTTON_FUEL_FLOW_RATE >> 32)) {
|
||||
c_x -= 3;
|
||||
c_y += 4;
|
||||
}
|
||||
RenderDecal(g_decal_shader, (int)(c_x - w / 2.0f), (int)(c_y - h / 2.0f), w,
|
||||
h, sb_tex_items[obj_toggle].x, sb_tex_items[obj_toggle].y, w, h,
|
||||
primary_color, secondary_color, 0);
|
||||
|
||||
// Buffer Material
|
||||
w = sb_tex_items[obj_toggle].w;
|
||||
h = sb_tex_items[obj_toggle].h;
|
||||
c_x = frame_x + buffer_material_ctr.x;
|
||||
c_y = frame_y + buffer_material_ctr.y;
|
||||
if (state->sbc.toggleSwitches & (SBC_BUTTON_BUFFER_MATERIAL >> 32)) {
|
||||
c_x -= 3;
|
||||
c_y += 4;
|
||||
}
|
||||
RenderDecal(g_decal_shader, (int)(c_x - w / 2.0f), (int)(c_y - h / 2.0f), w,
|
||||
h, sb_tex_items[obj_toggle].x, sb_tex_items[obj_toggle].y, w, h,
|
||||
primary_color, secondary_color, 0);
|
||||
|
||||
// VT Location Measurement
|
||||
w = sb_tex_items[obj_toggle].w;
|
||||
h = sb_tex_items[obj_toggle].h;
|
||||
c_x = frame_x + vt_location_measurement_ctr.x;
|
||||
c_y = frame_y + vt_location_measurement_ctr.y;
|
||||
if (state->sbc.toggleSwitches &
|
||||
(SBC_BUTTON_VT_LOCATION_MEASUREMENT >> 32)) {
|
||||
c_x -= 3;
|
||||
c_y += 4;
|
||||
}
|
||||
RenderDecal(g_decal_shader, (int)(c_x - w / 2.0f), (int)(c_y - h / 2.0f), w,
|
||||
h, sb_tex_items[obj_toggle].x, sb_tex_items[obj_toggle].y, w, h,
|
||||
primary_color, secondary_color, 0);
|
||||
|
||||
glBlendFunc(GL_ONE,
|
||||
GL_ZERO); // Don't blend, just overwrite values in buffer
|
||||
|
||||
glBindVertexArray(0);
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
void RenderDVDRemote(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 dvd_buttons[] = {
|
||||
{ 108, 248, 20, 10 }, // UP
|
||||
{ 78, 226, 20, 10 }, // LEFT
|
||||
{ 106, 225, 24, 11 }, // SELECT
|
||||
{ 139, 226, 19, 11 }, // RIGHT
|
||||
{ 109, 203, 19, 11 }, // DOWN
|
||||
{ 106, 326, 24, 11 }, // DISPLAY
|
||||
{ 74, 300, 24, 11 }, // REVERSE
|
||||
{ 106, 300, 24, 11 }, // PLAY
|
||||
{ 139, 300, 24, 11 }, // FORWARD
|
||||
{ 74, 274, 11, 11 }, // SKIP-
|
||||
{ 100, 274, 11, 11 }, // STOP
|
||||
{ 126, 274, 11, 11 }, // PAUSE
|
||||
{ 152, 274, 11, 11 }, // SKIP+
|
||||
{ 74, 248, 11, 11 }, // TITLE
|
||||
{ 152, 248, 11, 11 }, // INFO
|
||||
{ 74, 202, 11, 12 }, // MENU
|
||||
{ 152, 202, 11, 12 }, // BACK
|
||||
{ 80, 176, 11, 12 }, // 1
|
||||
{ 113, 176, 11, 12 }, // 2
|
||||
{ 145, 176, 11, 12 }, // 3
|
||||
{ 80, 154, 11, 11 }, // 4
|
||||
{ 113, 154, 11, 11 }, // 5
|
||||
{ 145, 154, 11, 11 }, // 6
|
||||
{ 80, 131, 11, 11 }, // 7
|
||||
{ 113, 131, 11, 11 }, // 8
|
||||
{ 145, 131, 11, 11 }, // 9
|
||||
{ 113, 108, 11, 11 }, // 0
|
||||
};
|
||||
const struct rect mce_buttons[] = {
|
||||
{ 339, 267, 16, 8 }, // UP
|
||||
{ 312, 251, 16, 8 }, // LEFT
|
||||
{ 337, 251, 21, 8 }, // SELECT -> OK
|
||||
{ 366, 251, 16, 8 }, // RIGHT
|
||||
{ 339, 235, 16, 8 }, // DOWN
|
||||
{ 340, 40, 14, 8 }, // DISPLAY -> XBOX
|
||||
{ 298, 306, 8, 8 }, // REVERSE -> REW
|
||||
{ 340, 290, 14,15 }, // PLAY
|
||||
{ 389, 306, 8, 8 }, // FORWARD -> FWD
|
||||
{ 320, 290, 8, 8 }, // SKIP- -> REPLAY
|
||||
{ 343, 313, 8, 8 }, // STOP
|
||||
{ 366, 306, 8, 8 }, // PAUSE
|
||||
{ 366, 290, 8, 8 }, // SKIP+ -> SKIP
|
||||
{ 327, 173, 11, 8 }, // TITLE -> GUIDE
|
||||
{ 385, 271, 8, 8 }, // INFO -> MORE
|
||||
{ 382, 176, 11, 8 }, // MENU -> DVD MENU
|
||||
{ 301, 271, 8, 8 }, // BACK
|
||||
{ 307, 154, 15, 8 }, // 1
|
||||
{ 340, 154, 15, 8 }, // 2
|
||||
{ 372, 154, 15, 8 }, // 3
|
||||
{ 307, 134, 15, 8 }, // 4
|
||||
{ 340, 134, 15, 8 }, // 5
|
||||
{ 372, 134, 15, 8 }, // 6
|
||||
{ 307, 115, 15, 8 }, // 7
|
||||
{ 340, 115, 15, 8 }, // 8
|
||||
{ 372, 115, 15, 8 }, // 9
|
||||
{ 340, 95, 15, 8 }, // 0
|
||||
{ 395, 342, 8, 8 }, // POWER
|
||||
{ 301, 323, 8, 8 }, // MY_TV
|
||||
{ 327, 332, 8, 8 }, // MY_MUSIC
|
||||
{ 359, 332, 8, 8 }, // MY_PICTURES
|
||||
{ 385, 323, 8, 8 }, // MY_VIDEOS
|
||||
{ 320, 306, 8, 8 }, // RECORD
|
||||
{ 337, 215, 21, 8 }, // START
|
||||
{ 298, 225, 21, 8 }, // VOL_UP
|
||||
{ 304, 206, 21, 8 }, // VOL_DOWN
|
||||
{ 337, 196, 21, 8 }, // MUTE
|
||||
{ 376, 225, 21, 8 }, // CH_UP
|
||||
{ 369, 206, 21, 8 }, // CH_DOWN
|
||||
{ 301, 176, 11, 8 }, // RECORDED_TV
|
||||
{ 356, 173, 11, 8 }, // LIVE_TV
|
||||
{ 307, 95, 15, 8 }, // STAR
|
||||
{ 372, 95, 15, 8 }, // POUND
|
||||
{ 327, 72, 11, 8 }, // CLEAR
|
||||
};
|
||||
const struct rect mce_enter_button =
|
||||
{ 356, 72, 11, 8 }; // ENTER
|
||||
|
||||
glUseProgram(g_decal_shader->prog);
|
||||
glBindVertexArray(g_decal_shader->vao);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, g_dvd_remote_tex);
|
||||
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFunc(GL_ONE, GL_ZERO);
|
||||
|
||||
// Render controller texture
|
||||
RenderDecal(g_decal_shader, frame_x + 0, frame_y + 0,
|
||||
tex_items[obj_controller].w, tex_items[obj_controller].h,
|
||||
tex_items[obj_controller].x, tex_items[obj_controller].y,
|
||||
tex_items[obj_controller].w, 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 < sizeof(dvd_buttons) / sizeof(dvd_buttons[0]); i++) {
|
||||
if (state->dvdKit.buttons & (1ULL << i)) {
|
||||
RenderDecal(g_decal_shader, frame_x + dvd_buttons[i].x,
|
||||
frame_y + dvd_buttons[i].y, dvd_buttons[i].w, dvd_buttons[i].h, 0,
|
||||
0, 1, 1, 0, 0, primary_color + 0xff);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < sizeof(mce_buttons) / sizeof(mce_buttons[0]); i++) {
|
||||
if (state->dvdKit.buttons & (1ULL << i)) {
|
||||
RenderDecal(g_decal_shader, frame_x + mce_buttons[i].x,
|
||||
frame_y + mce_buttons[i].y, mce_buttons[i].w, mce_buttons[i].h, 0,
|
||||
0, 1, 1, 0, 0, primary_color + 0xff);
|
||||
}
|
||||
}
|
||||
if (state->dvdKit.buttons & DVD_BUTTON_SELECT) {
|
||||
RenderDecal(g_decal_shader, frame_x + mce_enter_button.x,
|
||||
frame_y + mce_enter_button.y, mce_enter_button.w, mce_enter_button.h, 0,
|
||||
0, 1, 1, 0, 0, primary_color + 0xff);
|
||||
}
|
||||
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Blend with controller
|
||||
|
||||
glBindVertexArray(0);
|
||||
glUseProgram(0);
|
||||
|
@ -799,9 +1253,14 @@ void RenderController(float frame_x, float frame_y, uint32_t primary_color,
|
|||
if (strcmp(bound_drivers[state->bound], DRIVER_S) == 0)
|
||||
RenderControllerS(frame_x, frame_y, primary_color, secondary_color,
|
||||
state);
|
||||
if (strcmp(bound_drivers[state->bound], DRIVER_STEEL_BATTALION) == 0)
|
||||
RenderSteelBattalionController(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);
|
||||
else if (strcmp(bound_drivers[state->bound], DRIVER_DVD_PLAYBACK_KIT) == 0)
|
||||
RenderDVDRemote(frame_x, frame_y, primary_color, secondary_color, state);
|
||||
}
|
||||
|
||||
void RenderControllerPort(float frame_x, float frame_y, int i,
|
||||
|
@ -933,6 +1392,7 @@ void RenderFramebuffer(GLint tex, int width, int height, bool flip)
|
|||
{
|
||||
int tw, th;
|
||||
float scale[2];
|
||||
int viewport_width, viewport_height;
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, tex);
|
||||
|
@ -961,6 +1421,14 @@ void RenderFramebuffer(GLint tex, int width, int height, bool flip)
|
|||
}
|
||||
}
|
||||
|
||||
viewport_width = (int)(width * scale[0]);
|
||||
viewport_height = (int)(height * scale[1]);
|
||||
|
||||
viewport_coords[0] = (width - viewport_width) / 2;
|
||||
viewport_coords[1] = (height - viewport_height) / 2;
|
||||
viewport_coords[2] = viewport_width;
|
||||
viewport_coords[3] = viewport_height;
|
||||
|
||||
RenderFramebuffer(tex, width, height, flip, scale);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,11 +21,11 @@ void InputManager::Update()
|
|||
ControllerState *iter;
|
||||
QTAILQ_FOREACH(iter, &available_controllers, entry) {
|
||||
if (iter->type != INPUT_DEVICE_SDL_GAMECONTROLLER) continue;
|
||||
m_buttons |= iter->buttons;
|
||||
m_buttons |= iter->gp.buttons;
|
||||
// We simply take any axis that is >10 % activation
|
||||
for (int i = 0; i < CONTROLLER_AXIS__COUNT; i++) {
|
||||
if ((iter->axis[i] > 3276) || (iter->axis[i] < -3276)) {
|
||||
axis[i] = iter->axis[i];
|
||||
if ((iter->gp.axis[i] > 3276) || (iter->gp.axis[i] < -3276)) {
|
||||
axis[i] = iter->gp.axis[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -172,14 +172,25 @@ 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_STEEL_BATTALION) == 0)
|
||||
driver = DRIVER_STEEL_BATTALION_DISPLAY_NAME;
|
||||
else if (strcmp(driver, DRIVER_DVD_PLAYBACK_KIT) == 0)
|
||||
driver = DRIVER_DVD_PLAYBACK_KIT_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[] = {
|
||||
DRIVER_DUKE_DISPLAY_NAME,
|
||||
DRIVER_S_DISPLAY_NAME
|
||||
const char *available_drivers[] = {
|
||||
DRIVER_DUKE,
|
||||
DRIVER_S,
|
||||
DRIVER_STEEL_BATTALION,
|
||||
DRIVER_DVD_PLAYBACK_KIT
|
||||
};
|
||||
const char *driver_display_names[] = {
|
||||
DRIVER_DUKE_DISPLAY_NAME,
|
||||
DRIVER_S_DISPLAY_NAME,
|
||||
DRIVER_STEEL_BATTALION_DISPLAY_NAME,
|
||||
DRIVER_DVD_PLAYBACK_KIT_DISPLAY_NAME
|
||||
};
|
||||
bool is_selected = false;
|
||||
int num_drivers = sizeof(driver_display_names) / sizeof(driver_display_names[0]);
|
||||
|
@ -324,162 +335,183 @@ void MainMenuInputView::Draw()
|
|||
ImGui::SetCursorPos(pos);
|
||||
|
||||
if (bound_state) {
|
||||
SectionTitle("Expansion Slots");
|
||||
// Begin a 2-column layout to render the expansion slots
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,
|
||||
g_viewport_mgr.Scale(ImVec2(0, 12)));
|
||||
ImGui::Columns(2, "mixed", false);
|
||||
bool hasInternalHub = strcmp(bound_drivers[active], DRIVER_STEEL_BATTALION) != 0
|
||||
&& strcmp(bound_drivers[active], DRIVER_DVD_PLAYBACK_KIT) != 0;
|
||||
bool hasFirmware = strcmp(bound_drivers[active], DRIVER_DVD_PLAYBACK_KIT) == 0;
|
||||
if (hasInternalHub) {
|
||||
SectionTitle("Expansion Slots");
|
||||
// Begin a 2-column layout to render the expansion slots
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,
|
||||
g_viewport_mgr.Scale(ImVec2(0, 12)));
|
||||
ImGui::Columns(2, "mixed", false);
|
||||
|
||||
xmu_fbo->Target();
|
||||
id = (ImTextureID)(intptr_t)xmu_fbo->Texture();
|
||||
xmu_fbo->Target();
|
||||
id = (ImTextureID)(intptr_t)xmu_fbo->Texture();
|
||||
|
||||
const char *img_file_filters = ".img Files\0*.img\0All Files\0*.*\0";
|
||||
const char *comboLabels[2] = { "###ExpansionSlotA",
|
||||
"###ExpansionSlotB" };
|
||||
for (int i = 0; i < 2; i++) {
|
||||
// Display a combo box to allow the user to choose the type of
|
||||
// peripheral they want to use
|
||||
enum peripheral_type selected_type =
|
||||
bound_state->peripheral_types[i];
|
||||
const char *peripheral_type_names[2] = { "None", "Memory Unit" };
|
||||
const char *selected_peripheral_type =
|
||||
peripheral_type_names[selected_type];
|
||||
ImGui::SetNextItemWidth(-FLT_MIN);
|
||||
if (ImGui::BeginCombo(comboLabels[i], selected_peripheral_type,
|
||||
ImGuiComboFlags_NoArrowButton)) {
|
||||
// Handle all available peripheral types
|
||||
for (int j = 0; j < 2; j++) {
|
||||
bool is_selected = selected_type == j;
|
||||
ImGui::PushID(j);
|
||||
const char *selectable_label = peripheral_type_names[j];
|
||||
const char *img_file_filters = ".img Files\0*.img\0All Files\0*.*\0";
|
||||
const char *comboLabels[2] = { "###ExpansionSlotA",
|
||||
"###ExpansionSlotB" };
|
||||
for (int i = 0; i < 2; i++) {
|
||||
// Display a combo box to allow the user to choose the type of
|
||||
// peripheral they want to use
|
||||
enum peripheral_type selected_type =
|
||||
bound_state->peripheral_types[i];
|
||||
const char *peripheral_type_names[2] = { "None", "Memory Unit" };
|
||||
const char *selected_peripheral_type =
|
||||
peripheral_type_names[selected_type];
|
||||
ImGui::SetNextItemWidth(-FLT_MIN);
|
||||
if (ImGui::BeginCombo(comboLabels[i], selected_peripheral_type,
|
||||
ImGuiComboFlags_NoArrowButton)) {
|
||||
// Handle all available peripheral types
|
||||
for (int j = 0; j < 2; j++) {
|
||||
bool is_selected = selected_type == j;
|
||||
ImGui::PushID(j);
|
||||
const char *selectable_label = peripheral_type_names[j];
|
||||
|
||||
if (ImGui::Selectable(selectable_label, is_selected)) {
|
||||
// Free any existing peripheral
|
||||
if (bound_state->peripherals[i] != NULL) {
|
||||
if (bound_state->peripheral_types[i] ==
|
||||
PERIPHERAL_XMU) {
|
||||
// Another peripheral was already bound.
|
||||
// Unplugging
|
||||
xemu_input_unbind_xmu(active, i);
|
||||
if (ImGui::Selectable(selectable_label, is_selected)) {
|
||||
// Free any existing peripheral
|
||||
if (bound_state->peripherals[i] != NULL) {
|
||||
if (bound_state->peripheral_types[i] ==
|
||||
PERIPHERAL_XMU) {
|
||||
// Another peripheral was already bound.
|
||||
// Unplugging
|
||||
xemu_input_unbind_xmu(active, i);
|
||||
}
|
||||
|
||||
// Free the existing state
|
||||
g_free((void *)bound_state->peripherals[i]);
|
||||
bound_state->peripherals[i] = NULL;
|
||||
}
|
||||
|
||||
// Free the existing state
|
||||
g_free((void *)bound_state->peripherals[i]);
|
||||
bound_state->peripherals[i] = NULL;
|
||||
// Change the peripheral type to the newly selected type
|
||||
bound_state->peripheral_types[i] =
|
||||
(enum peripheral_type)j;
|
||||
|
||||
// Allocate state for the new peripheral
|
||||
if (j == PERIPHERAL_XMU) {
|
||||
bound_state->peripherals[i] =
|
||||
g_malloc(sizeof(XmuState));
|
||||
memset(bound_state->peripherals[i], 0,
|
||||
sizeof(XmuState));
|
||||
}
|
||||
|
||||
xemu_save_peripheral_settings(
|
||||
active, i, bound_state->peripheral_types[i], NULL);
|
||||
}
|
||||
|
||||
// Change the peripheral type to the newly selected type
|
||||
bound_state->peripheral_types[i] =
|
||||
(enum peripheral_type)j;
|
||||
|
||||
// Allocate state for the new peripheral
|
||||
if (j == PERIPHERAL_XMU) {
|
||||
bound_state->peripherals[i] =
|
||||
g_malloc(sizeof(XmuState));
|
||||
memset(bound_state->peripherals[i], 0,
|
||||
sizeof(XmuState));
|
||||
if (is_selected) {
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
|
||||
xemu_save_peripheral_settings(
|
||||
active, i, bound_state->peripheral_types[i], NULL);
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
if (is_selected) {
|
||||
ImGui::SetItemDefaultFocus();
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
DrawComboChevron();
|
||||
|
||||
// Set an X offset to center the image button within the column
|
||||
ImGui::SetCursorPosX(
|
||||
ImGui::GetCursorPosX() +
|
||||
(int)((ImGui::GetColumnWidth() -
|
||||
xmu_w * g_viewport_mgr.m_scale -
|
||||
2 * port_padding * g_viewport_mgr.m_scale) /
|
||||
2));
|
||||
|
||||
selected_type = bound_state->peripheral_types[i];
|
||||
if (selected_type == PERIPHERAL_XMU) {
|
||||
float x = xmu_x + i * xmu_x_stride;
|
||||
float y = xmu_y;
|
||||
|
||||
XmuState *xmu = (XmuState *)bound_state->peripherals[i];
|
||||
if (xmu->filename != NULL && strlen(xmu->filename) > 0) {
|
||||
RenderXmu(x, y, 0x81dc8a00, 0x0f0f0f00);
|
||||
|
||||
} else {
|
||||
RenderXmu(x, y, 0x1f1f1f00, 0x0f0f0f00);
|
||||
}
|
||||
|
||||
ImVec2 xmu_display_size;
|
||||
if (ImGui::GetContentRegionMax().x <
|
||||
xmu_h * g_viewport_mgr.m_scale) {
|
||||
xmu_display_size.x = ImGui::GetContentRegionMax().x / 2;
|
||||
xmu_display_size.y = xmu_display_size.x * xmu_h / xmu_w;
|
||||
} else {
|
||||
xmu_display_size = ImVec2(xmu_w * g_viewport_mgr.m_scale,
|
||||
xmu_h * g_viewport_mgr.m_scale);
|
||||
}
|
||||
|
||||
ImGui::SetCursorPosX(
|
||||
ImGui::GetCursorPosX() +
|
||||
(int)((ImGui::GetColumnWidth() - xmu_display_size.x) /
|
||||
2.0));
|
||||
|
||||
ImGui::Image(id, xmu_display_size, ImVec2(0.5f * i, 1),
|
||||
ImVec2(0.5f * (i + 1), 0));
|
||||
ImVec2 pos = ImGui::GetCursorPos();
|
||||
|
||||
ImGui::SetCursorPos(pos);
|
||||
|
||||
// Button to generate a new XMU
|
||||
ImGui::PushID(i);
|
||||
if (ImGui::Button("New Image", ImVec2(250, 0))) {
|
||||
int flags = NOC_FILE_DIALOG_SAVE |
|
||||
NOC_FILE_DIALOG_OVERWRITE_CONFIRMATION;
|
||||
const char *new_path = PausedFileOpen(
|
||||
flags, img_file_filters, NULL, "xmu.img");
|
||||
|
||||
if (new_path) {
|
||||
if (create_fatx_image(new_path, DEFAULT_XMU_SIZE)) {
|
||||
// XMU was created successfully. Bind it
|
||||
xemu_input_bind_xmu(active, i, new_path, false);
|
||||
} else {
|
||||
// Show alert message
|
||||
char *msg = g_strdup_printf(
|
||||
"Unable to create XMU image at %s", new_path);
|
||||
xemu_queue_error_message(msg);
|
||||
g_free(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char *xmu_port_path = NULL;
|
||||
if (xmu->filename == NULL)
|
||||
xmu_port_path = g_strdup("");
|
||||
else
|
||||
xmu_port_path = g_strdup(xmu->filename);
|
||||
if (FilePicker("Image", &xmu_port_path, img_file_filters)) {
|
||||
if (strlen(xmu_port_path) == 0) {
|
||||
xemu_input_unbind_xmu(active, i);
|
||||
} else {
|
||||
xemu_input_bind_xmu(active, i, xmu_port_path, false);
|
||||
}
|
||||
}
|
||||
g_free((void *)xmu_port_path);
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
DrawComboChevron();
|
||||
|
||||
// Set an X offset to center the image button within the column
|
||||
ImGui::SetCursorPosX(
|
||||
ImGui::GetCursorPosX() +
|
||||
(int)((ImGui::GetColumnWidth() -
|
||||
xmu_w * g_viewport_mgr.m_scale -
|
||||
2 * port_padding * g_viewport_mgr.m_scale) /
|
||||
2));
|
||||
|
||||
selected_type = bound_state->peripheral_types[i];
|
||||
if (selected_type == PERIPHERAL_XMU) {
|
||||
float x = xmu_x + i * xmu_x_stride;
|
||||
float y = xmu_y;
|
||||
|
||||
XmuState *xmu = (XmuState *)bound_state->peripherals[i];
|
||||
if (xmu->filename != NULL && strlen(xmu->filename) > 0) {
|
||||
RenderXmu(x, y, 0x81dc8a00, 0x0f0f0f00);
|
||||
|
||||
} else {
|
||||
RenderXmu(x, y, 0x1f1f1f00, 0x0f0f0f00);
|
||||
}
|
||||
|
||||
ImVec2 xmu_display_size;
|
||||
if (ImGui::GetContentRegionMax().x <
|
||||
xmu_h * g_viewport_mgr.m_scale) {
|
||||
xmu_display_size.x = ImGui::GetContentRegionMax().x / 2;
|
||||
xmu_display_size.y = xmu_display_size.x * xmu_h / xmu_w;
|
||||
} else {
|
||||
xmu_display_size = ImVec2(xmu_w * g_viewport_mgr.m_scale,
|
||||
xmu_h * g_viewport_mgr.m_scale);
|
||||
}
|
||||
|
||||
ImGui::SetCursorPosX(
|
||||
ImGui::GetCursorPosX() +
|
||||
(int)((ImGui::GetColumnWidth() - xmu_display_size.x) /
|
||||
2.0));
|
||||
|
||||
ImGui::Image(id, xmu_display_size, ImVec2(0.5f * i, 1),
|
||||
ImVec2(0.5f * (i + 1), 0));
|
||||
|
||||
// Button to generate a new XMU
|
||||
ImGui::PushID(i);
|
||||
if (ImGui::Button("New Image", ImVec2(250, 0))) {
|
||||
int flags = NOC_FILE_DIALOG_SAVE |
|
||||
NOC_FILE_DIALOG_OVERWRITE_CONFIRMATION;
|
||||
const char *new_path = PausedFileOpen(
|
||||
flags, img_file_filters, NULL, "xmu.img");
|
||||
|
||||
if (new_path) {
|
||||
if (create_fatx_image(new_path, DEFAULT_XMU_SIZE)) {
|
||||
// XMU was created successfully. Bind it
|
||||
xemu_input_bind_xmu(active, i, new_path, false);
|
||||
} else {
|
||||
// Show alert message
|
||||
char *msg = g_strdup_printf(
|
||||
"Unable to create XMU image at %s", new_path);
|
||||
xemu_queue_error_message(msg);
|
||||
g_free(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char *xmu_port_path = NULL;
|
||||
if (xmu->filename == NULL)
|
||||
xmu_port_path = g_strdup("");
|
||||
else
|
||||
xmu_port_path = g_strdup(xmu->filename);
|
||||
if (FilePicker("Image", &xmu_port_path, img_file_filters)) {
|
||||
if (strlen(xmu_port_path) == 0) {
|
||||
xemu_input_unbind_xmu(active, i);
|
||||
} else {
|
||||
xemu_input_bind_xmu(active, i, xmu_port_path, false);
|
||||
}
|
||||
}
|
||||
g_free((void *)xmu_port_path);
|
||||
|
||||
ImGui::PopID();
|
||||
ImGui::NextColumn();
|
||||
}
|
||||
|
||||
ImGui::NextColumn();
|
||||
xmu_fbo->Restore();
|
||||
|
||||
ImGui::PopStyleVar(); // ItemSpacing
|
||||
ImGui::Columns(1);
|
||||
}
|
||||
if (hasFirmware) {
|
||||
SectionTitle("Firmware");
|
||||
const char *firmware_filters = ".bin Files\0*.bin\0All Files\0*.*\0";
|
||||
const char *firmware_path = NULL;
|
||||
if (bound_state->dvdKit.firmware == NULL)
|
||||
firmware_path = g_strdup("");
|
||||
else
|
||||
firmware_path = g_strdup(bound_state->dvdKit.firmware);
|
||||
if (FilePicker("DVD Kit Firmware", &firmware_path, firmware_filters)) {
|
||||
xemu_save_dvd_firmware_settings(active, firmware_path);
|
||||
}
|
||||
g_free((void *)firmware_path);
|
||||
}
|
||||
|
||||
xmu_fbo->Restore();
|
||||
|
||||
ImGui::PopStyleVar(); // ItemSpacing
|
||||
ImGui::Columns(1);
|
||||
}
|
||||
|
||||
SectionTitle("Options");
|
||||
|
|
|
@ -286,9 +286,7 @@ void xemu_hud_render(void)
|
|||
g_scene_mgr.PushScene(g_main_menu);
|
||||
} else if (ImGui::IsKeyPressed(ImGuiKey_F2)) {
|
||||
g_scene_mgr.PushScene(g_popup_menu);
|
||||
} else if (menu_button ||
|
||||
(ImGui::IsMouseClicked(ImGuiMouseButton_Right) &&
|
||||
!ImGui::IsAnyItemFocused() && !ImGui::IsAnyItemHovered())) {
|
||||
} else if (menu_button) {
|
||||
g_scene_mgr.PushScene(g_popup_menu);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue