mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-29 16:20:11 -04:00
Implement an M_confined mouse mode to ensure mouse stays in window.
This commit is contained in:
parent
500da29013
commit
48cc1aa496
@ -736,24 +736,10 @@ set_properties_now(WindowProperties &properties) {
|
||||
// Fullscreen property specified, but unchanged.
|
||||
properties.clear_fullscreen();
|
||||
}
|
||||
if (properties.has_mouse_mode() ) {
|
||||
|
||||
if (properties.get_mouse_mode() == _properties.get_mouse_mode()) {
|
||||
properties.clear_mouse_mode();
|
||||
}
|
||||
else {
|
||||
if(properties.get_mouse_mode() == WindowProperties::M_absolute) {
|
||||
_properties.set_mouse_mode(WindowProperties::M_absolute);
|
||||
mouse_mode_absolute();
|
||||
properties.clear_mouse_mode();
|
||||
}
|
||||
else
|
||||
{
|
||||
_properties.set_mouse_mode(WindowProperties::M_relative);
|
||||
mouse_mode_relative();
|
||||
properties.clear_mouse_mode();
|
||||
}
|
||||
}
|
||||
if (properties.has_mouse_mode() &&
|
||||
properties.get_mouse_mode() == _properties.get_mouse_mode()) {
|
||||
// Mouse mode specified, but unchanged.
|
||||
properties.clear_mouse_mode();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -798,19 +798,30 @@ clear_z_order() {
|
||||
// Function: WindowProperties::set_mouse_mode
|
||||
// Access: Published
|
||||
// Description: Specifies the mode in which the window is to operate
|
||||
// its mouse pointer. The default is M_absolute, which
|
||||
// is the normal mode in which a mouse pointer operates;
|
||||
// but you can also set M_relative, which is
|
||||
// particularly useful for FPS-style mouse movements
|
||||
// where you have hidden the mouse pointer and are are
|
||||
// more interested in how fast the mouse is moving,
|
||||
// rather than precisely where the pointer is hovering.
|
||||
// its mouse pointer.
|
||||
//
|
||||
// M_absolute: the normal mode in which a mouse pointer
|
||||
// operates, where the mouse can move outside the window
|
||||
// and the mouse coordinates are relative to its
|
||||
// position in the window.
|
||||
//
|
||||
// M_relative (OSX or Unix/X11 only): a mode where only
|
||||
// relative movements are reported; particularly useful
|
||||
// for FPS-style mouse movements where you have hidden
|
||||
// the mouse pointer and are are more interested in how
|
||||
// fast the mouse is moving, rather than precisely where
|
||||
// the pointer is hovering.
|
||||
//
|
||||
// This has no effect on Windows. On Unix/X11, this
|
||||
// requires the Xxf86dga extension to be available.
|
||||
//
|
||||
// M_confined: this mode reports absolute mouse
|
||||
// positions, but confines the mouse pointer to
|
||||
// the window boundary. It can portably replace
|
||||
// M_relative for an FPS, but you need to periodically
|
||||
// move the pointer to the center of the window
|
||||
// and track movement deltas.
|
||||
//
|
||||
// This has no effect on Windows, which does not
|
||||
// have this concept; but is important to do on OSX
|
||||
// and Unix/X11 to properly enable a smooth FPS-style
|
||||
// mouselook mode. On Unix/X11, this requires the
|
||||
// Xxf86dga extension to be available.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void WindowProperties::
|
||||
set_mouse_mode(MouseMode mode) {
|
||||
|
@ -400,6 +400,8 @@ operator << (ostream &out, WindowProperties::MouseMode mode) {
|
||||
return out << "absolute";
|
||||
case WindowProperties::M_relative:
|
||||
return out << "relative";
|
||||
case WindowProperties::M_confined:
|
||||
return out << "confined";
|
||||
}
|
||||
return out << "**invalid WindowProperties::MouseMode(" << (int)mode << ")**";
|
||||
}
|
||||
@ -413,6 +415,8 @@ operator >> (istream &in, WindowProperties::MouseMode &mode) {
|
||||
mode = WindowProperties::M_absolute;
|
||||
} else if (word == "relative") {
|
||||
mode = WindowProperties::M_relative;
|
||||
} else if (word == "confined") {
|
||||
mode = WindowProperties::M_confined;
|
||||
} else {
|
||||
display_cat.warning()
|
||||
<< "Unknown mouse mode: " << word << "\n";
|
||||
|
@ -40,6 +40,7 @@ PUBLISHED:
|
||||
enum MouseMode {
|
||||
M_absolute,
|
||||
M_relative,
|
||||
M_confined,
|
||||
};
|
||||
|
||||
WindowProperties();
|
||||
|
@ -35,6 +35,8 @@ WinGraphicsWindow *WinGraphicsWindow::_creating_window = NULL;
|
||||
WinGraphicsWindow *WinGraphicsWindow::_cursor_window = NULL;
|
||||
bool WinGraphicsWindow::_cursor_hidden = false;
|
||||
|
||||
RECT WinGraphicsWindow::_mouse_unconfined_cliprect;
|
||||
|
||||
// These are used to save the previous state of the fancy Win2000
|
||||
// effects that interfere with rendering when the mouse wanders into a
|
||||
// window's client area.
|
||||
@ -359,6 +361,50 @@ set_properties_now(WindowProperties &properties) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (properties.has_mouse_mode()) {
|
||||
if (properties.get_mouse_mode() != _properties.get_mouse_mode()) {
|
||||
switch (properties.get_mouse_mode()) {
|
||||
case WindowProperties::M_absolute:
|
||||
case WindowProperties::M_relative: // not implemented, treat as absolute
|
||||
|
||||
if (_properties.get_mouse_mode() == WindowProperties::M_confined) {
|
||||
ClipCursor(NULL);
|
||||
windisplay_cat.info() << "Unconfining cursor from window\n";
|
||||
}
|
||||
_properties.set_mouse_mode(WindowProperties::M_absolute);
|
||||
break;
|
||||
|
||||
case WindowProperties::M_confined:
|
||||
{
|
||||
RECT clip;
|
||||
|
||||
if (!GetWindowRect(_hWnd, &clip)) {
|
||||
if (windisplay_cat.is_debug()) {
|
||||
windisplay_cat.debug()
|
||||
<< "GetWindowRect() failed in set_properties_now. Cannot confine cursor.\n";
|
||||
}
|
||||
} else {
|
||||
windisplay_cat.debug()
|
||||
<< "ClipCursor() to " << clip.left << "," << clip.top << " to "
|
||||
<< clip.right << "," << clip.bottom << endl;
|
||||
|
||||
GetClipCursor(&_mouse_unconfined_cliprect);
|
||||
if (!ClipCursor(&clip)) {
|
||||
windisplay_cat.debug()
|
||||
<< "ClipCursor() failed in set_properties_now. Ignoring.\n";
|
||||
} else {
|
||||
_properties.set_mouse_mode(WindowProperties::M_confined);
|
||||
windisplay_cat.info() << "Confining cursor to window\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
properties.clear_mouse_mode();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -214,6 +214,9 @@ private:
|
||||
static BOOL _saved_cursor_shadow;
|
||||
static BOOL _saved_mouse_vanish;
|
||||
|
||||
// The mouse constraints before applying mouse mode M_confined.
|
||||
static RECT _mouse_unconfined_cliprect;
|
||||
|
||||
// Since the Panda API requests icons and cursors by filename, we
|
||||
// need a table mapping filenames to handles, so we can avoid
|
||||
// re-reading the file each time we change icons.
|
||||
|
@ -711,6 +711,92 @@ set_properties_now(WindowProperties &properties) {
|
||||
properties.clear_foreground();
|
||||
}
|
||||
|
||||
if (properties.has_mouse_mode()) {
|
||||
switch (properties.get_mouse_mode()) {
|
||||
case WindowProperties::M_absolute:
|
||||
XUngrabPointer(_display, CurrentTime);
|
||||
#ifdef HAVE_XF86DGA
|
||||
if (_dga_mouse_enabled) {
|
||||
x11display_cat.info() << "Disabling relative mouse using XF86DGA extension\n";
|
||||
XF86DGADirectVideo(_display, _screen, 0);
|
||||
_dga_mouse_enabled = false;
|
||||
}
|
||||
#endif
|
||||
_properties.set_mouse_mode(WindowProperties::M_absolute);
|
||||
properties.clear_mouse_mode();
|
||||
break;
|
||||
|
||||
case WindowProperties::M_relative:
|
||||
#ifdef HAVE_XF86DGA
|
||||
if (!_dga_mouse_enabled) {
|
||||
int major_ver, minor_ver;
|
||||
if (XF86DGAQueryVersion(_display, &major_ver, &minor_ver)) {
|
||||
|
||||
X11_Cursor cursor = None;
|
||||
if (_properties.get_cursor_hidden()) {
|
||||
x11GraphicsPipe *x11_pipe;
|
||||
DCAST_INTO_V(x11_pipe, _pipe);
|
||||
cursor = x11_pipe->get_hidden_cursor();
|
||||
}
|
||||
|
||||
if (XGrabPointer(_display, _xwindow, True, 0, GrabModeAsync,
|
||||
GrabModeAsync, _xwindow, cursor, CurrentTime) != GrabSuccess) {
|
||||
x11display_cat.error() << "Failed to grab pointer!\n";
|
||||
} else {
|
||||
x11display_cat.info() << "Enabling relative mouse using XF86DGA extension\n";
|
||||
XF86DGADirectVideo(_display, _screen, XF86DGADirectMouse);
|
||||
|
||||
_properties.set_mouse_mode(WindowProperties::M_relative);
|
||||
_dga_mouse_enabled = true;
|
||||
|
||||
// Get the real mouse position, so we can add/subtract
|
||||
// our relative coordinates later.
|
||||
XEvent event;
|
||||
XQueryPointer(_display, _xwindow, &event.xbutton.root,
|
||||
&event.xbutton.window, &event.xbutton.x_root, &event.xbutton.y_root,
|
||||
&event.xbutton.x, &event.xbutton.y, &event.xbutton.state);
|
||||
_input_devices[0].set_pointer_in_window(event.xbutton.x, event.xbutton.y);
|
||||
}
|
||||
} else {
|
||||
x11display_cat.info() << "XF86DGA extension not available\n";
|
||||
_dga_mouse_enabled = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
// can't change
|
||||
properties.clear_mouse_mode();
|
||||
}
|
||||
break;
|
||||
|
||||
case WindowProperties::M_confined:
|
||||
{
|
||||
#ifdef HAVE_XF86DGA
|
||||
if (_dga_mouse_enabled) {
|
||||
XF86DGADirectVideo(_display, _screen, 0);
|
||||
_dga_mouse_enabled = false;
|
||||
}
|
||||
#endif
|
||||
X11_Cursor cursor = None;
|
||||
if (_properties.get_cursor_hidden()) {
|
||||
x11GraphicsPipe *x11_pipe;
|
||||
DCAST_INTO_V(x11_pipe, _pipe);
|
||||
cursor = x11_pipe->get_hidden_cursor();
|
||||
}
|
||||
|
||||
if (XGrabPointer(_display, _xwindow, True, 0, GrabModeAsync,
|
||||
GrabModeAsync, _xwindow, cursor, CurrentTime) != GrabSuccess) {
|
||||
x11display_cat.error() << "Failed to grab pointer!\n";
|
||||
} else {
|
||||
_properties.set_mouse_mode(WindowProperties::M_confined);
|
||||
properties.clear_mouse_mode();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
set_wm_properties(wm_properties, true);
|
||||
}
|
||||
|
||||
@ -721,14 +807,7 @@ set_properties_now(WindowProperties &properties) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void x11GraphicsWindow::
|
||||
mouse_mode_absolute() {
|
||||
#ifdef HAVE_XF86DGA
|
||||
if (!_dga_mouse_enabled) return;
|
||||
|
||||
XUngrabPointer(_display, CurrentTime);
|
||||
x11display_cat.info() << "Disabling relative mouse using XF86DGA extension\n";
|
||||
XF86DGADirectVideo(_display, _screen, 0);
|
||||
_dga_mouse_enabled = false;
|
||||
#endif
|
||||
// unused: remove in 1.10!
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -738,42 +817,7 @@ mouse_mode_absolute() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void x11GraphicsWindow::
|
||||
mouse_mode_relative() {
|
||||
#ifdef HAVE_XF86DGA
|
||||
if (_dga_mouse_enabled) return;
|
||||
|
||||
int major_ver, minor_ver;
|
||||
if (XF86DGAQueryVersion(_display, &major_ver, &minor_ver)) {
|
||||
|
||||
X11_Cursor cursor = None;
|
||||
if (_properties.get_cursor_hidden()) {
|
||||
x11GraphicsPipe *x11_pipe;
|
||||
DCAST_INTO_V(x11_pipe, _pipe);
|
||||
cursor = x11_pipe->get_hidden_cursor();
|
||||
}
|
||||
|
||||
if (XGrabPointer(_display, _xwindow, True, 0, GrabModeAsync,
|
||||
GrabModeAsync, _xwindow, cursor, CurrentTime) != GrabSuccess) {
|
||||
x11display_cat.error() << "Failed to grab pointer!\n";
|
||||
return;
|
||||
}
|
||||
|
||||
x11display_cat.info() << "Enabling relative mouse using XF86DGA extension\n";
|
||||
XF86DGADirectVideo(_display, _screen, XF86DGADirectMouse);
|
||||
|
||||
_dga_mouse_enabled = true;
|
||||
} else {
|
||||
x11display_cat.info() << "XF86DGA extension not available\n";
|
||||
_dga_mouse_enabled = false;
|
||||
}
|
||||
|
||||
// Get the real mouse position, so we can add/subtract
|
||||
// our relative coordinates later.
|
||||
XEvent event;
|
||||
XQueryPointer(_display, _xwindow, &event.xbutton.root,
|
||||
&event.xbutton.window, &event.xbutton.x_root, &event.xbutton.y_root,
|
||||
&event.xbutton.x, &event.xbutton.y, &event.xbutton.state);
|
||||
_input_devices[0].set_pointer_in_window(event.xbutton.x, event.xbutton.y);
|
||||
#endif
|
||||
// unused: remove in 1.10!
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
Loading…
x
Reference in New Issue
Block a user