match alerts cgame extension and s_autoMute for Windows

This commit is contained in:
myT 2017-11-07 06:17:28 +01:00
parent e26163aa79
commit fca556e2ad
12 changed files with 264 additions and 52 deletions

View file

@ -1,6 +1,17 @@
DD Mmm 17 - 1.49
add: s_autoMute selects when the audio output should be disabled
s_autoMute 0 = never mute
s_autoMute 1 (default) = mute when the window doesn't have input focus
s_autoMute 2 = mute when the window is minimized
add: cl_matchAlerts (bitmask, default: 7) lets you know when a match is starting
1 - when unfocused (otherwise only when minimized)
2 - flash the task bar (Windows only)
4 - beep once (Windows only)
8 - unmute (temporarily overrides s_autoMute)
add: new commands to take screenshots with the console hidden
screenshotnc for TARGA (.tga) images
screenshotncJPEG for JPEG (.jpg) images
@ -156,11 +167,6 @@ chg: the client requires SDL 2 - the following things are handled by it:
add: m_relative <0|1> (default: 1) enables SDL's relative mouse mode
you might want to set it to 0 if you have a messed up input driver
add: s_autoMute selects when the audio output should be disabled
s_autoMute 0 = never mute
s_autoMute 1 (default) = mute when the window doesn't have input focus
s_autoMute 2 = mute when the window is minimized
add: minimize command to minimize the client's window
add: automatic dedicated server process restarts for crashes and timed reboots (sv_minRebootDelayMins)

View file

@ -307,6 +307,7 @@ static qbool CL_CG_GetValue( char* value, int valueSize, const char* key )
{ "trap_Cvar_SetRange", CG_EXT_CVAR_SETRANGE },
{ "trap_Cvar_SetHelp", CG_EXT_CVAR_SETHELP },
{ "trap_Cmd_SetHelp", CG_EXT_CMD_SETHELP },
{ "trap_MatchAlertEvent", CG_EXT_MATCHALERTEVENT },
// commands
{ "screenshotnc", 1 },
{ "screenshotncJPEG", 1 }
@ -610,6 +611,10 @@ static intptr_t CL_CgameSystemCalls( intptr_t *args )
Cmd_SetHelp( VMA(1), VMA(2) );
return 0;
case CG_EXT_MATCHALERTEVENT:
Sys_MatchAlert( (sysMatchAlertEvent_t)args[1] );
return 0;
default:
Com_Error( ERR_DROP, "Bad cgame system trap: %i", args[0] );
}

View file

@ -45,6 +45,8 @@ cvar_t *cl_aviMotionJpeg;
cvar_t *cl_allowDownload;
cvar_t *cl_inGameVideo;
cvar_t *cl_matchAlerts;
clientActive_t cl;
clientConnection_t clc;
clientStatic_t cls;
@ -2013,7 +2015,8 @@ static const cvarTableItem_t cl_cvars[] =
{ NULL, "name", "UnnamedPlayer", CVAR_USERINFO | CVAR_ARCHIVE, CVART_STRING, NULL, NULL, "your name" },
{ NULL, "rate", "25000", CVAR_USERINFO | CVAR_ARCHIVE, CVART_INTEGER, "4000", "99999", "network transfer rate" },
{ NULL, "snaps", "30", CVAR_USERINFO | CVAR_ARCHIVE, CVART_INTEGER }, // documented by the mod
{ NULL, "password", "", CVAR_USERINFO, CVART_STRING, NULL, NULL, "used by /connect" }
{ NULL, "password", "", CVAR_USERINFO, CVART_STRING, NULL, NULL, "used by /connect" },
{ &cl_matchAlerts, "cl_matchAlerts", "7", CVAR_ARCHIVE, CVART_BITMASK, "0", XSTRING(MAF_MAX), help_cl_matchAlerts }
};

View file

