1
0
forked from 0ad/0ad

remove key- and mouse-state-clear code (previously called after alt+tab out). wsdl now takes care of this: by maintaining its own key array+sending up events for all currently down keys; and by capturing the mouse on each click.

-- this fixes "cursor keys require ctrl" bug reported by jason
wdbg_sym: fix warning
wsdl: as above and also better SDL_ACTIVEEVENT handling
mmgr: 500µs -> 500s -> 500us :)

This was SVN commit r3065.
This commit is contained in:
janwas 2005-10-31 01:15:49 +00:00
parent be44dc842e
commit 2452e29f0d
10 changed files with 202 additions and 139 deletions

View File

@ -65,28 +65,12 @@ InReaction gui_handler(const SDL_Event* ev)
return g_GUI.HandleEvent(ev);
}
// This is called after tasking out to another application. It avoids
// havoc by resetting the state of all mouse buttons to
// "not currently pressed". Since a button that happened to be pressed
// before the task switch will most likely be released during that time, we
// have to do this to prevent phantom mouse events when returing to our app.
void CGUI::ClearMouseState()
{
// reset all bits to "button is not currently pressed".
m_MouseButtons = 0;
}
InReaction CGUI::HandleEvent(const SDL_Event* ev)
{
InReaction ret = IN_PASS;
if (ev->type == SDL_ACTIVEEVENT)
{
if(ev->active.gain == 0)
g_GUI.ClearMouseState();
}
else if (ev->type == SDL_GUIHOTKEYPRESS)
if (ev->type == SDL_GUIHOTKEYPRESS)
{
const CStr& objectName = *(CStr*) ev->user.data1;
IGUIObject* object = FindObjectByName(objectName);

View File

@ -251,8 +251,6 @@ public:
private:
void ClearMouseState();
/**
* Updates the object pointers, needs to be called each
* time an object has been added or removed.

View File

@ -134,7 +134,7 @@ const uint MMGR_TRACE = 0x008;
// use debug information to resolve owner address to file/line/function.
// note: passing owner information to global operator delete via macro
// isn't reliable, so a stack backtrace (list of function addresses) is all
// we have there. this costs ~500s per unique call site on Windows.
// we have there. this costs ~500us per unique call site on Windows.
const uint MMGR_RESOLVE_OWNER = 0x010;
// force each log line to be written directly to disk. slow!

View File

@ -424,8 +424,6 @@ static int walk_stack(StackFrameCallback cb, void* user_arg = 0, uint skip = 0,
sf.AddrStack.Offset = pcontext->SP_;
sf.AddrStack.Mode = AddrModeFlat;
const HANDLE hThread = GetCurrentThread();
// for each stack frame found:
int ret = WDBG_NO_STACK_FRAMES_FOUND;
for(;;)
@ -451,6 +449,7 @@ static int walk_stack(StackFrameCallback cb, void* user_arg = 0, uint skip = 0,
// note: unfortunately StackWalk64 doesn't always SetLastError,
// so we have to reset it and check for 0. *sigh*
SetLastError(0);
const HANDLE hThread = GetCurrentThread();
BOOL ok = StackWalk64(machine, hProcess, hThread, &sf, (PVOID)pcontext,
0, SymFunctionTableAccess64, SymGetModuleBase64, 0);
if(ok)

View File

@ -69,24 +69,22 @@ WIN_REGISTER_FUNC(wsdl_shutdown);
#pragma data_seg()
static bool app_active;
// window is active and visible.
// used to send SDL_ACTIVEEVENT messages and in the msgproc.
// note: responsibility for yielding lies with SDL apps -
// they control the main loop.
// SDL_APP* bitflags indicating whether we are active.
// note: responsibility for yielding lies with SDL apps -
// they control the main loop.
static uint app_state;
// in fullscreen mode, i.e. not windowed.
// video mode will be restored when app is deactivated.
static bool fullscreen;
// in fullscreen mode, i.e. not windowed.
// video mode must be restored when app is deactivated.
// the app is shutting down.
// if set, ignore further Windows messages for clean shutdown.
static bool is_shutdown;
// the app is shutting down.
// if set, ignore further Windows messages for clean shutdown.
// app instance.
// returned by GetModuleHandle and used in kbd hook and window creation.
static HINSTANCE hInst = 0;
// app instance.
// returned by GetModuleHandle and used in kbd hook and window creation.
HWND hWnd = (HWND)INVALID_HANDLE_VALUE;
@ -101,6 +99,62 @@ static int depth_bits = 24; // depth buffer size; set via SDL_GL_SetAttribute
static u16 mouse_x, mouse_y;
Uint8 SDL_GetAppState()
{
return app_state;
}
//----------------------------------------------------------------------------
typedef std::queue<SDL_Event> Queue;
static Queue queue;
static void queue_event(const SDL_Event& ev)
{
queue.push(ev);
}
static bool dequeue_event(SDL_Event* ev)
{
if(queue.empty())
return false;
*ev = queue.front();
queue.pop();
return true;
}
static inline void queue_active_event(uint gain, uint changed_app_state)
{
// SDL says this event is not generated when the window is created,
// but skipping the first event may confuse things.
SDL_Event ev;
ev.type = SDL_ACTIVEEVENT;
ev.active.state = (u8)changed_app_state;
ev.active.gain = (u8)gain;
queue_event(ev);
}
static void queue_quit_event()
{
SDL_Event ev;
ev.type = SDL_QUIT;
queue_event(ev);
}
static void queue_button_event(uint button, uint state, uint x, uint y)
{
SDL_Event ev;
ev.type = (state == SDL_PRESSED)? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP;
ev.button.button = (u8)button;
ev.button.state = (u8)state;
ev.button.x = x;
ev.button.y = y;
queue_event(ev);
}
//----------------------------------------------------------------------------
// gamma
//----------------------------------------------------------------------------
@ -178,6 +232,8 @@ int SDL_SetGamma(float r, float g, float b)
//----------------------------------------------------------------------------
static bool keys[SDLK_LAST];
static void init_vkmap(SDLKey (&VK_keymap)[256])
{
int i;
@ -273,55 +329,18 @@ inline SDLKey vkmap(int vk)
}
//----------------------------------------------------------------------------
typedef std::queue<SDL_Event> Queue;
static Queue queue;
static void queue_event(const SDL_Event& ev)
static void reset_all_keys()
{
queue.push(ev);
}
SDL_Event spoofed_up_event;
spoofed_up_event.type = SDL_KEYUP;
spoofed_up_event.key.keysym.unicode = 0;
static bool dequeue_event(SDL_Event* ev)
{
if(queue.empty())
return false;
*ev = queue.front();
queue.pop();
return true;
}
static inline void queue_active_event()
{
// SDL says this event is not generated when the window is created;
// therefore, skip the first time.
ONCE(return);
SDL_Event ev;
ev.type = SDL_ACTIVEEVENT;
ev.active.state = SDL_APPACTIVE;
ev.active.gain = (u8)app_active;
queue_event(ev);
}
static void queue_quit_event()
{
SDL_Event ev;
ev.type = SDL_QUIT;
queue_event(ev);
}
static void queue_button_event(uint button, uint state, LPARAM lParam)
{
SDL_Event ev;
ev.type = (state == SDL_PRESSED)? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP;
ev.button.button = (u8)button;
ev.button.state = (u8)state;
ev.button.x = LOWORD(lParam);
ev.button.y = HIWORD(lParam);
queue_event(ev);
for(int i = 0; i < ARRAY_SIZE(keys); i++)
if(keys[i])
{
spoofed_up_event.key.keysym.sym = (SDLKey)i;
queue_event(spoofed_up_event);
}
}
@ -339,7 +358,9 @@ static LRESULT CALLBACK wndproc(HWND hWnd, uint uMsg, WPARAM wParam, LPARAM lPar
return 0;
case WM_ERASEBKGND:
return 0;
// this indicates we allegedly erased the background;
// PAINTSTRUCT.fErase is then FALSE.
return 1;
// prevent selecting menu in fullscreen mode
case WM_NCHITTEST:
@ -348,28 +369,54 @@ static LRESULT CALLBACK wndproc(HWND hWnd, uint uMsg, WPARAM wParam, LPARAM lPar
break;
case WM_ACTIVATE:
app_active = LOWORD(wParam) != 0;
gamma_swap(app_active? GAMMA_LATCH_NEW_RAMP : GAMMA_RESTORE_ORIGINAL);
if(fullscreen)
{
// (re)activating
if(app_active)
const uint wa_type = LOWORD(wParam);
const bool is_minimized = (HIWORD(wParam) != 0);
uint changed_app_state;
uint gain;
if(wa_type != WA_INACTIVE && !is_minimized)
{
gain = 1;
changed_app_state = SDL_APPINPUTFOCUS|SDL_APPACTIVE;
app_state |= changed_app_state;
}
// deactivated (Alt+Tab out) or minimized
else
{
gain = 0;
changed_app_state = SDL_APPINPUTFOCUS;
if(is_minimized)
changed_app_state |= SDL_APPACTIVE;
app_state &= ~changed_app_state;
}
if(gain)
{
gamma_swap(GAMMA_LATCH_NEW_RAMP);
if(fullscreen)
{
ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
ShowWindow(hWnd, SW_RESTORE);
ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
}
// deactivating
else
}
else
{
reset_all_keys();
gamma_swap(GAMMA_RESTORE_ORIGINAL);
if(fullscreen)
{
ChangeDisplaySettings(0, 0);
ShowWindow(hWnd, SW_MINIMIZE);
}
}
queue_active_event();
queue_active_event(gain, changed_app_state);
// let DefWindowProc run (gives us keyboard focus if
// we're being reactivated)
break;
}
case WM_DESTROY:
queue_quit_event();
@ -400,42 +447,99 @@ static LRESULT CALLBACK wndproc(HWND hWnd, uint uMsg, WPARAM wParam, LPARAM lPar
// TODO Modifier statekeeping
{
uint sdlk = vkmap((int)wParam);
if(sdlk != SDLK_UNKNOWN)
keys[sdlk] = false;
SDL_Event ev;
ev.type = SDL_KEYUP;
ev.key.keysym.sym = vkmap((int)wParam);
ev.key.keysym.sym = (SDLKey)sdlk;
ev.key.keysym.unicode = 0;
queue_event(ev);
}
return 1;
case WM_SYSKEYDOWN:
case WM_KEYDOWN:
{
uint sdlk = vkmap((int)wParam);
if(sdlk != SDLK_UNKNOWN)
keys[sdlk] = true;
break;
}
case WM_MOUSEWHEEL:
{
short delta = (short)HIWORD(wParam);
uint button = (delta < 0)? SDL_BUTTON_WHEELDOWN : SDL_BUTTON_WHEELUP;
uint x = LOWORD(lParam);
uint y = HIWORD(lParam);
// SDL says this sends a down message followed by up.
queue_button_event(button, SDL_PRESSED, lParam);
queue_button_event(button, SDL_RELEASED, lParam);
queue_button_event(button, SDL_PRESSED , x, y);
queue_button_event(button, SDL_RELEASED, x, y);
}
break;
case WM_LBUTTONDOWN:
queue_button_event(SDL_BUTTON_LEFT, SDL_PRESSED, lParam);
break;
case WM_LBUTTONUP:
queue_button_event(SDL_BUTTON_LEFT, SDL_RELEASED, lParam);
break;
case WM_RBUTTONDOWN:
queue_button_event(SDL_BUTTON_RIGHT, SDL_PRESSED, lParam);
break;
case WM_RBUTTONUP:
queue_button_event(SDL_BUTTON_RIGHT, SDL_RELEASED, lParam);
break;
case WM_MBUTTONDOWN:
queue_button_event(SDL_BUTTON_MIDDLE, SDL_PRESSED, lParam);
break;
case WM_MBUTTONUP:
queue_button_event(SDL_BUTTON_MIDDLE, SDL_RELEASED, lParam);
{
uint button;
uint state;
switch(uMsg)
{
case WM_LBUTTONDOWN:
button = SDL_BUTTON_LEFT;
state = SDL_PRESSED;
break;
case WM_LBUTTONUP:
button = SDL_BUTTON_LEFT;
state = SDL_RELEASED;
break;
case WM_RBUTTONDOWN:
button = SDL_BUTTON_RIGHT;
state = SDL_PRESSED;
break;
case WM_RBUTTONUP:
button = SDL_BUTTON_RIGHT;
state = SDL_RELEASED;
break;
case WM_MBUTTONDOWN:
button = SDL_BUTTON_MIDDLE;
state = SDL_PRESSED;
break;
case WM_MBUTTONUP:
button = SDL_BUTTON_MIDDLE;
state = SDL_RELEASED;
default:
UNREACHABLE;
}
// mouse capture
static int outstanding_press_events;
if(state == SDL_PRESSED)
{
// grab mouse to ensure we get up events
if(++outstanding_press_events > 0)
SetCapture(hWnd);
}
else
// release after all up events received
if(--outstanding_press_events <= 0)
{
ReleaseCapture();
outstanding_press_events = 0;
}
uint x = LOWORD(lParam);
uint y = HIWORD(lParam);
queue_button_event(button, state, x, y);
break;
}
default:
// can't call DefWindowProc here: some messages
@ -604,10 +708,10 @@ static LRESULT CALLBACK keyboard_ll_hook(int nCode, WPARAM wParam, LPARAM lParam
{
// disabled - we want the normal Windows printscreen handling to
// remain so as not to confuse artists.
/*
/*
// check whether PrintScreen should be taking screenshots -- if
// not, allow the standard Windows clipboard to work
if(app_active)
if(app_state & SDL_APPINPUTFOCUS)
{
// send to wndproc
UINT msg = (UINT)wParam;

View File

@ -46,6 +46,7 @@ extern int SDL_Init(Uint32 flags);
extern void SDL_Quit(void);
extern Uint8 SDL_GetAppState();
typedef enum
{

View File

@ -129,6 +129,8 @@ static void Frame()
MICROLOG(L"Frame");
oglCheck();
const uint app_state = SDL_GetAppState();
PROFILE_START( "update music" );
music_player.update();
PROFILE_END( "update music" );
@ -213,7 +215,6 @@ static void Frame()
if(snd_update(0, 0, 0) < 0)
debug_printf("snd_update (pos=0 version) failed\n");
}
PROFILE_END( "game logic" );
PROFILE_START( "update console" );
@ -223,7 +224,8 @@ static void Frame()
PROFILE_START( "render" );
oglCheck();
if(g_active)
if(app_state & SDL_APPACTIVE)
{
MICROLOG(L"render");
Render();
@ -235,7 +237,7 @@ static void Frame()
// inactive; relinquish CPU for a little while
// don't use SDL_WaitEvent: don't want the main loop to freeze until app focus is restored
else
SDL_Delay(10);
SDL_Delay(5);
oglCheck();
PROFILE_END( "render" );

View File

@ -21,7 +21,6 @@ extern CStr g_RenderPath;
extern int g_xres, g_yres;
extern int g_bpp;
extern int g_freq;
extern bool g_active;
extern bool g_Quickstart;
extern CStr g_AutostartMap;

View File

@ -22,19 +22,8 @@ InReaction GlobalsInputHandler(const SDL_Event* ev)
switch(ev->type)
{
case SDL_ACTIVEEVENT:
g_active = (ev->active.gain != 0);
// tasked out
if(ev->active.gain == 0)
{
// reset all key/button state, so that we don't get any
// phantom events when returning to our app.
// see CGUI::ClearMouseState.
for(uint i = 0; i < ARRAY_SIZE(g_mouse_buttons); i++)
g_mouse_buttons[i] = 0;
for(uint i = 0; i < ARRAY_SIZE(g_keys); i++)
g_keys[i] = 0;
}
if(ev->active.state & SDL_APPACTIVE)
g_active = (ev->active.gain != 0);
return IN_PASS;
case SDL_MOUSEMOTION:

View File

@ -323,19 +323,6 @@ InReaction hotkeyInputHandler( const SDL_Event* ev )
switch( ev->type )
{
case SDL_ACTIVEEVENT:
// tasked out
if(ev->active.gain == 0)
{
// reset all key/button state, so that we don't get any
// phantom events when returning to our app.
// see CGUI::ClearMouseState.
for(uint i = 0; i < ARRAY_SIZE(hotkeys); i++)
hotkeys[i] = 0;
}
// don't continue with the code below (this wasn't an input event)
return IN_PASS;
case SDL_KEYDOWN:
case SDL_KEYUP:
keycode = (int)ev->key.keysym.sym;