Added focus tracking in X11 and Windows classes, added new confined mouse mode (#7162)
This commit is contained in:
parent
4c28f35b2c
commit
1005a56e5a
@ -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")) );
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user