- Split the joystick menu into two parts: A top level with general options

and a list of all attached controllers, and a second level for configuring
  an individual controller.
- Fixed: Pressing Up at the top of a menu with more lines than fit on screen
  would find an incorrect bottom position if the menu had a custom top height.
- Added the cvars joy_dinput, joy_ps2raw, and joy_xinput to enable/disable
  specific game controller input systems independant of each other.
- Device change broadcasts are now sent to the Doom event queue, so
  device scanning can be handled in one common place.
- Added a fast version of IsXInputDevice that uses the Raw Input device
  list, because querying WMI for this information is painfully slow.
- Added support for compiling with FMOD Ex 4.26+ and running the game
  with an older DLL. This combination will now produce sound.


SVN r1717 (trunk)
This commit is contained in:
Randy Heit 2009-07-15 05:53:06 +00:00
parent 8e5b7373b8
commit f74f6a1659
15 changed files with 628 additions and 374 deletions

View file

@ -1,4 +1,19 @@
July 13, 2009 (Changes by Graf Zahl)
July 14, 2009
- Split the joystick menu into two parts: A top level with general options
and a list of all attached controllers, and a second level for configuring
an individual controller.
- Fixed: Pressing Up at the top of a menu with more lines than fit on screen
would find an incorrect bottom position if the menu had a custom top height.
- Added the cvars joy_dinput, joy_ps2raw, and joy_xinput to enable/disable
specific game controller input systems independant of each other.
- Device change broadcasts are now sent to the Doom event queue, so
device scanning can be handled in one common place.
- Added a fast version of IsXInputDevice that uses the Raw Input device
list, because querying WMI for this information is painfully slow.
- Added support for compiling with FMOD Ex 4.26+ and running the game
with an older DLL. This combination will now produce sound.
July 13, 2009 (Changes by Graf Zahl)
- added submission for raising master/children/siblings.
- added submission for no decals on wall option.
- removed some useless code from SpawnMissile function.

View file

@ -38,7 +38,8 @@ enum EGenericEvent
EV_KeyDown, // data1: scan code, data2: Qwerty ASCII code
EV_KeyUp, // same
EV_Mouse, // x, y: mouse movement deltas
EV_GUI_Event // subtype specifies actual event
EV_GUI_Event, // subtype specifies actual event
EV_DeviceChange,// a device has been connected or removed
};
// Event structure.

View file

@ -101,6 +101,7 @@
#include "v_palette.h"
#include "m_cheat.h"
#include "compatibility.h"
#include "m_joy.h"
EXTERN_CVAR(Bool, hud_althud)
void DrawHUD();
@ -240,6 +241,8 @@ void D_ProcessEvents (void)
for (; eventtail != eventhead ; eventtail = (eventtail+1)&(MAXEVENTS-1))
{
ev = &events[eventtail];
if (ev->type == EV_DeviceChange)
UpdateJoystickMenu(I_UpdateDeviceList());
if (C_Responder (ev))
continue; // console ate the event
if (M_Responder (ev))
@ -260,6 +263,11 @@ void D_ProcessEvents (void)
void D_PostEvent (const event_t *ev)
{
// Do not post duplicate consecutive EV_DeviceChange events.
if (ev->type == EV_DeviceChange && events[eventhead].type == EV_DeviceChange)
{
return;
}
events[eventhead] = *ev;
if (ev->type == EV_Mouse && !testpolymost && !paused && menuactive == MENU_Off &&
ConsoleState != c_down && ConsoleState != c_falling)

View file

@ -2,6 +2,7 @@
#include "m_joy.h"
#include "gameconfigfile.h"
#include "d_event.h"
// MACROS ------------------------------------------------------------------
@ -15,6 +16,23 @@
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
EXTERN_CVAR(Bool, joy_ps2raw)
EXTERN_CVAR(Bool, joy_dinput)
EXTERN_CVAR(Bool, joy_xinput)
// PUBLIC DATA DEFINITIONS -------------------------------------------------
CUSTOM_CVAR(Bool, use_joystick, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL)
{
#ifdef _WIN32
joy_ps2raw.Callback();
joy_dinput.Callback();
joy_xinput.Callback();
#endif
}
// PRIVATE DATA DEFINITIONS ------------------------------------------------
// CODE --------------------------------------------------------------------
//==========================================================================
@ -142,3 +160,80 @@ void M_SaveJoystickConfig(IJoystickConfig *joy)
}
}
}
//===========================================================================
//
// Joy_RemoveDeadZone
//
//===========================================================================
double Joy_RemoveDeadZone(double axisval, double deadzone, BYTE *buttons)
{
// Cancel out deadzone.
if (fabs(axisval) < deadzone)
{
axisval = 0;
*buttons = 0;
}
// Make the dead zone the new 0.
else if (axisval < 0)
{
axisval = (axisval + deadzone) / (1.0 - deadzone);
*buttons = 2; // button minus
}
else
{
axisval = (axisval - deadzone) / (1.0 - deadzone);
*buttons = 1; // button plus
}
return axisval;
}
//===========================================================================
//
// Joy_GenerateButtonEvents
//
// Provided two bitmasks for a set of buttons, generates events to reflect
// any changes from the old to new set, where base is the key for bit 0,
// base+1 is the key for bit 1, etc.
//
//===========================================================================
void Joy_GenerateButtonEvents(int oldbuttons, int newbuttons, int numbuttons, int base)
{
int changed = oldbuttons ^ newbuttons;
if (changed != 0)
{
event_t ev = { 0 };
int mask = 1;
for (int j = 0; j < numbuttons; mask <<= 1, ++j)
{
if (changed & mask)
{
ev.data1 = base + j;
ev.type = (newbuttons & mask) ? EV_KeyDown : EV_KeyUp;
D_PostEvent(&ev);
}
}
}
}
void Joy_GenerateButtonEvents(int oldbuttons, int newbuttons, int numbuttons, const int *keys)
{
int changed = oldbuttons ^ newbuttons;
if (changed != 0)
{
event_t ev = { 0 };
int mask = 1;
for (int j = 0; j < numbuttons; mask <<= 1, ++j)
{
if (changed & mask)
{
ev.data1 = keys[j];
ev.type = (newbuttons & mask) ? EV_KeyDown : EV_KeyUp;
D_PostEvent(&ev);
}
}
}
}

