Ver Fonte

windisplay: Support relative mouse mode (using raw input)

Fixes #928
rdb há 5 anos atrás
pai
commit
3000aa2369

+ 63 - 17
panda/src/windisplay/winGraphicsWindow.cxx

@@ -426,18 +426,22 @@ set_properties_now(WindowProperties &properties) {
     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) {
+        if (_properties.get_mouse_mode() != WindowProperties::M_absolute) {
           ClipCursor(nullptr);
           windisplay_cat.info() << "Unconfining cursor from window\n";
         }
         _properties.set_mouse_mode(WindowProperties::M_absolute);
         break;
 
+      case WindowProperties::M_relative:
+        if (!enable_raw_input()) {
+          break;
+        }
+        // Fall through
+
       case WindowProperties::M_confined:
         if (confine_cursor()) {
-          _properties.set_mouse_mode(WindowProperties::M_confined);
+          _properties.set_mouse_mode(properties.get_mouse_mode());
         }
         break;
       }
@@ -564,13 +568,8 @@ open_window() {
   }
 
   // Registers to receive the WM_INPUT messages
-  if (_input_devices.size() > 1) {
-    RAWINPUTDEVICE Rid;
-    Rid.usUsagePage = 0x01;
-    Rid.usUsage = 0x02;
-    Rid.dwFlags = 0;// RIDEV_NOLEGACY;   // adds HID mouse and also ignores legacy mouse messages
-    Rid.hwndTarget = _hWnd;
-    RegisterRawInputDevices(&Rid, 1, sizeof (Rid));
+  if (_input_devices.size() > 1 || _properties.get_mouse_mode() == WindowProperties::M_relative) {
+    enable_raw_input();
   }
 
   // Create a WindowHandle for ourselves
@@ -683,6 +682,32 @@ initialize_input_devices() {
   }
 }
 
+/**
+ * Enables raw mouse input for this window.  Returns true on success.
+ */
+bool WinGraphicsWindow::
+enable_raw_input() {
+  if (_raw_input_enabled) {
+    return true;
+  }
+
+  RAWINPUTDEVICE rid;
+  rid.usUsagePage = 0x01;
+  rid.usUsage = 0x02;
+  rid.dwFlags = 0;
+  rid.hwndTarget = _hWnd;
+  if (RegisterRawInputDevices(&rid, 1, sizeof(rid))) {
+    windisplay_cat.info()
+      << "Enabled raw mouse input.\n";
+    _raw_input_enabled = true;
+    return true;
+  } else {
+    windisplay_cat.warning()
+      << "Failed to enable raw mouse input.\n";
+    return false;
+  }
+}
+
 /**
  * This is a hook for derived classes to do something special, if necessary,
  * when a fullscreen window has been minimized.  The given WindowProperties
@@ -1586,7 +1611,9 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
       resend_lost_keypresses();
     }
     SetCapture(hwnd);
-    _input->set_pointer_in_window(translate_mouse(LOWORD(lparam)), translate_mouse(HIWORD(lparam)));
+    if (_properties.get_mouse_mode() != WindowProperties::M_relative) {
+      _input->set_pointer_in_window(translate_mouse(LOWORD(lparam)), translate_mouse(HIWORD(lparam)));
+    }
     _input->button_down(MouseButton::button(0), get_message_time());
 
     // A button-click in the window means to grab the keyboard focus.
@@ -1598,7 +1625,9 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
       resend_lost_keypresses();
     }
     SetCapture(hwnd);
-    _input->set_pointer_in_window(translate_mouse(LOWORD(lparam)), translate_mouse(HIWORD(lparam)));
+    if (_properties.get_mouse_mode() != WindowProperties::M_relative) {
+      _input->set_pointer_in_window(translate_mouse(LOWORD(lparam)), translate_mouse(HIWORD(lparam)));
+    }
     _input->button_down(MouseButton::button(1), get_message_time());
     // A button-click in the window means to grab the keyboard focus.
     set_focus();
@@ -1609,7 +1638,9 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
       resend_lost_keypresses();
     }
     SetCapture(hwnd);
-    _input->set_pointer_in_window(translate_mouse(LOWORD(lparam)), translate_mouse(HIWORD(lparam)));
+    if (_properties.get_mouse_mode() != WindowProperties::M_relative) {
+      _input->set_pointer_in_window(translate_mouse(LOWORD(lparam)), translate_mouse(HIWORD(lparam)));
+    }
     _input->button_down(MouseButton::button(2), get_message_time());
     // A button-click in the window means to grab the keyboard focus.
     set_focus();
@@ -1622,7 +1653,9 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
       }
       SetCapture(hwnd);
       int whichButton = GET_XBUTTON_WPARAM(wparam);
-      _input->set_pointer_in_window(translate_mouse(LOWORD(lparam)), translate_mouse(HIWORD(lparam)));
+      if (_properties.get_mouse_mode() != WindowProperties::M_relative) {
+        _input->set_pointer_in_window(translate_mouse(LOWORD(lparam)), translate_mouse(HIWORD(lparam)));
+      }
       if (whichButton == XBUTTON1) {
         _input->button_down(MouseButton::button(3), get_message_time());
       } else if (whichButton == XBUTTON2) {
@@ -2430,7 +2463,9 @@ show_error_message(DWORD message_id) {
  */
 void WinGraphicsWindow::
 handle_keypress(ButtonHandle key, int x, int y, double time) {
-  _input->set_pointer_in_window(x, y);
+  if (_properties.get_mouse_mode() != WindowProperties::M_relative) {
+    _input->set_pointer_in_window(x, y);
+  }
   if (key != ButtonHandle::none()) {
     _input->button_down(key, time);
   }
@@ -2776,6 +2811,15 @@ handle_raw_input(HRAWINPUT hraw) {
   }
 
   RAWINPUT *raw = (RAWINPUT *)lpb;
+  if (_properties.get_mouse_mode() == WindowProperties::M_relative &&
+      raw->header.dwType == RIM_TYPEMOUSE &&
+      (raw->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) == 0) {
+    double x = raw->data.mouse.lLastX;
+    double y = raw->data.mouse.lLastY;
+    PointerData md = _input->get_pointer();
+    _input->set_pointer_in_window(md.get_x() + x, md.get_y() + y);
+  }
+
   if (raw->header.hDevice == 0) {
     return;
   }
@@ -2833,7 +2877,9 @@ handle_raw_input(HRAWINPUT hraw) {
  */
 bool WinGraphicsWindow::
 handle_mouse_motion(int x, int y) {
-  _input->set_pointer_in_window(x, y);
+  if (_properties.get_mouse_mode() != WindowProperties::M_relative) {
+    _input->set_pointer_in_window(x, y);
+  }
   return false;
 }
 

+ 2 - 0
panda/src/windisplay/winGraphicsWindow.h

@@ -132,6 +132,7 @@ private:
   void adjust_z_order(WindowProperties::ZOrder last_z_order,
                       WindowProperties::ZOrder this_z_order);
   void initialize_input_devices();
+  bool enable_raw_input();
   void handle_raw_input(HRAWINPUT hraw);
   void track_mouse_leaving(HWND hwnd);
   bool confine_cursor();
@@ -190,6 +191,7 @@ private:
   bool _ralt_down;
 
   GraphicsWindowInputDevice *_input;
+  bool _raw_input_enabled = false;
 
   // following adds support platform specfic window processing functions.
   typedef pset<GraphicsWindowProc*> WinProcClasses;