Add Steel battalion controller support to input gui

This commit is contained in:
ergo720 2021-02-07 20:02:32 +01:00
parent 689e3ca93c
commit 6a54aa5573
21 changed files with 1064 additions and 1090 deletions

View File

@ -471,22 +471,35 @@ bool Settings::LoadConfig()
// ==== Input Port End ==============
// ==== Input Profile Begin ====
std::array<std::vector<std::string>, to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX)> control_names;
std::array<std::vector<std::string>, to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX)> control_names;
for (int device = 0; device < to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX); device++) {
if (dev_num_buttons[device] == 0) {
int num_buttons = dev_num_buttons[device];
if (num_buttons == 0) {
continue;
}
for (int i = 0; i < dev_num_buttons[device]; i++) {
char control_name[30];
std::sprintf(control_name, sect_input_profiles.control, button_xbox_ctrl_names[i][0]);
control_names[device].push_back(control_name);
auto &lambda = [&control_names, &device](int num_buttons, const char *const ctrl_names[]) {
for (int i = 0; i < num_buttons; i++) {
char control_name[BUF_NAME_LENGTH];
std::sprintf(control_name, sect_input_profiles.control, ctrl_names[i]);
control_names[device].push_back(control_name);
}
};
switch (num_buttons)
{
case XBOX_CTRL_NUM_BUTTONS:
lambda(XBOX_CTRL_NUM_BUTTONS, button_xbox_ctrl_names);
break;
case SBC_NUM_BUTTONS:
lambda(SBC_NUM_BUTTONS, button_sbc_names);
break;
}
}
// TODO: add the control names of the other devices
index = 0;
while (true) {
std::string current_section = std::string(section_input_profiles) + std::to_string(index);
@ -621,19 +634,32 @@ bool Settings::Save(std::string file_path)
std::array<std::vector<std::string>, to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX)> control_names;
for (int device = 0; device < to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX); device++) {
if (dev_num_buttons[device] == 0) {
int num_buttons = dev_num_buttons[device];
if (num_buttons == 0) {
continue;
}
for (int i = 0; i < dev_num_buttons[device]; i++) {
char control_name[30];
std::sprintf(control_name, sect_input_profiles.control, button_xbox_ctrl_names[i][0]);
control_names[device].push_back(control_name);
auto &lambda = [&control_names, &device](int num_buttons, const char *const ctrl_names[]) {
for (int i = 0; i < num_buttons; i++) {
char control_name[BUF_NAME_LENGTH];
std::sprintf(control_name, sect_input_profiles.control, ctrl_names[i]);
control_names[device].push_back(control_name);
}
};
switch (num_buttons)
{
case XBOX_CTRL_NUM_BUTTONS:
lambda(XBOX_CTRL_NUM_BUTTONS, button_xbox_ctrl_names);
break;
case SBC_NUM_BUTTONS:
lambda(SBC_NUM_BUTTONS, button_sbc_names);
break;
}
}
// TODO: add the control names of the other devices
int profile_num = 0;
for (int i = 0; i < to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX); i++) {
size_t vec_size = m_input_profiles[i].size();
@ -713,7 +739,7 @@ void Settings::SyncToEmulator()
// register Network settings
g_EmuShared->SetNetworkSettings(&m_network);
// register input settings
// register Input settings
for (int i = 0; i < 4; i++) {
g_EmuShared->SetInputDevTypeSettings(&m_input_port[i].Type, i);
if (m_input_port[i].Type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) {
@ -726,11 +752,11 @@ void Settings::SyncToEmulator()
return false;
});
if (it != m_input_profiles[m_input_port[i].Type].end()) {
char controls_name[XBOX_CTRL_NUM_BUTTONS][30];
char controls_name[HIGHEST_NUM_BUTTONS][30];
for (int index = 0; index < dev_num_buttons[m_input_port[i].Type]; index++) {
strncpy(controls_name[index], it->ControlList[index].c_str(), 30);
}
g_EmuShared->SetInputBindingsSettings(controls_name, XBOX_CTRL_NUM_BUTTONS, i);
g_EmuShared->SetInputBindingsSettings(controls_name, dev_num_buttons[m_input_port[i].Type], i);
}
}
}

View File

@ -51,27 +51,22 @@ void Button::GetText(char* const text, size_t size) const
SendMessage(m_button_hwnd, WM_GETTEXT, size, reinterpret_cast<LPARAM>(text));
}
std::string Button::GetName(int api, int idx) const
{
assert(api == XINPUT_DEFAULT || api == DINPUT_DEFAULT);
return button_xbox_ctrl_names[idx][api];
}
LRESULT CALLBACK ButtonSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
LRESULT CALLBACK ButtonDukeSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
switch (uMsg)
{
// Remove the window subclass when this window is destroyed
case WM_NCDESTROY: {
RemoveWindowSubclass(hWnd, ButtonSubclassProc, uIdSubclass);
RemoveWindowSubclass(hWnd, ButtonDukeSubclassProc, uIdSubclass);
}
break;
case WM_RBUTTONDOWN: {
reinterpret_cast<Button*>(dwRefData)->ClearText();
g_InputWindow->UpdateProfile(std::string(), BUTTON_CLEAR);
if (reinterpret_cast<Button*>(dwRefData)->GetId() == IDC_SET_MOTOR) {
g_InputWindow->UpdateProfile(std::string(), RUMBLE_CLEAR);
Button *button = reinterpret_cast<Button *>(dwRefData);
button->ClearText();
static_cast<DukeInputWindow *>(button->GetWnd())->UpdateProfile(std::string(), BUTTON_CLEAR);
if (button->GetId() == IDC_SET_MOTOR) {
static_cast<DukeInputWindow *>(button->GetWnd())->UpdateProfile(std::string(), RUMBLE_CLEAR);
}
}
break;
@ -80,3 +75,25 @@ LRESULT CALLBACK ButtonSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
LRESULT CALLBACK ButtonSbcSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
switch (uMsg)
{
// Remove the window subclass when this window is destroyed
case WM_NCDESTROY: {
RemoveWindowSubclass(hWnd, ButtonSbcSubclassProc, uIdSubclass);
}
break;
case WM_RBUTTONDOWN: {
Button *button = reinterpret_cast<Button *>(dwRefData);
button->ClearText();
static_cast<SbcInputWindow *>(button->GetWnd())->UpdateProfile(std::string(), BUTTON_CLEAR);
}
break;
}
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}

View File

@ -32,7 +32,7 @@
#include <string>
#define XBOX_CTRL_NUM_BUTTONS 25
#define SBC_NUM_BUTTONS 65
#define SBC_NUM_BUTTONS 56
#define HIGHEST_NUM_BUTTONS SBC_NUM_BUTTONS
@ -40,20 +40,22 @@
class Button
{
public:
Button(int id, int index, HWND hwnd) : m_id(id), m_index(index), m_button_hwnd(GetDlgItem(hwnd, m_id)) {};
Button(int id, int index, HWND hwnd, void *wnd) : m_id(id), m_index(index), m_button_hwnd(GetDlgItem(hwnd, m_id)), m_wnd(wnd) {};
void EnableButton(bool enable) const;
void UpdateText(const char* text) const;
void ClearText() const;
void GetText(char* const text, size_t size) const;
std::string GetName(int api, int idx) const;
int GetId() const { return m_id; }
int GetIndex() const { return m_index; }
void *GetWnd() const { return m_wnd; }
private:
int m_id;
int m_index;
HWND m_button_hwnd;
void *m_wnd;
};
LRESULT CALLBACK ButtonSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
LRESULT CALLBACK ButtonDukeSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
LRESULT CALLBACK ButtonSbcSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);

View File

@ -25,13 +25,13 @@
// *
// ******************************************************************
#include"Button.h"
#include "Button.h"
#include "InputManager.h"
#include "layout_xbox_device.h"
#include "gui/resource/ResCxbx.h"
EmuDevice::EmuDevice(int type, HWND hwnd)
EmuDevice::EmuDevice(int type, HWND hwnd, void *wnd)
{
m_hwnd = hwnd;
@ -40,21 +40,21 @@ EmuDevice::EmuDevice(int type, HWND hwnd)
case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE):
case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S): {
for (size_t i = 0; i < ARRAY_SIZE(button_xbox_ctrl_id); i++) {
m_buttons.push_back(new Button(button_xbox_ctrl_id[i], i, hwnd));
m_buttons.push_back(new Button(button_xbox_ctrl_id[i], i, hwnd, wnd));
// Install the subclass for the button control
SetWindowSubclass(GetDlgItem(hwnd, button_xbox_ctrl_id[i]), ButtonSubclassProc, 0, reinterpret_cast<DWORD_PTR>(m_buttons[i]));
SetWindowSubclass(GetDlgItem(hwnd, button_xbox_ctrl_id[i]), ButtonDukeSubclassProc, 0, reinterpret_cast<DWORD_PTR>(m_buttons[i]));
}
}
break;
case to_underlying(XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER): {
for (size_t i = 0; i < ARRAY_SIZE(button_sbc_id); i++) {
m_buttons.push_back(new Button(button_sbc_id[i], i, hwnd));
printf("button id: %d, button idx: %d\n", button_sbc_id[i], i);
m_buttons.push_back(new Button(button_sbc_id[i], i, hwnd, wnd));
// Not sure yet if this is necessary
// Install the subclass for the button control
//SetWindowSubclass(GetDlgItem(hwnd, button_sbc_id[i]), ButtonSubclassProc, 0, reinterpret_cast<DWORD_PTR>(m_buttons[i]));
SetWindowSubclass(GetDlgItem(hwnd, button_sbc_id[i]), ButtonSbcSubclassProc, 0, reinterpret_cast<DWORD_PTR>(m_buttons[i]));
}
}
break;
@ -86,10 +86,11 @@ Button* EmuDevice::FindButtonByIndex(int index)
return m_buttons[index];
}
void EmuDevice::BindDefault(int api)
template<size_t size>
void EmuDevice::BindDefault(const std::array<const char *, size> &arr)
{
std::for_each(m_buttons.begin(), m_buttons.end(), [&api](const auto button) {
button->UpdateText(button->GetName(api, button->GetIndex()).c_str());
std::for_each(m_buttons.begin(), m_buttons.end(), [&arr](const auto button) {
button->UpdateText(arr[button->GetIndex()]);
});
}

View File

@ -29,17 +29,19 @@
#include "Button.h"
#include "common\util\CxbxUtil.h"
#include <array>
/* Represents the guest device currently being configured in the gui */
class EmuDevice
{
public:
EmuDevice(int type, HWND hwnd);
EmuDevice(int type, HWND hwnd, void *wnd);
~EmuDevice();
Button* FindButtonById(int id);
Button* FindButtonByIndex(int index);
void BindDefault(int api);
template<size_t size>
void BindDefault(const std::array<const char *, size> &arr);
void ClearButtons();
@ -47,3 +49,5 @@ private:
std::vector<Button*> m_buttons;
HWND m_hwnd;
};
template void EmuDevice::BindDefault(const std::array<const char *, XBOX_CTRL_NUM_BUTTONS> &arr);

View File

@ -43,46 +43,41 @@ std::string GetInputDeviceName(int dev_type)
switch (dev_type)
{
case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE): {
case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE):
str = "MS Gamepad Duke";
}
break;
break;
case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S): {
case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S):
str = "MS Gamepad S";
}
break;
break;
case to_underlying(XBOX_INPUT_DEVICE::LIGHT_GUN): {
case to_underlying(XBOX_INPUT_DEVICE::LIGHT_GUN):
str = "Light gun";
}
break;
break;
case to_underlying(XBOX_INPUT_DEVICE::STEERING_WHEEL): {
case to_underlying(XBOX_INPUT_DEVICE::STEERING_WHEEL):
str = "Steering wheel";
}
break;
break;
case to_underlying(XBOX_INPUT_DEVICE::MEMORY_UNIT): {
case to_underlying(XBOX_INPUT_DEVICE::MEMORY_UNIT):
str = "Memory unit";
}
break;
break;
case to_underlying(XBOX_INPUT_DEVICE::IR_DONGLE): {
case to_underlying(XBOX_INPUT_DEVICE::IR_DONGLE):
str = "IR dongle";
}
break;
break;
case to_underlying(XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER): {
case to_underlying(XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER):
str = "Steel battalion controller";
}
break;
break;
case to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID):
case to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX): {
str = "None";
break;
case to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX):
str = "Invalid";
}
break;
break;
default:
str = "Unknown";

View File

@ -157,7 +157,7 @@ private:
// all the output controls detected and usable on this device
std::vector<Output*> m_Outputs;
// xbox port(s) this device is attached to
bool m_XboxPort[4] = { false };
bool m_XboxPort[4] = { false, false, false, false };
// button bindings to the xbox device buttons
std::map<int, IoControl*> m_Bindings;
};

View File