View file

@ -3,6 +3,7 @@
#include "doomtype.h"
#include "tarray.h"
#include "c_cvars.h"
enum EJoyAxis
{
@ -43,11 +44,18 @@ struct NOVTABLE IJoystickConfig
virtual FString GetIdentifier() = 0;
};
EXTERN_CVAR(Bool, use_joystick);
bool M_LoadJoystickConfig(IJoystickConfig *joy);
void M_SaveJoystickConfig(IJoystickConfig *joy);
void Joy_GenerateButtonEvents(int oldbuttons, int newbuttons, int numbuttons, int base);
void Joy_GenerateButtonEvents(int oldbuttons, int newbuttons, int numbuttons, const int *keys);
double Joy_RemoveDeadZone(double axisval, double deadzone, BYTE *buttons);
// These ought to be provided by a system-specific i_input.cpp.
void I_GetAxes(float axes[NUM_JOYAXIS]);
void I_GetJoysticks(TArray<IJoystickConfig *> &sticks);
IJoystickConfig *I_UpdateDeviceList();
#endif

View file

@ -94,6 +94,7 @@ typedef enum {
rightmore,
safemore,
rsafemore,
joymore,
slider,
absslider,
inverter,
@ -101,7 +102,6 @@ typedef enum {
discretes,
cdiscrete,
ediscrete,
discrete_joy,
control,
screenres,
bitflag,
@ -158,7 +158,6 @@ struct menuitem_t
struct value_t *values;
struct valuestring_t *valuestrings;
struct valueenum_t *enumvalues;
TArray<IJoystickConfig *> *joyvalues;
char *command;
void (*cfunc)(FBaseCVar *cvar, float newval);
void (*mfunc)(void);

View file

@ -290,34 +290,26 @@ menu_t MouseMenu =
*
*=======================================*/
#define SELECTED_JOYSTICK (Joysticks[JoystickItems[1].a.joyselection])
EXTERN_CVAR (Bool, use_joystick)
EXTERN_CVAR(Bool, use_joystick)
EXTERN_CVAR(Bool, joy_ps2raw)
EXTERN_CVAR(Bool, joy_dinput)
EXTERN_CVAR(Bool, joy_xinput)
#if 0
EXTERN_CVAR (Float, joy_speedmultiplier)
EXTERN_CVAR (Int, joy_xaxis)
EXTERN_CVAR (Int, joy_yaxis)
EXTERN_CVAR (Int, joy_zaxis)
EXTERN_CVAR (Int, joy_xrot)
EXTERN_CVAR (Int, joy_yrot)
EXTERN_CVAR (Int, joy_zrot)
EXTERN_CVAR (Int, joy_slider)
EXTERN_CVAR (Int, joy_dial)
EXTERN_CVAR (Float, joy_xthreshold)
EXTERN_CVAR (Float, joy_ythreshold)
EXTERN_CVAR (Float, joy_zthreshold)
EXTERN_CVAR (Float, joy_xrotthreshold)
EXTERN_CVAR (Float, joy_yrotthreshold)
EXTERN_CVAR (Float, joy_zrotthreshold)
EXTERN_CVAR (Float, joy_sliderthreshold)
EXTERN_CVAR (Float, joy_dialthreshold)
EXTERN_CVAR (Float, joy_yawspeed)
EXTERN_CVAR (Float, joy_pitchspeed)
EXTERN_CVAR (Float, joy_forwardspeed)
EXTERN_CVAR (Float, joy_sidespeed)
EXTERN_CVAR (Float, joy_upspeed)
EXTERN_CVAR (GUID, joy_guid)
#endif
static TArray<IJoystickConfig *> Joysticks;
static TArray<menuitem_t> JoystickItems;
menu_t JoystickMenu =
{
"CONTROLLER OPTIONS",
};
/*=======================================
*
* Joystick Config Menu
*
*=======================================*/
IJoystickConfig *SELECTED_JOYSTICK;
static value_t JoyAxisMapNames[6] =
{
@ -335,13 +327,11 @@ static value_t Inversion[2] =
{ 1.0, "Inverted" }
};
static TArray<IJoystickConfig *> Joysticks;
static TArray<menuitem_t> JoystickConfigItems;
static TArray<menuitem_t> JoystickItems;
menu_t JoystickMenu =
menu_t JoystickConfigMenu =
{
"JOYSTICK OPTIONS",
"CONFIGURE CONTROLLER",
};
@ -1519,7 +1509,7 @@ static void CalcIndent (menu_t *menu)
{
item = menu->items + i;
if (item->type != whitetext && item->type != redtext && item->type != screenres &&
(item->type != discrete || !item->c.discretecenter))
item->type != joymore && (item->type != discrete || !item->c.discretecenter))
{
thiswidth = SmallFont->StringWidth (item->label);
if (thiswidth > widest)
@ -1694,6 +1684,10 @@ void M_OptDrawer ()
{
indent = 160;
}
else if (item->type == joymore)
{
indent = 4;
}
else
{
indent = CurrentMenu->indent;
@ -1703,19 +1697,19 @@ void M_OptDrawer ()
{
FString somestring;
const char *label;
if (item->type != discrete_joy)
if (item->type != joymore)
{
label = item->label;
}
else
{
if (item->e.joyvalues->Size() == 0)
if (Joysticks.Size() == 0)
{
label = "No devices connected";
}
else
{
somestring = (*item->e.joyvalues)[item->a.joyselection]->GetName();
somestring = Joysticks[item->a.joyselection]->GetName();
label = somestring;
}
}
@ -1728,6 +1722,11 @@ void M_OptDrawer ()
color = MoreColor;
break;
case joymore:
x = 20;
color = MoreColor;
break;
case numberedmore:
case rsafemore:
case rightmore:
@ -1735,13 +1734,6 @@ void M_OptDrawer ()
color = item->type != rightmore ? CR_GREEN : MoreColor;
break;
case discrete_joy:
x = 160 - width / 2;
// Move cursor to the left of this item.
indent = x - 14;
color = ValueColor;
break;
case redtext:
x = 160 - width / 2;
color = LabelColor;
@ -2222,7 +2214,11 @@ void M_OptResponder (event_t *ev)
int maxitems, rowheight;
// Figure out how many lines of text fit on the menu
if (BigFont && CurrentMenu->texttitle)
if (CurrentMenu->y != 0)
{
maxitems = CurrentMenu->y;
}
else if (BigFont && CurrentMenu->texttitle)
{
maxitems = 15 + BigFont->GetHeight ();
}
@ -2457,15 +2453,6 @@ void M_OptResponder (event_t *ev)
S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE);
break;
case discrete_joy:
if (--item->a.joyselection < 0)
{
item->a.joyselection = item->e.joyvalues->Size() - 1;
}
UpdateJoystickMenu(NULL);
S_Sound(CHAN_VOICE|CHAN_UI, "menu/change", 1, ATTN_NONE);
break;
case inverter:
value = item->a.cvar->GetGenericRep (CVAR_Float);
value.Float = -value.Float;
@ -2663,15 +2650,6 @@ void M_OptResponder (event_t *ev)
S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE);
break;
case discrete_joy:
if ((unsigned)++item->a.joyselection >= item->e.joyvalues->Size())
{
item->a.joyselection = 0;
}
UpdateJoystickMenu(NULL);
S_Sound(CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE);
break;
case inverter:
value = item->a.cvar->GetGenericRep (CVAR_Float);
value.Float = -value.Float;
@ -2775,6 +2753,7 @@ void M_OptResponder (event_t *ev)
item->type == numberedmore ||
item->type == rightmore ||
item->type == rsafemore ||
item->type == joymore ||
item->type == safemore)
&& item->e.mfunc)
{
@ -3094,21 +3073,114 @@ CCMD (menu_mouse)
MouseOptions ();
}
static void DrawJoystickConfigMenuHeader()
{
FString joyname = SELECTED_JOYSTICK->GetName();
screen->DrawText(BigFont, gameinfo.gametype & GAME_DoomChex ? CR_RED : CR_UNTRANSLATED,
160-BigFont->StringWidth(CurrentMenu->texttitle)/2, 5,
CurrentMenu->texttitle, DTA_Clean, true, TAG_DONE);
screen->DrawText(SmallFont, gameinfo.gametype & GAME_DoomChex ? CR_RED : CR_UNTRANSLATED,
160-SmallFont->StringWidth(joyname)/2, 8 + BigFont->GetHeight(),
joyname, DTA_Clean, true, TAG_DONE);
}
static void UpdateJoystickConfigMenu(IJoystickConfig *joy)
{
int i;
menuitem_t item = { whitetext };
JoystickConfigItems.Clear();
if (joy == NULL)
{
item.type = redtext;
item.label = "Invalid controller specified for menu";
JoystickConfigItems.Push(item);
}
else
{
SELECTED_JOYSTICK = joy;
item.type = joy_sens;
item.label = "Overall sensitivity";
item.b.min = 0.5f;
item.c.max = 2.f;
item.d.step = 0.2f;
JoystickConfigItems.Push(item);
item.type = redtext;
item.label = " ";
JoystickConfigItems.Push(item);
item.type = whitetext;
if (joy->GetNumAxes() > 0)
{
item.label = "Axis Configuration";
JoystickConfigItems.Push(item);
for (i = 0; i < joy->GetNumAxes(); ++i)
{
item.type = redtext;
item.label = " ";
JoystickConfigItems.Push(item);
item.type = joy_map;
item.label = joy->GetAxisName(i);
item.a.joyselection = i;
item.b.numvalues = countof(JoyAxisMapNames);
item.e.values = JoyAxisMapNames;
JoystickConfigItems.Push(item);
item.type = joy_slider;
item.label = "Sensitivity";
item.b.min = 0;
item.c.max = 4;
item.d.step = 0.2f;
item.e.joyslidernum = 0;
JoystickConfigItems.Push(item);
item.type = joy_inverter;
item.label = "Invert";
JoystickConfigItems.Push(item);
item.type = joy_slider;
item.label = "Dead Zone";
item.b.position = 1;
item.c.max = 0.9f;
item.d.step = 0.05f;
item.e.joyslidernum = 1;
JoystickConfigItems.Push(item);
}
}
else
{
item.label = "No configurable axes";
JoystickConfigItems.Push(item);
}
}
JoystickConfigMenu.items = &JoystickConfigItems[0];
JoystickConfigMenu.numitems = JoystickConfigItems.Size();
JoystickConfigMenu.lastOn = 0;
JoystickConfigMenu.scrollpos = 0;
JoystickConfigMenu.y = 25 + BigFont->GetHeight();
JoystickConfigMenu.PreDraw = DrawJoystickConfigMenuHeader;
if (screen != NULL)
{
CalcIndent(&JoystickConfigMenu);
}
}
static void StartJoystickConfigMenu()
{
UpdateJoystickConfigMenu(Joysticks[JoystickItems[JoystickMenu.lastOn].a.joyselection]);
M_SwitchMenu(&JoystickConfigMenu);
}
void UpdateJoystickMenu(IJoystickConfig *selected)
{
int i;
menuitem_t item = { whitetext };
int itemnum;
IJoystickConfig *joy;
int itemnum = -1;
if (JoystickItems.Size() > 1)
{
itemnum = JoystickItems[1].a.joyselection;
}
else
{
itemnum = 0;
}
JoystickItems.Clear();
I_GetJoysticks(Joysticks);
if ((unsigned)itemnum >= Joysticks.Size())
@ -3126,162 +3198,95 @@ void UpdateJoystickMenu(IJoystickConfig *selected)
}
}
}
item.type = discrete;
item.label = "Enable controller support";
item.a.cvar = &use_joystick;
item.b.numvalues = 2;
item.e.values = YesNo;
JoystickItems.Push(item);
#ifdef _WIN32
item.label = "Enable DirectInput controllers";
item.a.cvar = &joy_dinput;
JoystickItems.Push(item);
item.label = "Enable XInput controllers";
item.a.cvar = &joy_xinput;
JoystickItems.Push(item);
item.label = "Enable raw PlayStation 2 adapters";
item.a.cvar = &joy_ps2raw;
JoystickItems.Push(item);
#endif
item.type = redtext;
item.label = " ";
JoystickItems.Push(item);
if (Joysticks.Size() == 0)
{
item.type = redtext;
item.label = "No joysticks connected";
item.label = "No controllers detected";
JoystickItems.Push(item);
if (!use_joystick)
{
item.type = whitetext;
item.label = "Controller support must be";
JoystickItems.Push(item);
item.label = "enabled to detect any";
JoystickItems.Push(item);
}
}
else
{
item.type = discrete;
item.label = "Enable joystick";
item.a.cvar = &use_joystick;
item.b.numvalues = 2;
item.e.values = YesNo;
item.label = "Configure controllers:";
JoystickItems.Push(item);
item.type = discrete_joy;
item.label = "Change settings for";
item.a.joyselection = itemnum;
item.e.joyvalues = &Joysticks;
JoystickItems.Push(item);
item.type = joy_sens;
item.label = "Overall sensitivity";
item.b.min = 0.5f;
item.c.max = 2.f;
item.d.step = 0.2f;
JoystickItems.Push(item);
item.type = redtext;
item.label = " ";
JoystickItems.Push(item);
joy = Joysticks[itemnum];
if (joy->GetNumAxes() > 0)
item.type = joymore;
item.e.mfunc = StartJoystickConfigMenu;
for (int i = 0; i < (int)Joysticks.Size(); ++i)
{
item.type = whitetext;
item.label = "Axis Configuration";
item.a.joyselection = i;
if (i == itemnum)
{
JoystickMenu.lastOn = JoystickItems.Size();
}
JoystickItems.Push(item);
for (i = 0; i < joy->GetNumAxes(); ++i)
{
item.type = redtext;
item.label = " ";
JoystickItems.Push(item);
item.type = joy_map;
item.label = joy->GetAxisName(i);
item.a.joyselection = i;
item.b.numvalues = countof(JoyAxisMapNames);
item.e.values = JoyAxisMapNames;
JoystickItems.Push(item);
item.type = joy_slider;
item.label = "Sensitivity";
item.b.min = 0;
item.c.max = 4;
item.d.step = 0.2f;
item.e.joyslidernum = 0;
JoystickItems.Push(item);
item.type = joy_inverter;
item.label = "Invert";
JoystickItems.Push(item);
item.type = joy_slider;
item.label = "Dead Zone";
item.b.position = 1;
item.c.max = 0.9f;
item.d.step = 0.05f;
item.e.joyslidernum = 1;
JoystickItems.Push(item);
}
}
}
#if 0
{
JoystickItems[0].type = discrete;
JoystickItems[0].label = "Enable joystick";
JoystickItems[1].b.numvalues = float(JoystickNames.Size());
JoystickItems[1].e.guidvalues = &JoystickNames[0];
line = 5;
for (i = 0; i < 8; ++i)
{
if (JoyAxisNames[i] != NULL)
{
JoystickItems[line].label = JoyAxisNames[i];
JoystickItems[line].type = discrete;
JoystickItems[line].a.intcvar = cvars[i];
JoystickItems[line].b.numvalues = 6.f;
JoystickItems[line].d.graycheck = NULL;
JoystickItems[line].e.values = JoyAxisMapNames;
line++;
}
}
JoystickItems[line].type = redtext;
JoystickItems[line].label = " ";
line++;
JoystickItems[line].type = whitetext;
JoystickItems[line].label = "Axis Sensitivity";
line++;
for (i = 0; i < 5; ++i)
{
JoystickItems[line].type = absslider;
JoystickItems[line].label = JoyAxisMapNames[i+1].name;
JoystickItems[line].a.cvar = cvars2[i];
JoystickItems[line].b.min = 0.0;
JoystickItems[line].c.max = 4.0;
JoystickItems[line].d.step = 0.2f;
line++;
JoystickItems[line].type = inverter;
JoystickItems[line].label = JoyAxisMapNames[i+1].name;
JoystickItems[line].a.cvar = cvars2[i];
JoystickItems[line].e.values = Inversion;
line++;
}
JoystickItems[line].type = redtext;
JoystickItems[line].label = " ";
line++;
JoystickItems[line].type = whitetext;
JoystickItems[line].label = "Axis Dead Zones";
line++;
for (i = 0; i < 8; ++i)
{
if (JoyAxisNames[i] != NULL)
{
JoystickItems[line].label = JoyAxisNames[i];
JoystickItems[line].type = slider;
JoystickItems[line].a.cvar = cvars3[i];
JoystickItems[line].b.min = 0.0;
JoystickItems[line].c.max = 0.9f;
JoystickItems[line].d.step = 0.05f;
line++;
}
}
}
#endif
JoystickMenu.items = &JoystickItems[0];
JoystickMenu.numitems = JoystickItems.Size();
if (JoystickMenu.lastOn >= JoystickMenu.numitems)
{
JoystickMenu.lastOn = JoystickMenu.numitems - 1;
}
if (CurrentMenu == &JoystickMenu && CurrentItem >= JoystickMenu.numitems)
{
CurrentItem = JoystickMenu.lastOn;
}
if (screen != NULL)
{
CalcIndent(&JoystickMenu);
}
// If the joystick config menu is open, close it if the device it's
// open for is gone.
for (i = 0; (unsigned)i < Joysticks.Size(); ++i)
{
if (Joysticks[i] == SELECTED_JOYSTICK)
{
break;
}
}
if (i == Joysticks.Size())
{
SELECTED_JOYSTICK = NULL;
if (CurrentMenu == &JoystickConfigMenu)
{
M_PopMenuStack();
}
}
}
static void JoystickOptions ()

