mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2025-04-21 01:00:52 +00:00
Merge pull request #213 from DanielGibson/rb-sdl-improvements
SDL: Unicode input and more then 3 mouse buttons, fixes issue #89
This commit is contained in:
commit
7bc5c56314
5 changed files with 189 additions and 72 deletions
|
@ -204,6 +204,17 @@ keyname_t keynames[] =
|
|||
NAMEKEY( MOUSE7, "#str_07060" ),
|
||||
NAMEKEY( MOUSE8, "#str_07061" ),
|
||||
|
||||
// DG: some more mouse buttons
|
||||
NAMEKEY2( MOUSE9 ),
|
||||
NAMEKEY2( MOUSE10 ),
|
||||
NAMEKEY2( MOUSE11 ),
|
||||
NAMEKEY2( MOUSE12 ),
|
||||
NAMEKEY2( MOUSE13 ),
|
||||
NAMEKEY2( MOUSE14 ),
|
||||
NAMEKEY2( MOUSE15 ),
|
||||
NAMEKEY2( MOUSE16 ),
|
||||
// DG end
|
||||
|
||||
NAMEKEY( MWHEELDOWN, "#str_07132" ),
|
||||
NAMEKEY( MWHEELUP, "#str_07131" ),
|
||||
|
||||
|
|
|
@ -1360,6 +1360,16 @@ void idUsercmdGenLocal::Mouse()
|
|||
case M_ACTION6:
|
||||
case M_ACTION7:
|
||||
case M_ACTION8:
|
||||
|
||||
// DG: support some more mouse buttons
|
||||
case M_ACTION9:
|
||||
case M_ACTION10:
|
||||
case M_ACTION11:
|
||||
case M_ACTION12:
|
||||
case M_ACTION13:
|
||||
case M_ACTION14:
|
||||
case M_ACTION15:
|
||||
case M_ACTION16: // DG end
|
||||
mouseButton = K_MOUSE1 + ( action - M_ACTION1 );
|
||||
mouseDown = ( value != 0 );
|
||||
Key( mouseButton, mouseDown );
|
||||
|
|
|
@ -163,6 +163,42 @@ static SDL_Scancode KeyNumToSDLScanCode( int keyNum )
|
|||
return SDL_SCANCODE_UNKNOWN;
|
||||
}
|
||||
|
||||
// both strings are expected to have at most SDL_TEXTINPUTEVENT_TEXT_SIZE chars/ints (including terminating null)
|
||||
static void ConvertUTF8toUTF32(const char* utf8str, int32* utf32buf)
|
||||
{
|
||||
static SDL_iconv_t cd = SDL_iconv_t(-1);
|
||||
|
||||
if( cd == SDL_iconv_t(-1) )
|
||||
{
|
||||
const char* toFormat = "UTF-32LE"; // TODO: what does d3bfg expect on big endian machines?
|
||||
cd = SDL_iconv_open(toFormat, "UTF-8");
|
||||
if( cd == SDL_iconv_t(-1) )
|
||||
{
|
||||
common->Warning("Couldn't initialize SDL_iconv for UTF-8 to UTF-32!"); // TODO: or error?
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
size_t len = strlen(utf8str);
|
||||
|
||||
size_t inbytesleft = len;
|
||||
size_t outbytesleft = 4 * SDL_TEXTINPUTEVENT_TEXT_SIZE; // *4 because utf-32 needs 4x as much space as utf-8
|
||||
char* outbuf = (char*)utf32buf;
|
||||
size_t n = SDL_iconv(cd, &utf8str, &inbytesleft, &outbuf, &outbytesleft);
|
||||
|
||||
if( n == size_t(-1) ) // some error occured during iconv
|
||||
{
|
||||
common->Warning("Converting UTF-8 string \"%s\" from SDL_TEXTINPUT to UTF-32 failed!", utf8str);
|
||||
|
||||
// clear utf32-buffer, just to be sure there's no garbage..
|
||||
memset(utf32buf, 0, SDL_TEXTINPUTEVENT_TEXT_SIZE*sizeof(int32));
|
||||
}
|
||||
|
||||
// reset cd so it can be used again
|
||||
SDL_iconv(cd, NULL, &inbytesleft, NULL, &outbytesleft);
|
||||
|
||||
}
|
||||
|
||||
#else // SDL1.2
|
||||
static int SDL_KeyToDoom3Key( SDL_Keycode key, bool& isChar )
|
||||
{
|
||||
|
@ -791,8 +827,9 @@ Sys_GetEvent
|
|||
*/
|
||||
sysEvent_t Sys_GetEvent()
|
||||
{
|
||||
SDL_Event ev;
|
||||
sysEvent_t res = { };
|
||||
|
||||
SDL_Event ev;
|
||||
int key;
|
||||
|
||||
// when this is returned, it's assumed that there are no more events!
|
||||
|
@ -802,24 +839,26 @@ sysEvent_t Sys_GetEvent()
|
|||
static int previous_hat_state = SDL_HAT_CENTERED;
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
static char str[SDL_TEXTINPUTEVENT_TEXT_SIZE] = {0};
|
||||
static size_t str_pos = 0;
|
||||
|
||||
if( str_pos != 0 )
|
||||
// utf-32 version of the textinput event
|
||||
static int32 uniStr[SDL_TEXTINPUTEVENT_TEXT_SIZE] = {0};
|
||||
static size_t uniStrPos = 0;
|
||||
|
||||
if(uniStr[0] != 0)
|
||||
{
|
||||
res.evType = SE_CHAR;
|
||||
res.evValue = str[str_pos];
|
||||
|
||||
++str_pos;
|
||||
if( !str[str_pos] )
|
||||
res.evValue = uniStr[uniStrPos];
|
||||
|
||||
++uniStrPos;
|
||||
|
||||
if( !uniStr[uniStrPos] || uniStrPos == SDL_TEXTINPUTEVENT_TEXT_SIZE )
|
||||
{
|
||||
memset( str, 0, sizeof( str ) );
|
||||
str_pos = 0;
|
||||
memset(uniStr, 0, sizeof(uniStr));
|
||||
uniStrPos = 0;
|
||||
}
|
||||
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// DG: fake a "mousewheel not pressed anymore" event for SDL2
|
||||
// so scrolling in menus stops after one step
|
||||
static int mwheelRel = 0;
|
||||
|
@ -832,20 +871,20 @@ sysEvent_t Sys_GetEvent()
|
|||
return res;
|
||||
}
|
||||
// DG end
|
||||
#endif
|
||||
#endif // SDL2
|
||||
|
||||
static byte c = 0;
|
||||
static int32 uniChar = 0;
|
||||
|
||||
if( c )
|
||||
if(uniChar)
|
||||
{
|
||||
res.evType = SE_CHAR;
|
||||
res.evValue = c;
|
||||
|
||||
c = 0;
|
||||
|
||||
res.evValue = uniChar;
|
||||
|
||||
uniChar = 0;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// loop until there is an event we care about (will return then) or no more events
|
||||
while( SDL_PollEvent( &ev ) )
|
||||
{
|
||||
|
@ -878,6 +917,11 @@ sysEvent_t Sys_GetEvent()
|
|||
cvarSystem->SetCVarBool( "com_pause", true );
|
||||
// DG end
|
||||
break;
|
||||
|
||||
case SDL_WINDOWEVENT_LEAVE:
|
||||
// mouse has left the window
|
||||
res.evType = SE_MOUSE_LEAVE;
|
||||
return res;
|
||||
|
||||
// DG: handle resizing and moving of window
|
||||
case SDL_WINDOWEVENT_RESIZED:
|
||||
|
@ -900,11 +944,10 @@ sysEvent_t Sys_GetEvent()
|
|||
r_windowY.SetInteger( y );
|
||||
break;
|
||||
}
|
||||
// DG end
|
||||
}
|
||||
|
||||
continue; // handle next event
|
||||
#else
|
||||
#else // SDL 1.2
|
||||
case SDL_ACTIVEEVENT:
|
||||
{
|
||||
// DG: (un-)pause the game when focus is gained, that also (un-)grabs the input
|
||||
|
@ -926,6 +969,14 @@ sysEvent_t Sys_GetEvent()
|
|||
}
|
||||
|
||||
cvarSystem->SetCVarBool( "com_pause", pause );
|
||||
|
||||
if( ev.active.state == SDL_APPMOUSEFOCUS && !ev.active.gain )
|
||||
{
|
||||
// the mouse has left the window.
|
||||
res.evType = SE_MOUSE_LEAVE;
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
continue; // handle next event
|
||||
|
@ -943,12 +994,13 @@ sysEvent_t Sys_GetEvent()
|
|||
|
||||
glConfig.nativeScreenWidth = w;
|
||||
glConfig.nativeScreenHeight = h;
|
||||
|
||||
// for some reason this needs a vid_restart in SDL1 but not SDL2 so GLimp_SetScreenParms() is called
|
||||
PushConsoleEvent( "vid_restart" );
|
||||
continue; // handle next event
|
||||
}
|
||||
// DG end
|
||||
#endif
|
||||
// DG end
|
||||
#endif // SDL1.2
|
||||
|
||||
case SDL_KEYDOWN:
|
||||
if( ev.key.keysym.sym == SDLK_RETURN && ( ev.key.keysym.mod & KMOD_ALT ) > 0 )
|
||||
|
@ -979,14 +1031,13 @@ sysEvent_t Sys_GetEvent()
|
|||
|
||||
#if ! SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
// DG: only do this for key-down, don't care about isChar from SDL_KeyToDoom3Key.
|
||||
// if unicode is not 0 and is translatable to ASCII it should work..
|
||||
if( ev.key.state == SDL_PRESSED && ( ev.key.keysym.unicode & 0xff80 ) == 0 )
|
||||
// if unicode is not 0 it should work..
|
||||
if( ev.key.state == SDL_PRESSED )
|
||||
{
|
||||
// FIXME: can we support utf32?
|
||||
c = ev.key.keysym.unicode & 0x7f;
|
||||
uniChar = ev.key.keysym.unicode; // for SE_CHAR
|
||||
}
|
||||
// DG end
|
||||
#endif
|
||||
#endif // SDL 1.2
|
||||
|
||||
// fall through
|
||||
case SDL_KEYUP:
|
||||
|
@ -997,7 +1048,7 @@ sysEvent_t Sys_GetEvent()
|
|||
if( ev.key.keysym.scancode == SDL_SCANCODE_GRAVE )
|
||||
{
|
||||
key = K_GRAVE;
|
||||
c = K_BACKSPACE; // bad hack to get empty console inputline..
|
||||
uniChar = K_BACKSPACE; // bad hack to get empty console inputline..
|
||||
} // DG end, the original code is in the else case
|
||||
else
|
||||
{
|
||||
|
@ -1012,7 +1063,7 @@ sysEvent_t Sys_GetEvent()
|
|||
|
||||
continue; // just handle next event
|
||||
}
|
||||
#else
|
||||
#else // SDL1.2
|
||||
key = SDL_KeyToDoom3Key( ev.key.keysym.sym, isChar );
|
||||
|
||||
if( key == 0 )
|
||||
|
@ -1022,28 +1073,27 @@ sysEvent_t Sys_GetEvent()
|
|||
if( uc == Sys_GetConsoleKey( false ) || uc == Sys_GetConsoleKey( true ) )
|
||||
{
|
||||
key = K_GRAVE;
|
||||
c = K_BACKSPACE; // bad hack to get empty console inputline..
|
||||
uniChar = K_BACKSPACE; // bad hack to get empty console inputline..
|
||||
}
|
||||
else
|
||||
{
|
||||
if( c )
|
||||
if(uniChar)
|
||||
{
|
||||
res.evType = SE_CHAR;
|
||||
res.evValue = c;
|
||||
|
||||
c = 0;
|
||||
|
||||
res.evValue = uniChar;
|
||||
|
||||
uniChar = 0;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
if( ev.type == SDL_KEYDOWN ) // FIXME: don't complain if this was an ASCII char and the console is open?
|
||||
common->Warning( "unmapped SDL key %d (0x%x) scancode %d", ev.key.keysym.sym, ev.key.keysym.unicode, ev.key.keysym.scancode );
|
||||
|
||||
|
||||
|
||||
continue; // just handle next event
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif // SDL 1.2
|
||||
}
|
||||
|
||||
res.evType = SE_KEY;
|
||||
|
@ -1053,7 +1103,7 @@ sysEvent_t Sys_GetEvent()
|
|||
kbd_polls.Append( kbd_poll_t( key, ev.key.state == SDL_PRESSED ) );
|
||||
|
||||
if( key == K_BACKSPACE && ev.key.state == SDL_PRESSED )
|
||||
c = key;
|
||||
uniChar = key;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@ -1062,20 +1112,26 @@ sysEvent_t Sys_GetEvent()
|
|||
case SDL_TEXTINPUT:
|
||||
if( ev.text.text[0] != '\0' )
|
||||
{
|
||||
// FIXME: all this really only works for ascii.. convert to unicode etc
|
||||
if( ev.text.text[1] )
|
||||
{
|
||||
// more than 1 char => handle the next chars later
|
||||
idStr::Copynz( str, ev.text.text + 1, sizeof( str ) );
|
||||
}
|
||||
// fill uniStr array for SE_CHAR events
|
||||
ConvertUTF8toUTF32(ev.text.text, uniStr);
|
||||
|
||||
// return an event with the first/only char
|
||||
res.evType = SE_CHAR;
|
||||
res.evValue = ev.text.text[0];
|
||||
res.evValue = uniStr[0];
|
||||
|
||||
uniStrPos = 1;
|
||||
|
||||
if( uniStr[1] == 0)
|
||||
{
|
||||
// it's just this one character, clear uniStr
|
||||
uniStr[0] = 0;
|
||||
uniStrPos = 0;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
continue; // just handle next event
|
||||
#endif
|
||||
#endif // SDL2
|
||||
|
||||
case SDL_MOUSEMOTION:
|
||||
// DG: return event with absolute mouse-coordinates when in menu
|
||||
|
@ -1108,25 +1164,16 @@ sysEvent_t Sys_GetEvent()
|
|||
case SDL_MOUSEWHEEL:
|
||||
res.evType = SE_KEY;
|
||||
|
||||
if( ev.wheel.y > 0 )
|
||||
{
|
||||
res.evValue = K_MWHEELUP;
|
||||
mouse_polls.Append( mouse_poll_t( M_DELTAZ, 1 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
res.evValue = K_MWHEELDOWN;
|
||||
mouse_polls.Append( mouse_poll_t( M_DELTAZ, -1 ) );
|
||||
}
|
||||
|
||||
// DG: remember mousewheel direction to issue a "not pressed anymore" event
|
||||
res.evValue = (ev.wheel.y > 0) ? K_MWHEELUP : K_MWHEELDOWN;
|
||||
mouse_polls.Append( mouse_poll_t( M_DELTAZ, ev.wheel.y ) );
|
||||
|
||||
res.evValue2 = 1; // for "pressed"
|
||||
|
||||
// remember mousewheel direction to issue a "not pressed anymore" event
|
||||
mwheelRel = res.evValue;
|
||||
// DG end
|
||||
|
||||
res.evValue2 = 1;
|
||||
|
||||
return res;
|
||||
#endif
|
||||
#endif // SDL2
|
||||
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
|
@ -1158,7 +1205,20 @@ sysEvent_t Sys_GetEvent()
|
|||
if( ev.button.state == SDL_PRESSED )
|
||||
mouse_polls.Append( mouse_poll_t( M_DELTAZ, -1 ) );
|
||||
break;
|
||||
#endif
|
||||
#endif // SDL1.2
|
||||
|
||||
default:
|
||||
// handle X1 button and above
|
||||
if( ev.button.button <= 16 ) // d3bfg doesn't support more than 16 mouse buttons
|
||||
{
|
||||
int buttonIndex = ev.button.button - SDL_BUTTON_LEFT;
|
||||
res.evValue = K_MOUSE1 + buttonIndex;
|
||||
mouse_polls.Append( mouse_poll_t( M_ACTION1 + buttonIndex, ev.button.state == SDL_PRESSED ? 1 : 0 ) );
|
||||
}
|
||||
else // unsupported mouse button
|
||||
{
|
||||
continue; // just ignore
|
||||
}
|
||||
}
|
||||
|
||||
res.evValue2 = ev.button.state == SDL_PRESSED ? 1 : 0;
|
||||
|
@ -1441,7 +1501,8 @@ sysEvent_t Sys_GetEvent()
|
|||
|
||||
case SDL_QUIT:
|
||||
PushConsoleEvent( "quit" );
|
||||
return no_more_events; // don't handle next event, just quit.
|
||||
res = no_more_events; // don't handle next event, just quit.
|
||||
return res;
|
||||
|
||||
case SDL_USEREVENT:
|
||||
switch( ev.user.code )
|
||||
|
@ -1461,7 +1522,8 @@ sysEvent_t Sys_GetEvent()
|
|||
}
|
||||
}
|
||||
|
||||
return no_more_events;
|
||||
res = no_more_events;
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -101,11 +101,11 @@ enum sysEventType_t
|
|||
{
|
||||
SE_NONE, // evTime is still valid
|
||||
SE_KEY, // evValue is a key code, evValue2 is the down flag
|
||||
SE_CHAR, // evValue is an ascii char FIXME: not really ascii, supports umlauts...
|
||||
SE_MOUSE, // evValue and evValue2 are reletive signed x / y moves
|
||||
SE_CHAR, // evValue is an Unicode UTF-32 char (or non-surrogate UTF-16)
|
||||
SE_MOUSE, // evValue and evValue2 are relative signed x / y moves
|
||||
SE_MOUSE_ABSOLUTE, // evValue and evValue2 are absolute coordinates in the window's client area.
|
||||
SE_MOUSE_LEAVE, // evValue and evValue2 are meaninless, this indicates the mouse has left the client area.
|
||||
SE_JOYSTICK, // 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
|
||||
};
|
||||
|
||||
|
@ -119,6 +119,16 @@ enum sys_mEvents
|
|||
M_ACTION6,
|
||||
M_ACTION7,
|
||||
M_ACTION8,
|
||||
// DG: support some more mouse buttons
|
||||
M_ACTION9,
|
||||
M_ACTION10,
|
||||
M_ACTION11,
|
||||
M_ACTION12,
|
||||
M_ACTION13,
|
||||
M_ACTION14,
|
||||
M_ACTION15,
|
||||
M_ACTION16,
|
||||
// DG end
|
||||
M_DELTAX,
|
||||
M_DELTAY,
|
||||
M_DELTAZ,
|
||||
|
@ -390,6 +400,17 @@ enum keyNum_t
|
|||
K_MOUSE7,
|
||||
K_MOUSE8,
|
||||
|
||||
// DG: add some more mouse buttons
|
||||
K_MOUSE9,
|
||||
K_MOUSE10,
|
||||
K_MOUSE11,
|
||||
K_MOUSE12,
|
||||
K_MOUSE13,
|
||||
K_MOUSE14,
|
||||
K_MOUSE15,
|
||||
K_MOUSE16,
|
||||
// DG end
|
||||
|
||||
K_MWHEELDOWN,
|
||||
K_MWHEELUP,
|
||||
|
||||
|
|
|
@ -338,6 +338,7 @@ LONG WINAPI MainWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
|
|||
key = K_NUMLOCK;
|
||||
}
|
||||
Sys_QueEvent( SE_KEY, key, true, 0, NULL, 0 );
|
||||
|
||||
break;
|
||||
|
||||
case WM_SYSKEYUP:
|
||||
|
@ -359,8 +360,20 @@ LONG WINAPI MainWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
|
|||
break;
|
||||
|
||||
case WM_CHAR:
|
||||
// DG: make sure it's an utf-16 non-surrogate character (and thus a valid utf-32 character as well)
|
||||
// TODO: will there ever be two messages with surrogate characters that should be combined?
|
||||
// (probably not, some people claim it's actually UCS-2, not UTF-16)
|
||||
if( wParam < 0xD800 || wParam > 0xDFFF )
|
||||
{
|
||||
Sys_QueEvent( SE_CHAR, wParam, 0, 0, NULL, 0 );
|
||||
}
|
||||
break;
|
||||
|
||||
// DG: support utf-32 input via WM_UNICHAR
|
||||
case WM_UNICHAR:
|
||||
Sys_QueEvent( SE_CHAR, wParam, 0, 0, NULL, 0 );
|
||||
break;
|
||||
// DG end
|
||||
|
||||
case WM_NCLBUTTONDOWN:
|
||||
// win32.movingWindow = true;
|
||||
|
|
Loading…
Reference in a new issue