595 lines
22 KiB
C
595 lines
22 KiB
C
/*
|
|
* VARCem Virtual Archaelogical Computer EMulator.
|
|
* An emulator of (mostly) x86-based PC systems and devices,
|
|
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
|
|
* spanning the era between 1981 and 1995.
|
|
*
|
|
* This file is part of the VARCem Project.
|
|
*
|
|
* Implementation of the Joystick Configuration dialog.
|
|
*
|
|
* Version: @(#)win_jsconf.c 1.0.1 2018/02/14
|
|
*
|
|
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
|
|
* Miran Grca, <mgrca8@gmail.com>
|
|
* Sarah Walker, <tommowalker@tommowalker.co.uk>
|
|
*
|
|
* Copyright 2017,2018 Fred N. van Kempen.
|
|
* Copyright 2016-2018 Miran Grca.
|
|
* Copyright 2008-2018 Sarah Walker.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the:
|
|
*
|
|
* Free Software Foundation, Inc.
|
|
* 59 Temple Place - Suite 330
|
|
* Boston, MA 02111-1307
|
|
* USA.
|
|
*/
|
|
#include <windows.h>
|
|
#include <windowsx.h>
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <wchar.h>
|
|
#include "../emu.h"
|
|
#include "../config.h"
|
|
#include "../device.h"
|
|
#include "../game/gameport.h"
|
|
#include "../plat.h"
|
|
#include "../plat_joystick.h"
|
|
#include "win.h"
|
|
|
|
|
|
static int joystick_nr;
|
|
static int joystick_config_type;
|
|
#define AXIS_STRINGS_MAX 3
|
|
static char *axis_strings[AXIS_STRINGS_MAX] = {"X Axis", "Y Axis", "Z Axis"};
|
|
|
|
static uint8_t joystickconfig_changed = 0;
|
|
|
|
|
|
static void rebuild_axis_button_selections(HWND hdlg)
|
|
{
|
|
int id = IDC_CONFIG_BASE + 2;
|
|
HWND h;
|
|
int joystick;
|
|
int c, d;
|
|
|
|
h = GetDlgItem(hdlg, IDC_CONFIG_BASE);
|
|
joystick = SendMessage(h, CB_GETCURSEL, 0, 0);
|
|
|
|
for (c = 0; c < joystick_get_axis_count(joystick_config_type); c++)
|
|
{
|
|
int sel = c;
|
|
|
|
h = GetDlgItem(hdlg, id);
|
|
SendMessage(h, CB_RESETCONTENT, 0, 0);
|
|
|
|
if (joystick)
|
|
{
|
|
for (d = 0; d < plat_joystick_state[joystick-1].nr_axes; d++)
|
|
{
|
|
SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)plat_joystick_state[joystick-1].axis[d].name);
|
|
if (c < AXIS_STRINGS_MAX)
|
|
{
|
|
if (!stricmp(axis_strings[c], plat_joystick_state[joystick-1].axis[d].name))
|
|
sel = d;
|
|
}
|
|
}
|
|
for (d = 0; d < plat_joystick_state[joystick-1].nr_povs; d++)
|
|
{
|
|
char s[80];
|
|
|
|
sprintf(s, "%s (X axis)", plat_joystick_state[joystick-1].pov[d].name);
|
|
SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s);
|
|
sprintf(s, "%s (Y axis)", plat_joystick_state[joystick-1].pov[d].name);
|
|
SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s);
|
|
}
|
|
SendMessage(h, CB_SETCURSEL, sel, 0);
|
|
EnableWindow(h, TRUE);
|
|
}
|
|
else
|
|
EnableWindow(h, FALSE);
|
|
|
|
id += 2;
|
|
}
|
|
|
|
for (c = 0; c < joystick_get_button_count(joystick_config_type); c++)
|
|
{
|
|
h = GetDlgItem(hdlg, id);
|
|
SendMessage(h, CB_RESETCONTENT, 0, 0);
|
|
|
|
if (joystick)
|
|
{
|
|
for (d = 0; d < plat_joystick_state[joystick-1].nr_buttons; d++)
|
|
SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)plat_joystick_state[joystick-1].button[d].name);
|
|
SendMessage(h, CB_SETCURSEL, c, 0);
|
|
EnableWindow(h, TRUE);
|
|
}
|
|
else
|
|
EnableWindow(h, FALSE);
|
|
|
|
id += 2;
|
|
}
|
|
|
|
for (c = 0; c < joystick_get_pov_count(joystick_config_type)*2; c++)
|
|
{
|
|
int sel = c;
|
|
|
|
h = GetDlgItem(hdlg, id);
|
|
SendMessage(h, CB_RESETCONTENT, 0, 0);
|
|
|
|
if (joystick)
|
|
{
|
|
for (d = 0; d < plat_joystick_state[joystick-1].nr_povs; d++)
|
|
{
|
|
char s[80];
|
|
|
|
sprintf(s, "%s (X axis)", plat_joystick_state[joystick-1].pov[d].name);
|
|
SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s);
|
|
sprintf(s, "%s (Y axis)", plat_joystick_state[joystick-1].pov[d].name);
|
|
SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s);
|
|
}
|
|
for (d = 0; d < plat_joystick_state[joystick-1].nr_axes; d++)
|
|
{
|
|
SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)plat_joystick_state[joystick-1].axis[d].name);
|
|
}
|
|
SendMessage(h, CB_SETCURSEL, sel, 0);
|
|
EnableWindow(h, TRUE);
|
|
}
|
|
else
|
|
EnableWindow(h, FALSE);
|
|
|
|
id += 2;
|
|
}
|
|
|
|
}
|
|
|
|
static int get_axis(HWND hdlg, int id)
|
|
{
|
|
HWND h = GetDlgItem(hdlg, id);
|
|
int axis_sel = SendMessage(h, CB_GETCURSEL, 0, 0);
|
|
int nr_axes = plat_joystick_state[joystick_state[joystick_nr].plat_joystick_nr-1].nr_axes;
|
|
|
|
if (axis_sel < nr_axes)
|
|
return axis_sel;
|
|
|
|
axis_sel -= nr_axes;
|
|
if (axis_sel & 1)
|
|
return POV_Y | (axis_sel >> 1);
|
|
else
|
|
return POV_X | (axis_sel >> 1);
|
|
}
|
|
|
|
static int get_pov(HWND hdlg, int id)
|
|
{
|
|
HWND h = GetDlgItem(hdlg, id);
|
|
int axis_sel = SendMessage(h, CB_GETCURSEL, 0, 0);
|
|
int nr_povs = plat_joystick_state[joystick_state[joystick_nr].plat_joystick_nr-1].nr_povs*2;
|
|
|
|
if (axis_sel < nr_povs)
|
|
{
|
|
if (axis_sel & 1)
|
|
return POV_Y | (axis_sel >> 1);
|
|
else
|
|
return POV_X | (axis_sel >> 1);
|
|
}
|
|
|
|
return axis_sel - nr_povs;
|
|
}
|
|
|
|
#ifdef __amd64__
|
|
static LRESULT CALLBACK
|
|
#else
|
|
static BOOL CALLBACK
|
|
#endif
|
|
joystickconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
HWND h;
|
|
int c;
|
|
int id;
|
|
int joystick;
|
|
int nr_axes;
|
|
int nr_povs;
|
|
int mapping;
|
|
|
|
switch (message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
h = GetDlgItem(hdlg, IDC_CONFIG_BASE);
|
|
id = IDC_CONFIG_BASE + 2;
|
|
joystick = joystick_state[joystick_nr].plat_joystick_nr;
|
|
|
|
SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"None");
|
|
|
|
for (c = 0; c < joysticks_present; c++)
|
|
SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)plat_joystick_state[c].name);
|
|
|
|
SendMessage(h, CB_SETCURSEL, joystick, 0);
|
|
|
|
rebuild_axis_button_selections(hdlg);
|
|
|
|
if (joystick_state[joystick_nr].plat_joystick_nr)
|
|
{
|
|
nr_axes = plat_joystick_state[joystick-1].nr_axes;
|
|
nr_povs = plat_joystick_state[joystick-1].nr_povs;
|
|
for (c = 0; c < joystick_get_axis_count(joystick_config_type); c++)
|
|
{
|
|
int mapping = joystick_state[joystick_nr].axis_mapping[c];
|
|
|
|
h = GetDlgItem(hdlg, id);
|
|
if (mapping & POV_X)
|
|
SendMessage(h, CB_SETCURSEL, nr_axes + (mapping & 3)*2, 0);
|
|
else if (mapping & POV_Y)
|
|
SendMessage(h, CB_SETCURSEL, nr_axes + (mapping & 3)*2 + 1, 0);
|
|
else
|
|
SendMessage(h, CB_SETCURSEL, mapping, 0);
|
|
id += 2;
|
|
}
|
|
for (c = 0; c < joystick_get_button_count(joystick_config_type); c++)
|
|
{
|
|
h = GetDlgItem(hdlg, id);
|
|
SendMessage(h, CB_SETCURSEL, joystick_state[joystick_nr].button_mapping[c], 0);
|
|
id += 2;
|
|
}
|
|
for (c = 0; c < joystick_get_pov_count(joystick_config_type); c++)
|
|
{
|
|
h = GetDlgItem(hdlg, id);
|
|
mapping = joystick_state[joystick_nr].pov_mapping[c][0];
|
|
if (mapping & POV_X)
|
|
SendMessage(h, CB_SETCURSEL, (mapping & 3)*2, 0);
|
|
else if (mapping & POV_Y)
|
|
SendMessage(h, CB_SETCURSEL, (mapping & 3)*2 + 1, 0);
|
|
else
|
|
SendMessage(h, CB_SETCURSEL, mapping + nr_povs*2, 0);
|
|
id += 2;
|
|
h = GetDlgItem(hdlg, id);
|
|
mapping = joystick_state[joystick_nr].pov_mapping[c][1];
|
|
if (mapping & POV_X)
|
|
SendMessage(h, CB_SETCURSEL, (mapping & 3)*2, 0);
|
|
else if (mapping & POV_Y)
|
|
SendMessage(h, CB_SETCURSEL, (mapping & 3)*2 + 1, 0);
|
|
else
|
|
SendMessage(h, CB_SETCURSEL, mapping + nr_povs*2, 0);
|
|
id += 2;
|
|
}
|
|
}
|
|
}
|
|
return TRUE;
|
|
|
|
case WM_COMMAND:
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDC_CONFIG_BASE:
|
|
if (HIWORD(wParam) == CBN_SELCHANGE)
|
|
rebuild_axis_button_selections(hdlg);
|
|
break;
|
|
|
|
case IDOK:
|
|
{
|
|
id = IDC_CONFIG_BASE + 2;
|
|
|
|
h = GetDlgItem(hdlg, IDC_CONFIG_BASE);
|
|
joystick_state[joystick_nr].plat_joystick_nr = SendMessage(h, CB_GETCURSEL, 0, 0);
|
|
|
|
if (joystick_state[joystick_nr].plat_joystick_nr)
|
|
{
|
|
for (c = 0; c < joystick_get_axis_count(joystick_config_type); c++)
|
|
{
|
|
joystick_state[joystick_nr].axis_mapping[c] = get_axis(hdlg, id);
|
|
id += 2;
|
|
}
|
|
for (c = 0; c < joystick_get_button_count(joystick_config_type); c++)
|
|
{
|
|
h = GetDlgItem(hdlg, id);
|
|
joystick_state[joystick_nr].button_mapping[c] = SendMessage(h, CB_GETCURSEL, 0, 0);
|
|
id += 2;
|
|
}
|
|
for (c = 0; c < joystick_get_button_count(joystick_config_type); c++)
|
|
{
|
|
h = GetDlgItem(hdlg, id);
|
|
joystick_state[joystick_nr].pov_mapping[c][0] = get_pov(hdlg, id);
|
|
id += 2;
|
|
h = GetDlgItem(hdlg, id);
|
|
joystick_state[joystick_nr].pov_mapping[c][1] = get_pov(hdlg, id);
|
|
id += 2;
|
|
}
|
|
}
|
|
}
|
|
joystickconfig_changed = 1;
|
|
EndDialog(hdlg, 0);
|
|
return TRUE;
|
|
case IDCANCEL:
|
|
joystickconfig_changed = 0;
|
|
EndDialog(hdlg, 0);
|
|
return TRUE;
|
|
}
|
|
break;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
uint8_t joystickconfig_open(HWND hwnd, int joy_nr, int type)
|
|
{
|
|
uint16_t *data_block = malloc(16384);
|
|
uint16_t *data;
|
|
DLGTEMPLATE *dlg = (DLGTEMPLATE *)data_block;
|
|
DLGITEMTEMPLATE *item;
|
|
int y = 10;
|
|
int id = IDC_CONFIG_BASE;
|
|
int c;
|
|
|
|
joystickconfig_changed = 0;
|
|
|
|
joystick_nr = joy_nr;
|
|
joystick_config_type = type;
|
|
|
|
memset(data_block, 0, 4096);
|
|
|
|
dlg->style = DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU;
|
|
dlg->x = 10;
|
|
dlg->y = 10;
|
|
dlg->cx = 220;
|
|
dlg->cy = 70;
|
|
|
|
data = (uint16_t *)(dlg + 1);
|
|
|
|
*data++ = 0; /*no menu*/
|
|
*data++ = 0; /*predefined dialog box class*/
|
|
data += MultiByteToWideChar(CP_ACP, 0, "Device Configuration", -1, data, 50);
|
|
|
|
*data++ = 8; /*Point*/
|
|
data += MultiByteToWideChar(CP_ACP, 0, "MS Sans Serif", -1, data, 50);
|
|
|
|
if (((uintptr_t)data) & 2)
|
|
data++;
|
|
|
|
|
|
/*Combo box*/
|
|
item = (DLGITEMTEMPLATE *)data;
|
|
item->x = 70;
|
|
item->y = y;
|
|
item->id = id++;
|
|
|
|
item->cx = 140;
|
|
item->cy = 150;
|
|
|
|
item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | WS_VSCROLL;
|
|
|
|
data = (uint16_t *)(item + 1);
|
|
*data++ = 0xFFFF;
|
|
*data++ = 0x0085; /* combo box class */
|
|
|
|
data += MultiByteToWideChar(CP_ACP, 0, "Device", -1, data, 256);
|
|
*data++ = 0; /* no creation data */
|
|
|
|
if (((uintptr_t)data) & 2)
|
|
data++;
|
|
|
|
/*Static text*/
|
|
item = (DLGITEMTEMPLATE *)data;
|
|
item->x = 10;
|
|
item->y = y;
|
|
item->id = id++;
|
|
|
|
item->cx = 60;
|
|
item->cy = 15;
|
|
|
|
item->style = WS_CHILD | WS_VISIBLE;
|
|
|
|
data = (uint16_t *)(item + 1);
|
|
*data++ = 0xFFFF;
|
|
*data++ = 0x0082; /* static class */
|
|
|
|
data += MultiByteToWideChar(CP_ACP, 0, "Device :", -1, data, 256);
|
|
*data++ = 0; /* no creation data */
|
|
|
|
if (((uintptr_t)data) & 2)
|
|
data++;
|
|
|
|
y += 20;
|
|
|
|
|
|
for (c = 0; c < joystick_get_axis_count(type); c++)
|
|
{
|
|
/*Combo box*/
|
|
item = (DLGITEMTEMPLATE *)data;
|
|
item->x = 70;
|
|
item->y = y;
|
|
item->id = id++;
|
|
|
|
item->cx = 140;
|
|
item->cy = 150;
|
|
|
|
item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | WS_VSCROLL;
|
|
|
|
data = (uint16_t *)(item + 1);
|
|
*data++ = 0xFFFF;
|
|
*data++ = 0x0085; /* combo box class */
|
|
|
|
data += MultiByteToWideChar(CP_ACP, 0, joystick_get_axis_name(type, c), -1, data, 256);
|
|
*data++ = 0; /* no creation data */
|
|
|
|
if (((uintptr_t)data) & 2)
|
|
data++;
|
|
|
|
/*Static text*/
|
|
item = (DLGITEMTEMPLATE *)data;
|
|
item->x = 10;
|
|
item->y = y;
|
|
item->id = id++;
|
|
|
|
item->cx = 60;
|
|
item->cy = 15;
|
|
|
|
item->style = WS_CHILD | WS_VISIBLE;
|
|
|
|
data = (uint16_t *)(item + 1);
|
|
*data++ = 0xFFFF;
|
|
*data++ = 0x0082; /* static class */
|
|
|
|
data += MultiByteToWideChar(CP_ACP, 0, joystick_get_axis_name(type, c), -1, data, 256);
|
|
*data++ = 0; /* no creation data */
|
|
|
|
if (((uintptr_t)data) & 2)
|
|
data++;
|
|
|
|
y += 20;
|
|
}
|
|
|
|
for (c = 0; c < joystick_get_button_count(type); c++)
|
|
{
|
|
/*Combo box*/
|
|
item = (DLGITEMTEMPLATE *)data;
|
|
item->x = 70;
|
|
item->y = y;
|
|
item->id = id++;
|
|
|
|
item->cx = 140;
|
|
item->cy = 150;
|
|
|
|
item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | WS_VSCROLL;
|
|
|
|
data = (uint16_t *)(item + 1);
|
|
*data++ = 0xFFFF;
|
|
*data++ = 0x0085; /* combo box class */
|
|
|
|
data += MultiByteToWideChar(CP_ACP, 0, joystick_get_button_name(type, c), -1, data, 256);
|
|
*data++ = 0; /* no creation data */
|
|
|
|
if (((uintptr_t)data) & 2)
|
|
data++;
|
|
|
|
/*Static text*/
|
|
item = (DLGITEMTEMPLATE *)data;
|
|
item->x = 10;
|
|
item->y = y;
|
|
item->id = id++;
|
|
|
|
item->cx = 60;
|
|
item->cy = 15;
|
|
|
|
item->style = WS_CHILD | WS_VISIBLE;
|
|
|
|
data = (uint16_t *)(item + 1);
|
|
*data++ = 0xFFFF;
|
|
*data++ = 0x0082; /* static class */
|
|
|
|
data += MultiByteToWideChar(CP_ACP, 0, joystick_get_button_name(type, c), -1, data, 256);
|
|
*data++ = 0; /* no creation data */
|
|
|
|
if (((uintptr_t)data) & 2)
|
|
data++;
|
|
|
|
y += 20;
|
|
}
|
|
|
|
for (c = 0; c < joystick_get_pov_count(type)*2; c++)
|
|
{
|
|
char s[80];
|
|
|
|
/*Combo box*/
|
|
item = (DLGITEMTEMPLATE *)data;
|
|
item->x = 70;
|
|
item->y = y;
|
|
item->id = id++;
|
|
|
|
item->cx = 140;
|
|
item->cy = 150;
|
|
|
|
item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | WS_VSCROLL;
|
|
|
|
data = (uint16_t *)(item + 1);
|
|
*data++ = 0xFFFF;
|
|
*data++ = 0x0085; /* combo box class */
|
|
|
|
if (c & 1)
|
|
sprintf(s, "%s (Y axis)", joystick_get_pov_name(type, c/2));
|
|
else
|
|
sprintf(s, "%s (X axis)", joystick_get_pov_name(type, c/2));
|
|
data += MultiByteToWideChar(CP_ACP, 0, s, -1, data, 256);
|
|
*data++ = 0; /* no creation data */
|
|
|
|
if (((uintptr_t)data) & 2)
|
|
data++;
|
|
|
|
/*Static text*/
|
|
item = (DLGITEMTEMPLATE *)data;
|
|
item->x = 10;
|
|
item->y = y;
|
|
item->id = id++;
|
|
|
|
item->cx = 60;
|
|
item->cy = 15;
|
|
|
|
item->style = WS_CHILD | WS_VISIBLE;
|
|
|
|
data = (uint16_t *)(item + 1);
|
|
*data++ = 0xFFFF;
|
|
*data++ = 0x0082; /* static class */
|
|
|
|
data += MultiByteToWideChar(CP_ACP, 0, s, -1, data, 256);
|
|
*data++ = 0; /* no creation data */
|
|
|
|
if (((uintptr_t)data) & 2)
|
|
data++;
|
|
|
|
y += 20;
|
|
}
|
|
|
|
dlg->cdit = (id - IDC_CONFIG_BASE) + 2;
|
|
|
|
item = (DLGITEMTEMPLATE *)data;
|
|
item->x = 20;
|
|
item->y = y;
|
|
item->cx = 50;
|
|
item->cy = 14;
|
|
item->id = IDOK; /* OK button identifier */
|
|
item->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON;
|
|
|
|
data = (uint16_t *)(item + 1);
|
|
*data++ = 0xFFFF;
|
|
*data++ = 0x0080; /* button class */
|
|
|
|
data += MultiByteToWideChar(CP_ACP, 0, "OK", -1, data, 50);
|
|
*data++ = 0; /* no creation data */
|
|
|
|
if (((uintptr_t)data) & 2)
|
|
data++;
|
|
|
|
item = (DLGITEMTEMPLATE *)data;
|
|
item->x = 80;
|
|
item->y = y;
|
|
item->cx = 50;
|
|
item->cy = 14;
|
|
item->id = IDCANCEL; /* OK button identifier */
|
|
item->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON;
|
|
|
|
data = (uint16_t *)(item + 1);
|
|
*data++ = 0xFFFF;
|
|
*data++ = 0x0080; /* button class */
|
|
|
|
data += MultiByteToWideChar(CP_ACP, 0, "Cancel", -1, data, 50);
|
|
*data++ = 0; /* no creation data */
|
|
|
|
dlg->cy = y + 20;
|
|
|
|
DialogBoxIndirect(hinstance, dlg, hwnd, joystickconfig_dlgproc);
|
|
|
|
free(data_block);
|
|
|
|
return joystickconfig_changed;
|
|
}
|