Added focus tracking in X11 and Windows classes, added new confined mouse mode (#7162)

This commit is contained in:
Ilija Boshkov 2017-01-25 19:21:41 +01:00 committed by Rémi Verschelde
parent 4c28f35b2c
commit 1005a56e5a
7 changed files with 78 additions and 34 deletions

View File

@ -38,7 +38,7 @@ Input *Input::get_singleton() {
}
void Input::set_mouse_mode(MouseMode p_mode) {
ERR_FAIL_INDEX(p_mode,3);
ERR_FAIL_INDEX(p_mode,4);
OS::get_singleton()->set_mouse_mode((OS::MouseMode)p_mode);
}
@ -87,6 +87,7 @@ void Input::_bind_methods() {
BIND_CONSTANT( MOUSE_MODE_VISIBLE );
BIND_CONSTANT( MOUSE_MODE_HIDDEN );
BIND_CONSTANT( MOUSE_MODE_CAPTURED );
BIND_CONSTANT( MOUSE_MODE_CONFINED );
ADD_SIGNAL( MethodInfo("joy_connection_changed", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::BOOL, "connected")) );
}

View File

@ -47,7 +47,8 @@ public:
enum MouseMode {
MOUSE_MODE_VISIBLE,
MOUSE_MODE_HIDDEN,
MOUSE_MODE_CAPTURED
MOUSE_MODE_CAPTURED,
MOUSE_MODE_CONFINED
};
void set_mouse_mode(MouseMode p_mode);

View File

@ -131,7 +131,8 @@ public:
enum MouseMode {
MOUSE_MODE_VISIBLE,
MOUSE_MODE_HIDDEN,
MOUSE_MODE_CAPTURED
MOUSE_MODE_CAPTURED,
MOUSE_MODE_CONFINED
};
virtual void set_mouse_mode(MouseMode p_mode);

View File