@ -312,6 +312,21 @@ extern refexport_t re; // interface to refresh .dll
//
// cvars
//
// match alert flags (cl_matchAlerts)
#define MAF_UNFOCUSED 1 // enable even when the window is visible but unfocused (otherwise only when minimized)
#define MAF_FLASH 2 // Windows: flash the task bar until unminimized / focused
#define MAF_BEEP 4 // Windows: play a message box beep sound once
#define MAF_UNMUTE 8 // unmute the audio
#define MAF_MAX 15 // max. bit mask value
// auto-mute modes (s_autoMute)
typedef enum {
AMM_NEVER,
AMM_UNFOCUSED,
AMM_MINIMIZED
} autoMuteMode_t;
extern cvar_t *cl_debugMove;
extern cvar_t *cl_timegraph;
extern cvar_t *cl_maxpackets;
@ -328,6 +343,10 @@ extern cvar_t *cl_aviMotionJpeg;
extern cvar_t *cl_allowDownload; // 0=off, 1=CNQ3, -1=id
extern cvar_t *cl_inGameVideo;
extern cvar_t *cl_matchAlerts; // bit mask, see the MAF_* constants
extern cvar_t *s_autoMute;
//=================================================
@ -494,3 +513,13 @@ qbool CL_MapDownload_Active();
void CL_MapDownload_Cancel();
void CL_MapDownload_DrawConsole( float cw, float ch );
void CL_MapDownload_CrashCleanUp();
//
// OS-specific
//
typedef enum {
SMAE_MATCH_START,
SMAE_MATCH_END
} sysMatchAlertEvent_t;
void Sys_MatchAlert( sysMatchAlertEvent_t event );

View file

@ -51,3 +51,16 @@ help_bind_extra
#define help_unbind \
"unbinds a key\n" \
help_bind_extra
#define help_cl_matchAlerts \
"lets you know when a match is starting\n" \
" 1 = when unfocused (otherwise only when minimized)\n" \
" 2 = flash the task bar (Windows only)\n" \
" 4 = beep once (Windows only)\n" \
" 8 = unmute"
#define help_s_autoMute \
"selects when the audio output should be disabled\n" \
" 0 = never\n" \
" 1 = window is not focused\n" \
" 2 = window is minimized"

View file

@ -22,6 +22,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "client.h"
#include "client_help.h"
#include "snd_codec.h"
#include "snd_local.h"
#include "snd_public.h"
@ -29,6 +30,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
cvar_t *s_volume;
cvar_t *s_musicVolume;
cvar_t *s_initsound;
cvar_t *s_autoMute;
static soundInterface_t si;
@ -235,7 +237,8 @@ static const cvarTableItem_t cl_cvars[] =
{
{ &s_volume, "s_volume", "0.8", CVAR_ARCHIVE, CVART_FLOAT, "0", "1", "global sound volume" },
{ &s_musicVolume, "s_musicvolume", "0", CVAR_ARCHIVE, CVART_FLOAT, "0", "16", "music volume" },
{ &s_initsound, "s_initsound", "1", 0, CVART_BOOL, NULL, NULL, "enables the audio system" }
{ &s_initsound, "s_initsound", "1", 0, CVART_BOOL, NULL, NULL, "enables the audio system" },
{ &s_autoMute, "s_autoMute", "1", CVAR_ARCHIVE, CVART_INTEGER, "0", "2", help_s_autoMute }
};

View file

