WinUAE/inputdevice.cpp
2012-08-26 14:18:48 +03:00

6603 lines
174 KiB
C++

/*
* UAE - The Un*x Amiga Emulator
*
* joystick/mouse emulation
*
* Copyright 2001-2012 Toni Wilen
*
* new fetures:
* - very configurable (and very complex to configure :)
* - supports multiple native input devices (joysticks and mice)
* - supports mapping joystick/mouse buttons to keys and vice versa
* - joystick mouse emulation (supports both ports)
* - supports parallel port joystick adapter
* - full cd32 pad support (supports both ports)
* - fully backward compatible with old joystick/mouse configuration
*
*/
//#define DONGLE_DEBUG
#include "sysconfig.h"
#include "sysdeps.h"
#include "options.h"
#include "keyboard.h"
#include "inputdevice.h"
#include "inputrecord.h"
#include "keybuf.h"
#include "custom.h"
#include "xwin.h"
#include "drawing.h"
#include "memory.h"
#include "events.h"
#include "newcpu.h"
#include "uae.h"
#include "picasso96.h"
#include "catweasel.h"
#include "debug.h"
#include "ar.h"
#include "gui.h"
#include "disk.h"
#include "audio.h"
#include "sound.h"
#include "savestate.h"
#include "arcadia.h"
#include "zfile.h"
#include "cia.h"
#include "autoconf.h"
#ifdef RETROPLATFORM
#include "rp.h"
#endif
#include "dongle.h"
#include "cdtv.h"
extern int bootrom_header, bootrom_items;
// 01 = host events
// 02 = joystick
// 04 = cia buttons
// 16 = potgo
// 32 = vsync
int inputdevice_logging = 0;
#define ID_FLAG_CANRELEASE 0x1000
#define ID_FLAG_TOGGLED 0x2000
#define ID_FLAG_CUSTOMEVENT_TOGGLED1 0x4000
#define ID_FLAG_CUSTOMEVENT_TOGGLED2 0x8000
#define ID_FLAG_SAVE_MASK_CONFIG 0x000000ff
#define ID_FLAG_SAVE_MASK_QUALIFIERS ID_FLAG_QUALIFIER_MASK
#define ID_FLAG_SAVE_MASK_FULL (ID_FLAG_SAVE_MASK_CONFIG | ID_FLAG_SAVE_MASK_QUALIFIERS)
#define IE_INVERT 0x80
#define IE_CDTV 0x100
#define INPUTEVENT_JOY1_CD32_FIRST INPUTEVENT_JOY1_CD32_PLAY
#define INPUTEVENT_JOY2_CD32_FIRST INPUTEVENT_JOY2_CD32_PLAY
#define INPUTEVENT_JOY1_CD32_LAST INPUTEVENT_JOY1_CD32_BLUE
#define INPUTEVENT_JOY2_CD32_LAST INPUTEVENT_JOY2_CD32_BLUE
/* event masks */
#define AM_KEY 1 /* keyboard allowed */
#define AM_JOY_BUT 2 /* joystick buttons allowed */
#define AM_JOY_AXIS 4 /* joystick axis allowed */
#define AM_MOUSE_BUT 8 /* mouse buttons allowed */
#define AM_MOUSE_AXIS 16 /* mouse direction allowed */
#define AM_AF 32 /* supports autofire */
#define AM_INFO 64 /* information data for gui */
#define AM_DUMMY 128 /* placeholder */
#define AM_CUSTOM 256 /* custom event */
#define AM_K (AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF) /* generic button/switch */
#define AM_KK (AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT)
#define JOYMOUSE_CDTV 8
#define DEFEVENT(A, B, C, D, E, F) {_T(#A), B, C, D, E, F },
static struct inputevent events[] = {
{0, 0, AM_K,0,0,0},
#include "inputevents.def"
{0, 0, 0, 0, 0, 0}
};
#undef DEFEVENT
static int sublevdir[2][MAX_INPUT_SUB_EVENT];
static const int slotorder1[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
static const int slotorder2[] = { 8, 1, 2, 3, 4, 5, 6, 7 };
struct uae_input_device2 {
uae_u32 buttonmask;
int states[MAX_INPUT_DEVICE_EVENTS / 2];
};
static struct uae_input_device2 joysticks2[MAX_INPUT_DEVICES];
static struct uae_input_device2 mice2[MAX_INPUT_DEVICES];
static uae_u8 scancodeused[MAX_INPUT_DEVICES][256];
static uae_u64 qualifiers, qualifiers_r;
static uae_s16 *qualifiers_evt[MAX_INPUT_QUALIFIERS];
// fire/left mouse button pullup resistors enabled?
static bool mouse_pullup = true;
static int joymodes[MAX_JPORTS];
static int *joyinputs[MAX_JPORTS];
static int input_acquired;
static int testmode, testmode_read, testmode_toggle;
struct teststore
{
int testmode_type;
int testmode_num;
int testmode_wtype;
int testmode_wnum;
int testmode_state;
};
#define TESTMODE_MAX 2
static int testmode_count;
static struct teststore testmode_data[TESTMODE_MAX];
static struct teststore testmode_wait[TESTMODE_MAX];
static int bouncy;
static signed long bouncy_cycles;
static int handle_input_event (int nr, int state, int max, int autofire, bool canstoprecord, bool playbackevent);
static struct inputdevice_functions idev[IDTYPE_MAX];
static int isdevice (struct uae_input_device *id)
{
int i, j;
for (i = 0; i < MAX_INPUT_DEVICE_EVENTS; i++) {
for (j = 0; j < MAX_INPUT_SUB_EVENT; j++) {
if (id->eventid[i][j] > 0)
return 1;
}
}
return 0;
}
int inputdevice_uaelib (const TCHAR *s, const TCHAR *parm)
{
int i;
for (i = 1; events[i].name; i++) {
if (!_tcscmp (s, events[i].confname)) {
handle_input_event (i, _tstol (parm), 1, 0, false, false);
return 1;
}
}
return 0;
}
static struct uae_input_device *joysticks;
static struct uae_input_device *mice;
static struct uae_input_device *keyboards;
static struct uae_input_device *internalevents;
static struct uae_input_device_kbr_default *keyboard_default, **keyboard_default_table;
#define KBR_DEFAULT_MAP_FIRST 0
#define KBR_DEFAULT_MAP_LAST 5
#define KBR_DEFAULT_MAP_CD32_FIRST 6
#define KBR_DEFAULT_MAP_CD32_LAST 8
#define KBR_DEFAULT_MAP_NP 0
#define KBR_DEFAULT_MAP_CK 1
#define KBR_DEFAULT_MAP_SE 2
#define KBR_DEFAULT_MAP_NP3 3
#define KBR_DEFAULT_MAP_CK3 4
#define KBR_DEFAULT_MAP_SE3 5
#define KBR_DEFAULT_MAP_CD32_NP 6
#define KBR_DEFAULT_MAP_CD32_CK 7
#define KBR_DEFAULT_MAP_CD32_SE 8
#define KBR_DEFAULT_MAP_XA1 9
#define KBR_DEFAULT_MAP_XA2 10
#define KBR_DEFAULT_MAP_ARCADIA 11
#define KBR_DEFAULT_MAP_ARCADIA_XA 12
#define KBR_DEFAULT_MAP_CDTV 13
static int **keyboard_default_kbmaps;
static int mouse_axis[MAX_INPUT_DEVICES][MAX_INPUT_DEVICE_EVENTS];
static int oldm_axis[MAX_INPUT_DEVICES][MAX_INPUT_DEVICE_EVENTS];
#define MOUSE_AXIS_TOTAL 4
static uae_s16 mouse_x[MAX_JPORTS], mouse_y[MAX_JPORTS];
static uae_s16 mouse_delta[MAX_JPORTS][MOUSE_AXIS_TOTAL];
static uae_s16 mouse_deltanoreset[MAX_JPORTS][MOUSE_AXIS_TOTAL];
static int joybutton[MAX_JPORTS];
static int joydir[MAX_JPORTS];
static int joydirpot[MAX_JPORTS][2];
static uae_s16 mouse_frame_x[MAX_JPORTS], mouse_frame_y[MAX_JPORTS];
static int mouse_port[NORMAL_JPORTS];
static int cd32_shifter[NORMAL_JPORTS];
static int cd32_pad_enabled[NORMAL_JPORTS];
static int parport_joystick_enabled;
static int oldmx[MAX_JPORTS], oldmy[MAX_JPORTS];
static int oleft[MAX_JPORTS], oright[MAX_JPORTS], otop[MAX_JPORTS], obot[MAX_JPORTS];
static int horizclear[MAX_JPORTS], vertclear[MAX_JPORTS];
uae_u16 potgo_value;
static int pot_cap[NORMAL_JPORTS][2];
static uae_u8 pot_dat[NORMAL_JPORTS][2];
static int pot_dat_act[NORMAL_JPORTS][2];
static int analog_port[NORMAL_JPORTS][2];
static int digital_port[NORMAL_JPORTS][2];
#define POTDAT_DELAY_PAL 8
#define POTDAT_DELAY_NTSC 7
static int use_joysticks[MAX_INPUT_DEVICES];
static int use_mice[MAX_INPUT_DEVICES];
static int use_keyboards[MAX_INPUT_DEVICES];
#define INPUT_QUEUE_SIZE 16
struct input_queue_struct {
int evt, storedstate, state, max, linecnt, nextlinecnt;
TCHAR *custom;
};
static struct input_queue_struct input_queue[INPUT_QUEUE_SIZE];
uae_u8 *restore_input (uae_u8 *src)
{
restore_u32 ();
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
pot_cap[i][j] = restore_u16 ();
}
}
return src;
}
uae_u8 *save_input (int *len, uae_u8 *dstptr)
{
uae_u8 *dstbak, *dst;
if (dstptr)
dstbak = dst = dstptr;
else
dstbak = dst = xmalloc (uae_u8, 1000);
save_u32 (0);
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
save_u16 (pot_cap[i][j]);
}
}
*len = dst - dstbak;
return dstbak;
}
static void freejport (struct uae_prefs *dst, int num)
{
memset (&dst->jports[num], 0, sizeof (struct jport));
dst->jports[num].id = -1;
}
static void copyjport (const struct uae_prefs *src, struct uae_prefs *dst, int num)
{
freejport (dst, num);
_tcscpy (dst->jports[num].configname, src->jports[num].configname);
_tcscpy (dst->jports[num].name, src->jports[num].name);
dst->jports[num].id = src->jports[num].id;
dst->jports[num].mode = src->jports[num].mode;
dst->jports[num].autofire = src->jports[num].autofire;
}
static void out_config (struct zfile *f, int id, int num, TCHAR *s1, TCHAR *s2)
{
TCHAR tmp[MAX_DPATH];
_stprintf (tmp, _T("input.%d.%s%d"), id, s1, num);
cfgfile_write_str (f, tmp, s2);
}
static bool write_config_head (struct zfile *f, int idnum, int devnum, TCHAR *name, struct uae_input_device *id, struct inputdevice_functions *idf)
{
TCHAR tmp2[CONFIG_BLEN];
if (idnum == GAMEPORT_INPUT_SETTINGS) {
if (!isdevice (id))
return false;
if (!id->enabled)
return false;
}
TCHAR *s = NULL;
if (id->name)
s = id->name;
else if (devnum < idf->get_num ())
s = idf->get_friendlyname (devnum);
if (s) {
_stprintf (tmp2, _T("input.%d.%s.%d.friendlyname"), idnum + 1, name, devnum);
cfgfile_write_str (f, tmp2, s);
}
s = NULL;
if (id->configname)
s = id->configname;
else if (devnum < idf->get_num ())
s = idf->get_uniquename (devnum);
if (s) {
_stprintf (tmp2, _T("input.%d.%s.%d.name"), idnum + 1, name, devnum);
cfgfile_write_str (f, tmp2, s);
}
if (!isdevice (id)) {
_stprintf (tmp2, _T("input.%d.%s.%d.empty"), idnum + 1, name, devnum);
cfgfile_write_bool (f, tmp2, true);
if (id->enabled) {
_stprintf (tmp2, _T("input.%d.%s.%d.disabled"), idnum + 1, name, devnum);
cfgfile_write (f, tmp2, _T("%d"), id->enabled ? 0 : 1);
}
return false;
}
if (idnum == GAMEPORT_INPUT_SETTINGS) {
_stprintf (tmp2, _T("input.%d.%s.%d.custom"), idnum + 1, name, devnum);
cfgfile_write_bool (f, tmp2, true);
} else {
_stprintf (tmp2, _T("input.%d.%s.%d.empty"), idnum + 1, name, devnum);
cfgfile_write_bool (f, tmp2, false);
_stprintf (tmp2, _T("input.%d.%s.%d.disabled"), idnum + 1, name, devnum);
cfgfile_write_bool (f, tmp2, id->enabled ? false : true);
}
return true;
}
static bool write_slot (TCHAR *p, struct uae_input_device *uid, int i, int j)
{
bool ok = false;
uae_u64 flags = uid->flags[i][j];
if (uid->custom[i][j] && _tcslen (uid->custom[i][j]) > 0) {
_stprintf (p, _T("'%s'.%d"), uid->custom[i][j], flags & ID_FLAG_SAVE_MASK_CONFIG);
ok = true;
} else if (uid->eventid[i][j] > 0) {
_stprintf (p, _T("%s.%d"), events[uid->eventid[i][j]].confname, flags & ID_FLAG_SAVE_MASK_CONFIG);
ok = true;
} else {
_tcscpy (p, _T("NULL"));
}
if (ok && (flags & ID_FLAG_SAVE_MASK_QUALIFIERS)) {
TCHAR *p2 = p + _tcslen (p);
*p2++ = '.';
for (int i = 0; i < MAX_INPUT_QUALIFIERS * 2; i++) {
if ((ID_FLAG_QUALIFIER1 << i) & flags) {
if (i & 1)
_stprintf (p2, _T("%c"), 'a' + i / 2);
else
_stprintf (p2, _T("%c"), 'A' + i / 2);
p2++;
}
}
}
return ok;
}
static struct inputdevice_functions *getidf (int devnum);
static void kbrlabel (TCHAR *s)
{
while (*s) {
*s = _totupper (*s);
if (*s == ' ')
*s = '_';
s++;
}
}
static void write_config2 (struct zfile *f, int idnum, int i, int offset, const TCHAR *extra, struct uae_input_device *id)
{
TCHAR tmp2[CONFIG_BLEN], tmp3[CONFIG_BLEN], *p;
int evt, got, j, k;
TCHAR *custom;
const int *slotorder;
int io = i + offset;
tmp2[0] = 0;
p = tmp2;
got = 0;
slotorder = slotorder1;
// if gameports non-custom mapping in slot0 -> save slot4 as slot0
if (id->port[io][0] && !(id->flags[io][0] & ID_FLAG_GAMEPORTSCUSTOM_MASK))
slotorder = slotorder2;
for (j = 0; j < MAX_INPUT_SUB_EVENT; j++) {
evt = id->eventid[io][slotorder[j]];
custom = id->custom[io][slotorder[j]];
if (custom == NULL && evt <= 0) {
for (k = j + 1; k < MAX_INPUT_SUB_EVENT; k++) {
if (id->eventid[io][slotorder[k]] > 0 || id->custom[io][slotorder[k]] != NULL)
break;
}
if (k == MAX_INPUT_SUB_EVENT)
break;
}
if (id->port[io][0] > 0) {
if (!(id->flags[io][0] & ID_FLAG_GAMEPORTSCUSTOM_MASK) && id->port[io][SPARE_SUB_EVENT] == 0)
break;
}
if (p > tmp2) {
*p++ = ',';
*p = 0;
}
bool ok = write_slot (p, id, io, slotorder[j]);
p += _tcslen (p);
if (ok) {
if (id->port[io][slotorder[j]] > 0) {
_stprintf (p, _T(".%d"), id->port[io][slotorder[j]] - 1);
p += _tcslen (p);
if (idnum != GAMEPORT_INPUT_SETTINGS && j == 0 && id->port[io][SPARE_SUB_EVENT] && slotorder == slotorder1) {
*p++ = '.';
write_slot (p, id, io, SPARE_SUB_EVENT);
p += _tcslen (p);
}
}
}
}
if (p > tmp2) {
_stprintf (tmp3, _T("input.%d.%s%d"), idnum + 1, extra, i);
cfgfile_write_str (f, tmp3, tmp2);
}
}
static void write_kbr_config (struct zfile *f, int idnum, int devnum, struct uae_input_device *kbr, struct inputdevice_functions *idf)
{
TCHAR tmp1[CONFIG_BLEN], tmp2[CONFIG_BLEN], tmp3[CONFIG_BLEN], tmp4[CONFIG_BLEN], tmp5[CONFIG_BLEN], *p;
int i, j, k, evt, skip;
const int *slotorder;
if (!keyboard_default)
return;
if (!write_config_head (f, idnum, devnum, _T("keyboard"), kbr, idf))
return;
i = 0;
while (i < MAX_INPUT_DEVICE_EVENTS && kbr->extra[i] >= 0) {
slotorder = slotorder1;
// if gameports non-custom mapping in slot0 -> save slot4 as slot0
if (kbr->port[i][0] && !(kbr->flags[i][0] & ID_FLAG_GAMEPORTSCUSTOM_MASK))
slotorder = slotorder2;
skip = 0;
k = 0;
while (keyboard_default[k].scancode >= 0) {
if (keyboard_default[k].scancode == kbr->extra[i]) {
skip = 1;
for (j = 0; j < MAX_INPUT_SUB_EVENT; j++) {
if (keyboard_default[k].node[j].evt != 0) {
if (keyboard_default[k].node[j].evt != kbr->eventid[i][slotorder[j]] || keyboard_default[k].node[j].flags != (kbr->flags[i][slotorder[j]] & ID_FLAG_SAVE_MASK_FULL))
skip = 0;
} else if ((kbr->flags[i][slotorder[j]] & ID_FLAG_SAVE_MASK_FULL) != 0 || kbr->eventid[i][slotorder[j]] > 0) {
skip = 0;
}
}
break;
}
k++;
}
bool isdefaultspare =
kbr->port[i][SPARE_SUB_EVENT] &&
keyboard_default[k].node[0].evt == kbr->eventid[i][SPARE_SUB_EVENT] && keyboard_default[k].node[0].flags == (kbr->flags[i][SPARE_SUB_EVENT] & ID_FLAG_SAVE_MASK_FULL);
if (kbr->port[i][0] > 0 && !(kbr->flags[i][0] & ID_FLAG_GAMEPORTSCUSTOM_MASK) &&
(kbr->eventid[i][1] <= 0 && kbr->eventid[i][2] <= 0 && kbr->eventid[i][3] <= 0) &&
(kbr->port[i][SPARE_SUB_EVENT] == 0 || isdefaultspare))
skip = 1;
if (kbr->eventid[i][0] == 0 && (kbr->flags[i][0] & ID_FLAG_SAVE_MASK_FULL) == 0 && keyboard_default[k].scancode < 0)
skip = 1;
if (skip) {
i++;
continue;
}
tmp2[0] = 0;
p = tmp2;
for (j = 0; j < MAX_INPUT_SUB_EVENT; j++) {
TCHAR *custom = kbr->custom[i][slotorder[j]];
evt = kbr->eventid[i][slotorder[j]];
if (custom == NULL && evt <= 0) {
for (k = j + 1; k < MAX_INPUT_SUB_EVENT; k++) {
if (kbr->eventid[i][slotorder[k]] > 0 || kbr->custom[i][slotorder[k]] != NULL)
break;
}
if (k == MAX_INPUT_SUB_EVENT)
break;
}
if (p > tmp2) {
*p++ = ',';
*p = 0;
}
bool ok = write_slot (p, kbr, i, slotorder[j]);
p += _tcslen (p);
if (ok) {
// save port number + SPARE SLOT if needed
if (kbr->port[i][slotorder[j]] > 0 && (kbr->flags[i][slotorder[j]] & ID_FLAG_GAMEPORTSCUSTOM_MASK)) {
_stprintf (p, _T(".%d"), kbr->port[i][slotorder[j]] - 1);
p += _tcslen (p);
if (idnum != GAMEPORT_INPUT_SETTINGS && j == 0 && kbr->port[i][SPARE_SUB_EVENT] && !isdefaultspare && slotorder == slotorder1) {
*p++ = '.';
write_slot (p, kbr, i, SPARE_SUB_EVENT);
p += _tcslen (p);
}
}
}
}
idf->get_widget_type (devnum, i, tmp5, NULL);
_stprintf (tmp3, _T("%d%s%s"), kbr->extra[i], tmp5[0] ? _T(".") : _T(""), tmp5[0] ? tmp5 : _T(""));
kbrlabel (tmp3);
_stprintf (tmp1, _T("keyboard.%d.button.%s"), devnum, tmp3);
_stprintf (tmp4, _T("input.%d.%s"), idnum + 1, tmp1);
cfgfile_write_str (f, tmp4, tmp2[0] ? tmp2 : _T("NULL"));
i++;
}
}
static void write_config (struct zfile *f, int idnum, int devnum, TCHAR *name, struct uae_input_device *id, struct inputdevice_functions *idf)
{
TCHAR tmp1[MAX_DPATH];
int i;
if (!write_config_head (f, idnum, devnum, name, id, idf))
return;
_stprintf (tmp1, _T("%s.%d.axis."), name, devnum);
for (i = 0; i < ID_AXIS_TOTAL; i++)
write_config2 (f, idnum, i, ID_AXIS_OFFSET, tmp1, id);
_stprintf (tmp1, _T("%s.%d.button.") ,name, devnum);
for (i = 0; i < ID_BUTTON_TOTAL; i++)
write_config2 (f, idnum, i, ID_BUTTON_OFFSET, tmp1, id);
}
static const TCHAR *kbtypes[] = { _T("amiga"), _T("pc"), NULL };
void write_inputdevice_config (struct uae_prefs *p, struct zfile *f)
{
int i, id;
cfgfile_write (f, _T("input.config"), _T("%d"), p->input_selected_setting == GAMEPORT_INPUT_SETTINGS ? 0 : p->input_selected_setting + 1);
cfgfile_write (f, _T("input.joymouse_speed_analog"), _T("%d"), p->input_joymouse_multiplier);
cfgfile_write (f, _T("input.joymouse_speed_digital"), _T("%d"), p->input_joymouse_speed);
cfgfile_write (f, _T("input.joymouse_deadzone"), _T("%d"), p->input_joymouse_deadzone);
cfgfile_write (f, _T("input.joystick_deadzone"), _T("%d"), p->input_joystick_deadzone);
cfgfile_write (f, _T("input.analog_joystick_multiplier"), _T("%d"), p->input_analog_joystick_mult);
cfgfile_write (f, _T("input.analog_joystick_offset"), _T("%d"), p->input_analog_joystick_offset);
cfgfile_write (f, _T("input.mouse_speed"), _T("%d"), p->input_mouse_speed);
cfgfile_write (f, _T("input.autofire_speed"), _T("%d"), p->input_autofire_linecnt);
cfgfile_dwrite_str (f, _T("input.keyboard_type"), kbtypes[p->input_keyboard_type]);
cfgfile_dwrite (f, _T("input.contact_bounce"), _T("%d"), p->input_contact_bounce);
for (id = 0; id < MAX_INPUT_SETTINGS; id++) {
TCHAR tmp[MAX_DPATH];
if (id < GAMEPORT_INPUT_SETTINGS) {
_stprintf (tmp, _T("input.%d.name"), id + 1);
cfgfile_dwrite_str (f, tmp, p->input_config_name[id]);
}
for (i = 0; i < MAX_INPUT_DEVICES; i++)
write_config (f, id, i, _T("joystick"), &p->joystick_settings[id][i], &idev[IDTYPE_JOYSTICK]);
for (i = 0; i < MAX_INPUT_DEVICES; i++)
write_config (f, id, i, _T("mouse"), &p->mouse_settings[id][i], &idev[IDTYPE_MOUSE]);
for (i = 0; i < MAX_INPUT_DEVICES; i++)
write_kbr_config (f, id, i, &p->keyboard_settings[id][i], &idev[IDTYPE_KEYBOARD]);
write_config (f, id, 0, _T("internal"), &p->internalevent_settings[id][0], &idev[IDTYPE_INTERNALEVENT]);
}
}
static uae_u64 getqual (const TCHAR **pp)
{
const TCHAR *p = *pp;
uae_u64 mask = 0;
while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z')) {
bool press = (*p >= 'A' && *p <= 'Z');
int shift, inc;
if (press) {
shift = *p - 'A';
inc = 0;
} else {
shift = *p - 'a';
inc = 1;
}
mask |= ID_FLAG_QUALIFIER1 << (shift * 2 + inc);
p++;
}
while (*p != 0 && *p !='.' && *p != ',')
p++;
if (*p == '.' || *p == ',')
p++;
*pp = p;
return mask;
}
static int getnum (const TCHAR **pp)
{
const TCHAR *p = *pp;
int v;
if (!_tcsnicmp (p, _T("false"), 5))
v = 0;
if (!_tcsnicmp (p, _T("true"), 4))
v = 1;
else
v = _tstol (p);
while (*p != 0 && *p !='.' && *p != ',')
p++;
if (*p == '.' || *p == ',')
p++;
*pp = p;
return v;
}
static TCHAR *getstring (const TCHAR **pp)
{
int i;
static TCHAR str[CONFIG_BLEN];
const TCHAR *p = *pp;
bool quoteds = false;
bool quotedd = false;
if (*p == 0)
return 0;
i = 0;
while (*p != 0 && i < 1000 - 1) {
if (*p == '\"')
quotedd = quotedd ? false : true;
if (*p == '\'')
quoteds = quoteds ? false : true;
if (!quotedd && !quoteds) {
if (*p == '.' || *p == ',')
break;
}
str[i++] = *p++;
}
if (*p == '.' || *p == ',')
p++;
str[i] = 0;
*pp = p;
return str;
}
static void reset_inputdevice_settings (struct uae_input_device *uid)
{
for (int l = 0; l < MAX_INPUT_DEVICE_EVENTS; l++) {
for (int i = 0; i < MAX_INPUT_SUB_EVENT_ALL; i++) {
uid->eventid[l][i] = 0;
uid->flags[l][i] = 0;
xfree (uid->custom[l][i]);
uid->custom[l][i] = NULL;
}
}
}
static void reset_inputdevice_slot (struct uae_prefs *prefs, int slot)
{
for (int m = 0; m < MAX_INPUT_DEVICES; m++) {
reset_inputdevice_settings (&prefs->joystick_settings[slot][m]);
reset_inputdevice_settings (&prefs->mouse_settings[slot][m]);
reset_inputdevice_settings (&prefs->keyboard_settings[slot][m]);
}
}
void reset_inputdevice_config (struct uae_prefs *prefs)
{
for (int i = 0; i< MAX_INPUT_SETTINGS; i++)
reset_inputdevice_slot (prefs, i);
}
static void set_kbr_default_event (struct uae_input_device *kbr, struct uae_input_device_kbr_default *trans, int num)
{
for (int i = 0; trans[i].scancode >= 0; i++) {
if (kbr->extra[num] == trans[i].scancode) {
int k;
for (k = 0; k < MAX_INPUT_SUB_EVENT; k++) {
if (kbr->eventid[num][k] == 0)
break;
}
if (k == MAX_INPUT_SUB_EVENT) {
write_log (_T("corrupt default keyboard mappings\n"));
return;
}
int l = 0;
while (k < MAX_INPUT_SUB_EVENT && trans[i].node[l].evt) {
int evt = trans[i].node[l].evt;
if (evt < 0 || evt >= INPUTEVENT_SPC_LAST)
gui_message(_T("invalid event in default keyboard table!"));
kbr->eventid[num][k] = evt;
kbr->flags[num][k] = trans[i].node[l].flags;
l++;
k++;
}
break;
}
}
}
static void clear_id (struct uae_input_device *id)
{
#ifndef _DEBUG
int i, j;
for (i = 0; i < MAX_INPUT_DEVICE_EVENTS; i++) {
for (j = 0; j < MAX_INPUT_SUB_EVENT_ALL; j++)
xfree (id->custom[i][j]);
}
#endif
TCHAR *cn = id->configname;
TCHAR *n = id->name;
memset (id, 0, sizeof (struct uae_input_device));
id->configname = cn;
id->name = n;
}
static void set_kbr_default (struct uae_prefs *p, int index, int devnum, struct uae_input_device_kbr_default *trans)
{
int i, j;
struct uae_input_device *kbr;
struct inputdevice_functions *id = &idev[IDTYPE_KEYBOARD];
uae_u32 scancode;
if (!trans)
return;
for (j = 0; j < MAX_INPUT_DEVICES; j++) {
if (devnum >= 0 && devnum != j)
continue;
kbr = &p->keyboard_settings[index][j];
for (i = 0; i < MAX_INPUT_DEVICE_EVENTS; i++) {
clear_id (kbr);
kbr->extra[i] = -1;
}
if (j < id->get_num ()) {
if (input_get_default_keyboard (j))
kbr->enabled = 1;
for (i = 0; i < id->get_widget_num (j); i++) {
id->get_widget_type (j, i, 0, &scancode);
kbr->extra[i] = scancode;
set_kbr_default_event (kbr, trans, i);
}
}
}
}
static void inputdevice_default_kb (struct uae_prefs *p, int num)
{
if (num == GAMEPORT_INPUT_SETTINGS) {
if (p->jports[0].id != JPORT_CUSTOM || p->jports[1].id != JPORT_CUSTOM)
reset_inputdevice_slot (p, num);
}
set_kbr_default (p, num, -1, keyboard_default);
}
static void inputdevice_default_kb_all (struct uae_prefs *p)
{
for (int i = 0; i < MAX_INPUT_SETTINGS; i++)
inputdevice_default_kb (p, i);
}
static bool read_slot (TCHAR *parm, int num, int joystick, int button, struct uae_input_device *id, int keynum, int subnum, struct inputevent *ie, uae_u64 flags, int port, TCHAR *custom)
{
int mask;
if (custom == NULL && ie->name == NULL) {
if (!_tcscmp (parm, _T("NULL"))) {
if (joystick < 0) {
id->eventid[keynum][subnum] = 0;
id->flags[keynum][subnum] = 0;
} else if (button) {
id->eventid[num + ID_BUTTON_OFFSET][subnum] = 0;
id->flags[num + ID_BUTTON_OFFSET][subnum] = 0;
} else {
id->eventid[num + ID_AXIS_OFFSET][subnum] = 0;
id->flags[num + ID_AXIS_OFFSET][subnum] = 0;
}
}
return false;
}
if (custom)
ie = &events[INPUTEVENT_SPC_CUSTOM_EVENT];
if (joystick < 0) {
if (!(ie->allow_mask & AM_K))
return false;
id->eventid[keynum][subnum] = ie - events;
id->flags[keynum][subnum] = flags;
id->port[keynum][subnum] = port;
xfree (id->custom[keynum][subnum]);
id->custom[keynum][subnum] = custom;
} else if (button) {
if (joystick)
mask = AM_JOY_BUT;
else
mask = AM_MOUSE_BUT;
if (!(ie->allow_mask & mask))
return false;
id->eventid[num + ID_BUTTON_OFFSET][subnum] = ie - events;
id->flags[num + ID_BUTTON_OFFSET][subnum] = flags;
id->port[num + ID_BUTTON_OFFSET][subnum] = port;
xfree (id->custom[num + ID_BUTTON_OFFSET][subnum]);
id->custom[num + ID_BUTTON_OFFSET][subnum] = custom;
} else {
if (joystick)
mask = AM_JOY_AXIS;
else
mask = AM_MOUSE_AXIS;
if (!(ie->allow_mask & mask))
return false;
id->eventid[num + ID_AXIS_OFFSET][subnum] = ie - events;
id->flags[num + ID_AXIS_OFFSET][subnum] = flags;
id->port[num + ID_AXIS_OFFSET][subnum] = port;
xfree (id->custom[num + ID_AXIS_OFFSET][subnum]);
id->custom[num + ID_AXIS_OFFSET][subnum] = custom;
}
return true;
}
static struct inputevent *readevent (const TCHAR *name, TCHAR **customp)
{
int i = 1;
while (events[i].name) {
if (!_tcscmp (events[i].confname, name))
return &events[i];
i++;
}
if (_tcslen (name) > 2 && name[0] == '\'' && name[_tcslen (name) - 1] == '\'') {
TCHAR *custom = my_strdup (name + 1);
custom[_tcslen (custom) - 1] = 0;
*customp = custom;
}
return &events[0];
}
void read_inputdevice_config (struct uae_prefs *pr, const TCHAR *option, TCHAR *value)
{
struct uae_input_device *id = 0;
struct inputevent *ie;
int devnum, num, button, joystick, subnum, idnum, keynum;
const TCHAR *p;
TCHAR *p2, *custom;
option += 6; /* "input." */
p = getstring (&option);
if (!strcasecmp (p, _T("config"))) {
pr->input_selected_setting = _tstol (value) - 1;
if (pr->input_selected_setting == -1)
pr->input_selected_setting = GAMEPORT_INPUT_SETTINGS;
if (pr->input_selected_setting < 0 || pr->input_selected_setting > MAX_INPUT_SETTINGS)
pr->input_selected_setting = 0;
}
if (!strcasecmp (p, _T("joymouse_speed_analog")))
pr->input_joymouse_multiplier = _tstol (value);
if (!strcasecmp (p, _T("joymouse_speed_digital")))
pr->input_joymouse_speed = _tstol (value);
if (!strcasecmp (p, _T("joystick_deadzone")))
pr->input_joystick_deadzone = _tstol (value);
if (!strcasecmp (p, _T("joymouse_deadzone")))
pr->input_joymouse_deadzone = _tstol (value);
if (!strcasecmp (p, _T("mouse_speed")))
pr->input_mouse_speed = _tstol (value);
if (!strcasecmp (p, _T("autofire_speed")))
pr->input_autofire_linecnt = _tstol (value);
if (!strcasecmp (p, _T("analog_joystick_multiplier")))
pr->input_analog_joystick_mult = _tstol (value);
if (!strcasecmp (p, _T("analog_joystick_offset")))
pr->input_analog_joystick_offset = _tstol (value);
if (!strcasecmp (p, _T("keyboard_type"))) {
cfgfile_strval (option, value, NULL, &pr->input_analog_joystick_offset, kbtypes, 0);
keyboard_default = keyboard_default_table[pr->input_keyboard_type];
inputdevice_default_kb_all (pr);
}
if (!strcasecmp (p, _T("contact_bounce")))
pr->input_contact_bounce = _tstol (value);
idnum = _tstol (p);
if (idnum <= 0 || idnum > MAX_INPUT_SETTINGS)
return;
idnum--;
if (!_tcscmp (option, _T("name"))) {
if (idnum < GAMEPORT_INPUT_SETTINGS)
_tcscpy (pr->input_config_name[idnum], value);
return;
}
if (_tcsncmp (option, _T("mouse."), 6) == 0) {
p = option + 6;
} else if (_tcsncmp (option, _T("joystick."), 9) == 0) {
p = option + 9;
} else if (_tcsncmp (option, _T("keyboard."), 9) == 0) {
p = option + 9;
} else if (_tcsncmp (option, _T("internal."), 9) == 0) {
p = option + 9;
} else
return;
devnum = getnum (&p);
if (devnum < 0 || devnum >= MAX_INPUT_DEVICES)
return;
p2 = getstring (&p);
if (!p2)
return;
if (_tcsncmp (option, _T("mouse."), 6) == 0) {
id = &pr->mouse_settings[idnum][devnum];
joystick = 0;
} else if (_tcsncmp (option, _T("joystick."), 9) == 0) {
id = &pr->joystick_settings[idnum][devnum];
joystick = 1;
} else if (_tcsncmp (option, _T("keyboard."), 9) == 0) {
id = &pr->keyboard_settings[idnum][devnum];
joystick = -1;
} else if (_tcsncmp (option, _T("internal."), 9) == 0) {
if (devnum > 0)
return;
id = &pr->internalevent_settings[idnum][devnum];
joystick = 1;
}
if (!id)
return;
if (!_tcscmp (p2, _T("name"))) {
xfree (id->configname);
id->configname = my_strdup (value);
return;
}
if (!_tcscmp (p2, _T("friendlyname"))) {
xfree (id->name);
id->name = my_strdup (value);
return;
}
if (!_tcscmp (p2, _T("custom"))) {
int iscustom;
p = value;
iscustom = getnum (&p);
if (idnum == GAMEPORT_INPUT_SETTINGS) {
clear_id (id);
if (joystick < 0)
set_kbr_default (pr, idnum, devnum, keyboard_default);
id->enabled = iscustom;
} else {
id->enabled = false;
}
return;
}
if (!_tcscmp (p2, _T("empty"))) {
int empty;
p = value;
empty = getnum (&p);
clear_id (id);
if (!empty) {
if (joystick < 0)
set_kbr_default (pr, idnum, devnum, keyboard_default);
}
id->enabled = 1;
if (idnum == GAMEPORT_INPUT_SETTINGS)
id->enabled = 0;
return;
}
if (!_tcscmp (p2, _T("disabled"))) {
int disabled;
p = value;
disabled = getnum (&p);
id->enabled = disabled == 0 ? 1 : 0;
if (idnum == GAMEPORT_INPUT_SETTINGS)
id->enabled = 0;
return;
}
if (idnum == GAMEPORT_INPUT_SETTINGS && id->enabled == 0)
return;
button = 0;
keynum = 0;
if (joystick < 0) {
num = getnum (&p);
for (keynum = 0; keynum < MAX_INPUT_DEVICE_EVENTS; keynum++) {
if (id->extra[keynum] == num)
break;
}
if (keynum >= MAX_INPUT_DEVICE_EVENTS)
return;
} else {
button = -1;
if (!_tcscmp (p2, _T("axis")))
button = 0;
else if(!_tcscmp (p2, _T("button")))
button = 1;
if (button < 0)
return;
num = getnum (&p);
}
p = value;
custom = NULL;
for (subnum = 0; subnum < MAX_INPUT_SUB_EVENT; subnum++) {
uae_u64 flags;
int port;
xfree (custom);
custom = NULL;
p2 = getstring (&p);
if (!p2)
break;
ie = readevent (p2, &custom);
flags = 0;
port = 0;
if (p[-1] == '.')
flags = getnum (&p) & ID_FLAG_SAVE_MASK_CONFIG;
if (p[-1] == '.') {
if ((p[0] >= 'A' && p[0] <= 'Z') || (p[0] >= 'a' && p[0] <= 'z'))
flags |= getqual (&p);
if (p[-1] == '.')
port = getnum (&p) + 1;
}
if (idnum == GAMEPORT_INPUT_SETTINGS && port == 0)
continue;
if (p[-1] == '.' && idnum != GAMEPORT_INPUT_SETTINGS) {
p2 = getstring (&p);
if (p2) {
int flags2 = 0;
if (p[-1] == '.')
flags2 = getnum (&p) & ID_FLAG_SAVE_MASK_CONFIG;
if (p[-1] == '.' && (p[0] >= 'A' && p[0] <= 'Z') || (p[0] >= 'a' && p[0] <= 'z'))
flags |= getqual (&p);
TCHAR *custom2 = NULL;
struct inputevent *ie2 = readevent (p2, &custom2);
read_slot (p2, num, joystick, button, id, keynum, SPARE_SUB_EVENT, ie2, flags2, MAX_JPORTS + 1, custom2);
}
}
while (*p != 0) {
if (p[-1] == ',')
break;
p++;
}
if (!read_slot (p2, num, joystick, button, id, keynum, subnum, ie, flags, port, custom))
continue;
custom = NULL;
}
xfree (custom);
}
static int mouseedge_alive, mousehack_alive_cnt;
static int lastmx, lastmy;
static uaecptr magicmouse_ibase, magicmouse_gfxbase;
static int dimensioninfo_width, dimensioninfo_height, dimensioninfo_dbl;
static int vp_xoffset, vp_yoffset, mouseoffset_x, mouseoffset_y;
static int tablet_maxx, tablet_maxy, tablet_data;
int mousehack_alive (void)
{
return mousehack_alive_cnt > 0 ? mousehack_alive_cnt : 0;
}
static uaecptr get_base (const uae_char *name)
{
uaecptr v = get_long (4);
addrbank *b = &get_mem_bank(v);
if (!b || !b->check (v, 400) || b->flags != ABFLAG_RAM)
return 0;
v += 378; // liblist
while (v = get_long (v)) {
uae_u32 v2;
uae_u8 *p;
b = &get_mem_bank (v);
if (!b || !b->check (v, 32) || b->flags != ABFLAG_RAM)
goto fail;
v2 = get_long (v + 10); // name
b = &get_mem_bank (v2);
if (!b || !b->check (v2, 20))
goto fail;
if (b->flags != ABFLAG_ROM && b->flags != ABFLAG_RAM)
return 0;
p = b->xlateaddr (v2);
if (!memcmp (p, name, strlen (name) + 1)) {
TCHAR *s = au (name);
write_log (_T("get_base('%s')=%08x\n"), s, v);
xfree (s);
return v;
}
}
return 0;
fail:
{
TCHAR *s = au (name);
write_log (_T("get_base('%s') failed, invalid library list\n"), s);
xfree (s);
}
return 0xffffffff;
}
static uaecptr get_intuitionbase (void)
{
if (magicmouse_ibase == 0xffffffff)
return 0;
if (magicmouse_ibase)
return magicmouse_ibase;
magicmouse_ibase = get_base ("intuition.library");
return magicmouse_ibase;
}
static uaecptr get_gfxbase (void)
{
if (magicmouse_gfxbase == 0xffffffff)
return 0;
if (magicmouse_gfxbase)
return magicmouse_gfxbase;
magicmouse_gfxbase = get_base ("graphics.library");
return magicmouse_gfxbase;
}
#define MH_E 0
#define MH_CNT 2
#define MH_MAXX 4
#define MH_MAXY 6
#define MH_MAXZ 8
#define MH_X 10
#define MH_Y 12
#define MH_Z 14
#define MH_RESX 16
#define MH_RESY 18
#define MH_MAXAX 20
#define MH_MAXAY 22
#define MH_MAXAZ 24
#define MH_AX 26
#define MH_AY 28
#define MH_AZ 30
#define MH_PRESSURE 32
#define MH_BUTTONBITS 34
#define MH_INPROXIMITY 38
#define MH_ABSX 40
#define MH_ABSY 42
#define MH_END 44
#define MH_START 4
int inputdevice_is_tablet (void)
{
int v;
if (!uae_boot_rom)
return 0;
if (currprefs.input_tablet == TABLET_OFF)
return 0;
if (currprefs.input_tablet == TABLET_MOUSEHACK)
return -1;
v = is_tablet ();
if (!v)
return 0;
if (kickstart_version < 37)
return v ? -1 : 0;
return v ? 1 : 0;
}
static uaecptr mousehack_address;
static bool mousehack_enabled;
static void mousehack_reset (void)
{
dimensioninfo_width = dimensioninfo_height = 0;
mouseoffset_x = mouseoffset_y = 0;
dimensioninfo_dbl = 0;
mousehack_alive_cnt = 0;
vp_xoffset = vp_yoffset = 0;
tablet_data = 0;
if (mousehack_address)
put_byte (mousehack_address + MH_E, 0);
mousehack_address = 0;
mousehack_enabled = false;
}
static bool mousehack_enable (void)
{
int mode;
if (!uae_boot_rom || currprefs.input_tablet == TABLET_OFF)
return false;
if (mousehack_address && mousehack_enabled)
return true;
mode = 0x80;
if (currprefs.input_tablet == TABLET_MOUSEHACK)
mode |= 1;
if (inputdevice_is_tablet () > 0)
mode |= 2;
if (mousehack_address) {
write_log (_T("Mouse driver enabled (%s)\n"), ((mode & 3) == 3 ? _T("tablet+mousehack") : ((mode & 3) == 2) ? _T("tablet") : _T("mousehack")));
put_byte (mousehack_address + MH_E, mode);
mousehack_enabled = true;
}
return true;
}
void input_mousehack_mouseoffset (uaecptr pointerprefs)
{
mouseoffset_x = (uae_s16)get_word (pointerprefs + 28);
mouseoffset_y = (uae_s16)get_word (pointerprefs + 30);
}
int input_mousehack_status (int mode, uaecptr diminfo, uaecptr dispinfo, uaecptr vp, uae_u32 moffset)
{
if (mode == 4) {
return mousehack_enable () ? 1 : 0;
} else if (mode == 5) {
mousehack_address = m68k_dreg (regs, 0);
mousehack_enable ();
} else if (mode == 0) {
uae_u8 v = get_byte (mousehack_address + MH_E);
v |= 0x40;
put_byte (mousehack_address + MH_E, v);
write_log (_T("Tablet driver running (%08x,%02x)\n"), mousehack_address, v);
} else if (mode == 1) {
int x1 = -1, y1 = -1, x2 = -1, y2 = -1;
uae_u32 props = 0;
dimensioninfo_width = -1;
dimensioninfo_height = -1;
vp_xoffset = 0;
vp_yoffset = 0;
if (diminfo) {
x1 = get_word (diminfo + 50);
y1 = get_word (diminfo + 52);
x2 = get_word (diminfo + 54);
y2 = get_word (diminfo + 56);
dimensioninfo_width = x2 - x1 + 1;
dimensioninfo_height = y2 - y1 + 1;
}
if (vp) {
vp_xoffset = get_word (vp + 28);
vp_yoffset = get_word (vp + 30);
}
if (dispinfo)
props = get_long (dispinfo + 18);
dimensioninfo_dbl = (props & 0x00020000) ? 1 : 0;
write_log (_T("%08x %08x %08x (%dx%d)-(%dx%d) d=%dx%d %s\n"),
diminfo, props, vp, x1, y1, x2, y2, vp_xoffset, vp_yoffset,
(props & 0x00020000) ? _T("dbl") : _T(""));
} else if (mode == 2) {
if (mousehack_alive_cnt == 0)
mousehack_alive_cnt = -100;
else if (mousehack_alive_cnt > 0)
mousehack_alive_cnt = 100;
}
return 1;
}
void get_custom_mouse_limits (int *w, int *h, int *dx, int *dy, int dbl);
void inputdevice_tablet_strobe (void)
{
mousehack_enable ();
if (!uae_boot_rom)
return;
if (!tablet_data)
return;
if (mousehack_address)
put_byte (mousehack_address + MH_CNT, get_byte (mousehack_address + MH_CNT) + 1);
}
void inputdevice_tablet (int x, int y, int z, int pressure, uae_u32 buttonbits, int inproximity, int ax, int ay, int az)
{
uae_u8 *p;
uae_u8 tmp[MH_END];
mousehack_enable ();
if (inputdevice_is_tablet () <= 0)
return;
//write_log (_T("%d %d %d %d %08X %d %d %d %d\n"), x, y, z, pressure, buttonbits, inproximity, ax, ay, az);
p = get_real_address (mousehack_address);
memcpy (tmp, p + MH_START, MH_END - MH_START);
#if 0
if (currprefs.input_magic_mouse) {
int maxx, maxy, diffx, diffy;
int dw, dh, ax, ay, aw, ah;
float xmult, ymult;
float fx, fy;
fx = (float)x;
fy = (float)y;
desktop_coords (&dw, &dh, &ax, &ay, &aw, &ah);
xmult = (float)tablet_maxx / dw;
ymult = (float)tablet_maxy / dh;
diffx = 0;
diffy = 0;
if (picasso_on) {
maxx = gfxvidinfo.width;
maxy = gfxvidinfo.height;
} else {
get_custom_mouse_limits (&maxx, &maxy, &diffx, &diffy);
}
diffx += ax;
diffy += ah;
fx -= diffx * xmult;
if (fx < 0)
fx = 0;
if (fx >= aw * xmult)
fx = aw * xmult - 1;
fy -= diffy * ymult;
if (fy < 0)
fy = 0;
if (fy >= ah * ymult)
fy = ah * ymult - 1;
x = (int)(fx * (aw * xmult) / tablet_maxx + 0.5);
y = (int)(fy * (ah * ymult) / tablet_maxy + 0.5);
}
#endif
p[MH_X] = x >> 8;
p[MH_X + 1] = x;
p[MH_Y] = y >> 8;
p[MH_Y + 1] = y;
p[MH_Z] = z >> 8;
p[MH_Z + 1] = z;
p[MH_AX] = ax >> 8;
p[MH_AX + 1] = ax;
p[MH_AY] = ay >> 8;
p[MH_AY + 1] = ay;
p[MH_AZ] = az >> 8;
p[MH_AZ + 1] = az;
p[MH_MAXX] = tablet_maxx >> 8;
p[MH_MAXX + 1] = tablet_maxx;
p[MH_MAXY] = tablet_maxy >> 8;
p[MH_MAXY + 1] = tablet_maxy;
p[MH_PRESSURE] = pressure >> 8;
p[MH_PRESSURE + 1] = pressure;
p[MH_BUTTONBITS + 0] = buttonbits >> 24;
p[MH_BUTTONBITS + 1] = buttonbits >> 16;
p[MH_BUTTONBITS + 2] = buttonbits >> 8;
p[MH_BUTTONBITS + 3] = buttonbits >> 0;
if (inproximity < 0) {
p[MH_INPROXIMITY] = p[MH_INPROXIMITY + 1] = 0xff;
} else {
p[MH_INPROXIMITY] = 0;
p[MH_INPROXIMITY + 1] = inproximity ? 1 : 0;
}
if (!memcmp (tmp, p + MH_START, MH_END - MH_START))
return;
p[MH_E] = 0xc0 | 2;
p[MH_CNT]++;
}
void inputdevice_tablet_info (int maxx, int maxy, int maxz, int maxax, int maxay, int maxaz, int xres, int yres)
{
uae_u8 *p;
if (!uae_boot_rom)
return;
p = get_real_address (mousehack_address);
tablet_maxx = maxx;
tablet_maxy = maxy;
p[MH_MAXX] = maxx >> 8;
p[MH_MAXX + 1] = maxx;
p[MH_MAXY] = maxy >> 8;
p[MH_MAXY + 1] = maxy;
p[MH_MAXZ] = maxz >> 8;
p[MH_MAXZ + 1] = maxz;
p[MH_RESX] = xres >> 8;
p[MH_RESX + 1] = xres;
p[MH_RESY] = yres >> 8;
p[MH_RESY + 1] = yres;
p[MH_MAXAX] = maxax >> 8;
p[MH_MAXAX + 1] = maxax;
p[MH_MAXAY] = maxay >> 8;
p[MH_MAXAY + 1] = maxay;
p[MH_MAXAZ] = maxaz >> 8;
p[MH_MAXAZ + 1] = maxaz;
}
void getgfxoffset (int *dx, int *dy, int*,int*);
static void inputdevice_mh_abs (int x, int y)
{
uae_u8 *p;
uae_u8 tmp[4];
mousehack_enable ();
if (!mousehack_address)
return;
p = get_real_address (mousehack_address);
memcpy (tmp, p + MH_ABSX, sizeof tmp);
x -= mouseoffset_x + 1;
y -= mouseoffset_y + 2;
p[MH_ABSX] = x >> 8;
p[MH_ABSX + 1] = x;
p[MH_ABSY] = y >> 8;
p[MH_ABSY + 1] = y;
if (!memcmp (tmp, p + MH_ABSX, sizeof tmp))
return;
p[MH_E] = 0xc0 | 1;
p[MH_CNT]++;
tablet_data = 1;
}
#if 0
static void inputdevice_mh_abs_v36 (int x, int y)
{
uae_u8 *p;
uae_u8 tmp[MH_END];
uae_u32 off;
int maxx, maxy, diffx, diffy;
int fdy, fdx, fmx, fmy;
mousehack_enable ();
off = getmhoffset ();
p = rtarea + off;
memcpy (tmp, p + MH_START, MH_END - MH_START);
getgfxoffset (&fdx, &fdy, &fmx, &fmy);
x -= fdx;
y -= fdy;
x += vp_xoffset;
y += vp_yoffset;
diffx = diffy = 0;
maxx = maxy = 0;
if (picasso_on) {
maxx = picasso96_state.Width;
maxy = picasso96_state.Height;
} else if (dimensioninfo_width > 0 && dimensioninfo_height > 0) {
maxx = dimensioninfo_width;
maxy = dimensioninfo_height;
get_custom_mouse_limits (&maxx, &maxy, &diffx, &diffy, dimensioninfo_dbl);
} else {
uaecptr gb = get_gfxbase ();
maxx = 0; maxy = 0;
if (gb) {
maxy = get_word (gb + 216);
maxx = get_word (gb + 218);
}
get_custom_mouse_limits (&maxx, &maxy, &diffx, &diffy, 0);
}
#if 0
{
uaecptr gb = get_intuitionbase ();
maxy = get_word (gb + 1344 + 2);
maxx = get_word (gb + 1348 + 2);
write_log (_T("%d %d\n"), maxx, maxy);
}
#endif
#if 1
{
uaecptr gb = get_gfxbase ();
uaecptr view = get_long (gb + 34);
if (view) {
uaecptr vp = get_long (view);
if (vp) {
int w, h, dw, dh;
w = get_word (vp + 24);
h = get_word (vp + 26) * 2;
dw = get_word (vp + 28);
dh = get_word (vp + 30);
//write_log (_T("%d %d %d %d\n"), w, h, dw, dh);
if (w < maxx)
maxx = w;
if (h < maxy)
maxy = h;
x -= dw;
y -= dh;
}
}
//write_log (_T("* %d %d\n"), get_word (gb + 218), get_word (gb + 216));
}
//write_log (_T("%d %d\n"), maxx, maxy);
#endif
maxx = maxx * 1000 / fmx;
maxy = maxy * 1000 / fmy;
if (maxx <= 0)
maxx = 1;
if (maxy <= 0)
maxy = 1;
x -= diffx;
if (x < 0)
x = 0;
if (x >= maxx)
x = maxx - 1;
y -= diffy;
if (y < 0)
y = 0;
if (y >= maxy)
y = maxy - 1;
//write_log (_T("%d %d %d %d\n"), x, y, maxx, maxy);
p[MH_X] = x >> 8;
p[MH_X + 1] = x;
p[MH_Y] = y >> 8;
p[MH_Y + 1] = y;
p[MH_MAXX] = maxx >> 8;
p[MH_MAXX + 1] = maxx;
p[MH_MAXY] = maxy >> 8;
p[MH_MAXY + 1] = maxy;
p[MH_Z] = p[MH_Z + 1] = 0;
p[MH_MAXZ] = p[MH_MAXZ + 1] = 0;
p[MH_AX] = p[MH_AX + 1] = 0;
p[MH_AY] = p[MH_AY + 1] = 0;
p[MH_AZ] = p[MH_AZ + 1] = 0;
p[MH_PRESSURE] = p[MH_PRESSURE + 1] = 0;
p[MH_INPROXIMITY] = p[MH_INPROXIMITY + 1] = 0xff;
if (!memcmp (tmp, p + MH_START, MH_END - MH_START))
return;
p[MH_CNT]++;
tablet_data = 1;
}
#endif
static void mousehack_helper (void)
{
int x, y;
int fdy, fdx, fmx, fmy;
if (currprefs.input_magic_mouse == 0 && currprefs.input_tablet < TABLET_MOUSEHACK)
return;
#if 0
if (kickstart_version >= 36) {
inputdevice_mh_abs_v36 (lastmx, lastmy);
return;
}
#endif
x = lastmx;
y = lastmy;
getgfxoffset (&fdx, &fdy, &fmx, &fmy);
#ifdef PICASSO96
if (picasso_on) {
x -= picasso96_state.XOffset;
y -= picasso96_state.YOffset;
x = x * fmx / 1000;
y = y * fmy / 1000;
x -= fdx * fmx / 1000;
y -= fdy * fmy / 1000;
} else
#endif
{
x = x * fmx / 1000;
y = y * fmy / 1000;
x -= fdx * fmx / 1000 - 1;
y -= fdy * fmy / 1000 - 2;
if (x < 0)
x = 0;
if (x >= gfxvidinfo.outbuffer->outwidth)
x = gfxvidinfo.outbuffer->outwidth - 1;
if (y < 0)
y = 0;
if (y >= gfxvidinfo.outbuffer->outheight)
y = gfxvidinfo.outbuffer->outheight - 1;
x = coord_native_to_amiga_x (x);
y = coord_native_to_amiga_y (y) << 1;
}
inputdevice_mh_abs (x, y);
}
static int mouseedge_x, mouseedge_y, mouseedge_time;
#define MOUSEEDGE_RANGE 100
#define MOUSEEDGE_TIME 2
extern void setmouseactivexy (int,int,int);
static int mouseedge (void)
{
int x, y, dir;
uaecptr ib;
static int melast_x, melast_y;
static int isnonzero;
if (currprefs.input_magic_mouse == 0 || currprefs.input_tablet > 0)
return 0;
if (magicmouse_ibase == 0xffffffff)
return 0;
dir = 0;
if (!mouseedge_time) {
isnonzero = 0;
goto end;
}
ib = get_intuitionbase ();
if (!ib || get_word (ib + 20) < 31) // version < 31
return 0;
x = get_word (ib + 70);
y = get_word (ib + 68);
if (x || y)
isnonzero = 1;
if (!isnonzero)
return 0;
if (melast_x == x) {
if (mouseedge_x < -MOUSEEDGE_RANGE) {
mouseedge_x = 0;
dir |= 1;
goto end;
}
if (mouseedge_x > MOUSEEDGE_RANGE) {
mouseedge_x = 0;
dir |= 2;
goto end;
}
} else {
mouseedge_x = 0;
melast_x = x;
}
if (melast_y == y) {
if (mouseedge_y < -MOUSEEDGE_RANGE) {
mouseedge_y = 0;
dir |= 4;
goto end;
}
if (mouseedge_y > MOUSEEDGE_RANGE) {
mouseedge_y = 0;
dir |= 8;
goto end;
}
} else {
mouseedge_y = 0;
melast_y = y;
}
return 1;
end:
mouseedge_time = 0;
if (dir) {
if (!picasso_on) {
int aw = 0, ah = 0, dx, dy;
get_custom_mouse_limits (&aw, &ah, &dx, &dy, dimensioninfo_dbl);
x += dx;
y += dy;
}
if (!dmaen (DMA_SPRITE))
setmouseactivexy (x, y, 0);
else
setmouseactivexy (x, y, dir);
}
return 1;
}
int magicmouse_alive (void)
{
return mouseedge_alive > 0;
}
STATIC_INLINE int adjust (int val)
{
if (val > 127)
return 127;
else if (val < -127)
return -127;
return val;
}
static int getbuttonstate (int joy, int button)
{
return (joybutton[joy] & (1 << button)) ? 1 : 0;
}
static int getvelocity (int num, int subnum, int pct)
{
int val;
int v;
if (pct > 1000)
pct = 1000;
val = mouse_delta[num][subnum];
v = val * pct / 1000;
if (!v) {
if (val < -maxvpos / 2)
v = -2;
else if (val < 0)
v = -1;
else if (val > maxvpos / 2)
v = 2;
else if (val > 0)
v = 1;
}
if (!mouse_deltanoreset[num][subnum]) {
mouse_delta[num][subnum] -= v;
gui_gameport_axis_change (num, subnum * 2 + 0, 0, -1);
gui_gameport_axis_change (num, subnum * 2 + 1, 0, -1);
}
return v;
}
static void mouseupdate (int pct, int vsync)
{
int v, i;
int max = 120;
static int mxd, myd;
if (vsync) {
if (mxd < 0) {
if (mouseedge_x > 0)
mouseedge_x = 0;
else
mouseedge_x += mxd;
mouseedge_time = MOUSEEDGE_TIME;
}
if (mxd > 0) {
if (mouseedge_x < 0)
mouseedge_x = 0;
else
mouseedge_x += mxd;
mouseedge_time = MOUSEEDGE_TIME;
}
if (myd < 0) {
if (mouseedge_y > 0)
mouseedge_y = 0;
else
mouseedge_y += myd;
mouseedge_time = MOUSEEDGE_TIME;
}
if (myd > 0) {
if (mouseedge_y < 0)
mouseedge_y = 0;
else
mouseedge_y += myd;
mouseedge_time = MOUSEEDGE_TIME;
}
if (mouseedge_time > 0) {
mouseedge_time--;
if (mouseedge_time == 0) {
mouseedge_x = 0;
mouseedge_y = 0;
}
}
mxd = 0;
myd = 0;
}
for (i = 0; i < 2; i++) {
if (mouse_port[i]) {
v = getvelocity (i, 0, pct);
mxd += v;
mouse_x[i] += v;
v = getvelocity (i, 1, pct);
myd += v;
mouse_y[i] += v;
v = getvelocity (i, 2, pct);
if (v > 0)
record_key (0x7a << 1);
else if (v < 0)
record_key (0x7b << 1);
if (!mouse_deltanoreset[i][2])
mouse_delta[i][2] = 0;
if (mouse_frame_x[i] - mouse_x[i] > max)
mouse_x[i] = mouse_frame_x[i] - max;
if (mouse_frame_x[i] - mouse_x[i] < -max)
mouse_x[i] = mouse_frame_x[i] + max;
if (mouse_frame_y[i] - mouse_y[i] > max)
mouse_y[i] = mouse_frame_y[i] - max;
if (mouse_frame_y[i] - mouse_y[i] < -max)
mouse_y[i] = mouse_frame_y[i] + max;
}
if (!vsync) {
mouse_frame_x[i] = mouse_x[i];
mouse_frame_y[i] = mouse_y[i];
}
}
}
static int input_vpos, input_frame;
extern int vpos;
static void readinput (void)
{
uae_u32 totalvpos;
int diff;
totalvpos = input_frame * current_maxvpos () + vpos;
diff = totalvpos - input_vpos;
if (diff > 0) {
if (diff < 10) {
mouseupdate (0, 0);
} else {
mouseupdate (diff * 1000 / current_maxvpos (), 0);
}
}
input_vpos = totalvpos;
}
static void joymousecounter (int joy)
{
int left = 1, right = 1, top = 1, bot = 1;
int b9, b8, b1, b0;
int cntx, cnty, ocntx, ocnty;
if (joydir[joy] & DIR_LEFT)
left = 0;
if (joydir[joy] & DIR_RIGHT)
right = 0;
if (joydir[joy] & DIR_UP)
top = 0;
if (joydir[joy] & DIR_DOWN)
bot = 0;
b0 = (bot ^ right) ? 1 : 0;
b1 = (right ^ 1) ? 2 : 0;
b8 = (top ^ left) ? 1 : 0;
b9 = (left ^ 1) ? 2 : 0;
cntx = b0 | b1;
cnty = b8 | b9;
ocntx = mouse_x[joy] & 3;
ocnty = mouse_y[joy] & 3;
if (cntx == 3 && ocntx == 0)
mouse_x[joy] -= 4;
else if (cntx == 0 && ocntx == 3)
mouse_x[joy] += 4;
mouse_x[joy] = (mouse_x[joy] & 0xfc) | cntx;
if (cnty == 3 && ocnty == 0)
mouse_y[joy] -= 4;
else if (cnty == 0 && ocnty == 3)
mouse_y[joy] += 4;
mouse_y[joy] = (mouse_y[joy] & 0xfc) | cnty;
if (!left || !right || !top || !bot) {
mouse_frame_x[joy] = mouse_x[joy];
mouse_frame_y[joy] = mouse_y[joy];
}
}
static uae_u16 getjoystate (int joy)
{
uae_u16 v;
v = (uae_u8)mouse_x[joy] | (mouse_y[joy] << 8);
#ifdef DONGLE_DEBUG
if (notinrom ())
write_log (_T("JOY%dDAT %04X %s\n"), joy, v, debuginfo (0));
#endif
if (inputdevice_logging & 2)
write_log (_T("JOY%dDAT=%04x %08x\n"), joy, v, M68K_GETPC);
return v;
}
uae_u16 JOY0DAT (void)
{
uae_u16 v;
readinput ();
v = getjoystate (0);
v = dongle_joydat (0, v);
return v;
}
uae_u16 JOY1DAT (void)
{
uae_u16 v;
readinput ();
v = getjoystate (1);
v = dongle_joydat (1, v);
if (inputrecord_debug & 2) {
if (input_record > 0)
inprec_recorddebug_cia (v, -1, m68k_getpc ());
else if (input_play > 0)
inprec_playdebug_cia (v, -1, m68k_getpc ());
}
return v;
}
uae_u16 JOYGET (int num)
{
uae_u16 v;
v = getjoystate (num);
v = dongle_joydat (num, v);
return v;
}
void JOYSET (int num, uae_u16 dat)
{
mouse_x[num] = dat & 0xff;
mouse_y[num] = (dat >> 8) & 0xff;
mouse_frame_x[num] = mouse_x[num];
mouse_frame_y[num] = mouse_y[num];
}
void JOYTEST (uae_u16 v)
{
mouse_x[0] &= 3;
mouse_y[0] &= 3;
mouse_x[1] &= 3;
mouse_y[1] &= 3;
mouse_x[0] |= v & 0xFC;
mouse_x[1] |= v & 0xFC;
mouse_y[0] |= (v >> 8) & 0xFC;
mouse_y[1] |= (v >> 8) & 0xFC;
mouse_frame_x[0] = mouse_x[0];
mouse_frame_y[0] = mouse_y[0];
mouse_frame_x[1] = mouse_x[1];
mouse_frame_y[1] = mouse_y[1];
dongle_joytest (v);
if (inputdevice_logging & 2)
write_log (_T("JOYTEST: %04X PC=%x\n"), v , M68K_GETPC);
}
static uae_u8 parconvert (uae_u8 v, int jd, int shift)
{
if (jd & DIR_UP)
v &= ~(1 << shift);
if (jd & DIR_DOWN)
v &= ~(2 << shift);
if (jd & DIR_LEFT)
v &= ~(4 << shift);
if (jd & DIR_RIGHT)
v &= ~(8 << shift);
return v;
}
/* io-pins floating: dir=1 -> return data, dir=0 -> always return 1 */
uae_u8 handle_parport_joystick (int port, uae_u8 pra, uae_u8 dra)
{
uae_u8 v;
switch (port)
{
case 0:
v = (pra & dra) | (dra ^ 0xff);
if (parport_joystick_enabled) {
v = parconvert (v, joydir[2], 0);
v = parconvert (v, joydir[3], 4);
}
return v;
case 1:
v = ((pra & dra) | (dra ^ 0xff)) & 0x7;
if (parport_joystick_enabled) {
if (getbuttonstate (2, 0))
v &= ~4;
if (getbuttonstate (3, 0))
v &= ~1;
if (getbuttonstate (2, 1) || getbuttonstate (3, 1))
v &= ~2; /* spare */
}
return v;
default:
abort ();
return 0;
}
}
/* p5 is 1 or floating = cd32 2-button mode */
static bool cd32padmode (uae_u16 p5dir, uae_u16 p5dat)
{
if (!(potgo_value & p5dir) || ((potgo_value & p5dat) && (potgo_value & p5dir)))
return false;
return true;
}
static bool is_joystick_pullup (int joy)
{
return joymodes[joy] == JSEM_MODE_GAMEPAD;
}
static bool is_mouse_pullup (int joy)
{
return mouse_pullup;
}
static void charge_cap (int joy, int idx, int charge)
{
if (charge < -1 || charge > 1)
charge = charge * 80;
pot_cap[joy][idx] += charge;
if (pot_cap[joy][idx] < 0)
pot_cap[joy][idx] = 0;
if (pot_cap[joy][idx] > 511)
pot_cap[joy][idx] = 511;
}
static void cap_check (void)
{
int joy, i;
for (joy = 0; joy < 2; joy++) {
for (i = 0; i < 2; i++) {
int charge = 0, dong, joypot;
uae_u16 pdir = 0x0200 << (joy * 4 + i * 2); /* output enable */
uae_u16 pdat = 0x0100 << (joy * 4 + i * 2); /* data */
uae_u16 p5dir = 0x0200 << (joy * 4);
uae_u16 p5dat = 0x0100 << (joy * 4);
int isbutton = getbuttonstate (joy, i == 0 ? JOYBUTTON_3 : JOYBUTTON_2);
if (cd32_pad_enabled[joy]) {
// only red and blue can be read if CD32 pad and only if it is in normal pad mode
isbutton |= getbuttonstate (joy, JOYBUTTON_CD32_BLUE);
// CD32 pad 3rd button line (P5) is always floating
if (i == 0)
isbutton = 0;
if (cd32padmode (p5dir, p5dat))
continue;
}
dong = dongle_analogjoy (joy, i);
if (dong >= 0) {
isbutton = 0;
joypot = dong;
if (pot_cap[joy][i] < joypot)
charge = 1; // slow charge via dongle resistor
} else {
joypot = joydirpot[joy][i];
if (analog_port[joy][i] && pot_cap[joy][i] < joypot)
charge = 1; // slow charge via pot variable resistor
if ((is_joystick_pullup (joy) && digital_port[joy][i]) || (is_mouse_pullup (joy) && mouse_port[joy]))
charge = 1; // slow charge via pull-up resistor
}
if (!(potgo_value & pdir)) { // input?
if (pot_dat_act[joy][i])
pot_dat[joy][i]++;
/* first 7 or 8 lines after potgo has been started = discharge cap */
if (pot_dat_act[joy][i] == 1) {
if (pot_dat[joy][i] < (currprefs.ntscmode ? POTDAT_DELAY_NTSC : POTDAT_DELAY_PAL)) {
charge = -2; /* fast discharge delay */
} else {
pot_dat_act[joy][i] = 2;
pot_dat[joy][i] = 0;
}
}
if (dong >= 0) {
if (pot_dat_act[joy][i] == 2 && pot_cap[joy][i] >= joypot)
pot_dat_act[joy][i] = 0;
} else {
if (analog_port[joy][i] && pot_dat_act[joy][i] == 2 && pot_cap[joy][i] >= joypot)
pot_dat_act[joy][i] = 0;
if ((digital_port[joy][i] || mouse_port[joy]) && pot_dat_act[joy][i] == 2) {
if (pot_cap[joy][i] >= 10 && !isbutton)
pot_dat_act[joy][i] = 0;
}
}
} else { // output?
charge = (potgo_value & pdat) ? 2 : -2; /* fast (dis)charge if output */
if (potgo_value & pdat)
pot_dat_act[joy][i] = 0; // instant stop if output+high
if (isbutton)
pot_dat[joy][i]++; // "free running" if output+low
}
if (isbutton)
charge = -2; // button press overrides everything
if (currprefs.cs_cdtvcd) {
/* CDTV P9 is not floating */
if (!(potgo_value & pdir) && i == 1 && charge == 0)
charge = 2;
}
// CD32 pad in 2-button mode: blue button is not floating
if (cd32_pad_enabled[joy] && i == 1 && charge == 0)
charge = 2;
/* official Commodore mouse has pull-up resistors in button lines
* NOTE: 3rd party mice may not have pullups! */
if (dong < 0 && (is_mouse_pullup (joy) && mouse_port[joy] && digital_port[joy][i]) && charge == 0)
charge = 2;
/* emulate pullup resistor if button mapped because there too many broken
* programs that read second button in input-mode (and most 2+ button pads have
* pullups)
*/
if (dong < 0 && (is_joystick_pullup (joy) && digital_port[joy][i]) && charge == 0)
charge = 2;
charge_cap (joy, i, charge);
}
}
}
uae_u8 handle_joystick_buttons (uae_u8 pra, uae_u8 dra)
{
uae_u8 but = 0;
int i;
cap_check ();
for (i = 0; i < 2; i++) {
int mask = 0x40 << i;
if (cd32_pad_enabled[i]) {
uae_u16 p5dir = 0x0200 << (i * 4);
uae_u16 p5dat = 0x0100 << (i * 4);
but |= mask;
if (!cd32padmode (p5dir, p5dat)) {
if (getbuttonstate (i, JOYBUTTON_CD32_RED) || getbuttonstate (i, JOYBUTTON_1))
but &= ~mask;
}
} else {
if (!getbuttonstate (i, JOYBUTTON_1))
but |= mask;
if (bouncy && cycles_in_range (bouncy_cycles)) {
but &= ~mask;
if (uaerand () & 1)
but |= mask;
}
if (dra & mask)
but = (but & ~mask) | (pra & mask);
}
}
if (inputdevice_logging & 4) {
static uae_u8 old;
if (but != old)
write_log (_T("BFE001: %02X:%02X %x\n"), dra, but, M68K_GETPC);
old = but;
}
return but;
}
/* joystick 1 button 1 is used as a output for incrementing shift register */
void handle_cd32_joystick_cia (uae_u8 pra, uae_u8 dra)
{
static int oldstate[2];
int i;
cap_check ();
for (i = 0; i < 2; i++) {
uae_u8 but = 0x40 << i;
uae_u16 p5dir = 0x0200 << (i * 4); /* output enable P5 */
uae_u16 p5dat = 0x0100 << (i * 4); /* data P5 */
if (cd32padmode (p5dir, p5dat)) {
if ((dra & but) && (pra & but) != oldstate[i]) {
if (!(pra & but)) {
cd32_shifter[i]--;
if (cd32_shifter[i] < 0)
cd32_shifter[i] = 0;
}
}
}
oldstate[i] = pra & but;
}
}
/* joystick port 1 button 2 is input for button state */
static uae_u16 handle_joystick_potgor (uae_u16 potgor)
{
int i;
cap_check ();
for (i = 0; i < 2; i++) {
uae_u16 p9dir = 0x0800 << (i * 4); /* output enable P9 */
uae_u16 p9dat = 0x0400 << (i * 4); /* data P9 */
uae_u16 p5dir = 0x0200 << (i * 4); /* output enable P5 */
uae_u16 p5dat = 0x0100 << (i * 4); /* data P5 */
if (cd32_pad_enabled[i] && cd32padmode (p5dir, p5dat)) {
/* p5 is floating in input-mode */
potgor &= ~p5dat;
potgor |= potgo_value & p5dat;
if (!(potgo_value & p9dir))
potgor |= p9dat;
/* (P5 output and 1) or floating -> shift register is kept reset (Blue button) */
if (!(potgo_value & p5dir) || ((potgo_value & p5dat) && (potgo_value & p5dir)))
cd32_shifter[i] = 8;
/* shift at 1 == return one, >1 = return button states */
if (cd32_shifter[i] == 0)
potgor &= ~p9dat; /* shift at zero == return zero */
if (cd32_shifter[i] >= 2 && (joybutton[i] & ((1 << JOYBUTTON_CD32_PLAY) << (cd32_shifter[i] - 2))))
potgor &= ~p9dat;
} else {
potgor &= ~p5dat;
if (pot_cap[i][0] > 100)
potgor |= p5dat;
if (!cd32_pad_enabled[i] || !cd32padmode (p5dir, p5dat)) {
potgor &= ~p9dat;
if (pot_cap[i][1] > 100)
potgor |= p9dat;
}
}
}
return potgor;
}
static int inputdelay;
void inputdevice_read (void)
{
do {
handle_msgpump ();
idev[IDTYPE_MOUSE].read ();
idev[IDTYPE_JOYSTICK].read ();
idev[IDTYPE_KEYBOARD].read ();
} while (handle_msgpump ());
}
static int handle_custom_event (const TCHAR *custom)
{
TCHAR *p, *buf, *nextp;
if (custom == NULL)
return 0;
write_log (_T("%s\n"), custom);
p = buf = my_strdup (custom);
while (p && *p) {
TCHAR *p2;
if (*p != '\"')
break;
p++;
p2 = p;
while (*p2 != '\"' && *p2 != 0)
p2++;
if (*p2 == '\"') {
*p2++ = 0;
nextp = p2 + 1;
while (*nextp == ' ')
nextp++;
}
//write_log (L"-> '%s'\n", p);
cfgfile_parse_line (&changed_prefs, p, 0);
p = nextp;
}
xfree (buf);
config_changed = 1;
return 0;
}
void inputdevice_hsync (void)
{
static int cnt;
cap_check ();
#ifdef CATWEASEL
catweasel_hsync ();
#endif
for (int i = 0; i < INPUT_QUEUE_SIZE; i++) {
struct input_queue_struct *iq = &input_queue[i];
if (iq->linecnt > 0) {
iq->linecnt--;
if (iq->linecnt == 0) {
if (iq->state)
iq->state = 0;
else
iq->state = iq->storedstate;
if (iq->custom)
handle_custom_event (iq->custom);
if (iq->evt)
handle_input_event (iq->evt, iq->state, iq->max, 0, false, true);
iq->linecnt = iq->nextlinecnt;
}
}
}
if (bouncy && get_cycles () > bouncy_cycles)
bouncy = 0;
if (input_record && input_record != INPREC_RECORD_PLAYING) {
if (vpos == 0)
inputdevice_read ();
inputdelay = 0;
}
if (input_play) {
inprec_playdiskchange ();
int nr, state, max, autofire;
while (inprec_playevent (&nr, &state, &max, &autofire))
handle_input_event (nr, state, max, autofire, false, true);
if (vpos == 0)
handle_msgpump ();
}
if (!input_record && !input_play) {
if ((++cnt & 63) == 63 ) {
inputdevice_read ();
} else if (inputdelay > 0) {
inputdelay--;
if (inputdelay == 0)
inputdevice_read ();
}
}
}
static uae_u16 POTDAT (int joy)
{
uae_u16 v = (pot_dat[joy][1] << 8) | pot_dat[joy][0];
if (inputdevice_logging & 16)
write_log (_T("POTDAT%d: %04X %08X\n"), joy, v, M68K_GETPC);
return v;
}
uae_u16 POT0DAT (void)
{
return POTDAT (0);
}
uae_u16 POT1DAT (void)
{
return POTDAT (1);
}
/* direction=input, data pin floating, last connected logic level or previous status
* written when direction was ouput
* otherwise it is currently connected logic level.
* direction=output, data pin is current value, forced to zero if joystick button is pressed
* it takes some tens of microseconds before data pin changes state
*/
void POTGO (uae_u16 v)
{
int i, j;
if (inputdevice_logging & 16)
write_log (_T("POTGO_W: %04X %08X\n"), v, M68K_GETPC);
#ifdef DONGLE_DEBUG
if (notinrom ())
write_log (_T("POTGO %04X %s\n"), v, debuginfo(0));
#endif
dongle_potgo (v);
potgo_value = potgo_value & 0x5500; /* keep state of data bits */
potgo_value |= v & 0xaa00; /* get new direction bits */
for (i = 0; i < 8; i += 2) {
uae_u16 dir = 0x0200 << i;
if (v & dir) {
uae_u16 data = 0x0100 << i;
potgo_value &= ~data;
potgo_value |= v & data;
}
}
for (i = 0; i < 2; i++) {
if (cd32_pad_enabled[i]) {
uae_u16 p5dir = 0x0200 << (i * 4); /* output enable P5 */
uae_u16 p5dat = 0x0100 << (i * 4); /* data P5 */
if (!(potgo_value & p5dir) || ((potgo_value & p5dat) && (potgo_value & p5dir)))
cd32_shifter[i] = 8;
}
}
if (v & 1) {
for (i = 0; i < 2; i++) {
for (j = 0; j < 2; j++) {
pot_dat_act[i][j] = 1;
pot_dat[i][j] = 0;
}
}
}
}
uae_u16 POTGOR (void)
{
uae_u16 v;
v = handle_joystick_potgor (potgo_value) & 0x5500;
v = dongle_potgor (v);
#ifdef DONGLE_DEBUG
if (notinrom ())
write_log (_T("POTGOR %04X %s\n"), v, debuginfo(0));
#endif
if (inputdevice_logging & 16)
write_log (_T("POTGO_R: %04X %08X %d\n"), v, M68K_GETPC, cd32_shifter[1]);
return v;
}
static int check_input_queue (int evt)
{
struct input_queue_struct *iq;
int i;
for (i = 0; i < INPUT_QUEUE_SIZE; i++) {
iq = &input_queue[i];
if (iq->evt == evt)
return i;
}
return -1;
}
static void queue_input_event (int evt, const TCHAR *custom, int state, int max, int linecnt, int autofire)
{
struct input_queue_struct *iq;
int idx = check_input_queue (evt);
if (state < 0 && idx >= 0) {
iq = &input_queue[idx];
iq->nextlinecnt = -1;
iq->linecnt = -1;
iq->evt = 0;
if (iq->state == 0 && evt > 0)
handle_input_event (evt, 0, 1, 0, false, false);
} else if (state >= 0 && idx < 0) {
if (evt == 0 && custom == NULL)
return;
for (idx = 0; idx < INPUT_QUEUE_SIZE; idx++) {
iq = &input_queue[idx];
if (iq->linecnt < 0)
break;
}
if (idx == INPUT_QUEUE_SIZE) {
write_log (_T("input queue overflow\n"));
return;
}
xfree (iq->custom);
iq->custom = NULL;
if (custom)
iq->custom = my_strdup (custom);
iq->evt = evt;
iq->state = iq->storedstate = state;
iq->max = max;
iq->linecnt = linecnt;
iq->nextlinecnt = autofire > 0 ? linecnt : -1;
}
}
static uae_u8 keybuf[256];
static int inputcode_pending, inputcode_pending_state;
void inputdevice_release_all_keys (void)
{
int i;
for (i = 0; i < 0x80; i++) {
if (keybuf[i] != 0) {
keybuf[i] = 0;
record_key (i << 1|1);
}
}
}
void inputdevice_add_inputcode (int code, int state)
{
inputcode_pending = code;
inputcode_pending_state = state;
}
void inputdevice_do_keyboard (int code, int state)
{
#ifdef CDTV
if (code >= 0x72 && code <= 0x77) { // CDTV keys
if (cdtv_front_panel (-1)) {
// front panel active
if (!state)
return;
cdtv_front_panel (code - 0x72);
return;
}
}
#endif
if (code < 0x80) {
uae_u8 key = code | (state ? 0x00 : 0x80);
keybuf[key & 0x7f] = (key & 0x80) ? 0 : 1;
if (key == AK_RESETWARNING) {
resetwarning_do (0);
return;
} else if ((keybuf[AK_CTRL] || keybuf[AK_RCTRL]) && keybuf[AK_LAMI] && keybuf[AK_RAMI]) {
int r = keybuf[AK_LALT] | keybuf[AK_RALT];
if (!r && currprefs.cs_resetwarning && resetwarning_do (1))
return;
memset (keybuf, 0, sizeof (keybuf));
send_internalevent (INTERNALEVENT_KBRESET);
uae_reset (r);
}
if (record_key ((uae_u8)((key << 1) | (key >> 7)))) {
if (inputdevice_logging & 1)
write_log (_T("Amiga key %02X %d\n"), key & 0x7f, key >> 7);
}
return;
}
inputdevice_add_inputcode (code, state);
}
// these need cpu trace data
static bool needcputrace (int code)
{
switch (code)
{
case AKS_ENTERGUI:
case AKS_STATECAPTURE:
case AKS_STATESAVEQUICK:
case AKS_STATESAVEQUICK1:
case AKS_STATESAVEQUICK2:
case AKS_STATESAVEQUICK3:
case AKS_STATESAVEQUICK4:
case AKS_STATESAVEQUICK5:
case AKS_STATESAVEQUICK6:
case AKS_STATESAVEQUICK7:
case AKS_STATESAVEQUICK8:
case AKS_STATESAVEQUICK9:
case AKS_STATESAVEDIALOG:
return true;
}
return false;
}
void inputdevice_handle_inputcode (void)
{
static int swapperslot;
int code = inputcode_pending;
int state = inputcode_pending_state;
static int tracer_enable;
if (code == 0)
goto end;
if (needcputrace (code) && can_cpu_tracer () == true && is_cpu_tracer () == false && !input_play && !input_record && !debugging) {
if (set_cpu_tracer (true)) {
tracer_enable = 1;
return; // wait for next frame
}
}
inputcode_pending = 0;
if (vpos != 0)
write_log (_T("inputcode=%d but vpos = %d"), code, vpos);
#ifdef ARCADIA
switch (code)
{
case AKS_ARCADIADIAGNOSTICS:
arcadia_flag &= ~1;
arcadia_flag |= state ? 1 : 0;
break;
case AKS_ARCADIAPLY1:
arcadia_flag &= ~4;
arcadia_flag |= state ? 4 : 0;
break;
case AKS_ARCADIAPLY2:
arcadia_flag &= ~2;
arcadia_flag |= state ? 2 : 0;
break;
case AKS_ARCADIACOIN1:
if (state)
arcadia_coin[0]++;
break;
case AKS_ARCADIACOIN2:
if (state)
arcadia_coin[1]++;
break;
}
#endif
if (!state)
return;
switch (code)
{
case AKS_ENTERGUI:
gui_display (-1);
setsystime ();
break;
case AKS_SCREENSHOT_FILE:
screenshot (1, 1);
break;
case AKS_SCREENSHOT_CLIPBOARD:
screenshot (0, 1);
break;
#ifdef ACTION_REPLAY
case AKS_FREEZEBUTTON:
action_replay_freeze ();
break;
#endif
case AKS_FLOPPY0:
gui_display (0);
setsystime ();
break;
case AKS_FLOPPY1:
gui_display (1);
setsystime ();
break;
case AKS_FLOPPY2:
gui_display (2);
setsystime ();
break;
case AKS_FLOPPY3:
gui_display (3);
setsystime ();
break;
case AKS_EFLOPPY0:
disk_eject (0);
break;
case AKS_EFLOPPY1:
disk_eject (1);
break;
case AKS_EFLOPPY2:
disk_eject (2);
break;
case AKS_EFLOPPY3:
disk_eject (3);
break;
case AKS_IRQ7:
NMI_delayed ();
break;
case AKS_PAUSE:
pausemode (-1);
break;
case AKS_WARP:
warpmode (-1);
break;
case AKS_INHIBITSCREEN:
toggle_inhibit_frame (IHF_SCROLLLOCK);
break;
case AKS_STATEREWIND:
savestate_dorewind (-2);
break;
case AKS_STATECURRENT:
savestate_dorewind (-1);
break;
case AKS_STATECAPTURE:
savestate_capture (1);
break;
case AKS_VOLDOWN:
sound_volume (-1);
break;
case AKS_VOLUP:
sound_volume (1);
break;
case AKS_VOLMUTE:
sound_mute (-1);
break;
case AKS_MVOLDOWN:
master_sound_volume (-1);
break;
case AKS_MVOLUP:
master_sound_volume (1);
break;
case AKS_MVOLMUTE:
master_sound_volume (0);
break;
case AKS_QUIT:
uae_quit ();
break;
case AKS_SOFTRESET:
uae_reset (0);
break;
case AKS_HARDRESET:
uae_reset (1);
break;
case AKS_STATESAVEQUICK:
case AKS_STATESAVEQUICK1:
case AKS_STATESAVEQUICK2:
case AKS_STATESAVEQUICK3:
case AKS_STATESAVEQUICK4:
case AKS_STATESAVEQUICK5:
case AKS_STATESAVEQUICK6:
case AKS_STATESAVEQUICK7:
case AKS_STATESAVEQUICK8:
case AKS_STATESAVEQUICK9:
savestate_quick ((code - AKS_STATESAVEQUICK) / 2, 1);
break;
case AKS_STATERESTOREQUICK:
case AKS_STATERESTOREQUICK1:
case AKS_STATERESTOREQUICK2:
case AKS_STATERESTOREQUICK3:
case AKS_STATERESTOREQUICK4:
case AKS_STATERESTOREQUICK5:
case AKS_STATERESTOREQUICK6:
case AKS_STATERESTOREQUICK7:
case AKS_STATERESTOREQUICK8:
case AKS_STATERESTOREQUICK9:
savestate_quick ((code - AKS_STATERESTOREQUICK) / 2, 0);
break;
case AKS_TOGGLEDEFAULTSCREEN:
toggle_fullscreen (-1);
break;
case AKS_TOGGLEWINDOWEDFULLSCREEN:
toggle_fullscreen (0);
break;
case AKS_TOGGLEFULLWINDOWFULLSCREEN:
toggle_fullscreen (1);
break;
case AKS_TOGGLEWINDOWFULLWINDOW:
toggle_fullscreen (2);
break;
case AKS_TOGGLEMOUSEGRAB:
toggle_mousegrab ();
break;
case AKS_ENTERDEBUGGER:
activate_debugger ();
break;
case AKS_STATESAVEDIALOG:
gui_display (5);
break;
case AKS_STATERESTOREDIALOG:
gui_display (4);
break;
case AKS_DECREASEREFRESHRATE:
case AKS_INCREASEREFRESHRATE:
{
int dir = code == AKS_INCREASEREFRESHRATE ? 5 : -5;
if (currprefs.chipset_refreshrate == 0)
currprefs.chipset_refreshrate = currprefs.ntscmode ? 60 : 50;
changed_prefs.chipset_refreshrate = currprefs.chipset_refreshrate + dir;
if (changed_prefs.chipset_refreshrate < 10.0)
changed_prefs.chipset_refreshrate = 10.0;
if (changed_prefs.chipset_refreshrate > 900.0)
changed_prefs.chipset_refreshrate = 900.0;
config_changed = 1;
}
break;
case AKS_DISKSWAPPER_NEXT:
swapperslot++;
if (swapperslot >= MAX_SPARE_DRIVES || currprefs.dfxlist[swapperslot][0] == 0)
swapperslot = 0;
break;
case AKS_DISKSWAPPER_PREV:
swapperslot--;
if (swapperslot < 0)
swapperslot = MAX_SPARE_DRIVES - 1;
while (swapperslot > 0) {
if (currprefs.dfxlist[swapperslot][0])
break;
swapperslot--;
}
break;
case AKS_DISKSWAPPER_INSERT0:
case AKS_DISKSWAPPER_INSERT1:
case AKS_DISKSWAPPER_INSERT2:
case AKS_DISKSWAPPER_INSERT3:
_tcscpy (changed_prefs.floppyslots[code - AKS_DISKSWAPPER_INSERT0].df, currprefs.dfxlist[swapperslot]);
config_changed = 1;
break;
break;
case AKS_INPUT_CONFIG_1:
case AKS_INPUT_CONFIG_2:
case AKS_INPUT_CONFIG_3:
case AKS_INPUT_CONFIG_4:
changed_prefs.input_selected_setting = currprefs.input_selected_setting = code - AKS_INPUT_CONFIG_1;
inputdevice_updateconfig (&currprefs);
break;
case AKS_DISK_PREV0:
case AKS_DISK_PREV1:
case AKS_DISK_PREV2:
case AKS_DISK_PREV3:
disk_prevnext (code - AKS_DISK_PREV0, -1);
break;
case AKS_DISK_NEXT0:
case AKS_DISK_NEXT1:
case AKS_DISK_NEXT2:
case AKS_DISK_NEXT3:
disk_prevnext (code - AKS_DISK_NEXT0, 1);
break;
#ifdef CDTV
case AKS_CDTV_FRONT_PANEL_STOP:
case AKS_CDTV_FRONT_PANEL_PLAYPAUSE:
case AKS_CDTV_FRONT_PANEL_PREV:
case AKS_CDTV_FRONT_PANEL_NEXT:
case AKS_CDTV_FRONT_PANEL_REW:
case AKS_CDTV_FRONT_PANEL_FF:
cdtv_front_panel (code - AKS_CDTV_FRONT_PANEL_STOP);
break;
#endif
}
end:
if (tracer_enable) {
set_cpu_tracer (false);
tracer_enable = 0;
}
}
static int getqualid (int evt)
{
if (evt > INPUTEVENT_SPC_QUALIFIER_START && evt < INPUTEVENT_SPC_QUALIFIER_END)
return evt - INPUTEVENT_SPC_QUALIFIER1;
return -1;
}
static uae_u64 isqual (int evt)
{
int num = getqualid (evt);
if (num < 0)
return 0;
return ID_FLAG_QUALIFIER1 << (num * 2);
}
static int handle_input_event (int nr, int state, int max, int autofire, bool canstopplayback, bool playbackevent)
{
struct inputevent *ie;
int joy;
bool isaks = false;
if (nr <= 0 || nr == INPUTEVENT_SPC_CUSTOM_EVENT)
return 0;
ie = &events[nr];
if (isqual (nr))
return 0; // qualifiers do nothing
if (ie->unit == 0 && ie->data >= AKS_FIRST) {
isaks = true;
if (!state) // release AKS_ does nothing
return 0;
}
if (!isaks) {
if (input_record && input_record != INPREC_RECORD_PLAYING)
inprec_recordevent (nr, state, max, autofire);
if (input_play && state && canstopplayback) {
if (inprec_realtime ()) {
if (input_record && input_record != INPREC_RECORD_PLAYING)
inprec_recordevent (nr, state, max, autofire);
}
}
if (!playbackevent && input_play)
return 0;
}
if ((inputdevice_logging & 1) || input_record || input_play)
write_log (_T("STATE=%05d MAX=%05d AF=%d QUAL=%06x '%s' \n"), state, max, autofire, (uae_u32)(qualifiers >> 32), ie->name);
if (autofire) {
if (state)
queue_input_event (nr, NULL, state, max, currprefs.input_autofire_linecnt, 1);
else
queue_input_event (nr, NULL, -1, 0, 0, 1);
}
switch (ie->unit)
{
case 5: /* lightpen/gun */
{
if (lightpen_x < 0 && lightpen_y < 0) {
lightpen_x = gfxvidinfo.outbuffer->outwidth / 2;
lightpen_y = gfxvidinfo.outbuffer->outheight / 2;
}
if (ie->type == 0) {
int delta = 0;
if (max == 0)
delta = state * currprefs.input_mouse_speed / 100;
else if (state > 0)
delta = currprefs.input_joymouse_speed;
else if (state < 0)
delta = -currprefs.input_joymouse_speed;
if (ie->data)
lightpen_y += delta;
else
lightpen_x += delta;
} else {
int delta = currprefs.input_joymouse_speed;
if (ie->data & DIR_LEFT)
lightpen_x -= delta;
if (ie->data & DIR_RIGHT)
lightpen_x += delta;
if (ie->data & DIR_UP)
lightpen_y -= delta;
if (ie->data & DIR_DOWN)
lightpen_y += delta;
}
}
break;
case 1: /* ->JOY1 */
case 2: /* ->JOY2 */
case 3: /* ->Parallel port joystick adapter port #1 */
case 4: /* ->Parallel port joystick adapter port #2 */
joy = ie->unit - 1;
if (ie->type & 4) {
int old = joybutton[joy] & (1 << ie->data);
if (state) {
joybutton[joy] |= 1 << ie->data;
gui_gameport_button_change (joy, ie->data, 1);
} else {
joybutton[joy] &= ~(1 << ie->data);
gui_gameport_button_change (joy, ie->data, 0);
}
if (ie->data == 0 && old != (joybutton[joy] & (1 << ie->data)) && currprefs.cpu_cycle_exact) {
if (!input_record && !input_play && currprefs.input_contact_bounce) {
// emulate contact bounce, 1st button only, others have capacitors
bouncy = 1;
bouncy_cycles = get_cycles () + CYCLE_UNIT * currprefs.input_contact_bounce;
}
}
} else if (ie->type & 8) {
/* real mouse / analog stick mouse emulation */
int delta;
int deadzone = currprefs.input_joymouse_deadzone * max / 100;
int unit = ie->data & 0x7f;
if (max) {
if (state <= deadzone && state >= -deadzone) {
state = 0;
mouse_deltanoreset[joy][unit] = 0;
} else if (state < 0) {
state += deadzone;
mouse_deltanoreset[joy][unit] = 1;
} else {
state -= deadzone;
mouse_deltanoreset[joy][unit] = 1;
}
max -= deadzone;
delta = state * currprefs.input_joymouse_multiplier / max;
} else {
delta = state;
mouse_deltanoreset[joy][unit] = 0;
}
if (ie->data & IE_CDTV) {
delta = 0;
if (state > 0)
delta = JOYMOUSE_CDTV;
else if (state < 0)
delta = -JOYMOUSE_CDTV;
}
if (ie->data & IE_INVERT)
delta = -delta;
if (max)
mouse_delta[joy][unit] = delta;
else
mouse_delta[joy][unit] += delta;
max = 32;
if (unit) {
if (delta < 0) {
gui_gameport_axis_change (joy, DIR_UP_BIT, abs (delta), max);
gui_gameport_axis_change (joy, DIR_DOWN_BIT, 0, max);
}
if (delta > 0) {
gui_gameport_axis_change (joy, DIR_DOWN_BIT, abs (delta), max);
gui_gameport_axis_change (joy, DIR_UP_BIT, 0, max);
}
} else {
if (delta < 0) {
gui_gameport_axis_change (joy, DIR_LEFT_BIT, abs (delta), max);
gui_gameport_axis_change (joy, DIR_RIGHT_BIT, 0, max);
}
if (delta > 0) {
gui_gameport_axis_change (joy, DIR_RIGHT_BIT, abs (delta), max);
gui_gameport_axis_change (joy, DIR_LEFT_BIT, 0, max);
}
}
} else if (ie->type & 32) { /* button mouse emulation vertical */
int speed = (ie->data & IE_CDTV) ? JOYMOUSE_CDTV : currprefs.input_joymouse_speed;
if (state && (ie->data & DIR_UP)) {
mouse_delta[joy][1] = -speed;
mouse_deltanoreset[joy][1] = 1;
} else if (state && (ie->data & DIR_DOWN)) {
mouse_delta[joy][1] = speed;
mouse_deltanoreset[joy][1] = 1;
} else
mouse_deltanoreset[joy][1] = 0;
} else if (ie->type & 64) { /* button mouse emulation horizontal */
int speed = (ie->data & IE_CDTV) ? JOYMOUSE_CDTV : currprefs.input_joymouse_speed;
if (state && (ie->data & DIR_LEFT)) {
mouse_delta[joy][0] = -speed;
mouse_deltanoreset[joy][0] = 1;
} else if (state && (ie->data & DIR_RIGHT)) {
mouse_delta[joy][0] = speed;
mouse_deltanoreset[joy][0] = 1;
} else
mouse_deltanoreset[joy][0] = 0;
} else if (ie->type & 128) { /* analog joystick / paddle */
int deadzone = currprefs.input_joymouse_deadzone * max / 100;
int unit = ie->data & 0x7f;
if (max) {
if (state <= deadzone && state >= -deadzone) {
state = 0;
} else if (state < 0) {
state += deadzone;
} else {
state -= deadzone;
}
state = state * max / (max - deadzone);
}
if (ie->data & IE_INVERT)
state = -state;
if (!unit) {
if (state <= 0)
gui_gameport_axis_change (joy, DIR_UP_BIT, abs (state), max);
if (state >= 0)
gui_gameport_axis_change (joy, DIR_DOWN_BIT, abs (state), max);
} else {
if (state <= 0)
gui_gameport_axis_change (joy, DIR_LEFT_BIT, abs (state), max);
if (state >= 0)
gui_gameport_axis_change (joy, DIR_RIGHT_BIT, abs (state), max);
}
state = state * currprefs.input_analog_joystick_mult / max;
state += (128 * currprefs.input_analog_joystick_mult / 100) + currprefs.input_analog_joystick_offset;
if (state < 0)
state = 0;
if (state > 255)
state = 255;
joydirpot[joy][unit] = state;
mouse_deltanoreset[joy][0] = 1;
mouse_deltanoreset[joy][1] = 1;
} else {
int left = oleft[joy], right = oright[joy], top = otop[joy], bot = obot[joy];
if (ie->type & 16) {
/* button to axis mapping */
if (ie->data & DIR_LEFT) {
left = oleft[joy] = state ? 1 : 0;
if (horizclear[joy] && left) {
horizclear[joy] = 0;
right = oright[joy] = 0;
}
}
if (ie->data & DIR_RIGHT) {
right = oright[joy] = state ? 1 : 0;
if (horizclear[joy] && right) {
horizclear[joy] = 0;
left = oleft[joy] = 0;
}
}
if (ie->data & DIR_UP) {
top = otop[joy] = state ? 1 : 0;
if (vertclear[joy] && top) {
vertclear[joy] = 0;
bot = obot[joy] = 0;
}
}
if (ie->data & DIR_DOWN) {
bot = obot[joy] = state ? 1 : 0;
if (vertclear[joy] && bot) {
vertclear[joy] = 0;
top = otop[joy] = 0;
}
}
} else {
/* "normal" joystick axis */
int deadzone = currprefs.input_joystick_deadzone * max / 100;
int neg, pos;
if (state < deadzone && state > -deadzone)
state = 0;
neg = state < 0 ? 1 : 0;
pos = state > 0 ? 1 : 0;
if (ie->data & DIR_LEFT) {
left = oleft[joy] = neg;
if (horizclear[joy] && left) {
horizclear[joy] = 0;
right = oright[joy] = 0;
}
}
if (ie->data & DIR_RIGHT) {
right = oright[joy] = pos;
if (horizclear[joy] && right) {
horizclear[joy] = 0;
left = oleft[joy] = 0;
}
}
if (ie->data & DIR_UP) {
top = otop[joy] = neg;
if (vertclear[joy] && top) {
vertclear[joy] = 0;
bot = obot[joy] = 0;
}
}
if (ie->data & DIR_DOWN) {
bot = obot[joy] = pos;
if (vertclear[joy] && bot) {
vertclear[joy] = 0;
top = otop[joy] = 0;
}
}
}
mouse_deltanoreset[joy][0] = 1;
mouse_deltanoreset[joy][1] = 1;
joydir[joy] = 0;
if (left)
joydir[joy] |= DIR_LEFT;
if (right)
joydir[joy] |= DIR_RIGHT;
if (top)
joydir[joy] |= DIR_UP;
if (bot)
joydir[joy] |= DIR_DOWN;
if (joy == 0 || joy == 1)
joymousecounter (joy);
gui_gameport_axis_change (joy, DIR_LEFT_BIT, left, 0);
gui_gameport_axis_change (joy, DIR_RIGHT_BIT, right, 0);
gui_gameport_axis_change (joy, DIR_UP_BIT, top, 0);
gui_gameport_axis_change (joy, DIR_DOWN_BIT, bot, 0);
}
break;
case 0: /* ->KEY */
inputdevice_do_keyboard (ie->data, state);
break;
}
return 1;
}
static void inputdevice_checkconfig (void)
{
if (
currprefs.jports[0].id != changed_prefs.jports[0].id ||
currprefs.jports[1].id != changed_prefs.jports[1].id ||
currprefs.jports[2].id != changed_prefs.jports[2].id ||
currprefs.jports[3].id != changed_prefs.jports[3].id ||
currprefs.jports[0].mode != changed_prefs.jports[0].mode ||
currprefs.jports[1].mode != changed_prefs.jports[1].mode ||
currprefs.jports[2].mode != changed_prefs.jports[2].mode ||
currprefs.jports[3].mode != changed_prefs.jports[3].mode ||
currprefs.input_selected_setting != changed_prefs.input_selected_setting ||
currprefs.input_joymouse_multiplier != changed_prefs.input_joymouse_multiplier ||
currprefs.input_joymouse_deadzone != changed_prefs.input_joymouse_deadzone ||
currprefs.input_joystick_deadzone != changed_prefs.input_joystick_deadzone ||
currprefs.input_joymouse_speed != changed_prefs.input_joymouse_speed ||
currprefs.input_autofire_linecnt != changed_prefs.input_autofire_linecnt ||
currprefs.input_mouse_speed != changed_prefs.input_mouse_speed) {
currprefs.input_selected_setting = changed_prefs.input_selected_setting;
currprefs.input_joymouse_multiplier = changed_prefs.input_joymouse_multiplier;
currprefs.input_joymouse_deadzone = changed_prefs.input_joymouse_deadzone;
currprefs.input_joystick_deadzone = changed_prefs.input_joystick_deadzone;
currprefs.input_joymouse_speed = changed_prefs.input_joymouse_speed;
currprefs.input_autofire_linecnt = changed_prefs.input_autofire_linecnt;
currprefs.input_mouse_speed = changed_prefs.input_mouse_speed;
inputdevice_updateconfig (&currprefs);
}
if (currprefs.dongle != changed_prefs.dongle) {
currprefs.dongle = changed_prefs.dongle;
dongle_reset ();
}
}
void inputdevice_vsync (void)
{
if (inputdevice_logging & 32)
write_log (_T("*\n"));
input_frame++;
mouseupdate (0, 1);
if (!input_record) {
inputdevice_read ();
if (!input_play)
inputdelay = uaerand () % (maxvpos <= 1 ? 1 : maxvpos - 1);
}
inputdevice_handle_inputcode ();
if (mouseedge_alive > 0)
mouseedge_alive--;
#ifdef ARCADIA
if (arcadia_bios)
arcadia_vsync ();
#endif
if (mouseedge ())
mouseedge_alive = 10;
if (mousehack_alive_cnt > 0) {
mousehack_alive_cnt--;
if (mousehack_alive_cnt == 0)
setmouseactive (-1);
} else if (mousehack_alive_cnt < 0) {
mousehack_alive_cnt++;
if (mousehack_alive_cnt == 0) {
mousehack_alive_cnt = 100;
setmouseactive (0);
setmouseactive (1);
}
}
inputdevice_checkconfig ();
}
void inputdevice_reset (void)
{
magicmouse_ibase = 0;
magicmouse_gfxbase = 0;
mousehack_reset ();
if (inputdevice_is_tablet ())
mousehack_enable ();
bouncy = 0;
potgo_value = 0;
}
static int getoldport (struct uae_input_device *id)
{
int i, j;
for (i = 0; i < MAX_INPUT_DEVICE_EVENTS; i++) {
for (j = 0; j < MAX_INPUT_SUB_EVENT; j++) {
int evt = id->eventid[i][j];
if (evt > 0) {
int unit = events[evt].unit;
if (unit >= 1 && unit <= 4)
return unit;
}
}
}
return -1;
}
static int switchdevice (struct uae_input_device *id, int num, bool buttonmode)
{
int i, j;
int ismouse = 0;
int newport = 0;
int flags = 0;
TCHAR *name = NULL;
int otherbuttonpressed = 0;
if (num >= 4)
return 0;
#ifdef RETROPLATFORM
if (rp_isactive ())
return 0;
#endif
for (i = 0; i < MAX_INPUT_DEVICES; i++) {
if (id == &joysticks[i]) {
name = idev[IDTYPE_JOYSTICK].get_uniquename (i);
newport = num == 0 ? 1 : 0;
flags = idev[IDTYPE_JOYSTICK].get_flags (i);
for (j = 0; j < MAX_INPUT_DEVICES; j++) {
if (j != i) {
struct uae_input_device2 *id2 = &joysticks2[j];
if (id2->buttonmask)
otherbuttonpressed = 1;
}
}
}
if (id == &mice[i]) {
ismouse = 1;
name = idev[IDTYPE_MOUSE].get_uniquename (i);
newport = num == 0 ? 0 : 1;
flags = idev[IDTYPE_MOUSE].get_flags (i);
}
}
if (!name)
return 0;
if (buttonmode) {
if (num == 0 && otherbuttonpressed)
newport = newport ? 0 : 1;
} else {
newport = num ? 1 : 0;
}
/* "GamePorts" switch if in GamePorts mode or Input mode and GamePorts port was not NONE */
if (currprefs.input_selected_setting == GAMEPORT_INPUT_SETTINGS || currprefs.jports[newport].id != JPORT_NONE) {
if ((num == 0 || num == 1) && currprefs.jports[newport].id != JPORT_CUSTOM) {
int om = jsem_ismouse (num, &currprefs);
int om1 = jsem_ismouse (0, &currprefs);
int om2 = jsem_ismouse (1, &currprefs);
if ((om1 >= 0 || om2 >= 0) && ismouse)
return 0;
if (flags)
return 0;
if (name) {
write_log (_T("inputdevice change '%s':%d->%d\n"), name, num, newport);
inputdevice_joyport_config (&changed_prefs, name, newport, -1, 2);
inputdevice_copyconfig (&changed_prefs, &currprefs);
return 1;
}
}
return 0;
} else {
int oldport = getoldport (id);
int k, evt;
struct inputevent *ie, *ie2;
if (flags)
return 0;
if (oldport <= 0)
return 0;
newport++;
/* do not switch if switching mouse and any "supermouse" mouse enabled */
if (ismouse) {
for (i = 0; i < MAX_INPUT_SETTINGS; i++) {
if (mice[i].enabled && idev[IDTYPE_MOUSE].get_flags (i))
return 0;
}
}
for (i = 0; i < MAX_INPUT_SETTINGS; i++) {
if (getoldport (&joysticks[i]) == newport)
joysticks[i].enabled = 0;
if (getoldport (&mice[i]) == newport)
mice[i].enabled = 0;
}
id->enabled = 1;
for (i = 0; i < MAX_INPUT_DEVICE_EVENTS; i++) {
for (j = 0; j < MAX_INPUT_SUB_EVENT; j++) {
evt = id->eventid[i][j];
if (evt <= 0)
continue;
ie = &events[evt];
if (ie->unit == oldport) {
k = 1;
while (events[k].confname) {
ie2 = &events[k];
if (ie2->type == ie->type && ie2->data == ie->data && ie2->allow_mask == ie->allow_mask && ie2->unit == newport) {
id->eventid[i][j] = k;
break;
}
k++;
}
} else if (ie->unit == newport) {
k = 1;
while (events[k].confname) {
ie2 = &events[k];
if (ie2->type == ie->type && ie2->data == ie->data && ie2->allow_mask == ie->allow_mask && ie2->unit == oldport) {
id->eventid[i][j] = k;
break;
}
k++;
}
}
}
}
write_log (_T("inputdevice change '%s':%d->%d\n"), name, num, newport);
inputdevice_copyconfig (&currprefs, &changed_prefs);
inputdevice_copyconfig (&changed_prefs, &currprefs);
return 1;
}
return 0;
}
uae_u64 input_getqualifiers (void)
{
return qualifiers;
}
static bool checkqualifiers (int evt, uae_u64 flags, uae_u64 *qualmask, uae_s16 events[MAX_INPUT_SUB_EVENT_ALL])
{
int i, j;
int qualid = getqualid (evt);
int nomatch = 0;
bool isspecial = (qualifiers & (ID_FLAG_QUALIFIER_SPECIAL | ID_FLAG_QUALIFIER_SPECIAL_R)) != 0;
flags &= ID_FLAG_QUALIFIER_MASK;
if (qualid >= 0 && events)
qualifiers_evt[qualid] = events;
/* special set and new qualifier pressed? do not sent it to Amiga-side */
if ((qualifiers & (ID_FLAG_QUALIFIER_SPECIAL | ID_FLAG_QUALIFIER_SPECIAL_R)) && qualid >= 0)
return false;
for (i = 0; i < MAX_INPUT_SUB_EVENT; i++) {
if (qualmask[i])
break;
}
if (i == MAX_INPUT_SUB_EVENT) {
// no qualifiers in any slot and no special = always match
return isspecial == false;
}
for (i = 0; i < MAX_INPUT_SUB_EVENT; i++) {
for (j = 0; j < MAX_INPUT_QUALIFIERS; j++) {
uae_u64 mask = (ID_FLAG_QUALIFIER1 | ID_FLAG_QUALIFIER1_R) << (j * 2);
bool isqualmask = (qualmask[i] & mask) != 0;
bool isqual = (qualifiers & mask) != 0;
if (isqualmask != isqual) {
nomatch++;
break;
}
}
}
if (nomatch == MAX_INPUT_SUB_EVENT) {
// no matched qualifiers in any slot
// allow all slots without qualifiers
// special = never accept
if (isspecial)
return false;
return flags ? false : true;
}
for (i = 0; i < MAX_INPUT_QUALIFIERS; i++) {
uae_u64 mask = (ID_FLAG_QUALIFIER1 | ID_FLAG_QUALIFIER1_R) << (i * 2);
bool isflags = (flags & mask) != 0;
bool isqual = (qualifiers & mask) != 0;
if (isflags != isqual)
return false;
}
return true;
}
static void setqualifiers (int evt, int state)
{
uae_u64 mask = isqual (evt);
if (!mask)
return;
if (state)
qualifiers |= mask;
else
qualifiers &= ~mask;
//write_log (_T("%llx\n"), qualifiers);
}
static uae_u64 getqualmask (uae_u64 *qualmask, struct uae_input_device *id, int num, bool *qualonly)
{
uae_u64 mask = 0, mask2 = 0;
for (int i = 0; i < MAX_INPUT_SUB_EVENT; i++) {
int evt = id->eventid[num][i];
mask |= id->flags[num][i];
qualmask[i] = id->flags[num][i] & ID_FLAG_QUALIFIER_MASK;
mask2 |= isqual (evt);
}
mask &= ID_FLAG_QUALIFIER_MASK;
*qualonly = false;
if (qualifiers & ID_FLAG_QUALIFIER_SPECIAL) {
// ID_FLAG_QUALIFIER_SPECIAL already active and this event has one or more qualifiers configured
*qualonly = mask2 != 0;
}
return mask;
}
static bool process_custom_event (struct uae_input_device *id, int offset, int state, uae_u64 *qualmask, int autofire, int sub)
{
int idx, slotoffset, custompos;
TCHAR *custom;
uae_u64 flags, qual;
if (!id)
return false;
slotoffset = sub & ~3;
sub &= 3;
flags = id->flags[offset][slotoffset];
qual = flags & ID_FLAG_QUALIFIER_MASK;
custom = id->custom[offset][slotoffset];
int af = flags & ID_FLAG_AUTOFIRE_MASK;
for (idx = 1; idx < 4; idx++) {
uae_u64 flags2 = id->flags[offset][slotoffset + idx];
TCHAR *custom2 = id->custom[offset][slotoffset + idx];
// all slots must have same qualifier
if ((flags2 & ID_FLAG_QUALIFIER_MASK) != qual)
break;
// no slot must have autofire
if ((flags2 & ID_FLAG_AUTOFIRE_MASK) || (flags & ID_FLAG_AUTOFIRE_MASK))
break;
}
// at least slot 0 and 2 must have custom
if (custom == NULL || id->custom[offset][slotoffset + 2] == NULL)
idx = -1;
if (idx < 4) {
id->flags[offset][slotoffset] &= ~(ID_FLAG_CUSTOMEVENT_TOGGLED1 | ID_FLAG_CUSTOMEVENT_TOGGLED2);
int evt2 = id->eventid[offset][slotoffset + sub];
uae_u64 flags2 = id->flags[offset][slotoffset + sub];
if (checkqualifiers (evt2, flags2, qualmask, NULL)) {
custom = id->custom[offset][slotoffset + sub];
if (state && custom) {
if (autofire)
queue_input_event (-1, custom, 1, 1, currprefs.input_autofire_linecnt, 1);
handle_custom_event (custom);
return true;
}
}
return false;
}
if (sub != 0)
return false;
slotoffset = 0;
if (!checkqualifiers (id->eventid[offset][slotoffset], id->flags[offset][slotoffset], qualmask, NULL)) {
slotoffset = 4;
if (!checkqualifiers (id->eventid[offset][slotoffset], id->flags[offset][slotoffset], qualmask, NULL))
return false;
}
flags = id->flags[offset][slotoffset];
custompos = (flags & ID_FLAG_CUSTOMEVENT_TOGGLED1) ? 1 : 0;
custompos |= (flags & ID_FLAG_CUSTOMEVENT_TOGGLED2) ? 2 : 0;
if (state < 0) {
idx = 0;
custompos = 0;
} else {
if (state > 0) {
if (custompos & 1)
return false; // waiting for release
} else {
if (!(custompos & 1))
return false; // waiting for press
}
idx = custompos;
custompos++;
}
queue_input_event (-1, NULL, -1, 0, 0, 1);
if ((id->flags[offset][slotoffset + idx] & ID_FLAG_QUALIFIER_MASK) == qual) {
custom = id->custom[offset][slotoffset + idx];
if (autofire)
queue_input_event (-1, custom, 1, 1, currprefs.input_autofire_linecnt, 1);
if (custom)
handle_custom_event (custom);
}
id->flags[offset][slotoffset] &= ~(ID_FLAG_CUSTOMEVENT_TOGGLED1 | ID_FLAG_CUSTOMEVENT_TOGGLED2);
id->flags[offset][slotoffset] |= (custompos & 1) ? ID_FLAG_CUSTOMEVENT_TOGGLED1 : 0;
id->flags[offset][slotoffset] |= (custompos & 2) ? ID_FLAG_CUSTOMEVENT_TOGGLED2 : 0;
return true;
}
static void setbuttonstateall (struct uae_input_device *id, struct uae_input_device2 *id2, int button, int state)
{
static frame_time_t switchdevice_timeout;
int i;
uae_u32 mask = 1 << button;
uae_u32 omask = id2 ? id2->buttonmask & mask : 0;
uae_u32 nmask = (state ? 1 : 0) << button;
uae_u64 qualmask[MAX_INPUT_SUB_EVENT];
bool qualonly;
if (input_play && state)
inprec_realtime ();
if (input_play)
return;
if (!id->enabled) {
frame_time_t t = read_processor_time ();
if (state) {
switchdevice_timeout = t;
} else {
int port = button;
if (t - switchdevice_timeout >= syncbase) // 1s
port ^= 1;
switchdevice (id, port, true);
}
return;
}
if (button >= ID_BUTTON_TOTAL)
return;
getqualmask (qualmask, id, ID_BUTTON_OFFSET + button, &qualonly);
bool didcustom = false;
for (i = 0; i < MAX_INPUT_SUB_EVENT; i++) {
uae_u64 *flagsp = &id->flags[ID_BUTTON_OFFSET + button][sublevdir[state <= 0 ? 1 : 0][i]];
int evt = id->eventid[ID_BUTTON_OFFSET + button][sublevdir[state <= 0 ? 1 : 0][i]];
uae_u64 flags = flagsp[0];
int autofire = (flags & ID_FLAG_AUTOFIRE) ? 1 : 0;
int toggle = (flags & ID_FLAG_TOGGLE) ? 1 : 0;
int inverttoggle = (flags & ID_FLAG_INVERTTOGGLE) ? 1 : 0;
if (!state) {
didcustom |= process_custom_event (id, ID_BUTTON_OFFSET + button, state, qualmask, autofire, i);
}
setqualifiers (evt, state > 0);
if (qualonly)
continue;
if (state < 0) {
if (!checkqualifiers (evt, flags, qualmask, NULL))
continue;
handle_input_event (evt, 1, 1, 0, true, false);
queue_input_event (evt, NULL, 0, 1, 1, 0); /* send release event next frame */
didcustom |= process_custom_event (id, ID_BUTTON_OFFSET + button, state, qualmask, 0, i);
} else if (inverttoggle) {
/* pressed = firebutton, not pressed = autofire */
if (state) {
queue_input_event (evt, NULL, -1, 0, 0, 1);
handle_input_event (evt, 1, 1, 0, true, false);
} else {
handle_input_event (evt, 1, 1, autofire, true, false);
}
didcustom |= process_custom_event (id, ID_BUTTON_OFFSET + button, state, qualmask, autofire, i);
} else if (toggle) {
if (!state)
continue;
if (omask & mask)
continue;
if (!checkqualifiers (evt, flags, qualmask, NULL))
continue;
*flagsp ^= ID_FLAG_TOGGLED;
int toggled = (*flagsp & ID_FLAG_TOGGLED) ? 1 : 0;
handle_input_event (evt, toggled, 1, autofire, true, false);
didcustom |= process_custom_event (id, ID_BUTTON_OFFSET + button, toggled, qualmask, autofire, i);
} else {
if (!checkqualifiers (evt, flags, qualmask, NULL)) {
if (!state && !(flags & ID_FLAG_CANRELEASE)) {
continue;
} else if (state) {
continue;
}
}
if (!state)
*flagsp &= ~ID_FLAG_CANRELEASE;
else
*flagsp |= ID_FLAG_CANRELEASE;
if ((omask ^ nmask) & mask) {
handle_input_event (evt, state, 1, autofire, true, false);
if (state)
didcustom |= process_custom_event (id, ID_BUTTON_OFFSET + button, state, qualmask, autofire, i);
}
}
}
if (!didcustom)
queue_input_event (-1, NULL, -1, 0, 0, 1);
if (id2 && ((omask ^ nmask) & mask)) {
if (state)
id2->buttonmask |= mask;
else
id2->buttonmask &= ~mask;
}
}
/* - detect required number of joysticks and mice from configuration data
* - detect if CD32 pad emulation is needed
* - detect device type in ports (mouse or joystick)
*/
static int iscd32 (int ei)
{
if (ei >= INPUTEVENT_JOY1_CD32_FIRST && ei <= INPUTEVENT_JOY1_CD32_LAST) {
cd32_pad_enabled[0] = 1;
return 1;
}
if (ei >= INPUTEVENT_JOY2_CD32_FIRST && ei <= INPUTEVENT_JOY2_CD32_LAST) {
cd32_pad_enabled[1] = 1;
return 2;
}
return 0;
}
static int isparport (int ei)
{
if (ei > INPUTEVENT_PAR_JOY1_START && ei < INPUTEVENT_PAR_JOY_END) {
parport_joystick_enabled = 1;
return 1;
}
return 0;
}
static int ismouse (int ei)
{
if (ei >= INPUTEVENT_MOUSE1_FIRST && ei <= INPUTEVENT_MOUSE1_LAST) {
mouse_port[0] = 1;
return 1;
}
if (ei >= INPUTEVENT_MOUSE2_FIRST && ei <= INPUTEVENT_MOUSE2_LAST) {
mouse_port[1] = 1;
return 2;
}
return 0;
}
static int isanalog (int ei)
{
if (ei == INPUTEVENT_JOY1_HORIZ_POT || ei == INPUTEVENT_JOY1_HORIZ_POT_INV) {
analog_port[0][0] = 1;
return 1;
}
if (ei == INPUTEVENT_JOY1_VERT_POT || ei == INPUTEVENT_JOY1_VERT_POT_INV) {
analog_port[0][1] = 1;
return 1;
}
if (ei == INPUTEVENT_JOY2_HORIZ_POT || ei == INPUTEVENT_JOY2_HORIZ_POT_INV) {
analog_port[1][0] = 1;
return 1;
}
if (ei == INPUTEVENT_JOY2_VERT_POT || ei == INPUTEVENT_JOY2_VERT_POT_INV) {
analog_port[1][1] = 1;
return 1;
}
return 0;
}
static int isdigitalbutton (int ei)
{
if (ei == INPUTEVENT_JOY1_2ND_BUTTON) {
digital_port[0][1] = 1;
return 1;
}
if (ei == INPUTEVENT_JOY1_3RD_BUTTON) {
digital_port[0][0] = 1;
return 1;
}
if (ei == INPUTEVENT_JOY2_2ND_BUTTON) {
digital_port[1][1] = 1;
return 1;
}
if (ei == INPUTEVENT_JOY2_3RD_BUTTON) {
digital_port[1][0] = 1;
return 1;
}
return 0;
}
static void isqualifier (int ei)
{
}
static void scanevents (struct uae_prefs *p)
{
int i, j, k, ei;
const struct inputevent *e;
int n_joy = idev[IDTYPE_JOYSTICK].get_num ();
int n_mouse = idev[IDTYPE_MOUSE].get_num ();
cd32_pad_enabled[0] = cd32_pad_enabled[1] = 0;
parport_joystick_enabled = 0;
mouse_port[0] = mouse_port[1] = 0;
qualifiers = 0;
for (i = 0; i < NORMAL_JPORTS; i++) {
for (j = 0; j < 2; j++) {
digital_port[i][j] = 0;
analog_port[i][j] = 0;
joydirpot[i][j] = 128 / (312 * 100 / currprefs.input_analog_joystick_mult) + (128 * currprefs.input_analog_joystick_mult / 100) + currprefs.input_analog_joystick_offset;
}
}
for (i = 0; i < MAX_INPUT_DEVICES; i++) {
use_joysticks[i] = 0;
use_mice[i] = 0;
for (k = 0; k < MAX_INPUT_SUB_EVENT; k++) {
for (j = 0; j < ID_BUTTON_TOTAL; j++) {
if ((joysticks[i].enabled && i < n_joy) || joysticks[i].enabled < 0) {
ei = joysticks[i].eventid[ID_BUTTON_OFFSET + j][k];
e = &events[ei];
iscd32 (ei);
isparport (ei);
ismouse (ei);
isdigitalbutton (ei);
isqualifier (ei);
if (joysticks[i].eventid[ID_BUTTON_OFFSET + j][k] > 0)
use_joysticks[i] = 1;
}
if ((mice[i].enabled && i < n_mouse) || mice[i].enabled < 0) {
ei = mice[i].eventid[ID_BUTTON_OFFSET + j][k];
e = &events[ei];
iscd32 (ei);
isparport (ei);
ismouse (ei);
isdigitalbutton (ei);
isqualifier (ei);
if (mice[i].eventid[ID_BUTTON_OFFSET + j][k] > 0)
use_mice[i] = 1;
}
}
for (j = 0; j < ID_AXIS_TOTAL; j++) {
if ((joysticks[i].enabled && i < n_joy) || joysticks[i].enabled < 0) {
ei = joysticks[i].eventid[ID_AXIS_OFFSET + j][k];
iscd32 (ei);
isparport (ei);
ismouse (ei);
isanalog (ei);
isdigitalbutton (ei);
isqualifier (ei);
if (ei > 0)
use_joysticks[i] = 1;
}
if ((mice[i].enabled && i < n_mouse) || mice[i].enabled < 0) {
ei = mice[i].eventid[ID_AXIS_OFFSET + j][k];
iscd32 (ei);
isparport (ei);
ismouse (ei);
isanalog (ei);
isdigitalbutton (ei);
isqualifier (ei);
if (ei > 0)
use_mice[i] = 1;
}
}
}
}
memset (scancodeused, 0, sizeof scancodeused);
for (i = 0; i < MAX_INPUT_DEVICES; i++) {
use_keyboards[i] = 0;
if (keyboards[i].enabled && i < idev[IDTYPE_KEYBOARD].get_num ()) {
j = 0;
while (j < MAX_INPUT_DEVICE_EVENTS && keyboards[i].extra[j] >= 0) {
use_keyboards[i] = 1;
for (k = 0; k < MAX_INPUT_SUB_EVENT; k++) {
ei = keyboards[i].eventid[j][k];
iscd32 (ei);
isparport (ei);
ismouse (ei);
isdigitalbutton (ei);
isqualifier (ei);
if (ei > 0)
scancodeused[i][keyboards[i].extra[j]] = ei;
}
j++;
}
}
}
}
static int axistable[] = {
INPUTEVENT_MOUSE1_HORIZ, INPUTEVENT_MOUSE1_LEFT, INPUTEVENT_MOUSE1_RIGHT,
INPUTEVENT_MOUSE1_VERT, INPUTEVENT_MOUSE1_UP, INPUTEVENT_MOUSE1_DOWN,
INPUTEVENT_MOUSE2_HORIZ, INPUTEVENT_MOUSE2_LEFT, INPUTEVENT_MOUSE2_RIGHT,
INPUTEVENT_MOUSE2_VERT, INPUTEVENT_MOUSE2_UP, INPUTEVENT_MOUSE2_DOWN,
INPUTEVENT_JOY1_HORIZ, INPUTEVENT_JOY1_LEFT, INPUTEVENT_JOY1_RIGHT,
INPUTEVENT_JOY1_VERT, INPUTEVENT_JOY1_UP, INPUTEVENT_JOY1_DOWN,
INPUTEVENT_JOY2_HORIZ, INPUTEVENT_JOY2_LEFT, INPUTEVENT_JOY2_RIGHT,
INPUTEVENT_JOY2_VERT, INPUTEVENT_JOY2_UP, INPUTEVENT_JOY2_DOWN,
INPUTEVENT_LIGHTPEN_HORIZ, INPUTEVENT_LIGHTPEN_LEFT, INPUTEVENT_LIGHTPEN_RIGHT,
INPUTEVENT_LIGHTPEN_VERT, INPUTEVENT_LIGHTPEN_UP, INPUTEVENT_LIGHTPEN_DOWN,
INPUTEVENT_PAR_JOY1_HORIZ, INPUTEVENT_PAR_JOY1_LEFT, INPUTEVENT_PAR_JOY1_RIGHT,
INPUTEVENT_PAR_JOY1_VERT, INPUTEVENT_PAR_JOY1_UP, INPUTEVENT_PAR_JOY1_DOWN,
INPUTEVENT_PAR_JOY2_HORIZ, INPUTEVENT_PAR_JOY2_LEFT, INPUTEVENT_PAR_JOY2_RIGHT,
INPUTEVENT_PAR_JOY2_VERT, INPUTEVENT_PAR_JOY2_UP, INPUTEVENT_PAR_JOY2_DOWN,
INPUTEVENT_MOUSE_CDTV_HORIZ, INPUTEVENT_MOUSE_CDTV_LEFT, INPUTEVENT_MOUSE_CDTV_RIGHT,
INPUTEVENT_MOUSE_CDTV_VERT, INPUTEVENT_MOUSE_CDTV_UP, INPUTEVENT_MOUSE_CDTV_DOWN,
-1
};
int intputdevice_compa_get_eventtype (int evt, int **axistablep)
{
for (int i = 0; axistable[i] >= 0; i += 3) {
*axistablep = &axistable[i];
if (axistable[i] == evt)
return IDEV_WIDGET_AXIS;
if (axistable[i + 1] == evt)
return IDEV_WIDGET_BUTTONAXIS;
if (axistable[i + 2] == evt)
return IDEV_WIDGET_BUTTONAXIS;
}
*axistablep = NULL;
return IDEV_WIDGET_BUTTON;
}
static int rem_port1[] = {
INPUTEVENT_MOUSE1_HORIZ, INPUTEVENT_MOUSE1_VERT,
INPUTEVENT_JOY1_HORIZ, INPUTEVENT_JOY1_VERT,
INPUTEVENT_JOY1_HORIZ_POT, INPUTEVENT_JOY1_VERT_POT,
INPUTEVENT_JOY1_FIRE_BUTTON, INPUTEVENT_JOY1_2ND_BUTTON, INPUTEVENT_JOY1_3RD_BUTTON,
INPUTEVENT_JOY1_CD32_RED, INPUTEVENT_JOY1_CD32_BLUE, INPUTEVENT_JOY1_CD32_GREEN, INPUTEVENT_JOY1_CD32_YELLOW,
INPUTEVENT_JOY1_CD32_RWD, INPUTEVENT_JOY1_CD32_FFW, INPUTEVENT_JOY1_CD32_PLAY,
INPUTEVENT_MOUSE_CDTV_HORIZ, INPUTEVENT_MOUSE_CDTV_VERT,
INPUTEVENT_LIGHTPEN_HORIZ, INPUTEVENT_LIGHTPEN_VERT,
-1
};
static int rem_port2[] = {
INPUTEVENT_MOUSE2_HORIZ, INPUTEVENT_MOUSE2_VERT,
INPUTEVENT_JOY2_HORIZ, INPUTEVENT_JOY2_VERT,
INPUTEVENT_JOY2_HORIZ_POT, INPUTEVENT_JOY2_VERT_POT,
INPUTEVENT_JOY2_FIRE_BUTTON, INPUTEVENT_JOY2_2ND_BUTTON, INPUTEVENT_JOY2_3RD_BUTTON,
INPUTEVENT_JOY2_CD32_RED, INPUTEVENT_JOY2_CD32_BLUE, INPUTEVENT_JOY2_CD32_GREEN, INPUTEVENT_JOY2_CD32_YELLOW,
INPUTEVENT_JOY2_CD32_RWD, INPUTEVENT_JOY2_CD32_FFW, INPUTEVENT_JOY2_CD32_PLAY,
-1, -1,
-1, -1,
-1
};
static int rem_port3[] = {
INPUTEVENT_PAR_JOY1_LEFT, INPUTEVENT_PAR_JOY1_RIGHT, INPUTEVENT_PAR_JOY1_UP, INPUTEVENT_PAR_JOY1_DOWN,
INPUTEVENT_PAR_JOY1_FIRE_BUTTON, INPUTEVENT_PAR_JOY1_2ND_BUTTON,
-1
};
static int rem_port4[] = {
INPUTEVENT_PAR_JOY2_LEFT, INPUTEVENT_PAR_JOY2_RIGHT, INPUTEVENT_PAR_JOY2_UP, INPUTEVENT_PAR_JOY2_DOWN,
INPUTEVENT_PAR_JOY2_FIRE_BUTTON, INPUTEVENT_PAR_JOY2_2ND_BUTTON,
-1
};
static int *rem_ports[] = { rem_port1, rem_port2, rem_port3, rem_port4 };
static int af_port1[] = {
INPUTEVENT_JOY1_FIRE_BUTTON, INPUTEVENT_JOY1_CD32_RED,
-1
};
static int af_port2[] = {
INPUTEVENT_JOY2_FIRE_BUTTON, INPUTEVENT_JOY2_CD32_RED,
-1
};
static int af_port3[] = {
INPUTEVENT_PAR_JOY1_FIRE_BUTTON, INPUTEVENT_PAR_JOY1_2ND_BUTTON,
-1
};
static int af_port4[] = {
INPUTEVENT_PAR_JOY2_FIRE_BUTTON, INPUTEVENT_PAR_JOY2_2ND_BUTTON,
-1
};
static int *af_ports[] = { af_port1, af_port2, af_port3, af_port4 };
static int ip_joy1[] = {
INPUTEVENT_JOY1_LEFT, INPUTEVENT_JOY1_RIGHT, INPUTEVENT_JOY1_UP, INPUTEVENT_JOY1_DOWN,
INPUTEVENT_JOY1_FIRE_BUTTON, INPUTEVENT_JOY1_2ND_BUTTON,
-1
};
static int ip_joy2[] = {
INPUTEVENT_JOY2_LEFT, INPUTEVENT_JOY2_RIGHT, INPUTEVENT_JOY2_UP, INPUTEVENT_JOY2_DOWN,
INPUTEVENT_JOY2_FIRE_BUTTON, INPUTEVENT_JOY2_2ND_BUTTON,
-1
};
static int ip_joypad1[] = {
INPUTEVENT_JOY1_LEFT, INPUTEVENT_JOY1_RIGHT, INPUTEVENT_JOY1_UP, INPUTEVENT_JOY1_DOWN,
INPUTEVENT_JOY1_FIRE_BUTTON, INPUTEVENT_JOY1_2ND_BUTTON, INPUTEVENT_JOY1_3RD_BUTTON,
-1
};
static int ip_joypad2[] = {
INPUTEVENT_JOY2_LEFT, INPUTEVENT_JOY2_RIGHT, INPUTEVENT_JOY2_UP, INPUTEVENT_JOY2_DOWN,
INPUTEVENT_JOY2_FIRE_BUTTON, INPUTEVENT_JOY2_2ND_BUTTON, INPUTEVENT_JOY2_3RD_BUTTON,
-1
};
static int ip_joycd321[] = {
INPUTEVENT_JOY1_LEFT, INPUTEVENT_JOY1_RIGHT, INPUTEVENT_JOY1_UP, INPUTEVENT_JOY1_DOWN,
INPUTEVENT_JOY1_CD32_RED, INPUTEVENT_JOY1_CD32_BLUE, INPUTEVENT_JOY1_CD32_GREEN, INPUTEVENT_JOY1_CD32_YELLOW,
INPUTEVENT_JOY1_CD32_RWD, INPUTEVENT_JOY1_CD32_FFW, INPUTEVENT_JOY1_CD32_PLAY,
-1
};
static int ip_joycd322[] = {
INPUTEVENT_JOY2_LEFT, INPUTEVENT_JOY2_RIGHT, INPUTEVENT_JOY2_UP, INPUTEVENT_JOY2_DOWN,
INPUTEVENT_JOY2_CD32_RED, INPUTEVENT_JOY2_CD32_BLUE, INPUTEVENT_JOY2_CD32_GREEN, INPUTEVENT_JOY2_CD32_YELLOW,
INPUTEVENT_JOY2_CD32_RWD, INPUTEVENT_JOY2_CD32_FFW, INPUTEVENT_JOY2_CD32_PLAY,
-1
};
static int ip_parjoy1[] = {
INPUTEVENT_PAR_JOY1_LEFT, INPUTEVENT_PAR_JOY1_RIGHT, INPUTEVENT_PAR_JOY1_UP, INPUTEVENT_PAR_JOY1_DOWN,
INPUTEVENT_PAR_JOY1_FIRE_BUTTON, INPUTEVENT_PAR_JOY1_2ND_BUTTON,
-1
};
static int ip_parjoy2[] = {
INPUTEVENT_PAR_JOY2_LEFT, INPUTEVENT_PAR_JOY2_RIGHT, INPUTEVENT_PAR_JOY2_UP, INPUTEVENT_PAR_JOY2_DOWN,
INPUTEVENT_PAR_JOY2_FIRE_BUTTON, INPUTEVENT_PAR_JOY2_2ND_BUTTON,
-1
};
static int ip_parjoy1default[] = {
INPUTEVENT_PAR_JOY1_LEFT, INPUTEVENT_PAR_JOY1_RIGHT, INPUTEVENT_PAR_JOY1_UP, INPUTEVENT_PAR_JOY1_DOWN,
INPUTEVENT_PAR_JOY1_FIRE_BUTTON,
-1
};
static int ip_parjoy2default[] = {
INPUTEVENT_PAR_JOY2_LEFT, INPUTEVENT_PAR_JOY2_RIGHT, INPUTEVENT_PAR_JOY2_UP, INPUTEVENT_PAR_JOY2_DOWN,
INPUTEVENT_PAR_JOY2_FIRE_BUTTON,
-1
};
static int ip_mouse1[] = {
INPUTEVENT_MOUSE1_LEFT, INPUTEVENT_MOUSE1_RIGHT, INPUTEVENT_MOUSE1_UP, INPUTEVENT_MOUSE1_DOWN,
INPUTEVENT_JOY1_FIRE_BUTTON, INPUTEVENT_JOY1_2ND_BUTTON,
-1
};
static int ip_mouse2[] = {
INPUTEVENT_MOUSE2_LEFT, INPUTEVENT_MOUSE2_RIGHT, INPUTEVENT_MOUSE2_UP, INPUTEVENT_MOUSE2_DOWN,
INPUTEVENT_JOY2_FIRE_BUTTON, INPUTEVENT_JOY2_2ND_BUTTON,
-1
};
static int ip_mousecdtv[] =
{
INPUTEVENT_MOUSE_CDTV_LEFT, INPUTEVENT_MOUSE_CDTV_RIGHT, INPUTEVENT_MOUSE_CDTV_UP, INPUTEVENT_MOUSE_CDTV_DOWN,
INPUTEVENT_JOY1_FIRE_BUTTON, INPUTEVENT_JOY1_2ND_BUTTON,
-1
};
static int ip_mediacdtv[] =
{
INPUTEVENT_KEY_CDTV_PLAYPAUSE, INPUTEVENT_KEY_CDTV_STOP, INPUTEVENT_KEY_CDTV_PREV, INPUTEVENT_KEY_CDTV_NEXT,
-1
};
static int ip_arcadia[] = {
INPUTEVENT_SPC_ARCADIA_DIAGNOSTICS, INPUTEVENT_SPC_ARCADIA_PLAYER1, INPUTEVENT_SPC_ARCADIA_PLAYER2,
INPUTEVENT_SPC_ARCADIA_COIN1, INPUTEVENT_SPC_ARCADIA_COIN2,
-1
};
static int ip_lightpen1[] = {
INPUTEVENT_LIGHTPEN_HORIZ, INPUTEVENT_LIGHTPEN_VERT, INPUTEVENT_JOY1_3RD_BUTTON,
-1
};
static int ip_lightpen2[] = {
INPUTEVENT_LIGHTPEN_HORIZ, INPUTEVENT_LIGHTPEN_VERT, INPUTEVENT_JOY2_3RD_BUTTON,
-1
};
static int ip_analog1[] = {
INPUTEVENT_JOY1_HORIZ_POT, INPUTEVENT_JOY1_VERT_POT, INPUTEVENT_JOY1_LEFT, INPUTEVENT_JOY1_RIGHT,
-1
};
static int ip_analog2[] = {
INPUTEVENT_JOY2_HORIZ_POT, INPUTEVENT_JOY2_VERT_POT, INPUTEVENT_JOY2_LEFT, INPUTEVENT_JOY2_RIGHT,
-1
};
static int ip_arcadiaxa[] = {
-1
};
static void checkcompakb (int *kb, int *srcmap)
{
int found = 0, avail = 0;
int j, k;
k = j = 0;
while (kb[j] >= 0) {
struct uae_input_device *uid = &keyboards[0];
while (kb[j] >= 0 && srcmap[k] >= 0) {
int id = kb[j];
for (int l = 0; l < MAX_INPUT_DEVICE_EVENTS; l++) {
if (uid->extra[l] == id) {
avail++;
if (uid->eventid[l][0] == srcmap[k])
found++;
break;
}
}
j++;
}
if (srcmap[k] < 0)
break;
j++;
k++;
}
if (avail != found || avail == 0)
return;
k = j = 0;
while (kb[j] >= 0) {
struct uae_input_device *uid = &keyboards[0];
while (kb[j] >= 0) {
int id = kb[j];
int evt0 = 0, evt1 = 0;
k = 0;
while (keyboard_default[k].scancode >= 0) {
if (keyboard_default[k].scancode == kb[j]) {
for (int l = 0; l < MAX_INPUT_DEVICE_EVENTS; l++) {
if (uid->extra[l] == id) {
for (int m = 0; m < MAX_INPUT_SUB_EVENT && keyboard_default[k].node[m].evt; m++) {
uid->eventid[l][m] = keyboard_default[k].node[m].evt;
}
break;
}
}
break;
}
k++;
}
j++;
}
j++;
}
}
static void setautofireevent (struct uae_input_device *uid, int num, int sub, int af, int index)
{
if (!af)
return;
#ifdef RETROPLATFORM
// don't override custom AF autofire mappings
if (rp_isactive ())
return;
#endif
int *afp = af_ports[index];
for (int k = 0; afp[k] >= 0; k++) {
if (afp[k] == uid->eventid[num][sub]) {
uid->flags[num][sub] &= ~ID_FLAG_AUTOFIRE_MASK;
if (af >= JPORT_AF_NORMAL)
uid->flags[num][sub] |= ID_FLAG_AUTOFIRE;
if (af == JPORT_AF_TOGGLE)
uid->flags[num][sub] |= ID_FLAG_TOGGLE;
if (af == JPORT_AF_ALWAYS)
uid->flags[num][sub] |= ID_FLAG_INVERTTOGGLE;
return;
}
}
}
static void sparerestore (struct uae_input_device *uid, int num, int sub)
{
uid->eventid[num][sub] = uid->eventid[num][SPARE_SUB_EVENT];
uid->flags[num][sub] = uid->flags[num][SPARE_SUB_EVENT];
uid->custom[num][sub] = uid->custom[num][SPARE_SUB_EVENT];
uid->eventid[num][SPARE_SUB_EVENT] = 0;
uid->flags[num][SPARE_SUB_EVENT] = 0;
uid->port[num][SPARE_SUB_EVENT] = 0;
uid->custom[num][SPARE_SUB_EVENT] = 0;
}
static void sparecopy (struct uae_input_device *uid, int num, int sub)
{
uid->eventid[num][SPARE_SUB_EVENT] = uid->eventid[num][sub];
uid->flags[num][SPARE_SUB_EVENT] = uid->flags[num][sub];
uid->port[num][SPARE_SUB_EVENT] = MAX_JPORTS + 1;
xfree (uid->custom[num][SPARE_SUB_EVENT]);
uid->custom[num][SPARE_SUB_EVENT] = uid->custom[num][sub];
uid->custom[num][sub] = NULL;
}
static void setcompakb (int *kb, int *srcmap, int index, int af)
{
int j, k;
k = j = 0;
while (kb[j] >= 0 && srcmap[k] >= 0) {
while (kb[j] >= 0) {
int id = kb[j];
for (int m = 0; m < MAX_INPUT_DEVICES; m++) {
struct uae_input_device *uid = &keyboards[m];
for (int l = 0; l < MAX_INPUT_DEVICE_EVENTS; l++) {
if (uid->extra[l] == id) {
sparecopy (uid, l, 0);
uid->eventid[l][0] = srcmap[k];
uid->flags[l][0] = 0;
uid->port[l][0] = index + 1;
xfree (uid->custom[l][0]);
uid->custom[l][0] = NULL;
setautofireevent (uid, l, 0, af, index);
break;
}
}
}
j++;
}
j++;
k++;
}
}
int inputdevice_get_compatibility_input (struct uae_prefs *prefs, int index, int *typelist, int **inputlist, int **at)
{
if (index >= MAX_JPORTS || joymodes[index] < 0)
return 0;
*typelist = joymodes[index];
*inputlist = joyinputs[index];
*at = axistable;
int cnt = 0;
for (int i = 0; joyinputs[index] && joyinputs[index][i] >= 0; i++, cnt++);
return cnt;
}
static void clearevent (struct uae_input_device *uid, int evt)
{
for (int i = 0; i < MAX_INPUT_DEVICE_EVENTS; i++) {
for (int j = 0; j < MAX_INPUT_SUB_EVENT; j++) {
if (uid->eventid[i][j] == evt) {
uid->eventid[i][j] = 0;
uid->flags[i][j] = 0;
xfree (uid->custom[i][j]);
uid->custom[i][j] = NULL;
}
}
}
}
static void clearkbrevent (struct uae_input_device *uid, int evt)
{
for (int i = 0; i < MAX_INPUT_DEVICE_EVENTS; i++) {
for (int j = 0; j < MAX_INPUT_SUB_EVENT; j++) {
if (uid->eventid[i][j] == evt) {
uid->eventid[i][j] = 0;
uid->flags[i][j] = 0;
xfree (uid->custom[i][j]);
uid->custom[i][j] = NULL;
if (j == 0)
set_kbr_default_event (uid, keyboard_default, i);
}
}
}
}
static void resetjport (struct uae_prefs *prefs, int index)
{
int *p = rem_ports[index];
while (*p >= 0) {
int evtnum = *p++;
for (int l = 0; l < MAX_INPUT_DEVICES; l++) {
clearevent (&prefs->joystick_settings[GAMEPORT_INPUT_SETTINGS][l], evtnum);
clearevent (&prefs->mouse_settings[GAMEPORT_INPUT_SETTINGS][l], evtnum);
clearkbrevent (&prefs->keyboard_settings[GAMEPORT_INPUT_SETTINGS][l], evtnum);
}
for (int i = 0; axistable[i] >= 0; i += 3) {
if (evtnum == axistable[i] || evtnum == axistable[i + 1] || evtnum == axistable[i + 2]) {
for (int j = 0; j < 3; j++) {
int evtnum2 = axistable[i + j];
for (int l = 0; l < MAX_INPUT_DEVICES; l++) {
clearevent (&prefs->joystick_settings[GAMEPORT_INPUT_SETTINGS][l], evtnum2);
clearevent (&prefs->mouse_settings[GAMEPORT_INPUT_SETTINGS][l], evtnum2);
clearkbrevent (&prefs->keyboard_settings[GAMEPORT_INPUT_SETTINGS][l], evtnum2);
}
}
break;
}
}
}
}
static void remove_compa_config (struct uae_prefs *prefs, int index)
{
int typelist, *inputlist, *atp;
if (!inputdevice_get_compatibility_input (prefs, index, &typelist, &inputlist, &atp))
return;
for (int i = 0; inputlist[i] >= 0; i++) {
int evtnum = inputlist[i];
int atpidx = 0;
while (*atp >= 0) {
if (*atp == evtnum) {
atp++;
atpidx = 2;
break;
}
if (atp[1] == evtnum || atp[2] == evtnum) {
atpidx = 1;
break;
}
atp += 3;
}
while (atpidx >= 0) {
for (int l = 0; l < MAX_INPUT_DEVICES; l++) {
clearevent (&prefs->joystick_settings[GAMEPORT_INPUT_SETTINGS][l], evtnum);
clearevent (&prefs->mouse_settings[GAMEPORT_INPUT_SETTINGS][l], evtnum);
clearkbrevent (&prefs->keyboard_settings[GAMEPORT_INPUT_SETTINGS][l], evtnum);
}
evtnum = *atp++;
atpidx--;
}
}
}
static void cleardevgp (struct uae_input_device *uid, int num, bool nocustom, int index)
{
for (int i = 0; i < MAX_INPUT_DEVICE_EVENTS; i++) {
for (int j = 0; j < MAX_INPUT_SUB_EVENT; j++) {
if (uid[num].port[i][j] == index + 1) {
if (nocustom && (uid[num].flags[i][j] & ID_FLAG_GAMEPORTSCUSTOM_MASK))
continue;
uid[num].eventid[i][j] = 0;
uid[num].flags[i][j] = 0;
xfree (uid[num].custom[i][j]);
uid[num].custom[i][j] = NULL;
uid[num].port[i][j] = 0;
if (uid[num].port[i][SPARE_SUB_EVENT])
sparerestore (&uid[num], i, j);
}
}
}
}
static void cleardevkbrgp (struct uae_input_device *uid, int num, bool nocustom, int index)
{
for (int i = 0; i < MAX_INPUT_DEVICE_EVENTS; i++) {
for (int j = 0; j < MAX_INPUT_SUB_EVENT; j++) {
if (uid[num].port[i][j] == index + 1) {
if (nocustom && (uid[num].flags[i][j] & ID_FLAG_GAMEPORTSCUSTOM_MASK))
continue;
uid[num].eventid[i][j] = 0;
uid[num].flags[i][j] = 0;
xfree (uid[num].custom[i][j]);
uid[num].custom[i][j] = NULL;
uid[num].port[i][j] = 0;
if (uid[num].port[i][SPARE_SUB_EVENT]) {
sparerestore (&uid[num], i, j);
} else if (j == 0) {
set_kbr_default_event (&uid[num], keyboard_default, i);
}
}
}
}
}
// remove all gameports mappings mapped to port 'index'
static void remove_custom_config (struct uae_prefs *prefs, bool nocustom, int index)
{
for (int l = 0; l < MAX_INPUT_DEVICES; l++) {
cleardevgp (joysticks, l, nocustom, index);
cleardevgp (mice, l, nocustom, index);
cleardevkbrgp (keyboards, l, nocustom, index);
}
}
// prepare port for custom mapping, remove all current Amiga side device mappings
void inputdevice_compa_prepare_custom (struct uae_prefs *prefs, int index, int newmode)
{
int mode = prefs->jports[index].mode;
freejport (prefs, index);
resetjport (prefs, index);
if (newmode >= 0) {
mode = newmode;
} else if (mode == 0) {
mode = index == 0 ? JSEM_MODE_MOUSE : (prefs->cs_cd32cd ? JSEM_MODE_JOYSTICK_CD32 : JSEM_MODE_JOYSTICK);
}
prefs->jports[index].mode = mode;
prefs->jports[index].id = -2;
remove_compa_config (prefs, index);
remove_custom_config (prefs, false, index);
}
// clear device before switching to new one
void inputdevice_compa_clear (struct uae_prefs *prefs, int index)
{
freejport (prefs, index);
resetjport (prefs, index);
remove_compa_config (prefs, index);
}
static void cleardev (struct uae_input_device *uid, int num)
{
for (int i = 0; i < MAX_INPUT_DEVICE_EVENTS; i++) {
for (int j = 0; j < MAX_INPUT_SUB_EVENT; j++) {
uid[num].eventid[i][j] = 0;
uid[num].flags[i][j] = 0;
xfree (uid[num].custom[i][j]);
uid[num].custom[i][j] = NULL;
}
}
}
static void enablejoydevice (struct uae_input_device *uid, bool gameportsmode, int evtnum)
{
for (int i = 0; i < MAX_INPUT_DEVICE_EVENTS; i++) {
for (int j = 0; j < MAX_INPUT_SUB_EVENT; j++) {
if ((gameportsmode && uid->eventid[i][j] == evtnum) || uid->port[i][j] > 0) {
uid->enabled = 1;
}
}
}
}
static void setjoydevices (struct uae_prefs *prefs, bool gameportsmode, int port)
{
for (int i = 0; joyinputs[port] && joyinputs[port][i] >= 0; i++) {
int evtnum = joyinputs[port][i];
for (int l = 0; l < MAX_INPUT_DEVICES; l++) {
enablejoydevice (&joysticks[l], gameportsmode, evtnum);
enablejoydevice (&mice[l], gameportsmode, evtnum);
enablejoydevice (&keyboards[l], gameportsmode, evtnum);
}
for (int k = 0; axistable[k] >= 0; k += 3) {
if (evtnum == axistable[k] || evtnum == axistable[k + 1] || evtnum == axistable[k + 2]) {
for (int j = 0; j < 3; j++) {
int evtnum2 = axistable[k + j];
for (int l = 0; l < MAX_INPUT_DEVICES; l++) {
enablejoydevice (&joysticks[l], gameportsmode, evtnum2);
enablejoydevice (&mice[l], gameportsmode, evtnum2);
enablejoydevice (&keyboards[l], gameportsmode, evtnum2);
}
}
break;
}
}
}
}
static void setjoyinputs (struct uae_prefs *prefs, int port)
{
joyinputs[port] = NULL;
switch (joymodes[port])
{
case JSEM_MODE_JOYSTICK:
if (port >= 2)
joyinputs[port] = port == 3 ? ip_parjoy2 : ip_parjoy1;
else
joyinputs[port] = port == 1 ? ip_joy2 : ip_joy1;
break;
case JSEM_MODE_GAMEPAD:
joyinputs[port] = port ? ip_joypad2 : ip_joypad1;
break;
case JSEM_MODE_JOYSTICK_CD32:
joyinputs[port] = port ? ip_joycd322 : ip_joycd321;
break;
case JSEM_MODE_JOYSTICK_ANALOG:
joyinputs[port] = port ? ip_analog2 : ip_analog1;
break;
case JSEM_MODE_MOUSE:
joyinputs[port] = port ? ip_mouse2 : ip_mouse1;
break;
case JSEM_MODE_LIGHTPEN:
joyinputs[port] = port ? ip_lightpen2 : ip_lightpen1;
break;
case JSEM_MODE_MOUSE_CDTV:
joyinputs[port] = ip_mousecdtv;
break;
}
}
static void setautofire (struct uae_input_device *uid, int port, int af)
{
int *afp = af_ports[port];
for (int k = 0; afp[k] >= 0; k++) {
for (int i = 0; i < MAX_INPUT_DEVICE_EVENTS; i++) {
for (int j = 0; j < MAX_INPUT_SUB_EVENT; j++) {
if (uid->eventid[i][j] == afp[k]) {
uid->flags[i][j] &= ~ID_FLAG_AUTOFIRE_MASK;
if (af >= JPORT_AF_NORMAL)
uid->flags[i][j] |= ID_FLAG_AUTOFIRE;
if (af == JPORT_AF_TOGGLE)
uid->flags[i][j] |= ID_FLAG_TOGGLE;
if (af == JPORT_AF_ALWAYS)
uid->flags[i][j] |= ID_FLAG_INVERTTOGGLE;
}
}
}
}
}
static void setautofires (struct uae_prefs *prefs, int port, int af)
{
#ifdef RETROPLATFORM
// don't override custom AF autofire mappings
if (rp_isactive ())
return;
#endif
for (int l = 0; l < MAX_INPUT_DEVICES; l++) {
setautofire (&joysticks[l], port, af);
setautofire (&mice[l], port, af);
setautofire (&keyboards[l], port, af);
}
}
// merge gameport settings with current input configuration
static void compatibility_copy (struct uae_prefs *prefs, bool gameports)
{
int used[MAX_INPUT_DEVICES] = { 0 };
int i, joy;
for (i = 0; i < MAX_JPORTS; i++) {
joymodes[i] = prefs->jports[i].mode;
joyinputs[i]= NULL;
// remove all mappings from this port, except if custom
if (prefs->jports[i].id != JPORT_CUSTOM) {
if (gameports)
remove_compa_config (prefs, i);
}
remove_custom_config (prefs, prefs->jports[i].id == JPORT_CUSTOM, i);
setjoyinputs (prefs, i);
}
for (i = 0; i < 2; i++) {
int af = prefs->jports[i].autofire;
if (prefs->jports[i].id >= 0 && joymodes[i] <= 0) {
int mode = prefs->jports[i].mode;
if (jsem_ismouse (i, prefs) >= 0) {
switch (mode)
{
case JSEM_MODE_DEFAULT:
case JSEM_MODE_MOUSE:
default:
joymodes[i] = JSEM_MODE_MOUSE;
joyinputs[i] = i ? ip_mouse2 : ip_mouse1;
break;
case JSEM_MODE_LIGHTPEN:
joymodes[i] = JSEM_MODE_LIGHTPEN;
joyinputs[i] = i ? ip_lightpen2 : ip_lightpen1;
break;
case JSEM_MODE_MOUSE_CDTV:
joymodes[i] = JSEM_MODE_MOUSE_CDTV;
joyinputs[i] = ip_mousecdtv;
break;
}
} else if (jsem_isjoy (i, prefs) >= 0) {
switch (mode)
{
case JSEM_MODE_DEFAULT:
case JSEM_MODE_JOYSTICK:
case JSEM_MODE_GAMEPAD:
case JSEM_MODE_JOYSTICK_CD32:
default:
{
bool iscd32 = mode == JSEM_MODE_JOYSTICK_CD32 || (mode == JSEM_MODE_DEFAULT && prefs->cs_cd32cd);
if (iscd32) {
joymodes[i] = JSEM_MODE_JOYSTICK_CD32;
joyinputs[i] = i ? ip_joycd322 : ip_joycd321;
} else if (mode == JSEM_MODE_GAMEPAD) {
joymodes[i] = JSEM_MODE_GAMEPAD;
joyinputs[i] = i ? ip_joypad2 : ip_joypad1;
} else {
joymodes[i] = JSEM_MODE_JOYSTICK;
joyinputs[i] = i ? ip_joy2 : ip_joy1;
}
break;
}
case JSEM_MODE_JOYSTICK_ANALOG:
joymodes[i] = JSEM_MODE_JOYSTICK_ANALOG;
joyinputs[i] = i ? ip_analog2 : ip_analog1;
break;
case JSEM_MODE_MOUSE:
joymodes[i] = JSEM_MODE_MOUSE;
joyinputs[i] = i ? ip_mouse2 : ip_mouse1;
break;
case JSEM_MODE_LIGHTPEN:
joymodes[i] = JSEM_MODE_LIGHTPEN;
joyinputs[i] = i ? ip_lightpen2 : ip_lightpen1;
break;
case JSEM_MODE_MOUSE_CDTV:
joymodes[i] = JSEM_MODE_MOUSE_CDTV;
joyinputs[i] = ip_mousecdtv;
break;
}
} else if (prefs->jports[i].id >= 0) {
joymodes[i] = i ? JSEM_MODE_JOYSTICK : JSEM_MODE_MOUSE;
joyinputs[i] = i ? ip_joy2 : ip_mouse1;
}
}
}
for (i = 2; i < MAX_JPORTS; i++) {
if (prefs->jports[i].id >= 0 && joymodes[i] <= 0) {
int mode = prefs->jports[i].mode;
if (jsem_isjoy (i, prefs) >= 0) {
joymodes[i] = JSEM_MODE_JOYSTICK;
joyinputs[i] = i == 3 ? ip_parjoy2 : ip_parjoy1;
} else if (prefs->jports[i].id >= 0) {
prefs->jports[i].mode = joymodes[i] = JSEM_MODE_JOYSTICK;
joyinputs[i] = i == 3 ? ip_parjoy2 : ip_parjoy1;
}
}
}
for (i = 0; i < 2; i++) {
int af = prefs->jports[i].autofire;
if (prefs->jports[i].id >= 0) {
int mode = prefs->jports[i].mode;
if ((joy = jsem_ismouse (i, prefs)) >= 0) {
if (gameports)
cleardev (mice, joy);
switch (mode)
{
case JSEM_MODE_DEFAULT:
case JSEM_MODE_MOUSE:
default:
input_get_default_mouse (mice, joy, i, af);
joymodes[i] = JSEM_MODE_MOUSE;
break;
case JSEM_MODE_LIGHTPEN:
input_get_default_lightpen (mice, joy, i, af);
joymodes[i] = JSEM_MODE_LIGHTPEN;
break;
}
_tcsncpy (prefs->jports[i].name, idev[IDTYPE_MOUSE].get_friendlyname (joy), MAX_JPORTNAME - 1);
_tcsncpy (prefs->jports[i].configname, idev[IDTYPE_MOUSE].get_uniquename (joy), MAX_JPORTNAME - 1);
}
}
}
for (i = 1; i >= 0; i--) {
int af = prefs->jports[i].autofire;
if (prefs->jports[i].id >= 0) {
int mode = prefs->jports[i].mode;
joy = jsem_isjoy (i, prefs);
if (joy >= 0) {
if (gameports)
cleardev (joysticks, joy);
switch (mode)
{
case JSEM_MODE_DEFAULT:
case JSEM_MODE_JOYSTICK:
case JSEM_MODE_GAMEPAD:
case JSEM_MODE_JOYSTICK_CD32:
default:
{
bool iscd32 = mode == JSEM_MODE_JOYSTICK_CD32 || (mode == JSEM_MODE_DEFAULT && prefs->cs_cd32cd);
input_get_default_joystick (joysticks, joy, i, af, mode);
if (iscd32)
joymodes[i] = JSEM_MODE_JOYSTICK_CD32;
else if (mode == JSEM_MODE_GAMEPAD)
joymodes[i] = JSEM_MODE_GAMEPAD;
else
joymodes[i] = JSEM_MODE_JOYSTICK;
break;
}
case JSEM_MODE_JOYSTICK_ANALOG:
input_get_default_joystick_analog (joysticks, joy, i, af);
joymodes[i] = JSEM_MODE_JOYSTICK_ANALOG;
break;
case JSEM_MODE_MOUSE:
input_get_default_mouse (joysticks, joy, i, af);
joymodes[i] = JSEM_MODE_MOUSE;
break;
case JSEM_MODE_LIGHTPEN:
input_get_default_lightpen (joysticks, joy, i, af);
joymodes[i] = JSEM_MODE_LIGHTPEN;
break;
case JSEM_MODE_MOUSE_CDTV:
joymodes[i] = JSEM_MODE_MOUSE_CDTV;
input_get_default_joystick (joysticks, joy, i, af, mode);
break;
}
_tcsncpy (prefs->jports[i].name, idev[IDTYPE_JOYSTICK].get_friendlyname (joy), MAX_JPORTNAME - 1);
_tcsncpy (prefs->jports[i].configname, idev[IDTYPE_JOYSTICK].get_uniquename (joy), MAX_JPORTNAME - 1);
used[joy] = 1;
}
}
}
if (gameports) {
// replace possible old mappings with default keyboard mapping
for (i = KBR_DEFAULT_MAP_FIRST; i <= KBR_DEFAULT_MAP_LAST; i++) {
checkcompakb (keyboard_default_kbmaps[i], ip_joy2);
checkcompakb (keyboard_default_kbmaps[i], ip_joy1);
checkcompakb (keyboard_default_kbmaps[i], ip_joypad2);
checkcompakb (keyboard_default_kbmaps[i], ip_joypad1);
checkcompakb (keyboard_default_kbmaps[i], ip_parjoy2);
checkcompakb (keyboard_default_kbmaps[i], ip_parjoy1);
checkcompakb (keyboard_default_kbmaps[i], ip_mouse2);
checkcompakb (keyboard_default_kbmaps[i], ip_mouse1);
}
for (i = KBR_DEFAULT_MAP_CD32_FIRST; i <= KBR_DEFAULT_MAP_CD32_LAST; i++) {
checkcompakb (keyboard_default_kbmaps[i], ip_joycd321);
checkcompakb (keyboard_default_kbmaps[i], ip_joycd322);
}
}
for (i = 0; i < 2; i++) {
if (prefs->jports[i].id >= 0) {
int *kb = NULL;
int mode = prefs->jports[i].mode;
int af = prefs->jports[i].autofire;
for (joy = 0; used[joy]; joy++);
if (JSEM_ISANYKBD (i, prefs)) {
bool cd32 = mode == JSEM_MODE_JOYSTICK_CD32 || (mode == JSEM_MODE_DEFAULT && prefs->cs_cd32cd);
if (JSEM_ISNUMPAD (i, prefs)) {
if (cd32)
kb = keyboard_default_kbmaps[KBR_DEFAULT_MAP_CD32_NP];
else if (mode == JSEM_MODE_GAMEPAD)
kb = keyboard_default_kbmaps[KBR_DEFAULT_MAP_NP3];
else
kb = keyboard_default_kbmaps[KBR_DEFAULT_MAP_NP];
} else if (JSEM_ISCURSOR (i, prefs)) {
if (cd32)
kb = keyboard_default_kbmaps[KBR_DEFAULT_MAP_CD32_CK];
else if (mode == JSEM_MODE_GAMEPAD)
kb = keyboard_default_kbmaps[KBR_DEFAULT_MAP_CK3];
else
kb = keyboard_default_kbmaps[KBR_DEFAULT_MAP_CK];
} else if (JSEM_ISSOMEWHEREELSE (i, prefs)) {
if (cd32)
kb = keyboard_default_kbmaps[KBR_DEFAULT_MAP_CD32_SE];
else if (mode == JSEM_MODE_GAMEPAD)
kb = keyboard_default_kbmaps[KBR_DEFAULT_MAP_SE3];
else
kb = keyboard_default_kbmaps[KBR_DEFAULT_MAP_SE];
} else if (JSEM_ISXARCADE1 (i, prefs)) {
kb = keyboard_default_kbmaps[KBR_DEFAULT_MAP_XA1];
} else if (JSEM_ISXARCADE2 (i, prefs)) {
kb = keyboard_default_kbmaps[KBR_DEFAULT_MAP_XA2];
}
if (kb) {
switch (mode)
{
case JSEM_MODE_JOYSTICK:
case JSEM_MODE_GAMEPAD:
case JSEM_MODE_JOYSTICK_CD32:
case JSEM_MODE_DEFAULT:
if (cd32) {
setcompakb (kb, i ? ip_joycd322 : ip_joycd321, i, af);
joymodes[i] = JSEM_MODE_JOYSTICK_CD32;
} else if (mode == JSEM_MODE_GAMEPAD) {
setcompakb (kb, i ? ip_joypad2 : ip_joypad1, i, af);
joymodes[i] = JSEM_MODE_GAMEPAD;
} else {
setcompakb (kb, i ? ip_joy2 : ip_joy1, i, af);
joymodes[i] = JSEM_MODE_JOYSTICK;
}
break;
case JSEM_MODE_MOUSE:
setcompakb (kb, i ? ip_mouse2 : ip_mouse1, i, af);
joymodes[i] = JSEM_MODE_MOUSE;
break;
}
used[joy] = 1;
}
}
}
}
if (arcadia_bios) {
setcompakb (keyboard_default_kbmaps[KBR_DEFAULT_MAP_ARCADIA], ip_arcadia, 0, 0);
if (JSEM_ISXARCADE1 (i, prefs) || JSEM_ISXARCADE2 (i, prefs))
setcompakb (keyboard_default_kbmaps[KBR_DEFAULT_MAP_ARCADIA_XA], ip_arcadiaxa, JSEM_ISXARCADE2 (i, prefs) ? 1 : 0, prefs->jports[i].autofire);
}
if (0 && currprefs.cs_cdtvcd) {
setcompakb (keyboard_default_kbmaps[KBR_DEFAULT_MAP_CDTV], ip_mediacdtv, 0, 0);
}
// parport
for (i = 2; i < MAX_JPORTS; i++) {
int af = prefs->jports[i].autofire;
if (prefs->jports[i].id >= 0) {
int *kb = NULL;
joy = jsem_isjoy (i, prefs);
if (joy >= 0) {
if (gameports)
cleardev (joysticks, joy);
input_get_default_joystick (joysticks, joy, i, af, 0);
_tcsncpy (prefs->jports[i].name, idev[IDTYPE_JOYSTICK].get_friendlyname (joy), MAX_JPORTNAME - 1);
_tcsncpy (prefs->jports[i].configname, idev[IDTYPE_JOYSTICK].get_uniquename (joy), MAX_JPORTNAME - 1);
used[joy] = 1;
joymodes[i] = JSEM_MODE_JOYSTICK;
}
}
}
for (i = 2; i < MAX_JPORTS; i++) {
if (prefs->jports[i].id >= 0) {
int *kb = NULL;
for (joy = 0; used[joy]; joy++);
if (JSEM_ISANYKBD (i, prefs)) {
if (JSEM_ISNUMPAD (i, prefs))
kb = keyboard_default_kbmaps[KBR_DEFAULT_MAP_NP];
else if (JSEM_ISCURSOR (i, prefs))
kb = keyboard_default_kbmaps[KBR_DEFAULT_MAP_CK];
else if (JSEM_ISSOMEWHEREELSE (i, prefs))
kb = keyboard_default_kbmaps[KBR_DEFAULT_MAP_SE];
else if (JSEM_ISXARCADE1 (i, prefs))
kb = keyboard_default_kbmaps[KBR_DEFAULT_MAP_XA1];
else if (JSEM_ISXARCADE2 (i, prefs))
kb = keyboard_default_kbmaps[KBR_DEFAULT_MAP_XA2];
if (kb) {
setcompakb (kb, i == 3 ? ip_parjoy2default : ip_parjoy1default, i, prefs->jports[i].autofire);
used[joy] = 1;
joymodes[i] = JSEM_MODE_JOYSTICK;
}
}
}
}
for (i = 0; i < MAX_JPORTS; i++) {
if (gameports)
setautofires (prefs, i, prefs->jports[i].autofire);
}
for (i = 0; i < MAX_JPORTS; i++) {
setjoyinputs (prefs, i);
setjoydevices (prefs, gameports, i);
}
}
static void disableifempty2 (struct uae_input_device *uid)
{
for (int i = 0; i < MAX_INPUT_DEVICE_EVENTS; i++) {
for (int j = 0; j < MAX_INPUT_SUB_EVENT; j++) {
if (uid->eventid[i][j] > 0 || uid->custom[i][j] != NULL)
return;
}
}
uid->enabled = false;
}
static void disableifempty (struct uae_prefs *prefs)
{
for (int l = 0; l < MAX_INPUT_DEVICES; l++) {
disableifempty2 (&joysticks[l]);
disableifempty2 (&mice[l]);
disableifempty2 (&keyboards[l]);
}
prefs->internalevent_settings[0]->enabled = true;
}
static void matchdevices (struct inputdevice_functions *inf, struct uae_input_device *uid)
{
int i, j;
for (i = 0; i < inf->get_num (); i++) {
TCHAR *aname1 = inf->get_friendlyname (i);
TCHAR *aname2 = inf->get_uniquename (i);
int match = -1;
for (j = 0; j < MAX_INPUT_DEVICES; j++) {
if (aname2 && uid[j].configname) {
bool matched = false;
TCHAR bname[MAX_DPATH];
TCHAR bname2[MAX_DPATH];
TCHAR *p1 ,*p2;
_tcscpy (bname, uid[j].configname);
_tcscpy (bname2, aname2);
// strip possible local guid part
p1 = _tcschr (bname, '{');
p2 = _tcschr (bname2, '{');
if (!p1 && !p2) {
// check possible directinput names too
p1 = _tcschr (bname, ' ');
p2 = _tcschr (bname2, ' ');
}
if (!_tcscmp (bname, bname2)) {
matched = true;
} else if (p1 && p2 && p1 - bname == p2 - bname2) {
*p1 = 0;
*p2 = 0;
if (bname && !_tcscmp (bname2, bname))
matched = true;
}
if (matched) {
if (match >= 0)
match = -2;
else
match = j;
}
if (match == -2)
break;
}
}
// multiple matches -> use complete local-only id string for comparisons
if (match == -2) {
for (j = 0; j < MAX_INPUT_DEVICES; j++) {
TCHAR *bname2 = uid[j].configname;
if (aname2 && bname2 && !_tcscmp (aname2, bname2)) {
match = j;
break;
}
}
}
if (match < 0) {
// no match, try friend names
for (j = 0; j < MAX_INPUT_DEVICES; j++) {
TCHAR *bname1 = uid[j].name;
if (aname1 && bname1 && !_tcscmp (aname1, bname1)) {
match = j;
break;
}
}
}
if (match >= 0) {
j = match;
if (j != i) {
struct uae_input_device *tmp = xmalloc (struct uae_input_device, 1);
memcpy (tmp, &uid[j], sizeof (struct uae_input_device));
memcpy (&uid[j], &uid[i], sizeof (struct uae_input_device));
memcpy (&uid[i], tmp, sizeof (struct uae_input_device));
xfree (tmp);
}
}
}
for (i = 0; i < inf->get_num (); i++) {
if (uid[i].name == NULL)
uid[i].name = my_strdup (inf->get_friendlyname (i));
if (uid[i].configname == NULL)
uid[i].configname = my_strdup (inf->get_uniquename (i));
}
}
static void matchdevices_all (struct uae_prefs *prefs)
{
int i;
for (i = 0; i < MAX_INPUT_SETTINGS; i++) {
matchdevices (&idev[IDTYPE_MOUSE], prefs->mouse_settings[i]);
matchdevices (&idev[IDTYPE_JOYSTICK], prefs->joystick_settings[i]);
matchdevices (&idev[IDTYPE_KEYBOARD], prefs->keyboard_settings[i]);
}
}
bool inputdevice_set_gameports_mapping (struct uae_prefs *prefs, int devnum, int num, int evtnum, uae_u64 flags, int port)
{
TCHAR name[256];
struct inputevent *ie;
ie = inputdevice_get_eventinfo (evtnum);
if (!inputdevice_get_eventname (ie, name))
return false;
joysticks = prefs->joystick_settings[GAMEPORT_INPUT_SETTINGS];
mice = prefs->mouse_settings[GAMEPORT_INPUT_SETTINGS];
keyboards = prefs->keyboard_settings[GAMEPORT_INPUT_SETTINGS];
int sub = 0;
if (inputdevice_get_widget_type (devnum, num, NULL) != IDEV_WIDGET_KEY) {
for (sub = 0; sub < MAX_INPUT_SUB_EVENT; sub++) {
if (!inputdevice_get_mapping (devnum, num, NULL, NULL, NULL, NULL, sub))
break;
}
}
if (sub >= MAX_INPUT_SUB_EVENT)
sub = MAX_INPUT_SUB_EVENT - 1;
inputdevice_set_mapping (devnum, num, name, NULL, IDEV_MAPPED_GAMEPORTSCUSTOM1 | flags, port + 1, sub);
joysticks = prefs->joystick_settings[prefs->input_selected_setting];
mice = prefs->mouse_settings[prefs->input_selected_setting];
keyboards = prefs->keyboard_settings[prefs->input_selected_setting];
if (prefs->input_selected_setting != GAMEPORT_INPUT_SETTINGS) {
int xport;
uae_u64 xflags;
TCHAR xname[MAX_DPATH], xcustom[MAX_DPATH];
inputdevice_get_mapping (devnum, num, &xflags, &xport, xname, xcustom, 0);
if (xport == 0)
inputdevice_set_mapping (devnum, num, xname, xcustom, xflags, MAX_JPORTS + 1, SPARE_SUB_EVENT);
inputdevice_set_mapping (devnum, num, name, NULL, IDEV_MAPPED_GAMEPORTSCUSTOM1 | flags, port + 1, 0);
}
return true;
}
static void resetinput (void)
{
if ((input_play || input_record) && hsync_counter > 0)
return;
cd32_shifter[0] = cd32_shifter[1] = 8;
for (int i = 0; i < MAX_JPORTS; i++) {
oleft[i] = 0;
oright[i] = 0;
otop[i] = 0;
obot[i] = 0;
oldmx[i] = -1;
oldmy[i] = -1;
joybutton[i] = 0;
joydir[i] = 0;
mouse_deltanoreset[i][0] = 0;
mouse_delta[i][0] = 0;
mouse_deltanoreset[i][1] = 0;
mouse_delta[i][1] = 0;
mouse_deltanoreset[i][2] = 0;
mouse_delta[i][2] = 0;
}
memset (keybuf, 0, sizeof keybuf);
for (int i = 0; i < INPUT_QUEUE_SIZE; i++)
input_queue[i].linecnt = input_queue[i].nextlinecnt = -1;
for (int i = 0; i < MAX_INPUT_SUB_EVENT; i++) {
sublevdir[0][i] = i;
sublevdir[1][i] = MAX_INPUT_SUB_EVENT - i - 1;
}
}
void inputdevice_updateconfig_internal (struct uae_prefs *prefs)
{
int i;
keyboard_default = keyboard_default_table[currprefs.input_keyboard_type];
copyjport (&changed_prefs, &currprefs, 0);
copyjport (&changed_prefs, &currprefs, 1);
copyjport (&changed_prefs, &currprefs, 2);
copyjport (&changed_prefs, &currprefs, 3);
resetinput ();
joysticks = prefs->joystick_settings[prefs->input_selected_setting];
mice = prefs->mouse_settings[prefs->input_selected_setting];
keyboards = prefs->keyboard_settings[prefs->input_selected_setting];
internalevents = prefs->internalevent_settings[prefs->input_selected_setting];
matchdevices_all (prefs);
memset (joysticks2, 0, sizeof joysticks2);
memset (mice2, 0, sizeof mice2);
joysticks = prefs->joystick_settings[GAMEPORT_INPUT_SETTINGS];
mice = prefs->mouse_settings[GAMEPORT_INPUT_SETTINGS];
keyboards = prefs->keyboard_settings[GAMEPORT_INPUT_SETTINGS];
internalevents = prefs->internalevent_settings[GAMEPORT_INPUT_SETTINGS];
for (i = 0; i < MAX_INPUT_SETTINGS; i++) {
joysticks[i].enabled = 0;
mice[i].enabled = 0;
}
compatibility_copy (prefs, true);
joysticks = prefs->joystick_settings[prefs->input_selected_setting];
mice = prefs->mouse_settings[prefs->input_selected_setting];
keyboards = prefs->keyboard_settings[prefs->input_selected_setting];
internalevents = prefs->internalevent_settings[prefs->input_selected_setting];
if (prefs->input_selected_setting != GAMEPORT_INPUT_SETTINGS) {
compatibility_copy (prefs, false);
}
disableifempty (prefs);
scanevents (prefs);
}
void inputdevice_updateconfig (struct uae_prefs *prefs)
{
inputdevice_updateconfig_internal (prefs);
config_changed = 1;
#ifdef RETROPLATFORM
rp_input_change (0);
rp_input_change (1);
rp_input_change (2);
rp_input_change (3);
for (int i = 0; i < MAX_JPORTS; i++)
rp_update_gameport (i, -1, 0);
#endif
}
/* called when devices get inserted or removed
* store old devices temporarily, enumerate all devices
* restore old devices back (order may have changed)
*/
void inputdevice_devicechange (struct uae_prefs *prefs)
{
int acc = input_acquired;
int i, idx;
TCHAR *jports[MAX_JPORTS];
int jportskb[MAX_JPORTS], jportsmode[MAX_JPORTS];
for (i = 0; i < MAX_JPORTS; i++) {
jports[i] = NULL;
jportskb[i] = -1;
idx = inputdevice_getjoyportdevice (i, prefs->jports[i].id);
if (idx >= JSEM_LASTKBD) {
struct inputdevice_functions *idf;
int devidx;
idx -= JSEM_LASTKBD;
idf = getidf (idx);
devidx = inputdevice_get_device_index (idx);
jports[i] = my_strdup (idf->get_uniquename (devidx));
} else {
jportskb[i] = idx;
}
jportsmode[i] = prefs->jports[i].mode;
}
inputdevice_unacquire ();
idev[IDTYPE_JOYSTICK].close ();
idev[IDTYPE_MOUSE].close ();
idev[IDTYPE_KEYBOARD].close ();
idev[IDTYPE_JOYSTICK].init ();
idev[IDTYPE_MOUSE].init ();
idev[IDTYPE_KEYBOARD].init ();
matchdevices (&idev[IDTYPE_MOUSE], mice);
matchdevices (&idev[IDTYPE_JOYSTICK], joysticks);
matchdevices (&idev[IDTYPE_KEYBOARD], keyboards);
for (i = 0; i < MAX_JPORTS; i++) {
freejport (prefs, i);
if (jports[i]) {
inputdevice_joyport_config (prefs, jports[i], i, jportsmode[i], 2);
xfree (jports[i]);
} else if (jportskb[i] >= 0) {
TCHAR tmp[10];
_stprintf (tmp, _T("kbd%d"), jportskb[i]);
inputdevice_joyport_config (prefs, tmp, i, jportsmode[i], 0);
}
}
if (prefs == &changed_prefs)
inputdevice_copyconfig (&changed_prefs, &currprefs);
if (acc)
inputdevice_acquire (TRUE);
config_changed = 1;
}
// set default prefs to all input configuration settings
void inputdevice_default_prefs (struct uae_prefs *p)
{
inputdevice_init ();
p->input_selected_setting = GAMEPORT_INPUT_SETTINGS;
p->input_joymouse_multiplier = 100;
p->input_joymouse_deadzone = 33;
p->input_joystick_deadzone = 33;
p->input_joymouse_speed = 10;
p->input_analog_joystick_mult = 15;
p->input_analog_joystick_offset = -1;
p->input_mouse_speed = 100;
p->input_autofire_linecnt = 600;
p->input_keyboard_type = 0;
keyboard_default = keyboard_default_table[p->input_keyboard_type];
inputdevice_default_kb_all (p);
}
// set default keyboard and keyboard>joystick layouts
void inputdevice_setkeytranslation (struct uae_input_device_kbr_default **trans, int **kbmaps)
{
keyboard_default_table = trans;
keyboard_default_kbmaps = kbmaps;
}
// return true if keyboard/scancode pair is mapped
int inputdevice_iskeymapped (int keyboard, int scancode)
{
struct uae_input_device *na = &keyboards[keyboard];
if (!keyboards || scancode < 0)
return 0;
return scancodeused[keyboard][scancode];
}
int inputdevice_synccapslock (int oldcaps, int *capstable)
{
struct uae_input_device *na = &keyboards[0];
int j, i;
if (!keyboards)
return -1;
for (j = 0; na->extra[j]; j++) {
if (na->extra[j] == INPUTEVENT_KEY_CAPS_LOCK) {
for (i = 0; capstable[i]; i += 2) {
if (na->extra[j] == capstable[i]) {
if (oldcaps != capstable[i + 1]) {
oldcaps = capstable[i + 1];
inputdevice_translatekeycode (0, capstable[i], oldcaps ? -1 : 0);
}
return i;
}
}
}
}
return -1;
}
static void rqualifiers (uae_u64 flags, bool release)
{
uae_u64 mask = ID_FLAG_QUALIFIER1 << 1;
for (int i = 0; i < MAX_INPUT_QUALIFIERS; i++) {
if ((flags & mask) && (mask & (qualifiers << 1))) {
if (release) {
if (!(mask & qualifiers_r)) {
qualifiers_r |= mask;
for (int ii = 0; ii < MAX_INPUT_SUB_EVENT; ii++) {
int qevt = qualifiers_evt[i][ii];
if (qevt > 0) {
write_log (_T("Released %d '%s'\n"), qevt, events[qevt].name);
inputdevice_do_keyboard (events[qevt].data, 0);
}
}
}
} else {
if ((mask & qualifiers_r)) {
qualifiers_r &= ~mask;
for (int ii = 0; ii < MAX_INPUT_SUB_EVENT; ii++) {
int qevt = qualifiers_evt[i][ii];
if (qevt > 0) {
write_log (_T("Pressed %d '%s'\n"), qevt, events[qevt].name);
inputdevice_do_keyboard (events[qevt].data, 1);
}
}
}
}
}
mask <<= 2;
}
}
static int inputdevice_translatekeycode_2 (int keyboard, int scancode, int state, bool qualifiercheckonly)
{
struct uae_input_device *na = &keyboards[keyboard];
int j, k;
int handled = 0;
bool didcustom = false;
if (!keyboards || scancode < 0)
return handled;
// if (!state)
// process_custom_event (NULL, 0, 0, 0, 0, 0);
j = 0;
while (j < MAX_INPUT_DEVICE_EVENTS && na->extra[j] >= 0) {
if (na->extra[j] == scancode) {
bool qualonly;
uae_u64 qualmask[MAX_INPUT_SUB_EVENT];
getqualmask (qualmask, na, j, &qualonly);
if (qualonly)
qualifiercheckonly = true;
for (k = 0; k < MAX_INPUT_SUB_EVENT; k++) {/* send key release events in reverse order */
uae_u64 *flagsp = &na->flags[j][sublevdir[state == 0 ? 1 : 0][k]];
int evt = na->eventid[j][sublevdir[state == 0 ? 1 : 0][k]];
uae_u64 flags = *flagsp;
int autofire = (flags & ID_FLAG_AUTOFIRE) ? 1 : 0;
int toggle = (flags & ID_FLAG_TOGGLE) ? 1 : 0;
int inverttoggle = (flags & ID_FLAG_INVERTTOGGLE) ? 1 : 0;
int toggled;
setqualifiers (evt, state > 0);
if (qualifiercheckonly) {
if (!state && (flags & ID_FLAG_CANRELEASE)) {
*flagsp &= ~ID_FLAG_CANRELEASE;
handle_input_event (evt, state, 1, autofire, true, false);
if (k == 0) {
process_custom_event (na, j, state, qualmask, autofire, k);
}
}
continue;
}
if (!state) {
didcustom |= process_custom_event (na, j, state, qualmask, autofire, k);
}
// if evt == caps and scan == caps: sync with native caps led
if (evt == INPUTEVENT_KEY_CAPS_LOCK) {
int v;
if (state < 0)
state = 1;
v = target_checkcapslock (scancode, &state);
if (v < 0)
continue;
if (v > 0)
toggle = 0;
} else if (state < 0) {
// it was caps lock resync, ignore, not mapped to caps
continue;
}
if (inverttoggle) {
na->flags[j][sublevdir[state == 0 ? 1 : 0][k]] &= ~ID_FLAG_TOGGLED;
if (state) {
queue_input_event (evt, NULL, -1, 0, 0, 1);
handled |= handle_input_event (evt, 1, 1, 0, true, false);
} else {
handled |= handle_input_event (evt, 1, 1, autofire, true, false);
}
didcustom |= process_custom_event (na, j, state, qualmask, autofire, k);
} else if (toggle) {
if (!state)
continue;
if (!checkqualifiers (evt, flags, qualmask, na->eventid[j]))
continue;
*flagsp ^= ID_FLAG_TOGGLED;
toggled = (*flagsp & ID_FLAG_TOGGLED) ? 1 : 0;
handled |= handle_input_event (evt, toggled, 1, autofire, true, false);
if (k == 0)
didcustom |= process_custom_event (na, j, state, qualmask, autofire, k);
} else {
rqualifiers (flags, state ? true : false);
if (!checkqualifiers (evt, flags, qualmask, na->eventid[j])) {
if (!state && !(flags & ID_FLAG_CANRELEASE))
continue;
else if (state)
continue;
}
if (state) {
*flagsp |= ID_FLAG_CANRELEASE;
} else {
if (!(flags & ID_FLAG_CANRELEASE))
continue;
*flagsp &= ~ID_FLAG_CANRELEASE;
}
handled |= handle_input_event (evt, state, 1, autofire, true, false);
didcustom |= process_custom_event (na, j, state, qualmask, autofire, k);
}
}
if (!didcustom)
queue_input_event (-1, NULL, -1, 0, 0, 1);
return handled;
}
j++;
}
return handled;
}
#define IECODE_UP_PREFIX 0x80
#define RAW_STEALTH 0x68
#define STEALTHF_E0KEY 0x08
#define STEALTHF_UPSTROKE 0x04
#define STEALTHF_SPECIAL 0x02
#define STEALTHF_E1KEY 0x01
static void sendmmcodes (int code, int newstate)
{
uae_u8 b;
b = RAW_STEALTH | IECODE_UP_PREFIX;
record_key (((b << 1) | (b >> 7)) & 0xff);
b = IECODE_UP_PREFIX;
if ((code >> 8) == 0x01)
b |= STEALTHF_E0KEY;
if ((code >> 8) == 0x02)
b |= STEALTHF_E1KEY;
if (!newstate)
b |= STEALTHF_UPSTROKE;
record_key(((b << 1) | (b >> 7)) & 0xff);
b = ((code >> 4) & 0x0f) | IECODE_UP_PREFIX;
record_key(((b << 1) | (b >> 7)) & 0xff);
b = (code & 0x0f) | IECODE_UP_PREFIX;
record_key(((b << 1) | (b >> 7)) & 0xff);
}
// main keyboard press/release entry point
int inputdevice_translatekeycode (int keyboard, int scancode, int state)
{
if (inputdevice_translatekeycode_2 (keyboard, scancode, state, false))
return 1;
if (currprefs.mmkeyboard && scancode > 0)
sendmmcodes (scancode, state);
return 0;
}
void inputdevice_checkqualifierkeycode (int keyboard, int scancode, int state)
{
inputdevice_translatekeycode_2 (keyboard, scancode, state, true);
}
static const TCHAR *internaleventlabels[] = {
_T("CPU reset"),
_T("Keyboard reset"),
NULL
};
static int init_int (void)
{
return 1;
}
static void close_int (void)
{
}
static int acquire_int (int num, int flags)
{
return 1;
}
static void unacquire_int (int num)
{
}
static void read_int (void)
{
}
static int get_int_num (void)
{
return 1;
}
static TCHAR *get_int_friendlyname (int num)
{
return _T("Internal events");
}
static TCHAR *get_int_uniquename (int num)
{
return _T("INTERNALEVENTS1");
}
static int get_int_widget_num (int num)
{
int i;
for (i = 0; internaleventlabels[i]; i++);
return i;
}
static int get_int_widget_type (int kb, int num, TCHAR *name, uae_u32 *code)
{
if (code)
*code = num;
if (name)
_tcscpy (name, internaleventlabels[num]);
return IDEV_WIDGET_BUTTON;
}
static int get_int_widget_first (int kb, int type)
{
return 0;
}
static int get_int_flags (int num)
{
return 0;
}
static struct inputdevice_functions inputdevicefunc_internalevent = {
init_int, close_int, acquire_int, unacquire_int, read_int,
get_int_num, get_int_friendlyname, get_int_uniquename,
get_int_widget_num, get_int_widget_type,
get_int_widget_first,
get_int_flags
};
void send_internalevent (int eventid)
{
setbuttonstateall (&internalevents[0], NULL, eventid, -1);
}
void inputdevice_init (void)
{
idev[IDTYPE_JOYSTICK] = inputdevicefunc_joystick;
idev[IDTYPE_JOYSTICK].init ();
idev[IDTYPE_MOUSE] = inputdevicefunc_mouse;
idev[IDTYPE_MOUSE].init ();
idev[IDTYPE_KEYBOARD] = inputdevicefunc_keyboard;
idev[IDTYPE_KEYBOARD].init ();
idev[IDTYPE_INTERNALEVENT] = inputdevicefunc_internalevent;
idev[IDTYPE_INTERNALEVENT].init ();
}
void inputdevice_close (void)
{
idev[IDTYPE_JOYSTICK].close ();
idev[IDTYPE_MOUSE].close ();
idev[IDTYPE_KEYBOARD].close ();
idev[IDTYPE_INTERNALEVENT].close ();
inprec_close (true);
}
static struct uae_input_device *get_uid (const struct inputdevice_functions *id, int devnum)
{
struct uae_input_device *uid = 0;
if (id == &idev[IDTYPE_JOYSTICK]) {
uid = &joysticks[devnum];
} else if (id == &idev[IDTYPE_MOUSE]) {
uid = &mice[devnum];
} else if (id == &idev[IDTYPE_KEYBOARD]) {
uid = &keyboards[devnum];
} else if (id == &idev[IDTYPE_INTERNALEVENT]) {
uid = &internalevents[devnum];
}
return uid;
}
static int get_event_data (const struct inputdevice_functions *id, int devnum, int num, int *eventid, TCHAR **custom, uae_u64 *flags, int *port, int sub)
{
const struct uae_input_device *uid = get_uid (id, devnum);
int type = id->get_widget_type (devnum, num, 0, 0);
int i;
if (type == IDEV_WIDGET_BUTTON || type == IDEV_WIDGET_BUTTONAXIS) {
i = num - id->get_widget_first (devnum, IDEV_WIDGET_BUTTON) + ID_BUTTON_OFFSET;
*eventid = uid->eventid[i][sub];
if (flags)
*flags = uid->flags[i][sub];
if (port)
*port = uid->port[i][sub];
if (custom)
*custom = uid->custom[i][sub];
return i;
} else if (type == IDEV_WIDGET_AXIS) {
i = num - id->get_widget_first (devnum, type) + ID_AXIS_OFFSET;
*eventid = uid->eventid[i][sub];
if (flags)
*flags = uid->flags[i][sub];
if (port)
*port = uid->port[i][sub];
if (custom)
*custom = uid->custom[i][sub];
return i;
} else if (type == IDEV_WIDGET_KEY) {
i = num - id->get_widget_first (devnum, type);
*eventid = uid->eventid[i][sub];
if (flags)
*flags = uid->flags[i][sub];
if (port)
*port = uid->port[i][sub];
if (custom)
*custom = uid->custom[i][sub];
return i;
}
return -1;
}
static TCHAR *stripstrdup (const TCHAR *s)
{
TCHAR *out = my_strdup (s);
if (!out)
return NULL;
for (int i = 0; out[i]; i++) {
if (out[i] < ' ')
out[i] = ' ';
}
return out;
}
static int put_event_data (const struct inputdevice_functions *id, int devnum, int num, int eventid, TCHAR *custom, uae_u64 flags, int port, int sub)
{
struct uae_input_device *uid = get_uid (id, devnum);
int type = id->get_widget_type (devnum, num, 0, 0);
int i, ret;
for (i = 0; i < MAX_INPUT_QUALIFIERS; i++) {
uae_u64 mask1 = ID_FLAG_QUALIFIER1 << (i * 2);
uae_u64 mask2 = mask1 << 1;
if ((flags & (mask1 | mask2)) == (mask1 | mask2))
flags &= ~mask2;
}
if (custom && custom[0] == 0) {
custom = NULL;
eventid = 0;
}
if (eventid <= 0 && !custom) {
flags = 0;
}
ret = -1;
if (type == IDEV_WIDGET_BUTTON || type == IDEV_WIDGET_BUTTONAXIS) {
i = num - id->get_widget_first (devnum, IDEV_WIDGET_BUTTON) + ID_BUTTON_OFFSET;
uid->eventid[i][sub] = eventid;
uid->flags[i][sub] = flags;
uid->port[i][sub] = port;
xfree (uid->custom[i][sub]);
uid->custom[i][sub] = custom && _tcslen (custom) > 0 ? stripstrdup (custom) : NULL;
ret = i;
} else if (type == IDEV_WIDGET_AXIS) {
i = num - id->get_widget_first (devnum, type) + ID_AXIS_OFFSET;
uid->eventid[i][sub] = eventid;
uid->flags[i][sub] = flags;
uid->port[i][sub] = port;
xfree (uid->custom[i][sub]);
uid->custom[i][sub] = custom && _tcslen (custom) > 0 ? stripstrdup (custom) : NULL;
ret = i;
} else if (type == IDEV_WIDGET_KEY) {
i = num - id->get_widget_first (devnum, type);
uid->eventid[i][sub] = eventid;
uid->flags[i][sub] = flags;
uid->port[i][sub] = port;
xfree (uid->custom[i][sub]);
uid->custom[i][sub] = custom && _tcslen (custom) > 0 ? stripstrdup (custom) : NULL;
ret = i;
}
if (ret < 0)
return -1;
if (uid->custom[i][sub])
uid->eventid[i][sub] = INPUTEVENT_SPC_CUSTOM_EVENT;
return ret;
}
static int is_event_used (const struct inputdevice_functions *id, int devnum, int isnum, int isevent)
{
struct uae_input_device *uid = get_uid (id, devnum);
int num, evt, sub;
for (num = 0; num < id->get_widget_num (devnum); num++) {
for (sub = 0; sub < MAX_INPUT_SUB_EVENT; sub++) {
if (get_event_data (id, devnum, num, &evt, NULL, NULL, NULL, sub) >= 0) {
if (evt == isevent && isnum != num)
return 1;
}
}
}
return 0;
}
// device based index from global device index
int inputdevice_get_device_index (int devnum)
{
int jcnt = idev[IDTYPE_JOYSTICK].get_num ();
int mcnt = idev[IDTYPE_MOUSE].get_num ();
int kcnt = idev[IDTYPE_KEYBOARD].get_num ();
if (devnum < jcnt)
return devnum;
else if (devnum < jcnt + mcnt)
return devnum - jcnt;
else if (devnum < jcnt + mcnt + kcnt)
return devnum - (jcnt + mcnt);
else if (devnum < jcnt + mcnt + kcnt + INTERNALEVENT_COUNT)
return devnum - (jcnt + mcnt + kcnt);
return -1;
}
static int getdevnum (int type, int devnum)
{
int jcnt = idev[IDTYPE_JOYSTICK].get_num ();
int mcnt = idev[IDTYPE_MOUSE].get_num ();
int kcnt = idev[IDTYPE_KEYBOARD].get_num ();
if (type == IDTYPE_JOYSTICK)
return devnum;
else if (type == IDTYPE_MOUSE)
return jcnt + devnum;
else if (type == IDTYPE_KEYBOARD)
return jcnt + mcnt + devnum;
else if (type == IDTYPE_INTERNALEVENT)
return jcnt + mcnt + kcnt + devnum;
return -1;
}
static int gettype (int devnum)
{
int jcnt = idev[IDTYPE_JOYSTICK].get_num ();
int mcnt = idev[IDTYPE_MOUSE].get_num ();
int kcnt = idev[IDTYPE_KEYBOARD].get_num ();
if (devnum < jcnt)
return IDTYPE_JOYSTICK;
else if (devnum < jcnt + mcnt)
return IDTYPE_MOUSE;
else if (devnum < jcnt + mcnt + kcnt)
return IDTYPE_KEYBOARD;
else if (devnum < jcnt + mcnt + kcnt + INTERNALEVENT_COUNT)
return IDTYPE_INTERNALEVENT;
return -1;
}
static struct inputdevice_functions *getidf (int devnum)
{
int type = gettype (devnum);
if (type < 0)
return NULL;
return &idev[type];
}
struct inputevent *inputdevice_get_eventinfo (int evt)
{
return &events[evt];
}
/* returns number of devices of type "type" */
int inputdevice_get_device_total (int type)
{
return idev[type].get_num ();
}
/* returns the name of device */
TCHAR *inputdevice_get_device_name (int type, int devnum)
{
return idev[type].get_friendlyname (devnum);
}
/* returns the name of device */
TCHAR *inputdevice_get_device_name2 (int devnum)
{
return getidf (devnum)->get_friendlyname (inputdevice_get_device_index (devnum));
}
/* returns machine readable name of device */
TCHAR *inputdevice_get_device_unique_name (int type, int devnum)
{
return idev[type].get_uniquename (devnum);
}
/* returns state (enabled/disabled) */
int inputdevice_get_device_status (int devnum)
{
const struct inputdevice_functions *idf = getidf (devnum);
if (idf == NULL)
return -1;
struct uae_input_device *uid = get_uid (idf, inputdevice_get_device_index (devnum));
return uid->enabled;
}
/* set state (enabled/disabled) */
void inputdevice_set_device_status (int devnum, int enabled)
{
const struct inputdevice_functions *idf = getidf (devnum);
int num = inputdevice_get_device_index (devnum);
struct uae_input_device *uid = get_uid (idf, num);
if (enabled) { // disable incompatible devices ("super device" vs "raw device")
for (int i = 0; i < idf->get_num (); i++) {
if (idf->get_flags (i) != idf->get_flags (num)) {
struct uae_input_device *uid2 = get_uid (idf, i);
uid2->enabled = 0;
}
}
}
uid->enabled = enabled;
}
/* returns number of axis/buttons and keys from selected device */
int inputdevice_get_widget_num (int devnum)
{
const struct inputdevice_functions *idf = getidf (devnum);
return idf->get_widget_num (inputdevice_get_device_index (devnum));
}
// return name of event, do not use ie->name directly
bool inputdevice_get_eventname (const struct inputevent *ie, TCHAR *out)
{
if (!out)
return false;
_tcscpy (out, ie->name);
return true;
}
int inputdevice_iterate (int devnum, int num, TCHAR *name, int *af)
{
const struct inputdevice_functions *idf = getidf (devnum);
static int id_iterator;
struct inputevent *ie;
int mask, data, type;
uae_u64 flags;
int devindex = inputdevice_get_device_index (devnum);
*af = 0;
*name = 0;
for (;;) {
ie = &events[++id_iterator];
if (!ie->confname) {
id_iterator = 0;
return 0;
}
mask = 0;
type = idf->get_widget_type (devindex, num, NULL, NULL);
if (type == IDEV_WIDGET_BUTTON || type == IDEV_WIDGET_BUTTONAXIS) {
if (idf == &idev[IDTYPE_JOYSTICK]) {
mask |= AM_JOY_BUT;
} else {
mask |= AM_MOUSE_BUT;
}
} else if (type == IDEV_WIDGET_AXIS) {
if (idf == &idev[IDTYPE_JOYSTICK]) {
mask |= AM_JOY_AXIS;
} else {
mask |= AM_MOUSE_AXIS;
}
} else if (type == IDEV_WIDGET_KEY) {
mask |= AM_K;
}
if (ie->allow_mask & AM_INFO) {
struct inputevent *ie2 = ie + 1;
while (!(ie2->allow_mask & AM_INFO)) {
if (is_event_used (idf, devindex, ie2 - ie, -1)) {
ie2++;
continue;
}
if (ie2->allow_mask & mask)
break;
ie2++;
}
if (!(ie2->allow_mask & AM_INFO))
mask |= AM_INFO;
}
if (!(ie->allow_mask & mask))
continue;
get_event_data (idf, devindex, num, &data, NULL, &flags, NULL, 0);
inputdevice_get_eventname (ie, name);
*af = (flags & ID_FLAG_AUTOFIRE) ? 1 : 0;
return 1;
}
}
// return mapped event from devnum/num/sub
int inputdevice_get_mapping (int devnum, int num, uae_u64 *pflags, int *pport, TCHAR *name, TCHAR *custom, int sub)
{
const struct inputdevice_functions *idf = getidf (devnum);
const struct uae_input_device *uid = get_uid (idf, inputdevice_get_device_index (devnum));
int port, data;
uae_u64 flags = 0, flag;
int devindex = inputdevice_get_device_index (devnum);
TCHAR *customp = NULL;
if (name)
_tcscpy (name, _T("<none>"));
if (custom)
custom[0] = 0;
if (pflags)
*pflags = 0;
if (pport)
*pport = 0;
if (uid == 0 || num < 0)
return 0;
if (get_event_data (idf, devindex, num, &data, &customp, &flag, &port, sub) < 0)
return 0;
if (customp && custom)
_tcscpy (custom, customp);
if (flag & ID_FLAG_AUTOFIRE)
flags |= IDEV_MAPPED_AUTOFIRE_SET;
if (flag & ID_FLAG_TOGGLE)
flags |= IDEV_MAPPED_TOGGLE;
if (flag & ID_FLAG_INVERTTOGGLE)
flags |= IDEV_MAPPED_INVERTTOGGLE;
if (flag & ID_FLAG_GAMEPORTSCUSTOM1)
flags |= IDEV_MAPPED_GAMEPORTSCUSTOM1;
if (flag & ID_FLAG_GAMEPORTSCUSTOM2)
flags |= IDEV_MAPPED_GAMEPORTSCUSTOM2;
if (flag & ID_FLAG_QUALIFIER_MASK)
flags |= flag & ID_FLAG_QUALIFIER_MASK;
if (pflags)
*pflags = flags;
if (pport)
*pport = port;
if (!data)
return 0;
if (events[data].allow_mask & AM_AF)
flags |= IDEV_MAPPED_AUTOFIRE_POSSIBLE;
if (pflags)
*pflags = flags;
inputdevice_get_eventname (&events[data], name);
return data;
}
// set event name/custom/flags to devnum/num/sub
int inputdevice_set_mapping (int devnum, int num, const TCHAR *name, TCHAR *custom, uae_u64 flags, int port, int sub)
{
const struct inputdevice_functions *idf = getidf (devnum);
const struct uae_input_device *uid = get_uid (idf, inputdevice_get_device_index (devnum));
int eid, data, portp, amask;
uae_u64 flag;
TCHAR ename[256];
int devindex = inputdevice_get_device_index (devnum);
TCHAR *customp = NULL;
if (uid == 0 || num < 0)
return 0;
if (name) {
eid = 1;
while (events[eid].name) {
inputdevice_get_eventname (&events[eid], ename);
if (!_tcscmp(ename, name))
break;
eid++;
}
if (!events[eid].name)
return 0;
if (events[eid].allow_mask & AM_INFO)
return 0;
} else {
eid = 0;
}
if (get_event_data (idf, devindex, num, &data, &customp, &flag, &portp, sub) < 0)
return 0;
if (data >= 0) {
amask = events[eid].allow_mask;
flag &= ~(ID_FLAG_AUTOFIRE_MASK | ID_FLAG_GAMEPORTSCUSTOM_MASK | IDEV_MAPPED_QUALIFIER_MASK);
if (amask & AM_AF) {
flag |= (flags & IDEV_MAPPED_AUTOFIRE_SET) ? ID_FLAG_AUTOFIRE : 0;
flag |= (flags & IDEV_MAPPED_TOGGLE) ? ID_FLAG_TOGGLE : 0;
flag |= (flags & IDEV_MAPPED_INVERTTOGGLE) ? ID_FLAG_INVERTTOGGLE : 0;
}
flag |= (flags & IDEV_MAPPED_GAMEPORTSCUSTOM1) ? ID_FLAG_GAMEPORTSCUSTOM1 : 0;
flag |= (flags & IDEV_MAPPED_GAMEPORTSCUSTOM2) ? ID_FLAG_GAMEPORTSCUSTOM2 : 0;
flag |= flags & IDEV_MAPPED_QUALIFIER_MASK;
if (port >= 0)
portp = port;
put_event_data (idf, devindex, num, eid, custom, flag, portp, sub);
return 1;
}
return 0;
}
int inputdevice_get_widget_type (int devnum, int num, TCHAR *name)
{
const struct inputdevice_functions *idf = getidf (devnum);
return idf->get_widget_type (inputdevice_get_device_index (devnum), num, name, 0);
}
static int config_change;
void inputdevice_config_change (void)
{
config_change = 1;
}
int inputdevice_config_change_test (void)
{
int v = config_change;
config_change = 0;
return v;
}
// copy configuration #src to configuration #dst
void inputdevice_copyconfig (const struct uae_prefs *src, struct uae_prefs *dst)
{
int i, j;
dst->input_selected_setting = src->input_selected_setting;
dst->input_joymouse_multiplier = src->input_joymouse_multiplier;
dst->input_joymouse_deadzone = src->input_joymouse_deadzone;
dst->input_joystick_deadzone = src->input_joystick_deadzone;
dst->input_joymouse_speed = src->input_joymouse_speed;
dst->input_mouse_speed = src->input_mouse_speed;
dst->input_autofire_linecnt = src->input_autofire_linecnt;
copyjport (src, dst, 0);
copyjport (src, dst, 1);
copyjport (src, dst, 2);
copyjport (src, dst, 3);
for (i = 0; i < MAX_INPUT_SETTINGS; i++) {
for (j = 0; j < MAX_INPUT_DEVICES; j++) {
memcpy (&dst->joystick_settings[i][j], &src->joystick_settings[i][j], sizeof (struct uae_input_device));
memcpy (&dst->mouse_settings[i][j], &src->mouse_settings[i][j], sizeof (struct uae_input_device));
memcpy (&dst->keyboard_settings[i][j], &src->keyboard_settings[i][j], sizeof (struct uae_input_device));
}
}
inputdevice_updateconfig (dst);
}
static void swapjoydevice (struct uae_input_device *uid, int **swaps)
{
for (int i = 0; i < MAX_INPUT_DEVICE_EVENTS; i++) {
for (int j = 0; j < MAX_INPUT_SUB_EVENT; j++) {
bool found = false;
for (int k = 0; k < 2 && !found; k++) {
int evtnum;
for (int kk = 0; (evtnum = swaps[k][kk]) >= 0 && !found; kk++) {
if (uid->eventid[i][j] == evtnum) {
uid->eventid[i][j] = swaps[1 - k][kk];
found = true;
} else {
for (int jj = 0; axistable[jj] >= 0; jj += 3) {
if (evtnum == axistable[jj] || evtnum == axistable[jj + 1] || evtnum == axistable[jj + 2]) {
for (int ii = 0; ii < 3; ii++) {
if (uid->eventid[i][j] == axistable[jj + ii]) {
int evtnum2 = swaps[1 - k][kk];
for (int m = 0; axistable[m] >= 0; m += 3) {
if (evtnum2 == axistable[m] || evtnum2 == axistable[m + 1] || evtnum2 == axistable[m + 2]) {
uid->eventid[i][j] = axistable[m + ii];
found = true;
}
}
}
}
}
}
}
}
}
}
}
}
// swap gameports ports, remember to handle customized ports too
void inputdevice_swap_compa_ports (struct uae_prefs *prefs, int portswap)
{
struct jport tmp;
if ((prefs->jports[portswap].id == JPORT_CUSTOM || prefs->jports[portswap + 1].id == JPORT_CUSTOM)) {
int *swaps[2];
swaps[0] = rem_ports[portswap];
swaps[1] = rem_ports[portswap + 1];
for (int l = 0; l < MAX_INPUT_DEVICES; l++) {
swapjoydevice (&prefs->joystick_settings[GAMEPORT_INPUT_SETTINGS][l], swaps);
swapjoydevice (&prefs->mouse_settings[GAMEPORT_INPUT_SETTINGS][l], swaps);
swapjoydevice (&prefs->keyboard_settings[GAMEPORT_INPUT_SETTINGS][l], swaps);
}
}
memcpy (&tmp, &prefs->jports[portswap], sizeof (struct jport));
memcpy (&prefs->jports[portswap], &prefs->jports[portswap + 1], sizeof (struct jport));
memcpy (&prefs->jports[portswap + 1], &tmp, sizeof (struct jport));
inputdevice_updateconfig (prefs);
}
// swap device "devnum" ports 0<>1 and 2<>3
void inputdevice_swap_ports (struct uae_prefs *p, int devnum)
{
const struct inputdevice_functions *idf = getidf (devnum);
struct uae_input_device *uid = get_uid (idf, inputdevice_get_device_index (devnum));
int i, j, k, event, unit;
const struct inputevent *ie, *ie2;
for (i = 0; i < MAX_INPUT_DEVICE_EVENTS; i++) {
for (j = 0; j < MAX_INPUT_SUB_EVENT; j++) {
event = uid->eventid[i][j];
if (event <= 0)
continue;
ie = &events[event];
if (ie->unit <= 0)
continue;
unit = ie->unit;
k = 1;
while (events[k].confname) {
ie2 = &events[k];
if (ie2->type == ie->type && ie2->data == ie->data && ie2->unit - 1 == ((ie->unit - 1) ^ 1) &&
ie2->allow_mask == ie->allow_mask && uid->port[i][j] == 0) {
uid->eventid[i][j] = k;
break;
}
k++;
}
}
}
}
//memcpy (p->joystick_settings[dst], p->joystick_settings[src], sizeof (struct uae_input_device) * MAX_INPUT_DEVICES);
static void copydev (struct uae_input_device *dst, struct uae_input_device *src, int selectedwidget)
{
for (int i = 0; i < MAX_INPUT_DEVICES; i++) {
for (int j = 0; j < MAX_INPUT_DEVICE_EVENTS; j++) {
if (j == selectedwidget || selectedwidget < 0) {
for (int k = 0; k < MAX_INPUT_SUB_EVENT_ALL; k++) {
xfree (dst[i].custom[j][k]);
}
}
}
if (selectedwidget < 0) {
xfree (dst[i].configname);
xfree (dst[i].name);
}
}
if (selectedwidget < 0) {
memcpy (dst, src, sizeof (struct uae_input_device) * MAX_INPUT_DEVICES);
} else {
int j = selectedwidget;
for (int i = 0; i < MAX_INPUT_DEVICES; i++) {
for (int k = 0; k < MAX_INPUT_SUB_EVENT_ALL; k++) {
dst[i].eventid[j][k] = src[i].eventid[j][k];
dst[i].custom[j][k] = src[i].custom[j][k];
dst[i].flags[j][k] = src[i].flags[j][k];
dst[i].port[j][k] = src[i].port[j][k];
}
dst[i].extra[j] = src[i].extra[j];
}
}
for (int i = 0; i < MAX_INPUT_DEVICES; i++) {
for (int j = 0; j < MAX_INPUT_DEVICE_EVENTS; j++) {
if (j == selectedwidget || selectedwidget < 0) {
for (int k = 0; k < MAX_INPUT_SUB_EVENT_ALL; k++) {
if (dst[i].custom)
dst[i].custom[j][k] = my_strdup (dst[i].custom[j][k]);
}
}
}
if (selectedwidget < 0) {
dst[i].configname = my_strdup (dst[i].configname);
dst[i].name = my_strdup (dst[i].name);
}
}
}
// copy whole configuration #x-slot to another
// +1 = default
// +2 = default (pc keyboard)
void inputdevice_copy_single_config (struct uae_prefs *p, int src, int dst, int devnum, int selectedwidget)
{
if (selectedwidget >= 0) {
if (devnum < 0)
return;
if (gettype (devnum) != IDTYPE_KEYBOARD)
return;
}
if (src >= MAX_INPUT_SETTINGS) {
if (gettype (devnum) == IDTYPE_KEYBOARD) {
p->input_keyboard_type = src > MAX_INPUT_SETTINGS ? 1 : 0;
keyboard_default = keyboard_default_table[p->input_keyboard_type];
inputdevice_default_kb (p, dst);
}
}
if (src == dst)
return;
if (src < MAX_INPUT_SETTINGS) {
if (devnum < 0 || gettype (devnum) == IDTYPE_JOYSTICK)
copydev (p->joystick_settings[dst], p->joystick_settings[src], selectedwidget);
if (devnum < 0 || gettype (devnum) == IDTYPE_MOUSE)
copydev (p->mouse_settings[dst], p->mouse_settings[src], selectedwidget);
if (devnum < 0 || gettype (devnum) == IDTYPE_KEYBOARD)
copydev (p->keyboard_settings[dst], p->keyboard_settings[src], selectedwidget);
}
}
void inputdevice_acquire (int allmode)
{
int i;
for (i = 0; i < MAX_INPUT_DEVICES; i++)
idev[IDTYPE_JOYSTICK].unacquire (i);
for (i = 0; i < MAX_INPUT_DEVICES; i++)
idev[IDTYPE_MOUSE].unacquire (i);
for (i = 0; i < MAX_INPUT_DEVICES; i++)
idev[IDTYPE_KEYBOARD].unacquire (i);
for (i = 0; i < MAX_INPUT_DEVICES; i++) {
if ((use_joysticks[i] && allmode >= 0) || (allmode && !idev[IDTYPE_JOYSTICK].get_flags (i)))
idev[IDTYPE_JOYSTICK].acquire (i, 0);
}
for (i = 0; i < MAX_INPUT_DEVICES; i++) {
if ((use_mice[i] && allmode >= 0) || (allmode && !idev[IDTYPE_MOUSE].get_flags (i)))
idev[IDTYPE_MOUSE].acquire (i, allmode < 0);
}
for (i = 0; i < MAX_INPUT_DEVICES; i++) {
if ((use_keyboards[i] && allmode >= 0) || (allmode < 0 && !idev[IDTYPE_KEYBOARD].get_flags (i)))
idev[IDTYPE_KEYBOARD].acquire (i, allmode < 0);
}
if (input_acquired)
return;
idev[IDTYPE_JOYSTICK].acquire (-1, 0);
idev[IDTYPE_MOUSE].acquire (-1, 0);
idev[IDTYPE_KEYBOARD].acquire (-1, 0);
// if (!input_acquired)
// write_log (_T("input devices acquired (%s)\n"), allmode ? "all" : "selected only");
input_acquired = 1;
}
void inputdevice_unacquire (void)
{
int i;
for (i = 0; i < MAX_INPUT_DEVICES; i++)
idev[IDTYPE_JOYSTICK].unacquire (i);
for (i = 0; i < MAX_INPUT_DEVICES; i++)
idev[IDTYPE_MOUSE].unacquire (i);
for (i = 0; i < MAX_INPUT_DEVICES; i++)
idev[IDTYPE_KEYBOARD].unacquire (i);
if (!input_acquired)
return;
input_acquired = 0;
idev[IDTYPE_JOYSTICK].unacquire (-1);
idev[IDTYPE_MOUSE].unacquire (-1);
idev[IDTYPE_KEYBOARD].unacquire (-1);
}
void inputdevice_testrecord (int type, int num, int wtype, int wnum, int state)
{
if (wnum < 0) {
testmode = -1;
return;
}
if (testmode_count >= TESTMODE_MAX)
return;
if (type == IDTYPE_KEYBOARD) {
if (wnum == 0x100) {
wnum = -1;
} else {
struct uae_input_device *na = &keyboards[num];
int j = 0;
while (j < MAX_INPUT_DEVICE_EVENTS && na->extra[j] >= 0) {
if (na->extra[j] == wnum) {
wnum = j;
break;
}
j++;
}
if (j >= MAX_INPUT_DEVICE_EVENTS || na->extra[j] < 0)
type = -1;
}
}
// wait until previous event is released before accepting new ones
for (int i = 0; i < TESTMODE_MAX; i++) {
struct teststore *ts2 = &testmode_wait[i];
if (ts2->testmode_num < 0)
continue;
if (ts2->testmode_num != num || ts2->testmode_type != type || ts2->testmode_wtype != wtype || ts2->testmode_wnum != wnum)
continue;
if (state)
continue;
ts2->testmode_num = -1;
}
if (!state)
return;
//write_log (_T("%d %d %d %d %d\n"), type, num, wtype, wnum, state);
struct teststore *ts = &testmode_data[testmode_count];
ts->testmode_type = type;
ts->testmode_num = num;
ts->testmode_wtype = wtype;
ts->testmode_wnum = wnum;
ts->testmode_state = state;
testmode_count++;
}
int inputdevice_istest (void)
{
return testmode;
}
void inputdevice_settest (int set)
{
testmode = set;
testmode_count = 0;
testmode_wait[0].testmode_num = -1;
testmode_wait[1].testmode_num = -1;
}
int inputdevice_testread_count (void)
{
inputdevice_read ();
if (testmode != 1) {
testmode = 0;
return -1;
}
return testmode_count;
}
int inputdevice_testread (int *devnum, int *wtype, int *state)
{
inputdevice_read ();
if (testmode != 1) {
testmode = 0;
return -1;
}
if (testmode_count > 0) {
testmode_count--;
struct teststore *ts = &testmode_data[testmode_count];
*devnum = getdevnum (ts->testmode_type, ts->testmode_num);
*wtype = idev[ts->testmode_type].get_widget_first (ts->testmode_num, ts->testmode_wtype) + ts->testmode_wnum;
*state = ts->testmode_state;
if (ts->testmode_state)
memcpy (&testmode_wait[testmode_count], ts, sizeof (struct teststore));
return 1;
}
return 0;
}
/* Call this function when host machine's joystick/joypad/etc button state changes
* This function translates button events to Amiga joybutton/joyaxis/keyboard events
*/
/* button states:
* state = -1 -> mouse wheel turned or similar (button without release)
* state = 1 -> button pressed
* state = 0 -> button released
*/
void setjoybuttonstate (int joy, int button, int state)
{
if (testmode) {
inputdevice_testrecord (IDTYPE_JOYSTICK, joy, IDEV_WIDGET_BUTTON, button, state);
if (state < 0)
inputdevice_testrecord (IDTYPE_JOYSTICK, joy, IDEV_WIDGET_BUTTON, button, 0);
return;
}
#if 0
if (ignoreoldinput (joy)) {
if (state)
switchdevice (&joysticks[joy], button, 1);
return;
}
#endif
setbuttonstateall (&joysticks[joy], &joysticks2[joy], button, state ? 1 : 0);
}
/* buttonmask = 1 = normal toggle button, 0 = mouse wheel turn or similar
*/
void setjoybuttonstateall (int joy, uae_u32 buttonbits, uae_u32 buttonmask)
{
int i;
#if 0
if (ignoreoldinput (joy))
return;
#endif
for (i = 0; i < ID_BUTTON_TOTAL; i++) {
if (buttonmask & (1 << i))
setbuttonstateall (&joysticks[joy], &joysticks2[joy], i, (buttonbits & (1 << i)) ? 1 : 0);
else if (buttonbits & (1 << i))
setbuttonstateall (&joysticks[joy], &joysticks2[joy], i, -1);
}
}
/* mouse buttons (just like joystick buttons)
*/
void setmousebuttonstateall (int mouse, uae_u32 buttonbits, uae_u32 buttonmask)
{
int i;
for (i = 0; i < ID_BUTTON_TOTAL; i++) {
if (buttonmask & (1 << i))
setbuttonstateall (&mice[mouse], &mice2[mouse], i, (buttonbits & (1 << i)) ? 1 : 0);
else if (buttonbits & (1 << i))
setbuttonstateall (&mice[mouse], &mice2[mouse], i, -1);
}
}
void setmousebuttonstate (int mouse, int button, int state)
{
if (testmode) {
inputdevice_testrecord (IDTYPE_MOUSE, mouse, IDEV_WIDGET_BUTTON, button, state);
return;
}
setbuttonstateall (&mice[mouse], &mice2[mouse], button, state);
}
/* same for joystick axis (analog or digital)
* (0 = center, -max = full left/top, max = full right/bottom)
*/
void setjoystickstate (int joy, int axis, int state, int max)
{
struct uae_input_device *id = &joysticks[joy];
struct uae_input_device2 *id2 = &joysticks2[joy];
int deadzone = currprefs.input_joymouse_deadzone * max / 100;
int i, v1, v2;
if (testmode) {
inputdevice_testrecord (IDTYPE_JOYSTICK, joy, IDEV_WIDGET_AXIS, axis, state);
return;
}
v1 = state;
v2 = id2->states[axis];
if (v1 < deadzone && v1 > -deadzone)
v1 = 0;
if (v2 < deadzone && v2 > -deadzone)
v2 = 0;
if (v1 == v2)
return;
if (input_play && state)
inprec_realtime ();
if (input_play)
return;
if (!joysticks[joy].enabled) {
if (v1)
switchdevice (&joysticks[joy], axis * 2 + (v1 < 0 ? 0 : 1), false);
return;
}
for (i = 0; i < MAX_INPUT_SUB_EVENT; i++)
handle_input_event (id->eventid[ID_AXIS_OFFSET + axis][i], state, max, id->flags[ID_AXIS_OFFSET + axis][i] & ID_FLAG_AUTOFIRE, true, false);
id2->states[axis] = state;
}
int getjoystickstate (int joy)
{
if (testmode)
return 1;
return joysticks[joy].enabled;
}
void setmousestate (int mouse, int axis, int data, int isabs)
{
int i, v, diff;
int *mouse_p, *oldm_p;
double d;
struct uae_input_device *id = &mice[mouse];
static double fract[MAX_INPUT_DEVICES][MAX_INPUT_DEVICE_EVENTS];
if (testmode) {
inputdevice_testrecord (IDTYPE_MOUSE, mouse, IDEV_WIDGET_AXIS, axis, data);
// fake "release" event
inputdevice_testrecord (IDTYPE_MOUSE, mouse, IDEV_WIDGET_AXIS, axis, 0);
return;
}
if (input_play)
return;
if (!mice[mouse].enabled) {
if (isabs && currprefs.input_tablet > 0) {
if (axis == 0)
lastmx = data;
else
lastmy = data;
if (axis)
mousehack_helper ();
}
return;
}
d = 0;
mouse_p = &mouse_axis[mouse][axis];
oldm_p = &oldm_axis[mouse][axis];
if (!isabs) {
// eat relative movements while in mousehack mode
if (currprefs.input_tablet == TABLET_MOUSEHACK && mousehack_alive ())
return;
*oldm_p = *mouse_p;
*mouse_p += data;
d = (*mouse_p - *oldm_p) * currprefs.input_mouse_speed / 100.0;
} else {
d = data - *oldm_p;
*oldm_p = data;
*mouse_p += d;
if (axis == 0)
lastmx = data;
else
lastmy = data;
if (axis)
mousehack_helper ();
if (currprefs.input_tablet == TABLET_MOUSEHACK && mousehack_alive ())
return;
}
v = (int)d;
fract[mouse][axis] += d - v;
diff = (int)fract[mouse][axis];
v += diff;
fract[mouse][axis] -= diff;
for (i = 0; i < MAX_INPUT_SUB_EVENT; i++)
handle_input_event (id->eventid[ID_AXIS_OFFSET + axis][i], v, 0, 0, true, false);
}
int getmousestate (int joy)
{
if (testmode)
return 1;
return mice[joy].enabled;
}
void warpmode (int mode)
{
int fr, fr2;
fr = currprefs.gfx_framerate;
if (fr == 0)
fr = -1;
fr2 = currprefs.turbo_emulation;
if (fr2 == -1)
fr2 = 0;
if (mode < 0) {
if (currprefs.turbo_emulation) {
changed_prefs.gfx_framerate = currprefs.gfx_framerate = fr2;
currprefs.turbo_emulation = 0;
} else {
currprefs.turbo_emulation = fr;
}
} else if (mode == 0 && currprefs.turbo_emulation) {
if (currprefs.turbo_emulation > 0)
changed_prefs.gfx_framerate = currprefs.gfx_framerate = fr2;
currprefs.turbo_emulation = 0;
} else if (mode > 0 && !currprefs.turbo_emulation) {
currprefs.turbo_emulation = fr;
}
if (currprefs.turbo_emulation) {
if (!currprefs.cpu_cycle_exact && !currprefs.blitter_cycle_exact)
changed_prefs.gfx_framerate = currprefs.gfx_framerate = 10;
pause_sound ();
} else {
resume_sound ();
}
compute_vsynctime ();
#ifdef RETROPLATFORM
rp_turbo_cpu (currprefs.turbo_emulation);
#endif
changed_prefs.turbo_emulation = currprefs.turbo_emulation;
config_changed = 1;
setsystime ();
}
void pausemode (int mode)
{
if (mode < 0)
pause_emulation = pause_emulation ? 0 : 9;
else
pause_emulation = mode;
config_changed = 1;
setsystime ();
}
int jsem_isjoy (int port, const struct uae_prefs *p)
{
int v = JSEM_DECODEVAL (port, p);
if (v < JSEM_JOYS)
return -1;
v -= JSEM_JOYS;
if (v >= inputdevice_get_device_total (IDTYPE_JOYSTICK))
return -1;
return v;
}
int jsem_ismouse (int port, const struct uae_prefs *p)
{
int v = JSEM_DECODEVAL (port, p);
if (v < JSEM_MICE)
return -1;
v -= JSEM_MICE;
if (v >= inputdevice_get_device_total (IDTYPE_MOUSE))
return -1;
return v;
}
int jsem_iskbdjoy (int port, const struct uae_prefs *p)
{
int v = JSEM_DECODEVAL (port, p);
if (v < JSEM_KBDLAYOUT)
return -1;
v -= JSEM_KBDLAYOUT;
if (v >= JSEM_LASTKBD)
return -1;
return v;
}
int inputdevice_joyport_config (struct uae_prefs *p, const TCHAR *value, int portnum, int mode, int type)
{
switch (type)
{
case 1:
case 2:
{
int i, j;
for (j = 0; j < MAX_JPORTS; j++) {
struct inputdevice_functions *idf;
int type = IDTYPE_MOUSE;
int idnum = JSEM_MICE;
if (j > 0) {
type = IDTYPE_JOYSTICK;
idnum = JSEM_JOYS;
}
idf = &idev[type];
for (i = 0; i < idf->get_num (); i++) {
TCHAR *name1 = idf->get_friendlyname (i);
TCHAR *name2 = idf->get_uniquename (i);
if ((name1 && !_tcscmp (name1, value)) || (name2 && !_tcscmp (name2, value))) {
p->jports[portnum].id = idnum + i;
if (mode >= 0)
p->jports[portnum].mode = mode;
config_changed = 1;
return 1;
}
}
}
}
break;
case 0:
{
int start = JPORT_NONE, got = 0, max = -1;
const TCHAR *pp = 0;
if (_tcsncmp (value, _T("kbd"), 3) == 0) {
start = JSEM_KBDLAYOUT;
pp = value + 3;
got = 1;
max = JSEM_LASTKBD;
} else if (_tcsncmp (value, _T("joy"), 3) == 0) {
start = JSEM_JOYS;
pp = value + 3;
got = 1;
max = idev[IDTYPE_JOYSTICK].get_num ();
} else if (_tcsncmp (value, _T("mouse"), 5) == 0) {
start = JSEM_MICE;
pp = value + 5;
got = 1;
max = idev[IDTYPE_MOUSE].get_num ();
} else if (_tcscmp (value, _T("none")) == 0) {
got = 2;
} else if (_tcscmp (value, _T("custom")) == 0) {
got = 2;
start = JPORT_CUSTOM;
}
if (got) {
if (pp && max != 0) {
int v = _tstol (pp);
if (start >= 0) {
if (start == JSEM_KBDLAYOUT && v > 0)
v--;
if (v >= 0) {
if (v >= max)
v = 0;
start += v;
got = 2;
}
}
}
if (got == 2) {
p->jports[portnum].id = start;
if (mode >= 0)
p->jports[portnum].mode = mode;
config_changed = 1;
return 1;
}
}
}
break;
}
return 0;
}
int inputdevice_getjoyportdevice (int port, int val)
{
int idx;
if (val == JPORT_CUSTOM) {
idx = inputdevice_get_device_total (IDTYPE_JOYSTICK) + JSEM_LASTKBD;
if (port < 2)
idx += inputdevice_get_device_total (IDTYPE_MOUSE);
} else if (val < 0) {
idx = -1;
} else if (val >= JSEM_MICE) {
idx = val - JSEM_MICE;
if (idx >= inputdevice_get_device_total (IDTYPE_MOUSE))
idx = 0;
else
idx += inputdevice_get_device_total (IDTYPE_JOYSTICK);
idx += JSEM_LASTKBD;
} else if (val >= JSEM_JOYS) {
idx = val - JSEM_JOYS;
if (idx >= inputdevice_get_device_total (IDTYPE_JOYSTICK))
idx = 0;
idx += JSEM_LASTKBD;
} else {
idx = val - JSEM_KBDLAYOUT;
}
return idx;
}
// for state recorder use only!
uae_u8 *save_inputstate (int *len, uae_u8 *dstptr)
{
uae_u8 *dstbak, *dst;
if (dstptr)
dstbak = dst = dstptr;
else
dstbak = dst = xmalloc (uae_u8, 1000);
for (int i = 0; i < MAX_JPORTS; i++) {
save_u16 (joydir[i]);
save_u16 (joybutton[i]);
save_u16 (otop[i]);
save_u16 (obot[i]);
save_u16 (oleft[i]);
save_u16 (oright[i]);
}
for (int i = 0; i < NORMAL_JPORTS; i++) {
save_u16 (cd32_shifter[i]);
for (int j = 0; j < 2; j++) {
save_u16 (pot_cap[i][j]);
save_u16 (joydirpot[i][j]);
}
}
for (int i = 0; i < NORMAL_JPORTS; i++) {
for (int j = 0; j < MOUSE_AXIS_TOTAL; j++) {
save_u16 (mouse_delta[i][j]);
save_u16 (mouse_deltanoreset[i][j]);
}
save_u16 (mouse_frame_x[i]);
save_u16 (mouse_frame_y[i]);
}
*len = dst - dstbak;
return dstbak;
}
uae_u8 *restore_inputstate (uae_u8 *src)
{
for (int i = 0; i < MAX_JPORTS; i++) {
joydir[i] = restore_u16 ();
joybutton[i] = restore_u16 ();
otop[i] = restore_u16 ();
obot[i] = restore_u16 ();
oleft[i] = restore_u16 ();
oright[i] = restore_u16 ();
}
for (int i = 0; i < NORMAL_JPORTS; i++) {
cd32_shifter[i] = restore_u16 ();
for (int j = 0; j < 2; j++) {
pot_cap[i][j] = restore_u16 ();
joydirpot[i][j] = restore_u16 ();
}
}
for (int i = 0; i < NORMAL_JPORTS; i++) {
for (int j = 0; j < MOUSE_AXIS_TOTAL; j++) {
mouse_delta[i][j] = restore_u16 ();
mouse_deltanoreset[i][j] = restore_u16 ();
}
mouse_frame_x[i] = restore_u16 ();
mouse_frame_y[i] = restore_u16 ();
}
return src;
}
void clear_inputstate (void)
{
return;
for (int i = 0; i < MAX_JPORTS; i++) {
horizclear[i] = 1;
vertclear[i] = 1;
}
}