mirror of
https://github.com/dhewm/dhewm3.git
synced 2025-03-20 01:31:09 +00:00
Merge branch 'controller-input'
This commit is contained in:
commit
c743d21f08
15 changed files with 1339 additions and 105 deletions
|
@ -23,6 +23,8 @@ Note: Numbers starting with a "#" like #330 refer to the bugreport with that num
|
|||
(0 = TGA, still the default, 1 = BMP, 2 = PNG, 3 = JPG). `r_screenshotJpgQuality` and
|
||||
`r_screenshotPngCompression` allow configuring how JPG/PNG are compressed.
|
||||
Thanks *eezstreet (Nick Whitlock)*!
|
||||
* Support for gamepads (based on code from [Quadrilateral Cowboy](https://github.com/blendogames/quadrilateralcowboy),
|
||||
but heavily expanded). See [Configuration.md](./Configuration.md#using-gamepads) for more information.
|
||||
|
||||
1.5.2 (2022-06-13)
|
||||
------------------------------------------------------------------------
|
||||
|
|
143
Configuration.md
Normal file
143
Configuration.md
Normal file
|
@ -0,0 +1,143 @@
|
|||
# Configuration
|
||||
|
||||
This document explains some dhewm3-specific configuration options.
|
||||
|
||||
For general Doom3 configuration see for example [this list of CVars](https://modwiki.dhewm3.org/CVars_%28Doom_3%29)
|
||||
and [this list of Console Commands](https://modwiki.dhewm3.org/Commands_%28Doom_3%29).
|
||||
|
||||
**CVars** are set by entering `cvarName value` in the console, for example `com_showFPS 1`.
|
||||
They can also be set as commandline arguments when starting dhewm3, for example `./dhewm3 +set r_fullscreen 0`.
|
||||
|
||||
Just entering a CVar's name (without a value) will show its current value, its default value
|
||||
and a short description of what it does.
|
||||
|
||||
Starting dhewm3 with the commandline argument `-h` (for example `dhewm3.exe -h`) will show some
|
||||
useful commandline arguments, for example how to tell dhewm3 where the game data can be found on your system.
|
||||
|
||||
## The Console
|
||||
|
||||
Like most id Software games from Quake 1 on, Doom3 has a console that allows entering commands
|
||||
and setting Console Variables ("CVars"), often for advanced configuration or to aid development,
|
||||
see also https://modwiki.dhewm3.org/Console.
|
||||
|
||||
Unlike in original Doom3, in dhewm3 the console is always available (no need to set `com_allowconsole 1`
|
||||
or similar), and **can be opened with the key combination `Shift + Esc`**.
|
||||
The classic "console key" (the one between `Esc`, `Tab` and `1`) should also still work with
|
||||
most keyboard layouts. However you can disable that, so you can bind that key like any other key
|
||||
(for example to select the chainsaw), by setting `in_ignoreConsoleKey 1`.
|
||||
|
||||
## Using Gamepads
|
||||
|
||||
Starting with 1.5.3 (or the git commits preceding the one adding this document), dhewm3 supports
|
||||
using gamepads, as long as they're supported by SDL2.
|
||||
This includes XBox Controllers (and compatible ones), Playstation 3-5 controllers,
|
||||
Nintendo Switch Pro Controllers, many thirdparty controllers for those consoles, and lots of other
|
||||
gamepads for PC.
|
||||
|
||||
Some notes:
|
||||
* By default, no bindings for the gamepad exist, so you need to configure them once in the
|
||||
Settings -> Controls menu.
|
||||
- You need to bind *Turn Left*, *Turn Right*, *Look Up* and *Look Down* to the corresponding
|
||||
directions of one stick to use it to look around or aim.
|
||||
- Similarly, you need to bind *Forward*, *Backpedal*, *Move Left* and *Move Right* to the
|
||||
corresponding directions of a stick to use it for player movement.
|
||||
* The "Start" button ("+" on Nintendo gamepads, "Options" on Playstation 4/5 controllers) acts
|
||||
like the Escape key, so it will **open/close the menu** and can not be bound.
|
||||
The other buttons, axes and triggers can be bound to arbitrary actions in the Controls menu,
|
||||
except for the Home button, which can't be used by dhewm3 at all (because it opens Steam when that is running).
|
||||
* In **menus**, either stick will move the cursor, and the button you assign to *attack* (fire) acts
|
||||
like the left mouse button, and so does the lower face button (A on XBox controllers, B on Nintendo
|
||||
controllers, Cross on PS controllers) and the upper face button (Y on XBox, X on Nintendo, Triangle on PS).
|
||||
* The layout of the controller (XBox-like, Nintendo-like, Playstation-like) should be automatically
|
||||
detected and is used to display the button names according to the layout. If yours isn't detected
|
||||
correctly, you can overwrite it with the `joy_gamepadLayout` CVar.
|
||||
* Requires SDL2, layout detection requires SDL 2.0.12 or newer.
|
||||
* Only one gamepad is supported or, more specifically, if multiple are connected, they all behave the same
|
||||
and you can't bind their buttons/axes to different actions, and the auto-layout detection will use the
|
||||
last gamepad it found to determine the layout.
|
||||
* You can disable gamepads by setting the `in_useGamepad` CVar to `0`.
|
||||
* There are several CVars to tweak the behavior:
|
||||
- `joy_deadZone` Deadzone of the sticks, where `1.0` would be "stick moved fully in one direction".
|
||||
This means that values below this register as 0. If you move or look around ingame even though
|
||||
you're not moving a stick, try increasing the `joy_deadZone` value (default is `0.25`).
|
||||
- `joy_triggerThreshold` Basically the deadzone for triggers. If your trigger triggers without
|
||||
being touched, try increasing this value (default is `0.05`).
|
||||
- `joy_gamepadLayout` overwrite automatically detected layout (XBox, Nintendo, PS), see above.
|
||||
- `joy_pitchSpeed` How fast you look up/down (when the stick is at a maximum position)
|
||||
- `joy_yawSpeed` Same for turning left/right
|
||||
- `joy_invertLook` Inverts the controls for looking up/down (like in a flight simulator)
|
||||
- `joy_gammaLook` If set to `1`, use a log curve instead of a power curve for looking around,
|
||||
affects how fast you turn (or look up/down) when the stick is between center and maximum.
|
||||
- `joy_powerScale` If `joy_gammaLook` is `0`, this is the exponent used for the power curve.
|
||||
- `joy_dampenLook` if enabled (`1`), somehow reduced the speed of looking around, depending on
|
||||
`joy_deltaPerMSLook`.
|
||||
|
||||
I created gamepad configs for the base game and d3xp (Resurrection of Evil), based on the standard bindings
|
||||
of Doom3 BFG, see gamepad.cfg and gamepad-d3xp.cfg in the [base/ directory](./base/).
|
||||
Put them in your base/ folder, open the console and enter `exec gamepad.cfg` for the base game,
|
||||
or `exec gamepad-d3xp.cfg` for Resurrection of Evil (probably also works for Doom3: Lost Mission).
|
||||
|
||||
**_Note_** that in *configs* (or `bind` commands in the console), the following names are used for
|
||||
gamepad buttons, sticks and triggers:
|
||||
|
||||
<details><summary>Click to see the list of gamepad button/stick/trigger names</summary>
|
||||
|
||||
* "JOY_BTN_SOUTH" - `A` button on XBox-style gamepads, `B` on Nintendo-style gamepads or `Cross` on Playstation-style gamepads
|
||||
* "JOY_BTN_EAST" - `B` (XBox), `A` (Nintendo), `Circle` (Playstation)
|
||||
* "JOY_BTN_WEST" - `X` (XBox), `Y` (Nintendo), `Square` (Playstation)
|
||||
* "JOY_BTN_NORTH" - `Y` (XBox), `X` (Nintendo), `Triangle` (Playstation)
|
||||
* "JOY_BTN_BACK" - The `Back` button, aka `-` (Nintendo) or `Select`/`Share` (Playstation)
|
||||
* "JOY_BTN_LSTICK" - Pressing the Left Stick down
|
||||
* "JOY_BTN_RSTICK" - Pressing the Right Stick down
|
||||
* "JOY_BTN_LSHOULDER" - Left Shoulder Button
|
||||
* "JOY_BTN_RSHOULDER" - Right Shoulder button
|
||||
* "JOY_DPAD_UP" - DPad Up
|
||||
* "JOY_DPAD_DOWN" - DPad Down
|
||||
* "JOY_DPAD_LEFT" - DPad Left
|
||||
* "JOY_DPAD_RIGHT" - DPad Right
|
||||
* "JOY_BTN_MISC1" - misc. additional button, like Xbox Series X share button, PS5 microphone button, Nintendo Switch Pro capture button, Amazon Luna microphone button
|
||||
* "JOY_BTN_RPADDLE1" - Upper or primary paddle, under your right hand (e.g. Xbox Elite paddle P1)
|
||||
* "JOY_BTN_LPADDLE1" - Upper or primary paddle, under your left hand (e.g. Xbox Elite paddle P3)
|
||||
* "JOY_BTN_RPADDLE2" - Lower or secondary paddle, under your right hand (e.g. Xbox Elite paddle P2)
|
||||
* "JOY_BTN_LPADDLE2" - Lower or secondary paddle, under your left hand (e.g. Xbox Elite paddle P4
|
||||
* "JOY_STICK1_UP" - Moving Left Stick up
|
||||
* "JOY_STICK1_DOWN" - Moving Left Stick down
|
||||
* "JOY_STICK1_LEFT" - Moving Left Stick to the left
|
||||
* "JOY_STICK1_RIGHT" - Moving Left Stick to the right
|
||||
* "JOY_STICK2_UP" - Moving Right Stick up
|
||||
* "JOY_STICK2_DOWN" - Moving Right Stick down
|
||||
* "JOY_STICK2_LEFT" - Moving Right Stick to the left
|
||||
* "JOY_STICK2_RIGHT" - Moving Right Stick to the right
|
||||
* "JOY_TRIGGER1" - Pressing the Left Trigger
|
||||
* "JOY_TRIGGER2" - Pressing the Right Trigger
|
||||
|
||||
</details>
|
||||
|
||||
## Screenshot configuration
|
||||
|
||||
Doom3 always supported taking screenshots, but dhewm3 (from 1.5.3 on) supports using different
|
||||
formats than TGA.
|
||||
This can be configured with the following CVars:
|
||||
|
||||
- `r_screenshotFormat` What format screenshots should be in:
|
||||
`0` = TGA (default), `1` = BMP, `2` = PNG, `3` = JPG
|
||||
- `r_screenshotJpgQuality` Quality when using JPG screenshots (`0` - `100`)
|
||||
- `r_screenshotPngCompression` Compression level when using PNG screenshots (`0` - `9`)
|
||||
|
||||
## CVars added in dhewm3 that I'm currently too lazy to document more thoroughly
|
||||
|
||||
- g_hitEffect
|
||||
|
||||
- in_nograb
|
||||
- in_grabKeyboard
|
||||
|
||||
- in_tty
|
||||
- in_kbd
|
||||
|
||||
- r_fullscreenDesktop
|
||||
- r_fillWindowAlphaChan
|
||||
|
||||
- r_useCarmacksReverse
|
||||
- r_useStencilOpSeparate
|
||||
|
||||
- s_alReverbGain
|
|
@ -31,6 +31,7 @@ Compared to the original _DOOM 3_, the changes of _dhewm 3_ worth mentioning are
|
|||
- SDL for low-level OS support, OpenGL and input handling
|
||||
- OpenAL for audio output, all OS-specific audio backends are gone
|
||||
- OpenAL EFX for EAX reverb effects (read: EAX-like sound effects on all platforms/hardware)
|
||||
- Gamepad support
|
||||
- Better support for widescreen (and arbitrary display resolutions)
|
||||
- A portable build system based on CMake
|
||||
- (Cross-)compilation with MinGW-w64
|
||||
|
@ -55,6 +56,11 @@ https://store.steampowered.com/app/208200/DOOM_3/
|
|||
|
||||
See https://dhewm3.org/#how-to-install for game data installation instructions.
|
||||
|
||||
## Configuration
|
||||
|
||||
See [Configuration.md](./Configuration.md) for dhewm3-specific configuration, especially for
|
||||
using gamepads.
|
||||
|
||||
## Compiling
|
||||
|
||||
The build system is based on CMake: http://cmake.org/
|
||||
|
|
21
base/gamepad-d3xp.cfg
Executable file
21
base/gamepad-d3xp.cfg
Executable file
|
@ -0,0 +1,21 @@
|
|||
bind "JOY_BTN_SOUTH" "_moveUp"
|
||||
bind "JOY_BTN_WEST" "_impulse13"
|
||||
bind "JOY_BTN_BACK" "_impulse19"
|
||||
bind "JOY_BTN_LSTICK" "_speed"
|
||||
bind "JOY_BTN_RSTICK" "_moveDown"
|
||||
bind "JOY_BTN_LSHOULDER" "_impulse15"
|
||||
bind "JOY_BTN_RSHOULDER" "_impulse14"
|
||||
bind "JOY_DPAD_UP" "_impulse8"
|
||||
bind "JOY_DPAD_DOWN" "_impulse11"
|
||||
bind "JOY_DPAD_LEFT" "_impulse12"
|
||||
bind "JOY_DPAD_RIGHT" "_impulse1"
|
||||
bind "JOY_STICK1_UP" "_forward"
|
||||
bind "JOY_STICK1_DOWN" "_back"
|
||||
bind "JOY_STICK1_LEFT" "_moveLeft"
|
||||
bind "JOY_STICK1_RIGHT" "_moveRight"
|
||||
bind "JOY_STICK2_UP" "_lookUp"
|
||||
bind "JOY_STICK2_DOWN" "_lookDown"
|
||||
bind "JOY_STICK2_LEFT" "_left"
|
||||
bind "JOY_STICK2_RIGHT" "_right"
|
||||
bind "JOY_TRIGGER1" "_impulse0"
|
||||
bind "JOY_TRIGGER2" "_attack"
|
21
base/gamepad.cfg
Executable file
21
base/gamepad.cfg
Executable file
|
@ -0,0 +1,21 @@
|
|||
bind "JOY_BTN_SOUTH" "_moveUp"
|
||||
bind "JOY_BTN_WEST" "_impulse13"
|
||||
bind "JOY_BTN_BACK" "_impulse19"
|
||||
bind "JOY_BTN_LSTICK" "_speed"
|
||||
bind "JOY_BTN_RSTICK" "_moveDown"
|
||||
bind "JOY_BTN_LSHOULDER" "_impulse15"
|
||||
bind "JOY_BTN_RSHOULDER" "_impulse14"
|
||||
bind "JOY_DPAD_UP" "_impulse5"
|
||||
bind "JOY_DPAD_DOWN" "_impulse8"
|
||||
bind "JOY_DPAD_LEFT" "_impulse9"
|
||||
bind "JOY_DPAD_RIGHT" "_impulse0"
|
||||
bind "JOY_STICK1_UP" "_forward"
|
||||
bind "JOY_STICK1_DOWN" "_back"
|
||||
bind "JOY_STICK1_LEFT" "_moveLeft"
|
||||
bind "JOY_STICK1_RIGHT" "_moveRight"
|
||||
bind "JOY_STICK2_UP" "_lookUp"
|
||||
bind "JOY_STICK2_DOWN" "_lookDown"
|
||||
bind "JOY_STICK2_LEFT" "_left"
|
||||
bind "JOY_STICK2_RIGHT" "_right"
|
||||
bind "JOY_TRIGGER1" "_impulse11"
|
||||
bind "JOY_TRIGGER2" "_attack"
|
|
@ -2919,8 +2919,14 @@ void idCommonLocal::Init( int argc, char **argv ) {
|
|||
#endif
|
||||
#endif
|
||||
|
||||
if (SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO | SDL_INIT_JOYSTICK)) // init joystick to work around SDL 2.0.9 bug #4391
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
if (SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER)) // init joystick to work around SDL 2.0.9 bug #4391
|
||||
#else
|
||||
if (SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO)) // no gamecontroller support in SDL1
|
||||
#endif
|
||||
{
|
||||
Sys_Error("Error while initializing SDL: %s", SDL_GetError());
|
||||
}
|
||||
|
||||
Sys_InitThreads();
|
||||
|
||||
|
|
|
@ -109,38 +109,41 @@ static const keyname_t keynames[] =
|
|||
{"MWHEELUP", K_MWHEELUP, "#str_07131"},
|
||||
{"MWHEELDOWN", K_MWHEELDOWN, "#str_07132"},
|
||||
|
||||
{"JOY1", K_JOY1, "#str_07062"},
|
||||
{"JOY2", K_JOY2, "#str_07063"},
|
||||
{"JOY3", K_JOY3, "#str_07064"},
|
||||
{"JOY4", K_JOY4, "#str_07065"},
|
||||
{"JOY5", K_JOY5, "#str_07066"},
|
||||
{"JOY6", K_JOY6, "#str_07067"},
|
||||
{"JOY7", K_JOY7, "#str_07068"},
|
||||
{"JOY8", K_JOY8, "#str_07069"},
|
||||
{"JOY9", K_JOY9, "#str_07070"},
|
||||
{"JOY10", K_JOY10, "#str_07071"},
|
||||
{"JOY11", K_JOY11, "#str_07072"},
|
||||
{"JOY12", K_JOY12, "#str_07073"},
|
||||
{"JOY13", K_JOY13, "#str_07074"},
|
||||
{"JOY14", K_JOY14, "#str_07075"},
|
||||
{"JOY15", K_JOY15, "#str_07076"},
|
||||
{"JOY16", K_JOY16, "#str_07077"},
|
||||
{"JOY17", K_JOY17, "#str_07078"},
|
||||
{"JOY18", K_JOY18, "#str_07079"},
|
||||
{"JOY19", K_JOY19, "#str_07080"},
|
||||
{"JOY20", K_JOY20, "#str_07081"},
|
||||
{"JOY21", K_JOY21, "#str_07082"},
|
||||
{"JOY22", K_JOY22, "#str_07083"},
|
||||
{"JOY23", K_JOY23, "#str_07084"},
|
||||
{"JOY24", K_JOY24, "#str_07085"},
|
||||
{"JOY25", K_JOY25, "#str_07086"},
|
||||
{"JOY26", K_JOY26, "#str_07087"},
|
||||
{"JOY27", K_JOY27, "#str_07088"},
|
||||
{"JOY28", K_JOY28, "#str_07089"},
|
||||
{"JOY29", K_JOY29, "#str_07090"},
|
||||
{"JOY30", K_JOY30, "#str_07091"},
|
||||
{"JOY31", K_JOY31, "#str_07092"},
|
||||
{"JOY32", K_JOY32, "#str_07093"},
|
||||
// Note: for localized gamepad key names, we use Sys_GetLocalizedJoyKeyName()
|
||||
// so the last column is just NULL
|
||||
{"JOY_BTN_SOUTH", K_JOY_BTN_SOUTH, NULL},
|
||||
{"JOY_BTN_EAST", K_JOY_BTN_EAST, NULL},
|
||||
{"JOY_BTN_WEST", K_JOY_BTN_WEST, NULL},
|
||||
{"JOY_BTN_NORTH", K_JOY_BTN_NORTH, NULL},
|
||||
{"JOY_BTN_BACK", K_JOY_BTN_BACK, NULL},
|
||||
// leaving out K_JOY_BTN_GUIDE, as I think it shouldn't be used (might open Steam or similar)
|
||||
{"JOY_BTN_START", K_JOY_BTN_START, NULL},
|
||||
{"JOY_BTN_LSTICK", K_JOY_BTN_LSTICK, NULL},
|
||||
{"JOY_BTN_RSTICK", K_JOY_BTN_RSTICK, NULL},
|
||||
{"JOY_BTN_LSHOULDER", K_JOY_BTN_LSHOULDER, NULL},
|
||||
{"JOY_BTN_RSHOULDER", K_JOY_BTN_RSHOULDER, NULL},
|
||||
{"JOY_DPAD_UP", K_JOY_DPAD_UP, NULL},
|
||||
{"JOY_DPAD_DOWN", K_JOY_DPAD_DOWN, NULL},
|
||||
{"JOY_DPAD_LEFT", K_JOY_DPAD_LEFT, NULL},
|
||||
{"JOY_DPAD_RIGHT", K_JOY_DPAD_RIGHT, NULL},
|
||||
{"JOY_BTN_MISC1", K_JOY_BTN_MISC1, NULL},
|
||||
{"JOY_BTN_RPADDLE1", K_JOY_BTN_RPADDLE1, NULL},
|
||||
{"JOY_BTN_LPADDLE1", K_JOY_BTN_LPADDLE1, NULL},
|
||||
{"JOY_BTN_RPADDLE2", K_JOY_BTN_RPADDLE2, NULL},
|
||||
{"JOY_BTN_LPADDLE2", K_JOY_BTN_LPADDLE2, NULL},
|
||||
|
||||
{"JOY_STICK1_UP", K_JOY_STICK1_UP, NULL},
|
||||
{"JOY_STICK1_DOWN", K_JOY_STICK1_DOWN, NULL},
|
||||
{"JOY_STICK1_LEFT", K_JOY_STICK1_LEFT, NULL},
|
||||
{"JOY_STICK1_RIGHT", K_JOY_STICK1_RIGHT, NULL},
|
||||
|
||||
{"JOY_STICK2_UP", K_JOY_STICK2_UP, NULL},
|
||||
{"JOY_STICK2_DOWN", K_JOY_STICK2_DOWN, NULL},
|
||||
{"JOY_STICK2_LEFT", K_JOY_STICK2_LEFT, NULL},
|
||||
{"JOY_STICK2_RIGHT", K_JOY_STICK2_RIGHT, NULL},
|
||||
|
||||
{"JOY_TRIGGER1", K_JOY_TRIGGER1, NULL},
|
||||
{"JOY_TRIGGER2", K_JOY_TRIGGER2, NULL},
|
||||
|
||||
{"AUX1", K_AUX1, "#str_07094"},
|
||||
{"AUX2", K_AUX2, "#str_07095"},
|
||||
|
@ -409,6 +412,12 @@ const char *idKeyInput::KeyNumToString( int keynum, bool localized ) {
|
|||
}
|
||||
}
|
||||
|
||||
if ( localized && keynum >= K_FIRST_JOY && keynum <= K_LAST_JOY ) {
|
||||
const char* jname = Sys_GetLocalizedJoyKeyName(keynum);
|
||||
if(jname != NULL)
|
||||
return jname;
|
||||
}
|
||||
|
||||
// check for a key string
|
||||
for ( kn = keynames; kn->name; kn++ ) {
|
||||
if ( keynum == kn->keynum ) {
|
||||
|
|
|
@ -138,39 +138,51 @@ typedef enum {
|
|||
K_MWHEELDOWN = 195,
|
||||
K_MWHEELUP,
|
||||
|
||||
K_JOY1 = 197,
|
||||
K_JOY2,
|
||||
K_JOY3,
|
||||
K_JOY4,
|
||||
K_JOY5,
|
||||
K_JOY6,
|
||||
K_JOY7,
|
||||
K_JOY8,
|
||||
K_JOY9,
|
||||
K_JOY10,
|
||||
K_JOY11,
|
||||
K_JOY12,
|
||||
K_JOY13,
|
||||
K_JOY14,
|
||||
K_JOY15,
|
||||
K_JOY16,
|
||||
K_JOY17,
|
||||
K_JOY18,
|
||||
K_JOY19,
|
||||
K_JOY20,
|
||||
K_JOY21,
|
||||
K_JOY22,
|
||||
K_JOY23,
|
||||
K_JOY24,
|
||||
K_JOY25,
|
||||
K_JOY26,
|
||||
K_JOY27,
|
||||
K_GRAVE_A = 224, // lowercase a with grave accent
|
||||
K_JOY28,
|
||||
K_JOY29,
|
||||
K_JOY30,
|
||||
K_JOY31,
|
||||
K_JOY32,
|
||||
//------------------------
|
||||
// K_JOY codes must be contiguous, too, and K_JOY_BTN_* should be kept in sync with J_BTN_* of sys_jEvents
|
||||
//------------------------
|
||||
|
||||
K_FIRST_JOY = 197,
|
||||
K_JOY_BTN_SOUTH = K_FIRST_JOY, // bottom face button, like Xbox A
|
||||
K_JOY_BTN_EAST, // right face button, like Xbox B
|
||||
K_JOY_BTN_WEST, // left face button, like Xbox X
|
||||
K_JOY_BTN_NORTH, // top face button, like Xbox Y
|
||||
|
||||
K_JOY_BTN_BACK,
|
||||
K_JOY_BTN_GUIDE, // Note: this one should probably not be used?
|
||||
K_JOY_BTN_START, // hardcoded to generate Esc to open/close menu
|
||||
K_JOY_BTN_LSTICK, // press left stick
|
||||
K_JOY_BTN_RSTICK, // press right stick
|
||||
K_JOY_BTN_LSHOULDER,
|
||||
K_JOY_BTN_RSHOULDER,
|
||||
|
||||
K_JOY_DPAD_UP,
|
||||
K_JOY_DPAD_DOWN,
|
||||
K_JOY_DPAD_LEFT,
|
||||
K_JOY_DPAD_RIGHT,
|
||||
|
||||
K_JOY_BTN_MISC1, // Additional button (e.g. Xbox Series X share button, PS5 microphone button, Nintendo Switch Pro capture button, Amazon Luna microphone button)
|
||||
K_JOY_BTN_RPADDLE1, // Upper or primary paddle, under your right hand (e.g. Xbox Elite paddle P1)
|
||||
K_JOY_BTN_LPADDLE1, // Upper or primary paddle, under your left hand (e.g. Xbox Elite paddle P3)
|
||||
K_JOY_BTN_RPADDLE2, // Lower or secondary paddle, under your right hand (e.g. Xbox Elite paddle P2)
|
||||
K_JOY_BTN_LPADDLE2, // Lower or secondary paddle, under your left hand (e.g. Xbox Elite paddle P4)
|
||||
|
||||
K_JOY_STICK1_UP,
|
||||
K_JOY_STICK1_DOWN,
|
||||
K_JOY_STICK1_LEFT,
|
||||
K_JOY_STICK1_RIGHT,
|
||||
|
||||
K_JOY_STICK2_UP,
|
||||
K_JOY_STICK2_DOWN,
|
||||
K_JOY_STICK2_LEFT,
|
||||
K_JOY_STICK2_RIGHT,
|
||||
|
||||
K_JOY_TRIGGER1,
|
||||
K_JOY_TRIGGER2,
|
||||
|
||||
K_LAST_JOY = K_JOY_TRIGGER2,
|
||||
|
||||
K_GRAVE_A = 229, // lowercase a with grave accent FIXME: used to be 224; this probably isn't used anyway
|
||||
|
||||
K_AUX1 = 230,
|
||||
K_CEDILLA_C = 231, // lowercase c with Cedilla
|
||||
|
|
|
@ -1447,6 +1447,9 @@ void idSessionLocal::UnloadMap() {
|
|||
}
|
||||
|
||||
mapSpawned = false;
|
||||
|
||||
// DG: that state needs to be reset now
|
||||
Sys_SetInteractiveIngameGuiActive( false, NULL );
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -39,6 +39,8 @@ If you have questions concerning this license or the applicable additional terms
|
|||
|
||||
idCVar idSessionLocal::gui_configServerRate( "gui_configServerRate", "0", CVAR_GUI | CVAR_ARCHIVE | CVAR_ROM | CVAR_INTEGER, "" );
|
||||
|
||||
extern idCVar joy_gamepadLayout; // DG: used here to update bindings window when cvar is changed
|
||||
|
||||
// implements the setup for, and commands from, the main menu
|
||||
|
||||
/*
|
||||
|
@ -1209,6 +1211,14 @@ void idSessionLocal::GuiFrameEvents() {
|
|||
sysEvent_t ev;
|
||||
idUserInterface *gui;
|
||||
|
||||
// DG: if joy_gamepadLayout changes, the binding names in the main/controls menu must be updated
|
||||
if ( joy_gamepadLayout.IsModified() ) {
|
||||
if ( guiMainMenu != NULL ) {
|
||||
guiMainMenu->SetKeyBindingNames();
|
||||
}
|
||||
joy_gamepadLayout.ClearModified();
|
||||
}
|
||||
|
||||
// stop generating move and button commands when a local console or menu is active
|
||||
// running here so SP, async networking and no game all go through it
|
||||
if ( console->Active() || guiActive ) {
|
||||
|
|
|
@ -93,7 +93,7 @@ typedef enum {
|
|||
UB_BUTTON6,
|
||||
UB_BUTTON7,
|
||||
|
||||
UB_ATTACK,
|
||||
UB_ATTACK, // NOTE: this value (20) is hardcoded in idUserInterfaceLocal::HandleEvent() !
|
||||
UB_SPEED,
|
||||
UB_ZOOM,
|
||||
UB_SHOWSCORES,
|
||||
|
@ -350,7 +350,10 @@ private:
|
|||
bool Inhibited( void );
|
||||
void AdjustAngles( void );
|
||||
void KeyMove( void );
|
||||
void CircleToSquare( float & axis_x, float & axis_y ) const;
|
||||
void HandleJoystickAxis( int keyNum, float unclampedValue, float threshold, bool positive );
|
||||
void JoystickMove( void );
|
||||
void JoystickFakeMouse(float axis_x, float axis_y, float deadzone);
|
||||
void MouseMove( void );
|
||||
void CmdButtons( void );
|
||||
|
||||
|
@ -384,7 +387,14 @@ private:
|
|||
bool mouseDown;
|
||||
|
||||
int mouseDx, mouseDy; // added to by mouse events
|
||||
int joystickAxis[MAX_JOYSTICK_AXIS]; // set by joystick events
|
||||
float joystickAxis[MAX_JOYSTICK_AXIS]; // set by joystick events
|
||||
|
||||
int pollTime;
|
||||
int lastPollTime;
|
||||
float lastLookValuePitch;
|
||||
float lastLookValueYaw;
|
||||
|
||||
bool heldJump; // TODO: ???
|
||||
|
||||
static idCVar in_yawSpeed;
|
||||
static idCVar in_pitchSpeed;
|
||||
|
@ -419,6 +429,22 @@ idCVar idUsercmdGenLocal::m_smooth( "m_smooth", "1", CVAR_SYSTEM | CVAR_ARCHIVE
|
|||
idCVar idUsercmdGenLocal::m_strafeSmooth( "m_strafeSmooth", "4", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_INTEGER, "number of samples blended for mouse moving", 1, 8, idCmdSystem::ArgCompletion_Integer<1,8> );
|
||||
idCVar idUsercmdGenLocal::m_showMouseRate( "m_showMouseRate", "0", CVAR_SYSTEM | CVAR_BOOL, "shows mouse movement" );
|
||||
|
||||
idCVar joy_triggerThreshold( "joy_triggerThreshold", "0.05", CVAR_FLOAT | CVAR_ARCHIVE, "how far the joystick triggers have to be pressed before they register as down" );
|
||||
idCVar joy_deadZone( "joy_deadZone", "0.25", CVAR_FLOAT | CVAR_ARCHIVE, "specifies how large the dead-zone is on the joystick" );
|
||||
idCVar joy_gammaLook( "joy_gammaLook", "1", CVAR_INTEGER | CVAR_ARCHIVE, "use a log curve instead of a power curve for movement" );
|
||||
idCVar joy_powerScale( "joy_powerScale", "2", CVAR_FLOAT | CVAR_ARCHIVE, "Raise joystick values to this power" );
|
||||
idCVar joy_pitchSpeed( "joy_pitchSpeed", "130", CVAR_ARCHIVE | CVAR_FLOAT, "pitch speed when pressing up or down on the joystick", 60, 600 );
|
||||
idCVar joy_yawSpeed( "joy_yawSpeed", "240", CVAR_ARCHIVE | CVAR_FLOAT, "pitch speed when pressing left or right on the joystick", 60, 600 );
|
||||
idCVar joy_invertLook( "joy_invertLook", "0", CVAR_ARCHIVE | CVAR_BOOL, "inverts the look controls so the forward looks up (flight controls) - the proper way to play games!" );
|
||||
|
||||
// these were a bad idea!
|
||||
idCVar joy_dampenLook( "joy_dampenLook", "1", CVAR_BOOL | CVAR_ARCHIVE, "Do not allow full acceleration on look" );
|
||||
idCVar joy_deltaPerMSLook( "joy_deltaPerMSLook", "0.003", CVAR_FLOAT | CVAR_ARCHIVE, "Max amount to be added on look per MS" );
|
||||
|
||||
idCVar in_useGamepad( "in_useGamepad", "1", CVAR_ARCHIVE | CVAR_BOOL, "enables/disables the gamepad for PC use" );
|
||||
|
||||
// TODO idCVar in_mouseInvertLook( "in_mouseInvertLook", "0", CVAR_ARCHIVE | CVAR_BOOL, "inverts the look controls so the forward looks up (flight controls) - the proper way to play games!" );
|
||||
|
||||
static idUsercmdGenLocal localUsercmdGen;
|
||||
idUsercmdGen *usercmdGen = &localUsercmdGen;
|
||||
|
||||
|
@ -439,6 +465,8 @@ idUsercmdGenLocal::idUsercmdGenLocal( void ) {
|
|||
toggled_zoom.Clear();
|
||||
toggled_run.on = in_alwaysRun.GetBool();
|
||||
|
||||
lastLookValuePitch = lastLookValueYaw = 0.0f;
|
||||
|
||||
ClearAngles();
|
||||
Clear();
|
||||
}
|
||||
|
@ -573,9 +601,17 @@ void idUsercmdGenLocal::KeyMove( void ) {
|
|||
forward += KEY_MOVESPEED * ButtonState( UB_FORWARD );
|
||||
forward -= KEY_MOVESPEED * ButtonState( UB_BACK );
|
||||
|
||||
cmd.forwardmove = idMath::ClampChar( forward );
|
||||
cmd.rightmove = idMath::ClampChar( side );
|
||||
cmd.upmove = idMath::ClampChar( up );
|
||||
// only set each movement variable if its unset at this point.
|
||||
// NOTE: joystick input happens before this.
|
||||
if (cmd.forwardmove == 0) {
|
||||
cmd.forwardmove = idMath::ClampChar( forward );
|
||||
}
|
||||
if (cmd.rightmove == 0) {
|
||||
cmd.rightmove = idMath::ClampChar( side );
|
||||
}
|
||||
if (cmd.upmove == 0) {
|
||||
cmd.upmove = idMath::ClampChar( up );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -672,29 +708,233 @@ void idUsercmdGenLocal::MouseMove( void ) {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idUsercmdGenLocal::CircleToSquare
|
||||
========================
|
||||
*/
|
||||
void idUsercmdGenLocal::CircleToSquare( float & axis_x, float & axis_y ) const {
|
||||
// bring everything in the first quadrant
|
||||
bool flip_x = false;
|
||||
if ( axis_x < 0.0f ) {
|
||||
flip_x = true;
|
||||
axis_x *= -1.0f;
|
||||
}
|
||||
bool flip_y = false;
|
||||
if ( axis_y < 0.0f ) {
|
||||
flip_y = true;
|
||||
axis_y *= -1.0f;
|
||||
}
|
||||
|
||||
// swap the two axes so we project against the vertical line X = 1
|
||||
bool swap = false;
|
||||
if ( axis_y > axis_x ) {
|
||||
float tmp = axis_x;
|
||||
axis_x = axis_y;
|
||||
axis_y = tmp;
|
||||
swap = true;
|
||||
}
|
||||
|
||||
if ( axis_x < 0.001f ) {
|
||||
// on one of the axes where no correction is needed
|
||||
return;
|
||||
}
|
||||
|
||||
// length (max 1.0f at the unit circle)
|
||||
float len = idMath::Sqrt( axis_x * axis_x + axis_y * axis_y );
|
||||
if ( len > 1.0f ) {
|
||||
len = 1.0f;
|
||||
}
|
||||
// thales
|
||||
float axis_y_us = axis_y / axis_x;
|
||||
|
||||
// use a power curve to shift the correction to happen closer to the unit circle
|
||||
float correctionRatio = Square( len );
|
||||
axis_x += correctionRatio * ( len - axis_x );
|
||||
axis_y += correctionRatio * ( axis_y_us - axis_y );
|
||||
|
||||
// go back through the symmetries
|
||||
if ( swap ) {
|
||||
float tmp = axis_x;
|
||||
axis_x = axis_y;
|
||||
axis_y = tmp;
|
||||
}
|
||||
if ( flip_x ) {
|
||||
axis_x *= -1.0f;
|
||||
}
|
||||
if ( flip_y ) {
|
||||
axis_y *= -1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idUsercmdGenLocal::HandleJoystickAxis
|
||||
========================
|
||||
*/
|
||||
void idUsercmdGenLocal::HandleJoystickAxis( int keyNum, float unclampedValue, float threshold, bool positive ) {
|
||||
if ( ( unclampedValue > 0.0f ) && !positive ) {
|
||||
return;
|
||||
}
|
||||
if ( ( unclampedValue < 0.0f ) && positive ) {
|
||||
return;
|
||||
}
|
||||
float value = 0.0f;
|
||||
bool pressed = false;
|
||||
if ( unclampedValue > threshold ) {
|
||||
value = idMath::Fabs( ( unclampedValue - threshold ) / ( 1.0f - threshold ) );
|
||||
pressed = true;
|
||||
} else if ( unclampedValue < -threshold ) {
|
||||
value = idMath::Fabs( ( unclampedValue + threshold ) / ( 1.0f - threshold ) );
|
||||
pressed = true;
|
||||
}
|
||||
|
||||
int action = idKeyInput::GetUsercmdAction( keyNum );
|
||||
if ( action >= UB_ATTACK ) {
|
||||
Key( keyNum, pressed );
|
||||
return;
|
||||
}
|
||||
if ( !pressed ) {
|
||||
return;
|
||||
}
|
||||
|
||||
float lookValue = 0.0f;
|
||||
if ( joy_gammaLook.GetBool() ) {
|
||||
lookValue = idMath::Pow( 1.04712854805f, value * 100.0f ) * 0.01f;
|
||||
} else {
|
||||
lookValue = idMath::Pow( value, joy_powerScale.GetFloat() );
|
||||
}
|
||||
|
||||
#if 0 // TODO: aim assist maybe.
|
||||
idGame * game = common->Game();
|
||||
if ( game != NULL ) {
|
||||
lookValue *= game->GetAimAssistSensitivity();
|
||||
}
|
||||
#endif
|
||||
|
||||
switch ( action ) {
|
||||
case UB_FORWARD: {
|
||||
float move = (float)cmd.forwardmove + ( KEY_MOVESPEED * value );
|
||||
cmd.forwardmove = idMath::ClampChar( idMath::Ftoi( move ) );
|
||||
break;
|
||||
}
|
||||
case UB_BACK: {
|
||||
float move = (float)cmd.forwardmove - ( KEY_MOVESPEED * value );
|
||||
cmd.forwardmove = idMath::ClampChar( idMath::Ftoi( move ) );
|
||||
break;
|
||||
}
|
||||
case UB_MOVELEFT: {
|
||||
float move = (float)cmd.rightmove - ( KEY_MOVESPEED * value );
|
||||
cmd.rightmove = idMath::ClampChar( idMath::Ftoi( move ) );
|
||||
break;
|
||||
}
|
||||
case UB_MOVERIGHT: {
|
||||
float move = (float)cmd.rightmove + ( KEY_MOVESPEED * value );
|
||||
cmd.rightmove = idMath::ClampChar( idMath::Ftoi( move ) );
|
||||
break;
|
||||
}
|
||||
case UB_LOOKUP: {
|
||||
if ( joy_dampenLook.GetBool() ) {
|
||||
lookValue = Min( lookValue, ( pollTime - lastPollTime ) * joy_deltaPerMSLook.GetFloat() + lastLookValuePitch );
|
||||
lastLookValuePitch = lookValue;
|
||||
}
|
||||
|
||||
float invertPitch = joy_invertLook.GetBool() ? -1.0f : 1.0f;
|
||||
viewangles[PITCH] -= MS2SEC( pollTime - lastPollTime ) * lookValue * joy_pitchSpeed.GetFloat() * invertPitch;
|
||||
break;
|
||||
}
|
||||
case UB_LOOKDOWN: {
|
||||
if ( joy_dampenLook.GetBool() ) {
|
||||
lookValue = Min( lookValue, ( pollTime - lastPollTime ) * joy_deltaPerMSLook.GetFloat() + lastLookValuePitch );
|
||||
lastLookValuePitch = lookValue;
|
||||
}
|
||||
|
||||
float invertPitch = joy_invertLook.GetBool() ? -1.0f : 1.0f;
|
||||
viewangles[PITCH] += MS2SEC( pollTime - lastPollTime ) * lookValue * joy_pitchSpeed.GetFloat() * invertPitch;
|
||||
break;
|
||||
}
|
||||
case UB_LEFT: {
|
||||
if ( joy_dampenLook.GetBool() ) {
|
||||
lookValue = Min( lookValue, ( pollTime - lastPollTime ) * joy_deltaPerMSLook.GetFloat() + lastLookValueYaw );
|
||||
lastLookValueYaw = lookValue;
|
||||
}
|
||||
viewangles[YAW] += MS2SEC( pollTime - lastPollTime ) * lookValue * joy_yawSpeed.GetFloat();
|
||||
break;
|
||||
}
|
||||
case UB_RIGHT: {
|
||||
if ( joy_dampenLook.GetBool() ) {
|
||||
lookValue = Min( lookValue, ( pollTime - lastPollTime ) * joy_deltaPerMSLook.GetFloat() + lastLookValueYaw );
|
||||
lastLookValueYaw = lookValue;
|
||||
}
|
||||
viewangles[YAW] -= MS2SEC( pollTime - lastPollTime ) * lookValue * joy_yawSpeed.GetFloat();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static float joyAxisToMouseDelta(float axis, float deadzone)
|
||||
{
|
||||
float ret = 0.0f;
|
||||
float val = fabsf(axis); // calculations below require a positive value
|
||||
if(val > deadzone) {
|
||||
// from deadzone .. 1 to 0 .. 1-deadzone
|
||||
val -= deadzone;
|
||||
// and then to 0..1
|
||||
val = val * (1.0f / (1.0f - deadzone));
|
||||
|
||||
// make it exponential curve - exp(val*3) should return sth between 1 and 20;
|
||||
// then turning that into 0.5 .. 10
|
||||
ret = expf( val * 3.0f ) * 0.5f;
|
||||
if(axis < 0.0f) // restore sign
|
||||
ret = -ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
extern bool D3_IN_interactiveIngameGuiActive; // from sys/events.cpp
|
||||
void idUsercmdGenLocal::JoystickFakeMouse(float axis_x, float axis_y, float deadzone)
|
||||
{
|
||||
if ( D3_IN_interactiveIngameGuiActive ) {
|
||||
float x = joyAxisToMouseDelta(axis_x, deadzone);
|
||||
float y = joyAxisToMouseDelta(axis_y, deadzone);
|
||||
continuousMouseX += x;
|
||||
continuousMouseY += y;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idUsercmdGenLocal::JoystickMove
|
||||
=================
|
||||
*/
|
||||
void idUsercmdGenLocal::JoystickMove( void ) {
|
||||
float anglespeed;
|
||||
void idUsercmdGenLocal::JoystickMove() {
|
||||
float threshold = joy_deadZone.GetFloat();
|
||||
float triggerThreshold = joy_triggerThreshold.GetFloat();
|
||||
|
||||
if ( toggled_run.on ^ ( in_alwaysRun.GetBool() && idAsyncNetwork::IsActive() ) ) {
|
||||
anglespeed = idMath::M_MS2SEC * USERCMD_MSEC * in_angleSpeedKey.GetFloat();
|
||||
} else {
|
||||
anglespeed = idMath::M_MS2SEC * USERCMD_MSEC;
|
||||
}
|
||||
float axis_y = joystickAxis[ AXIS_LEFT_Y ];
|
||||
float axis_x = joystickAxis[ AXIS_LEFT_X ];
|
||||
CircleToSquare( axis_x, axis_y );
|
||||
|
||||
if ( !ButtonState( UB_STRAFE ) ) {
|
||||
viewangles[YAW] += anglespeed * in_yawSpeed.GetFloat() * joystickAxis[AXIS_SIDE];
|
||||
viewangles[PITCH] += anglespeed * in_pitchSpeed.GetFloat() * joystickAxis[AXIS_FORWARD];
|
||||
} else {
|
||||
cmd.rightmove = idMath::ClampChar( cmd.rightmove + joystickAxis[AXIS_SIDE] );
|
||||
cmd.forwardmove = idMath::ClampChar( cmd.forwardmove + joystickAxis[AXIS_FORWARD] );
|
||||
}
|
||||
HandleJoystickAxis( K_JOY_STICK1_UP, axis_y, threshold, false );
|
||||
HandleJoystickAxis( K_JOY_STICK1_DOWN, axis_y, threshold, true );
|
||||
HandleJoystickAxis( K_JOY_STICK1_LEFT, axis_x, threshold, false );
|
||||
HandleJoystickAxis( K_JOY_STICK1_RIGHT, axis_x, threshold, true );
|
||||
|
||||
cmd.upmove = idMath::ClampChar( cmd.upmove + joystickAxis[AXIS_UP] );
|
||||
JoystickFakeMouse( axis_x, axis_y, threshold );
|
||||
|
||||
axis_y = joystickAxis[ AXIS_RIGHT_Y ];
|
||||
axis_x = joystickAxis[ AXIS_RIGHT_X ];
|
||||
CircleToSquare( axis_x, axis_y );
|
||||
|
||||
HandleJoystickAxis( K_JOY_STICK2_UP, axis_y, threshold, false );
|
||||
HandleJoystickAxis( K_JOY_STICK2_DOWN, axis_y, threshold, true );
|
||||
HandleJoystickAxis( K_JOY_STICK2_LEFT, axis_x, threshold, false );
|
||||
HandleJoystickAxis( K_JOY_STICK2_RIGHT, axis_x, threshold, true );
|
||||
|
||||
JoystickFakeMouse( axis_x, axis_y, threshold );
|
||||
|
||||
HandleJoystickAxis( K_JOY_TRIGGER1, joystickAxis[ AXIS_LEFT_TRIG ], triggerThreshold, true );
|
||||
HandleJoystickAxis( K_JOY_TRIGGER2, joystickAxis[ AXIS_RIGHT_TRIG ], triggerThreshold, true );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -778,6 +1018,9 @@ void idUsercmdGenLocal::MakeCurrent( void ) {
|
|||
// keyboard angle adjustment
|
||||
AdjustAngles();
|
||||
|
||||
// get basic movement from joystick
|
||||
JoystickMove();
|
||||
|
||||
// set button bits
|
||||
CmdButtons();
|
||||
|
||||
|
@ -787,9 +1030,6 @@ void idUsercmdGenLocal::MakeCurrent( void ) {
|
|||
// get basic movement from mouse
|
||||
MouseMove();
|
||||
|
||||
// get basic movement from joystick
|
||||
JoystickMove();
|
||||
|
||||
// check to make sure the angles haven't wrapped
|
||||
if ( viewangles[PITCH] - oldAngles[PITCH] > 90 ) {
|
||||
viewangles[PITCH] = oldAngles[PITCH] + 90;
|
||||
|
@ -877,6 +1117,7 @@ void idUsercmdGenLocal::Clear( void ) {
|
|||
// clears all key states
|
||||
memset( buttonState, 0, sizeof( buttonState ) );
|
||||
memset( keyState, false, sizeof( keyState ) );
|
||||
memset( joystickAxis, 0, sizeof( joystickAxis ) );
|
||||
|
||||
inhibitCommands = false;
|
||||
|
||||
|
@ -939,6 +1180,8 @@ void idUsercmdGenLocal::Key( int keyNum, bool down ) {
|
|||
|
||||
int action = idKeyInput::GetUsercmdAction( keyNum );
|
||||
|
||||
// TODO: if action == 0 return ?
|
||||
|
||||
if ( down ) {
|
||||
|
||||
buttonState[ action ]++;
|
||||
|
@ -1039,7 +1282,25 @@ idUsercmdGenLocal::Joystick
|
|||
===============
|
||||
*/
|
||||
void idUsercmdGenLocal::Joystick( void ) {
|
||||
memset( joystickAxis, 0, sizeof( joystickAxis ) );
|
||||
int numEvents = Sys_PollJoystickInputEvents( 0 );
|
||||
|
||||
// Study each of the buffer elements and process them.
|
||||
for ( int i = 0; i < numEvents; i++ ) {
|
||||
int action;
|
||||
int value;
|
||||
if ( Sys_ReturnJoystickInputEvent( i, action, value ) ) {
|
||||
if ( action >= J_ACTION_FIRST && action <= J_ACTION_MAX ) {
|
||||
int joyButton = K_FIRST_JOY + ( action - J_ACTION_FIRST );
|
||||
Key( joyButton, ( value != 0 ) );
|
||||
} else if ( ( action >= J_AXIS_MIN ) && ( action <= J_AXIS_MAX ) ) {
|
||||
joystickAxis[ action - J_AXIS_MIN ] = static_cast<float>( value ) / 32767.0f;
|
||||
} else {
|
||||
//assert( !"Unknown joystick event" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Sys_EndJoystickInputEvents();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1065,7 +1326,9 @@ void idUsercmdGenLocal::UsercmdInterrupt( void ) {
|
|||
Keyboard();
|
||||
|
||||
// process the system joystick events
|
||||
Joystick();
|
||||
if ( in_useGamepad.GetBool() ) {
|
||||
Joystick();
|
||||
}
|
||||
|
||||
// create the usercmd for com_ticNumber+1
|
||||
MakeCurrent();
|
||||
|
@ -1095,6 +1358,11 @@ idUsercmdGenLocal::GetDirectUsercmd
|
|||
*/
|
||||
usercmd_t idUsercmdGenLocal::GetDirectUsercmd( void ) {
|
||||
|
||||
pollTime = Sys_Milliseconds();
|
||||
if ( pollTime - lastPollTime > 100 ) {
|
||||
lastPollTime = pollTime - 100;
|
||||
}
|
||||
|
||||
// initialize current usercmd
|
||||
InitCurrent();
|
||||
|
||||
|
@ -1105,12 +1373,15 @@ usercmd_t idUsercmdGenLocal::GetDirectUsercmd( void ) {
|
|||
Keyboard();
|
||||
|
||||
// process the system joystick events
|
||||
Joystick();
|
||||
|
||||
if ( in_useGamepad.GetBool() ) {
|
||||
Joystick();
|
||||
}
|
||||
// create the usercmd
|
||||
MakeCurrent();
|
||||
|
||||
cmd.duplicateCount = 0;
|
||||
|
||||
lastPollTime = pollTime;
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
|
|
@ -96,8 +96,8 @@ public:
|
|||
signed char rightmove; // left/right movement
|
||||
signed char upmove; // up/down movement
|
||||
short angles[3]; // view angles
|
||||
short mx; // mouse delta x
|
||||
short my; // mouse delta y
|
||||
short mx; // mouse delta x - DG: not really delta, but from continuousMouseX which accumulates
|
||||
short my; // mouse delta y - DG: same but from continuousMouseY
|
||||
signed char impulse; // impulse command
|
||||
byte flags; // additional flags
|
||||
int sequence; // just for debugging
|
||||
|
|
|
@ -60,6 +60,9 @@ If you have questions concerning this license or the applicable additional terms
|
|||
#define SDLK_PRINTSCREEN SDLK_PRINT
|
||||
#endif
|
||||
|
||||
extern idCVar in_useGamepad; // from UsercmdGen.cpp
|
||||
extern idCVar joy_deadZone; // ditto
|
||||
|
||||
// NOTE: g++-4.7 doesn't like when this is static (for idCmdSystem::ArgCompletion_String<kbdNames>)
|
||||
const char *_in_kbdNames[] = {
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0) // auto-detection is only available for SDL2
|
||||
|
@ -77,11 +80,21 @@ static idCVar in_nograb("in_nograb", "0", CVAR_SYSTEM | CVAR_NOCHEAT, "prevents
|
|||
static idCVar in_grabKeyboard("in_grabKeyboard", "0", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_NOCHEAT | CVAR_BOOL,
|
||||
"if enabled, grabs all keyboard input if mouse is grabbed (so keyboard shortcuts from the OS like Alt-Tab or Windows Key won't work)");
|
||||
|
||||
idCVar joy_gamepadLayout("joy_gamepadLayout", "-1", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_NOCHEAT | CVAR_INTEGER,
|
||||
"Button layout of gamepad. -1: auto (needs SDL 2.0.12 or newer), 0: XBox-style, 1: Nintendo-style, 2: PS4/5-style, 3: PS2/3-style", idCmdSystem::ArgCompletion_Integer<-1, 3> );
|
||||
|
||||
// set in handleMouseGrab(), used in Sys_GetEvent() to decide what kind of internal mouse event to generate
|
||||
static bool in_relativeMouseMode = true;
|
||||
// set in Sys_GetEvent() on window focus gained/lost events
|
||||
static bool in_hasFocus = true;
|
||||
|
||||
static enum D3_Gamepad_Type {
|
||||
D3_GAMEPAD_XINPUT, // XBox/XInput standard, the default
|
||||
D3_GAMEPAD_NINTENDO, // nintendo-like (A/B and X/Y are switched)
|
||||
D3_GAMEPAD_PLAYSTATION, // PS-like (geometric symbols instead of A/B/X/Y)
|
||||
D3_GAMEPAD_PLAYSTATION_OLD // PS2/PS3-like: the back button is called "select" instead of "share"
|
||||
} gamepadType = D3_GAMEPAD_XINPUT;
|
||||
|
||||
struct kbd_poll_t {
|
||||
int key;
|
||||
bool state;
|
||||
|
@ -108,8 +121,26 @@ struct mouse_poll_t {
|
|||
}
|
||||
};
|
||||
|
||||
struct joystick_poll_t {
|
||||
int action;
|
||||
int value;
|
||||
|
||||
joystick_poll_t() : action(0), value(0) {} // TODO: or -1?
|
||||
|
||||
joystick_poll_t(int a, int v) {
|
||||
action = a;
|
||||
value = v;
|
||||
}
|
||||
};
|
||||
|
||||
static idList<kbd_poll_t> kbd_polls;
|
||||
static idList<mouse_poll_t> mouse_polls;
|
||||
static idList<joystick_poll_t> joystick_polls;
|
||||
|
||||
static bool buttonStates[K_LAST_KEY];
|
||||
static float joyAxis[MAX_JOYSTICK_AXIS];
|
||||
|
||||
static idList<sysEvent_t> event_overflow;
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
// for utf8ToISO8859_1() - used for non-ascii text input and Sys_GetLocalizedScancodeName()
|
||||
|
@ -171,7 +202,7 @@ static scancodename_t scancodemappings[] = {
|
|||
D3_SC_MAPPING(COMMA),
|
||||
D3_SC_MAPPING(PERIOD),
|
||||
D3_SC_MAPPING(SLASH),
|
||||
// leaving out lots of key incl. from keypad, we already handle them as normal keys
|
||||
// leaving out lots of keys incl. from keypad, we already handle them as normal keys
|
||||
D3_SC_MAPPING(NONUSBACKSLASH),
|
||||
D3_SC_MAPPING(INTERNATIONAL1), /**< used on Asian keyboards, see footnotes in USB doc */
|
||||
D3_SC_MAPPING(INTERNATIONAL2),
|
||||
|
@ -246,6 +277,137 @@ static bool utf8ToISO8859_1(const char* inbuf, char* outbuf, size_t outsize) {
|
|||
}
|
||||
#endif // SDL2
|
||||
|
||||
const char* Sys_GetLocalizedJoyKeyName( int key ) {
|
||||
// Note: trying to keep the returned names short, because the Doom3 binding window doesn't have much space for names..
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0) // gamecontroller/gamepad not supported in SDL1
|
||||
if (key >= K_FIRST_JOY && key <= K_LAST_JOY) {
|
||||
|
||||
if (key <= K_JOY_BTN_BACK) {
|
||||
#if SDL_VERSION_ATLEAST(3, 0, 0)
|
||||
// TODO: or use the SDL2 code and just set joy_gamepadLayout automatically based on SDL_GetGamepadType() ?
|
||||
SDL_GamepadButton gpbtn = SDL_GAMEPAD_BUTTON_SOUTH + (key - K_JOY_BTN_SOUTH);
|
||||
SDL_GamepadButtonLabel label = SDL_GetGamepadButtonLabelForType(TODO, gpbtn);
|
||||
switch(label) {
|
||||
case SDL_GAMEPAD_BUTTON_LABEL_A:
|
||||
return "Pad A";
|
||||
case SDL_GAMEPAD_BUTTON_LABEL_B:
|
||||
return "Pad B";
|
||||
case SDL_GAMEPAD_BUTTON_LABEL_X:
|
||||
return "Pad X";
|
||||
case SDL_GAMEPAD_BUTTON_LABEL_Y:
|
||||
return "Pad Y";
|
||||
case SDL_GAMEPAD_BUTTON_LABEL_CROSS:
|
||||
return "Pad Cross";
|
||||
case SDL_GAMEPAD_BUTTON_LABEL_CIRCLE:
|
||||
return "Pad Circle";
|
||||
case SDL_GAMEPAD_BUTTON_LABEL_SQUARE:
|
||||
return "Pad Square";
|
||||
case SDL_GAMEPAD_BUTTON_LABEL_TRIANGLE:
|
||||
return "Pad Triangle";
|
||||
}
|
||||
|
||||
#else // SDL2
|
||||
// South, East, West, North Back
|
||||
static const char* xboxBtnNames[5] = { "Pad A", "Pad B", "Pad X", "Pad Y", "Pad Back" };
|
||||
static const char* nintendoBtnNames[5] = { "Pad B", "Pad A", "Pad Y", "Pad X", "Pad -" };
|
||||
static const char* psBtnNames[5] = { "Pad Cross", "Pad Circle", "Pad Square", "Pad Triangle", "Pad Share" };
|
||||
|
||||
int layout = joy_gamepadLayout.GetInteger();
|
||||
if ( layout == -1 ) {
|
||||
layout = gamepadType;
|
||||
}
|
||||
|
||||
unsigned btnIdx = key - K_JOY_BTN_SOUTH;
|
||||
assert(btnIdx < 5);
|
||||
|
||||
switch( layout ) {
|
||||
default:
|
||||
common->Warning( "joy_gamepadLayout has invalid value %d !\n", joy_gamepadLayout.GetInteger() );
|
||||
// fall-through
|
||||
case D3_GAMEPAD_XINPUT:
|
||||
return xboxBtnNames[btnIdx];
|
||||
case D3_GAMEPAD_NINTENDO:
|
||||
return nintendoBtnNames[btnIdx];
|
||||
case D3_GAMEPAD_PLAYSTATION_OLD:
|
||||
if ( key == K_JOY_BTN_BACK )
|
||||
return "Pad Select";
|
||||
// the other button names are identical for PS2/3 and PS4/5
|
||||
// fall-through
|
||||
case D3_GAMEPAD_PLAYSTATION:
|
||||
return psBtnNames[btnIdx];
|
||||
}
|
||||
#endif // face button names for SDL2
|
||||
}
|
||||
|
||||
// the labels for the remaining keys are the same for SDL2 and SDL3 (and all controllers)
|
||||
switch(key) {
|
||||
case K_JOY_BTN_GUIDE: // can't be used in dhewm3, because it opens steam on some systems
|
||||
case K_JOY_BTN_START: // can't be used for bindings, because it's hardcoded to generate Esc
|
||||
return NULL;
|
||||
|
||||
case K_JOY_BTN_LSTICK:
|
||||
return "Pad LStick";
|
||||
case K_JOY_BTN_RSTICK:
|
||||
return "Pad RStick";
|
||||
case K_JOY_BTN_LSHOULDER:
|
||||
return "Pad LShoulder";
|
||||
case K_JOY_BTN_RSHOULDER:
|
||||
return "Pad RShoulder";
|
||||
|
||||
case K_JOY_DPAD_UP:
|
||||
return "DPad Up";
|
||||
case K_JOY_DPAD_DOWN:
|
||||
return "DPad Down";
|
||||
case K_JOY_DPAD_LEFT:
|
||||
return "DPad Left";
|
||||
case K_JOY_DPAD_RIGHT:
|
||||
return "DPad Right";
|
||||
|
||||
case K_JOY_BTN_MISC1:
|
||||
return "Pad Misc";
|
||||
case K_JOY_BTN_RPADDLE1:
|
||||
return "Pad P1";
|
||||
case K_JOY_BTN_LPADDLE1:
|
||||
return "Pad P3";
|
||||
case K_JOY_BTN_RPADDLE2:
|
||||
return "Pad P2";
|
||||
case K_JOY_BTN_LPADDLE2:
|
||||
return "Pad P4";
|
||||
|
||||
// Note: Would be nicer with "Pad " (or even "Gamepad ") at the beginning,
|
||||
// but then it's too long for the keybinding window :-/
|
||||
case K_JOY_STICK1_UP:
|
||||
return "Stick1 Up";
|
||||
case K_JOY_STICK1_DOWN:
|
||||
return "Stick1 Down";
|
||||
case K_JOY_STICK1_LEFT:
|
||||
return "Stick1 Left";
|
||||
case K_JOY_STICK1_RIGHT:
|
||||
return "Stick1 Right";
|
||||
|
||||
case K_JOY_STICK2_UP:
|
||||
return "Stick2 Up";
|
||||
case K_JOY_STICK2_DOWN:
|
||||
return "Stick2 Down";
|
||||
case K_JOY_STICK2_LEFT:
|
||||
return "Stick2 Left";
|
||||
case K_JOY_STICK2_RIGHT:
|
||||
return "Stick2 Right";
|
||||
|
||||
case K_JOY_TRIGGER1:
|
||||
return "Trigger 1";
|
||||
case K_JOY_TRIGGER2:
|
||||
return "Trigger 2";
|
||||
|
||||
default:
|
||||
assert(0 && "missing a case in Sys_GetLocalizedJoyKeyName()!");
|
||||
}
|
||||
}
|
||||
#endif // SDL2+
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// returns localized name of the key (between K_FIRST_SCANCODE and K_LAST_SCANCODE),
|
||||
// regarding the current keyboard layout - if that name is in ASCII or corresponds
|
||||
// to a "High-ASCII" char supported by Doom3.
|
||||
|
@ -477,6 +639,162 @@ static byte mapkey(SDL_Keycode key) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
|
||||
#if ! SDL_VERSION_ATLEAST(2, 0, 14)
|
||||
// Hack: to support newer SDL2 runtime versions than the one built against,
|
||||
// define these controller buttons if needed
|
||||
enum {
|
||||
SDL_CONTROLLER_BUTTON_MISC1 = 15, /* Xbox Series X share button, PS5 microphone button, Nintendo Switch Pro capture button, Amazon Luna microphone button */
|
||||
SDL_CONTROLLER_BUTTON_PADDLE1, /* Xbox Elite paddle P1 */
|
||||
SDL_CONTROLLER_BUTTON_PADDLE2, /* Xbox Elite paddle P3 */
|
||||
SDL_CONTROLLER_BUTTON_PADDLE3, /* Xbox Elite paddle P2 */
|
||||
SDL_CONTROLLER_BUTTON_PADDLE4, /* Xbox Elite paddle P4 */
|
||||
SDL_CONTROLLER_BUTTON_TOUCHPAD, /* PS4/PS5 touchpad button */
|
||||
};
|
||||
#endif // ! SDL_VERSION_ATLEAST(2, 0, 14)
|
||||
|
||||
static sys_jEvents mapjoybutton(SDL_GameControllerButton button) {
|
||||
switch (button)
|
||||
{
|
||||
case SDL_CONTROLLER_BUTTON_A:
|
||||
return J_BTN_SOUTH;
|
||||
case SDL_CONTROLLER_BUTTON_B:
|
||||
return J_BTN_EAST;
|
||||
case SDL_CONTROLLER_BUTTON_X:
|
||||
return J_BTN_WEST;
|
||||
case SDL_CONTROLLER_BUTTON_Y:
|
||||
return J_BTN_NORTH;
|
||||
case SDL_CONTROLLER_BUTTON_BACK:
|
||||
return J_BTN_BACK;
|
||||
case SDL_CONTROLLER_BUTTON_GUIDE:
|
||||
// TODO: this one should probably not be bindable?
|
||||
//return J_BTN_GUIDE;
|
||||
break;
|
||||
case SDL_CONTROLLER_BUTTON_START:
|
||||
return J_BTN_START;
|
||||
case SDL_CONTROLLER_BUTTON_LEFTSTICK:
|
||||
return J_BTN_LSTICK;
|
||||
case SDL_CONTROLLER_BUTTON_RIGHTSTICK:
|
||||
return J_BTN_RSTICK;
|
||||
case SDL_CONTROLLER_BUTTON_LEFTSHOULDER:
|
||||
return J_BTN_LSHOULDER;
|
||||
case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER:
|
||||
return J_BTN_RSHOULDER;
|
||||
case SDL_CONTROLLER_BUTTON_DPAD_UP:
|
||||
return J_DPAD_UP;
|
||||
case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
|
||||
return J_DPAD_DOWN;
|
||||
case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
|
||||
return J_DPAD_LEFT;
|
||||
case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
|
||||
return J_DPAD_RIGHT;
|
||||
|
||||
case SDL_CONTROLLER_BUTTON_MISC1:
|
||||
return J_BTN_MISC1;
|
||||
case SDL_CONTROLLER_BUTTON_PADDLE1:
|
||||
return J_BTN_RPADDLE1;
|
||||
case SDL_CONTROLLER_BUTTON_PADDLE2:
|
||||
return J_BTN_RPADDLE2;
|
||||
case SDL_CONTROLLER_BUTTON_PADDLE3:
|
||||
return J_BTN_LPADDLE1;
|
||||
case SDL_CONTROLLER_BUTTON_PADDLE4:
|
||||
return J_BTN_LPADDLE2;
|
||||
default:
|
||||
common->Warning("unknown game controller button %u", button);
|
||||
break;
|
||||
}
|
||||
return MAX_JOY_EVENT;
|
||||
}
|
||||
|
||||
static sys_jEvents mapjoyaxis(SDL_GameControllerAxis axis) {
|
||||
switch (axis)
|
||||
{
|
||||
case SDL_CONTROLLER_AXIS_LEFTX:
|
||||
return J_AXIS_LEFT_X;
|
||||
case SDL_CONTROLLER_AXIS_LEFTY:
|
||||
return J_AXIS_LEFT_Y;
|
||||
case SDL_CONTROLLER_AXIS_RIGHTX:
|
||||
return J_AXIS_RIGHT_X;
|
||||
case SDL_CONTROLLER_AXIS_RIGHTY:
|
||||
return J_AXIS_RIGHT_Y;
|
||||
case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
|
||||
return J_AXIS_LEFT_TRIG;
|
||||
case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
|
||||
return J_AXIS_RIGHT_TRIG;
|
||||
default:
|
||||
common->Warning("unknown game controller axis %u", axis);
|
||||
break;
|
||||
}
|
||||
return J_AXIS_MAX;
|
||||
}
|
||||
|
||||
#if ! SDL_VERSION_ATLEAST(2, 24, 0)
|
||||
// Hack: to support newer SDL2 runtime versions than the one compiled against,
|
||||
// define some controller types that were added after 2.0.12
|
||||
enum {
|
||||
#if ! SDL_VERSION_ATLEAST(2, 0, 14)
|
||||
SDL_CONTROLLER_TYPE_PS5 = 7,
|
||||
#endif
|
||||
|
||||
// leaving out luna and stadia (from 2.0.16)
|
||||
// and nvidia shield (from 2.24), they're similar enough to XBox/XInput
|
||||
|
||||
// the following were added in 2.24
|
||||
SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT = 11,
|
||||
SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT,
|
||||
SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_PAIR
|
||||
};
|
||||
#endif // ! SDL_VERSION_ATLEAST(2, 24, 0)
|
||||
|
||||
static void setGamepadType( SDL_GameController* gc )
|
||||
{
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 12)
|
||||
const char* typestr = NULL;
|
||||
switch( SDL_GameControllerGetType( gc ) ) {
|
||||
default: // the other controller like luna, stadia, whatever, have a very similar layout
|
||||
case SDL_CONTROLLER_TYPE_UNKNOWN:
|
||||
case SDL_CONTROLLER_TYPE_XBOX360:
|
||||
case SDL_CONTROLLER_TYPE_XBOXONE:
|
||||
gamepadType = D3_GAMEPAD_XINPUT;
|
||||
typestr = "XBox-like";
|
||||
break;
|
||||
|
||||
case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO:
|
||||
case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT:
|
||||
case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT:
|
||||
case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_PAIR:
|
||||
gamepadType = D3_GAMEPAD_NINTENDO;
|
||||
typestr = "Nintendo-like";
|
||||
break;
|
||||
|
||||
case SDL_CONTROLLER_TYPE_PS3:
|
||||
gamepadType = D3_GAMEPAD_PLAYSTATION_OLD;
|
||||
typestr = "Playstation2/3-like";
|
||||
break;
|
||||
case SDL_CONTROLLER_TYPE_PS4:
|
||||
case SDL_CONTROLLER_TYPE_PS5:
|
||||
gamepadType = D3_GAMEPAD_PLAYSTATION;
|
||||
typestr = "Playstation-like";
|
||||
break;
|
||||
}
|
||||
|
||||
common->Printf( "Detected Gamepad %s as type %s\n", SDL_GameControllerName( gc ), typestr );
|
||||
SDL_Joystick* joy = SDL_GameControllerGetJoystick( gc );
|
||||
SDL_JoystickGUID guid = SDL_JoystickGetGUID( joy );
|
||||
char guidstr[34] = {};
|
||||
SDL_JoystickGetGUIDString( guid, guidstr, sizeof(guidstr) );
|
||||
Uint16 vendor = SDL_GameControllerGetVendor( gc );
|
||||
Uint16 product = SDL_GameControllerGetProduct( gc );
|
||||
const char* joyname = SDL_JoystickName( joy );
|
||||
|
||||
common->Printf( " USB IDs: %.4hx:%.4hx Joystick Name: \"%s\" GUID: %s\n", vendor, product, joyname, guidstr );
|
||||
|
||||
#endif // SDL_VERSION_ATLEAST(2, 0, 12)
|
||||
}
|
||||
|
||||
#endif // SDL2+ gamecontroller code
|
||||
|
||||
static void PushConsoleEvent(const char *s) {
|
||||
char *b;
|
||||
size_t len;
|
||||
|
@ -531,6 +849,28 @@ void Sys_InitInput() {
|
|||
#else // SDL1.2 doesn't support this
|
||||
in_grabKeyboard.ClearModified();
|
||||
#endif
|
||||
|
||||
joystick_polls.SetGranularity(64);
|
||||
event_overflow.SetGranularity(64);
|
||||
|
||||
memset( buttonStates, 0, sizeof( buttonStates ) );
|
||||
memset( joyAxis, 0, sizeof( joyAxis ) );
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0) // gamecontroller/gamepad not supported in SDL1
|
||||
// use button positions instead of button labels,
|
||||
// Sys_GetLocalizedJoyKeyName() will do the translation
|
||||
// (I think this also was the default before 2.0.12?)
|
||||
SDL_SetHint("SDL_GAMECONTROLLER_USE_BUTTON_LABELS", "0");
|
||||
|
||||
const int NumJoysticks = SDL_NumJoysticks();
|
||||
for( int i = 0; i < NumJoysticks; ++i )
|
||||
{
|
||||
SDL_GameController* gc = SDL_GameControllerOpen( i );
|
||||
if ( gc != NULL ) {
|
||||
setGamepadType( gc );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -541,6 +881,8 @@ Sys_ShutdownInput
|
|||
void Sys_ShutdownInput() {
|
||||
kbd_polls.Clear();
|
||||
mouse_polls.Clear();
|
||||
joystick_polls.Clear();
|
||||
event_overflow.Clear();
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
SDL_iconv_close( iconvDesc ); // used by utf8ToISO8859_1()
|
||||
iconvDesc = ( SDL_iconv_t ) -1;
|
||||
|
@ -666,6 +1008,67 @@ void Sys_GrabMouseCursor(bool grabIt) {
|
|||
GLimp_GrabInput(flags);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
Sys_SetInteractiveIngameGuiActive
|
||||
Tell the input system that currently an interactive *ingame* UI has focus,
|
||||
so there is an active cursor.
|
||||
Used for an ungodly hack to make gamepad button south (A) behave like
|
||||
left mouse button in that case, so "clicking" with gamepad in the PDA
|
||||
(and ingame GUIs) works as expected.
|
||||
Not set for proper menus like main menu etc - the gamepad hacks for that
|
||||
are in idUserInterfaceLocal::HandleEvent().
|
||||
Call with ui = NULL to clear the state.
|
||||
I hope this won't explode in my face :-p
|
||||
===============
|
||||
*/
|
||||
bool D3_IN_interactiveIngameGuiActive = false;
|
||||
void Sys_SetInteractiveIngameGuiActive( bool active, idUserInterface* ui )
|
||||
{
|
||||
static idList<idUserInterface*> lastuis;
|
||||
if ( ui == NULL ) {
|
||||
// special case for clearing
|
||||
D3_IN_interactiveIngameGuiActive = false;
|
||||
lastuis.Clear();
|
||||
return;
|
||||
}
|
||||
int idx = lastuis.FindIndex( ui );
|
||||
|
||||
if ( sessLocal.GetActiveMenu() == NULL && active ) {
|
||||
// add ui to lastuis, if it has been activated and no proper menu
|
||||
// (like main menu) is currently open
|
||||
lastuis.Append( ui );
|
||||
} else if ( idx != -1 ) {
|
||||
// if the UI is in lastuis and has been deactivated, or there
|
||||
// is a proper menu opened, remove it from the list.
|
||||
// this both handles the regular deactivate case and also works around
|
||||
// main-menu-in-multiplayer weirdness: that menu calls idUserInterface::Activate()
|
||||
// with activate = true twice, but on first call sessLocal.GetActiveMenu() is NULL
|
||||
// so we want to remove it once we realize that it really is a "proper" menu after all.
|
||||
// And because it's possible that we have an ingame UI focussed while opening
|
||||
// the multiplayer-main-menu, we keep a list of lastuis, instead of just one,
|
||||
// so D3_IN_interactiveIngameGuiActive remains true in that case
|
||||
// (the ingame UI is still in the list)
|
||||
|
||||
lastuis.RemoveIndex( idx );
|
||||
}
|
||||
|
||||
D3_IN_interactiveIngameGuiActive = lastuis.Num() != 0;
|
||||
}
|
||||
|
||||
|
||||
static void PushButton( int key, bool value ) {
|
||||
// So we don't keep sending the same SE_KEY message over and over again
|
||||
if ( buttonStates[key] != value ) {
|
||||
buttonStates[key] = value;
|
||||
sysEvent_t res = { SE_KEY, key, value ? 1 : 0, 0, NULL };
|
||||
// this is done to generate two events per controller axis event
|
||||
// one SE_JOYSTICK and one SE_KEY
|
||||
event_overflow.Append(res);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_GetEvent
|
||||
|
@ -678,6 +1081,14 @@ sysEvent_t Sys_GetEvent() {
|
|||
|
||||
static const sysEvent_t res_none = { SE_NONE, 0, 0, 0, NULL };
|
||||
|
||||
// process any overflow.
|
||||
if (event_overflow.Num() > 0)
|
||||
{
|
||||
res = event_overflow[0];
|
||||
event_overflow.RemoveIndex(0);
|
||||
return res;
|
||||
}
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
static char s[SDL_TEXTINPUTEVENT_TEXT_SIZE] = {0};
|
||||
static size_t s_pos = 0;
|
||||
|
@ -958,6 +1369,120 @@ sysEvent_t Sys_GetEvent() {
|
|||
|
||||
return res;
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0) // gamecontroller/gamepad not supported in SDL1
|
||||
case SDL_CONTROLLERBUTTONDOWN:
|
||||
case SDL_CONTROLLERBUTTONUP:
|
||||
{
|
||||
if ( !in_useGamepad.GetBool() ) {
|
||||
common->Warning( "Gamepad support is disabled! Set the in_useGamepad CVar to 1 to enable it!\n" );
|
||||
continue;
|
||||
}
|
||||
|
||||
res.evType = SE_KEY;
|
||||
res.evValue2 = ev.cbutton.state == SDL_PRESSED ? 1 : 0;
|
||||
|
||||
// special case: always treat the start button as escape so it opens/closes the menu
|
||||
// (also makes that button non-bindable)
|
||||
if ( ev.cbutton.button == SDL_CONTROLLER_BUTTON_START ) {
|
||||
res.evValue = K_ESCAPE;
|
||||
return res;
|
||||
} else if( (ev.cbutton.button == SDL_CONTROLLER_BUTTON_A || ev.cbutton.button == SDL_CONTROLLER_BUTTON_Y)
|
||||
&& D3_IN_interactiveIngameGuiActive && sessLocal.GetActiveMenu() == NULL )
|
||||
{
|
||||
// ugly hack: currently an interactive ingame GUI (with a cursor) is active/focused
|
||||
// so pretend that the gamepads A (south) or Y (north, used by D3BFG to click ingame GUIs) button
|
||||
// is the left mouse button so it can be used for "clicking"..
|
||||
mouse_polls.Append( mouse_poll_t(M_ACTION1, res.evValue2) );
|
||||
res.evValue = K_MOUSE1;
|
||||
return res;
|
||||
}
|
||||
|
||||
sys_jEvents jEvent = mapjoybutton( (SDL_GameControllerButton)ev.cbutton.button );
|
||||
joystick_polls.Append( joystick_poll_t(jEvent, ev.cbutton.state == SDL_PRESSED ? 1 : 0) );
|
||||
|
||||
if ( ( jEvent >= J_ACTION_FIRST ) && ( jEvent <= J_ACTION_MAX ) ) {
|
||||
res.evValue = K_FIRST_JOY + ( jEvent - J_ACTION_FIRST );
|
||||
return res;
|
||||
}
|
||||
|
||||
continue; // try to get a decent event.
|
||||
}
|
||||
|
||||
case SDL_CONTROLLERAXISMOTION:
|
||||
{
|
||||
const int range = 16384;
|
||||
|
||||
if ( !in_useGamepad.GetBool() ) {
|
||||
// not printing a message here, I guess we get lots of spurious axis events..
|
||||
// TODO: or print a message if value is big enough?
|
||||
continue;
|
||||
}
|
||||
|
||||
sys_jEvents jEvent = mapjoyaxis( (SDL_GameControllerAxis)ev.caxis.axis);
|
||||
joystick_polls.Append(joystick_poll_t( jEvent, ev.caxis.value) );
|
||||
|
||||
if ( jEvent == J_AXIS_LEFT_X ) {
|
||||
PushButton( K_JOY_STICK1_LEFT, ( ev.caxis.value < -range ) );
|
||||
PushButton( K_JOY_STICK1_RIGHT, ( ev.caxis.value > range ) );
|
||||
} else if ( jEvent == J_AXIS_LEFT_Y ) {
|
||||
PushButton( K_JOY_STICK1_UP, ( ev.caxis.value < -range ) );
|
||||
PushButton( K_JOY_STICK1_DOWN, ( ev.caxis.value > range ) );
|
||||
} else if ( jEvent == J_AXIS_RIGHT_X ) {
|
||||
PushButton( K_JOY_STICK2_LEFT, ( ev.caxis.value < -range ) );
|
||||
PushButton( K_JOY_STICK2_RIGHT, ( ev.caxis.value > range ) );
|
||||
} else if ( jEvent == J_AXIS_RIGHT_Y ) {
|
||||
PushButton( K_JOY_STICK2_UP, ( ev.caxis.value < -range ) );
|
||||
PushButton( K_JOY_STICK2_DOWN, ( ev.caxis.value > range ) );
|
||||
} else if ( jEvent == J_AXIS_LEFT_TRIG ) {
|
||||
PushButton( K_JOY_TRIGGER1, ( ev.caxis.value > range ) );
|
||||
} else if ( jEvent == J_AXIS_RIGHT_TRIG ) {
|
||||
PushButton( K_JOY_TRIGGER2, ( ev.caxis.value > range ) );
|
||||
}
|
||||
if ( jEvent >= J_AXIS_MIN && jEvent <= J_AXIS_MAX ) {
|
||||
// NOTE: the stuff set here is only used to move the cursor in menus
|
||||
// ingame movement is done via joystick_polls
|
||||
int axis = jEvent - J_AXIS_MIN;
|
||||
float dz = joy_deadZone.GetFloat();
|
||||
|
||||
float val = fabsf(ev.caxis.value * (1.0f / 32767.0f));
|
||||
if(val < dz) {
|
||||
val = 0.0f;
|
||||
} else {
|
||||
// from deadzone .. 1 to 0 .. 1-deadzone
|
||||
val -= dz;
|
||||
// and then to 0..1
|
||||
val = val * (1.0f / (1.0f - dz));
|
||||
|
||||
if( ev.caxis.value < 0 ) {
|
||||
val = -val;
|
||||
}
|
||||
}
|
||||
|
||||
joyAxis[axis] = val;
|
||||
}
|
||||
|
||||
// handle next event; joy axis events are generated below,
|
||||
// when there are no further SDL events
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_JOYDEVICEADDED:
|
||||
{
|
||||
SDL_GameController* gc = SDL_GameControllerOpen( ev.jdevice.which );
|
||||
if ( gc != NULL ) {
|
||||
setGamepadType( gc );
|
||||
}
|
||||
// TODO: hot swapping maybe.
|
||||
//lbOnControllerPlugIn(event.jdevice.which);
|
||||
break;
|
||||
}
|
||||
case SDL_JOYDEVICEREMOVED:
|
||||
// TODO: hot swapping maybe.
|
||||
//lbOnControllerUnPlug(event.jdevice.which);
|
||||
break;
|
||||
#endif // SDL2+
|
||||
|
||||
case SDL_QUIT:
|
||||
PushConsoleEvent("quit");
|
||||
return res_none;
|
||||
|
@ -980,6 +1505,29 @@ sysEvent_t Sys_GetEvent() {
|
|||
}
|
||||
}
|
||||
|
||||
// before returning res_none for "these were all events for now",
|
||||
// first return joyaxis events, if gamepad is enabled and 16ms are over
|
||||
// (or we haven't returned the values for all axis yet)
|
||||
if ( in_useGamepad.GetBool() ) {
|
||||
static unsigned int lastMS = 0;
|
||||
static int joyAxisToSend = 0;
|
||||
unsigned int nowMS = Sys_Milliseconds();
|
||||
if ( nowMS - lastMS >= 16 ) {
|
||||
int val = joyAxis[joyAxisToSend] * 100; // float to percent
|
||||
res.evType = SE_JOYSTICK;
|
||||
res.evValue = joyAxisToSend;
|
||||
res.evValue2 = val;
|
||||
++joyAxisToSend;
|
||||
if(joyAxisToSend == MAX_JOYSTICK_AXIS) {
|
||||
// we're done for this frame, so update lastMS and reset joyAxisToSend
|
||||
joyAxisToSend = 0;
|
||||
lastMS = nowMS;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return res_none;
|
||||
}
|
||||
|
||||
|
@ -996,6 +1544,12 @@ void Sys_ClearEvents() {
|
|||
|
||||
kbd_polls.SetNum(0, false);
|
||||
mouse_polls.SetNum(0, false);
|
||||
joystick_polls.SetNum(0, false);
|
||||
|
||||
memset( buttonStates, 0, sizeof( buttonStates ) );
|
||||
memset( joyAxis, 0, sizeof( joyAxis ) );
|
||||
|
||||
event_overflow.SetNum(0, false);
|
||||
}
|
||||
|
||||
static void handleMouseGrab() {
|
||||
|
@ -1146,3 +1700,35 @@ Sys_EndMouseInputEvents
|
|||
void Sys_EndMouseInputEvents() {
|
||||
mouse_polls.SetNum(0, false);
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Joystick Input Methods
|
||||
================
|
||||
*/
|
||||
void Sys_SetRumble( int device, int low, int hi ) {
|
||||
// TODO: support multiple controllers.
|
||||
assert(device == 0);
|
||||
// TODO: support rumble maybe.
|
||||
assert(0);
|
||||
}
|
||||
|
||||
int Sys_PollJoystickInputEvents( int deviceNum ) {
|
||||
// TODO: support multiple controllers.
|
||||
assert(deviceNum == 0);
|
||||
return joystick_polls.Num();
|
||||
}
|
||||
|
||||
int Sys_ReturnJoystickInputEvent( const int n, int &action, int &value ) {
|
||||
if (n >= joystick_polls.Num())
|
||||
return 0;
|
||||
|
||||
action = joystick_polls[n].action;
|
||||
value = joystick_polls[n].value;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Sys_EndJoystickInputEvents() {
|
||||
joystick_polls.SetNum(0, false);
|
||||
}
|
||||
|
||||
|
|
|
@ -44,12 +44,12 @@ typedef enum {
|
|||
} cpuidSimd_t;
|
||||
|
||||
typedef enum {
|
||||
AXIS_SIDE,
|
||||
AXIS_FORWARD,
|
||||
AXIS_UP,
|
||||
AXIS_ROLL,
|
||||
AXIS_YAW,
|
||||
AXIS_PITCH,
|
||||
AXIS_LEFT_X,
|
||||
AXIS_LEFT_Y,
|
||||
AXIS_RIGHT_X,
|
||||
AXIS_RIGHT_Y,
|
||||
AXIS_LEFT_TRIG,
|
||||
AXIS_RIGHT_TRIG,
|
||||
MAX_JOYSTICK_AXIS
|
||||
} joystickAxis_t;
|
||||
|
||||
|
@ -59,7 +59,7 @@ typedef enum {
|
|||
SE_CHAR, // evValue is an ascii char
|
||||
SE_MOUSE, // evValue and evValue2 are relative signed x / y moves
|
||||
SE_MOUSE_ABS, // evValue and evValue2 are absolute x / y coordinates in the window
|
||||
SE_JOYSTICK_AXIS, // evValue is an axis number and evValue2 is the current state (-127 to 127)
|
||||
SE_JOYSTICK, // evValue is an axis number and evValue2 is the current state (-127 to 127)
|
||||
SE_CONSOLE // evPtr is a char*, from typing something at a non-game console
|
||||
} sysEventType_t;
|
||||
|
||||
|
@ -77,10 +77,52 @@ typedef enum {
|
|||
M_DELTAZ
|
||||
} sys_mEvents;
|
||||
|
||||
typedef enum {
|
||||
J_ACTION_FIRST,
|
||||
// these names are similar to the SDL3 SDL_GamepadButton names
|
||||
J_BTN_SOUTH = J_ACTION_FIRST, // bottom face button, like Xbox A
|
||||
J_BTN_EAST, // right face button, like Xbox B
|
||||
J_BTN_WEST, // left face button, like Xbox X
|
||||
J_BTN_NORTH, // top face button, like Xbox Y
|
||||
J_BTN_BACK,
|
||||
J_BTN_GUIDE, // Note: this one should probably not be used?
|
||||
J_BTN_START,
|
||||
J_BTN_LSTICK, // press left stick
|
||||
J_BTN_RSTICK, // press right stick
|
||||
J_BTN_LSHOULDER,
|
||||
J_BTN_RSHOULDER,
|
||||
|
||||
J_DPAD_UP,
|
||||
J_DPAD_DOWN,
|
||||
J_DPAD_LEFT,
|
||||
J_DPAD_RIGHT,
|
||||
|
||||
J_BTN_MISC1, // Additional button (e.g. Xbox Series X share button, PS5 microphone button, Nintendo Switch Pro capture button, Amazon Luna microphone button)
|
||||
J_BTN_RPADDLE1, // Upper or primary paddle, under your right hand (e.g. Xbox Elite paddle P1)
|
||||
J_BTN_LPADDLE1, // Upper or primary paddle, under your left hand (e.g. Xbox Elite paddle P3)
|
||||
J_BTN_RPADDLE2, // Lower or secondary paddle, under your right hand (e.g. Xbox Elite paddle P2)
|
||||
J_BTN_LPADDLE2, // Lower or secondary paddle, under your left hand (e.g. Xbox Elite paddle P4)
|
||||
|
||||
J_ACTION_MAX = J_BTN_LPADDLE2,
|
||||
// leaving some space here for about 12 additional J_ACTIONs, if needed
|
||||
|
||||
J_AXIS_MIN = 32,
|
||||
J_AXIS_LEFT_X = J_AXIS_MIN + AXIS_LEFT_X,
|
||||
J_AXIS_LEFT_Y = J_AXIS_MIN + AXIS_LEFT_Y,
|
||||
J_AXIS_RIGHT_X = J_AXIS_MIN + AXIS_RIGHT_X,
|
||||
J_AXIS_RIGHT_Y = J_AXIS_MIN + AXIS_RIGHT_Y,
|
||||
J_AXIS_LEFT_TRIG = J_AXIS_MIN + AXIS_LEFT_TRIG,
|
||||
J_AXIS_RIGHT_TRIG = J_AXIS_MIN + AXIS_RIGHT_TRIG,
|
||||
|
||||
J_AXIS_MAX = J_AXIS_MIN + MAX_JOYSTICK_AXIS - 1,
|
||||
|
||||
MAX_JOY_EVENT
|
||||
} sys_jEvents;
|
||||
|
||||
struct sysEvent_t {
|
||||
sysEventType_t evType;
|
||||
int evValue;
|
||||
int evValue2;
|
||||
int evValue; // for keys: K_* or ASCII code; for joystick: axis; for mouse: mouseX
|
||||
int evValue2; // for keys: 0/1 for up/down; for axis: value; for mouse: mouseY
|
||||
int evPtrLength; // bytes of data pointed to by evPtr, for journaling
|
||||
void * evPtr; // this must be manually freed if not NULL
|
||||
};
|
||||
|
@ -179,6 +221,12 @@ const char* Sys_GetLocalizedScancodeName( int key );
|
|||
// returns keyNum_t (K_SC_* constant) for given scancode name (like "SC_A")
|
||||
int Sys_GetKeynumForScancodeName( const char* name );
|
||||
|
||||
// returns display name of the key (between K_FIRST_JOY and K_LAST_JOY)
|
||||
// With SDL2 it'll return the name in the SDL_GameController standard layout
|
||||
// (which is based on XBox/XInput => on Nintendo gamepads, A/B and X/Y will be flipped),
|
||||
// with SDL3 it will return the "real" button name
|
||||
const char* Sys_GetLocalizedJoyKeyName( int key );
|
||||
|
||||
// keyboard input polling
|
||||
int Sys_PollKeyboardInputEvents( void );
|
||||
int Sys_ReturnKeyboardInputEvent( const int n, int &ch, bool &state );
|
||||
|
@ -189,11 +237,23 @@ int Sys_PollMouseInputEvents( void );
|
|||
int Sys_ReturnMouseInputEvent( const int n, int &action, int &value );
|
||||
void Sys_EndMouseInputEvents( void );
|
||||
|
||||
// joystick input polling
|
||||
void Sys_SetRumble( int device, int low, int hi );
|
||||
int Sys_PollJoystickInputEvents( int deviceNum );
|
||||
int Sys_ReturnJoystickInputEvent( const int n, int &action, int &value );
|
||||
void Sys_EndJoystickInputEvents();
|
||||
|
||||
// when the console is down, or the game is about to perform a lengthy
|
||||
// operation like map loading, the system can release the mouse cursor
|
||||
// when in windowed mode
|
||||
void Sys_GrabMouseCursor( bool grabIt );
|
||||
|
||||
// DG: added this for an ungodly hack for gamepad support
|
||||
// active = true means "currently a GUI with a cursor is active/focused"
|
||||
// active = false means "that GUI is not active anymore"
|
||||
class idUserInterface;
|
||||
void Sys_SetInteractiveIngameGuiActive( bool active, idUserInterface* ui );
|
||||
|
||||
void Sys_ShowWindow( bool show );
|
||||
bool Sys_IsWindowVisible( void );
|
||||
void Sys_ShowConsole( int visLevel, bool quitOnClose );
|
||||
|
|
|
@ -118,6 +118,9 @@ void idUserInterfaceManagerLocal::EndLevelLoad() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DG: this should probably be reset at this point
|
||||
Sys_SetInteractiveIngameGuiActive( false, NULL );
|
||||
}
|
||||
|
||||
void idUserInterfaceManagerLocal::Reload( bool all ) {
|
||||
|
@ -344,6 +347,9 @@ const char *idUserInterfaceLocal::HandleEvent( const sysEvent_t *event, int _tim
|
|||
return ret;
|
||||
}
|
||||
|
||||
// DG: used to translate gamepad input into events the UI system is familiar with
|
||||
sysEvent_t fakedEvent = {};
|
||||
|
||||
if ( event->evType == SE_MOUSE || event->evType == SE_MOUSE_ABS ) {
|
||||
if ( !desktop || (desktop->GetFlags() & WIN_MENUGUI) ) {
|
||||
// DG: this is a fullscreen GUI, scale the mousedelta added to cursorX/Y
|
||||
|
@ -401,6 +407,80 @@ const char *idUserInterfaceLocal::HandleEvent( const sysEvent_t *event, int _tim
|
|||
cursorY = 0;
|
||||
}
|
||||
}
|
||||
else if ( event->evType == SE_JOYSTICK && event->evValue2 != 0 && event->evValue < 4 )
|
||||
{
|
||||
// evValue: axis = jEvent - J_AXIS_MIN;
|
||||
// evValue2: percent (-100 to 100)
|
||||
|
||||
// currently uses both sticks for cursor movement
|
||||
// TODO could use one stick for scrolling (maybe by generating K_UPARROW/DOWNARROW events?)
|
||||
float addVal = expf( fabsf(event->evValue2 * 0.03f) ) * 0.5f;
|
||||
if(event->evValue2 < 0)
|
||||
addVal = -addVal;
|
||||
|
||||
if( event->evValue == 0 || event->evValue == 2 ) {
|
||||
cursorX += addVal;
|
||||
} else if( event->evValue == 1 || event->evValue == 3 ) {
|
||||
cursorY += addVal;
|
||||
}
|
||||
|
||||
if (cursorX < 0) {
|
||||
cursorX = 0;
|
||||
}
|
||||
if (cursorY < 0) {
|
||||
cursorY = 0;
|
||||
}
|
||||
|
||||
// some things like highlighting hovered UI elements need a mouse event,
|
||||
// so create a fake mouse event
|
||||
fakedEvent.evType = SE_MOUSE;
|
||||
// the coordinates (evValue/evValue2) aren't used, but keeping them at 0
|
||||
// (as default-initialized above) shouldn't hurt either way
|
||||
event = &fakedEvent;
|
||||
}
|
||||
else if ( event->evType == SE_KEY && event->evValue >= K_FIRST_JOY && event->evValue <= K_LAST_JOY )
|
||||
{
|
||||
// map some gamepad buttons to SE_KEY events that the UI already knows how to use
|
||||
int key = 0;
|
||||
if( idKeyInput::GetUsercmdAction( event->evValue ) == 20 /* UB_ATTACK*/ ) {
|
||||
// if this button is bound to _attack (fire), treat it as left mouse button
|
||||
key = K_MOUSE1;
|
||||
} else {
|
||||
switch(event->evValue) {
|
||||
// emulate mouse buttons
|
||||
case K_JOY_BTN_SOUTH: // A on xbox controller
|
||||
key = K_MOUSE1;
|
||||
break;
|
||||
case K_JOY_BTN_EAST: // B on xbox controller
|
||||
key = K_MOUSE2;
|
||||
break;
|
||||
// emulate cursor keys (sometimes used for scrolling or selecting in a list)
|
||||
case K_JOY_DPAD_UP:
|
||||
key = K_UPARROW;
|
||||
break;
|
||||
case K_JOY_DPAD_DOWN:
|
||||
key = K_DOWNARROW;
|
||||
break;
|
||||
case K_JOY_DPAD_LEFT:
|
||||
key = K_LEFTARROW;
|
||||
break;
|
||||
case K_JOY_DPAD_RIGHT:
|
||||
key = K_RIGHTARROW;
|
||||
break;
|
||||
// enter is useful after selecting something with cursor keys (or dpad)
|
||||
// in a list, like selecting a savegame - I guess left trigger is suitable for that?
|
||||
// (right trigger is often used for shooting, which we use as K_MOUSE1 here)
|
||||
case K_JOY_TRIGGER1:
|
||||
key = K_ENTER;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (key != 0) {
|
||||
fakedEvent = *event;
|
||||
fakedEvent.evValue = key;
|
||||
event = &fakedEvent;
|
||||
}
|
||||
}
|
||||
|
||||
if ( desktop ) {
|
||||
return desktop->HandleEvent( event, updateVisuals );
|
||||
|
@ -507,6 +587,10 @@ const char *idUserInterfaceLocal::Activate(bool activate, int _time) {
|
|||
time = _time;
|
||||
active = activate;
|
||||
if ( desktop ) {
|
||||
// DG: added this hack for gamepad input
|
||||
if ( interactive ) {
|
||||
Sys_SetInteractiveIngameGuiActive( activate, this );
|
||||
} // DG end
|
||||
activateStr = "";
|
||||
desktop->Activate( activate, activateStr );
|
||||
return activateStr;
|
||||
|
|
Loading…
Reference in a new issue