@ -10,12 +10,12 @@ static qbool sdl_inputActive = qfalse;
static cvar_t* in_noGrab;
static cvar_t* m_relative;
static cvar_t* s_autoMute;
static qbool sdl_forceUnmute = qfalse; // overrides s_autoMute
static const cvarTableItem_t in_cvars[] = {
{ &in_noGrab, "in_noGrab", "0", 0, CVART_BOOL, NULL, NULL, "disables input grabbing" },
{ &m_relative, "m_relative", "1", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, "enables SDL's relative mouse mode" },
{ &s_autoMute, "s_autoMute", "1", CVAR_ARCHIVE, CVART_INTEGER, "0", "2", "0=never, 1=when unfocused, 2=when minimized" }
{ &m_relative, "m_relative", "1", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, "enables SDL's relative mouse mode" }
};
static void Minimize_f();
@ -263,6 +263,7 @@ static void sdl_Window( const SDL_WindowEvent* event )
//SDL_WINDOWEVENT_FOCUS_GAINED // kb focus gained
//SDL_WINDOWEVENT_FOCUS_LOST // kb focus lost
//SDL_WINDOWEVENT_CLOSE
//SDL_WINDOWEVENT_MOVED
switch (event->event) {
case SDL_WINDOWEVENT_MAXIMIZED:
@ -278,6 +279,20 @@ static void sdl_Window( const SDL_WindowEvent* event )
default:
break;
}
switch (event->event) {
case SDL_WINDOWEVENT_SHOWN:
case SDL_WINDOWEVENT_MAXIMIZED:
case SDL_WINDOWEVENT_RESTORED:
case SDL_WINDOWEVENT_FOCUS_GAINED:
// these mean the user reacted to the alert and
// it can now be stopped
sdl_forceUnmute = qfalse;
break;
default:
break;
}
}
@ -385,6 +400,26 @@ static qbool sdl_IsInputActive()
}
static void S_Frame()
{
if (sdl_forceUnmute) {
sdl_MuteAudio(qfalse);
return;
}
qbool mute = qfalse;
if (s_autoMute->integer == AMM_UNFOCUSED) {
const qbool hasFocus = (SDL_GetWindowFlags(glimp.window) & SDL_WINDOW_INPUT_FOCUS) != 0;
mute = !hasFocus;
} else if (s_autoMute->integer == AMM_MINIMIZED) {
const Uint32 hidingFlags = SDL_WINDOW_HIDDEN | SDL_WINDOW_MINIMIZED;
const qbool hidden = (SDL_GetWindowFlags(glimp.window) & hidingFlags) != 0;
mute = hidden;
}
sdl_MuteAudio(mute);
}
void sdl_Frame()
{
sdl_inputActive = sdl_IsInputActive();
@ -395,16 +430,7 @@ void sdl_Frame()
SDL_ShowCursor(sdl_inputActive ? SDL_DISABLE : SDL_ENABLE);
// @NOTE: SDL_WarpMouseInWindow generates a motion event
if (s_autoMute->integer == 1) {
const qbool hasFocus = (SDL_GetWindowFlags(glimp.window) & SDL_WINDOW_INPUT_FOCUS) != 0;
sdl_MuteAudio(!hasFocus);
} else if (s_autoMute->integer == 2) {
const Uint32 hidingFlags = SDL_WINDOW_HIDDEN | SDL_WINDOW_MINIMIZED;
const qbool hidden = (SDL_GetWindowFlags(glimp.window) & hidingFlags) != 0;
sdl_MuteAudio(hidden);
} else {
sdl_MuteAudio(qfalse);
}
S_Frame();
}
@ -484,3 +510,34 @@ char* Sys_GetClipboardData()
return text;
}
void Lin_MatchStartAlert()
{
const int alerts = cl_matchAlerts->integer;
const qbool unmuteBit = (alerts & MAF_UNMUTE) != 0;
if (!unmuteBit)
return;
const qbool unfocusedBit = (alerts & MAF_UNFOCUSED) != 0;
const qbool hasFocus = (SDL_GetWindowFlags(glimp.window) & SDL_WINDOW_INPUT_FOCUS) != 0;
const Uint32 hidingFlags = SDL_WINDOW_HIDDEN | SDL_WINDOW_MINIMIZED;
const qbool hidden = (SDL_GetWindowFlags(glimp.window) & hidingFlags) != 0;
if (hidden || (unfocusedBit && !hasFocus))
sdl_forceUnmute = qtrue;
}
void Lin_MatchEndAlert()
{
sdl_forceUnmute = qfalse;
}
void Sys_MatchAlert( sysMatchAlertEvent_t event )
{
if (event == SMAE_MATCH_START)
Lin_MatchStartAlert();
else if (event == SMAE_MATCH_END)
Lin_MatchEndAlert();
}

View file

@ -177,16 +177,17 @@ typedef enum {
DO_NOT_WANT_CG_TESTPRINTFLOAT,
CG_ACOS,
// engine extensions
// the mod should _never_ use these symbols
CG_EXT_GETVALUE = 700,
CG_EXT_LOCATEINTEROPDATA,
// engine extensions
// the mod should _never_ use these symbols
CG_EXT_GETVALUE = 700,
CG_EXT_LOCATEINTEROPDATA,
CG_EXT_R_ADDREFENTITYTOSCENE2,
CG_EXT_R_FORCEFIXEDDLIGHTS,
CG_EXT_SETINPUTFORWARDING,
CG_EXT_CVAR_SETRANGE,
CG_EXT_CVAR_SETHELP,
CG_EXT_CMD_SETHELP
CG_EXT_CMD_SETHELP,
CG_EXT_MATCHALERTEVENT
} cgameImport_t;

View file

