mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-02 09:52:27 -04:00
track keypresses better on setfocus/killfocus
This commit is contained in:
parent
7049173fb3
commit
34796b00b9
@ -69,6 +69,7 @@ WinGraphicsWindow(GraphicsPipe *pipe, GraphicsStateGuardian *gsg) :
|
|||||||
_tracking_mouse_leaving = false;
|
_tracking_mouse_leaving = false;
|
||||||
_maximized = false;
|
_maximized = false;
|
||||||
memset(_keyboard_state, 0, sizeof(BYTE) * num_virtual_keys);
|
memset(_keyboard_state, 0, sizeof(BYTE) * num_virtual_keys);
|
||||||
|
_lost_keypresses = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -772,6 +773,9 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
|||||||
}
|
}
|
||||||
// fall through
|
// fall through
|
||||||
case WM_RBUTTONDOWN:
|
case WM_RBUTTONDOWN:
|
||||||
|
if (_lost_keypresses) {
|
||||||
|
resend_lost_keypresses();
|
||||||
|
}
|
||||||
if (button < 0) {
|
if (button < 0) {
|
||||||
button = 2;
|
button = 2;
|
||||||
}
|
}
|
||||||
@ -789,6 +793,9 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
|||||||
}
|
}
|
||||||
// fall through
|
// fall through
|
||||||
case WM_RBUTTONUP:
|
case WM_RBUTTONUP:
|
||||||
|
if (_lost_keypresses) {
|
||||||
|
resend_lost_keypresses();
|
||||||
|
}
|
||||||
if (button < 0) {
|
if (button < 0) {
|
||||||
button = 2;
|
button = 2;
|
||||||
}
|
}
|
||||||
@ -891,6 +898,13 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case WM_SYSKEYDOWN:
|
case WM_SYSKEYDOWN:
|
||||||
|
if (_lost_keypresses) {
|
||||||
|
resend_lost_keypresses();
|
||||||
|
}
|
||||||
|
if (windisplay_cat.is_debug()) {
|
||||||
|
windisplay_cat.debug()
|
||||||
|
<< "keydown: " << wparam << " (" << lookup_key(wparam) << ")\n";
|
||||||
|
}
|
||||||
{
|
{
|
||||||
// Alt and F10 are sent as WM_SYSKEYDOWN instead of WM_KEYDOWN
|
// Alt and F10 are sent as WM_SYSKEYDOWN instead of WM_KEYDOWN
|
||||||
// want to use defwindproc on Alt syskey so std windows cmd
|
// want to use defwindproc on Alt syskey so std windows cmd
|
||||||
@ -912,12 +926,23 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
|||||||
// if Alt is released (alone w/o other keys), defwindproc will
|
// if Alt is released (alone w/o other keys), defwindproc will
|
||||||
// send this command, which will 'activate' the title bar menu
|
// send this command, which will 'activate' the title bar menu
|
||||||
// (we have none) and give focus to it. we dont want this to
|
// (we have none) and give focus to it. we dont want this to
|
||||||
// happen, so kill this msg
|
// happen, so kill this msg.
|
||||||
|
|
||||||
|
// Note that the WM_SYSKEYUP message for Alt has already
|
||||||
|
// been sent (if it is going to be), so ignoring this
|
||||||
|
// special message does no harm.
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WM_KEYDOWN:
|
case WM_KEYDOWN:
|
||||||
|
if (_lost_keypresses) {
|
||||||
|
resend_lost_keypresses();
|
||||||
|
}
|
||||||
|
if (windisplay_cat.is_debug()) {
|
||||||
|
windisplay_cat.debug()
|
||||||
|
<< "keydown: " << wparam << " (" << lookup_key(wparam) << ")\n";
|
||||||
|
}
|
||||||
{
|
{
|
||||||
POINT point;
|
POINT point;
|
||||||
|
|
||||||
@ -954,72 +979,70 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
|||||||
|
|
||||||
case WM_SYSKEYUP:
|
case WM_SYSKEYUP:
|
||||||
case WM_KEYUP:
|
case WM_KEYUP:
|
||||||
|
if (_lost_keypresses) {
|
||||||
|
resend_lost_keypresses();
|
||||||
|
}
|
||||||
|
if (windisplay_cat.is_debug()) {
|
||||||
|
windisplay_cat.debug()
|
||||||
|
<< "keyup: " << wparam << " (" << lookup_key(wparam) << ")\n";
|
||||||
|
}
|
||||||
handle_keyrelease(lookup_key(wparam));
|
handle_keyrelease(lookup_key(wparam));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WM_KILLFOCUS:
|
case WM_KILLFOCUS:
|
||||||
|
if (windisplay_cat.is_debug()) {
|
||||||
|
windisplay_cat.debug()
|
||||||
|
<< "killfocus\n";
|
||||||
|
}
|
||||||
|
if (_lost_keypresses) {
|
||||||
|
resend_lost_keypresses();
|
||||||
|
}
|
||||||
|
|
||||||
// Record the current state of the keyboard when the focus is
|
// Record the current state of the keyboard when the focus is
|
||||||
// lost, so we can check it for changes when we regain focus.
|
// lost, so we can check it for changes when we regain focus.
|
||||||
GetKeyboardState(_keyboard_state);
|
GetKeyboardState(_keyboard_state);
|
||||||
break;
|
if (windisplay_cat.is_debug()) {
|
||||||
|
// Report the set of keys that are held down at the time of
|
||||||
case WM_SETFOCUS:
|
// the killfocus event.
|
||||||
{
|
|
||||||
// When we lose focus, the app may miss key-up events for keys
|
|
||||||
// that were formerly held down (and vice-versa). Therefore,
|
|
||||||
// when focus is regained, compare the state of the keyboard to
|
|
||||||
// the last known state (stored above, when focus was lost) to
|
|
||||||
// regenerate the lost keyboard events.
|
|
||||||
|
|
||||||
if (GetForegroundWindow() != _hWnd) {
|
|
||||||
// Sometimes, particularly on window create, it appears we get
|
|
||||||
// a WM_SETFOCUS event even though the window hasn't really
|
|
||||||
// received focus yet. That's bad and confuses the
|
|
||||||
// GetKeyboardState logic, below. The above check filters out
|
|
||||||
// this case (while testing GetFocus() instead of
|
|
||||||
// GetForegroundWindow() doesn't).
|
|
||||||
windisplay_cat.info()
|
|
||||||
<< "Ignoring non-foreground WM_SETFOCUS\n";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
BYTE new_keyboard_state[num_virtual_keys];
|
|
||||||
GetKeyboardState(new_keyboard_state);
|
|
||||||
for (int i = 0; i < num_virtual_keys; i++) {
|
for (int i = 0; i < num_virtual_keys; i++) {
|
||||||
// Filter out these particular three. We don't want to test
|
|
||||||
// these, because these are virtual duplicates for
|
|
||||||
// VK_LSHIFT/VK_RSHIFT, etc.; and the left/right equivalent is
|
|
||||||
// also in the table. If we respect both VK_LSHIFT as well as
|
|
||||||
// VK_SHIFT, we'll generate two keyboard messages when
|
|
||||||
// VK_LSHIFT changes state.
|
|
||||||
if (i != VK_SHIFT && i != VK_CONTROL && i != VK_MENU) {
|
if (i != VK_SHIFT && i != VK_CONTROL && i != VK_MENU) {
|
||||||
if (((new_keyboard_state[i] ^ _keyboard_state[i]) & 0x80) != 0) {
|
if ((_keyboard_state[i] & 0x80) != 0) {
|
||||||
// This key has changed state.
|
windisplay_cat.debug()
|
||||||
if ((new_keyboard_state[i] & 0x80) != 0) {
|
<< "on killfocus, key is down: " << i << " (" << lookup_key(i) << ")\n";
|
||||||
// The key is now held down.
|
|
||||||
if (windisplay_cat.is_debug()) {
|
|
||||||
windisplay_cat.debug()
|
|
||||||
<< "key is down: " << lookup_key(i) << "\n";
|
|
||||||
}
|
|
||||||
handle_keyresume(lookup_key(i));
|
|
||||||
} else {
|
|
||||||
// The key is now released.
|
|
||||||
if (windisplay_cat.is_debug()) {
|
|
||||||
windisplay_cat.debug()
|
|
||||||
<< "key is up: " << lookup_key(i) << "\n";
|
|
||||||
}
|
|
||||||
handle_keyrelease(lookup_key(i));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Save the new keyboard state, just for good measure. This
|
|
||||||
// really shouldn't be necessary, but it protects against
|
// Now set the flag indicating that some keypresses from now
|
||||||
// inadvertently getting WM_SETFOCUS twice in a row, for
|
// on may be lost.
|
||||||
// instance.
|
_lost_keypresses = true;
|
||||||
memcpy(_keyboard_state, new_keyboard_state,
|
break;
|
||||||
sizeof(BYTE) * num_virtual_keys);
|
|
||||||
|
case WM_SETFOCUS:
|
||||||
|
// You would think that this would be a good time to call
|
||||||
|
// resend_lost_keypresses(), but it turns out that we get
|
||||||
|
// WM_SETFOCUS slightly before Windows starts resending key
|
||||||
|
// up/down events to us.
|
||||||
|
|
||||||
|
// In particular, if the user restored focus using alt-tab,
|
||||||
|
// then at this point the keyboard state will indicate that
|
||||||
|
// both the alt and tab keys are held down. However, there is
|
||||||
|
// a small window of opportunity for the user to release these
|
||||||
|
// keys before Windows starts telling us about keyup events.
|
||||||
|
// Thus, if we record the fact that alt and tab are being held
|
||||||
|
// down now, we may miss the keyup events for them, and they
|
||||||
|
// can get "stuck" down.
|
||||||
|
|
||||||
|
// So we have to defer calling resend_lost_keypresses() until
|
||||||
|
// we know Windows is ready to send us key up/down events. I
|
||||||
|
// don't know when we can guarantee that, except when we
|
||||||
|
// actually do start to receive key up/down events, so that
|
||||||
|
// call is made there.
|
||||||
|
|
||||||
|
if (windisplay_cat.is_debug()) {
|
||||||
|
windisplay_cat.debug()
|
||||||
|
<< "setfocus\n";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1027,6 +1050,7 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
|||||||
return DefWindowProc(hwnd, msg, wparam, lparam);
|
return DefWindowProc(hwnd, msg, wparam, lparam);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: WinGraphicsWindow::static_window_proc
|
// Function: WinGraphicsWindow::static_window_proc
|
||||||
// Access: Private, Static
|
// Access: Private, Static
|
||||||
@ -1075,6 +1099,68 @@ process_1_event() {
|
|||||||
DispatchMessage(&msg);
|
DispatchMessage(&msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: WinGraphicsWindow::resend_lost_keypresses
|
||||||
|
// Access: Private, Static
|
||||||
|
// Description: Called when the keyboard focus has been restored to
|
||||||
|
// the window after it has been lost for a time, this
|
||||||
|
// rechecks the keyboard state and generates key up/down
|
||||||
|
// messages for keys that have changed state in the
|
||||||
|
// meantime.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void WinGraphicsWindow::
|
||||||
|
resend_lost_keypresses() {
|
||||||
|
nassertv(_lost_keypresses);
|
||||||
|
if (windisplay_cat.is_debug()) {
|
||||||
|
windisplay_cat.debug()
|
||||||
|
<< "resending lost keypresses\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
BYTE new_keyboard_state[num_virtual_keys];
|
||||||
|
GetKeyboardState(new_keyboard_state);
|
||||||
|
|
||||||
|
for (int i = 0; i < num_virtual_keys; i++) {
|
||||||
|
// Filter out these particular three. We don't want to test
|
||||||
|
// these, because these are virtual duplicates for
|
||||||
|
// VK_LSHIFT/VK_RSHIFT, etc.; and the left/right equivalent is
|
||||||
|
// also in the table. If we respect both VK_LSHIFT as well as
|
||||||
|
// VK_SHIFT, we'll generate two keyboard messages when
|
||||||
|
// VK_LSHIFT changes state.
|
||||||
|
if (i != VK_SHIFT && i != VK_CONTROL && i != VK_MENU) {
|
||||||
|
if (((new_keyboard_state[i] ^ _keyboard_state[i]) & 0x80) != 0) {
|
||||||
|
// This key has changed state.
|
||||||
|
if ((new_keyboard_state[i] & 0x80) != 0) {
|
||||||
|
// The key is now held down.
|
||||||
|
if (windisplay_cat.is_debug()) {
|
||||||
|
windisplay_cat.debug()
|
||||||
|
<< "key has gone down: " << i << " (" << lookup_key(i) << ")\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_keyresume(lookup_key(i));
|
||||||
|
} else {
|
||||||
|
// The key is now released.
|
||||||
|
if (windisplay_cat.is_debug()) {
|
||||||
|
windisplay_cat.debug()
|
||||||
|
<< "key has gone up: " << i << " (" << lookup_key(i) << ")\n";
|
||||||
|
}
|
||||||
|
handle_keyrelease(lookup_key(i));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// This key is in the same state.
|
||||||
|
if (windisplay_cat.is_debug()) {
|
||||||
|
if ((new_keyboard_state[i] & 0x80) != 0) {
|
||||||
|
windisplay_cat.debug()
|
||||||
|
<< "key is still down: " << i << " (" << lookup_key(i) << ")\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keypresses are no longer lost.
|
||||||
|
_lost_keypresses = false;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: WinGraphicsWindow::update_cursor_window
|
// Function: WinGraphicsWindow::update_cursor_window
|
||||||
// Access: Private, Static
|
// Access: Private, Static
|
||||||
|
@ -92,6 +92,8 @@ private:
|
|||||||
INLINE int translate_mouse(int pos) const;
|
INLINE int translate_mouse(int pos) const;
|
||||||
INLINE void set_cursor_in_window();
|
INLINE void set_cursor_in_window();
|
||||||
INLINE void set_cursor_out_of_window();
|
INLINE void set_cursor_out_of_window();
|
||||||
|
|
||||||
|
void resend_lost_keypresses();
|
||||||
static void update_cursor_window(WinGraphicsWindow *to_window);
|
static void update_cursor_window(WinGraphicsWindow *to_window);
|
||||||
|
|
||||||
static void register_window_class();
|
static void register_window_class();
|
||||||
@ -125,6 +127,7 @@ private:
|
|||||||
// to work around the problem.
|
// to work around the problem.
|
||||||
|
|
||||||
BYTE _keyboard_state[num_virtual_keys];
|
BYTE _keyboard_state[num_virtual_keys];
|
||||||
|
bool _lost_keypresses;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static bool _loaded_custom_cursor;
|
static bool _loaded_custom_cursor;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user