@ -64,7 +64,7 @@ int dev_num_buttons[to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX)] = {
0,
0,
0,
XBOX_CTRL_NUM_BUTTONS, // STEEL_BATTALION_CONTROLLER This probably isn't correct?? Let's see what happens
SBC_NUM_BUTTONS, // STEEL_BATTALION_CONTROLLER
};
extern CXBX_CONTROLLER_HOST_BRIDGE g_XboxControllerHostBridge[4]; // hle xinput
@ -311,10 +311,10 @@ void InputDeviceManager::DisconnectDevice(int port, int usb_port, bool ack)
void InputDeviceManager::BindHostDevice(int port, int usb_port, int type)
{
char dev_name[50];
char dev_control_names[XBOX_CTRL_NUM_BUTTONS][30];
char dev_control_names[HIGHEST_NUM_BUTTONS][30];
g_EmuShared->GetInputDevNameSettings(dev_name, port);
g_EmuShared->GetInputBindingsSettings(dev_control_names, XBOX_CTRL_NUM_BUTTONS, port);
g_EmuShared->GetInputBindingsSettings(dev_control_names, dev_num_buttons[type], port);
auto dev = FindDevice(std::string(dev_name));
if (dev != nullptr) {
@ -342,7 +342,7 @@ bool InputDeviceManager::UpdateXboxPortInput(int usb_port, void* Buffer, int Dir
// If somebody else is currently holding the lock, we won't wait and instead report no input changes
if (m_Mtx.try_lock()) {
for (auto dev_ptr : m_Devices) {
for (auto &dev_ptr : m_Devices) {
if (dev_ptr->GetPort(usb_port)) {
switch (xid_type)
{
@ -353,7 +353,7 @@ bool InputDeviceManager::UpdateXboxPortInput(int usb_port, void* Buffer, int Dir
break;
case to_underlying(XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER): {
has_changed = UpdateInputSBC(dev_ptr, Buffer, Direction);
has_changed = UpdateInputSBC(dev_ptr, Buffer, Direction, usb_port);
}
break;
@ -384,12 +384,12 @@ bool InputDeviceManager::UpdateInputXpad(std::shared_ptr<InputDevice>& Device, v
assert(bindings.size() == static_cast<size_t>(dev_num_buttons[to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE)]));
if (Direction == DIRECTION_IN) {
//XpadInput* in_buf = reinterpret_cast<XpadInput*>(static_cast<uint8_t*>(Buffer) + 2); lle usb
XpadInput* in_buf = reinterpret_cast<XpadInput*>(Buffer);
if (!Device->UpdateInput()) {
return false;
}
//XpadInput* in_buf = reinterpret_cast<XpadInput*>(static_cast<uint8_t*>(Buffer) + 2); lle usb
XpadInput *in_buf = static_cast<XpadInput *>(Buffer);
for (int i = 0; i < 8; i++) {
ControlState state = (bindings[i] != nullptr) ? dynamic_cast<InputDevice::Input*>(bindings[i])->GetState() : 0.0;
if (state) {
@ -399,40 +399,34 @@ bool InputDeviceManager::UpdateInputXpad(std::shared_ptr<InputDevice>& Device, v
in_buf->wButtons &= ~(1 << i);
}
}
for (int i = 8, j = 0; i < 16; i++, j++) {
ControlState state = (bindings[i] != nullptr) ? dynamic_cast<InputDevice::Input*>(bindings[i])->GetState() : 0.0;
in_buf->bAnalogButtons[j] = static_cast<uint8_t>(state * 0xFF);
}
for (int i = 16, j = 0; i < 24; i += 2, j++) {
for (int i = 16; i < 24; i += 2) {
ControlState state_plus = (bindings[i] != nullptr) ? dynamic_cast<InputDevice::Input*>(bindings[i])->GetState() : 0.0;
ControlState state_minus = (bindings[i + 1] != nullptr) ? dynamic_cast<InputDevice::Input*>(bindings[i + 1])->GetState() : 0.0;
ControlState state = state_plus ? state_plus * 0x7FFF : state_minus ? -state_minus * 0x8000 : 0.0;
switch (j)
switch (i)
{
case 0: {
case 16:
in_buf->sThumbLX = static_cast<int16_t>(state);
}
break;
break;
case 1: {
case 18:
in_buf->sThumbLY = static_cast<int16_t>(state);
}
break;
break;
case 2: {
case 20:
in_buf->sThumbRX = static_cast<int16_t>(state);
}
break;
break;
case 3: {
case 22:
in_buf->sThumbRY = static_cast<int16_t>(state);
}
break;
break;
default: {
// unreachable
}
}
}
}
@ -444,75 +438,163 @@ bool InputDeviceManager::UpdateInputXpad(std::shared_ptr<InputDevice>& Device, v
out_buf->right_actuator_strength / static_cast<ControlState>(0xFFFF));
}
}
return true;
}
bool InputDeviceManager::UpdateInputSBC(std::shared_ptr<InputDevice>& Device, void* Buffer, int Direction)
bool InputDeviceManager::UpdateInputSBC(std::shared_ptr<InputDevice>& Device, void* Buffer, int Direction, int Port)
{
std::map<int, InputDevice::IoControl*> bindings = Device->GetBindings();
assert(bindings.size() == static_cast<size_t>(dev_num_buttons[to_underlying(XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER)]));
// NOTE: the output state is not supported
if (Direction == DIRECTION_IN) {
//XpadInput* in_buf = reinterpret_cast<XpadInput*>(static_cast<uint8_t*>(Buffer) + 2); lle usb
XpadInput* in_buf = reinterpret_cast<XpadInput*>(Buffer);
if (!Device->UpdateInput()) {
return false;
}
for (int i = 0; i < 8; i++) {
ControlState state = (bindings[i] != nullptr) ? dynamic_cast<InputDevice::Input*>(bindings[i])->GetState() : 0.0;
// We change the toggle buttons only when a press -> release input transaction is completed
// 0 -> CockpitHatch
// 1 -> Ignition
// 2 -> ToggleFilterControl
// 3 -> ToggleOxygenSupply
// 4 -> ToggleFuelFlowRate
// 5 -> ToggleBuffreMaterial
// 6 -> ToggleVTLocation
// 7 -> TunerDial Up
// 8 -> TunerDial Down
// 9 -> GearLever Up
// 10 -> GearLever Down
static uint16_t last_in_state[4] = { 0, 0, 0, 0 };
SBCInput *in_buf = static_cast<SBCInput *>(Buffer);
for (int i = 0; i < 4; i++) {
ControlState state = (bindings[i] != nullptr) ? dynamic_cast<InputDevice::Input *>(bindings[i])->GetState() : 0.0;
if (state) {
in_buf->wButtons |= (1 << i);
in_buf->wButtons[0] |= (1 << i);
}
else {
in_buf->wButtons &= ~(1 << i);
in_buf->wButtons[0] &= ~(1 << i);
}
}
for (int i = 8, j = 0; i < 16; i++, j++) {
ControlState state = (bindings[i] != nullptr) ? dynamic_cast<InputDevice::Input*>(bindings[i])->GetState() : 0.0;
in_buf->bAnalogButtons[j] = static_cast<uint8_t>(state * 0xFF);
// CockpitHatch and Ignition are toggle buttons
for (int i = 4, j = 0; i < 6; i++, j++) {
ControlState state = (bindings[i] != nullptr) ? dynamic_cast<InputDevice::Input *>(bindings[i])->GetState() : 0.0;
uint16_t curr_in_state = static_cast<uint16_t>(!!state);
if ((~curr_in_state) & ((last_in_state[Port] >> j) & 1)) {
in_buf->wButtons[0] ^= (1 << i);
}
(last_in_state[Port] &= ~(1 << j)) |= (curr_in_state << j);
}
for (int i = 16, j = 0; i < 24; i += 2, j++) {
ControlState state_plus = (bindings[i] != nullptr) ? dynamic_cast<InputDevice::Input*>(bindings[i])->GetState() : 0.0;
ControlState state_minus = (bindings[i + 1] != nullptr) ? dynamic_cast<InputDevice::Input*>(bindings[i + 1])->GetState() : 0.0;
ControlState state = state_plus ? state_plus * 0x7FFF : state_minus ? -state_minus * 0x8000 : 0.0;
switch (j)
for (int i = 6; i < 34; i++) {
ControlState state = (bindings[i] != nullptr) ? dynamic_cast<InputDevice::Input *>(bindings[i])->GetState() : 0.0;
if (state) {
in_buf->wButtons[i / 16] |= (1 << (i % 16));
}
else {
in_buf->wButtons[i / 16] &= ~(1 << (i % 16));
}
}
// The last five digital buttons are toggle buttons
for (int i = 34, j = 2; i < 39; i++, j++) {
ControlState state = (bindings[i] != nullptr) ? dynamic_cast<InputDevice::Input *>(bindings[i])->GetState() : 0.0;
uint16_t curr_in_state = static_cast<uint16_t>(!!state);
if ((~curr_in_state) & ((last_in_state[Port] >> j) & 1)) {
in_buf->wButtons[2] ^= (1 << (i % 16));
}
(last_in_state[Port] &= ~(1 << j)) |= (curr_in_state << j);
}
for (int i = 39; i < 49; i += 2) {
ControlState state_plus = (bindings[i] != nullptr) ? dynamic_cast<InputDevice::Input *>(bindings[i])->GetState() : 0.0;
ControlState state_minus = (bindings[i + 1] != nullptr) ? dynamic_cast<InputDevice::Input *>(bindings[i + 1])->GetState() : 0.0;
switch (i)
{
case 0: {
in_buf->sThumbLX = static_cast<int16_t>(state);
}
break;
case 39:
// NOTE: the center of the stick is 0x7F, not zero
in_buf->sAimingX = static_cast<uint8_t>(state_plus ? (0x80 * state_plus) + 0x7F : state_minus ? (1.0 - state_minus) * 0x7F : 0x7F);
break;
case 1: {
in_buf->sThumbLY = static_cast<int16_t>(state);
}
break;
case 41:
// NOTE: the center of the stick is 0x7F, not zero
in_buf->sAimingY = static_cast<uint8_t>(state_plus ? (1.0 - state_plus) * 0x7F : state_minus ? (0x80 * state_minus) + 0x7F : 0x7F);
break;
case 2: {
in_buf->sThumbRX = static_cast<int16_t>(state);
}
break;
case 43:
// left: negative, right: positive
in_buf->sRotationLever = static_cast<int8_t>(static_cast<int8_t>(state_plus ? -state_plus * 0x80 : state_minus ? state_minus * 0x7F : 0.0));
break;
case 3: {
in_buf->sThumbRY = static_cast<int16_t>(state);
}
break;
case 45:
// left: positive, right: negative
in_buf->sSightChangeX = static_cast<int8_t>(state_plus ? state_plus * 0x7F : state_minus ? -state_minus * 0x80 : 0.0);
break;
case 47:
// up: negative, down: positive
in_buf->sSightChangeY = static_cast<int8_t>(state_plus ? -state_plus * 0x80 : state_minus ? state_minus * 0x7F : 0.0);
break;
default: {
// unreachable
}
}
}
}
else {
if (bindings[24] != nullptr) {
//XpadOutput* out_buf = reinterpret_cast<XpadOutput*>(static_cast<uint8_t*>(Buffer) + 2); lle usb
XpadOutput* out_buf = reinterpret_cast<XpadOutput*>(Buffer);
dynamic_cast<InputDevice::Output*>(bindings[24])->SetState(out_buf->left_actuator_strength / static_cast<ControlState>(0xFFFF),
out_buf->right_actuator_strength / static_cast<ControlState>(0xFFFF));
for (int i = 49; i < 52; i++) {
ControlState state = (bindings[i] != nullptr) ? (dynamic_cast<InputDevice::Input *>(bindings[i])->GetState() * 0xFF) : 0.0;
switch (i)
{
case 49:
in_buf->wLeftPedal = static_cast<uint8_t>(state);
break;
case 50:
in_buf->wMiddlePedal = static_cast<uint8_t>(state);
break;
case 51:
in_buf->wRightPedal = static_cast<uint8_t>(state);
break;
}
}
// TunerDial and GearLever work like toggles
for (int i = 52, j = 7; i < 56; i++, j++) {
ControlState state = (bindings[i] != nullptr) ? dynamic_cast<InputDevice::Input *>(bindings[i])->GetState() : 0.0;
uint16_t curr_in_state = static_cast<uint16_t>(!!state);
if ((~curr_in_state) & ((last_in_state[Port] >> j) & 1)) {
switch (i)
{
case 52:
if (in_buf->ucTunerDial != 12) {
in_buf->ucTunerDial += 1;
}
break;
case 53:
if (in_buf->ucTunerDial != 0) {
in_buf->ucTunerDial -= 1;
}
break;
case 54:
if (in_buf->ucGearLever != 13) {
in_buf->ucGearLever += 1;
}
break;
case 55:
if (in_buf->ucGearLever != 7) {
in_buf->ucGearLever -= 1;
}
break;
}
}
(last_in_state[Port] &= ~(1 << j)) |= (curr_in_state << j);
}
}
return true;
}

View File

@ -39,18 +39,6 @@
extern int dev_num_buttons[to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX)];
typedef struct _input_controller {
XBOX_INPUT_DEVICE type;
const char* name;
} input_controller;
static input_controller input_support_list[] = {
{ XBOX_INPUT_DEVICE::DEVICE_INVALID, "None" },
{ XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE, "MS Controller Duke" },
{ XBOX_INPUT_DEVICE::MS_CONTROLLER_S, "MS Controller S" },
{ XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER, "Steel Battalion Controller" },
};
#pragma pack(1)
// xpad in/out buffers stripped of the first two bytes
@ -68,62 +56,30 @@ struct XpadOutput {
uint16_t right_actuator_strength;
};
struct SBCInput { //Was told not to copy this, did it anyways for the sake of having the proper input size and potentially modifying it's bindings from there.
uint16_t wButtons[3];
int16_t sAimingX;
int16_t sAimingY;
int16_t sRotationLever;//maybe only high byte was used.
int16_t sSightChangeX;
int16_t sSightChangeY;
uint16_t wLeftPedal;//maybe only high byte was used.
uint16_t wMiddlePedal;//maybe only high byte was used.
uint16_t wRightPedal;//maybe only high byte was used.
uint8_t ucTunerDial;//low nibble, The 9 o'clock postion is 0, and the 6 o'clock position is 12. The blank area between the 6 and 9 o'clock positions is 13, 14, and 15 clockwise.
uint8_t ucGearLever;//GearLever 1~5 for gear 1~5, 7~13 for gear R,N,1~5, 15 for gear R. we use the continues range from 7~13
struct SBCInput {
uint16_t wButtons[3];
uint8_t bPad1;
uint8_t sAimingX;
uint8_t bPad2;
uint8_t sAimingY;
uint8_t bPad3;
int8_t sRotationLever;
uint8_t bPad4;
int8_t sSightChangeX;
uint8_t bPad5;
int8_t sSightChangeY;
uint8_t bPad6;
uint8_t wLeftPedal;
uint8_t bPad7;
uint8_t wMiddlePedal;
uint8_t bPad8;
uint8_t wRightPedal;
uint8_t ucTunerDial;
uint8_t ucGearLever;
};
struct SBCOutput { //Likewise, with 0x14
uint16_t StartLED; //Commented out because it stops compilation
uint16_t bLen;
uint16_t EmergencyEject;
uint16_t CockpitHatch;
uint16_t Ignition;
uint16_t Start;
uint16_t OpenClose;
uint16_t MapZoomInOut;
uint16_t ModeSelect;
uint16_t SubMonitorModeSelect;
uint16_t MainMonitorZoomIn;
uint16_t MainMonitorZoomOut;
uint16_t ForecastShootingSystem;
uint16_t Manipulator;
uint16_t LineColorChange;
uint16_t Washing;
uint16_t Extinguisher;
uint16_t Chaff;
uint16_t TankDetach;
uint16_t Override;
uint16_t NightScope;
uint16_t F1;
uint16_t F2;
uint16_t F3;
uint16_t MainWeaponControl;
uint16_t SubWeaponControl;
uint16_t MagazineChange;
uint16_t Comm1;
uint16_t Comm2;
uint16_t Comm3;
uint16_t Comm4;
uint16_t Comm5;
uint16_t Blank; //This might not be correct, as XboxDevWiki shows an empty box for this entry
uint16_t GearR;
uint16_t GearN;
uint16_t Gear1;
uint16_t Gear2;
uint16_t Gear3;
uint16_t Gear4;
uint16_t Gear5;
uint16_t Unused; //Also might not be correct, but unsure
struct SBCOutput {
uint8_t LedState[20];
};
#pragma pack()
@ -160,7 +116,7 @@ private:
// update input for an xbox controller
bool UpdateInputXpad(std::shared_ptr<InputDevice>& Device, void* Buffer, int Direction);
// update input for a Steel Battalion controller
bool UpdateInputSBC(std::shared_ptr<InputDevice>& Device, void* Buffer, int Direction);
bool UpdateInputSBC(std::shared_ptr<InputDevice>& Device, void* Buffer, int Direction, int Port);
// bind a host device to an emulated device
void BindHostDevice(int port, int usb_port, int type);
// connect a device to the emulated machine

View File

@ -34,73 +34,8 @@
#include "Logging.h"
#include <future>
#define INPUT_TIMEOUT 5000
#define OUTPUT_TIMEOUT 3000
constexpr ControlState INPUT_DETECT_THRESHOLD = 0.35; // NOTE: this should probably be made user configurable
InputWindow* g_InputWindow = nullptr;
void InputWindow::Initialize(HWND hwnd, int port_num, int dev_type)
{
// Save window/device specific variables
m_hwnd_window = hwnd;
m_hwnd_device_list = GetDlgItem(m_hwnd_window, IDC_DEVICE_LIST);
m_hwnd_profile_list = GetDlgItem(m_hwnd_window, IDC_XID_PROFILE_NAME);
m_hwnd_default = GetDlgItem(m_hwnd_window, IDC_XID_DEFAULT);
m_dev_type = dev_type;
m_max_num_buttons = dev_num_buttons[dev_type];
m_port_num = port_num;
m_bHasChanges = false;
m_bIsBinding = false;
// Set window icon
SetClassLong(m_hwnd_window, GCL_HICON, (LONG)LoadIcon(GetModuleHandle(nullptr), MAKEINTRESOURCE(IDI_CXBX)));
// Set window title
std::string title;
switch (m_dev_type)
{
case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE): {
title += "Xbox Controller Duke at port ";
}
break;
case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S): {
title += "Xbox Controller S at port ";
}
break;
default:
break;
}
SendMessage(m_hwnd_window, WM_SETTEXT, 0,
reinterpret_cast<LPARAM>((title + std::to_string(PORT_INC(m_port_num))).c_str()));
// Set the maximum profile name lenght the user can enter in the profile combobox
SendMessage(m_hwnd_profile_list, CB_LIMITTEXT, 49, 0);
// construct emu device
m_DeviceConfig = new EmuDevice(m_dev_type, m_hwnd_window);
// Enumerate devices
UpdateDeviceList();
// Load currently saved profile for this port/device type
LoadDefaultProfile();
// Load currently selected host device
UpdateCurrentDevice();
// Load rumble binding
char rumble[30];
m_DeviceConfig->FindButtonByIndex(m_max_num_buttons - 1)->GetText(rumble, sizeof(rumble));
m_rumble = rumble;
// Install the subclass for the profile combobox
SetWindowSubclass(GetWindow(m_hwnd_profile_list, GW_CHILD), ProfileNameSubclassProc, 0, 0);
}
InputWindow::~InputWindow()
{
@ -242,38 +177,6 @@ void InputWindow::BindButton(int ControlID)
}
}
void InputWindow::BindDefault()
{
int api = EnableDefaultButton();
if (api != -1) {
m_DeviceConfig->BindDefault(api);
m_bHasChanges = true;
}
}
void InputWindow::ClearBindings()
{
m_DeviceConfig->ClearButtons();
m_rumble = std::string();
m_bHasChanges = true;
}
int InputWindow::EnableDefaultButton()
{
if (std::strncmp(m_host_dev.c_str(), "XInput", std::strlen("XInput")) == 0) {
EnableWindow(m_hwnd_default, TRUE);
return XINPUT_DEFAULT;
}
else if (std::strncmp(m_host_dev.c_str(), "DInput", std::strlen("DInput")) == 0) {
EnableWindow(m_hwnd_default, TRUE);
return DINPUT_DEFAULT;
}
else {
EnableWindow(m_hwnd_default, FALSE);
return -1;
}
}
InputWindow::ProfileIt InputWindow::FindProfile(const std::string& name)
{
auto it = std::find_if(g_Settings->m_input_profiles[m_dev_type].begin(),
@ -283,40 +186,6 @@ InputWindow::ProfileIt InputWindow::FindProfile(const std::string& name)
return it;
}
void InputWindow::UpdateProfile(const std::string& name, int command)
{
switch (command)
{
case PROFILE_LOAD: {
LoadProfile(name);
}
break;
case PROFILE_SAVE: {
SaveProfile(name);
}
break;
case PROFILE_DELETE: {
DeleteProfile(name);
}
break;
case RUMBLE_CLEAR: {
m_rumble = std::string();
}
break;
case BUTTON_CLEAR: {
m_bHasChanges = true;
}
break;
default:
break;
}
}
void InputWindow::LoadProfile(const std::string& name)
{
ProfileIt profile = FindProfile(name);
@ -421,74 +290,3 @@ void InputWindow::UpdateCurrentDevice()
m_host_dev = device_name;
EnableDefaultButton();
}
void InputWindow::InitRumble(HWND hwnd)
{
m_hwnd_rumble = hwnd;
m_hwnd_rumble_list = GetDlgItem(m_hwnd_rumble, IDC_RUMBLE_LIST);
SendMessage(m_hwnd_rumble_list, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(""));
auto dev = g_InputDeviceManager.FindDevice(m_host_dev);
if (dev != nullptr) {
auto outputs = dev->GetOutputs();
for (const auto out : outputs) {
SendMessage(m_hwnd_rumble_list, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(out->GetName().c_str()));
}
}
SendMessage(m_hwnd_rumble_list, CB_SETCURSEL, SendMessage(m_hwnd_rumble_list, CB_FINDSTRINGEXACT, 1,
reinterpret_cast<LPARAM>(m_rumble.c_str())), 0);
}
void InputWindow::UpdateRumble(int command)
{
switch (command)
{
case RUMBLE_SET: {
char rumble[30];
SendMessage(m_hwnd_rumble_list, WM_GETTEXT, sizeof(rumble), reinterpret_cast<LPARAM>(rumble));
m_rumble = rumble;
}
break;
case RUMBLE_UPDATE: {
m_DeviceConfig->FindButtonByIndex(m_max_num_buttons - 1)->UpdateText(m_rumble.c_str());
}
break;
case RUMBLE_TEST: {
DetectOutput(OUTPUT_TIMEOUT);
}
break;
default:
break;
}
}
void InputWindow::DetectOutput(int ms)
{
if (m_rumble == std::string()) {
return;
}
auto dev = g_InputDeviceManager.FindDevice(m_host_dev);
if (dev != nullptr) {
// Don't block the message processing loop
std::thread([this, dev, ms]() {
EnableWindow(m_hwnd_rumble, FALSE);
SendMessage(m_hwnd_rumble_list, WM_SETTEXT, 0, reinterpret_cast<LPARAM>("..."));
auto outputs = dev->GetOutputs();
for (const auto out : outputs) {
if (out->GetName() == m_rumble) {
out->SetState(1.0, 1.0);
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
for (const auto out : outputs) {
if (out->GetName() == m_rumble) {
out->SetState(0.0, 0.0);
}
}
SendMessage(m_hwnd_rumble_list, WM_SETTEXT, 0, reinterpret_cast<LPARAM>("Test"));
EnableWindow(m_hwnd_rumble, TRUE);
}).detach();
}
}

View File

@ -40,8 +40,11 @@
#define RUMBLE_CLEAR 7
#define BUTTON_CLEAR 8
#define XINPUT_DEFAULT 1
#define DINPUT_DEFAULT 2
#define XINPUT_DEFAULT 0
#define DINPUT_DEFAULT 1
#define INPUT_TIMEOUT 5000
#define OUTPUT_TIMEOUT 3000
LRESULT CALLBACK ProfileNameSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
@ -49,30 +52,26 @@ LRESULT CALLBACK ProfileNameSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LP
class InputWindow
{
public:
void Initialize(HWND hwnd, int port_num, int dev_type);
void InitRumble(HWND hwnd);
virtual void Initialize(HWND hwnd, int port_num, int dev_type) = 0;
~InputWindow();
void UpdateDeviceList();
void BindButton(int ControlID);
void BindDefault();
void ClearBindings();
void UpdateProfile(const std::string& name, int command);
void UpdateRumble(int command);
virtual void ClearBindings() = 0;
virtual void UpdateProfile(const std::string& name, int command) = 0;
void UpdateCurrentDevice();
bool IsProfileSaved();
private:
protected:
typedef std::vector<Settings::s_input_profiles>::iterator ProfileIt;
InputDevice::Input* DetectInput(InputDevice* const Device, int ms);
void DetectOutput(int ms);
ProfileIt FindProfile(const std::string& name);
void LoadProfile(const std::string& name);
bool SaveProfile(const std::string& name);
void DeleteProfile(const std::string& name);
void OverwriteProfile(const std::string& name);
void LoadDefaultProfile();
int EnableDefaultButton();
virtual int EnableDefaultButton() = 0;
// xbox device under configuration
EmuDevice* m_DeviceConfig;
@ -82,12 +81,6 @@ private:
HWND m_hwnd_device_list;
// handle of the profile list combobox
HWND m_hwnd_profile_list;
// handle of the rumble window
HWND m_hwnd_rumble;
// handle of the rumble combobox
HWND m_hwnd_rumble_list;
// handle of the default bindings button
HWND m_hwnd_default;
// type of the device
int m_dev_type;
// num of buttons of device under configuration
@ -96,12 +89,45 @@ private:
int m_port_num;
// host device under configuration
std::string m_host_dev;
// currently selected rumble control
std::string m_rumble;
// indicates if the current profile has unsaved changes
bool m_bHasChanges;
// prevent current input attempt to set the previous input at same time
std::atomic<bool> m_bIsBinding;
};
extern InputWindow* g_InputWindow;
class DukeInputWindow : public InputWindow
{
public:
void Initialize(HWND hwnd, int port_num, int dev_type) override;
void InitRumble(HWND hwnd);
void UpdateRumble(int command);
void BindDefault();
void ClearBindings() override;
void UpdateProfile(const std::string &name, int command) override;
private:
int EnableDefaultButton() override;
void DetectOutput(int ms);
// handle of the default bindings button
HWND m_hwnd_default;
// handle of the rumble window
HWND m_hwnd_rumble;
// handle of the rumble combobox
HWND m_hwnd_rumble_list;
// currently selected rumble control
std::string m_rumble;
};
class SbcInputWindow : public InputWindow
{
public:
void Initialize(HWND hwnd, int port_num, int dev_type) override;
void ClearBindings() override;
void UpdateProfile(const std::string &name, int command) override;
private:
int EnableDefaultButton() override;
};

View File

@ -27,6 +27,8 @@
#pragma once
#define BUF_NAME_LENGTH 30
#ifndef CXBXR_EMU_EXPORTS
#include "gui/resource/ResCxbx.h"
@ -104,7 +106,8 @@ inline int button_sbc_id[SBC_NUM_BUTTONS] = {
IDC_AIMING_NEGX,
IDC_AIMING_POSY,
IDC_AIMING_NEGY,
IDC_ROTATION_LEVER,
IDC_LEVER_LEFT,
IDC_LEVER_RIGHT,
IDC_SIGHT_CHANGE_POSX,
IDC_SIGHT_CHANGE_NEGX,
IDC_SIGHT_CHANGE_POSY,
@ -112,47 +115,129 @@ inline int button_sbc_id[SBC_NUM_BUTTONS] = {
IDC_BTN_LEFT_PEDAL,
IDC_BTN_MIDDLE_PEDAL,
IDC_BTN_RIGHT_PEDAL,
IDC_RADIO_TD0,
IDC_RADIO_TD1,
IDC_RADIO_TD2,
IDC_RADIO_TD3,
IDC_RADIO_TD4,
IDC_RADIO_TD5,
IDC_RADIO_TD6,
IDC_RADIO_TD7,
IDC_RADIO_TD8,
IDC_RADIO_TD9,
IDC_RADIO_TD10,
IDC_RADIO_TD11,
IDC_RADIO_TD12,
IDC_GEAR_LEVER,
IDC_RADIO_TD_UP,
IDC_RADIO_TD_DOWN,
IDC_GEAR_UP,
IDC_GEAR_DOWN,
};
#endif
inline const char* button_xbox_ctrl_names[XBOX_CTRL_NUM_BUTTONS][3] = {
"D Pad Up", "Pad N", "UP",
"D Pad Down", "Pad S", "DOWN",
"D Pad Left", "Pad W", "LEFT",
"D Pad Right", "Pad E", "RIGHT",
"Start", "Start", "RETURN",
"Back", "Back", "SPACE",
"L Thumb", "Thumb L", "B",
"R Thumb", "Thumb R", "M",
"A", "Button A", "S",
"B", "Button B", "D",
"X", "Button X", "W",
"Y", "Button Y", "E",
"Black", "Shoulder R", "C",
"White", "Shoulder L", "X",
"L Trigger", "Trigger L", "Q",
"R Trigger", "Trigger R", "R",
"Left Axis X+", "Left X+", "H",
"Left Axis X-", "Left X-", "F",
"Left Axis Y+", "Left Y+", "T",
"Left Axis Y-", "Left Y-", "G",
"Right Axis X+", "Right X+", "L",
"Right Axis X-", "Right X-", "J",
"Right Axis Y+", "Right Y+", "I",
"Right Axis Y-", "Right Y-", "K",
"Motor", "LeftRight", "",
inline constexpr const char* button_xbox_ctrl_names[XBOX_CTRL_NUM_BUTTONS] = {
"D Pad Up",
"D Pad Down",
"D Pad Left",
"D Pad Right",
"Start",
"Back",
"L Thumb",
"R Thumb",
"A",
"B",
"X",
"Y",
"Black",
"White",
"L Trigger",
"R Trigger",
"Left Axis X+",
"Left Axis X-",
"Left Axis Y+",
"Left Axis Y-",
"Right Axis X+",
"Right Axis X-",
"Right Axis Y+",
"Right Axis Y-",
"Motor",
};
inline constexpr const char *button_sbc_names[SBC_NUM_BUTTONS] = {
"RightJoyMainWeapon",
"RightJoyFire",
"RightJoyLockOn",
"Eject",
"CockpitHatch",
"Ignition",
"Start",
"MultiMonOpenClose",
"MultiMonMapZoomInOut",
"MultiMonModeSelect",
"MultiMonSubMonitor",
"MainMonZoomIn",
"MainMonZoomOut",
"FunctionFSS",
"FunctionManipulator",
"FunctionLineColorChange",
"Washing",
"Extinguisher",
"Chaff",
"FunctionTankDetach",
"FunctionOverride",
"FunctionNightScope",
"FunctionF1",
"FunctionF2",
"FunctionF3",
"WeaponConMain",
"WeaponConSub",
"WeaponConMagazine",
"Comm1",
"Comm2",
"Comm3",
"Comm4",
"Comm5",
"LeftJoySightChange",
"ToggleFilterControl",
"ToggleOxygenSupply",
"ToggleFuelFlowRate",
"ToggleBufferMaterial",
"ToggleVTLocation",
"Aiming X+",
"Aiming X-",
"Aiming Y+",
"Aiming Y-",
"LeverLeft",
"LeverRight",
"SightChange X+",
"SightChange X-",
"SightChange Y+",
"SightChange Y-",
"LeftPedal",
"MiddlePedal",
"RightPedal",
"TunerDial Up",
"TunerDial Down",
"GearLever Up",
"GearLever Down",
};
constexpr bool check_button_name_size(unsigned max_num_buttons)
{
switch (max_num_buttons)
{
case XBOX_CTRL_NUM_BUTTONS: {
for (unsigned i = 0; i < max_num_buttons; i++) {
if (std::char_traits<char>::length(button_xbox_ctrl_names[i]) > (BUF_NAME_LENGTH - 1)) {
return false;
}
}
}
break;
case SBC_NUM_BUTTONS: {
for (unsigned i = 0; i < max_num_buttons; i++) {
if (std::char_traits<char>::length(button_sbc_names[i]) > (BUF_NAME_LENGTH - 1)) {
return false;
}
}
}
break;
default:
return false;
}
return true;
}
// Sanity checks: the button buffers used in the input system are 30 bytes large, so ensure that we do not exceed them
static_assert(check_button_name_size(XBOX_CTRL_NUM_BUTTONS));
static_assert(check_button_name_size(SBC_NUM_BUTTONS));

View File

@ -132,7 +132,7 @@ class EmuShared : public Mutex
void SetInputDevNameSettings(const char* name, int port) { Lock(); strncpy(m_DeviceName[port], name, 50); Unlock(); }
void GetInputBindingsSettings(char button_str[][30], int max_num_buttons, int port)
{
assert(max_num_buttons <= XBOX_CTRL_NUM_BUTTONS);
assert(max_num_buttons <= HIGHEST_NUM_BUTTONS);
Lock();
for (int i = 0; i < max_num_buttons; i++) {
strncpy(button_str[i], m_DeviceControlNames[port][i], 30);
@ -141,7 +141,7 @@ class EmuShared : public Mutex
}
void SetInputBindingsSettings(const char button_str[][30], int max_num_buttons, int port)
{
assert(max_num_buttons <= XBOX_CTRL_NUM_BUTTONS);
assert(max_num_buttons <= HIGHEST_NUM_BUTTONS);
Lock();
for (int i = 0; i < max_num_buttons; i++) {
strncpy(m_DeviceControlNames[port][i], button_str[i], 30);
@ -303,7 +303,7 @@ class EmuShared : public Mutex
bool m_bReserved4;
unsigned int m_dwKrnlProcID; // Only used for kernel mode level.
int m_DeviceType[4];
char m_DeviceControlNames[4][XBOX_CTRL_NUM_BUTTONS][30]; // macro should be num of buttons of dev with highest num buttons
char m_DeviceControlNames[4][HIGHEST_NUM_BUTTONS][30];
char m_DeviceName[4][50];
long m_MoAxisRange;
long m_MoWheelRange;

View File

@ -46,33 +46,21 @@
#include "core\hle\XAPI\Xapi.h"
#include "core\hle\XAPI\XapiCxbxr.h"
bool g_bCxbxVSBCLoaded = false;
HINSTANCE g_module;
typedef int (FAR WINAPI *PFARPROC1)(int);
typedef int (FAR WINAPI *PFARPROC2)(UCHAR*);
typedef int (NEAR WINAPI *PNEARPROC1)(int);
typedef int (NEAR WINAPI *PNEARPROC2)(UCHAR*);
typedef int (WINAPI *PPROC)();
PFARPROC2 fnCxbxVSBCSetState;
PFARPROC2 fnCxbxVSBCGetState;
PFARPROC1 fnCxbxVSBCOpen;
//typedef DWORD(*fnCxbxVSBCOpen)(HWND);
//typedef DWORD(*fnCxbxVSBCSetState)(UCHAR *);
//typedef DWORD(*fnCxbxVSBCGetState)(UCHAR *);
xbox::PXPP_DEVICE_TYPE g_DeviceType_Gamepad = nullptr;
xbox::PXPP_DEVICE_TYPE g_DeviceType_SBC = nullptr; //deviceTable[i]->XppType?
xbox::PXPP_DEVICE_TYPE g_DeviceType_SBC = nullptr;
// Flag is unset after initialize devices is done by simulate LLE USB thread.
std::atomic<bool> g_bIsDevicesInitializing = true;
std::atomic<bool> g_bIsDevicesEmulating = false;
static CXBX_XINPUT_IN_STATE InState[4];
//global bridge for xbox controller to host, 4 elements for 4 ports.
CXBX_CONTROLLER_HOST_BRIDGE g_XboxControllerHostBridge[4] = {
{ NULL, PORT_INVALID, XBOX_INPUT_DEVICE::DEVICE_INVALID, nullptr, false, false, false, { 0, 0, 0, 0, 0 } },
{ NULL, PORT_INVALID, XBOX_INPUT_DEVICE::DEVICE_INVALID, nullptr, false, false, false, { 0, 0, 0, 0, 0 } },
{ NULL, PORT_INVALID, XBOX_INPUT_DEVICE::DEVICE_INVALID, nullptr, false, false, false, { 0, 0, 0, 0, 0 } },
{ NULL, PORT_INVALID, XBOX_INPUT_DEVICE::DEVICE_INVALID, nullptr, false, false, false, { 0, 0, 0, 0, 0 } },
{ NULL, PORT_INVALID, XBOX_INPUT_DEVICE::DEVICE_INVALID, &InState[0], false, false, false, { 0, 0, 0, 0, 0 } },
{ NULL, PORT_INVALID, XBOX_INPUT_DEVICE::DEVICE_INVALID, &InState[1], false, false, false, { 0, 0, 0, 0, 0 } },
{ NULL, PORT_INVALID, XBOX_INPUT_DEVICE::DEVICE_INVALID, &InState[2], false, false, false, { 0, 0, 0, 0, 0 } },
{ NULL, PORT_INVALID, XBOX_INPUT_DEVICE::DEVICE_INVALID, &InState[3], false, false, false, { 0, 0, 0, 0, 0 } },
};
@ -114,14 +102,13 @@ bool operator!=(xbox::PXPP_DEVICE_TYPE XppType, XBOX_INPUT_DEVICE XidType)
bool ConstructHleInputDevice(int Type, int Port)
{
g_bIsDevicesEmulating = true;
bool ret = true;
bool ret;
switch (Type)
{
case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE): {
g_XboxControllerHostBridge[Port].XboxPort = Port;
g_XboxControllerHostBridge[Port].XboxType = XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE;
g_XboxControllerHostBridge[Port].InState = new XpadInput();
g_XboxControllerHostBridge[Port].bPendingRemoval = false;
g_XboxControllerHostBridge[Port].bSignaled = false;
g_XboxControllerHostBridge[Port].bIoInProgress = false;
@ -130,12 +117,13 @@ bool ConstructHleInputDevice(int Type, int Port)
g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucInputStateSize = sizeof(XpadInput);
g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucFeedbackSize = sizeof(XpadOutput);
g_XboxControllerHostBridge[Port].XboxDeviceInfo.dwPacketNumber = 0;
ret = true;
}
break;
case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S): {
g_XboxControllerHostBridge[Port].XboxPort = Port;
g_XboxControllerHostBridge[Port].XboxType = XBOX_INPUT_DEVICE::MS_CONTROLLER_S;
g_XboxControllerHostBridge[Port].InState = new XpadInput();
g_XboxControllerHostBridge[Port].bPendingRemoval = false;
g_XboxControllerHostBridge[Port].bSignaled = false;
g_XboxControllerHostBridge[Port].bIoInProgress = false;
@ -144,36 +132,39 @@ bool ConstructHleInputDevice(int Type, int Port)
g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucInputStateSize = sizeof(XpadInput);
g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucFeedbackSize = sizeof(XpadOutput);
g_XboxControllerHostBridge[Port].XboxDeviceInfo.dwPacketNumber = 0;
ret = true;
}
break;
case to_underlying(XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER): {
g_XboxControllerHostBridge[Port].XboxPort = Port;
g_XboxControllerHostBridge[Port].XboxType = XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER;
g_XboxControllerHostBridge[Port].InState = new SBCInput();
g_XboxControllerHostBridge[Port].InState->SBC.ucGearLever = 8;
g_XboxControllerHostBridge[Port].InState->SBC.sAimingX = static_cast<uint8_t>(0x7F);
g_XboxControllerHostBridge[Port].InState->SBC.sAimingY = static_cast<uint8_t>(0x7F);
g_XboxControllerHostBridge[Port].bPendingRemoval = false;
g_XboxControllerHostBridge[Port].bSignaled = false;
g_XboxControllerHostBridge[Port].bIoInProgress = false;
g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucType = XINPUT_DEVTYPE_STEELBATTALION;
g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucSubType = XINPUT_DEVSUBTYPE_GC_GAMEPAD_ALT;
g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucInputStateSize = 0x18;
g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucFeedbackSize = 0x14;
g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucInputStateSize = sizeof(SBCInput);
g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucFeedbackSize = sizeof(SBCOutput);
g_XboxControllerHostBridge[Port].XboxDeviceInfo.dwPacketNumber = 0;
ret = true;
}
break;
case to_underlying(XBOX_INPUT_DEVICE::LIGHT_GUN):
case to_underlying(XBOX_INPUT_DEVICE::STEERING_WHEEL):
case to_underlying(XBOX_INPUT_DEVICE::MEMORY_UNIT):
case to_underlying(XBOX_INPUT_DEVICE::IR_DONGLE): {
case to_underlying(XBOX_INPUT_DEVICE::IR_DONGLE):
EmuLog(LOG_LEVEL::INFO, "%s: device %s is not yet supported", __func__, GetInputDeviceName(Type).c_str());
ret = false;
}
break;
break;
default:
EmuLog(LOG_LEVEL::WARNING, "Attempted to attach an unknown device type (type was %d)", Type);
ret = false;
break;
}
g_bIsDevicesEmulating = false;
@ -187,7 +178,7 @@ void DestructHleInputDevice(int Port)
g_XboxControllerHostBridge[Port].XboxType = XBOX_INPUT_DEVICE::DEVICE_INVALID;
g_XboxControllerHostBridge[Port].XboxPort = PORT_INVALID;
while (g_XboxControllerHostBridge[Port].bIoInProgress) {}
delete g_XboxControllerHostBridge[Port].InState;
std::memset(&InState[Port], 0, g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucInputStateSize);
g_XboxControllerHostBridge[Port].bPendingRemoval = false;
g_XboxControllerHostBridge[Port].bSignaled = false;
g_XboxControllerHostBridge[Port].bIoInProgress = false;
@ -207,7 +198,7 @@ void SetupXboxDeviceTypes()
// First, attempt to find GetTypeInformation
auto typeInformation = g_SymbolAddresses.find("GetTypeInformation");
if (typeInformation != g_SymbolAddresses.end() && typeInformation->second != xbox::zero) {
printf("Deriving XDEVICE_TYPE_GAMEPAD from DeviceTable (via GetTypeInformation)\n");
EmuLog(LOG_LEVEL::INFO, "Deriving XDEVICE_TYPE_GAMEPAD from DeviceTable (via GetTypeInformation)");
// Read the offset values of the device table structure from GetTypeInformation
xbox::addr_xt deviceTableStartOffset = *(uint32_t*)((uint32_t)typeInformation->second + 0x01);
xbox::addr_xt deviceTableEndOffset = *(uint32_t*)((uint32_t)typeInformation->second + 0x09);
@ -215,9 +206,9 @@ void SetupXboxDeviceTypes()
// Calculate the number of device entires in the table
size_t deviceTableEntryCount = (deviceTableEndOffset - deviceTableStartOffset) / sizeof(uint32_t);
printf("DeviceTableStart: 0x%08X\n", deviceTableStartOffset);
printf("DeviceTableEnd: 0x%08X\n", deviceTableEndOffset);
printf("DeviceTable Entires: %u\n", deviceTableEntryCount);
EmuLog(LOG_LEVEL::INFO, "DeviceTableStart: 0x%08X", deviceTableStartOffset);
EmuLog(LOG_LEVEL::INFO, "DeviceTableEnd: 0x%08X", deviceTableEndOffset);
EmuLog(LOG_LEVEL::INFO, "DeviceTable Entires: %u", deviceTableEntryCount);
// Sanity check: Where all these device offsets within Xbox memory
if ((deviceTableStartOffset >= g_SystemMaxMemory) || (deviceTableEndOffset >= g_SystemMaxMemory)) {
@ -232,21 +223,22 @@ void SetupXboxDeviceTypes()
continue;
}
printf("----------------------------------------\n");
printf("DeviceTable[%u]->ucType = %d\n", i, deviceTable[i]->ucType);
printf("DeviceTable[%u]->XppType = 0x%08X (", i, (uintptr_t)deviceTable[i]->XppType);
EmuLog(LOG_LEVEL::INFO, "----------------------------------------");
EmuLog(LOG_LEVEL::INFO, "DeviceTable[%u]->ucType = %d", i, deviceTable[i]->ucType);
switch (deviceTable[i]->ucType) {
case XINPUT_DEVTYPE_GAMEPAD:
g_DeviceType_Gamepad = deviceTable[i]->XppType;
printf("XDEVICE_TYPE_GAMEPAD)\n");
EmuLog(LOG_LEVEL::INFO, "DeviceTable[%u]->XppType = 0x%08X (XDEVICE_TYPE_GAMEPAD)", i, (uintptr_t)g_DeviceType_Gamepad);
break;
case XINPUT_DEVTYPE_STEELBATTALION:
g_DeviceType_SBC = deviceTable[i]->XppType;
printf("XDEVICE_TYPE_STEELBATTALION)\n");
EmuLog(LOG_LEVEL::INFO, "DeviceTable[%u]->XppType = 0x%08X (XDEVICE_TYPE_STEELBATTALION)", i, (uintptr_t)g_DeviceType_SBC);
break;
default:
printf("Unknown device type)\n");
EmuLog(LOG_LEVEL::WARNING, "DeviceTable[%u]->XppType = 0x%08X (Unknown device type)", i, (uintptr_t)deviceTable[i]->XppType);
continue;
}
}
@ -256,7 +248,7 @@ void SetupXboxDeviceTypes()
// so this works well for us.
void* XInputOpenAddr = (void*)g_SymbolAddresses["XInputOpen"];
if (XInputOpenAddr != nullptr) {
printf("XAPI: Deriving XDEVICE_TYPE_GAMEPAD from XInputOpen (0x%08X)\n", (uintptr_t)XInputOpenAddr);
EmuLog(LOG_LEVEL::INFO, "Deriving XDEVICE_TYPE_GAMEPAD from XInputOpen (0x%08X)", (uintptr_t)XInputOpenAddr);
g_DeviceType_Gamepad = *(xbox::PXPP_DEVICE_TYPE*)((uint32_t)XInputOpenAddr + 0x0B);
}
}
@ -266,7 +258,7 @@ void SetupXboxDeviceTypes()
return;
}
printf("XAPI: XDEVICE_TYPE_GAMEPAD Found at 0x%08X\n", (uintptr_t)g_DeviceType_Gamepad);
EmuLog(LOG_LEVEL::INFO, "XDEVICE_TYPE_GAMEPAD Found at 0x%08X", (uintptr_t)g_DeviceType_Gamepad);
}
}
@ -434,32 +426,6 @@ xbox::HANDLE WINAPI xbox::EMUPATCH(XInputOpen)
if (dwPort >= PORT_1 && dwPort <= PORT_4) {
if (DeviceType == g_XboxControllerHostBridge[dwPort].XboxType) {
#if 0 // TODO
if(g_XboxControllerHostBridge[dwPort].dwHostType==X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_VIRTUAL_SBC){
//if DLL not loaded yet, load it.
if (g_bCxbxVSBCLoaded != true) {
g_module = LoadLibrary(TEXT("CxbxVSBC.dll"));
if (g_module != 0) {
g_bCxbxVSBCLoaded = true;
}
}
if(g_module!=0&& fnCxbxVSBCOpen==0){
fnCxbxVSBCSetState = (PFARPROC2)GetProcAddress(g_module, "VSBCSetState");
fnCxbxVSBCGetState = (PFARPROC2)GetProcAddress(g_module, "VSBCGetState");
fnCxbxVSBCOpen = (PFARPROC1)GetProcAddress(g_module, "VSBCOpen");
}
if (fnCxbxVSBCOpen == 0) {
printf("EmuXapi: EmuXInputOpen: GetPRocAddress VSBCOpen failed!\n");
}
else {
(*fnCxbxVSBCOpen)(X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_VIRTUAL_SBC);
}
//DWORD dwVXBCOpenResult = CxbxVSBC::MyCxbxVSBC::VSBCOpen(X_XONTROLLER_HOST_BRIDGE_HOSTTYPE_VIRTUAL_SBC);
}
#endif
g_XboxControllerHostBridge[dwPort].hXboxDevice = &g_XboxControllerHostBridge[dwPort];
RETURN(g_XboxControllerHostBridge[dwPort].hXboxDevice);
}
@ -528,234 +494,6 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(XInputGetCapabilities)
RETURN(ret);
}
//variable names correlated to SBC_FEEDBACK, mapped to each nibble accordingly.
char * XboxSBCFeedbackNames[] = {
"EmergencyEject",
"CockpitHatch",
"Ignition",
"Start",
"OpenClose",
"RightJoyMainWeapon",
"RightJoyLockOn",
"RightJoyFire",
"MapZoomInOut",
"ModeSelect",
"SubMonitorModeSelect",
"MainMonitorZoomIn",
"MainMonitorZoomOut",
"ForecastShootingSystem",
"Manipulator",
"LineColorChange",
"Washing",
"Extinguisher",
"Chaff",
"TankDetach",
"Override",
"NightScope",
"F1",
"F2",
"F3",
"MainWeaponControl",
"SubWeaponControl",
"MagazineChange",
"Comm1",
"Comm2",
"Comm3",
"Comm4",
"Comm5",
"Unknown",
"GearR",
"GearN",
"Gear1",
"Gear2",
"Gear3",
"Gear4",
"Gear5"
};
//keep last SBC_GAMEPAD status, for DIP switch and GearLever
xbox::SBC_GAMEPAD XboxSBCGamepad = {};
//virtual SteelBattalion controller GetState, using port 0 from XInput and DirectInput to emulate virtual controller.
void EmuSBCGetState(xbox::PSBC_GAMEPAD pSBCGamepad, xbox::PXINPUT_GAMEPAD pXIGamepad, xbox::PXINPUT_GAMEPAD pDIGamepad)
{
// Now convert those values to SteelBattalion Gamepad
//restore certain variables such as GerLever and Toggle Switches.
//restore the kept ucGearLever
pSBCGamepad->ucGearLever = XboxSBCGamepad.ucGearLever;
//we use continues range 7~13, 8 for gear N.
if (pSBCGamepad->ucGearLever < 7 || pSBCGamepad->ucGearLever>13) {
pSBCGamepad->ucGearLever = 8;
}
//restore Toggle Switches.
pSBCGamepad->wButtons[0] |= (XboxSBCGamepad.wButtons[0] & (CXBX_SBC_GAMEPAD_W0_COCKPITHATCH | CXBX_SBC_GAMEPAD_W0_IGNITION));
pSBCGamepad->wButtons[2] |= (XboxSBCGamepad.wButtons[2]&( CXBX_SBC_GAMEPAD_W2_TOGGLEFILTERCONTROL
| CXBX_SBC_GAMEPAD_W2_TOGGLEOXYGENSUPPLY
| CXBX_SBC_GAMEPAD_W2_TOGGLEFUELFLOWRATE
| CXBX_SBC_GAMEPAD_W2_TOGGLEBUFFREMATERIAL
| CXBX_SBC_GAMEPAD_W2_TOGGLEVTLOCATION));
// Analog Sticks
pSBCGamepad->sAimingX = pXIGamepad->sThumbRX;
pSBCGamepad->sAimingY = pXIGamepad->sThumbRY;
pSBCGamepad->sRotationLever = 0;//(pXIGamepad->wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) ? 255 : 0;
pSBCGamepad->sSightChangeX = pXIGamepad->sThumbLX;
pSBCGamepad->sSightChangeY = pXIGamepad->sThumbLY;
pSBCGamepad->wLeftPedal = ((SHORT)(pXIGamepad->bAnalogButtons[CXBX_XINPUT_GAMEPAD_LEFT_TRIGGER]))<<8;
pSBCGamepad->wMiddlePedal=0;// = (pXIGamepad->wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) ? 255 : 0;
pSBCGamepad->wRightPedal = (SHORT)(pXIGamepad->bAnalogButtons[CXBX_XINPUT_GAMEPAD_RIGHT_TRIGGER])<<8;
pSBCGamepad->ucTunerDial=0;//low nibble
// Digital Buttons
if (pXIGamepad->bAnalogButtons [CXBX_XINPUT_GAMEPAD_A]>0) {
pSBCGamepad->wButtons[0] |= CXBX_SBC_GAMEPAD_W0_RIGHTJOYMAINWEAPON;
}
else {
pSBCGamepad->wButtons[0] &= ~CXBX_SBC_GAMEPAD_W0_RIGHTJOYMAINWEAPON;
}
if (pXIGamepad->bAnalogButtons[CXBX_XINPUT_GAMEPAD_B]>0) {
pSBCGamepad->wButtons[0] |= CXBX_SBC_GAMEPAD_W0_RIGHTJOYFIRE;
}
else {
pSBCGamepad->wButtons[0] &= ~CXBX_SBC_GAMEPAD_W0_RIGHTJOYFIRE;
}
if (pXIGamepad->bAnalogButtons[CXBX_XINPUT_GAMEPAD_X]>0) {
pSBCGamepad->wButtons[0] |= CXBX_SBC_GAMEPAD_W0_RIGHTJOYLOCKON;
}
else {
pSBCGamepad->wButtons[0] &= ~CXBX_SBC_GAMEPAD_W0_RIGHTJOYLOCKON;
}
if (pXIGamepad->bAnalogButtons[CXBX_XINPUT_GAMEPAD_Y]>0) {
pSBCGamepad->wButtons[1] |= CXBX_SBC_GAMEPAD_W1_WEAPONCONMAGAZINE;
}
else {
pSBCGamepad->wButtons[1] &= ~CXBX_SBC_GAMEPAD_W1_WEAPONCONMAGAZINE;
}
//GearLever 1~5 for gear 1~5, 7~13 for gear R,N,1~5, 15 for gear R. we use the continues range from 7~13
if (pXIGamepad->bAnalogButtons[CXBX_XINPUT_GAMEPAD_WHITE]>0) {//Left Shouder, Gear Down
if (pSBCGamepad->ucGearLever >7) {
pSBCGamepad->ucGearLever-- ;
}
}
if (pXIGamepad->bAnalogButtons[CXBX_XINPUT_GAMEPAD_BLACK]>0) {//Right Shouder, Gear Up
if (pSBCGamepad->ucGearLever < 13) {
pSBCGamepad->ucGearLever ++;
}
}
//OLD_XINPUT
/* //not used, don't duplicate the handling for same setting of pXIGamepad's members, later one will over write privous one.
if (pXIGamepad->wButtons & CXBX_XINPUT_GAMEPAD_START) {
pSBCGamepad->wButtons[0] |= CXBX_SBC_GAMEPAD_W0_START;
}
else {
pSBCGamepad->wButtons[0] &= ~CXBX_SBC_GAMEPAD_W0_START;
}
*/
if (pXIGamepad->wButtons & CXBX_XINPUT_GAMEPAD_LEFT_THUMB) {//Center Sight Change
pSBCGamepad->wButtons[2] |= CXBX_SBC_GAMEPAD_W2_LEFTJOYSIGHTCHANGE;
}
else {
pSBCGamepad->wButtons[2] &= ~CXBX_SBC_GAMEPAD_W2_LEFTJOYSIGHTCHANGE;
}
//OLD_XINPUT
/* //not used
if (pXIGamepad->wButtons & CXBX_XINPUT_GAMEPAD_RIGHT_THUMB) {
pSBCGamepad->wButtons |= CXBX_XINPUT_GAMEPAD_RIGHT_THUMB;
}
else {
pSBCGamepad->wButtons &= ~CXBX_XINPUT_GAMEPAD_RIGHT_THUMB;
}
*/
//additional input from 2nd input, default using directinput
if (pDIGamepad->bAnalogButtons[CXBX_XINPUT_GAMEPAD_A]>0) {
pSBCGamepad->wButtons[0] |= CXBX_SBC_GAMEPAD_W0_START;
}
else {
pSBCGamepad->wButtons[0] &= ~CXBX_SBC_GAMEPAD_W0_START;
}
// Iginition is Toggle Switch
if (pDIGamepad->bAnalogButtons[CXBX_XINPUT_GAMEPAD_B]>0) {
if (pSBCGamepad->wButtons[0] & CXBX_SBC_GAMEPAD_W0_IGNITION) {
pSBCGamepad->wButtons[0] &= ~CXBX_SBC_GAMEPAD_W0_IGNITION;
}
else {
pSBCGamepad->wButtons[0] |= CXBX_SBC_GAMEPAD_W0_IGNITION;
}
}
if (pDIGamepad->bAnalogButtons[CXBX_XINPUT_GAMEPAD_X]>0) {
pSBCGamepad->wButtons[0] |= CXBX_SBC_GAMEPAD_W0_EJECT;
}
else {
pSBCGamepad->wButtons[0] &= ~CXBX_SBC_GAMEPAD_W0_EJECT;
}
// CockpitHatch is Toggle Switch
if (pDIGamepad->bAnalogButtons[CXBX_XINPUT_GAMEPAD_Y]>0) {
if (pSBCGamepad->wButtons[0] & CXBX_SBC_GAMEPAD_W0_COCKPITHATCH) {
pSBCGamepad->wButtons[0] &= ~CXBX_SBC_GAMEPAD_W0_COCKPITHATCH;
}
else {
pSBCGamepad->wButtons[0] |= CXBX_SBC_GAMEPAD_W0_COCKPITHATCH;
}
}
if (pDIGamepad->wButtons & CXBX_XINPUT_GAMEPAD_BACK) {//Toggle Switch ToggleFilterControl
if (pSBCGamepad->wButtons[2] & CXBX_SBC_GAMEPAD_W2_TOGGLEFILTERCONTROL) {
pSBCGamepad->wButtons[2] &= ~CXBX_SBC_GAMEPAD_W2_TOGGLEFILTERCONTROL;
}
else {
pSBCGamepad->wButtons[2] |= CXBX_SBC_GAMEPAD_W2_TOGGLEFILTERCONTROL;
}
}
if (pDIGamepad->wButtons & CXBX_XINPUT_GAMEPAD_DPAD_UP) {//Toggle Switch ToggleOxygenSupply
if (pSBCGamepad->wButtons[2] & CXBX_SBC_GAMEPAD_W2_TOGGLEOXYGENSUPPLY) {
pSBCGamepad->wButtons[2] &= ~CXBX_SBC_GAMEPAD_W2_TOGGLEOXYGENSUPPLY;
}
else {
pSBCGamepad->wButtons[2] |= CXBX_SBC_GAMEPAD_W2_TOGGLEOXYGENSUPPLY;
}
}
if (pDIGamepad->wButtons & CXBX_XINPUT_GAMEPAD_DPAD_DOWN) {//Toggle Switch ToggleBuffreMaterial
if (pSBCGamepad->wButtons[2] & CXBX_SBC_GAMEPAD_W2_TOGGLEBUFFREMATERIAL) {
pSBCGamepad->wButtons[2] &= ~CXBX_SBC_GAMEPAD_W2_TOGGLEBUFFREMATERIAL;
}
else {
pSBCGamepad->wButtons[2] |= CXBX_SBC_GAMEPAD_W2_TOGGLEBUFFREMATERIAL;
}
}
if (pDIGamepad->wButtons & CXBX_XINPUT_GAMEPAD_DPAD_LEFT) {//Toggle Switch ToggleVTLocation
if (pSBCGamepad->wButtons[2] & CXBX_SBC_GAMEPAD_W2_TOGGLEVTLOCATION) {
pSBCGamepad->wButtons[2] &= ~CXBX_SBC_GAMEPAD_W2_TOGGLEVTLOCATION;
}
else {
pSBCGamepad->wButtons[2] |= CXBX_SBC_GAMEPAD_W2_TOGGLEVTLOCATION;
}
}
if (pDIGamepad->wButtons & CXBX_XINPUT_GAMEPAD_DPAD_RIGHT) {//Toggle Switch ToggleFuelFlowRate
if (pSBCGamepad->wButtons[2] & CXBX_SBC_GAMEPAD_W2_TOGGLEFUELFLOWRATE) {
pSBCGamepad->wButtons[2] &= ~CXBX_SBC_GAMEPAD_W2_TOGGLEFUELFLOWRATE;
}
else {
pSBCGamepad->wButtons[2] |= CXBX_SBC_GAMEPAD_W2_TOGGLEFUELFLOWRATE;
}
}
//reserve the SBCGamepad to keep the status of GearLever and Toggole Switches.
XboxSBCGamepad = *pSBCGamepad;
}
// ******************************************************************
// * patch: XInputGetState
// ******************************************************************
@ -781,7 +519,7 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(XInputGetState)
if (g_InputDeviceManager.UpdateXboxPortInput(Port, g_XboxControllerHostBridge[Port].InState, DIRECTION_IN, to_underlying(g_XboxControllerHostBridge[Port].XboxType))) {
pState->dwPacketNumber = g_XboxControllerHostBridge[Port].XboxDeviceInfo.dwPacketNumber++;
}
memcpy((void*)&pState->Gamepad, g_XboxControllerHostBridge[Port].InState, sizeof(pState->Gamepad));
memcpy((void*)&pState->Gamepad, g_XboxControllerHostBridge[Port].InState, g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucInputStateSize);
g_XboxControllerHostBridge[Port].bIoInProgress = false;
ret = ERROR_SUCCESS;
}

View File

@ -111,13 +111,13 @@ typedef struct _XID_TYPE_INFORMATION
{
xbox::uchar_xt ucType;
xbox::byte_xt bRemainingHandles;
xbox::uchar_xt ucUnknown[2];//probably for xbox::dword_xt align
PXPP_DEVICE_TYPE XppType;//pointer to DeviceType structure.
PXPP_DEVICE_INPUTSTATE_DESC pInputStateDesc;//pointer to InputStateDesc structure
PXPP_DEVICE_FEEDBACK_DESC pFeedbackDesc;//pointer to FeedbackDesc structure
xbox::dword_xt * pConstant;//always 0x0801
void * pFunction;//unknown function for device related process
xbox::dword_xt dwEndZero;//last DWROD, always 0
xbox::uchar_xt ucUnknown[2]; // probably for xbox::dword_xt align
PXPP_DEVICE_TYPE XppType; // pointer to DeviceType structure.
PXPP_DEVICE_INPUTSTATE_DESC pInputStateDesc; // pointer to InputStateDesc structure
PXPP_DEVICE_FEEDBACK_DESC pFeedbackDesc; // pointer to FeedbackDesc structure
xbox::dword_xt * pConstant; // always 0x0801
void * pFunction; // unknown function for device related process
xbox::dword_xt dwEndZero; // last DWROD, always 0
} XID_TYPE_INFORMATION, *PXID_TYPE_INFORMATION;
// ******************************************************************
@ -130,6 +130,7 @@ typedef struct _XDEVICE_PREALLOC_TYPE
}
XDEVICE_PREALLOC_TYPE, *PXDEVICE_PREALLOC_TYPE;
#pragma pack(1)
// ******************************************************************
// * XINPUT_GAMEPAD for xbox, xbox's GAMEPAD struct differs from PC's
// ******************************************************************
@ -145,43 +146,24 @@ typedef struct _XINPUT_GAMEPAD
XINPUT_GAMEPAD, *PXINPUT_GAMEPAD;
// ******************************************************************
// * X_SBC_GAMEPAD for xbox SteelBattalion GAMEPAD struc
// * X_SBC_GAMEPAD for xbox SteelBattalion GAMEPAD struct
// ******************************************************************
typedef struct _SBC_GAMEPAD {
xbox::word_xt wButtons[3];
xbox::short_xt sAimingX;
xbox::short_xt sAimingY;
xbox::short_xt sRotationLever;//maybe only high byte was used.
xbox::ushort_xt sAimingX;
xbox::ushort_xt sAimingY;
xbox::short_xt sRotationLever; //maybe only high byte was used.
xbox::short_xt sSightChangeX;
xbox::short_xt sSightChangeY;
xbox::word_xt wLeftPedal;//maybe only high byte was used.
xbox::word_xt wMiddlePedal;//maybe only high byte was used.
xbox::word_xt wRightPedal;//maybe only high byte was used.
xbox::uchar_xt ucTunerDial;//low nibble, The 9 o'clock postion is 0, and the 6 o'clock position is 12. The blank area between the 6 and 9 o'clock positions is 13, 14, and 15 clockwise.
xbox::uchar_xt ucGearLever;//GearLever 1~5 for gear 1~5, 7~13 for gear R,N,1~5, 15 for gear R. we use the continues range from 7~13
xbox::word_xt wLeftPedal; //maybe only high byte was used.
xbox::word_xt wMiddlePedal; //maybe only high byte was used.
xbox::word_xt wRightPedal; //maybe only high byte was used.
xbox::uchar_xt ucTunerDial; //low nibble, The 9 o'clock postion is 0, and the 6 o'clock position is 12. The blank area between the 6 and 9 o'clock positions is 13, 14, and 15 clockwise.
xbox::uchar_xt ucGearLever; //GearLever 1~5 for gear 1~5, 7~13 for gear R,N,1~5, 15 for gear R. we use the continues range from 7~13
}
SBC_GAMEPAD, *PSBC_GAMEPAD;
// ergo720: from the description of the above gear levers, the gear to use is probably interpreted by looking at the first 3 bits of ucGearLever.
// Remove this when this theory is confirmed to be true or false
/*
0000 0000 -> should be N ??
0000 0001 1
0000 0010 2
0000 0011 3
0000 0100 4
0000 0101 5
0000 0110
0000 0111 R
0000 1000 N
0000 1001 1
0000 1010 2
0000 1011 3
0000 1100 4
0000 1101 5
0000 1110
0000 1111 R
*/
#pragma pack()
// ******************************************************************
// * XINPUT_RUMBLE
@ -223,7 +205,7 @@ XINPUT_CAPABILITIES, *PXINPUT_CAPABILITIES;
// all game controller use 0x01 GAMEPAD device type. then specify the subtype in returned Capabilities when XInputGetCapabilities called.
#define XINPUT_DEVTYPE_GAMEPAD 0x01
// SteelBattalion controller is the only one with special device type other than 1.
#define XINPUT_DEVTYPE_STEELBATTALION 0x80
#define XINPUT_DEVTYPE_STEELBATTALION 0x80
// ******************************************************************
// * Device XBOX Input Device SubTypes, for use in XINPUT_CAPABILITIES

View File

@ -31,18 +31,25 @@
// ******************************************************************
// * XINPUT_DEVICE_INFO
// ******************************************************************
typedef struct _CXBX_XINPUT_DEVICE_INFO
{
UCHAR ucType; //xbox controller type
UCHAR ucSubType; //xbox controller subtype
UCHAR ucInputStateSize; //xbox controller input state size in bytes, not include dwPacketNumber
UCHAR ucFeedbackSize; //xbox controller feedback size in bytes, not include FeedbackHeader
DWORD dwPacketNumber;
uint8_t ucType; //xbox controller type
uint8_t ucSubType; //xbox controller subtype
uint8_t ucInputStateSize; //xbox controller input state size in bytes, not include dwPacketNumber
uint8_t ucFeedbackSize; //xbox controller feedback size in bytes, not include FeedbackHeader
uint16_t dwPacketNumber;
}
CXBX_XINPUT_DEVICE_INFO, *PCXBX_XINPUT_DEVICE_INFO;
// ******************************************************************
// * XINPUT_IN_STATE
// ******************************************************************
union CXBX_XINPUT_IN_STATE {
XpadInput Gamepad;
SBCInput SBC;
};
//this structure is for use of tracking the xbox controllers assigned to 4 ports.
// ******************************************************************
// * CXBX_CONTROLLER_HOST_BRIDGE
@ -52,7 +59,7 @@ typedef struct _CXBX_CONTROLLER_HOST_BRIDGE
HANDLE hXboxDevice; //xbox device handle to this device, we use the address of this bridge as the handle, only set after opened. cleared after closed.
int XboxPort; //xbox port# for this xbox controller
XBOX_INPUT_DEVICE XboxType; //xbox device type
void* InState;
CXBX_XINPUT_IN_STATE * InState;
bool bPendingRemoval;
bool bSignaled;
bool bIoInProgress;

View File

@ -64,11 +64,11 @@ void SyncInputSettings(int port_num, int dev_type, bool is_opt)
return false;
});
if (it != g_Settings->m_input_profiles[dev_type].end()) {
char controls_name[XBOX_CTRL_NUM_BUTTONS][30];
char controls_name[HIGHEST_NUM_BUTTONS][30];
for (int index = 0; index < dev_num_buttons[dev_type]; index++) {
strncpy(controls_name[index], it->ControlList[index].c_str(), 30);
}
g_EmuShared->SetInputBindingsSettings(controls_name, XBOX_CTRL_NUM_BUTTONS, port_num);
g_EmuShared->SetInputBindingsSettings(controls_name, dev_num_buttons[dev_type], port_num);
}
}
}
@ -115,11 +115,15 @@ INT_PTR CALLBACK DlgInputConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPAR
for (int i = 0, j = 0; i != 4; i++) {
HWND hHandle = GetDlgItem(hWndDlg, IDC_DEVICE_PORT1 + i);
for (auto input : input_support_list) {
LRESULT index = SendMessage(hHandle, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(input.name));
SendMessage(hHandle, CB_SETITEMDATA, index,
to_underlying(input.type));
if (g_Settings->m_input_port[i].Type == to_underlying(input.type)) {
for (auto dev_type : {
XBOX_INPUT_DEVICE::DEVICE_INVALID,
XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE,
XBOX_INPUT_DEVICE::MS_CONTROLLER_S,
XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER
}) {
LRESULT index = SendMessage(hHandle, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(GetInputDeviceName(to_underlying(dev_type)).c_str()));
SendMessage(hHandle, CB_SETITEMDATA, index, to_underlying(dev_type));
if (g_Settings->m_input_port[i].Type == to_underlying(dev_type)) {
SendMessage(hHandle, CB_SETCURSEL, index, 0);
if (g_Settings->m_input_port[i].Type == to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) {
EnableWindow(GetDlgItem(hWndDlg, IDC_CONFIGURE_PORT1 + i), FALSE);
@ -175,6 +179,9 @@ INT_PTR CALLBACK DlgInputConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPAR
assert(port != -1);
HWND hHandle = GetDlgItem(hWndDlg, IDC_DEVICE_PORT1 + port);
int DeviceType = SendMessage(hHandle, CB_GETITEMDATA, SendMessage(hHandle, CB_GETCURSEL, 0, 0), 0);
assert(DeviceType > to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID) &&
DeviceType < to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX));
if (g_bHasOptChanges) {
UpdateInputOpt(hWndDlg);
g_InputDeviceManager.UpdateOpt(true);
@ -190,7 +197,7 @@ INT_PTR CALLBACK DlgInputConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPAR
break;
case to_underlying(XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER): {
DialogBoxParam(GetModuleHandle(nullptr), MAKEINTRESOURCE(IDD_VIRTUAL_SBC_FEEDBACK), hWndDlg, DlgSBControllerConfigProc,
DialogBoxParam(GetModuleHandle(nullptr), MAKEINTRESOURCE(IDD_SBC_CFG), hWndDlg, DlgSBControllerConfigProc,
(DeviceType << 8) | port);
}
break;
@ -198,8 +205,6 @@ INT_PTR CALLBACK DlgInputConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPAR
default:
break;
}
assert(DeviceType > to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID) &&
DeviceType < to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX));
// Also inform the kernel process if it exists
SyncInputSettings(port, DeviceType, false);

View File

@ -34,6 +34,205 @@
#include "common/Logging.h"
static constexpr std::array<std::array<const char *, XBOX_CTRL_NUM_BUTTONS>, 2> button_xbox_ctrl_default = { {
{ "Pad N", "Pad S", "Pad W", "Pad E", "Start", "Back", "Thumb L", "Thumb R", "Button A", "Button B", "Button X", "Button Y", "Shoulder R", "Shoulder L", "Trigger L",
"Trigger R", "Left X+", "Left X-", "Left Y+", "Left Y-", "Right X+", "Right X-", "Right Y+", "Right Y-", "LeftRight" },
{ "UP", "DOWN", "LEFT", "RIGHT", "RETURN", "SPACE", "B", "M", "S", "D", "W", "E", "C", "X", "Q", "R", "H", "F", "T", "G", "L", "J", "I", "K", "" }
} };
static DukeInputWindow *g_InputWindow = nullptr;
void DukeInputWindow::Initialize(HWND hwnd, int port_num, int dev_type)
{
// Save window/device specific variables
m_hwnd_window = hwnd;
m_hwnd_device_list = GetDlgItem(m_hwnd_window, IDC_DEVICE_LIST);
m_hwnd_profile_list = GetDlgItem(m_hwnd_window, IDC_PROFILE_NAME);
m_hwnd_default = GetDlgItem(m_hwnd_window, IDC_DEFAULT);
m_dev_type = dev_type;
m_max_num_buttons = dev_num_buttons[dev_type];
m_port_num = port_num;
m_bHasChanges = false;
m_bIsBinding = false;
// Set window icon
SetClassLong(m_hwnd_window, GCL_HICON, (LONG)LoadIcon(GetModuleHandle(nullptr), MAKEINTRESOURCE(IDI_CXBX)));
// Set window title
std::string title;
switch (m_dev_type)
{
case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE): {
title += "Xbox Controller Duke at port ";
}
break;
case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S): {
title += "Xbox Controller S at port ";
}
break;
}
SendMessage(m_hwnd_window, WM_SETTEXT, 0,
reinterpret_cast<LPARAM>((title + std::to_string(PORT_INC(m_port_num))).c_str()));
// Set the maximum profile name lenght the user can enter in the profile combobox
SendMessage(m_hwnd_profile_list, CB_LIMITTEXT, 49, 0);
// construct emu device
m_DeviceConfig = new EmuDevice(m_dev_type, m_hwnd_window, this);
// Enumerate devices
UpdateDeviceList();
// Load currently saved profile for this port/device type
LoadDefaultProfile();
// Load currently selected host device
UpdateCurrentDevice();
// Load rumble binding
char rumble[30];
m_DeviceConfig->FindButtonByIndex(m_max_num_buttons - 1)->GetText(rumble, sizeof(rumble));
m_rumble = rumble;
// Install the subclass for the profile combobox
SetWindowSubclass(GetWindow(m_hwnd_profile_list, GW_CHILD), ProfileNameSubclassProc, 0, 0);
}
void DukeInputWindow::InitRumble(HWND hwnd)
{
m_hwnd_rumble = hwnd;
m_hwnd_rumble_list = GetDlgItem(m_hwnd_rumble, IDC_RUMBLE_LIST);
SendMessage(m_hwnd_rumble_list, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(""));
auto dev = g_InputDeviceManager.FindDevice(m_host_dev);
if (dev != nullptr) {
auto outputs = dev->GetOutputs();
for (const auto out : outputs) {
SendMessage(m_hwnd_rumble_list, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(out->GetName().c_str()));
}
}
SendMessage(m_hwnd_rumble_list, CB_SETCURSEL, SendMessage(m_hwnd_rumble_list, CB_FINDSTRINGEXACT, 1,
reinterpret_cast<LPARAM>(m_rumble.c_str())), 0);
}
void DukeInputWindow::UpdateRumble(int command)
{
switch (command)
{
case RUMBLE_SET: {
char rumble[30];
SendMessage(m_hwnd_rumble_list, WM_GETTEXT, sizeof(rumble), reinterpret_cast<LPARAM>(rumble));
m_rumble = rumble;
}
break;
case RUMBLE_UPDATE: {
m_DeviceConfig->FindButtonByIndex(m_max_num_buttons - 1)->UpdateText(m_rumble.c_str());
}
break;
case RUMBLE_TEST: {
DetectOutput(OUTPUT_TIMEOUT);
}
break;
}
}
void DukeInputWindow::BindDefault()
{
int api = EnableDefaultButton();
if (api != -1) {
m_DeviceConfig->BindDefault<XBOX_CTRL_NUM_BUTTONS>(button_xbox_ctrl_default[api]);
m_bHasChanges = true;
}
}
int DukeInputWindow::EnableDefaultButton()
{
if (std::strncmp(m_host_dev.c_str(), "XInput", std::strlen("XInput")) == 0) {
EnableWindow(m_hwnd_default, TRUE);
return XINPUT_DEFAULT;
}
else if (std::strncmp(m_host_dev.c_str(), "DInput", std::strlen("DInput")) == 0) {
EnableWindow(m_hwnd_default, TRUE);
return DINPUT_DEFAULT;
}
else {
EnableWindow(m_hwnd_default, FALSE);
return -1;
}
}
void DukeInputWindow::ClearBindings()
{
m_DeviceConfig->ClearButtons();
m_rumble = std::string();
m_bHasChanges = true;
}
void DukeInputWindow::UpdateProfile(const std::string &name, int command)
{
switch (command)
{
case PROFILE_LOAD: {
LoadProfile(name);
}
break;
case PROFILE_SAVE: {
SaveProfile(name);
}
break;
case PROFILE_DELETE: {
DeleteProfile(name);
}
break;
case RUMBLE_CLEAR: {
m_rumble = std::string();
}
break;
case BUTTON_CLEAR: {
m_bHasChanges = true;
}
break;
}
}
void DukeInputWindow::DetectOutput(int ms)
{
if (m_rumble == std::string()) {
return;
}
auto dev = g_InputDeviceManager.FindDevice(m_host_dev);
if (dev != nullptr) {
// Don't block the message processing loop
std::thread([this, dev, ms]() {
EnableWindow(m_hwnd_rumble, FALSE);
SendMessage(m_hwnd_rumble_list, WM_SETTEXT, 0, reinterpret_cast<LPARAM>("..."));
auto outputs = dev->GetOutputs();
for (const auto out : outputs) {
if (out->GetName() == m_rumble) {
out->SetState(1.0, 1.0);
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
for (const auto out : outputs) {
if (out->GetName() == m_rumble) {
out->SetState(0.0, 0.0);
}
}
SendMessage(m_hwnd_rumble_list, WM_SETTEXT, 0, reinterpret_cast<LPARAM>("Test"));
EnableWindow(m_hwnd_rumble, TRUE);
}).detach();
}
}
static INT_PTR CALLBACK DlgRumbleConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
INT_PTR CALLBACK DlgXidControllerConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
@ -52,7 +251,7 @@ INT_PTR CALLBACK DlgXidControllerConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wPar
assert(dev_type == to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE) ||
dev_type == to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S));
g_InputWindow = new InputWindow;
g_InputWindow = new DukeInputWindow;
g_InputWindow->Initialize(hWndDlg, port_num, dev_type);
}
break;
@ -78,10 +277,10 @@ INT_PTR CALLBACK DlgXidControllerConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wPar
}
break;
case IDC_XID_PROFILE_NAME: {
case IDC_PROFILE_NAME: {
if (HIWORD(wParam) == CBN_SELCHANGE) {
char name[50];
HWND hwnd = GetDlgItem(hWndDlg, IDC_XID_PROFILE_NAME);
HWND hwnd = GetDlgItem(hWndDlg, IDC_PROFILE_NAME);
LRESULT str_idx = SendMessage(hwnd, CB_GETCURSEL, 0, 0);
if (str_idx != CB_ERR) {
SendMessage(hwnd, CB_GETLBTEXT, str_idx, reinterpret_cast<LPARAM>(name));
@ -91,25 +290,25 @@ INT_PTR CALLBACK DlgXidControllerConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wPar
}
break;
case IDC_XID_PROFILE_SAVE:
case IDC_XID_PROFILE_DELETE: {
case IDC_PROFILE_SAVE:
case IDC_PROFILE_DELETE: {
if (HIWORD(wParam) == BN_CLICKED) {
char name[50];
SendMessage(GetDlgItem(hWndDlg, IDC_XID_PROFILE_NAME), WM_GETTEXT,
SendMessage(GetDlgItem(hWndDlg, IDC_PROFILE_NAME), WM_GETTEXT,
sizeof(name), reinterpret_cast<LPARAM>(name));
g_InputWindow->UpdateProfile(std::string(name), (LOWORD(wParam) == IDC_XID_PROFILE_SAVE) ? PROFILE_SAVE : PROFILE_DELETE);
g_InputWindow->UpdateProfile(std::string(name), (LOWORD(wParam) == IDC_PROFILE_SAVE) ? PROFILE_SAVE : PROFILE_DELETE);
}
}
break;
case IDC_XID_DEFAULT: {
case IDC_DEFAULT: {
if (HIWORD(wParam) == BN_CLICKED) {
g_InputWindow->BindDefault();
}
}
break;
case IDC_XID_CLEAR: {
case IDC_CLEAR: {
if (HIWORD(wParam) == BN_CLICKED) {
if (PopupQuestionEx(hWndDlg, LOG_LEVEL::WARNING, PopupButtons::YesNo, PopupReturn::No, "Are you sure you want to remove all button bindings?") == PopupReturn::Yes) {
g_InputWindow->ClearBindings();

View File

@ -19,7 +19,7 @@
// * If not, write to the Free Software Foundation, Inc.,
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
// *
// * (c) 2019 ergo720
// * (c) 2021 ergo720
// *
// * All rights reserved
// *
@ -33,6 +33,87 @@
#include "gui\DlgInputConfig.h"
#include "common/Logging.h"
static SbcInputWindow *g_InputWindow = nullptr;
void SbcInputWindow::Initialize(HWND hwnd, int port_num, int dev_type)
{
// Save window/device specific variables
m_hwnd_window = hwnd;
m_hwnd_device_list = GetDlgItem(m_hwnd_window, IDC_DEVICE_LIST);
m_hwnd_profile_list = GetDlgItem(m_hwnd_window, IDC_PROFILE_NAME);
m_dev_type = dev_type;
m_max_num_buttons = dev_num_buttons[dev_type];
m_port_num = port_num;
m_bHasChanges = false;
m_bIsBinding = false;
// Set window icon
SetClassLong(m_hwnd_window, GCL_HICON, (LONG)LoadIcon(GetModuleHandle(nullptr), MAKEINTRESOURCE(IDI_CXBX)));
// Set window title
std::string title("Steel Battalion Controller at port ");
SendMessage(m_hwnd_window, WM_SETTEXT, 0,
reinterpret_cast<LPARAM>((title + std::to_string(PORT_INC(m_port_num))).c_str()));
// Set the maximum profile name lenght the user can enter in the profile combobox
SendMessage(m_hwnd_profile_list, CB_LIMITTEXT, 49, 0);
// construct emu device
m_DeviceConfig = new EmuDevice(m_dev_type, m_hwnd_window, this);
// Enumerate devices
UpdateDeviceList();
// Load currently saved profile for this port/device type
LoadDefaultProfile();
// Load currently selected host device
UpdateCurrentDevice();
// Install the subclass for the profile combobox
SetWindowSubclass(GetWindow(m_hwnd_profile_list, GW_CHILD), ProfileNameSubclassProc, 0, 0);
}
void SbcInputWindow::ClearBindings()
{
m_DeviceConfig->ClearButtons();
m_bHasChanges = true;
}
void SbcInputWindow::UpdateProfile(const std::string &name, int command)
{
switch (command)
{
case PROFILE_LOAD: {
LoadProfile(name);
}
break;
case PROFILE_SAVE: {
SaveProfile(name);
}
break;
case PROFILE_DELETE: {
DeleteProfile(name);
}
break;
case BUTTON_CLEAR: {
m_bHasChanges = true;
}
break;
}
}
int SbcInputWindow::EnableDefaultButton()
{
// The SBC window does not have a default button, so we return a dummy value here
return -1;
}
INT_PTR CALLBACK DlgSBControllerConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
@ -46,9 +127,9 @@ INT_PTR CALLBACK DlgSBControllerConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wPara
assert(port_num >= PORT_1 && port_num <= PORT_4);
// Ensure that the controller type is valid
dev_type == to_underlying(XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER);
assert(dev_type == to_underlying(XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER));
g_InputWindow = new InputWindow;
g_InputWindow = new SbcInputWindow;
g_InputWindow->Initialize(hWndDlg, port_num, dev_type);
}
break;
@ -74,10 +155,10 @@ INT_PTR CALLBACK DlgSBControllerConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wPara
}
break;
case IDC_XID_PROFILE_NAME: {
case IDC_PROFILE_NAME: {
if (HIWORD(wParam) == CBN_SELCHANGE) {
char name[50];
HWND hwnd = GetDlgItem(hWndDlg, IDC_XID_PROFILE_NAME);
HWND hwnd = GetDlgItem(hWndDlg, IDC_PROFILE_NAME);
LRESULT str_idx = SendMessage(hwnd, CB_GETCURSEL, 0, 0);
if (str_idx != CB_ERR) {
SendMessage(hwnd, CB_GETLBTEXT, str_idx, reinterpret_cast<LPARAM>(name));
@ -87,25 +168,18 @@ INT_PTR CALLBACK DlgSBControllerConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wPara
}
break;
case IDC_XID_PROFILE_SAVE:
case IDC_XID_PROFILE_DELETE: {
case IDC_PROFILE_SAVE:
case IDC_PROFILE_DELETE: {
if (HIWORD(wParam) == BN_CLICKED) {
char name[50];
SendMessage(GetDlgItem(hWndDlg, IDC_XID_PROFILE_NAME), WM_GETTEXT,
SendMessage(GetDlgItem(hWndDlg, IDC_PROFILE_NAME), WM_GETTEXT,
sizeof(name), reinterpret_cast<LPARAM>(name));
g_InputWindow->UpdateProfile(std::string(name), (LOWORD(wParam) == IDC_XID_PROFILE_SAVE) ? PROFILE_SAVE : PROFILE_DELETE);
g_InputWindow->UpdateProfile(std::string(name), (LOWORD(wParam) == IDC_PROFILE_SAVE) ? PROFILE_SAVE : PROFILE_DELETE);
}
}
break;
case IDC_XID_DEFAULT: {
if (HIWORD(wParam) == BN_CLICKED) {
g_InputWindow->BindDefault();
}
}
break;
case IDC_XID_CLEAR: {
case IDC_CLEAR: {
if (HIWORD(wParam) == BN_CLICKED) {
if (PopupQuestionEx(hWndDlg, LOG_LEVEL::WARNING, PopupButtons::YesNo, PopupReturn::No, "Are you sure you want to remove all button bindings?") == PopupReturn::Yes) {
g_InputWindow->ClearBindings();
@ -121,81 +195,9 @@ INT_PTR CALLBACK DlgSBControllerConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wPara
}
break;
case IDC_SET_X:
case IDC_SET_Y:
case IDC_SET_A:
case IDC_SET_B:
case IDC_SET_WHITE:
case IDC_SET_BLACK:
case IDC_SET_LTRIGGER:
case IDC_SET_RTRIGGER:
case IDC_SET_LTHUMB:
case IDC_SET_RTHUMB:
case IDC_SET_START:
case IDC_SET_BACK:
case IDC_SET_DPAD_LEFT:
case IDC_SET_DPAD_RIGHT:
case IDC_SET_DPAD_UP:
case IDC_SET_DPAD_DOWN:
case IDC_SET_LEFT_POSY:
case IDC_SET_LEFT_NEGX:
case IDC_SET_LEFT_NEGY:
case IDC_SET_LEFT_POSX:
case IDC_SET_RIGHT_POSY:
case IDC_SET_RIGHT_NEGY:
case IDC_SET_RIGHT_NEGX:
case IDC_SET_RIGHT_POSX:
case IDC_GEAR_0:
case IDC_GEAR_1:
case IDC_GEAR_2:
case IDC_GEAR_3:
case IDC_GEAR_4:
case IDC_GEAR_5:
case IDC_GEAR_R:
case IDC_SIGHT_CHANGE_NEGY:
case IDC_OXYGEN_SUPPLY_SYSTEM:
case IDC_FILT_CONTROL_SYSTEM:
case IDC_FUEL_FLOW_RATE:
case IDC_BUFFER_MATERIAL:
case IDC_VT_LOCATION_MEASUREMENT:
case IDC_ROTATION_LEVER:
case IDC_BTN_SIGHT_CHANGE:
case IDC_BTN_COM1:
case IDC_BTN_COM2:
case IDC_BTN_COM3:
case IDC_BTN_COM4:
case IDC_BTN_COM5:
case IDC_BTN_MAIN_WEAPON_CONTROL:
case IDC_BTN_SUB_WEAPON_CONTROL:
case IDC_BTN_MAGAZINE_CHANGE:
case IDC_BTN_WASHING:
case IDC_BTN_EXTINGUISHER:
case IDC_BTN_CHAFF:
case IDC_BTN_FUNC3:
case IDC_BTN_FUNC2:
case IDC_BTN_FUNC1:
case IDC_BTN_NIGHT_SCOPE:
case IDC_BTN_LINE_COLOR_CHANGE:
case IDC_BTN_OVERRIDE:
case IDC_BTN_MANIPULATOR:
case IDC_BTN_TANK_DETACH:
case IDC_BTN_FSS:
case IDC_RADIO_TD0:
case IDC_RADIO_TD1:
case IDC_RADIO_TD2:
case IDC_RADIO_TD3:
case IDC_RADIO_TD4:
case IDC_RADIO_TD5:
case IDC_RADIO_TD6:
case IDC_RADIO_TD7:
case IDC_RADIO_TD8:
case IDC_RADIO_TD9:
case IDC_RADIO_TD10:
case IDC_RADIO_TD11:
case IDC_RADIO_TD12:
case IDC_BTN_LOCK_ON:
case IDC_BTN_SUB_WEAPON:
case IDC_BTN_MAIN_WEAPON:
case IDC_BTN_SUB_WEAPON:
case IDC_BTN_LOCK_ON:
case IDC_BTN_EJECT:
case IDC_BTN_COCKPIT_HATCH:
case IDC_BTN_IGNITION:
@ -206,9 +208,49 @@ INT_PTR CALLBACK DlgSBControllerConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wPara
case IDC_BTN_SUB_MONITOR_MODE_SELECT:
case IDC_BTN_ZOOM_IN:
case IDC_BTN_ZOOM_OUT:
case IDC_BTN_FSS:
case IDC_BTN_MANIPULATOR:
case IDC_BTN_LINE_COLOR_CHANGE:
case IDC_BTN_WASHING:
case IDC_BTN_EXTINGUISHER:
case IDC_BTN_CHAFF:
case IDC_BTN_TANK_DETACH:
case IDC_BTN_OVERRIDE:
case IDC_BTN_NIGHT_SCOPE:
case IDC_BTN_FUNC1:
case IDC_BTN_FUNC2:
case IDC_BTN_FUNC3:
case IDC_BTN_MAIN_WEAPON_CONTROL:
case IDC_BTN_SUB_WEAPON_CONTROL:
case IDC_BTN_MAGAZINE_CHANGE:
case IDC_BTN_COM1:
case IDC_BTN_COM2:
case IDC_BTN_COM3:
case IDC_BTN_COM4:
case IDC_BTN_COM5:
case IDC_BTN_SIGHT_CHANGE:
case IDC_FILT_CONTROL_SYSTEM:
case IDC_OXYGEN_SUPPLY_SYSTEM:
case IDC_FUEL_FLOW_RATE:
case IDC_BUFFER_MATERIAL:
case IDC_VT_LOCATION_MEASUREMENT:
case IDC_AIMING_POSX:
case IDC_AIMING_NEGX:
case IDC_AIMING_POSY:
case IDC_AIMING_NEGY:
case IDC_LEVER_LEFT:
case IDC_LEVER_RIGHT:
case IDC_SIGHT_CHANGE_POSX:
case IDC_SIGHT_CHANGE_NEGX:
case IDC_SIGHT_CHANGE_POSY:
case IDC_SIGHT_CHANGE_NEGY:
case IDC_BTN_LEFT_PEDAL:
case IDC_BTN_MIDDLE_PEDAL:
case IDC_BTN_RIGHT_PEDAL: {
case IDC_BTN_RIGHT_PEDAL:
case IDC_RADIO_TD_UP:
case IDC_RADIO_TD_DOWN:
case IDC_GEAR_UP:
case IDC_GEAR_DOWN: {
if (HIWORD(wParam) == BN_CLICKED) {
g_InputWindow->BindButton(LOWORD(wParam));
}

View File

@ -31,12 +31,9 @@ BEGIN
BEGIN
END
IDD_VIRTUAL_SBC_FEEDBACK, DIALOG
IDD_SBC_CFG, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 1032
TOPMARGIN, 7
BOTTOMMARGIN, 207
BOTTOMMARGIN, 269
END
IDD_VIDEO_CFG, DIALOG
@ -92,7 +89,7 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMEN
CAPTION "Cxbx-Reloaded : Input Configuration"
FONT 8, "Verdana", 0, 0, 0x1
BEGIN
GROUPBOX "Xbox device configuration",IDC_XID_CONFIG,13,10,217,103,WS_GROUP,WS_EX_CLIENTEDGE
GROUPBOX "Xbox device configuration",IDC_DEVICE,13,10,217,103,WS_GROUP,WS_EX_CLIENTEDGE
COMBOBOX IDC_DEVICE_PORT1,50,25,110,14,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
COMBOBOX IDC_DEVICE_PORT2,50,46,110,14,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
COMBOBOX IDC_DEVICE_PORT3,50,67,110,14,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
@ -116,14 +113,14 @@ IDD_XID_DUKE_CFG DIALOGEX 0, 0, 528, 280
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
FONT 8, "Verdana", 0, 0, 0x1
BEGIN
GROUPBOX "Device",IDC_XID_CONFIG,12,10,175,35,WS_GROUP
GROUPBOX "Device",IDC_DEVICE,12,10,175,35,WS_GROUP
COMBOBOX IDC_DEVICE_LIST,21,23,101,15,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
PUSHBUTTON "Refresh",IDC_REFRESH_DEVICES,128,23,50,14,BS_FLAT
GROUPBOX "Profile",IDC_XID_PROFILE,197,10,320,35,WS_GROUP
COMBOBOX IDC_XID_PROFILE_NAME,207,24,194,10,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP
PUSHBUTTON "Save",IDC_XID_PROFILE_SAVE,405,23,50,14,BS_FLAT
PUSHBUTTON "Delete",IDC_XID_PROFILE_DELETE,459,23,50,14,BS_FLAT
GROUPBOX "Buttons",IDC_XID_BUTTONS,12,65,121,181,WS_GROUP
GROUPBOX "Profile",IDC_PROFILE,197,10,320,35,WS_GROUP
COMBOBOX IDC_PROFILE_NAME,207,24,194,10,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP
PUSHBUTTON "Save",IDC_PROFILE_SAVE,405,23,50,14,BS_FLAT
PUSHBUTTON "Delete",IDC_PROFILE_DELETE,459,23,50,14,BS_FLAT
GROUPBOX "Buttons",IDC_BUTTONS,12,65,121,181,WS_GROUP
PUSHBUTTON "",IDC_SET_A,59,75,57,14,BS_FLAT
PUSHBUTTON "",IDC_SET_B,59,93,57,14,BS_FLAT
PUSHBUTTON "",IDC_SET_X,59,111,57,14,BS_FLAT
@ -140,7 +137,7 @@ BEGIN
LTEXT "White",IDC_STATIC,28,165,20,14,SS_CENTERIMAGE
LTEXT "Back",IDC_STATIC,28,183,20,14,SS_CENTERIMAGE
LTEXT "Start",IDC_STATIC,28,201,20,14,SS_CENTERIMAGE
GROUPBOX "L Stick",IDC_XID_LSTICK,140,65,121,181,WS_GROUP
GROUPBOX "L Stick",IDC_LSTICK,140,65,121,181,WS_GROUP
PUSHBUTTON "",IDC_SET_LEFT_POSY,187,75,57,14,BS_FLAT
PUSHBUTTON "",IDC_SET_LEFT_NEGY,187,93,57,14,BS_FLAT
PUSHBUTTON "",IDC_SET_LEFT_NEGX,187,111,57,14,BS_FLAT
@ -150,8 +147,8 @@ BEGIN
LTEXT "Down",IDC_STATIC,156,93,20,14,SS_CENTERIMAGE
LTEXT "Left",IDC_STATIC,156,111,20,14,SS_CENTERIMAGE
LTEXT "Right",IDC_STATIC,156,129,20,14,SS_CENTERIMAGE
LTEXT "L Click",IDC_STATIC,156,147,27,14,SS_CENTERIMAGE
GROUPBOX "R Stick",IDC_XID_RSTICK,268,65,121,181,WS_GROUP
LTEXT "Click",IDC_STATIC,156,147,27,14,SS_CENTERIMAGE
GROUPBOX "R Stick",IDC_RSTICK,268,65,121,181,WS_GROUP
PUSHBUTTON "",IDC_SET_RIGHT_POSY,315,75,57,14,BS_FLAT
PUSHBUTTON "",IDC_SET_RIGHT_NEGY,315,93,57,14,BS_FLAT
PUSHBUTTON "",IDC_SET_RIGHT_NEGX,315,111,57,14,BS_FLAT
@ -161,8 +158,8 @@ BEGIN
LTEXT "Down",IDC_STATIC,284,93,20,14,SS_CENTERIMAGE
LTEXT "Left",IDC_STATIC,284,111,20,14,SS_CENTERIMAGE
LTEXT "Right",IDC_STATIC,284,129,20,14,SS_CENTERIMAGE
LTEXT "R Click",IDC_STATIC,284,147,27,14,SS_CENTERIMAGE
GROUPBOX "D Pad",IDC_XID_DPAD,396,65,121,88,WS_GROUP
LTEXT "Click",IDC_STATIC,284,147,27,14,SS_CENTERIMAGE
GROUPBOX "D Pad",IDC_DPAD,396,65,121,88,WS_GROUP
PUSHBUTTON "",IDC_SET_DPAD_UP,443,75,57,14,BS_FLAT
PUSHBUTTON "",IDC_SET_DPAD_DOWN,443,93,57,14,BS_FLAT
PUSHBUTTON "",IDC_SET_DPAD_LEFT,443,111,57,14,BS_FLAT
@ -171,16 +168,16 @@ BEGIN
LTEXT "Down",IDC_STATIC,412,93,20,14,SS_CENTERIMAGE
LTEXT "Left",IDC_STATIC,412,111,20,14,SS_CENTERIMAGE
LTEXT "Right",IDC_STATIC,412,129,20,14,SS_CENTERIMAGE
GROUPBOX "Triggers",IDC_XID_TRIGGERS,396,157,121,52,WS_GROUP
GROUPBOX "Triggers",IDC_TRIGGERS,396,157,121,52,WS_GROUP
PUSHBUTTON "",IDC_SET_LTRIGGER,443,168,57,14,BS_FLAT
PUSHBUTTON "",IDC_SET_RTRIGGER,443,187,57,14,BS_FLAT
LTEXT "Left",IDC_STATIC,412,168,20,14,SS_CENTERIMAGE
LTEXT "Right",IDC_STATIC,412,187,20,14,SS_CENTERIMAGE
GROUPBOX "Rumble",IDC_XID_RUMBLE,396,212,121,34,WS_GROUP
GROUPBOX "Rumble",IDC_RUMBLE,396,212,121,34,WS_GROUP
PUSHBUTTON "",IDC_SET_MOTOR,443,224,57,14,BS_FLAT
LTEXT "Motor",IDC_STATIC,412,224,26,14,SS_CENTERIMAGE
PUSHBUTTON "Default Bindings",IDC_XID_DEFAULT,362,256,69,14,BS_FLAT
PUSHBUTTON "Clear",IDC_XID_CLEAR,443,256,50,14,BS_FLAT
PUSHBUTTON "Default Bindings",IDC_DEFAULT,362,256,69,14,BS_FLAT
PUSHBUTTON "Clear",IDC_CLEAR,443,256,50,14,BS_FLAT
END
IDD_RUMBLE_CFG DIALOGEX 0, 0, 155, 35
@ -192,111 +189,134 @@ BEGIN
PUSHBUTTON "Test",IDC_RUMBLE_TEST,95,11,45,14,BS_FLAT
END
IDD_VIRTUAL_SBC_FEEDBACK DIALOGEX 0, 0, 1039, 280
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Virtual SteelBattalion Controller"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
IDD_SBC_CFG DIALOGEX 0, 0, 854, 280
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
FONT 8, "Verdana", 0, 0, 0x1
BEGIN
GROUPBOX "Device", IDC_XID_CONFIG, 12, 10, 175, 35, WS_GROUP
COMBOBOX IDC_DEVICE_LIST, 21, 23, 101, 15, CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
PUSHBUTTON "Refresh", IDC_REFRESH_DEVICES, 128, 23, 50, 14, BS_FLAT
GROUPBOX "Profile", IDC_XID_PROFILE, 703, 10, 320, 35, WS_GROUP
COMBOBOX IDC_XID_PROFILE_NAME, 713, 24, 194, 10, CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP //Move forward 506
PUSHBUTTON "Save", IDC_XID_PROFILE_SAVE, 911, 23, 50, 14, BS_FLAT
PUSHBUTTON "Delete", IDC_XID_PROFILE_DELETE, 965, 23, 50, 14, BS_FLAT
PUSHBUTTON "Clear", IDC_XID_CLEAR, 192, 23, 50, 14, BS_FLAT
GROUPBOX "Left Block",IDC_LEFTBLOCK,12,50,292,203,0,WS_EX_RIGHT //Subtract 8x from all Left Block items
//GROUPBOX "Left Block",IDC_LEFTBLOCK2,7,50,329,200,0,WS_EX_RIGHT
GROUPBOX "Communication Buttons",IDC_LEFTBLOCK2,314,55,315,28,0,WS_EX_RIGHT
GROUPBOX "", IDC_LEFTBLOCK2, 309, 50, 329, 203, 0, WS_EX_RIGHT
GROUPBOX "Center Block", IDC_LEFTBLOCK2, 439, 178, 200, 75, 0, WS_EX_RIGHT //309
GROUPBOX "Right Block",IDC_RIGHTBLOCK,689,50,329,203,0,WS_EX_LEFT
GROUPBOX "Gear Lever",IDC_GEAR_LEVER,16,65,87,145,WS_GROUP,WS_EX_LEFT
GROUPBOX "Toggle Switches",IDC_STATIC,113,148,185,100,0,WS_EX_LEFT
PUSHBUTTON "", IDC_GEAR_5, 35, 79, 57, 14, BS_FLAT //Debug exception?
LTEXT "5", IDC_STATIC, 25, 79, 5, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_GEAR_4, 35, 97, 57, 14, BS_FLAT //Debug exception?
LTEXT "4", IDC_STATIC, 25, 97, 5, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_GEAR_3, 35, 115, 57, 14, BS_FLAT //Debug exception?
LTEXT "3", IDC_STATIC, 25, 115, 5, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_GEAR_2, 35, 133, 57, 14, BS_FLAT //Debug exception?
LTEXT "2", IDC_STATIC, 25, 133, 5, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_GEAR_1, 35, 152, 57, 14, BS_FLAT //Debug exception?
LTEXT "1", IDC_STATIC, 25, 152, 5, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_GEAR_0, 35, 169, 57, 14, BS_FLAT //Debug exception?
LTEXT "N", IDC_STATIC, 25, 169, 5, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_GEAR_R, 35, 187, 57, 14, BS_FLAT //Debug exception?
LTEXT "R", IDC_STATIC, 25, 187, 5, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_VT_LOCATION_MEASUREMENT, 142, 161, 57, 14, BS_FLAT //Doesn't save
LTEXT "VT-Location Measurement", IDC_STATIC, 204, 161, 90, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_BUFFER_MATERIAL, 142, 178, 57, 14, BS_FLAT //Doesn't save
LTEXT "Buffer Material", IDC_STATIC, 204, 178, 80, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_FUEL_FLOW_RATE, 142, 195, 57, 14, BS_FLAT //Doesn't save
LTEXT "Fuel Flow Rate", IDC_STATIC, 204, 195, 80, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_OXYGEN_SUPPLY_SYSTEM, 120, 212, 57, 14, BS_FLAT //Doesn't save
LTEXT "Oxygen Supply System", IDC_STATIC, 182, 212, 80, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_FILT_CONTROL_SYSTEM, 120, 229, 57, 14, BS_FLAT //Doesn't save
LTEXT "Filt Control System", IDC_STATIC, 182, 229, 80, 14, SS_CENTERIMAGE
LTEXT "Sight Change", IDC_STATIC, 139, 55, 80, 11, SS_CENTERIMAGE
LTEXT "Rotation Lever", IDC_STATIC, 242, 88, 50, 11, SS_CENTERIMAGE
LTEXT "Left", IDC_STATIC, 217, 99, 65, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_ROTATION_LEVER, 237, 99, 57, 14, BS_FLAT //Doesn't save
LTEXT "Right", IDC_STATIC, 215, 115, 65, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_ROTATION_LEVER, 238, 115, 57, 14, BS_FLAT //I don't think IDC_ROTATION_LEVER should be duplicated? Is it only one axis?
LTEXT "Up", IDC_STATIC, 113, 67, 65, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_SET_LEFT_POSY, 132, 67, 57, 14, BS_FLAT //Debug exception?
LTEXT "Down", IDC_STATIC, 109, 83, 65, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_SET_LEFT_NEGY, 132, 83, 57, 14, BS_FLAT //Debug exception?
LTEXT "Left", IDC_STATIC, 111, 99, 65, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_SET_LEFT_NEGX, 132, 99, 57, 14, BS_FLAT //Debug exception?
LTEXT "Right", IDC_STATIC, 109, 115, 65, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_SET_LEFT_POSX, 132, 115, 57, 14, BS_FLAT //Debug exception?
LTEXT "Center", IDC_STATIC, 108, 131, 65, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_BTN_SIGHT_CHANGE, 132, 131, 57, 14, BS_FLAT //Doesn't save
PUSHBUTTON "", IDC_BTN_COM1, 319, 63, 57, 14, BS_FLAT //Doesn't save
PUSHBUTTON "", IDC_BTN_COM2, 380, 63, 57, 14, BS_FLAT //Doesn't save
PUSHBUTTON "", IDC_BTN_COM3, 441, 63, 57, 14, BS_FLAT //Doesn't save
PUSHBUTTON "", IDC_BTN_COM4, 502, 63, 57, 14, BS_FLAT //Doesn't save
PUSHBUTTON "", IDC_BTN_COM5, 563, 63, 57, 14, BS_FLAT //Doesn't save
LTEXT "Main Weapon", IDC_STATIC, 459, 223, 65, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_BTN_MAIN_WEAPON_CONTROL, 451, 235, 57, 14, BS_FLAT //Doesn't save
LTEXT "Sub Weapon", IDC_STATIC, 519, 223, 65, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_BTN_SUB_WEAPON_CONTROL, 512, 235, 57, 14, BS_FLAT //Doesn't save
LTEXT "Magazine Change", IDC_STATIC, 573, 223, 60, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_BTN_MAGAZINE_CHANGE, 573, 235, 57, 14, BS_FLAT //Doesn't save
LTEXT "Washing", IDC_STATIC, 465, 188, 65, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_BTN_WASHING, 451, 200, 57, 14, BS_FLAT
LTEXT "Extinguisher", IDC_STATIC, 520, 188, 65, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_BTN_EXTINGUISHER, 512, 200, 57, 14, BS_FLAT
LTEXT "Chaff", IDC_STATIC, 593, 188, 40, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_BTN_CHAFF, 573, 200, 57, 14, BS_FLAT
LTEXT "F3", IDC_STATIC, 475, 143, 65, 14, SS_CENTERIMAGE //-5y
PUSHBUTTON "", IDC_BTN_FUNC3, 451, 155, 57, 14, BS_FLAT //Crashes
LTEXT "Night Scope", IDC_STATIC, 520, 143, 65, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_BTN_NIGHT_SCOPE, 512, 155, 57, 14, BS_FLAT
LTEXT "Line Color Change", IDC_STATIC, 573, 143, 60, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_BTN_LINE_COLOR_CHANGE, 573, 155, 57, 14, BS_FLAT
LTEXT "F2", IDC_STATIC, 475, 113, 65, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_BTN_FUNC2, 451, 125, 57, 14, BS_FLAT
LTEXT "Override", IDC_STATIC, 525, 112, 65, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_BTN_OVERRIDE, 512, 125, 57, 14, BS_FLAT
LTEXT "Manipulator", IDC_STATIC, 583, 113, 40, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_BTN_MANIPULATOR, 573, 125, 57, 14, BS_FLAT
LTEXT "F1", IDC_STATIC, 475, 83, 65, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_BTN_FUNC1, 451, 95, 57, 14, BS_FLAT
LTEXT "Tank Detach", IDC_STATIC, 524, 83, 65, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_BTN_TANK_DETACH, 512, 95, 57, 14, BS_FLAT
LTEXT "F.S.S", IDC_STATIC, 583, 83, 40, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_BTN_FSS, 573, 95, 57, 14, BS_FLAT
LTEXT "Slide-step Pedal", IDC_STATIC, 320, 11, 60, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_BTN_LEFT_PEDAL, 320, 23, 50, 14, BS_FLAT //Doesn't save
LTEXT "Brake Pedal", IDC_STATIC, 425, 11, 40, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_BTN_MIDDLE_PEDAL, 420, 23, 50, 14, BS_FLAT //Doesn't save
LTEXT "Gas Pedal", IDC_STATIC, 529, 11, 40, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_BTN_RIGHT_PEDAL, 520, 23, 50, 14, BS_FLAT //Doesn't save
LTEXT "Main Weapon", IDC_STATIC, 840, 80, 60, 14, SS_CENTERIMAGE
PUSHBUTTON "", IDC_BTN_MAIN_WEAPON, 840, 60, 57, 14, BS_FLAT
GROUPBOX "Device",IDC_DEVICE,12,10,175,35,WS_GROUP
COMBOBOX IDC_DEVICE_LIST,21,23,101,15,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
PUSHBUTTON "Refresh",IDC_REFRESH_DEVICES,128,23,50,14,BS_FLAT
GROUPBOX "Profile",IDC_PROFILE,196,10,320,35,WS_GROUP
COMBOBOX IDC_PROFILE_NAME,206,23,194,10,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP
PUSHBUTTON "Save",IDC_PROFILE_SAVE,404,23,50,14,BS_FLAT
PUSHBUTTON "Delete",IDC_PROFILE_DELETE,458,23,50,14,BS_FLAT
PUSHBUTTON "Clear",IDC_CLEAR,774,23,50,14,BS_FLAT
GROUPBOX "Left Block",IDC_LEFTBLOCK,12,50,281,167
GROUPBOX "Center Block",IDC_CENTERBLOCK,299,50,281,218
GROUPBOX "Right Block",IDC_RIGHTBLOCK,586,50,255,218
PUSHBUTTON "",IDC_GEAR_UP,67,64,57,14,BS_FLAT
LTEXT "Gear Up",IDC_STATIC,25,64,38,14,SS_CENTERIMAGE
PUSHBUTTON "",IDC_GEAR_DOWN,67,82,57,14,BS_FLAT
LTEXT "Gear Down",IDC_STATIC,25,82,38,14,SS_CENTERIMAGE
PUSHBUTTON "",IDC_VT_LOCATION_MEASUREMENT,223,64,57,14,BS_FLAT
LTEXT "VT-Location Measurement",IDC_STATIC,133,64,90,14,SS_CENTERIMAGE
PUSHBUTTON "",IDC_BUFFER_MATERIAL,223,82,57,14,BS_FLAT
LTEXT "Buffer Material",IDC_STATIC,133,82,80,14,SS_CENTERIMAGE
PUSHBUTTON "",IDC_FUEL_FLOW_RATE,223,100,57,14,BS_FLAT
LTEXT "Fuel Flow Rate",IDC_STATIC,133,100,80,14,SS_CENTERIMAGE
PUSHBUTTON "",IDC_OXYGEN_SUPPLY_SYSTEM,223,118,57,14,BS_FLAT
LTEXT "Oxygen Supply System",IDC_STATIC,133,118,80,14,SS_CENTERIMAGE
PUSHBUTTON "",IDC_FILT_CONTROL_SYSTEM,223,136,57,14,BS_FLAT
LTEXT "Filt Control System",IDC_STATIC,133,136,80,14,SS_CENTERIMAGE
PUSHBUTTON "",IDC_BTN_SIGHT_CHANGE,223,154,57,14, BS_FLAT
LTEXT "Sight Change",IDC_STATIC,133,154,80,14, SS_CENTERIMAGE
PUSHBUTTON "",IDC_LEVER_LEFT,67,172,57,14,BS_FLAT
LTEXT "Lever Left",IDC_STATIC,25,172,42,14,SS_CENTERIMAGE
PUSHBUTTON "",IDC_LEVER_RIGHT,67,191,57,14,BS_FLAT
LTEXT "Lever Right",IDC_STATIC,25,191,42,14,SS_CENTERIMAGE
PUSHBUTTON "",IDC_SIGHT_CHANGE_POSY,67,100,57,14,BS_FLAT
LTEXT "Sight Up",IDC_STATIC,25,100,37,14,SS_CENTERIMAGE
PUSHBUTTON "",IDC_SIGHT_CHANGE_NEGY,67,118,57,14,BS_FLAT
LTEXT "Sight Down",IDC_STATIC,25,118,40,14,SS_CENTERIMAGE
PUSHBUTTON "",IDC_SIGHT_CHANGE_NEGX,67,136,57,14,BS_FLAT
LTEXT "Sight Left",IDC_STATIC,25,136,38,14,SS_CENTERIMAGE
PUSHBUTTON "",IDC_SIGHT_CHANGE_POSX,67,154,57,14,BS_FLAT
LTEXT "Sight Right",IDC_STATIC,25,154,39,14,SS_CENTERIMAGE
PUSHBUTTON "",IDC_BTN_COM1,375,64,57,14,BS_FLAT
PUSHBUTTON "",IDC_BTN_COM2,375,82,57,14,BS_FLAT
PUSHBUTTON "",IDC_BTN_COM3,375,100,57,14,BS_FLAT
PUSHBUTTON "",IDC_BTN_COM4,375,118,57,14,BS_FLAT
PUSHBUTTON "",IDC_BTN_COM5,375,136,57,14,BS_FLAT
LTEXT "Extinguisher",IDC_STATIC,444,136,65,14,SS_CENTERIMAGE
PUSHBUTTON "",IDC_BTN_MAIN_WEAPON_CONTROL,511,172,57,14,BS_FLAT
LTEXT "Main Weapon",IDC_STATIC,444,172,65,14,SS_CENTERIMAGE
PUSHBUTTON "",IDC_BTN_SUB_WEAPON_CONTROL,511,190,57,14,BS_FLAT
LTEXT "Magazine Change",IDC_STATIC,444,208,60,14,SS_CENTERIMAGE
PUSHBUTTON "",IDC_BTN_MAGAZINE_CHANGE,511,208,57,14,BS_FLAT
LTEXT "Washing",IDC_STATIC,444,118,65,14,SS_CENTERIMAGE
PUSHBUTTON "",IDC_BTN_WASHING,511,118,57,14,BS_FLAT
LTEXT "Chaff",IDC_STATIC,444,154,65,14,SS_CENTERIMAGE
PUSHBUTTON "",IDC_BTN_EXTINGUISHER,511,136,57,14,BS_FLAT
LTEXT "Sub Weapon",IDC_STATIC,444,190,40,14,SS_CENTERIMAGE
PUSHBUTTON "",IDC_BTN_CHAFF,511,154,57,14,BS_FLAT
LTEXT "Function 3",IDC_STATIC,311,191,44,14,SS_CENTERIMAGE
PUSHBUTTON "",IDC_BTN_FUNC3,375,190,57,14,BS_FLAT
LTEXT "Night Scope",IDC_STATIC,311,244,51,14,SS_CENTERIMAGE
PUSHBUTTON "",IDC_BTN_NIGHT_SCOPE,375,244,57,14,BS_FLAT
LTEXT "Line Color Change",IDC_STATIC,444,100,60,14,SS_CENTERIMAGE
PUSHBUTTON "",IDC_BTN_LINE_COLOR_CHANGE,511,100,57,14,BS_FLAT
LTEXT "Function 2",IDC_STATIC,311,172,46,14,SS_CENTERIMAGE
PUSHBUTTON "",IDC_BTN_FUNC2,375,172,57,14,BS_FLAT
LTEXT "Override",IDC_STATIC,311,226,47,14,SS_CENTERIMAGE
PUSHBUTTON "",IDC_BTN_OVERRIDE,375,226,57,14,BS_FLAT
LTEXT "Manipulator",IDC_STATIC,444,82,40,14,SS_CENTERIMAGE
PUSHBUTTON "",IDC_BTN_MANIPULATOR,511,82,57,14,BS_FLAT
LTEXT "Function 1",IDC_STATIC,311,154,37,14,SS_CENTERIMAGE
PUSHBUTTON "",IDC_BTN_FUNC1,375,154,57,14,BS_FLAT
LTEXT "Tank Detach",IDC_STATIC,311,208,52,14,SS_CENTERIMAGE
PUSHBUTTON "",IDC_BTN_TANK_DETACH,375,208,57,14,BS_FLAT
LTEXT "F.S.S",IDC_STATIC,444,64,40,14,SS_CENTERIMAGE
PUSHBUTTON "",IDC_BTN_FSS,511,64,57,14,BS_FLAT
LTEXT "Slide-step",IDC_STATIC,17,239,40,14,SS_CENTERIMAGE
LTEXT "Brake",IDC_STATIC,120,239,26,14,SS_CENTERIMAGE
LTEXT "Accel",IDC_STATIC,209,239,23,14,SS_CENTERIMAGE
LTEXT "Communication 1",IDC_STATIC,311,64,64,14,SS_CENTERIMAGE
LTEXT "Communication 2",IDC_STATIC,311,82,64,14,SS_CENTERIMAGE
LTEXT "Communication 3",IDC_STATIC,311,100,64,14,SS_CENTERIMAGE
LTEXT "Communication 4",IDC_STATIC,311,118,64,14,SS_CENTERIMAGE
LTEXT "Communication 5",IDC_STATIC,311,136,64,14,SS_CENTERIMAGE
GROUPBOX "Pedals",IDC_BLOCK_PEDALS,12,220,281,48
PUSHBUTTON "",IDC_BTN_LEFT_PEDAL,55,239,57,14,BS_FLAT
PUSHBUTTON "",IDC_BTN_MIDDLE_PEDAL,144,239,57,14,BS_FLAT
PUSHBUTTON "",IDC_BTN_RIGHT_PEDAL,230,239,57,14,BS_FLAT
LTEXT "Tuner Up",IDC_STATIC,444,226,60,14,SS_CENTERIMAGE
LTEXT "Tuner Down",IDC_STATIC,444,244,60,14,SS_CENTERIMAGE
PUSHBUTTON "",IDC_RADIO_TD_UP,511,226,57,14,BS_FLAT
PUSHBUTTON "",IDC_RADIO_TD_DOWN,511,244,57,14,BS_FLAT
PUSHBUTTON "",IDC_AIMING_POSY,650,64,57,14,BS_FLAT
PUSHBUTTON "",IDC_AIMING_NEGY,650,82,57,14,BS_FLAT
PUSHBUTTON "",IDC_AIMING_NEGX,650,100,57,14,BS_FLAT
PUSHBUTTON "",IDC_AIMING_POSX,650,118,57,14,BS_FLAT
PUSHBUTTON "",IDC_BTN_MAIN_WEAPON,650,136,57,14,BS_FLAT
PUSHBUTTON "",IDC_BTN_SUB_WEAPON,650,154,57,14,BS_FLAT
PUSHBUTTON "",IDC_BTN_LOCK_ON,650,172,57,14,BS_FLAT
PUSHBUTTON "",IDC_BTN_OPEN_CLOSE,650,190,57,14,BS_FLAT
PUSHBUTTON "",IDC_BTN_MODE_SELECT,650,208,57,14,BS_FLAT
PUSHBUTTON "",IDC_BTN_ZOOM_IN,650,226,57,14,BS_FLAT
PUSHBUTTON "",IDC_BTN_MAP_ZOOM_IN_OUT,650,244,57,14,BS_FLAT
PUSHBUTTON "",IDC_BTN_START,771,154,57,14,BS_FLAT
PUSHBUTTON "",IDC_BTN_IGNITION,771,136,57,14,BS_FLAT
PUSHBUTTON "",IDC_BTN_COCKPIT_HATCH,771,118,57,14,BS_FLAT
PUSHBUTTON "",IDC_BTN_EJECT,771,100,57,14,BS_FLAT
PUSHBUTTON "",IDC_BTN_ZOOM_OUT,771,82,57,14,BS_FLAT
PUSHBUTTON "",IDC_BTN_SUB_MONITOR_MODE_SELECT,771,64,57,14,BS_FLAT
LTEXT "Aim Up",IDC_STATIC,599,64,51,14,SS_CENTERIMAGE
LTEXT "Aim Down",IDC_STATIC,599,82,51,14,SS_CENTERIMAGE
LTEXT "Aim Left",IDC_STATIC,599,100,51,14,SS_CENTERIMAGE
LTEXT "Aim Right",IDC_STATIC,599,118,51,14,SS_CENTERIMAGE
LTEXT "Main Weapon",IDC_STATIC,599,136,51,14,SS_CENTERIMAGE
LTEXT "Sub Weapon",IDC_STATIC,599,154,51,14,SS_CENTERIMAGE
LTEXT "Lock On",IDC_STATIC,599,172,51,14,SS_CENTERIMAGE
LTEXT "Open Close",IDC_STATIC,599,190,51,14,SS_CENTERIMAGE
LTEXT "Mode Select",IDC_STATIC,599,208,51,14,SS_CENTERIMAGE
LTEXT "Zoom In",IDC_STATIC,599,226,51,14,SS_CENTERIMAGE
LTEXT "Map Zoom",IDC_STATIC,599,244,51,14,SS_CENTERIMAGE
LTEXT "Start",IDC_STATIC,720,154,51,14,SS_CENTERIMAGE
LTEXT "Ignition",IDC_STATIC,720,136,51,14,SS_CENTERIMAGE
LTEXT "Cockpit Hatch",IDC_STATIC,720,118,51,14,SS_CENTERIMAGE
LTEXT "Eject",IDC_STATIC,720,100,51,14,SS_CENTERIMAGE
LTEXT "Zoom Out",IDC_STATIC,720,82,51,14,SS_CENTERIMAGE
LTEXT "Sub Monitor",IDC_STATIC,720,64,51,14,SS_CENTERIMAGE
END
IDD_VIDEO_CFG DIALOGEX 0, 0, 259, 150
@ -535,6 +555,11 @@ BEGIN
0
END
IDD_SBC_CFG AFX_DIALOG_LAYOUT
BEGIN
0
END
/////////////////////////////////////////////////////////////////////////////
//

View File

@ -17,7 +17,7 @@
#define IDD_ABOUT 119
#define IDR_CONTRIBUTORS 121
#define IDR_COPYING 122
#define IDD_VIRTUAL_SBC_FEEDBACK 133
#define IDD_SBC_CFG 133
#define IDD_XID_DUKE_CFG 134
#define IDD_RUMBLE_CFG 135
#define IDD_NETWORK_CFG 136
@ -199,41 +199,25 @@
#define IDC_XBOX_PORT_1 1166
#define IDC_XBOX_PORT_2 1174
#define IDC_XBOX_PORT_3 1182
#define IDC_LEFTBLOCK 1200
#define IDC_LEFTBLOCK2 1201
#define IDC_CENTERBLOCK 1200
#define IDC_LEFTBLOCK 1201
#define IDC_RIGHTBLOCK 1202
#define IDC_GEAR_LEVER 1203
#define IDC_GEAR_0 1204
#define IDC_GEAR_1 1205
#define IDC_GEAR_2 1206
#define IDC_GEAR_3 1207
#define IDC_GEAR_4 1208
#define IDC_GEAR_5 1209
#define IDC_GEAR_R 1210
#define IDC_ROTATION_LEVER 1211
#define IDC_TXT_ROTATION_LEVER 1212
#define IDC_GEAR_UP 1203
#define IDC_GEAR_DOWN 1204
#define IDC_BLOCK_PEDALS 1205
#define IDC_LEVER_LEFT 1211
#define IDC_LEVER_RIGHT 1212
#define IDC_VT_LOCATION_MEASUREMENT 1213
#define IDC_BUFFER_MATERIAL 1214
#define IDC_FUEL_FLOW_RATE 1215
#define IDC_OXYGEN_SUPPLY_SYSTEM 1216
#define IDC_FILT_CONTROL_SYSTEM 1217
#define IDC_RADIO_TD0 1255
#define IDC_RADIO_TD1 1256
#define IDC_RADIO_TD2 1257
#define IDC_RADIO_TD3 1258
#define IDC_RADIO_TD4 1259
#define IDC_RADIO_TD5 1260
#define IDC_RADIO_TD6 1261
#define IDC_RADIO_TD7 1262
#define IDC_RADIO_TD8 1263
#define IDC_RADIO_TD9 1264
#define IDC_RADIO_TD10 1265
#define IDC_RADIO_TD11 1266
#define IDC_RADIO_TD12 1267
#define IDC_RADIO_TD_UP 1255
#define IDC_RADIO_TD_DOWN 1256
#define IDC_EVENT_LV 1273
#define IDC_CXBXR_EVENTS 1274
#define IDC_KERNEL_EVENTS 1275
#define IDC_XID_CONFIG 1276
#define IDC_DEVICE 1276
#define IDC_DEVICE_PORT1 1277
#define IDC_DEVICE_PORT2 1278
#define IDC_DEVICE_PORT3 1279
@ -244,19 +228,19 @@
#define IDC_CONFIGURE_PORT4 1284
#define IDC_DEVICE_LIST 1285
#define IDC_REFRESH_DEVICES 1286
#define IDC_XID_DEFAULT 1287
#define IDC_XID_PROFILE 1288
#define IDC_XID_PROFILE_NAME 1289
#define IDC_XID_PROFILE_SAVE 1291
#define IDC_XID_PROFILE_DELETE 1292
#define IDC_XID_BUTTONS 1293
#define IDC_XID_LSTICK 1294
#define IDC_XID_RSTICK 1295
#define IDC_XID_DPAD 1296
#define IDC_XID_TRIGGERS 1297
#define IDC_XID_RUMBLE 1298
#define IDC_XID_OPTIONS 1299
#define IDC_XID_CLEAR 1300
#define IDC_DEFAULT 1287
#define IDC_PROFILE 1288
#define IDC_PROFILE_NAME 1289
#define IDC_PROFILE_SAVE 1291
#define IDC_PROFILE_DELETE 1292
#define IDC_BUTTONS 1293
#define IDC_LSTICK 1294
#define IDC_RSTICK 1295
#define IDC_DPAD 1296
#define IDC_TRIGGERS 1297
#define IDC_RUMBLE 1298
#define IDC_OPTIONS 1299
#define IDC_CLEAR 1300
#define IDC_RUMBLE_LIST 1301
#define IDC_RUMBLE_TEST 1302
#define IDC_NETWORK_ADAPTER 1303
@ -275,10 +259,10 @@
#define IDC_AIMING_NEGX 1316
#define IDC_AIMING_NEGY 1317
#define IDC_AIMING_POSX 1318
#define IDC_SIGHT_CHANGE_POSY 1319
#define IDC_SIGHT_CHANGE_NEGX 1320
#define IDC_SIGHT_CHANGE_NEGY 1321
#define IDC_SIGHT_CHANGE_POSX 1322
#define IDC_SIGHT_CHANGE_POSY 1319
#define IDC_SIGHT_CHANGE_NEGX 1320
#define IDC_SIGHT_CHANGE_NEGY 1321
#define IDC_SIGHT_CHANGE_POSX 1322
#define ID_FILE_EXIT 40005
#define ID_HELP_ABOUT 40008
#define ID_EMULATION_START 40009
@ -347,7 +331,7 @@
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 136
#define _APS_NEXT_RESOURCE_VALUE 137
#define _APS_NEXT_COMMAND_VALUE 40117
#define _APS_NEXT_CONTROL_VALUE 1308
#define _APS_NEXT_SYMED_VALUE 109