View file

@ -474,3 +474,8 @@ void I_GetAxes(float axes[NUM_JOYAXIS])
axes[i] = 0;
}
}
IJoystickConfig *I_UpdateDeviceList()
{
return NULL;
}

View file

@ -1179,6 +1179,8 @@ void FMODSoundRenderer::PrintStatus()
unsigned int bufferlength;
int numbuffers;
Printf ("Loaded FMOD version: "TEXTCOLOR_GREEN"%x.%02x.%02x\n", ActiveFMODVersion >> 16,
(ActiveFMODVersion >> 8) & 255, ActiveFMODVersion & 255);
if (FMOD_OK == Sys->getOutput(&output))
{
Printf ("Output type: "TEXTCOLOR_GREEN"%s\n", Enum_NameForNum(OutputNames, output));
@ -1361,11 +1363,12 @@ SoundStream *FMODSoundRenderer::CreateStream (SoundStreamCallback callback, int
FMODStreamCapsule *capsule;
FMOD::Sound *sound;
FMOD_RESULT result;
FMOD_CREATESOUNDEXINFO exinfo = { sizeof(exinfo), };
FMOD_CREATESOUNDEXINFO exinfo;
FMOD_MODE mode;
int sample_shift;
int channel_shift;
InitCreateSoundExInfo(&exinfo);
capsule = new FMODStreamCapsule (userdata, callback, this);
mode = FMOD_2D | FMOD_OPENUSER | FMOD_LOOP_NORMAL | FMOD_SOFTWARE | FMOD_CREATESTREAM | FMOD_OPENONLY;
@ -1434,11 +1437,12 @@ SoundStream *FMODSoundRenderer::CreateStream (SoundStreamCallback callback, int
SoundStream *FMODSoundRenderer::OpenStream(const char *filename_or_data, int flags, int offset, int length)
{
FMOD_MODE mode;
FMOD_CREATESOUNDEXINFO exinfo = { sizeof(exinfo), };
FMOD_CREATESOUNDEXINFO exinfo;
FMOD::Sound *stream;
FMOD_RESULT result;
bool url;
InitCreateSoundExInfo(&exinfo);
mode = FMOD_SOFTWARE | FMOD_2D | FMOD_CREATESTREAM;
if (flags & SoundStream::Loop)
{
@ -2129,11 +2133,12 @@ void FMODSoundRenderer::UpdateSounds()
SoundHandle FMODSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int length, int frequency, int channels, int bits)
{
FMOD_CREATESOUNDEXINFO exinfo = { sizeof(exinfo), };
FMOD_CREATESOUNDEXINFO exinfo;
SoundHandle retval = { NULL };
if (length == 0) return retval;
InitCreateSoundExInfo(&exinfo);
exinfo.length = length;
exinfo.numchannels = channels;
exinfo.defaultfrequency = frequency;
@ -2184,11 +2189,12 @@ SoundHandle FMODSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int length, int frequ
SoundHandle FMODSoundRenderer::LoadSound(BYTE *sfxdata, int length)
{
FMOD_CREATESOUNDEXINFO exinfo = { sizeof(exinfo), };
FMOD_CREATESOUNDEXINFO exinfo;
SoundHandle retval = { NULL };
if (length == 0) return retval;
InitCreateSoundExInfo(&exinfo);
exinfo.length = length;
const FMOD_MODE samplemode = FMOD_3D | FMOD_OPENMEMORY | FMOD_SOFTWARE;
@ -2623,7 +2629,7 @@ void FMODSoundRenderer::DrawSpectrum(float *spectrumarray, int x, int y, int wid
short *FMODSoundRenderer::DecodeSample(int outlen, const void *coded, int sizebytes, ECodecType type)
{
FMOD_CREATESOUNDEXINFO exinfo = { sizeof(exinfo), };
FMOD_CREATESOUNDEXINFO exinfo;
FMOD::Sound *sound;
FMOD_SOUND_FORMAT format;
int channels;
@ -2631,6 +2637,7 @@ short *FMODSoundRenderer::DecodeSample(int outlen, const void *coded, int sizeby
FMOD_RESULT result;
short *outbuf;
InitCreateSoundExInfo(&exinfo);
if (type == CODEC_Vorbis)
{
exinfo.suggestedsoundtype = FMOD_SOUND_TYPE_OGGVORBIS;
@ -2667,3 +2674,28 @@ short *FMODSoundRenderer::DecodeSample(int outlen, const void *coded, int sizeby
}
return outbuf;
}
//==========================================================================
//
// FMODSoundRenderer :: InitCreateSoundExInfo
//
// Allow for compiling with 4.26 APIs while still running with older DLLs.
//
//==========================================================================
void FMODSoundRenderer::InitCreateSoundExInfo(FMOD_CREATESOUNDEXINFO *exinfo) const
{
#if FMOD_VERSION >= 0x42600
if (ActiveFMODVersion < 0x42600)
{
// This parameter was added for 4.26.00, and trying to pass it to older
// DLLs will fail.
exinfo->cbsize = myoffsetof(FMOD_CREATESOUNDEXINFO, ignoresetfilesystem);
}
else
#endif
{
exinfo->cbsize = sizeof(exinfo);
}
memset((BYTE *)exinfo + sizeof(exinfo->cbsize), 0, exinfo->cbsize - sizeof(exinfo->cbsize));
}

View file

@ -74,6 +74,7 @@ private:
FMOD_MODE SetChanHeadSettings(SoundListener *listener, FMOD::Channel *chan, const FVector3 &pos, bool areasound, FMOD_MODE oldmode) const;
bool ReconnectSFXReverbUnit();
void InitCreateSoundExInfo(FMOD_CREATESOUNDEXINFO *exinfo) const;
bool Init ();
void Shutdown ();

View file

@ -9,7 +9,6 @@
#include <wbemidl.h>
#endif
#include <oleauto.h>
#include <dbt.h>
#include <malloc.h>
#define USE_WINDOWS_DWORD
@ -28,6 +27,7 @@
#include "cmdlib.h"
#include "v_text.h"
#include "m_argv.h"
#include "rawinput.h"
// WBEMIDL BITS -- because w32api doesn't have this, either -----------------
@ -208,9 +208,9 @@ public:
bool GetDevice();
void ProcessInput();
bool WndProcHook(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result);
void AddAxes(float axes[NUM_JOYAXIS]);
void GetDevices(TArray<IJoystickConfig *> &sticks);
IJoystickConfig *Rescan();
protected:
struct Enumerator
@ -225,6 +225,8 @@ protected:
static BOOL CALLBACK EnumCallback(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef);
static int STACK_ARGS NameSort(const void *a, const void *b);
static bool IsXInputDevice(const GUID *guid);
static bool IsXInputDeviceFast(const GUID *guid);
static bool IsXInputDeviceSlow(const GUID *guid);
};
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
@ -245,8 +247,12 @@ extern HWND Window;
// PUBLIC DATA DEFINITIONS -------------------------------------------------
CVAR (Bool, use_joystick, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
FJoystickCollection *JoyDevices[NUM_JOYDEVICES];
CUSTOM_CVAR(Bool, joy_dinput, true, CVAR_GLOBALCONFIG|CVAR_ARCHIVE|CVAR_NOINITCALL)
{
I_StartupDirectInputJoystick();
event_t ev = { EV_DeviceChange };
D_PostEvent(&ev);
}
// PRIVATE DATA DEFINITIONS ------------------------------------------------
@ -981,7 +987,7 @@ FDInputJoystickManager::~FDInputJoystickManager()
bool FDInputJoystickManager::GetDevice()
{
if (g_pdi == NULL || !use_joystick || Args->CheckParm("-nojoy"))
if (g_pdi == NULL)
{
return false;
}
@ -1041,37 +1047,6 @@ void FDInputJoystickManager::GetDevices(TArray<IJoystickConfig *> &sticks)
}
}
//===========================================================================
//
// FDInputJoystickManager :: WndProcHook
//
// Listen for device change broadcasts and rescan the attached devices
// when they are received.
//
//===========================================================================
bool FDInputJoystickManager::WndProcHook(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result)
{
if (message != WM_DEVICECHANGE)
{
return false;
}
#ifdef _DEBUG
char out[64];
mysnprintf(out, countof(out), "WM_DEVICECHANGE wParam=%d\n", wParam);
OutputDebugString(out);
#endif
if ((wParam != DBT_DEVNODES_CHANGED &&
wParam != DBT_DEVICEARRIVAL &&
wParam != DBT_CONFIGCHANGED))
{
return false;
}
UpdateJoystickMenu(EnumDevices());
// Return false so that other devices can handle this too if they want.
return false;
}
//===========================================================================
//
// FDInputJoystickManager :: EnumCallback STATIC
@ -1101,16 +1076,46 @@ BOOL CALLBACK FDInputJoystickManager::EnumCallback(LPCDIDEVICEINSTANCE lpddi, LP
//
// FDInputJoystickManager :: IsXInputDevice STATIC
//
// Pretty much copied straight from the article "XInput and DirectInput".
//
// Enum each PNP device using WMI and check each device ID to see if it
// contains "IG_" (ex. "VID_045E&PID_028E&IG_00"). If it does, then it's an
// XInput device. Unfortunately this information can not be found by just
// using DirectInput.
// Does the DirectInput product GUID correspond to an XInput controller?
// If the product's device ID contains contains "IG_"
// (ex. "VID_045E&PID_028E&IG_00"), then it is an XInput device.
// Unfortunately this information can not be found by just using DirectInput.
//
//===========================================================================
bool FDInputJoystickManager::IsXInputDevice(const GUID *guid)
{
if (MyGetRawInputDeviceList == NULL || MyGetRawInputDeviceInfoA == NULL)
{
return IsXInputDeviceSlow(guid);
}
else
{
return IsXInputDeviceFast(guid);
}
}
//===========================================================================
//
// FDInputJoystickManager :: IsXInputDeviceSlow STATIC
//
// Pretty much copied straight from the article "XInput and DirectInput".
//
// Enum each PNP device using WMI and check each device ID. This is
// Microsoft's reference implementation, but it is damn slow. After
// a hardware change, connecting to the WMI server can take nearly three
// seconds, and creating the instance enumerator consistantly takes longer
// than 0.25 seconds.
//
// The XInput DLL can apparently be hacked fairly simply to work with
// Windows 2000, and since Raw Input wasn't introduced until XP, I think
// that's reason enough to keep this version around, despite it being
// so horrendously slow.
//
//===========================================================================
bool FDInputJoystickManager::IsXInputDeviceSlow(const GUID *guid)
{
IWbemLocator *wbemlocator = NULL;
IEnumWbemClassObject *enumdevices = NULL;
@ -1201,6 +1206,71 @@ cleanup:
return isxinput;
}
//===========================================================================
//
// FDInputJoystickManager :: IsXInputDeviceFast STATIC
//
// The theory of operation is the same as for IsXInputDeviceSlow, except that
// we use the Raw Input device list to find the device ID instead of WMI.
// This generally takes ~0.02 ms on my machine, though it occasionally spikes
// at over 1 ms. Either way, it is a huge order of magnitude faster than WMI.
// (around 10,000 times faster, in fact!)
//
//===========================================================================
bool FDInputJoystickManager::IsXInputDeviceFast(const GUID *guid)
{
UINT nDevices, numDevices;
RAWINPUTDEVICELIST *devices;
UINT i;
bool isxinput = false;
if (MyGetRawInputDeviceList(NULL, &nDevices, sizeof(RAWINPUTDEVICELIST)) != 0)
{
return false;
}
if ((devices = (RAWINPUTDEVICELIST *)malloc(sizeof(RAWINPUTDEVICELIST) * nDevices)) == NULL)
{
return false;
}
if ((numDevices = MyGetRawInputDeviceList(devices, &nDevices, sizeof(RAWINPUTDEVICELIST))) == (UINT)-1)
{
free(devices);
return false;
}
for (i = 0; i < numDevices; ++i)
{
// I am making the assumption here that all possible XInput devices
// will report themselves as generic HID devices and not as keyboards
// or mice.
if (devices[i].dwType == RIM_TYPEHID)
{
RID_DEVICE_INFO rdi;
UINT cbSize;
cbSize = rdi.cbSize = sizeof(rdi);
if (MyGetRawInputDeviceInfoA(devices[i].hDevice, RIDI_DEVICEINFO, &rdi, &cbSize) >= 0)
{
if(MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) == guid->Data1)
{
char name[256];
UINT namelen = countof(name);
UINT reslen;
reslen = MyGetRawInputDeviceInfoA(devices[i].hDevice, RIDI_DEVICENAME, name, &namelen);
if (reslen != (UINT)-1)
{
isxinput = (strstr(name, "IG_") != NULL);
break;
}
}
}
}
}
free(devices);
return isxinput;
}
//===========================================================================
//
// FDInputJoystickManager :: NameSort STATIC
@ -1319,6 +1389,21 @@ FDInputJoystick *FDInputJoystickManager::EnumDevices()
return newone;
}
//===========================================================================
//
// FDInputJoystickManager :: Rescan
//
// Used by the joy_ps2raw and joy_xinput callbacks to rescan the
// DirectInput devices, since their presence or absence can affect the
// results of the scan.
//
//===========================================================================
IJoystickConfig *FDInputJoystickManager::Rescan()
{
return EnumDevices();
}
//===========================================================================
//
// I_StartupDirectInputJoystick
@ -1327,85 +1412,24 @@ FDInputJoystick *FDInputJoystickManager::EnumDevices()
void I_StartupDirectInputJoystick()
{
FJoystickCollection *joys = new FDInputJoystickManager;
if (joys->GetDevice())
if (!joy_dinput || !use_joystick || Args->CheckParm("-nojoy"))
{
JoyDevices[INPUT_DIJoy] = joys;
}
}
//===========================================================================
//
// Joy_RemoveDeadZone
//
//===========================================================================
double Joy_RemoveDeadZone(double axisval, double deadzone, BYTE *buttons)
{
// Cancel out deadzone.
if (fabs(axisval) < deadzone)
{
axisval = 0;
*buttons = 0;
}
// Make the dead zone the new 0.
else if (axisval < 0)
{
axisval = (axisval + deadzone) / (1.0 - deadzone);
*buttons = 2; // button minus
if (JoyDevices[INPUT_DIJoy] != NULL)
{
delete JoyDevices[INPUT_DIJoy];
JoyDevices[INPUT_DIJoy] = NULL;
UpdateJoystickMenu(NULL);
}
}
else
{
axisval = (axisval - deadzone) / (1.0 - deadzone);
*buttons = 1; // button plus
}
return axisval;
}
//===========================================================================
//
// Joy_GenerateButtonEvents
//
// Provided two bitmasks for a set of buttons, generates events to reflect
// any changes from the old to new set, where base is the key for bit 0,
// base+1 is the key for bit 1, etc.
//
//===========================================================================
void Joy_GenerateButtonEvents(int oldbuttons, int newbuttons, int numbuttons, int base)
{
int changed = oldbuttons ^ newbuttons;
if (changed != 0)
{
event_t ev = { 0 };
int mask = 1;
for (int j = 0; j < numbuttons; mask <<= 1, ++j)
if (JoyDevices[INPUT_DIJoy] == NULL)
{
if (changed & mask)
FJoystickCollection *joys = new FDInputJoystickManager;
if (joys->GetDevice())
{
ev.data1 = base + j;
ev.type = (newbuttons & mask) ? EV_KeyDown : EV_KeyUp;
D_PostEvent(&ev);
JoyDevices[INPUT_DIJoy] = joys;
}
}
}
}
void Joy_GenerateButtonEvents(int oldbuttons, int newbuttons, int numbuttons, const int *keys)
{
int changed = oldbuttons ^ newbuttons;
if (changed != 0)
{
event_t ev = { 0 };
int mask = 1;
for (int j = 0; j < numbuttons; mask <<= 1, ++j)
{
if (changed & mask)
{
ev.data1 = keys[j];
ev.type = (newbuttons & mask) ? EV_KeyDown : EV_KeyUp;
D_PostEvent(&ev);
}
}
}
}

View file

@ -47,6 +47,7 @@
#endif
#include <windows.h>
#include <mmsystem.h>
#include <dbt.h>
#include <dinput.h>
#include <malloc.h>
@ -118,7 +119,8 @@
#endif
static void FindRawInputFunctions();
BOOL DI_InitJoy (void);
FJoystickCollection *JoyDevices[NUM_JOYDEVICES];
extern HINSTANCE g_hInst;
extern DWORD SessionID;
@ -551,6 +553,16 @@ LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
case WM_ERASEBKGND:
return true;
case WM_DEVICECHANGE:
if (wParam == DBT_DEVNODES_CHANGED ||
wParam == DBT_DEVICEARRIVAL ||
wParam == DBT_CONFIGCHANGED)
{
event_t ev = { EV_DeviceChange };
D_PostEvent(&ev);
}
return DefWindowProc (hWnd, message, wParam, lParam);
default:
return DefWindowProc (hWnd, message, wParam, lParam);
}
@ -765,6 +777,24 @@ void I_GetJoysticks(TArray<IJoystickConfig *> &sticks)
}
}
// If a new controller was added, returns a pointer to it.
IJoystickConfig *I_UpdateDeviceList()
{
IJoystickConfig *newone = NULL;
for (int i = 0; i < NUM_JOYDEVICES; ++i)
{
if (JoyDevices[i] != NULL)
{
IJoystickConfig *thisnewone = JoyDevices[i]->Rescan();
if (newone == NULL)
{
newone = thisnewone;
}
}
}
return newone;
}
void I_PutInClipboard (const char *str)
{
if (str == NULL || !OpenClipboard (Window))

View file

@ -115,6 +115,7 @@ class NOVTABLE FJoystickCollection : public FInputDevice
public:
virtual void AddAxes(float axes[NUM_JOYAXIS]) = 0;
virtual void GetDevices(TArray<IJoystickConfig *> &sticks) = 0;
virtual IJoystickConfig *Rescan() = 0;
};
enum
@ -135,10 +136,6 @@ void I_StartupDirectInputJoystick();
void I_StartupRawPS2();
bool I_IsPS2Adapter(DWORD vidpid);
void Joy_GenerateButtonEvents(int oldbuttons, int newbuttons, int numbuttons, int base);
void Joy_GenerateButtonEvents(int oldbuttons, int newbuttons, int numbuttons, const int *keys);
double Joy_RemoveDeadZone(double axisval, double deadzone, BYTE *buttons);
// USB HID usage page numbers
#define HID_GENERIC_DESKTOP_PAGE 0x01
#define HID_SIMULATION_CONTROLS_PAGE 0x02

View file

@ -5,7 +5,6 @@
#include <windows.h>
#include <malloc.h>
#include <limits.h>
#include <dbt.h>
#define USE_WINDOWS_DWORD
#include "i_input.h"
@ -150,12 +149,11 @@ public:
bool GetDevice();
bool ProcessRawInput(RAWINPUT *raw, int code);
bool WndProcHook(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result);
void AddAxes(float axes[NUM_JOYAXIS]);
void GetDevices(TArray<IJoystickConfig *> &sticks);
IJoystickConfig *Rescan();
protected:
HMODULE XInputDLL;
TArray<FRawPS2Controller *> Devices;
bool Registered;
@ -200,6 +198,13 @@ extern HWND Window;
// PUBLIC DATA DEFINITIONS -------------------------------------------------
CUSTOM_CVAR(Bool, joy_ps2raw, true, CVAR_GLOBALCONFIG|CVAR_ARCHIVE|CVAR_NOINITCALL)
{
I_StartupRawPS2();
event_t ev = { EV_DeviceChange };
D_PostEvent(&ev);
}
// PRIVATE DATA DEFINITIONS ------------------------------------------------
static const int ButtonKeys[16] =
@ -938,37 +943,6 @@ void FRawPS2Manager::GetDevices(TArray<IJoystickConfig *> &sticks)
}
}
//===========================================================================
//
// FRawPS2Manager :: WndProcHook
//
// Listen for device change broadcasts and rescan the attached devices
// when they are received.
//
//===========================================================================
bool FRawPS2Manager::WndProcHook(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result)
{
if (message != WM_DEVICECHANGE)
{
return false;
}
#ifdef _DEBUG
char out[64];
mysnprintf(out, countof(out), "WM_DEVICECHANGE wParam=%d\n", wParam);
OutputDebugString(out);
#endif
if ((wParam != DBT_DEVNODES_CHANGED &&
wParam != DBT_DEVICEARRIVAL &&
wParam != DBT_CONFIGCHANGED))
{
return false;
}
UpdateJoystickMenu(EnumDevices());
// Return false so that other devices can handle this too if they want.
return false;
}
//===========================================================================
//
// FRawPS2Manager :: ProcessRawInput
@ -994,6 +968,17 @@ bool FRawPS2Manager::ProcessRawInput(RAWINPUT *raw, int code)
return false;
}
//===========================================================================
//
// FRawPS2Manager :: Rescan
//
//===========================================================================
IJoystickConfig *FRawPS2Manager::Rescan()
{
return EnumDevices();
}
//===========================================================================
//
// FRawPS2Manager :: EnumDevices
@ -1292,10 +1277,25 @@ void FRawPS2Manager::DoRegister()
void I_StartupRawPS2()
{
FJoystickCollection *joys = new FRawPS2Manager;
if (joys->GetDevice())
if (!joy_ps2raw || !use_joystick || Args->CheckParm("-nojoy"))
{
JoyDevices[INPUT_RawPS2] = joys;
if (JoyDevices[INPUT_RawPS2] != NULL)
{
delete JoyDevices[INPUT_RawPS2];
JoyDevices[INPUT_RawPS2] = NULL;
UpdateJoystickMenu(NULL);
}
}
else
{
if (JoyDevices[INPUT_RawPS2] == NULL)
{
FJoystickCollection *joys = new FRawPS2Manager;
if (joys->GetDevice())
{
JoyDevices[INPUT_RawPS2] = joys;
}
}
}
}

View file

@ -120,6 +120,7 @@ public:
bool WndProcHook(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result);
void AddAxes(float axes[NUM_JOYAXIS]);
void GetDevices(TArray<IJoystickConfig *> &sticks);
IJoystickConfig *Rescan();
protected:
HMODULE XInputDLL;
@ -136,6 +137,13 @@ protected:
// PUBLIC DATA DEFINITIONS -------------------------------------------------
CUSTOM_CVAR(Bool, joy_xinput, true, CVAR_GLOBALCONFIG|CVAR_ARCHIVE|CVAR_NOINITCALL)
{
I_StartupXInput();
event_t ev = { EV_DeviceChange };
D_PostEvent(&ev);
}
// PRIVATE DATA DEFINITIONS ------------------------------------------------
static XInputGetStateType InputGetState;
@ -734,6 +742,17 @@ bool FXInputManager::WndProcHook(HWND hWnd, UINT message, WPARAM wParam, LPARAM
return false;
}
//===========================================================================
//
// FXInputManager :: Rescan
//
//===========================================================================
IJoystickConfig *FXInputManager::Rescan()
{
return NULL;
}
//===========================================================================
//
// I_StartupXInput
@ -742,10 +761,25 @@ bool FXInputManager::WndProcHook(HWND hWnd, UINT message, WPARAM wParam, LPARAM
void I_StartupXInput()
{
FJoystickCollection *joys = new FXInputManager;
if (joys->GetDevice())
if (!joy_xinput || !use_joystick || Args->CheckParm("-nojoy"))
{
JoyDevices[INPUT_XInput] = joys;
if (JoyDevices[INPUT_XInput] != NULL)
{
delete JoyDevices[INPUT_XInput];
JoyDevices[INPUT_XInput] = NULL;
UpdateJoystickMenu(NULL);
}
}
else
{
if (JoyDevices[INPUT_XInput] == NULL)
{
FJoystickCollection *joys = new FXInputManager;
if (joys->GetDevice())
{
JoyDevices[INPUT_XInput] = joys;
}
}
}
}