@ -254,6 +254,25 @@ LRESULT OS_Windows::WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) // Check For Windows Messages
{
case WM_SETFOCUS:
{
window_has_focus = true;
// Re-capture cursor if we're in one of the capture modes
if (mouse_mode==MOUSE_MODE_CAPTURED || mouse_mode==MOUSE_MODE_CONFINED) {
SetCapture(hWnd);
}
break;
}
case WM_KILLFOCUS:
{
window_has_focus = false;
// Release capture if we're in one of the capture modes
if (mouse_mode==MOUSE_MODE_CAPTURED || mouse_mode==MOUSE_MODE_CONFINED) {
ReleaseCapture();
}
break;
}
case WM_ACTIVATE: // Watch For Window Activate Message
{
minimized = HIWORD(wParam) != 0;
@ -266,19 +285,17 @@ LRESULT OS_Windows::WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam) {
alt_mem=false;
control_mem=false;
shift_mem=false;
if (mouse_mode==MOUSE_MODE_CAPTURED) {
if (mouse_mode==MOUSE_MODE_CAPTURED || mouse_mode==MOUSE_MODE_CONFINED) {
RECT clipRect;
GetClientRect(hWnd, &clipRect);
ClientToScreen(hWnd, (POINT*) &clipRect.left);
ClientToScreen(hWnd, (POINT*) &clipRect.right);
ClipCursor(&clipRect);
SetCapture(hWnd);
}
} else {
main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT);
alt_mem=false;
};
return 0; // Return To The Message Loop
@ -345,6 +362,9 @@ LRESULT OS_Windows::WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam) {
}
// Don't calculate relative mouse movement if we don't have focus in CAPTURED mode.
if (!window_has_focus && mouse_mode==MOUSE_MODE_CAPTURED)
break;
/*
LPARAM extra = GetMessageExtraInfo();
if (IsPenEvent(extra)) {
@ -376,7 +396,7 @@ LRESULT OS_Windows::WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam) {
mm.button_mask|=(wParam&MK_XBUTTON2)?(1<<6):0;*/
mm.x=GET_X_LPARAM(lParam);
mm.y=GET_Y_LPARAM(lParam);
if (mouse_mode==MOUSE_MODE_CAPTURED) {
Point2i c(video_mode.width/2,video_mode.height/2);
@ -410,7 +430,7 @@ LRESULT OS_Windows::WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam) {
mm.relative_y=mm.y-old_y;
old_x=mm.x;
old_y=mm.y;
if (main_loop)
if (window_has_focus && main_loop)
input->parse_input_event(event);
@ -714,9 +734,8 @@ LRESULT OS_Windows::WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam) {
joypad->probe_joypads();
} break;
case WM_SETCURSOR: {
if(LOWORD(lParam) == HTCLIENT) {
if(mouse_mode == MOUSE_MODE_HIDDEN || mouse_mode == MOUSE_MODE_CAPTURED) {
if(window_has_focus && (mouse_mode == MOUSE_MODE_HIDDEN || mouse_mode == MOUSE_MODE_CAPTURED)) {
//Hide the cursor
if(hCursor == NULL)
hCursor = SetCursor(NULL);
@ -948,7 +967,7 @@ void OS_Windows::initialize(const VideoMode& p_desired,int p_video_driver,int p_
main_loop=NULL;
outside=true;
window_has_focus=true;
WNDCLASSEXW wc;
video_mode=p_desired;
@ -1326,17 +1345,17 @@ void OS_Windows::set_mouse_mode(MouseMode p_mode) {
if (mouse_mode==p_mode)
return;
mouse_mode=p_mode;
if (p_mode==MOUSE_MODE_CAPTURED) {
if (mouse_mode==MOUSE_MODE_CAPTURED || mouse_mode==MOUSE_MODE_CONFINED) {
RECT clipRect;
GetClientRect(hWnd, &clipRect);
ClientToScreen(hWnd, (POINT*) &clipRect.left);
ClientToScreen(hWnd, (POINT*) &clipRect.right);
ClipCursor(&clipRect);
SetCapture(hWnd);
center=Point2i(video_mode.width/2,video_mode.height/2);
POINT pos = { (int) center.x, (int) center.y };
ClientToScreen(hWnd, &pos);
SetCursorPos(pos.x, pos.y);
if (mouse_mode==MOUSE_MODE_CAPTURED)
SetCursorPos(pos.x, pos.y);
} else {
ReleaseCapture();
ClipCursor(NULL);

View File

@ -118,6 +118,7 @@ class OS_Windows : public OS {
bool control_mem;
bool meta_mem;
bool force_quit;
bool window_has_focus;
uint32_t last_button_state;
CursorShape cursor_shape;

View File

@ -450,6 +450,8 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi
physics_2d_server->init();
input = memnew( InputDefault );
window_has_focus = true; // Set focus to true at init
#ifdef JOYDEV_ENABLED
joypad = memnew( JoypadLinux(input));
#endif
@ -518,17 +520,21 @@ void OS_X11::set_mouse_mode(MouseMode p_mode) {
if (p_mode==mouse_mode)
return;
if (mouse_mode==MOUSE_MODE_CAPTURED)
if (mouse_mode==MOUSE_MODE_CAPTURED || mouse_mode==MOUSE_MODE_CONFINED)
XUngrabPointer(x11_display, CurrentTime);
if (mouse_mode!=MOUSE_MODE_VISIBLE && p_mode==MOUSE_MODE_VISIBLE)
XUndefineCursor(x11_display,x11_window);
if (p_mode!=MOUSE_MODE_VISIBLE && mouse_mode==MOUSE_MODE_VISIBLE) {
XDefineCursor(x11_display,x11_window,null_cursor);
// The only modes that show a cursor are VISIBLE and CONFINED
bool showCursor = (p_mode == MOUSE_MODE_VISIBLE || p_mode == MOUSE_MODE_CONFINED);
if (showCursor) {
XUndefineCursor(x11_display,x11_window); // show cursor
} else {
XDefineCursor(x11_display,x11_window,null_cursor); // hide cursor
}
mouse_mode=p_mode;
if (mouse_mode==MOUSE_MODE_CAPTURED) {
if (mouse_mode==MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED) {
while(true) {
//flush pending motion events
@ -1254,6 +1260,10 @@ void OS_X11::process_xevents() {
do_mouse_warp=false;
// Is the current mouse mode one where it needs to be grabbed.
bool mouse_mode_grab = mouse_mode==MOUSE_MODE_CAPTURED || mouse_mode==MOUSE_MODE_CONFINED;
while (XPending(x11_display) > 0) {
XEvent event;
XNextEvent(x11_display, &event);
@ -1272,35 +1282,45 @@ void OS_X11::process_xevents() {
minimized = (visibility->state == VisibilityFullyObscured);
} break;
case LeaveNotify: {
if (main_loop && mouse_mode!=MOUSE_MODE_CAPTURED)
if (main_loop && !mouse_mode_grab)
main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_EXIT);
if (input)
input->set_mouse_in_window(false);
} break;
case EnterNotify: {
if (main_loop && mouse_mode!=MOUSE_MODE_CAPTURED)
if (main_loop && !mouse_mode_grab)
main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_ENTER);
if (input)
input->set_mouse_in_window(true);
} break;
case FocusIn:
minimized = false;
window_has_focus = true;
main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_IN);
if (mouse_mode==MOUSE_MODE_CAPTURED) {
if (mouse_mode_grab) {
// Show and update the cursor if confined and the window regained focus.
if (mouse_mode==MOUSE_MODE_CONFINED)
XUndefineCursor(x11_display, x11_window);
else if (mouse_mode==MOUSE_MODE_CAPTURED) // or re-hide it in captured mode
XDefineCursor(x11_display, x11_window, null_cursor);
XGrabPointer(
x11_display, x11_window, True,
x11_display, x11_window, True,
ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
GrabModeAsync, GrabModeAsync, x11_window, None, CurrentTime);
}
break;
case FocusOut:
window_has_focus = false;
main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT);
if (mouse_mode==MOUSE_MODE_CAPTURED) {
if (mouse_mode_grab) {
//dear X11, I try, I really try, but you never work, you do whathever you want.
if (mouse_mode==MOUSE_MODE_CAPTURED) {
// Show the cursor if we're in captured mode so it doesn't look weird.
XUndefineCursor(x11_display, x11_window);
}
XUngrabPointer(x11_display, CurrentTime);
}
break;
@ -1320,7 +1340,7 @@ void OS_X11::process_xevents() {
/* exit in case of a mouse button press */
last_timestamp=event.xbutton.time;
if (mouse_mode==MOUSE_MODE_CAPTURED) {
if (mouse_mode == MOUSE_MODE_CAPTURED) {
event.xbutton.x=last_mouse_pos.x;
event.xbutton.y=last_mouse_pos.y;
}
@ -1343,7 +1363,6 @@ void OS_X11::process_xevents() {
mouse_event.mouse_button.pressed=(event.type==ButtonPress);
if (event.type==ButtonPress && event.xbutton.button==1) {
uint64_t diff = get_ticks_usec()/1000 - last_click_ms;
@ -1377,7 +1396,6 @@ void OS_X11::process_xevents() {
// PLEASE DO ME A FAVOR AND DIE DROWNED IN A FECAL
// MOUNTAIN BECAUSE THAT'S WHERE YOU BELONG.
while(true) {
if (mouse_mode==MOUSE_MODE_CAPTURED && event.xmotion.x==current_videomode.width/2 && event.xmotion.y==current_videomode.height/2) {
//this is likely the warp event since it was warped here
@ -1419,7 +1437,7 @@ void OS_X11::process_xevents() {
Point2i new_center = pos;
pos = last_mouse_pos + ( pos - center );
center=new_center;
do_mouse_warp=true;
do_mouse_warp=window_has_focus; // warp the cursor if we're focused in
#else
//Dear X11, thanks for making my life miserable
@ -1462,8 +1480,11 @@ void OS_X11::process_xevents() {
last_mouse_pos=pos;
// printf("rel: %d,%d\n", rel.x, rel.y );
input->parse_input_event( motion_event);
// Don't propagate the motion event unless we have focus
// this is so that the relative motion doesn't get messed up
// after we regain focus.
if (window_has_focus || !mouse_mode_grab)
input->parse_input_event( motion_event);
} break;
case KeyPress:

View File

@ -134,7 +134,7 @@ class OS_X11 : public OS_Unix {
bool force_quit;
bool minimized;
bool window_has_focus;
bool do_mouse_warp;
const char *cursor_theme;