diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d81bb4a5..96650c30 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -111,7 +111,8 @@ if( WIN32 ) comctl32 comdlg32 ws2_32 - setupapi ) + setupapi + oleaut32 ) else( WIN32 ) option( NO_GTK "Disable GTK+ dialogs (Not applicable to Windows)" ) option( VALGRIND "Add special Valgrind sequences to self-modifying code" ) @@ -416,6 +417,7 @@ if( WIN32 ) win32/i_input.cpp win32/i_keyboard.cpp win32/i_mouse.cpp + win32/i_dijoy.cpp win32/i_main.cpp win32/i_movie.cpp win32/i_system.cpp diff --git a/src/doomdef.h b/src/doomdef.h index 479fbc5f..ec20b233 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -172,13 +172,17 @@ enum ESkillLevels #define NUM_KEYS 0x19C -#define JOYAXIS_NONE 0 -#define JOYAXIS_YAW 1 -#define JOYAXIS_PITCH 2 -#define JOYAXIS_FORWARD 3 -#define JOYAXIS_SIDE 4 -#define JOYAXIS_UP 5 -//#define JOYAXIS_ROLL 6 // Ha ha. No roll for you. +enum EJoyAxis +{ + JOYAXIS_None = -1, + JOYAXIS_Yaw, + JOYAXIS_Pitch, + JOYAXIS_Forward, + JOYAXIS_Side, + JOYAXIS_Up, +// JOYAXIS_Roll, // Ha ha. No roll for you. + NUM_JOYAXIS, +}; // [RH] dmflags bits (based on Q2's) enum diff --git a/src/doomstat.h b/src/doomstat.h index 0b5d6aba..7a130a70 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -207,8 +207,6 @@ EXTERN_CVAR (Bool, developer) extern bool ToggleFullscreen; -extern float JoyAxes[6]; - extern int Net_Arbitrator; EXTERN_CVAR (Bool, var_friction) diff --git a/src/g_game.cpp b/src/g_game.cpp index 8f9b1454..1fae1eea 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -41,6 +41,7 @@ #include "m_random.h" #include "m_crc32.h" #include "i_system.h" +#include "i_input.h" #include "p_saveg.h" #include "p_tick.h" #include "d_main.h" @@ -575,22 +576,39 @@ void G_BuildTiccmd (ticcmd_t *cmd) if (Button_MoveUp.bDown) cmd->ucmd.buttons |= BT_MOVEUP; if (Button_ShowScores.bDown) cmd->ucmd.buttons |= BT_SHOWSCORES; - // [RH] Scale joystick moves to full range of allowed speeds - if (JoyAxes[JOYAXIS_PITCH] != 0) + // Handle joysticks/game controllers. + float joyaxes[NUM_JOYAXIS]; + + I_GetAxes(joyaxes); + + // Remap some axes depending on button state. + if (Button_Strafe.bDown || (Button_Mlook.bDown && lookstrafe)) { - G_AddViewPitch (int((JoyAxes[JOYAXIS_PITCH] * 2048) / 256)); + joyaxes[JOYAXIS_Side] = -joyaxes[JOYAXIS_Yaw]; + joyaxes[JOYAXIS_Yaw] = 0; + } + if (Button_Mlook.bDown) + { + joyaxes[JOYAXIS_Pitch] = joyaxes[JOYAXIS_Forward]; + joyaxes[JOYAXIS_Forward] = 0; + } + + if (joyaxes[JOYAXIS_Pitch] != 0) + { + G_AddViewPitch(int(joyaxes[JOYAXIS_Pitch] * 2048)); LocalKeyboardTurner = true; } - if (JoyAxes[JOYAXIS_YAW] != 0) + if (joyaxes[JOYAXIS_Yaw] != 0) { - G_AddViewAngle (int((-1280 * JoyAxes[JOYAXIS_YAW]) / 256)); + G_AddViewAngle(int(-1280 * joyaxes[JOYAXIS_Yaw])); LocalKeyboardTurner = true; } - side += int((MAXPLMOVE * JoyAxes[JOYAXIS_SIDE]) / 256); - forward += int((JoyAxes[JOYAXIS_FORWARD] * MAXPLMOVE) / 256); - fly += int(JoyAxes[JOYAXIS_UP] * 8); + side += int(MAXPLMOVE * joyaxes[JOYAXIS_Side]); + forward += int(joyaxes[JOYAXIS_Forward] * MAXPLMOVE); + fly += int(joyaxes[JOYAXIS_Up] * 2048); + // Handle mice. if (!Button_Mlook.bDown && !freelook) { forward += (int)((float)mousey * m_forward); @@ -609,6 +627,7 @@ void G_BuildTiccmd (ticcmd_t *cmd) mousex = mousey = 0; + // Build command. if (forward > MAXPLMOVE) forward = MAXPLMOVE; else if (forward < -MAXPLMOVE) diff --git a/src/g_heretic/a_hereticmisc.cpp b/src/g_heretic/a_hereticmisc.cpp index d4ffc879..67f2d4d0 100644 --- a/src/g_heretic/a_hereticmisc.cpp +++ b/src/g_heretic/a_hereticmisc.cpp @@ -173,7 +173,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_VolcanoBlast) blast->momx = FixedMul (1*FRACUNIT, finecosine[angle]); blast->momy = FixedMul (1*FRACUNIT, finesine[angle]); blast->momz = (FRACUNIT*5/2) + (pr_blast() << 10); - S_Sound (blast, CHAN_BODY, "world/self/shoot", 1, ATTN_NORM); + S_Sound (blast, CHAN_BODY, "world/volcano/shoot", 1, ATTN_NORM); P_CheckMissileSpawn (blast); } } diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index 0bd4f6b5..8698c934 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -618,23 +618,30 @@ IMPLEMENT_CLASS(AWeaponGiver) bool AWeaponGiver::TryPickup(AActor *&toucher) { FDropItem *di = GetDropItems(); + AWeapon *weap; if (di != NULL) { const PClass *ti = PClass::FindClass(di->Name); if (ti->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { - AWeapon *weap = static_cast(Spawn(di->Name, 0, 0, 0, NO_REPLACE)); - if (weap != NULL) + if (master == NULL) { - weap->ItemFlags &= ~IF_ALWAYSPICKUP; // use the flag of this item only. - if (weap->AmmoGive1 >= 0) weap->AmmoGive1 = AmmoGive1; - if (weap->AmmoGive2 >= 0) weap->AmmoGive2 = AmmoGive2; - bool res = weap->CallTryPickup(toucher); - if (!res) weap->Destroy(); - else GoAwayAndDie(); - return res; + master = weap = static_cast(Spawn(di->Name, 0, 0, 0, NO_REPLACE)); + if (weap != NULL) + { + weap->ItemFlags &= ~IF_ALWAYSPICKUP; // use the flag of this item only. + if (AmmoGive1 >= 0) weap->AmmoGive1 = AmmoGive1; + if (AmmoGive2 >= 0) weap->AmmoGive2 = AmmoGive2; + weap->BecomeItem(); + } + else return false; } + + weap = barrier_cast(master); + bool res = weap->CallTryPickup(toucher); + if (res) GoAwayAndDie(); + return res; } } return false; diff --git a/src/g_shared/sbarinfo.h b/src/g_shared/sbarinfo.h index bffd1830..91afb8f8 100644 --- a/src/g_shared/sbarinfo.h +++ b/src/g_shared/sbarinfo.h @@ -49,23 +49,21 @@ class FScanner; * This class is used to help prevent errors that may occur from adding or * subtracting from coordinates. * - * In order to provide the maximum flexibility, coordinates can be stored as an - * int with the 31st bit representing REL_CENTER. This class can handle this - * flag. + * In order to provide the maximum flexibility, coordinates are packed into + * an int with one bit reserved for relCenter. */ class SBarInfoCoordinate { public: - static const int REL_CENTER = 0x40000000; - SBarInfoCoordinate() {} SBarInfoCoordinate(int coord, bool relCenter); - SBarInfoCoordinate(int value); SBarInfoCoordinate &Add(int add); int Coordinate() const { return value; } bool RelCenter() const { return relCenter; } - int Value() const { return value | (relCenter ? REL_CENTER : 0); } + void Set(int coord, bool center) { value = coord; relCenter = center; } + void SetCoord(int coord) { value = coord; } + void SetRelCenter(bool center) { relCenter = center; } int operator* () const { return Coordinate(); } SBarInfoCoordinate operator+ (int add) const { return SBarInfoCoordinate(*this).Add(add); } @@ -76,8 +74,8 @@ class SBarInfoCoordinate void operator-= (int sub) { Add(-sub); } protected: - int value; - bool relCenter; + unsigned relCenter:1; + int value:31; }; struct SBarInfoCommand; //we need to be able to use this before it is defined. @@ -171,8 +169,7 @@ struct SBarInfo void ParseSBarInfo(int lump); void ParseSBarInfoBlock(FScanner &sc, SBarInfoBlock &block); void ParseMugShotBlock(FScanner &sc, FMugShotState &state); - void getCoordinates(FScanner &sc, bool fullScreenOffsets, int &x, int &y); //retrieves the next two arguments as x and y. - void getCoordinates(FScanner &sc, bool fullScreenOffsets, SBarInfoCoordinate &x, SBarInfoCoordinate &y); + void getCoordinates(FScanner &sc, bool fullScreenOffsets, SBarInfoCoordinate &x, SBarInfoCoordinate &y); //retrieves the next two arguments as x and y. int getSignedInteger(FScanner &sc); //returns a signed integer. int newImage(const char* patchname); void Init(); diff --git a/src/g_shared/sbarinfo_display.cpp b/src/g_shared/sbarinfo_display.cpp index be78f5d0..1a0527ef 100644 --- a/src/g_shared/sbarinfo_display.cpp +++ b/src/g_shared/sbarinfo_display.cpp @@ -96,15 +96,6 @@ SBarInfoCoordinate::SBarInfoCoordinate(int coord, bool relCenter) : { } -SBarInfoCoordinate::SBarInfoCoordinate(int value) -{ - relCenter = ((value & REL_CENTER) != 0); - if(value < 0) - this->value = (value | REL_CENTER); - else - this->value = (value & (~REL_CENTER)); -} - SBarInfoCoordinate &SBarInfoCoordinate::Add(int add) { value += add; @@ -265,10 +256,13 @@ void DSBarInfo::Draw (EHudState state) { hud = STBAR_NONE; } + bool oldhud_scale = hud_scale; if(script->huds[hud].forceScaled) //scale the statusbar { SetScaled(true, true); setsizeneeded = true; + if(script->huds[hud].fullScreenOffsets) + hud_scale = true; } doCommands(script->huds[hud], 0, 0, script->huds[hud].alpha); if(CPlayer->inventorytics > 0 && !(level.flags & LEVEL_NOINVENTORYBAR)) @@ -301,6 +295,8 @@ void DSBarInfo::Draw (EHudState state) doCommands(script->huds[popbar], script->popups[currentPopup-1].getXOffset(), script->popups[currentPopup-1].getYOffset(), script->popups[currentPopup-1].getAlpha(script->huds[popbar].alpha)); } + if(script->huds[hud].forceScaled && script->huds[hud].fullScreenOffsets) + hud_scale = oldhud_scale; } void DSBarInfo::NewGame () @@ -760,7 +756,7 @@ void DSBarInfo::doCommands(SBarInfoBlock &block, int xOffset, int yOffset, int a { drawingFont = cmd.font; } - DrawNumber(CPlayer->mo->InvSel->Amount, 3, cmd.special2, cmd.special3, xOffset, yOffset, alpha, block.fullScreenOffsets, cmd.translation, cmd.special4, false, !!(cmd.flags & DRAWSELECTEDINVENTORY_DRAWSHADOW)); + DrawNumber(CPlayer->mo->InvSel->Amount, 3, *(SBarInfoCoordinate*)&cmd.special2, *(SBarInfoCoordinate*)&cmd.special3, xOffset, yOffset, alpha, block.fullScreenOffsets, cmd.translation, cmd.special4, false, !!(cmd.flags & DRAWSELECTEDINVENTORY_DRAWSHADOW)); } } else if((cmd.flags & DRAWSELECTEDINVENTORY_ALTERNATEONEMPTY)) @@ -789,7 +785,7 @@ void DSBarInfo::doCommands(SBarInfoBlock &block, int xOffset, int yOffset, int a { drawingFont = cmd.font; } - DrawInventoryBar(cmd.special, cmd.value, cmd.x, cmd.y, xOffset, yOffset, alpha, block.fullScreenOffsets, alwaysshow, cmd.special2, cmd.special3, cmd.translation, artibox, noarrows, alwaysshowcounter, bgalpha); + DrawInventoryBar(cmd.special, cmd.value, cmd.x, cmd.y, xOffset, yOffset, alpha, block.fullScreenOffsets, alwaysshow, *(SBarInfoCoordinate*)&cmd.special2, *(SBarInfoCoordinate*)&cmd.special3, cmd.translation, artibox, noarrows, alwaysshowcounter, bgalpha); break; } case SBARINFO_DRAWBAR: @@ -1203,8 +1199,8 @@ void DSBarInfo::doCommands(SBarInfoBlock &block, int xOffset, int yOffset, int a int tmpX = *x; int tmpY = *y; screen->VirtualToRealCoordsInt(tmpX, tmpY, w, h, 320, 200, true); - x = tmpX; - y = tmpY; + x.SetCoord(tmpX); + y.SetCoord(tmpY); } } else diff --git a/src/g_shared/sbarinfo_parser.cpp b/src/g_shared/sbarinfo_parser.cpp index 6dd1a81a..d0b45514 100644 --- a/src/g_shared/sbarinfo_parser.cpp +++ b/src/g_shared/sbarinfo_parser.cpp @@ -765,12 +765,12 @@ void SBarInfo::ParseSBarInfoBlock(FScanner &sc, SBarInfoBlock &block) sc.MustGetToken(','); } this->getCoordinates(sc, block.fullScreenOffsets, cmd.x, cmd.y); - cmd.special2 = *(cmd.x + 30); - cmd.special3 = *(cmd.y + 24); + *(SBarInfoCoordinate*)&cmd.special2 = cmd.x + 30; + *(SBarInfoCoordinate*)&cmd.special3 = cmd.y + 24; cmd.translation = CR_GOLD; if(sc.CheckToken(',')) //more font information { - this->getCoordinates(sc, block.fullScreenOffsets, cmd.special2, cmd.special3); + this->getCoordinates(sc, block.fullScreenOffsets, *(SBarInfoCoordinate*)&cmd.special2, *(SBarInfoCoordinate*)&cmd.special3); if(sc.CheckToken(',')) { sc.MustGetToken(TK_Identifier); @@ -847,12 +847,12 @@ void SBarInfo::ParseSBarInfoBlock(FScanner &sc, SBarInfoBlock &block) sc.MustGetToken(','); this->getCoordinates(sc, block.fullScreenOffsets, cmd.x, cmd.y); - cmd.special2 = *(cmd.x + 26); - cmd.special3 = *(cmd.y + 22); + *(SBarInfoCoordinate*)&cmd.special2 = cmd.x + 26; + *(SBarInfoCoordinate*)&cmd.special3 = cmd.y + 22; cmd.translation = CR_GOLD; if(sc.CheckToken(',')) //more font information { - this->getCoordinates(sc, block.fullScreenOffsets, cmd.special2, cmd.special3); + this->getCoordinates(sc, block.fullScreenOffsets, *(SBarInfoCoordinate*)&cmd.special2, *(SBarInfoCoordinate*)&cmd.special3); if(sc.CheckToken(',')) { sc.MustGetToken(TK_Identifier); @@ -1346,11 +1346,11 @@ void SBarInfo::ParseMugShotBlock(FScanner &sc, FMugShotState &state) } } -void SBarInfo::getCoordinates(FScanner &sc, bool fullScreenOffsets, int &x, int &y) +void SBarInfo::getCoordinates(FScanner &sc, bool fullScreenOffsets, SBarInfoCoordinate &x, SBarInfoCoordinate &y) { bool negative = false; bool relCenter = false; - int *coords[2] = {&x, &y}; + SBarInfoCoordinate *coords[2] = {&x, &y}; for(int i = 0;i < 2;i++) { negative = false; @@ -1361,7 +1361,7 @@ void SBarInfo::getCoordinates(FScanner &sc, bool fullScreenOffsets, int &x, int // [-]INT center negative = sc.CheckToken('-'); sc.MustGetToken(TK_IntConst); - *coords[i] = negative ? -sc.Number : sc.Number; + coords[i]->Set(negative ? -sc.Number : sc.Number, false); if(sc.CheckToken('+')) { sc.MustGetToken(TK_Identifier); @@ -1371,24 +1371,12 @@ void SBarInfo::getCoordinates(FScanner &sc, bool fullScreenOffsets, int &x, int } if(fullScreenOffsets) { - if(relCenter) - *coords[i] |= SBarInfoCoordinate::REL_CENTER; - else - *coords[i] &= ~SBarInfoCoordinate::REL_CENTER; + coords[i]->SetRelCenter(relCenter); } } if(!fullScreenOffsets) - y = (negative ? -sc.Number : sc.Number) - (200 - this->height); -} - -void SBarInfo::getCoordinates(FScanner &sc, bool fullScreenOffsets, SBarInfoCoordinate &x, SBarInfoCoordinate &y) -{ - int tmpX = *x; - int tmpY = *y; - getCoordinates(sc, fullScreenOffsets, tmpX, tmpY); - x = tmpX; - y = tmpY; + y.SetCoord((negative ? -sc.Number : sc.Number) - (200 - this->height)); } int SBarInfo::getSignedInteger(FScanner &sc) @@ -1497,8 +1485,8 @@ SBarInfoCommand::SBarInfoCommand() //sets the default values for more predicable special3 = 0; special4 = 0; flags = 0; - x = 0; - y = 0; + x.Set(0, 0); + y.Set(0, 0); value = 0; image_index = 0; sprite_index.SetInvalid(); diff --git a/src/m_options.cpp b/src/m_options.cpp index 43a143f7..ef441ddd 100644 --- a/src/m_options.cpp +++ b/src/m_options.cpp @@ -302,6 +302,7 @@ menu_t MouseMenu = *=======================================*/ EXTERN_CVAR (Bool, use_joystick) +#if 0 EXTERN_CVAR (Float, joy_speedmultiplier) EXTERN_CVAR (Int, joy_xaxis) EXTERN_CVAR (Int, joy_yaxis) @@ -325,6 +326,7 @@ EXTERN_CVAR (Float, joy_forwardspeed) EXTERN_CVAR (Float, joy_sidespeed) EXTERN_CVAR (Float, joy_upspeed) EXTERN_CVAR (GUID, joy_guid) +#endif static value_t JoyAxisMapNames[6] = { @@ -344,9 +346,11 @@ static value_t Inversion[2] = static menuitem_t JoystickItems[] = { +#if 0 { discrete, "Enable joystick", {&use_joystick}, {2.0}, {0.0}, {0.0}, {YesNo} }, { discrete_guid,"Active joystick", {&joy_guid}, {0.0}, {0.0}, {0.0}, {NULL} }, { slider, "Overall sensitivity", {&joy_speedmultiplier}, {0.9f}, {2.0}, {0.2f}, {NULL} }, +#endif { redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} }, { whitetext,"Axis Assignments", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} }, { redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} }, @@ -1652,6 +1656,7 @@ int M_FindCurVal (float cur, valuestring_t *values, int numvals) return v; } +#if 0 int M_FindCurGUID (const GUID &guid, GUIDName *values, int numvals) { int v; @@ -1662,6 +1667,7 @@ int M_FindCurGUID (const GUID &guid, GUIDName *values, int numvals) return v; } +#endif const char *M_FindCurVal(const char *cur, valueenum_t *values, int numvals) { @@ -1919,6 +1925,7 @@ void M_OptDrawer () } break; +#if 0 case discrete_guid: { int v, vals; @@ -1939,6 +1946,7 @@ void M_OptDrawer () } break; +#endif case nochoice: screen->DrawText (SmallFont, CR_GOLD, indent + 14, y, @@ -2432,6 +2440,7 @@ void M_OptResponder (event_t *ev) S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); break; +#if 0 case discrete_guid: { int cur; @@ -2446,6 +2455,7 @@ void M_OptResponder (event_t *ev) } S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); break; +#endif case inverter: value = item->a.cvar->GetGenericRep (CVAR_Float); @@ -2581,6 +2591,7 @@ void M_OptResponder (event_t *ev) S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); break; +#if 0 case discrete_guid: { int cur; @@ -2595,6 +2606,7 @@ void M_OptResponder (event_t *ev) } S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); break; +#endif case inverter: value = item->a.cvar->GetGenericRep (CVAR_Float); @@ -3006,6 +3018,7 @@ CCMD (menu_mouse) void UpdateJoystickMenu () { +#if 0 static FIntCVar * const cvars[8] = { &joy_xaxis, &joy_yaxis, &joy_zaxis, @@ -3113,6 +3126,7 @@ void UpdateJoystickMenu () { CalcIndent (&JoystickMenu); } +#endif } static void JoystickOptions () diff --git a/src/m_random.h b/src/m_random.h index 6b00d72a..5b124c50 100644 --- a/src/m_random.h +++ b/src/m_random.h @@ -69,8 +69,8 @@ public: // Returns (rand# & mask) - (rand# & mask) int Random2(int mask) { - int t = GenRand32() & mask; - return t - (GenRand32() & mask); + int t = GenRand32() & mask & 255; + return t - (GenRand32() & mask & 255); } // HITDICE macro used in Heretic and Hexen diff --git a/src/p_slopes.cpp b/src/p_slopes.cpp index 9375b366..0f909873 100644 --- a/src/p_slopes.cpp +++ b/src/p_slopes.cpp @@ -462,7 +462,7 @@ void P_SpawnSlopeMakers (FMapThing *firstmt, FMapThing *lastmt) static void P_AlignPlane (sector_t *sec, line_t *line, int which) { sector_t *refsec; - int bestdist; + double bestdist; vertex_t *refvert = (*sec->lines)->v1; // Shut up, GCC int i; line_t **probe; @@ -471,23 +471,19 @@ static void P_AlignPlane (sector_t *sec, line_t *line, int which) return; // Find furthest vertex from the reference line. It, along with the two ends - // of the line will define the plane. + // of the line, will define the plane. bestdist = 0; for (i = sec->linecount*2, probe = sec->lines; i > 0; i--) { - int dist; + double dist; vertex_t *vert; - // Do calculations with only the upper bits, because the lower ones - // are all zero, and we would overflow for a lot of distances if we - // kept them around. - if (i & 1) vert = (*probe++)->v2; else vert = (*probe)->v1; - dist = abs (((line->v1->y - vert->y) >> FRACBITS) * (line->dx >> FRACBITS) - - ((line->v1->x - vert->x) >> FRACBITS) * (line->dy >> FRACBITS)); + dist = fabs((double(line->v1->y) - vert->y) * line->dx - + (double(line->v1->x) - vert->x) * line->dy); if (dist > bestdist) { diff --git a/src/sdl/i_input.cpp b/src/sdl/i_input.cpp index 4b550b38..78754d19 100644 --- a/src/sdl/i_input.cpp +++ b/src/sdl/i_input.cpp @@ -30,112 +30,7 @@ CVAR (Bool, use_mouse, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Bool, m_noprescale, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Bool, m_filter, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Bool, sdl_nokeyrepeat, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) - -float JoyAxes[6]; -//static int JoyActive; -//static BYTE JoyButtons[128]; -//static BYTE JoyPOV[4]; -static BYTE JoyAxisMap[8]; -static float JoyAxisThresholds[8]; -char *JoyAxisNames[8]; -static const BYTE POVButtons[9] = { 0x01, 0x03, 0x02, 0x06, 0x04, 0x0C, 0x08, 0x09, 0x00 }; - -TArray JoystickNames; -CVAR (Bool, use_joystick, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (GUID, joy_guid, NULL, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL) - -static void MapAxis (FIntCVar &var, int num) -{ - if (var < JOYAXIS_NONE || var > JOYAXIS_UP) - { - var = JOYAXIS_NONE; - } - else - { - JoyAxisMap[num] = var; - } -} - -CUSTOM_CVAR (Int, joy_xaxis, JOYAXIS_YAW, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - MapAxis (self, 0); -} -CUSTOM_CVAR (Int, joy_yaxis, JOYAXIS_FORWARD, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - MapAxis (self, 1); -} -CUSTOM_CVAR (Int, joy_zaxis, JOYAXIS_SIDE, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - MapAxis (self, 2); -} -CUSTOM_CVAR (Int, joy_xrot, JOYAXIS_NONE, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - MapAxis (self, 3); -} -CUSTOM_CVAR (Int, joy_yrot, JOYAXIS_NONE, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - MapAxis (self, 4); -} -CUSTOM_CVAR (Int, joy_zrot, JOYAXIS_PITCH, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - MapAxis (self, 5); -} -CUSTOM_CVAR (Int, joy_slider, JOYAXIS_NONE, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - MapAxis (self, 6); -} -CUSTOM_CVAR (Int, joy_dial, JOYAXIS_NONE, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - MapAxis (self, 7); -} - -CUSTOM_CVAR (Float, joy_xthreshold, 0.15f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - JoyAxisThresholds[0] = clamp (self * 256.f, 0.f, 256.f); -} -CUSTOM_CVAR (Float, joy_ythreshold, 0.15f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - JoyAxisThresholds[1] = clamp (self * 256.f, 0.f, 256.f); -} -CUSTOM_CVAR (Float, joy_zthreshold, 0.15f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - JoyAxisThresholds[2] = clamp (self * 256.f, 0.f, 256.f); -} -CUSTOM_CVAR (Float, joy_xrotthreshold, 0.15f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - JoyAxisThresholds[3] = clamp (self * 256.f, 0.f, 256.f); -} -CUSTOM_CVAR (Float, joy_yrotthreshold, 0.15f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - JoyAxisThresholds[4] = clamp (self * 256.f, 0.f, 256.f); -} -CUSTOM_CVAR (Float, joy_zrotthreshold, 0.15f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - JoyAxisThresholds[5] = clamp (self * 256.f, 0.f, 256.f); -} -CUSTOM_CVAR (Float, joy_sliderthreshold, 0.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - JoyAxisThresholds[6] = clamp (self * 256.f, 0.f, 256.f); -} -CUSTOM_CVAR (Float, joy_dialthreshold, 0.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - JoyAxisThresholds[7] = clamp (self * 256.f, 0.f, 256.f); -} - -CVAR (Float, joy_speedmultiplier,1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (Float, joy_yawspeed, -1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (Float, joy_pitchspeed, -.75f,CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (Float, joy_forwardspeed, -1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (Float, joy_sidespeed, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (Float, joy_upspeed, -1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) - -static FBaseCVar * const JoyConfigVars[] = -{ - &joy_xaxis, &joy_yaxis, &joy_zaxis, &joy_xrot, &joy_yrot, &joy_zrot, &joy_slider, &joy_dial, - &joy_xthreshold, &joy_ythreshold, &joy_zthreshold, &joy_xrotthreshold, &joy_yrotthreshold, &joy_zrotthreshold, &joy_sliderthreshold, &joy_dialthreshold, - &joy_speedmultiplier, &joy_yawspeed, &joy_pitchspeed, &joy_forwardspeed, &joy_sidespeed, - &joy_upspeed -}; +CVAR (Bool, use_joystick, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) EXTERN_CVAR (Bool, fullscreen) @@ -565,3 +460,11 @@ void I_StartFrame () InitKeySymMap (); } } + +void I_GetAxes(float axes[NUM_JOYAXIS]) +{ + for (int i = 0; i < NUM_JOYAXIS; ++i) + { + axes[i] = 0; + } +} diff --git a/src/sdl/i_input.h b/src/sdl/i_input.h index 2551159b..cfbf476d 100644 --- a/src/sdl/i_input.h +++ b/src/sdl/i_input.h @@ -4,16 +4,7 @@ void I_PutInClipboard (const char *str); FString I_GetFromClipboard (bool use_primary_selection); -struct GUIDName -{ - GUID ID; - char *Name; -}; - -extern TArray JoystickNames; -extern char *JoyAxisNames[8]; - -extern void DI_EnumJoy (); +void I_GetAxes(float axes[NUM_JOYAXIS]); #endif diff --git a/src/svnrevision.h b/src/svnrevision.h index 89e4139b..9362aa8c 100644 --- a/src/svnrevision.h +++ b/src/svnrevision.h @@ -3,5 +3,5 @@ // This file was automatically generated by the // updaterevision tool. Do not edit by hand. -#define ZD_SVN_REVISION_STRING "1668" -#define ZD_SVN_REVISION_NUMBER 1668 +#define ZD_SVN_REVISION_STRING "1679" +#define ZD_SVN_REVISION_NUMBER 1679 diff --git a/src/win32/i_dijoy.cpp b/src/win32/i_dijoy.cpp new file mode 100644 index 00000000..a26e1bbc --- /dev/null +++ b/src/win32/i_dijoy.cpp @@ -0,0 +1,1237 @@ +// HEADER FILES ------------------------------------------------------------ + +#define WIN32_LEAN_AND_MEAN +#define DIRECTINPUT_VERSION 0x800 +#define _WIN32_WINNT 0x0501 +#include +#include +#ifndef __GNUC__ +#include +#endif +#include +#include +#include + +#define USE_WINDOWS_DWORD +#include "i_input.h" +#include "i_system.h" +#include "d_event.h" +#include "d_gui.h" +#include "c_cvars.h" +#include "c_dispatch.h" +#include "doomdef.h" +#include "doomstat.h" +#include "win32iface.h" +#include "m_menu.h" +#include "templates.h" +#include "gameconfigfile.h" +#include "cmdlib.h" +#include "v_text.h" +#include "m_argv.h" + +// WBEMIDL BITS -- because w32api doesn't have this, either ----------------- + +#ifdef __GNUC__ +struct IWbemClassObject : public IUnknown +{ +public: + virtual HRESULT __stdcall GetQualifierSet() = 0; + virtual HRESULT __stdcall Get(LPCWSTR wszName, long lFlags, VARIANT *pVal, long *pType, long *plFlavor) = 0; + virtual HRESULT __stdcall Put() = 0; + virtual HRESULT __stdcall Delete() = 0; + virtual HRESULT __stdcall GetNames() = 0; + virtual HRESULT __stdcall BeginEnumeration() = 0; + virtual HRESULT __stdcall Next() = 0; + virtual HRESULT __stdcall EndEnumeration() = 0; + virtual HRESULT __stdcall GetPropertyQualifierSet() = 0; + virtual HRESULT __stdcall Clone() = 0; + virtual HRESULT __stdcall GetObjectText() = 0; + virtual HRESULT __stdcall SpawnDerivedClass() = 0; + virtual HRESULT __stdcall SpawnInstance() = 0; + virtual HRESULT __stdcall CompareTo() = 0; + virtual HRESULT __stdcall GetPropertyOrigin() = 0; + virtual HRESULT __stdcall InheritsFrom() = 0; + virtual HRESULT __stdcall GetMethod() = 0; + virtual HRESULT __stdcall PutMethod() = 0; + virtual HRESULT __stdcall DeleteMethod() = 0; + virtual HRESULT __stdcall BeginMethodEnumeration() = 0; + virtual HRESULT __stdcall NextMethod() = 0; + virtual HRESULT __stdcall EndMethodEnumeration() = 0; + virtual HRESULT __stdcall GetMethodQualifierSet() = 0; + virtual HRESULT __stdcall GetMethodOrigin() = 0; +}; + +struct IEnumWbemClassObject : public IUnknown +{ +public: + virtual HRESULT __stdcall Reset() = 0; + virtual HRESULT __stdcall Next(long lTimeout, ULONG uCount, + IWbemClassObject **apObjects, ULONG *puReturned) = 0; + virtual HRESULT __stdcall NextAsync() = 0; + virtual HRESULT __stdcall Clone() = 0; + virtual HRESULT __stdcall Skip(long lTimeout, ULONG nCount) = 0; +}; + +struct IWbemServices : public IUnknown +{ +public: + virtual HRESULT __stdcall OpenNamespace() = 0; + virtual HRESULT __stdcall CancelAsyncCall() = 0; + virtual HRESULT __stdcall QueryObjectSink() = 0; + virtual HRESULT __stdcall GetObject() = 0; + virtual HRESULT __stdcall GetObjectAsync() = 0; + virtual HRESULT __stdcall PutClass() = 0; + virtual HRESULT __stdcall PutClassAsync() = 0; + virtual HRESULT __stdcall DeleteClass() = 0; + virtual HRESULT __stdcall DeleteClassAsync() = 0; + virtual HRESULT __stdcall CreateClassEnum() = 0; + virtual HRESULT __stdcall CreateClassEnumAsync() = 0; + virtual HRESULT __stdcall PutInstance() = 0; + virtual HRESULT __stdcall PutInstanceAsync() = 0; + virtual HRESULT __stdcall DeleteInstance() = 0; + virtual HRESULT __stdcall DeleteInstanceAsync() = 0; + virtual HRESULT __stdcall CreateInstanceEnum( + const BSTR strFilter, long lFlags, void *pCtx, IEnumWbemClassObject **ppEnum) = 0; + virtual HRESULT __stdcall CreateInstanceEnumAsync() = 0; + virtual HRESULT __stdcall ExecQuery() = 0; + virtual HRESULT __stdcall ExecQueryAsync() = 0; + virtual HRESULT __stdcall ExecNotificationQuery() = 0; + virtual HRESULT __stdcall ExecNotificationQueryAsync() = 0; + virtual HRESULT __stdcall ExecMethod() = 0; + virtual HRESULT __stdcall ExecMethodAsync() = 0; +}; + +struct IWbemLocator : public IUnknown +{ +public: + virtual HRESULT __stdcall ConnectServer( + const BSTR strNetworkResource, + const BSTR strUser, + const BSTR strPassword, + const BSTR strLocale, + long lSecurityFlags, + const BSTR strAuthority, + void *pCtx, + IWbemServices **ppNamespace) = 0; +}; +#endif + +// MACROS ------------------------------------------------------------------ + +// TYPES ------------------------------------------------------------------- + +class FDInputJoystick : public FInputDevice +{ +public: + FDInputJoystick(const GUID *instance, FString &name); + ~FDInputJoystick(); + + bool GetDevice(); + void ProcessInput(); + void AddAxes(float axes[NUM_JOYAXIS]); + void SaveConfig(); + bool LoadConfig(); + FString GetIdentifier(); + void SetDefaultConfig(); + +protected: + struct AxisInfo + { + FString Name; + GUID Guid; + DWORD Type; + DWORD Ofs; + LONG Min, Max; + LONG Value; + float DeadZone; + float Multiplier; + EJoyAxis GameAxis; + }; + struct ButtonInfo + { + FString Name; + GUID Guid; + DWORD Type; + DWORD Ofs; + BYTE Value; + }; + + LPDIRECTINPUTDEVICE8 Device; + GUID Instance; + FString Name; + bool Marked; + float Multiplier; + int Warmup; + TArray Axes; + TArray Buttons; + TArray POVs; + + DIOBJECTDATAFORMAT *Objects; + DIDATAFORMAT DataFormat; + + static BOOL CALLBACK EnumObjectsCallback(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef); + void OrderAxes(); + bool ReorderAxisPair(const GUID &x, const GUID &y, int pos); + HRESULT SetDataFormat(); + bool SetConfigSection(bool create); + + friend class FDInputJoystickManager; +}; + +class FDInputJoystickManager : public FJoystickCollection +{ +public: + FDInputJoystickManager(); + ~FDInputJoystickManager(); + + bool GetDevice(); + void ProcessInput(); + bool WndProcHook(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result); + void AddAxes(float axes[NUM_JOYAXIS]); + +protected: + struct Enumerator + { + GUID Instance; + FString Name; + }; + TArray Devices; + + void EnumDevices(); + + static BOOL CALLBACK EnumCallback(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef); + static int STACK_ARGS NameSort(const void *a, const void *b); + static int STACK_ARGS GUIDSort(const void *a, const void *b); + static bool IsXInputDevice(const GUID *guid); +}; + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +extern void UpdateJoystickMenu(); + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +static void MapAxis(FIntCVar &var, int num); + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- + +extern menu_t JoystickMenu; +extern LPDIRECTINPUT8 g_pdi; +extern HWND Window; + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +CVAR (Bool, use_joystick, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +FJoystickCollection *JoyDevices[NUM_JOYDEVICES]; + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +static const BYTE POVButtons[9] = { 0x01, 0x03, 0x02, 0x06, 0x04, 0x0C, 0x08, 0x09, 0x00 }; + +//("dc12a687-737f-11cf-884d-00aa004b2e24") +static const IID IID_IWbemLocator = { 0xdc12a687, 0x737f, 0x11cf, + { 0x88, 0x4d, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24 } }; + +//("4590f811-1d3a-11d0-891f-00aa004b2e24") +static const CLSID CLSID_WbemLocator = { 0x4590f811, 0x1d3a, 0x11d0, + { 0x89, 0x1f, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24 } }; + +// CODE -------------------------------------------------------------------- + +//=========================================================================== +// +// FDInputJoystick - Constructor +// +//=========================================================================== + +FDInputJoystick::FDInputJoystick(const GUID *instance, FString &name) +{ + Device = NULL; + DataFormat.rgodf = NULL; + Instance = *instance; + Name = name; + Marked = false; +} + +//=========================================================================== +// +// FDInputJoystick - Destructor +// +//=========================================================================== + +FDInputJoystick::~FDInputJoystick() +{ + SAFE_RELEASE(Device); + if (DataFormat.rgodf != NULL) + { + delete[] DataFormat.rgodf; + } +} + +//=========================================================================== +// +// FDInputJoystick :: GetDevice +// +//=========================================================================== + +bool FDInputJoystick::GetDevice() +{ + HRESULT hr; + + if (g_pdi == NULL) + { + return false; + } + hr = g_pdi->CreateDevice(Instance, &Device, NULL); + if (FAILED(hr) || Device == NULL) + { + return false; + } + hr = Device->EnumObjects(EnumObjectsCallback, this, DIDFT_ABSAXIS | DIDFT_BUTTON | DIDFT_POV); + OrderAxes(); + hr = SetDataFormat(); + if (FAILED(hr)) + { + Printf(TEXTCOLOR_ORANGE "Setting data format for %s failed.\n", Name.GetChars()); + return false; + } + hr = Device->SetCooperativeLevel(Window, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND); + if (FAILED(hr)) + { + Printf(TEXTCOLOR_ORANGE "Setting cooperative level for %s failed.\n", Name.GetChars()); + return false; + } + Device->Acquire(); + LoadConfig(); + Warmup = 4; + return true; +} + +//=========================================================================== +// +// FDInputJoystick :: ProcessInput +// +// Send button events and record axes for later. +// +//=========================================================================== + +void FDInputJoystick::ProcessInput() +{ + HRESULT hr; + BYTE *state; + unsigned i; + event_t ev; + + if (Device == NULL) + { + return; + } + + hr = Device->Poll(); + if (hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED) + { + hr = Device->Acquire(); + } + if (FAILED(hr)) + { + return; + } + + state = (BYTE *)alloca(DataFormat.dwDataSize); + hr = Device->GetDeviceState(DataFormat.dwDataSize, state); + if (FAILED(hr)) + return; + + // Some controllers send false values when they are first + // initialized, so give some time for them to get past that + // before we pay any attention to their state. + if (Warmup > 0) + { + Warmup--; + return; + } + + // Copy axis values. They will be returned in a separate call. + for (i = 0; i < Axes.Size(); ++i) + { + AxisInfo *info = &Axes[i]; + info->Value = *(LONG *)(state + info->Ofs); + } + + // Compare button states and generate events for buttons that have changed. + memset(&ev, 0, sizeof(ev)); + for (i = 0; i < Buttons.Size(); ++i) + { + ButtonInfo *info = &Buttons[i]; + BYTE newstate = *(BYTE *)(state + info->Ofs) & 0x80; + if (newstate != info->Value) + { + info->Value = newstate; + ev.data1 = KEY_FIRSTJOYBUTTON + i; + ev.type = (newstate != 0) ? EV_KeyDown : EV_KeyUp; + D_PostEvent(&ev); + } + } + + // POV hats are treated as a set of four buttons, because if it's a + // D-pad, that's exactly what it is. + for (i = 0; i < POVs.Size(); ++i) + { + ButtonInfo *info = &POVs[i]; + DWORD povangle = *(DWORD *)(state + info->Ofs); + int pov, changed; + + // Smoosh POV angles down into octants. 8 is centered. + pov = (LOWORD(povangle) == 0xFFFF) ? 8 : ((povangle + 2250) % 36000) / 4500; + + // Convert octant to one or two buttons needed to represent it. + pov = POVButtons[pov]; + + // Send events for POV "buttons" that have changed. + changed = pov ^ info->Value; + if (changed != 0) + { + int j, mask; + info->Value = pov; + mask = 1; + for (j = 0; j < 4; mask <<= 1, ++j) + { + if (changed & mask) + { + ev.data1 = KEY_JOYPOV1_UP + i*4 + j; + ev.type = (pov & mask) ? EV_KeyDown : EV_KeyUp; + D_PostEvent(&ev); + } + } + } + } +} + +//=========================================================================== +// +// FDInputJoystick :: AddAxes +// +// Add the values of each axis to the game axes. +// +//=========================================================================== + +void FDInputJoystick::AddAxes(float axes[NUM_JOYAXIS]) +{ + float mul = Multiplier; + if (Button_Speed.bDown) + { + mul *= 0.5f; + } + + for (unsigned i = 0; i < Axes.Size(); ++i) + { + double axisval = Axes[i].Value; + float deadzone = Axes[i].DeadZone; + + // Scale to [-1.0, 1.0] + axisval = (Axes[i].Value - Axes[i].Min) * 2.0 / (Axes[i].Max - Axes[i].Min) - 1.0; + // Cancel out dead zone + if (fabs(axisval) < deadzone) + { + continue; + } + // Make the dead zone the new 0 + if (axisval < 0) + { + axisval = (axisval + deadzone) / (1.0 - deadzone); + } + else + { + axisval = (axisval - deadzone) / (1.0 - deadzone); + } + // Add to the game axis. + axes[Axes[i].GameAxis] += float(axisval * mul * Axes[i].Multiplier); + } +} + +//=========================================================================== +// +// FDInputJoystick :: EnumObjectsCallback STATIC +// +// Finds all axes, buttons, and hats on the controller. +// +//=========================================================================== + +BOOL CALLBACK FDInputJoystick::EnumObjectsCallback(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef) +{ + FDInputJoystick *joy = (FDInputJoystick *)pvRef; + + if (lpddoi->guidType == GUID_Button) + { + ButtonInfo info; + info.Name = lpddoi->tszName; + info.Guid = lpddoi->guidType; + info.Type = lpddoi->dwType; + info.Ofs = 0; + info.Value = 0; + // We don't have the key labels necessary to support more than 128 + // joystick buttons. This is what DIJOYSTATE2 offers, so we + // probably don't need to worry about any devices with more than + // that. + if (joy->Buttons.Size() < 128) + { + joy->Buttons.Push(info); + } + } + else if (lpddoi->guidType == GUID_POV) + { + ButtonInfo info; + info.Name = lpddoi->tszName; + info.Guid = lpddoi->guidType; + info.Type = lpddoi->dwType; + info.Ofs = 0; + info.Value = 0; + // We don't have the key labels necessary to support more than 4 + // hats. I don't know any devices with more than 1, and the + // standard DirectInput DIJOYSTATE does not support more than 4 + // hats either, so this is probably a non-issue. + if (joy->POVs.Size() < 4) + { + joy->POVs.Push(info); + } + } + else + if (lpddoi->guidType == GUID_XAxis || + lpddoi->guidType == GUID_YAxis || + lpddoi->guidType == GUID_ZAxis || + lpddoi->guidType == GUID_RxAxis || + lpddoi->guidType == GUID_RyAxis || + lpddoi->guidType == GUID_RzAxis || + lpddoi->guidType == GUID_Slider) + { + DIPROPRANGE diprg; + AxisInfo info; + + diprg.diph.dwSize = sizeof(DIPROPRANGE); + diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER); + diprg.diph.dwObj = lpddoi->dwType; + diprg.diph.dwHow = DIPH_BYID; + diprg.lMin = 0; + diprg.lMax = 0; + joy->Device->GetProperty(DIPROP_RANGE, &diprg.diph); + + info.Name = lpddoi->tszName; + info.Guid = lpddoi->guidType; + info.Type = lpddoi->dwType; + info.Ofs = 0; + info.Min = diprg.lMin; + info.Max = diprg.lMax; + info.GameAxis = JOYAXIS_None; + info.Value = (diprg.lMin + diprg.lMax) / 2; + joy->Axes.Push(info); + } + return DIENUM_CONTINUE; +} + +//=========================================================================== +// +// FDInputJoystick :: OrderAxes +// +// Try to put the axes in some sort of sane order. X and Y axes are pretty +// much standard. Unfortunately, the rest are entirely up to the +// manufacturers to decide how they want to assign them. +// +//=========================================================================== + +void FDInputJoystick::OrderAxes() +{ + // Make X,Y the first pair. + if (!ReorderAxisPair(GUID_XAxis, GUID_YAxis, 0)) + { + return; + } + // The second pair is either Rx,Ry or Rz,Z, depending on what we have + if (!ReorderAxisPair(GUID_RxAxis, GUID_RyAxis, 2)) + { + ReorderAxisPair(GUID_RzAxis, GUID_ZAxis, 2); + } +} + +bool FDInputJoystick::ReorderAxisPair(const GUID &xid, const GUID &yid, int pos) +{ + unsigned i; + int x, y; + + // Find each axis. + x = -1; + y = -1; + for (i = 0; i < Axes.Size(); ++i) + { + if (x < 0 && Axes[i].Guid == xid) + { + x = i; + } + else if (y < 0 && Axes[i].Guid == yid) + { + y = i; + } + } + // If we don't have both X and Y axes, do nothing. + if (x < 0 || y < 0) + { + return false; + } + if (x == pos + 1 && y == pos) + { // Xbox 360 Controllers return them in this order. + swap(Axes[pos], Axes[pos + 1]); + } + else if (x != pos || y != pos + 1) + { + AxisInfo xinfo = Axes[x], yinfo = Axes[y]; + Axes.Delete(x); + if (x < y) + { + y--; + } + Axes.Delete(y); + Axes.Insert(pos, xinfo); + Axes.Insert(pos + 1, yinfo); + } + return true; +} + +//=========================================================================== +// +// FDInputJoystick :: SetDataFormat +// +// Using the objects we previously enumerated, construct a data format +// structure for DirectInput to use for this device. We could use the +// predefined c_dfDIJoystick2, except that we would have no way of knowing +// which axis mapped to a certain point in the structure if there is more +// than one of a particular type of axis. The dwOfs member of +// DIDEVICEOBJECTINSTANCE is practically useless, because it describes the +// offset of the object in the device's native data format, and not +// the offset in something we can actually use. +// +//=========================================================================== + +HRESULT FDInputJoystick::SetDataFormat() +{ + DIOBJECTDATAFORMAT *objects; + DWORD numobjs; + DWORD nextofs; + unsigned i; + + objects = new DIOBJECTDATAFORMAT[Axes.Size() + POVs.Size() + Buttons.Size()]; + numobjs = nextofs = 0; + + // Add all axes + for (i = 0; i < Axes.Size(); ++i) + { + objects[i].pguid = &Axes[i].Guid; + objects[i].dwOfs = Axes[i].Ofs = nextofs; + objects[i].dwType = Axes[i].Type; + objects[i].dwFlags = 0; + nextofs += sizeof(LONG); + } + numobjs = i; + // Add all POVs + for (i = 0; i < POVs.Size(); ++i) + { + objects[numobjs + i].pguid = &POVs[i].Guid; + objects[numobjs + i].dwOfs = POVs[i].Ofs = nextofs; + objects[numobjs + i].dwType = POVs[i].Type; + objects[numobjs + i].dwFlags = 0; + nextofs += sizeof(DWORD); + } + numobjs += i; + // Add all buttons + for (i = 0; i < Buttons.Size(); ++i) + { + objects[numobjs + i].pguid = &Buttons[i].Guid; + objects[numobjs + i].dwOfs = Buttons[i].Ofs = nextofs; + objects[numobjs + i].dwType = Buttons[i].Type; + objects[numobjs + i].dwFlags = 0; + nextofs += sizeof(BYTE); + } + numobjs += i; + + // Set format + DataFormat.dwSize = sizeof(DIDATAFORMAT); + DataFormat.dwObjSize = sizeof(DIOBJECTDATAFORMAT); + DataFormat.dwFlags = DIDF_ABSAXIS; + DataFormat.dwDataSize = (nextofs + 3) & ~3; // Round to the nearest multiple of 4. + DataFormat.dwNumObjs = numobjs; + DataFormat.rgodf = objects; + return Device->SetDataFormat(&DataFormat); +} + +//=========================================================================== +// +// FDInputJoystick :: GetIdentifier +// +//=========================================================================== + +FString FDInputJoystick::GetIdentifier() +{ + char id[48]; + + id[0] = 'D'; id[1] = 'I'; id[2] = ':'; + FormatGUID(id + 3, countof(id) - 3, Instance); + return id; +} + +//=========================================================================== +// +// FDInputJoystick :: SetConfigSection +// +// Sets up the config for reading or writing this controller's axis config. +// +//=========================================================================== + +bool FDInputJoystick::SetConfigSection(bool create) +{ + FString id = GetIdentifier(); + id += ".Axes"; + return GameConfig->SetSection(id, create); + DIDEVICEINSTANCE inst = { sizeof(DIDEVICEINSTANCE), }; +} + +//=========================================================================== +// +// FDInputJoystick :: LoadConfig +// +//=========================================================================== + +bool FDInputJoystick::LoadConfig() +{ + char key[32]; + const char *value; + int axislen; + + SetDefaultConfig(); + if (!SetConfigSection(false)) + { + return false; + } + value = GameConfig->GetValueForKey("Multiplier"); + if (value != NULL) + { + Multiplier = (float)atof(value); + } + for (unsigned i = 0; i < Axes.Size(); ++i) + { + axislen = mysnprintf(key, countof(key), "Axis%u", i); + + mysnprintf(key + axislen, countof(key) - axislen, "deadzone"); + value = GameConfig->GetValueForKey(key); + if (value != NULL) + { + Axes[i].DeadZone = (float)atof(value); + } + mysnprintf(key + axislen, countof(key) - axislen, "multiplier"); + value = GameConfig->GetValueForKey(key); + if (value != NULL) + { + Axes[i].Multiplier = (float)atof(value); + } + mysnprintf(key + axislen, countof(key) - axislen, "gameaxis"); + value = GameConfig->GetValueForKey(key); + if (value != NULL) + { + Axes[i].GameAxis = (EJoyAxis)atoi(value); + if (Axes[i].GameAxis < JOYAXIS_None || Axes[i].GameAxis >= NUM_JOYAXIS) + { + Axes[i].GameAxis = JOYAXIS_None; + } + } + } + return true; +} + +//=========================================================================== +// +// FDInputJoystick :: SaveConfig +// +//=========================================================================== + +void FDInputJoystick::SaveConfig() +{ + char key[32], value[32]; + int axislen; + + if (SetConfigSection(true)) + { + GameConfig->ClearCurrentSection(); + mysnprintf(value, countof(value), "%g", Multiplier); + GameConfig->SetValueForKey("Multiplier", value); + for (unsigned i = 0; i < Axes.Size(); ++i) + { + axislen = mysnprintf(key, countof(key), "Axis%u", i); + + mysnprintf(key + axislen, countof(key) - axislen, "deadzone"); + mysnprintf(value, countof(value), "%g", Axes[i].DeadZone); + GameConfig->SetValueForKey(key, value); + mysnprintf(key + axislen, countof(key) - axislen, "multiplier"); + mysnprintf(value, countof(value), "%g", Axes[i].Multiplier); + GameConfig->SetValueForKey(key, value); + mysnprintf(key + axislen, countof(key) - axislen, "gameaxis"); + mysnprintf(value, countof(value), "%d", Axes[i].GameAxis); + GameConfig->SetValueForKey(key, value); + } + } +} + +//=========================================================================== +// +// FDInputJoystick :: SetDefaultConfig +// +// Try for a reasonable default axis configuration. +// +//=========================================================================== + +void FDInputJoystick::SetDefaultConfig() +{ + Multiplier = 1; + for (unsigned i = 0; i < Axes.Size(); ++i) + { + Axes[i].DeadZone = 0.25f; + Axes[i].Multiplier = 1; + } + // Triggers on a 360 controller have a much smaller deadzone. + if (Axes.Size() == 5 && Axes[4].Guid == GUID_ZAxis) + { + Axes[4].DeadZone = 30 / 32768.f; + } + // Two axes? Horizontal is yaw and vertical is forward. + if (Axes.Size() == 2) + { + Axes[0].GameAxis = JOYAXIS_Yaw; Axes[0].Multiplier = -1; + Axes[1].GameAxis = JOYAXIS_Forward; + } + // Three axes? First two are movement, third is yaw. + else if (Axes.Size() >= 3) + { + Axes[0].GameAxis = JOYAXIS_Side; + Axes[1].GameAxis = JOYAXIS_Forward; Axes[1].Multiplier = -1; + Axes[2].GameAxis = JOYAXIS_Yaw; Axes[2].Multiplier = -1; + // Four axes? First two are movement, last two are looking around. + if (Axes.Size() >= 4) + { + Axes[3].GameAxis = JOYAXIS_Pitch; Axes[3].Multiplier = -0.75f; + // Five axes? Use the fifth one for moving up and down. + if (Axes.Size() >= 5) + { + Axes[4].GameAxis = JOYAXIS_Up; Axes[4].Multiplier = -1; + } + } + } + // If there is only one axis, then we make no assumptions about how + // the user might want to use it. +} + +//=========================================================================== +// +// FDInputJoystickManager - Constructor +// +//=========================================================================== + +FDInputJoystickManager::FDInputJoystickManager() +{ +} + +//=========================================================================== +// +// FDInputJoystickManager - Destructor +// +//=========================================================================== + +FDInputJoystickManager::~FDInputJoystickManager() +{ + for (unsigned i = 0; i < Devices.Size(); ++i) + { + delete Devices[i]; + } +} + +//=========================================================================== +// +// FDInputJoystickManager :: GetDevice +// +//=========================================================================== + +bool FDInputJoystickManager::GetDevice() +{ + if (g_pdi == NULL || !use_joystick || Args->CheckParm("-nojoy")) + { + return false; + } + EnumDevices(); + return true; +} + +//=========================================================================== +// +// FDInputJoystickManager :: ProcessInput +// +// Process input for every attached device. +// +//=========================================================================== + +void FDInputJoystickManager::ProcessInput() +{ + for (unsigned i = 0; i < Devices.Size(); ++i) + { + if (Devices[i] != NULL) + { + Devices[i]->ProcessInput(); + } + } +} + +//=========================================================================== +// +// FDInputJoystickManager :: AddAxes +// +// Adds the state of all attached device axes to the passed array. +// +//=========================================================================== + +void FDInputJoystickManager :: AddAxes(float axes[NUM_JOYAXIS]) +{ + for (unsigned i = 0; i < Devices.Size(); ++i) + { + Devices[i]->AddAxes(axes); + } +} + +//=========================================================================== +// +// 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 || + (wParam != DBT_DEVNODES_CHANGED && + wParam != DBT_DEVICEARRIVAL && + wParam != DBT_CONFIGCHANGED)) + { + return false; + } + EnumDevices(); +#if 0 + unsigned int i; + TArray oldjoys; + + for (i = 0; i < JoystickNames.Size(); ++i) + { + oldjoys.Push (JoystickNames[i].ID); + } + + DI_EnumJoy (); + + // If a new joystick was added and the joystick menu is open, + // switch to it. + if (menuactive != MENU_Off && CurrentMenu == &JoystickMenu) + { + for (i = 0; i < JoystickNames.Size(); ++i) + { + bool wasListed = false; + + for (unsigned int j = 0; j < oldjoys.Size(); ++j) + { + if (oldjoys[j] == JoystickNames[i].ID) + { + wasListed = true; + break; + } + } + if (!wasListed) + { + joy_guid = JoystickNames[i].ID; + break; + } + } + } + + // If the current joystick was removed, + // try to switch to a different one. + if (g_pJoy != NULL) + { + DIDEVICEINSTANCE inst = { sizeof(DIDEVICEINSTANCE), }; + + if (SUCCEEDED(g_pJoy->GetDeviceInfo (&inst))) + { + for (i = 0; i < JoystickNames.Size(); ++i) + { + if (JoystickNames[i].ID == inst.guidInstance) + { + break; + } + } + if (i == JoystickNames.Size ()) + { + DI_InitJoy (); + } + } + } + else + { + DI_InitJoy (); + } + UpdateJoystickMenu (); +#endif + // Return false so that other devices can handle this too if they want. + return false; +} + +//=========================================================================== +// +// FDInputJoystickManager :: EnumCallback STATIC +// +// Adds each DirectInput game controller to a TArray. +// +//=========================================================================== + +BOOL CALLBACK FDInputJoystickManager::EnumCallback(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef) +{ + TArray *all = (TArray *)pvRef; + Enumerator thisone; + + thisone.Instance = lpddi->guidInstance; + thisone.Name = lpddi->tszInstanceName; + all->Push(thisone); + return DIENUM_CONTINUE; +} + +//=========================================================================== +// +// 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. +// +//=========================================================================== + +bool FDInputJoystickManager::IsXInputDevice(const GUID *guid) +{ + IWbemLocator *wbemlocator = NULL; + IEnumWbemClassObject *enumdevices = NULL; + IWbemClassObject *devices[20] = { 0 }; + IWbemServices *wbemservices = NULL; + BSTR namespce = NULL; + BSTR deviceid = NULL; + BSTR classname = NULL; + DWORD returned = 0; + bool isxinput = false; + UINT device = 0; + VARIANT var; + HRESULT hr; + + // Create WMI + hr = CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&wbemlocator); + if (FAILED(hr) || wbemlocator == NULL) + goto cleanup; + + if (NULL == (namespce = SysAllocString(OLESTR("\\\\.\\root\\cimv2")))) goto cleanup; + if (NULL == (classname = SysAllocString(OLESTR("Win32_PNPEntity")))) goto cleanup; + if (NULL == (deviceid = SysAllocString(OLESTR("DeviceID")))) goto cleanup; + + // Connect to WMI + hr = wbemlocator->ConnectServer(namespce, NULL, NULL, 0, 0, NULL, NULL, &wbemservices); + if (FAILED(hr) || wbemservices == NULL) + goto cleanup; + + // Switch security level to IMPERSONATE. + CoSetProxyBlanket(wbemservices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, + RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE); + + hr = wbemservices->CreateInstanceEnum(classname, 0, NULL, &enumdevices); + if (FAILED(hr) || enumdevices == NULL) + goto cleanup; + + // Loop over all devices + for (;;) + { + // Get 20 at a time. + hr = enumdevices->Next(10000, countof(devices), devices, &returned); + if (FAILED(hr)) + goto cleanup; + if (returned == 0) + break; + + for (device = 0; device < returned; device++) + { + // For each device, get its device ID. + hr = devices[device]->Get(deviceid, 0L, &var, NULL, NULL); + if (SUCCEEDED(hr) && var.vt == VT_BSTR && var.bstrVal != NULL) + { + // Check if the device ID contains "IG_". If it does, then it's an XInput device. + // This information cannot be found from DirectInput. + if (wcsstr(var.bstrVal, L"IG_")) + { + // If it does, then get the VID/PID from var.bstrVal. + DWORD pid = 0, vid = 0; + WCHAR *strvid = wcsstr(var.bstrVal, L"VID_"); + if (strvid && swscanf(strvid, L"VID_%4X", &vid) != 1) + vid = 0; + WCHAR *strpid = wcsstr(var.bstrVal, L"PID_"); + if (strpid && swscanf(strpid, L"PID_%4X", &pid) != 1) + pid = 0; + + // Compare the VID/PID to the DInput device. + DWORD vidpid = MAKELONG(vid, pid); + if (vidpid == guid->Data1) + { + isxinput = true; + goto cleanup; + } + } + } + SAFE_RELEASE(devices[device]); + } + } + +cleanup: + if (namespce) SysFreeString(namespce); + if (deviceid) SysFreeString(deviceid); + if (classname) SysFreeString(classname); + for (device = 0; device < countof(devices); ++device) + SAFE_RELEASE(devices[device]); + SAFE_RELEASE(enumdevices); + SAFE_RELEASE(wbemlocator); + SAFE_RELEASE(wbemservices); + return isxinput; +} + +//=========================================================================== +// +// FDInputJoystickManager :: NameSort STATIC +// +//=========================================================================== + +int FDInputJoystickManager::NameSort(const void *a, const void *b) +{ + const Enumerator *ea = (const Enumerator *)a; + const Enumerator *eb = (const Enumerator *)b; + int lex = ea->Name.Compare(eb->Name); + if (lex == 0) + { + return memcmp(&ea->Instance, &eb->Instance, sizeof(GUID)); + } + return lex; +} + +//=========================================================================== +// +// FDInputJoystickManager :: EnumDevices +// +// Find out what DirectInput game controllers are on the system and create +// FDInputJoystick objects for them. +// +//=========================================================================== + +void FDInputJoystickManager::EnumDevices() +{ + TArray controllers; + unsigned i, j, k; + + g_pdi->EnumDevices(DI8DEVCLASS_GAMECTRL, EnumCallback, &controllers, DIEDFL_ALLDEVICES); + + // Sort by name so that devices with duplicate names can have numbers appended. + qsort(&controllers[0], controllers.Size(), sizeof(Enumerator), NameSort); + for (i = 1; i < controllers.Size(); ++i) + { + // Does this device have the same name as the previous one? If so, how + // many more have the same name? + for (j = i; j < controllers.Size(); ++j) + { + if (controllers[j-1].Name.Compare(controllers[j].Name) != 0) + break; + } + // j is one past the last duplicate name. + if (j > i) + { + // Append numbers. + for (k = i - 1; k < j; ++k) + { + controllers[k].Name.AppendFormat(" %d", k - i - 2); + } + } + } + + // Compare the new list of devices with the one we previously instantiated. + // Every device we currently hold is marked 0. Then scan through the new + // list and try to find it there, if it's found, it is marked 1. At the end + // of this, devices marked 1 existed before and are left alone. Devices + // marked 0 are no longer present and should be destroyed. If a device is + // present in the new list that we have not yet instantiated, we + // instantiate it now. + for (j = 0; j < Devices.Size(); ++j) + { + Devices[j]->Marked = false; + } + for (i = 0; i < controllers.Size(); ++i) + { + GUID *lookfor = &controllers[i].Instance; + for (j = 0; j < Devices.Size(); ++j) + { + if (Devices[j]->Instance == *lookfor) + { + Devices[j]->Marked = true; + break; + } + } + if (j == Devices.Size()) + { // Not found. Add it. + FDInputJoystick *device = new FDInputJoystick(lookfor, controllers[i].Name); + if (!device->GetDevice()) + { + delete device; + } + else + { + device->Marked = true; + Devices.Push(device); + } + } + } + // Remove detached devices and avoid holes in the list. + for (i = j = 0; j < Devices.Size(); ++j) + { + if (!Devices[j]->Marked) + { + delete Devices[j]; + } + else + { + if (i != j) + { + Devices[i] = Devices[j]; + } + ++i; + } + } + Devices.Resize(i); +} + +//=========================================================================== +// +// I_StartupJoystick +// +//=========================================================================== + +void I_StartupJoystick() +{ + FJoystickCollection *joys = new FDInputJoystickManager; + if (joys->GetDevice()) + { + JoyDevices[INPUT_DIJoy] = joys; + } +} diff --git a/src/win32/i_input.cpp b/src/win32/i_input.cpp index f434c680..d99fc5cb 100644 --- a/src/win32/i_input.cpp +++ b/src/win32/i_input.cpp @@ -3,7 +3,7 @@ ** Handles input from keyboard, mouse, and joystick ** **--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit +** Copyright 1998-2009 Randy Heit ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without @@ -47,8 +47,8 @@ #endif #include #include -#include #include +#include #include #include @@ -128,8 +128,6 @@ extern bool SpawnEAXWindow; static HMODULE DInputDLL; -static HRESULT InitJoystick (); - bool GUICapture; extern FMouse *Mouse; extern FKeyboard *Keyboard; @@ -141,11 +139,9 @@ extern BOOL vidactive; extern HWND Window, ConWindow; extern HWND EAXEditWindow; -extern void UpdateJoystickMenu (); -extern menu_t JoystickMenu; - EXTERN_CVAR (String, language) EXTERN_CVAR (Bool, lookstrafe) +EXTERN_CVAR (Bool, use_joystick) static int WheelDelta; @@ -155,151 +151,12 @@ static bool noidle = false; LPDIRECTINPUT8 g_pdi; LPDIRECTINPUT g_pdi3; -static LPDIRECTINPUTDEVICE8 g_pJoy; - -TArray JoystickNames; - -static DIDEVCAPS JoystickCaps; - -float JoyAxes[6]; -static int JoyActive; -static BYTE JoyButtons[128]; -static BYTE JoyPOV[4]; -static BYTE JoyAxisMap[8]; -static float JoyAxisThresholds[8]; -char *JoyAxisNames[8]; -static const size_t Axes[8] = -{ - myoffsetof(DIJOYSTATE2,lX), - myoffsetof(DIJOYSTATE2,lY), - myoffsetof(DIJOYSTATE2,lZ), - myoffsetof(DIJOYSTATE2,lRx), - myoffsetof(DIJOYSTATE2,lRy), - myoffsetof(DIJOYSTATE2,lRz), - myoffsetof(DIJOYSTATE2,rglSlider[0]), - myoffsetof(DIJOYSTATE2,rglSlider[1]) -}; -static const BYTE POVButtons[9] = { 0x01, 0x03, 0x02, 0x06, 0x04, 0x0C, 0x08, 0x09, 0x00 }; BOOL AppActive = TRUE; int SessionState = 0; -CVAR (Bool, use_joystick, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) - -CUSTOM_CVAR (GUID, joy_guid, NULL, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL) -{ - if (g_pJoy != NULL) - { - DIDEVICEINSTANCE inst = { sizeof(DIDEVICEINSTANCE), }; - - if (SUCCEEDED(g_pJoy->GetDeviceInfo (&inst)) && self != inst.guidInstance) - { - DI_InitJoy (); - UpdateJoystickMenu (); - } - } - else - { - DI_InitJoy (); - UpdateJoystickMenu (); - } -} - -static void MapAxis (FIntCVar &var, int num) -{ - if (var < JOYAXIS_NONE || var > JOYAXIS_UP) - { - var = JOYAXIS_NONE; - } - else - { - JoyAxisMap[num] = var; - } -} - -CUSTOM_CVAR (Int, joy_xaxis, JOYAXIS_YAW, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - MapAxis (self, 0); -} -CUSTOM_CVAR (Int, joy_yaxis, JOYAXIS_FORWARD, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - MapAxis (self, 1); -} -CUSTOM_CVAR (Int, joy_zaxis, JOYAXIS_SIDE, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - MapAxis (self, 2); -} -CUSTOM_CVAR (Int, joy_xrot, JOYAXIS_NONE, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - MapAxis (self, 3); -} -CUSTOM_CVAR (Int, joy_yrot, JOYAXIS_NONE, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - MapAxis (self, 4); -} -CUSTOM_CVAR (Int, joy_zrot, JOYAXIS_PITCH, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - MapAxis (self, 5); -} -CUSTOM_CVAR (Int, joy_slider, JOYAXIS_NONE, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - MapAxis (self, 6); -} -CUSTOM_CVAR (Int, joy_dial, JOYAXIS_NONE, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - MapAxis (self, 7); -} - -CUSTOM_CVAR (Float, joy_xthreshold, 0.15f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - JoyAxisThresholds[0] = clamp (self * 256.f, 0.f, 256.f); -} -CUSTOM_CVAR (Float, joy_ythreshold, 0.15f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - JoyAxisThresholds[1] = clamp (self * 256.f, 0.f, 256.f); -} -CUSTOM_CVAR (Float, joy_zthreshold, 0.15f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - JoyAxisThresholds[2] = clamp (self * 256.f, 0.f, 256.f); -} -CUSTOM_CVAR (Float, joy_xrotthreshold, 0.15f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - JoyAxisThresholds[3] = clamp (self * 256.f, 0.f, 256.f); -} -CUSTOM_CVAR (Float, joy_yrotthreshold, 0.15f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - JoyAxisThresholds[4] = clamp (self * 256.f, 0.f, 256.f); -} -CUSTOM_CVAR (Float, joy_zrotthreshold, 0.15f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - JoyAxisThresholds[5] = clamp (self * 256.f, 0.f, 256.f); -} -CUSTOM_CVAR (Float, joy_sliderthreshold, 0.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - JoyAxisThresholds[6] = clamp (self * 256.f, 0.f, 256.f); -} -CUSTOM_CVAR (Float, joy_dialthreshold, 0.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - JoyAxisThresholds[7] = clamp (self * 256.f, 0.f, 256.f); -} - -CVAR (Float, joy_speedmultiplier,1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (Float, joy_yawspeed, -1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (Float, joy_pitchspeed, -.75f,CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (Float, joy_forwardspeed, -1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (Float, joy_sidespeed, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (Float, joy_upspeed, -1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) - CVAR (Bool, k_allowfullscreentoggle, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -static FBaseCVar * const JoyConfigVars[] = -{ - &joy_xaxis, &joy_yaxis, &joy_zaxis, &joy_xrot, &joy_yrot, &joy_zrot, &joy_slider, &joy_dial, - &joy_xthreshold, &joy_ythreshold, &joy_zthreshold, &joy_xrotthreshold, &joy_yrotthreshold, &joy_zrotthreshold, &joy_sliderthreshold, &joy_dialthreshold, - &joy_speedmultiplier, &joy_yawspeed, &joy_pitchspeed, &joy_forwardspeed, &joy_sidespeed, - &joy_upspeed -}; - extern int chatmodeon; static void I_CheckGUICapture () @@ -498,15 +355,18 @@ LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { return result; } + for (int i = 0; i < NUM_JOYDEVICES; ++i) + { + if (CallHook(JoyDevices[i], hWnd, message, wParam, lParam, &result)) + { + return result; + } + } if (GUICapture && GUIWndProcHook(hWnd, message, wParam, lParam, &result)) { return result; } - event_t event; - - memset (&event, 0, sizeof(event)); - switch (message) { case WM_DESTROY: @@ -669,74 +529,6 @@ LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) } break; - case WM_DEVICECHANGE: - if (wParam == DBT_DEVNODES_CHANGED || - wParam == DBT_DEVICEARRIVAL || - wParam == DBT_CONFIGCHANGED) - { - unsigned int i; - TArray oldjoys; - - for (i = 0; i < JoystickNames.Size(); ++i) - { - oldjoys.Push (JoystickNames[i].ID); - } - - DI_EnumJoy (); - - // If a new joystick was added and the joystick menu is open, - // switch to it. - if (menuactive != MENU_Off && CurrentMenu == &JoystickMenu) - { - for (i = 0; i < JoystickNames.Size(); ++i) - { - bool wasListed = false; - - for (unsigned int j = 0; j < oldjoys.Size(); ++j) - { - if (oldjoys[j] == JoystickNames[i].ID) - { - wasListed = true; - break; - } - } - if (!wasListed) - { - joy_guid = JoystickNames[i].ID; - break; - } - } - } - - // If the current joystick was removed, - // try to switch to a different one. - if (g_pJoy != NULL) - { - DIDEVICEINSTANCE inst = { sizeof(DIDEVICEINSTANCE), }; - - if (SUCCEEDED(g_pJoy->GetDeviceInfo (&inst))) - { - for (i = 0; i < JoystickNames.Size(); ++i) - { - if (JoystickNames[i].ID == inst.guidInstance) - { - break; - } - } - if (i == JoystickNames.Size ()) - { - DI_InitJoy (); - } - } - } - else - { - DI_InitJoy (); - } - UpdateJoystickMenu (); - } - break; - case WM_PALETTECHANGED: if ((HWND)wParam == Window) break; @@ -763,376 +555,6 @@ LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) return 0; } -/****** Joystick stuff ******/ - -void DI_JoyCheck () -{ - float mul; - event_t event; - HRESULT hr; - DIJOYSTATE2 js; - int i; - BYTE pov; - - if (g_pJoy == NULL) - { - return; - } - - hr = g_pJoy->Poll (); - if (FAILED(hr)) - { - do - { - hr = g_pJoy->Acquire (); - } - while (hr == DIERR_INPUTLOST); - if (FAILED(hr)) - return; - } - - hr = g_pJoy->GetDeviceState (sizeof(DIJOYSTATE2), &js); - if (FAILED(hr)) - return; - - mul = joy_speedmultiplier; - if (Button_Speed.bDown) - { - mul *= 0.5f; - } - - for (i = 0; i < 6; ++i) - { - JoyAxes[i] = 0.f; - } - - for (i = 0; i < 8; ++i) - { - int vaxis = JoyAxisMap[i]; - - if (vaxis != JOYAXIS_NONE) - { - if (vaxis == JOYAXIS_YAW && (Button_Strafe.bDown || - (Button_Mlook.bDown && lookstrafe))) - { - vaxis = JOYAXIS_SIDE; - } - else if (vaxis == JOYAXIS_FORWARD && Button_Mlook.bDown) - { - vaxis = JOYAXIS_PITCH; - } - - float axisval = *((LONG *)((BYTE *)&js + Axes[i])); - if (fabsf(axisval) > JoyAxisThresholds[i]) - { - if (axisval > 0.f) - { - axisval -= JoyAxisThresholds[i]; - } - else - { - axisval += JoyAxisThresholds[i]; - } - JoyAxes[vaxis] += axisval * mul * 256.f / (256.f - JoyAxisThresholds[i]); - } - } - } - - JoyAxes[JOYAXIS_YAW] *= joy_yawspeed; - JoyAxes[JOYAXIS_PITCH] *= joy_pitchspeed; - JoyAxes[JOYAXIS_FORWARD] *= joy_forwardspeed; - JoyAxes[JOYAXIS_SIDE] *= joy_sidespeed; - JoyAxes[JOYAXIS_UP] *= joy_upspeed; - - event.data2 = event.data3 = 0; - - // Send button up/down events - - for (i = 0; i < 128; ++i) - { - if ((js.rgbButtons[i] ^ JoyButtons[i]) & 0x80) - { - event.data1 = KEY_FIRSTJOYBUTTON + i; - if (JoyButtons[i]) - { - event.type = EV_KeyUp; - JoyButtons[i] = 0; - } - else - { - event.type = EV_KeyDown; - JoyButtons[i] = 0x80; - } - D_PostEvent (&event); - } - } - - for (i = 0; i < 4; ++i) - { - if (LOWORD(js.rgdwPOV[i]) == 0xFFFF) - { - pov = 8; - } - else - { - pov = ((js.rgdwPOV[i] + 2250) % 36000) / 4500; - } - pov = POVButtons[pov]; - for (int j = 0; j < 4; ++j) - { - BYTE mask = 1 << j; - - if ((JoyPOV[i] ^ pov) & mask) - { - event.data1 = KEY_JOYPOV1_UP + i*4 + j; - event.type = (pov & mask) ? EV_KeyDown : EV_KeyUp; - D_PostEvent (&event); - } - } - JoyPOV[i] = pov; - } -} - -bool SetJoystickSection (bool create) -{ - DIDEVICEINSTANCE inst = { sizeof(DIDEVICEINSTANCE), }; - char section[80] = "Joystick."; - - if (g_pJoy != NULL && SUCCEEDED(g_pJoy->GetDeviceInfo (&inst))) - { - FormatGUID (section + 9, countof(section) - 9, inst.guidInstance); - strcpy (section + 9 + 38, ".Axes"); - return GameConfig->SetSection (section, create); - } - else - { - return false; - } -} - -void LoadJoystickConfig () -{ - if (SetJoystickSection (false)) - { - for (size_t i = 0; i < countof(JoyConfigVars); ++i) - { - const char *val = GameConfig->GetValueForKey (JoyConfigVars[i]->GetName()); - UCVarValue cval; - - if (val != NULL) - { - cval.String = const_cast(val); - JoyConfigVars[i]->SetGenericRep (cval, CVAR_String); - } - } - } -} - -void SaveJoystickConfig () -{ - if (SetJoystickSection (true)) - { - GameConfig->ClearCurrentSection (); - for (size_t i = 0; i < countof(JoyConfigVars); ++i) - { - UCVarValue cval = JoyConfigVars[i]->GetGenericRep (CVAR_String); - GameConfig->SetValueForKey (JoyConfigVars[i]->GetName(), cval.String); - } - } -} - -BOOL CALLBACK EnumJoysticksCallback (LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef) -{ - GUIDName name; - - JoyActive++; - name.ID = lpddi->guidInstance; - name.Name = copystring (lpddi->tszInstanceName); - JoystickNames.Push (name); - return DIENUM_CONTINUE; -} - -void DI_EnumJoy () -{ - unsigned int i; - - for (i = 0; i < JoystickNames.Size(); ++i) - { - delete[] JoystickNames[i].Name; - } - - JoyActive = 0; - JoystickNames.Clear (); - - if (g_pdi != NULL && !Args->CheckParm ("-nojoy")) - { - g_pdi->EnumDevices (DI8DEVCLASS_GAMECTRL, EnumJoysticksCallback, NULL, DIEDFL_ALLDEVICES); - } -} - -BOOL DI_InitJoy (void) -{ - HRESULT hr; - unsigned int i; - - if (g_pdi == NULL) - { - return TRUE; - } - - if (g_pJoy != NULL) - { - SaveJoystickConfig (); - g_pJoy->Release (); - g_pJoy = NULL; - } - - if (JoystickNames.Size() == 0) - { - return TRUE; - } - - // Try to obtain the joystick specified by joy_guid - for (i = 0; i < JoystickNames.Size(); ++i) - { - if (JoystickNames[i].ID == joy_guid) - { - hr = g_pdi->CreateDevice (JoystickNames[i].ID, &g_pJoy, NULL); - if (FAILED(hr)) - { - i = JoystickNames.Size(); - } - break; - } - } - - // If the preferred joystick could not be obtained, grab the first - // one available. - if (i == JoystickNames.Size()) - { - for (i = 0; i <= JoystickNames.Size(); ++i) - { - hr = g_pdi->CreateDevice (JoystickNames[i].ID, &g_pJoy, NULL); - if (SUCCEEDED(hr)) - { - break; - } - } - } - - if (i == JoystickNames.Size()) - { - JoyActive = 0; - return TRUE; - } - - if (FAILED (InitJoystick ())) - { - JoyActive = 0; - g_pJoy->Release (); - g_pJoy = NULL; - } - else - { - LoadJoystickConfig (); - joy_guid = JoystickNames[i].ID; - } - - return TRUE; -} - -BOOL CALLBACK EnumAxesCallback (LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef) -{ - DIPROPRANGE diprg = - { - { - sizeof (DIPROPRANGE), - sizeof (DIPROPHEADER), - lpddoi->dwType, - DIPH_BYID - }, - -256, - +256 - }; - if (lpddoi->wUsagePage == 1) - { - if (lpddoi->wUsage >= 0x30 && lpddoi->wUsage <= 0x37) - { - JoyAxisNames[lpddoi->wUsage-0x30] = copystring (lpddoi->tszName); - } - } - if (FAILED(g_pJoy->SetProperty (DIPROP_RANGE, &diprg.diph))) - { - return DIENUM_STOP; - } - else - { - return DIENUM_CONTINUE; - } -} - -static HRESULT InitJoystick () -{ - HRESULT hr; - - memset (JoyPOV, 9, sizeof(JoyPOV)); - for (int i = 0; i < 8; ++i) - { - if (JoyAxisNames[i]) - { - delete[] JoyAxisNames[i]; - JoyAxisNames[i] = NULL; - } - } - - hr = g_pJoy->SetDataFormat (&c_dfDIJoystick2); - if (FAILED(hr)) - { - Printf (PRINT_BOLD, "Could not set joystick data format.\n"); - return hr; - } - - hr = g_pJoy->SetCooperativeLevel (Window, DISCL_EXCLUSIVE|DISCL_FOREGROUND); - if (FAILED(hr)) - { - Printf (PRINT_BOLD, "Could not set joystick cooperative level.\n"); - return hr; - } - - JoystickCaps.dwSize = sizeof(JoystickCaps); - hr = g_pJoy->GetCapabilities (&JoystickCaps); - if (FAILED(hr)) - { - Printf (PRINT_BOLD, "Could not query joystick capabilities.\n"); - return hr; - } - - hr = g_pJoy->EnumObjects (EnumAxesCallback, NULL, DIDFT_AXIS); - if (FAILED(hr)) - { - Printf (PRINT_BOLD, "Could not set joystick axes ranges.\n"); - return hr; - } - - g_pJoy->Acquire (); - - return S_OK; -} - -/****** Stuff from Andy Bay's mymouse.c ******/ - -/**************************************************************************** - * - * DIInit - * - * Initialize the DirectInput variables. - * - ****************************************************************************/ - - -// [RH] Used to obtain DirectInput access to the mouse. -// (Preferred for Win95, but buggy under NT 4.) - bool I_InitInput (void *hwnd) { HRESULT hr; @@ -1198,8 +620,7 @@ bool I_InitInput (void *hwnd) I_StartupMouse(); Printf ("I_StartupJoystick\n"); - DI_EnumJoy (); - DI_InitJoy (); + I_StartupJoystick(); Printf ("I_StartupKeyboard\n"); I_StartupKeyboard(); @@ -1221,11 +642,13 @@ void I_ShutdownInput () delete Mouse; Mouse = NULL; } - if (g_pJoy) + for (int i = 0; i < NUM_JOYDEVICES; ++i) { - SaveJoystickConfig (); - g_pJoy->Release (); - g_pJoy = NULL; + if (JoyDevices[i] != NULL) + { + delete JoyDevices[i]; + JoyDevices[i] = NULL; + } } if (g_pdi) { @@ -1273,7 +696,6 @@ void I_GetEvent () } } - // // I_StartTic // @@ -1292,7 +714,33 @@ void I_StartFrame () { if (use_joystick) { - DI_JoyCheck (); + for (int i = 0; i < NUM_JOYDEVICES; ++i) + { + if (JoyDevices[i] != NULL) + { + JoyDevices[i]->ProcessInput(); + } + } + } +} + +void I_GetAxes(float axes[NUM_JOYAXIS]) +{ + int i; + + for (i = 0; i < NUM_JOYAXIS; ++i) + { + axes[i] = 0; + } + if (use_joystick) + { + for (i = 0; i < NUM_JOYDEVICES; ++i) + { + if (JoyDevices[i] != NULL) + { + JoyDevices[i]->AddAxes(axes); + } + } } } diff --git a/src/win32/i_input.h b/src/win32/i_input.h index fda5c8ff..c98cdc13 100644 --- a/src/win32/i_input.h +++ b/src/win32/i_input.h @@ -35,24 +35,15 @@ #define __I_INPUT_H__ #include "doomtype.h" +#include "doomdef.h" bool I_InitInput (void *hwnd); void I_ShutdownInput (); void I_PutInClipboard (const char *str); FString I_GetFromClipboard (bool windows_has_no_selection_clipboard); -void I_GetEvent (); - -struct GUIDName -{ - GUID ID; - char *Name; -}; - -extern TArray JoystickNames; -extern char *JoyAxisNames[8]; - -extern void DI_EnumJoy (); +void I_GetEvent(); +void I_GetAxes(float axes[NUM_JOYAXIS]); #ifdef USE_WINDOWS_DWORD // Don't make these definitions available to the main body of the source code. @@ -118,9 +109,26 @@ protected: void PostKeyEvent(int keynum, INTBOOL down, bool foreground); }; +class FJoystickCollection : public FInputDevice +{ +public: + virtual void AddAxes(float axes[NUM_JOYAXIS]) = 0; +}; + +enum +{ + INPUT_DIJoy, + INPUT_XInput, + INPUT_PS2EMS, + NUM_JOYDEVICES +}; + +extern FJoystickCollection *JoyDevices[NUM_JOYDEVICES]; + void I_StartupMouse(); void I_CheckNativeMouse(bool prefer_native); void I_StartupKeyboard(); +void I_StartupJoystick(); // USB HID usage page numbers #define HID_GENERIC_DESKTOP_PAGE 0x01 diff --git a/src/win32/win32iface.h b/src/win32/win32iface.h index e3f9df52..2c6440c2 100644 --- a/src/win32/win32iface.h +++ b/src/win32/win32iface.h @@ -98,8 +98,6 @@ class Win32Video : public IVideo bool m_IteratorFS; bool m_IsFullscreen; - bool m_CalledCoInitialize; - void AddMode (int x, int y, int bits, int baseHeight, int doubling); void FreeModes ();