@ -46,8 +46,8 @@ void WIN_UnregisterHotKey();
void WIN_SetGameDisplaySettings();
void WIN_SetDesktopDisplaySettings();
// sound - called in reaction to WM_ACTIVATE
void WIN_S_WindowActivate();
// sound
void WIN_S_Mute( qbool mute );
LRESULT CALLBACK MainWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
@ -85,6 +85,8 @@ typedef struct {
UINT minimizeHotKeyMods;
qbool inputInitialized;
qbool forceUnmute; // overrides s_autoMute
} WinVars_t;
extern WinVars_t g_wv;

View file

@ -544,22 +544,113 @@ void Sys_Init()
}
///////////////////////////////////////////////////////////////
#ifndef DEDICATED
static void WIN_StartTaskBarFlashing()
{
FLASHWINFO info;
ZeroMemory( &info, sizeof( info ) );
info.cbSize = sizeof( info );
info.dwFlags = FLASHW_TRAY | FLASHW_TIMERNOFG;
info.dwTimeout = 0; // use the default value
info.hwnd = g_wv.hWnd;
info.uCount = 0; // it's continuous because of FLASHW_TIMERNOFG
FlashWindowEx( &info );
}
static void WIN_StopTaskBarFlashing()
{
FLASHWINFO info;
ZeroMemory( &info, sizeof( info ) );
info.cbSize = sizeof( info );
info.dwFlags = FLASHW_STOP;
info.hwnd = g_wv.hWnd;
FlashWindowEx( &info );
}
static void WIN_MatchStartAlert()
{
const int alerts = cl_matchAlerts->integer;
const qbool unfocusedBit = ( alerts & MAF_UNFOCUSED ) != 0;
const qbool minimized = !!IsIconic( g_wv.hWnd );
const qbool hasFocus = GetFocus() == g_wv.hWnd;
const qbool enable = minimized || ( unfocusedBit && !hasFocus );
if ( !enable )
return;
const qbool flashBit = ( alerts & MAF_FLASH ) != 0;
const qbool beepBit = ( alerts & MAF_BEEP ) != 0;
const qbool unmuteBit = ( alerts & MAF_UNMUTE ) != 0;
if ( flashBit )
WIN_StartTaskBarFlashing();
if ( beepBit )
MessageBeep( MB_OK );
if ( unmuteBit )
g_wv.forceUnmute = qtrue;
}
static void WIN_MatchEndAlert()
{
g_wv.forceUnmute = qfalse;
WIN_StopTaskBarFlashing();
}
void Sys_MatchAlert( sysMatchAlertEvent_t event )
{
if ( event == SMAE_MATCH_START )
WIN_MatchStartAlert();
else if ( event == SMAE_MATCH_END )
WIN_MatchEndAlert();
}
static void S_Frame()
{
if ( g_wv.forceUnmute ) {
WIN_S_Mute( qfalse );
return;
}
qbool mute = qfalse;
if ( s_autoMute->integer == AMM_UNFOCUSED ) {
const qbool hasFocus = GetFocus() == g_wv.hWnd;
mute = !hasFocus;
} else if ( s_autoMute->integer == AMM_MINIMIZED ) {
const qbool minimized = !!IsIconic( g_wv.hWnd );
mute = minimized;
}
WIN_S_Mute( mute );
}
#endif
///////////////////////////////////////////////////////////////
static BOOL CALLBACK WIN_MonitorEnumCallback( HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData )
{
if ( lprcMonitor )
{
if ( lprcMonitor ) {
g_wv.monitorRects[g_wv.monitorCount] = *lprcMonitor;
g_wv.hMonitors[g_wv.monitorCount] = hMonitor;
g_wv.monitorCount++;
}
if ( g_wv.monitorCount >= MAX_MONITOR_COUNT )
{
return FALSE;
}
return TRUE;
}
@ -571,10 +662,8 @@ static void WIN_InitMonitorList()
const POINT zero = { 0, 0 };
const HMONITOR hMonitor = MonitorFromPoint( zero, MONITOR_DEFAULTTOPRIMARY );
for ( int i = 0; i < g_wv.monitorCount; i++ )
{
if ( hMonitor == g_wv.hMonitors[i] )
{
for ( int i = 0; i < g_wv.monitorCount; i++ ) {
if ( hMonitor == g_wv.hMonitors[i] ) {
g_wv.primaryMonitor = i;
g_wv.monitor = i;
break;
@ -590,8 +679,7 @@ void WIN_UpdateMonitorIndexFromCvar()
const int monitor = Cvar_Get( "r_monitor", "0", CVAR_ARCHIVE | CVAR_LATCH )->integer;
Cvar_SetRange( "r_monitor", CVART_INTEGER, "0", va("%d", g_wv.monitorCount) );
Cvar_SetHelp( "r_monitor", "1-based monitor index, 0=primary" );
if ( monitor <= 0 || monitor > g_wv.monitorCount )
{
if ( monitor <= 0 || monitor > g_wv.monitorCount ) {
g_wv.monitor = g_wv.primaryMonitor;
return;
}
@ -603,10 +691,8 @@ void WIN_UpdateMonitorIndexFromCvar()
void WIN_UpdateMonitorIndexFromMainWindow()
{
const HMONITOR hMonitor = MonitorFromWindow( g_wv.hWnd, MONITOR_DEFAULTTONEAREST );
for ( int i = 0; i < g_wv.monitorCount; i++ )
{
if ( hMonitor == g_wv.hMonitors[i] )
{
for ( int i = 0; i < g_wv.monitorCount; i++ ) {
if ( hMonitor == g_wv.hMonitors[i] ) {
g_wv.monitor = i;
break;
}
@ -615,8 +701,7 @@ void WIN_UpdateMonitorIndexFromMainWindow()
// if r_monitor is 0 and we're already on the primary monitor,
// don't change the cvar to a non-zero number
if ( Cvar_VariableIntegerValue( "r_monitor" ) == 0 &&
g_wv.monitor == g_wv.primaryMonitor )
{
g_wv.monitor == g_wv.primaryMonitor ) {
return;
}
@ -679,6 +764,7 @@ int WINAPI WinMainImpl( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCm
#ifndef DEDICATED
// make sure mouse and joystick are only called once a frame
IN_Frame();
S_Frame();
#endif
// run the game

View file

@ -160,13 +160,13 @@ static qbool SNDDMA_InitDS()
dsbcaps.dwSize = sizeof(dsbcaps);
Com_DPrintf( "...creating secondary buffer: " );
dsbuf.dwFlags = DSBCAPS_LOCHARDWARE | DSBCAPS_GETCURRENTPOSITION2;
dsbuf.dwFlags = DSBCAPS_LOCHARDWARE | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLVOLUME;
if (DS_OK == pDS->CreateSoundBuffer( &dsbuf, &pDSBuf, NULL )) {
Com_Printf( "locked hardware. ok\n" );
}
else {
// Couldn't get hardware, fallback to software.
dsbuf.dwFlags = DSBCAPS_LOCSOFTWARE | DSBCAPS_GETCURRENTPOSITION2;
dsbuf.dwFlags = DSBCAPS_LOCSOFTWARE | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLVOLUME;
if (DS_OK != pDS->CreateSoundBuffer( &dsbuf, &pDSBuf, NULL )) {
Com_Printf( "failed\n" );
Sys_S_Shutdown();
@ -299,15 +299,21 @@ void Sys_S_Submit( void )
}
// Called in reaction to WM_ACTIVATE
void WIN_S_WindowActivate()
void WIN_S_Mute( qbool mute )
{
if ( !pDS ) {
if (!pDSBuf) {
return;
}
if ( DS_OK != pDS->SetCooperativeLevel( g_wv.hWnd, DSSCL_PRIORITY ) ) {
Com_Printf ("sound SetCooperativeLevel failed\n");
Sys_S_Shutdown();
static LONG lVolume = DSBVOLUME_MIN;
static qbool bWasMuted = qfalse;
if (mute && !bWasMuted) {
pDSBuf->GetVolume(&lVolume);
pDSBuf->SetVolume(DSBVOLUME_MIN);
bWasMuted = qtrue;
} else if (!mute && bWasMuted && lVolume != DSBVOLUME_MIN) {
pDSBuf->SetVolume(lVolume);
bWasMuted = qfalse;
}
}

View file

@ -269,7 +269,7 @@ LRESULT CALLBACK MainWndProc (
case WM_ACTIVATE:
WIN_AppActivate( (LOWORD(wParam) != WA_INACTIVE), !!(BOOL)HIWORD(wParam) );
WIN_S_WindowActivate();
WIN_S_Mute( !g_wv.activeApp );
break;
case WM_MOVE:
@ -361,6 +361,7 @@ LRESULT CALLBACK MainWndProc (
}
}
g_wv.activeApp = (qbool)!IsIconic( hWnd );
g_wv.forceUnmute = qfalse;
break;
case WM_KILLFOCUS: