mingw-spice-vdagent/0017-vdagent-Fix-loss-of-mouse-movement-events.patch
2023-04-04 16:01:10 +00:00

258 lines
10 KiB
Diff

From b291e4ca14b611ad20cb93d90dc98c8a715b91f9 Mon Sep 17 00:00:00 2001
From: "free.user.name" <free.user.name@ya.ru>
Date: Fri, 16 Feb 2018 15:05:39 +0300
Subject: [PATCH 17/43] vdagent: Fix loss of mouse movement events
send_input() may not be immediately called from handle_mouse_event() on
movement. INPUT structure is generated and stored and a timer may be set
instead. If subsequent call to handle_mouse_event() occurs before timer
expires, prepared INPUT structure gets overwritten and MOUSEEVENTF_MOVE
bit is lost. Windows doesn't see updated mouse position as the result.
Make handle_mouse_event() merely store the new mouse state, and move
INPUT structure generation to send_input(). Shuffle new mouse state to
previous only after mouse events are submitted to SendInput() Windows
API function.
This patch was sent to the mailing list by an anonymous contributor
with minimal style changes.
You can easily test increasing VD_INPUT_INTERVAL_MS (like 1000).
For instance you can try in a word processor to move the cursor
clicking the mouse on different positions.
Acked-by: Victor Toso <victortoso@redhat.com>
---
vdagent/vdagent.cpp | 145 +++++++++++++++++++++-----------------------
1 file changed, 70 insertions(+), 75 deletions(-)
diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp
index 0a364df..ca1f8fa 100644
--- a/vdagent/vdagent.cpp
+++ b/vdagent/vdagent.cpp
@@ -89,8 +89,7 @@ private:
void on_clipboard_grab();
void on_clipboard_request(UINT format);
void on_clipboard_release();
- DWORD get_buttons_change(DWORD last_buttons_state, DWORD new_buttons_state,
- DWORD mask, DWORD down_flag, DWORD up_flag);
+ DWORD get_buttons_change(DWORD mask, DWORD down_flag, DWORD up_flag);
static HGLOBAL utf8_alloc(LPCSTR data, int size);
static LRESULT CALLBACK wnd_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
static DWORD WINAPI event_thread_proc(LPVOID param);
@@ -130,10 +129,8 @@ private:
int _system_version;
int _clipboard_owner;
DWORD _clipboard_tick;
- DWORD _buttons_state;
- ULONG _mouse_x;
- ULONG _mouse_y;
- INPUT _input;
+ VDAgentMouseState _new_mouse = {};
+ VDAgentMouseState _last_mouse = {};
DWORD _input_time;
HANDLE _control_event;
HANDLE _stop_event;
@@ -190,9 +187,6 @@ VDAgent::VDAgent()
, _remove_clipboard_listener (NULL)
, _clipboard_owner (owner_none)
, _clipboard_tick (0)
- , _buttons_state (0)
- , _mouse_x (0)
- , _mouse_y (0)
, _input_time (0)
, _control_event (NULL)
, _stop_event (NULL)
@@ -220,7 +214,6 @@ VDAgent::VDAgent()
swprintf_s(log_path, MAX_PATH, VD_AGENT_LOG_PATH, temp_path);
_log = VDLog::get(log_path);
}
- ZeroMemory(&_input, sizeof(_input));
ZeroMemory(&_read_overlapped, sizeof(_read_overlapped));
ZeroMemory(&_write_overlapped, sizeof(_write_overlapped));
ZeroMemory(_read_buf, sizeof(_read_buf));
@@ -521,113 +514,115 @@ void VDAgent::event_dispatcher(DWORD timeout, DWORD wake_mask)
}
}
-DWORD VDAgent::get_buttons_change(DWORD last_buttons_state, DWORD new_buttons_state,
- DWORD mask, DWORD down_flag, DWORD up_flag)
+DWORD VDAgent::get_buttons_change(DWORD mask, DWORD down_flag, DWORD up_flag)
{
DWORD ret = 0;
- if (!(last_buttons_state & mask) && (new_buttons_state & mask)) {
+ if (!(_last_mouse.buttons & mask) && (_new_mouse.buttons & mask)) {
ret = down_flag;
- } else if ((last_buttons_state & mask) && !(new_buttons_state & mask)) {
+ } else if ((_last_mouse.buttons & mask) && !(_new_mouse.buttons & mask)) {
ret = up_flag;
}
return ret;
}
bool VDAgent::send_input()
-{
- bool ret = true;
- _desktop_layout->lock();
- if (_pending_input) {
- if (KillTimer(_hwnd, VD_TIMER_ID)) {
- _pending_input = false;
- } else {
- vd_printf("KillTimer failed: %lu", GetLastError());
- _running = false;
- _desktop_layout->unlock();
- return false;
- }
- }
- if (!SendInput(1, &_input, sizeof(INPUT))) {
- DWORD err = GetLastError();
- // Don't stop agent due to UIPI blocking, which is usually only for specific windows
- // of system security applications (anti-viruses etc.)
- if (err != ERROR_SUCCESS && err != ERROR_ACCESS_DENIED) {
- vd_printf("SendInput failed: %lu", err);
- ret = _running = false;
- }
- }
- _input_time = GetTickCount();
- _desktop_layout->unlock();
- return ret;
-}
-
-bool VDAgent::handle_mouse_event(VDAgentMouseState* state)
{
DisplayMode* mode = NULL;
DWORD mouse_move = 0;
DWORD buttons_change = 0;
DWORD mouse_wheel = 0;
bool ret = true;
+ INPUT input;
+
+ if (_pending_input) {
+ if (KillTimer(_hwnd, VD_TIMER_ID)) {
+ _pending_input = false;
+ } else {
+ vd_printf("KillTimer failed: %lu", GetLastError());
+ _running = false;
+ return false;
+ }
+ }
ASSERT(_desktop_layout);
_desktop_layout->lock();
- if (state->display_id < _desktop_layout->get_display_count()) {
- mode = _desktop_layout->get_display(state->display_id);
+ if (_new_mouse.display_id < _desktop_layout->get_display_count()) {
+ mode = _desktop_layout->get_display(_new_mouse.display_id);
}
if (!mode || !mode->get_attached()) {
_desktop_layout->unlock();
return true;
}
- ZeroMemory(&_input, sizeof(INPUT));
- _input.type = INPUT_MOUSE;
- if (state->x != _mouse_x || state->y != _mouse_y) {
+ ZeroMemory(&input, sizeof(INPUT));
+ input.type = INPUT_MOUSE;
+ if (_new_mouse.x != _last_mouse.x || _new_mouse.y != _last_mouse.y) {
DWORD w = _desktop_layout->get_total_width();
DWORD h = _desktop_layout->get_total_height();
w = (w > 1) ? w-1 : 1; /* coordinates are 0..w-1, protect w==0 */
h = (h > 1) ? h-1 : 1; /* coordinates are 0..h-1, protect h==0 */
- _mouse_x = state->x;
- _mouse_y = state->y;
mouse_move = MOUSEEVENTF_MOVE;
- _input.mi.dx = (mode->get_pos_x() + _mouse_x) * 0xffff / w;
- _input.mi.dy = (mode->get_pos_y() + _mouse_y) * 0xffff / h;
+ input.mi.dx = (mode->get_pos_x() + _new_mouse.x) * 0xffff / w;
+ input.mi.dy = (mode->get_pos_y() + _new_mouse.y) * 0xffff / h;
}
- if (state->buttons != _buttons_state) {
- buttons_change = get_buttons_change(_buttons_state, state->buttons, VD_AGENT_LBUTTON_MASK,
+ if (_new_mouse.buttons != _last_mouse.buttons) {
+ buttons_change = get_buttons_change(VD_AGENT_LBUTTON_MASK,
MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_LEFTUP) |
- get_buttons_change(_buttons_state, state->buttons, VD_AGENT_MBUTTON_MASK,
+ get_buttons_change(VD_AGENT_MBUTTON_MASK,
MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_MIDDLEUP) |
- get_buttons_change(_buttons_state, state->buttons, VD_AGENT_RBUTTON_MASK,
+ get_buttons_change(VD_AGENT_RBUTTON_MASK,
MOUSEEVENTF_RIGHTDOWN, MOUSEEVENTF_RIGHTUP);
- mouse_wheel = get_buttons_change(_buttons_state, state->buttons,
- VD_AGENT_UBUTTON_MASK | VD_AGENT_DBUTTON_MASK,
+ mouse_wheel = get_buttons_change(VD_AGENT_UBUTTON_MASK | VD_AGENT_DBUTTON_MASK,
MOUSEEVENTF_WHEEL, 0);
if (mouse_wheel) {
- if (state->buttons & VD_AGENT_UBUTTON_MASK) {
- _input.mi.mouseData = WHEEL_DELTA;
- } else if (state->buttons & VD_AGENT_DBUTTON_MASK) {
- _input.mi.mouseData = (DWORD)(-WHEEL_DELTA);
+ if (_new_mouse.buttons & VD_AGENT_UBUTTON_MASK) {
+ input.mi.mouseData = WHEEL_DELTA;
+ } else if (_new_mouse.buttons & VD_AGENT_DBUTTON_MASK) {
+ input.mi.mouseData = (DWORD)(-WHEEL_DELTA);
}
}
- _buttons_state = state->buttons;
}
- _input.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK | mouse_move |
- mouse_wheel | buttons_change;
+ input.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK | mouse_move |
+ mouse_wheel | buttons_change;
- if ((mouse_move && GetTickCount() - _input_time > VD_INPUT_INTERVAL_MS) || buttons_change ||
- mouse_wheel) {
- ret = send_input();
- } else if (!_pending_input) {
- if (SetTimer(_hwnd, VD_TIMER_ID, VD_INPUT_INTERVAL_MS, NULL)) {
+ if (!SendInput(1, &input, sizeof(INPUT))) {
+ DWORD err = GetLastError();
+ // Don't stop agent due to UIPI blocking, which is usually only for specific windows
+ // of system security applications (anti-viruses etc.)
+ if (err != ERROR_SUCCESS && err != ERROR_ACCESS_DENIED) {
+ vd_printf("SendInput failed: %lu", err);
+ ret = _running = false;
+ }
+ } else {
+ _last_mouse = _new_mouse;
+ }
+ _input_time = GetTickCount();
+ _desktop_layout->unlock();
+ return ret;
+}
+
+bool VDAgent::handle_mouse_event(VDAgentMouseState* state)
+{
+ _new_mouse = *state;
+ if (_new_mouse.buttons != _last_mouse.buttons) {
+ return send_input();
+ }
+
+ if (_new_mouse.x != _last_mouse.x || _new_mouse.y != _last_mouse.y) {
+ if (GetTickCount() - _input_time > VD_INPUT_INTERVAL_MS) {
+ return send_input();
+ }
+
+ if (!_pending_input) {
+ if (!SetTimer(_hwnd, VD_TIMER_ID, VD_INPUT_INTERVAL_MS, NULL)) {
+ vd_printf("SetTimer failed: %lu", GetLastError());
+ _running = false;
+ return false;
+ }
_pending_input = true;
- } else {
- vd_printf("SetTimer failed: %lu", GetLastError());
- _running = false;
- ret = false;
}
}
- _desktop_layout->unlock();
- return ret;
+ return true;
}
bool VDAgent::handle_mon_config(VDAgentMonitorsConfig* mon_config, uint32_t port)
--
2.17.1