mirror of
https://github.com/dhewm/dhewm3.git
synced 2024-11-29 07:32:25 +00:00
Some functions that will be used by the ImGui keybinding menu
This commit is contained in:
parent
8554487bf5
commit
6d508eac17
4 changed files with 209 additions and 15 deletions
|
@ -278,6 +278,28 @@ static bool utf8ToISO8859_1(const char* inbuf, char* outbuf, size_t outsize) {
|
|||
}
|
||||
#endif // SDL2
|
||||
|
||||
// start button isn't bindable, but I want to use its name in the imgui-based menu
|
||||
const char* D3_GetGamepadStartButtonName() {
|
||||
int layout = joy_gamepadLayout.GetInteger();
|
||||
if ( layout == -1 ) {
|
||||
layout = gamepadType;
|
||||
}
|
||||
|
||||
switch( layout ) {
|
||||
default:
|
||||
common->Warning( "joy_gamepadLayout has invalid value %d !\n", joy_gamepadLayout.GetInteger() );
|
||||
// fall-through
|
||||
case D3_GAMEPAD_PLAYSTATION_OLD:
|
||||
case D3_GAMEPAD_XINPUT:
|
||||
return "Pad Start";
|
||||
case D3_GAMEPAD_NINTENDO:
|
||||
return "Pad (+)";
|
||||
|
||||
case D3_GAMEPAD_PLAYSTATION:
|
||||
return "Pad Options";
|
||||
}
|
||||
}
|
||||
|
||||
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..
|
||||
|
||||
|
@ -409,28 +431,41 @@ const char* Sys_GetLocalizedJoyKeyName( int key ) {
|
|||
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.
|
||||
// Otherwise return same name as Sys_GetScancodeName()
|
||||
// !! Returned string is only valid until next call to this function !!
|
||||
const char* Sys_GetLocalizedScancodeName( int key ) {
|
||||
static const char* getLocalizedScancodeName( int key, bool useUtf8 )
|
||||
{
|
||||
if ( key >= K_FIRST_SCANCODE && key <= K_LAST_SCANCODE ) {
|
||||
int scIdx = key - K_FIRST_SCANCODE;
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
SDL_Scancode sc = ( SDL_Scancode ) scancodemappings[scIdx].sdlScancode;
|
||||
SDL_Keycode k = SDL_GetKeyFromScancode( sc );
|
||||
if ( k >= 0xA1 && k <= 0xFF ) {
|
||||
static char shortStr[3] = {};
|
||||
if ( useUtf8 ) {
|
||||
// SDL_Keycodes are unicode chars (where applicable),
|
||||
// so at least for Latin-1 turn them directly into UTF-8
|
||||
if ( k >= 0xE0 && k <= 0xFE && k != 0xF7 ) {
|
||||
// turn lowercase chars into their uppercase equivalents
|
||||
k -= 32;
|
||||
}
|
||||
shortStr[0] = (unsigned char)( 0xC0 + (k >> 6) );
|
||||
shortStr[1] = (unsigned char)( 0x80 + (k & 0x3F) );
|
||||
return shortStr;
|
||||
} else {
|
||||
// luckily, the "High-ASCII" (ISO-8559-1) chars supported by Doom3
|
||||
// have the same values as the corresponding SDL_Keycodes.
|
||||
static char oneCharStr[2] = {0, 0};
|
||||
oneCharStr[0] = (unsigned char)k;
|
||||
return oneCharStr;
|
||||
shortStr[0] = (unsigned char)k;
|
||||
shortStr[1] = 0;
|
||||
return shortStr;
|
||||
}
|
||||
} else if ( k != SDLK_UNKNOWN ) {
|
||||
const char *ret = SDL_GetKeyName( k );
|
||||
// the keyname from SDL2 is in UTF-8, which Doom3 can't print,
|
||||
// so only return the name if it's ASCII, otherwise fall back to "SC_bla"
|
||||
if ( ret && *ret != '\0' ) {
|
||||
if( useUtf8 ) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if( isAscii( ret ) ) {
|
||||
return ret;
|
||||
}
|
||||
|
@ -448,6 +483,19 @@ const char* Sys_GetLocalizedScancodeName( int key ) {
|
|||
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.
|
||||
// Otherwise return same name as Sys_GetScancodeName()
|
||||
// !! Returned string is only valid until next call to this function !!
|
||||
const char* Sys_GetLocalizedScancodeName( int key ) {
|
||||
return getLocalizedScancodeName( key, false );
|
||||
}
|
||||
|
||||
const char* Sys_GetLocalizedScancodeNameUTF8( int key ) {
|
||||
return getLocalizedScancodeName( key, true );
|
||||
}
|
||||
|
||||
// returns keyNum_t (K_SC_* constant) for given scancode name (like "SC_A")
|
||||
// only makes sense to call it if name starts with "SC_" (or "sc_")
|
||||
// returns -1 if not found
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "sys_imgui.h"
|
||||
|
@ -14,6 +16,7 @@ typedef char* (*MY_XGETDEFAULTFUN)(Display*, const char*, const char*);
|
|||
#include "../libs/imgui/backends/imgui_impl_sdl2.h"
|
||||
|
||||
#include "framework/Common.h"
|
||||
#include "framework/KeyInput.h"
|
||||
#include "renderer/qgl.h"
|
||||
#include "renderer/tr_local.h" // glconfig
|
||||
|
||||
|
@ -31,6 +34,82 @@ ImGuiContext* imguiCtx = NULL;
|
|||
static bool haveNewFrame = false;
|
||||
static int openImguiWindows = 0; // or-ed enum D3ImGuiWindow values
|
||||
|
||||
// was there a key down or button (mouse/gamepad) down event this frame?
|
||||
// used to make the warning overlay disappear
|
||||
static bool hadKeyDownEvent = false;
|
||||
|
||||
static idStr warningOverlayText;
|
||||
static double warningOverlayStartTime = -100.0;
|
||||
static ImVec2 warningOverlayStartPos;
|
||||
|
||||
static void UpdateWarningOverlay()
|
||||
{
|
||||
double timeNow = ImGui::GetTime();
|
||||
if ( timeNow - warningOverlayStartTime > 4.0f ) {
|
||||
warningOverlayStartTime = -100.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
// also hide if a key was pressed or maybe even if the mouse was moved (too much)
|
||||
ImVec2 mdv = ImGui::GetMousePos() - warningOverlayStartPos; // Mouse Delta Vector
|
||||
float mouseDelta = sqrtf( mdv.x * mdv.x + mdv.y * mdv.y );
|
||||
const float fontSize = ImGui::GetFontSize();
|
||||
if ( mouseDelta > fontSize * 4.0f || hadKeyDownEvent ) {
|
||||
warningOverlayStartTime = -100.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Always, ImVec2(0.5f, 0.5f));
|
||||
ImGui::PushStyleColor( ImGuiCol_WindowBg, ImVec4(1.0f, 0.4f, 0.4f, 0.4f) );
|
||||
float padSize = fontSize * 2.0f;
|
||||
ImGui::PushStyleVar( ImGuiStyleVar_WindowPadding, ImVec2(padSize, padSize) );
|
||||
|
||||
int winFlags = ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove
|
||||
| ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize;
|
||||
ImGui::Begin("WarningOverlay", NULL, winFlags);
|
||||
|
||||
ImDrawList* drawList = ImGui::GetWindowDrawList();
|
||||
ImVec2 points[] = {
|
||||
{0, 40}, {40, 40}, {20, 0}, // triangle
|
||||
{20, 12}, {20, 28}, // line
|
||||
{20, 33} // dot
|
||||
};
|
||||
|
||||
float iconScale = 1.0f; // TODO: global scale also used for fontsize
|
||||
|
||||
ImVec2 offset = ImGui::GetWindowPos() + ImVec2(fontSize, fontSize);
|
||||
for ( ImVec2& v : points ) {
|
||||
v.x = roundf( v.x * iconScale );
|
||||
v.y = roundf( v.y * iconScale );
|
||||
v += offset;
|
||||
}
|
||||
|
||||
ImU32 color = ImGui::GetColorU32( ImVec4(0.1f, 0.1f, 0.1f, 1.0f) );
|
||||
|
||||
drawList->AddTriangle( points[0], points[1], points[2], color, roundf( iconScale * 4.0f ) );
|
||||
|
||||
drawList->AddPolyline( points+3, 2, color, 0, roundf( iconScale * 3.0f ) );
|
||||
|
||||
float dotRadius = 2.0f * iconScale;
|
||||
drawList->AddEllipseFilled( points[5], ImVec2(dotRadius, dotRadius), color, 0, 6 );
|
||||
|
||||
ImGui::Indent( 40.0f * iconScale );
|
||||
ImGui::TextUnformatted( warningOverlayText.c_str() );
|
||||
|
||||
ImGui::End();
|
||||
|
||||
ImGui::PopStyleVar(); // WindowPadding
|
||||
ImGui::PopStyleColor(); // WindowBg
|
||||
}
|
||||
|
||||
void ShowWarningOverlay( const char* text )
|
||||
{
|
||||
warningOverlayText = text;
|
||||
warningOverlayStartTime = ImGui::GetTime();
|
||||
warningOverlayStartPos = ImGui::GetMousePos();
|
||||
}
|
||||
|
||||
|
||||
static float GetDefaultDPI()
|
||||
{
|
||||
SDL_Window* win = sdlWindow;
|
||||
|
@ -203,6 +282,8 @@ void NewFrame()
|
|||
ImGui::NewFrame();
|
||||
haveNewFrame = true;
|
||||
|
||||
UpdateWarningOverlay();
|
||||
|
||||
if (openImguiWindows & D3_ImGuiWin_Settings) {
|
||||
Com_DrawDhewm3SettingsMenu();
|
||||
}
|
||||
|
@ -215,6 +296,8 @@ void NewFrame()
|
|||
}
|
||||
}
|
||||
|
||||
bool keybindModeEnabled = false;
|
||||
|
||||
// called with every SDL event by Sys_GetEvent()
|
||||
// returns true if ImGui has handled the event (so it shouldn't be handled by D3)
|
||||
bool ProcessEvent(const void* sdlEvent)
|
||||
|
@ -228,14 +311,42 @@ bool ProcessEvent(const void* sdlEvent)
|
|||
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data.
|
||||
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
|
||||
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
|
||||
if( ImGui_ImplSDL2_ProcessEvent( ev ) ) {
|
||||
|
||||
bool imguiUsedEvent = ImGui_ImplSDL2_ProcessEvent( ev );
|
||||
if ( keybindModeEnabled ) {
|
||||
// in keybind mode, all input events are passed to Doom3 so it can translate them
|
||||
// to internal events and we can access and use them to create a new binding
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ImGui::IsWindowFocused( ImGuiFocusedFlags_AnyWindow )
|
||||
&& (ev->type == SDL_CONTROLLERAXISMOTION || ev->type == SDL_CONTROLLERBUTTONDOWN) ) {
|
||||
// don't pass on controller axis events to avoid moving the mouse cursor
|
||||
// and controller button events to avoid emulating mouse clicks
|
||||
return true;
|
||||
}
|
||||
|
||||
switch( ev->type ) {
|
||||
// Hack: detect if any key was pressed to close the warning overlay
|
||||
case SDL_CONTROLLERBUTTONDOWN:
|
||||
case SDL_MOUSEWHEEL:
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
case SDL_KEYDOWN:
|
||||
// TODO: controller trigger?
|
||||
hadKeyDownEvent = true;
|
||||
}
|
||||
if( imguiUsedEvent ) {
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
if ( io.WantCaptureMouse ) {
|
||||
switch( ev->type ) {
|
||||
case SDL_MOUSEMOTION:
|
||||
case SDL_MOUSEWHEEL:
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
|
||||
// Note: still pass button up events to the engine, so if they were pressed down
|
||||
// before an imgui window got focus they don't remain pressed indefinitely
|
||||
//case SDL_MOUSEBUTTONUP:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -243,15 +354,30 @@ bool ProcessEvent(const void* sdlEvent)
|
|||
if ( io.WantCaptureKeyboard ) {
|
||||
switch( ev->type ) {
|
||||
case SDL_TEXTINPUT:
|
||||
return true;
|
||||
case SDL_KEYDOWN:
|
||||
case SDL_KEYUP:
|
||||
//case SDL_KEYUP: NOTE: see above why key up events are passed to the engine
|
||||
if ( ev->key.keysym.sym < SDLK_F1 || ev->key.keysym.sym > SDLK_F12) {
|
||||
// F1 - F12 are passed to the engine so its shortcuts
|
||||
// (like quickload or screenshot) still work
|
||||
// Doom3's menu does the same
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SetKeyBindMode( bool enable )
|
||||
{
|
||||
keybindModeEnabled = enable;
|
||||
// make sure no keys are registered as down, neither when entering nor when exiting keybind mode
|
||||
idKeyInput::ClearStates();
|
||||
}
|
||||
|
||||
void EndFrame()
|
||||
{
|
||||
if (openImguiWindows == 0 && !haveNewFrame)
|
||||
|
@ -297,6 +423,11 @@ void EndFrame()
|
|||
if ( curArrayBuffer != 0 ) {
|
||||
qglBindBufferARB( GL_ARRAY_BUFFER_ARB, curArrayBuffer );
|
||||
}
|
||||
|
||||
// reset this at the end of each frame, will be set again by ProcessEvent()
|
||||
if ( hadKeyDownEvent ) {
|
||||
hadKeyDownEvent = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -41,6 +41,10 @@ extern int GetOpenWindowsMask();
|
|||
// returns true if ImGui has handled the event (so it shouldn't be handled by D3)
|
||||
extern bool ProcessEvent(const void* sdlEvent);
|
||||
|
||||
// for binding keys from an ImGui-based menu: send input events to dhewm3
|
||||
// even if ImGui window has focus
|
||||
extern void SetKeyBindMode( bool enable );
|
||||
|
||||
// NewFrame() is called once per D3 frame, after all events have been gotten
|
||||
// => ProcessEvent() has already been called (probably multiple times)
|
||||
extern void NewFrame();
|
||||
|
@ -52,6 +56,11 @@ extern void EndFrame();
|
|||
extern float GetScale();
|
||||
extern void SetScale( float scale );
|
||||
|
||||
// show a red overlay-window at the center of the screen that contains
|
||||
// a warning symbol (triangle with !) and the given text
|
||||
// disappears after a few seconds or when a key is pressed or the mouse is moved
|
||||
extern void ShowWarningOverlay( const char* text );
|
||||
|
||||
#else // IMGUI_DISABLE - just stub out everything
|
||||
|
||||
inline bool IsImguiEnabled()
|
||||
|
@ -69,6 +78,8 @@ inline void Shutdown() {}
|
|||
|
||||
inline bool ProcessEvent(const void* sdlEvent) { return false; }
|
||||
|
||||
inline void SetKeyBindMode( bool enable ) {}
|
||||
|
||||
inline void NewFrame() {}
|
||||
|
||||
inline void EndFrame() {}
|
||||
|
@ -82,6 +93,8 @@ inline int GetOpenWindowsMask() { return 0; }
|
|||
inline float GetScale() { return 1.0f; }
|
||||
inline void SetScale( float scale ) {}
|
||||
|
||||
inline void ShowWarningOverlay( const char* text ) {}
|
||||
|
||||
#endif
|
||||
|
||||
}} //namespace D3::ImGuiHooks
|
||||
|
|
|
@ -218,6 +218,8 @@ const char* Sys_GetScancodeName( int key );
|
|||
// Otherwise return same name as Sys_GetScancodeName()
|
||||
// !! Returned string is only valid until next call to this function !!
|
||||
const char* Sys_GetLocalizedScancodeName( int key );
|
||||
// the same, but using UTF-8 instead of "High-ASCII"
|
||||
const char* Sys_GetLocalizedScancodeNameUTF8( int key );
|
||||
// returns keyNum_t (K_SC_* constant) for given scancode name (like "SC_A")
|
||||
int Sys_GetKeynumForScancodeName( const char* name );
|
||||
|
||||
|
|
Loading…
Reference in a new issue