From: Conor McCarthy cmccarthy@codeweavers.com
When scaling applies, after a call to SetCursorPos(), a subsequent call to GetCursorPos() may not return the exact coordinates set, which an app may interpret as mouse movement. --- dlls/user32/tests/monitor.c | 2 - dlls/win32u/input.c | 39 +++++---- dlls/win32u/message.c | 30 +++---- dlls/win32u/sysparams.c | 98 ++++++++++++++++++++++ dlls/win32u/win32u_private.h | 2 + include/wine/rational.h | 148 +++++++++++++++++++++++++++++++++ include/wine/server_protocol.h | 25 +++--- server/protocol.def | 21 ++--- server/queue.c | 57 +++++++------ server/request_handlers.h | 27 +++--- server/request_trace.h | 17 ++-- server/trace.c | 9 ++ server/user.h | 6 +- server/window.c | 68 +++++++++++---- server/winstation.c | 4 +- tools/make_requests | 1 + 16 files changed, 432 insertions(+), 122 deletions(-) create mode 100644 include/wine/rational.h
diff --git a/dlls/user32/tests/monitor.c b/dlls/user32/tests/monitor.c index 7ad3970a646..f76971c1b53 100644 --- a/dlls/user32/tests/monitor.c +++ b/dlls/user32/tests/monitor.c @@ -3731,9 +3731,7 @@ static void test_monitor_dpi(void) y = x - infos[i].rect.left + infos[i].rect.top; SetCursorPos(x, y); GetCursorPos(&pt); - todo_wine_if(pt.x != x) ok(pt.x == x, "got x %ld, expected %d.\n", pt.x, x); - todo_wine_if(pt.y != y) ok(pt.y == y, "got y %ld, expected %d.\n", pt.y, y); }
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 59239eb0dd4..ab26f6825fb 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -706,16 +706,18 @@ UINT WINAPI NtUserSendInput( UINT count, INPUT *inputs, int size ) */ BOOL WINAPI NtUserSetCursorPos( INT x, INT y ) { - RECT rect = {x, y, x, y}; + rational_t new_x, new_y; + INT moved; BOOL ret; - INT new_x, new_y, moved;
- rect = map_rect_virt_to_raw( rect, get_thread_dpi() ); + new_x = rational_from_int( x ); + new_y = rational_from_int( y ); + map_rational_point_virt_to_raw( &new_x, &new_y, get_thread_dpi() ); SERVER_START_REQ( set_cursor ) { req->flags = SET_CURSOR_POS; - req->x = rect.left; - req->y = rect.top; + req->x = new_x; + req->y = new_y; if ((ret = !wine_server_call( req ))) { moved = reply->moved; @@ -724,7 +726,7 @@ BOOL WINAPI NtUserSetCursorPos( INT x, INT y ) } } SERVER_END_REQ; - if (ret && moved) user_driver->pSetCursorPos( new_x, new_y ); + if (ret && moved) user_driver->pSetCursorPos( rational_round_to_int( new_x ), rational_round_to_int( new_y ) ); return ret; }
@@ -733,30 +735,39 @@ BOOL WINAPI NtUserSetCursorPos( INT x, INT y ) */ BOOL WINAPI NtUserGetCursorPos( POINT *pt ) { + rational_t x = rational_from_int( 0 ), y = rational_from_int( 0 ); struct object_lock lock = OBJECT_LOCK_INIT; const desktop_shm_t *desktop_shm; BOOL ret = TRUE; DWORD last_change = 0; NTSTATUS status; - RECT rect;
if (!pt) return FALSE;
while ((status = get_shared_desktop( &lock, &desktop_shm )) == STATUS_PENDING) { - pt->x = desktop_shm->cursor.x; - pt->y = desktop_shm->cursor.y; + x = desktop_shm->cursor.x; + y = desktop_shm->cursor.y; last_change = desktop_shm->cursor.last_change; } if (status) return FALSE;
/* query new position from graphics driver if we haven't updated recently */ - if (NtGetTickCount() - last_change > 100) ret = user_driver->pGetCursorPos( pt ); - if (!ret) return FALSE; + if (NtGetTickCount() - last_change > 100) + { + ret = user_driver->pGetCursorPos( pt ); + if (!ret) return FALSE; + /* keep the more accurate rational position if the driver's position matches */ + if (pt->x != rational_round_to_int( x ) || pt->y != rational_round_to_int( y )) + { + x = rational_from_int( pt->x ); + y = rational_from_int( pt->y ); + } + }
- SetRect( &rect, pt->x, pt->y, pt->x, pt->y ); - rect = map_rect_raw_to_virt( rect, get_thread_dpi() ); - *pt = *(POINT *)&rect.left; + map_rational_point_raw_to_virt( &x, &y, get_thread_dpi() ); + pt->x = rational_round_to_int( x ); + pt->y = rational_round_to_int( y ); return ret; }
diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 3147cdd58b0..bdfa3edb8ae 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -2768,10 +2768,9 @@ static BOOL process_mouse_message( MSG *msg, UINT hw_id, ULONG_PTR extra_info, H * Process a hardware message; return TRUE if message should be passed on to the app */ static BOOL process_hardware_message( MSG *msg, UINT hw_id, const struct hardware_msg_data *msg_data, - HWND hwnd_filter, UINT first, UINT last, BOOL remove ) + rational_t x, rational_t y, HWND hwnd_filter, UINT first, UINT last, BOOL remove ) { struct ntuser_thread_info *thread_info = NtUserGetThreadInfo(); - RECT rect = {msg->pt.x, msg->pt.y, msg->pt.x, msg->pt.y}; UINT context; BOOL ret = FALSE;
@@ -2780,9 +2779,9 @@ static BOOL process_hardware_message( MSG *msg, UINT hw_id, const struct hardwar
/* hardware messages are always in raw physical coords */ context = set_thread_dpi_awareness_context( NTUSER_DPI_PER_MONITOR_AWARE ); - rect = map_rect_raw_to_virt( rect, get_thread_dpi() ); - msg->pt.x = rect.left; - msg->pt.y = rect.top; + map_rational_point_raw_to_virt( &x, &y, get_thread_dpi() ); + msg->pt.x = rational_round_to_int( x ); + msg->pt.y = rational_round_to_int( y );
if (msg->message == WM_INPUT || msg->message == WM_INPUT_DEVICE_CHANGE) ret = process_rawinput_message( msg, hw_id, msg_data ); @@ -2854,6 +2853,7 @@ static int peek_message( MSG *msg, const struct peek_message_filter *filter ) unsigned int hw_id = 0; /* id of previous hardware message */ unsigned char buffer_init[1024]; size_t buffer_size = sizeof(buffer_init); + rational_t reply_x, reply_y; void *buffer = buffer_init;
if (!first && !last) last = ~0; @@ -2906,8 +2906,10 @@ static int peek_message( MSG *msg, const struct peek_message_filter *filter ) info.msg.wParam = reply->wparam; info.msg.lParam = reply->lparam; info.msg.time = reply->time; - info.msg.pt.x = reply->x; - info.msg.pt.y = reply->y; + reply_x = reply->x; + reply_y = reply->y; + info.msg.pt.x = rational_round_to_int( reply_x ); + info.msg.pt.y = rational_round_to_int( reply_y ); hw_id = 0; } else buffer_size = reply->total; @@ -3007,12 +3009,11 @@ static int peek_message( MSG *msg, const struct peek_message_filter *filter ) } else if (info.msg.message == WH_MOUSE_LL && size >= sizeof(msg_data->hardware)) { - RECT rect = {info.msg.pt.x, info.msg.pt.y, info.msg.pt.x, info.msg.pt.y}; MSLLHOOKSTRUCT hook;
- rect = map_rect_raw_to_virt( rect, 0 ); - info.msg.pt.x = rect.left; - info.msg.pt.y = rect.top; + map_rational_point_raw_to_virt( &reply_x, &reply_y, 0 ); + info.msg.pt.x = rational_round_to_int( reply_x ); + info.msg.pt.y = rational_round_to_int( reply_y );
hook.pt = info.msg.pt; hook.mouseData = info.msg.lParam; @@ -3047,7 +3048,7 @@ static int peek_message( MSG *msg, const struct peek_message_filter *filter ) if (size >= sizeof(msg_data->hardware)) { hw_id = msg_data->hardware.hw_id; - if (!process_hardware_message( &info.msg, hw_id, &msg_data->hardware, + if (!process_hardware_message( &info.msg, hw_id, &msg_data->hardware, reply_x, reply_y, hwnd, first, last, flags & PM_REMOVE )) { TRACE("dropping msg %x\n", info.msg.message ); @@ -3777,8 +3778,9 @@ LRESULT send_internal_message_timeout( DWORD dest_pid, DWORD dest_tid, NTSTATUS send_hardware_message( HWND hwnd, UINT flags, const INPUT *input, LPARAM lparam ) { struct send_message_info info; - int new_x, new_y, moved; + rational_t new_x, new_y; NTSTATUS ret; + int moved; BOOL wait;
info.type = MSG_HARDWARE; @@ -3858,7 +3860,7 @@ NTSTATUS send_hardware_message( HWND hwnd, UINT flags, const INPUT *input, LPARA SERVER_END_REQ;
if (!ret && (flags & SEND_HWMSG_INJECTED) && moved) - user_driver->pSetCursorPos( new_x, new_y ); + user_driver->pSetCursorPos( rational_round_to_int( new_x ), rational_round_to_int( new_y ) );
if (wait) { diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 13b49a9f12c..30b7af17773 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -1913,6 +1913,76 @@ static UINT monitor_get_dpi( struct monitor *monitor, MONITOR_DPI_TYPE type, UIN return min( *dpi_x, *dpi_y ); }
+/* display_lock must be held */ +static void map_monitor_rational_point( struct monitor *monitor, rational_t *x, rational_t *y, UINT dpi_from, + MONITOR_DPI_TYPE type_from, UINT dpi_to, MONITOR_DPI_TYPE type_to ) +{ + rational_t centre_x_from, centre_y_from, centre_x_to, centre_y_to; + UINT dpi_x, dpi_y; + + assert( type_from != type_to ); + + if (monitor->source) + { + DEVMODEW current_mode = {.dmSize = sizeof(DEVMODEW)}, *mode_from, *mode_to; + UINT num, den, dpi; + + source_get_current_settings( monitor->source, ¤t_mode ); + + dpi = monitor_get_dpi( monitor, MDT_DEFAULT, &dpi_x, &dpi_y ); + if (!dpi_from) dpi_from = dpi; + if (!dpi_to) dpi_to = dpi; + + if (type_from == MDT_RAW_DPI) + { + monitor_virt_to_raw_ratio( monitor, &den, &num ); + mode_from = &monitor->source->physical; + mode_to = ¤t_mode; + } + else + { + monitor_virt_to_raw_ratio( monitor, &num, &den ); + mode_from = ¤t_mode; + mode_to = &monitor->source->physical; + } + + centre_x_to = rational_div( rational_from_int( mode_to->dmPosition.x * 2 + mode_to->dmPelsWidth ), 2 ); + centre_y_to = rational_div( rational_from_int( mode_to->dmPosition.y * 2 + mode_to->dmPelsHeight ), 2 ); + centre_x_from = rational_div( rational_from_int( mode_from->dmPosition.x * 2 + mode_from->dmPelsWidth ), 2 ); + centre_y_from = rational_div( rational_from_int( mode_from->dmPosition.y * 2 + mode_from->dmPelsHeight ), 2 ); + + if (dpi != dpi_from) + { + *x = rational_mul_div_int( *x, dpi, dpi_from ); + *y = rational_mul_div_int( *y, dpi, dpi_from ); + } + *x = rational_sub( *x, centre_x_from ); + *y = rational_sub( *y, centre_y_from ); + if (num != den) + { + *x = rational_mul_div_int( *x, num, den ); + *y = rational_mul_div_int( *y, num, den ); + } + *x = rational_add( *x, centre_x_to ); + *y = rational_add( *y, centre_y_to ); + if (dpi_to != dpi) + { + *x = rational_mul_div_int( *x, dpi_to, dpi ); + *y = rational_mul_div_int( *y, dpi_to, dpi ); + } + + return; + } + + if (!dpi_from) dpi_from = monitor_get_dpi( monitor, type_from, &dpi_x, &dpi_y ); + if (!dpi_to) dpi_to = monitor_get_dpi( monitor, type_to, &dpi_x, &dpi_y ); + if (dpi_from != dpi_to) + { + *x = rational_mul_div_int( *x, dpi_to, dpi_from ); + *y = rational_mul_div_int( *y, dpi_to, dpi_from ); + } +} + /* display_lock must be held */ static RECT map_monitor_rect( struct monitor *monitor, RECT rect, UINT dpi_from, MONITOR_DPI_TYPE type_from, UINT dpi_to, MONITOR_DPI_TYPE type_to ) @@ -2604,6 +2674,20 @@ static RECT monitors_get_union_rect( UINT dpi, MONITOR_DPI_TYPE type ) return rect; }
+/* map a monitor point from MDT_RAW_DPI to MDT_DEFAULT coordinates */ +void map_rational_point_raw_to_virt( rational_t *x, rational_t *y, UINT dpi_to ) +{ + struct monitor *monitor; + RECT pos; + + if (!lock_display_devices( FALSE )) return; + pos.left = pos.right = rational_round_to_int( *x ); + pos.top = pos.bottom = rational_round_to_int( *y ); + if ((monitor = get_monitor_from_rect( pos, MONITOR_DEFAULTTONEAREST, 0, MDT_RAW_DPI ))) + map_monitor_rational_point( monitor, x, y, 0, MDT_RAW_DPI, dpi_to, MDT_DEFAULT ); + unlock_display_devices(); +} + /* map a monitor rect from MDT_RAW_DPI to MDT_DEFAULT coordinates */ RECT map_rect_raw_to_virt( RECT rect, UINT dpi_to ) { @@ -2618,6 +2702,20 @@ RECT map_rect_raw_to_virt( RECT rect, UINT dpi_to ) return rect; }
+/* map a monitor point from MDT_DEFAULT to MDT_RAW_DPI coordinates */ +void map_rational_point_virt_to_raw( rational_t *x, rational_t *y, UINT dpi_from ) +{ + struct monitor *monitor; + RECT pos; + + if (!lock_display_devices( FALSE )) return; + pos.left = pos.right = rational_round_to_int( *x ); + pos.top = pos.bottom = rational_round_to_int( *y ); + if ((monitor = get_monitor_from_rect( pos, MONITOR_DEFAULTTONEAREST, dpi_from, MDT_DEFAULT ))) + map_monitor_rational_point( monitor, x, y, dpi_from, MDT_DEFAULT, 0, MDT_RAW_DPI ); + unlock_display_devices(); +} + /* map a monitor rect from MDT_DEFAULT to MDT_RAW_DPI coordinates */ RECT map_rect_virt_to_raw( RECT rect, UINT dpi_from ) { diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 6eaa7270b01..dd44593d52c 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -174,7 +174,9 @@ extern POINT map_dpi_point( POINT pt, UINT dpi_from, UINT dpi_to ); extern RECT map_dpi_rect( RECT rect, UINT dpi_from, UINT dpi_to ); extern HRGN map_dpi_region( HRGN region, UINT dpi_from, UINT dpi_to ); extern struct window_rects map_dpi_window_rects( struct window_rects rects, UINT dpi_from, UINT dpi_to ); +extern void map_rational_point_raw_to_virt( rational_t *x, rational_t *y, UINT dpi_to ); extern RECT map_rect_raw_to_virt( RECT rect, UINT dpi_to ); +extern void map_rational_point_virt_to_raw( rational_t *x, rational_t *y, UINT dpi_from ); extern RECT map_rect_virt_to_raw( RECT rect, UINT dpi_from ); extern struct window_rects map_window_rects_virt_to_raw( struct window_rects rects, UINT dpi_from ); extern POINT point_phys_to_win_dpi( HWND hwnd, POINT pt ); diff --git a/include/wine/rational.h b/include/wine/rational.h new file mode 100644 index 00000000000..4542ea73707 --- /dev/null +++ b/include/wine/rational.h @@ -0,0 +1,148 @@ +/* + * Rational number type + * + * Copyright (C) 2025 Conor McCarthy for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + * Based on rational.hpp from the Boost library, under the following license: + * (C) Copyright Paul Moore 1999. Permission to copy, use, modify, sell and + * distribute this software is granted provided this copyright notice appears + * in all copies. This software is provided "as is" without express or + * implied warranty, and with no claim as to its suitability for any purpose. + */ + +#ifndef __WINE_WINE_RATIONAL_H +#define __WINE_WINE_RATIONAL_H + +#include "minmax.h" + +typedef struct +{ + int num; + int den; +} rational_t; + +static inline int get_gcd(int a, int b) +{ + int m; + + while (b) + { + m = a % b; + a = b; + b = m; + } + + return a; +} + +static inline rational_t rational_normalise(rational_t r) +{ + if (!r.num) + { + r.den = 1; + } + else + { + int gcd = get_gcd(r.num, r.den); + + r.num /= gcd; + r.den /= gcd; + if (r.den < 0) + { + r.num = -r.num; + r.den = -r.den; + } + } + + return r; +} + +static inline rational_t rational_from_int(int num) +{ + rational_t r = {num, 1}; + return r; +} + +static inline rational_t rational_add_int(rational_t r, int a) +{ + r.num += a * r.den; + return rational_normalise(r); +} + +static inline rational_t rational_sub_int(rational_t r, int a) +{ + r.num -= a * r.den; + return rational_normalise(r); +} + +static inline rational_t rational_min_max_int(rational_t r, int min_i, int max_i) +{ + int min_num = min_i * r.den; + int max_num = max_i * r.den; + r.num = max(min(r.num, min_num), max_num); + return rational_normalise(r); +} + +static inline rational_t rational_add(rational_t r, rational_t a) +{ + /* Converted from the Boost rational addition algorithm written by Nickolay Mladenov. + * For mathematical proof see Boost rational.hpp */ + int g = get_gcd(r.den, a.den); + r.den /= g; + r.num = r.num * (a.den / g) + a.num * r.den; + g = get_gcd(r.num, g); + r.num /= g; + r.den *= a.den/g; + return r; +} + +static inline rational_t rational_sub(rational_t r, rational_t a) +{ + a.num = -a.num; + return rational_add(r, a); +} + +static inline rational_t rational_div(rational_t r, int div) +{ + r.den *= div; + return rational_normalise(r); +} + +static inline rational_t rational_mul_div_int(rational_t r, int num, int den) +{ + r.num *= num; + r.den *= den; + return rational_normalise(r); +} + +static inline int rational_is_equal(rational_t a, rational_t b) +{ + return a.num == b.num && a.den == b.den; +} + +static inline int rational_is_equal_int(rational_t a, int b) +{ + return a.num == b && a.den == 1; +} + +static inline int rational_round_to_int(rational_t r) +{ + int half = (r.num < 0) ? -(r.den >> 1) : r.den >> 1; + return (r.num + half) / r.den; +} + +#endif /* __WINE_WINE_RATIONAL_H */ diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 9cc4939f7f8..b4f9f702ece 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -11,6 +11,7 @@ #include <stdarg.h> #include <stdlib.h> #include <time.h> +#include "rational.h"
#include <windef.h> #include <winbase.h> @@ -979,8 +980,8 @@ struct obj_locator
struct shared_cursor { - int x; - int y; + rational_t x; + rational_t y; unsigned int last_change; struct rectangle clip; }; @@ -3116,8 +3117,8 @@ struct send_hardware_message_reply struct reply_header __header; int wait; int moved; - int new_x; - int new_y; + rational_t new_x; + rational_t new_y; }; #define SEND_HWMSG_INJECTED 0x01
@@ -3144,12 +3145,12 @@ struct get_message_reply lparam_t wparam; lparam_t lparam; int type; - int x; - int y; + rational_t x; + rational_t y; unsigned int time; data_size_t total; /* VARARG(data,message_data); */ - char __pad_52[4]; + char __pad_60[4]; };
@@ -5711,8 +5712,8 @@ struct set_cursor_request unsigned int flags; user_handle_t handle; int show_count; - int x; - int y; + rational_t x; + rational_t y; struct rectangle clip; }; struct set_cursor_reply @@ -5721,8 +5722,8 @@ struct set_cursor_reply user_handle_t prev_handle; int prev_count; int moved; - int new_x; - int new_y; + rational_t new_x; + rational_t new_y; struct rectangle new_clip; unsigned int last_change; }; @@ -7036,6 +7037,6 @@ union generic_reply struct d3dkmt_object_open_name_reply d3dkmt_object_open_name_reply; };
-#define SERVER_PROTOCOL_VERSION 923 +#define SERVER_PROTOCOL_VERSION 924
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/protocol.def b/server/protocol.def index bc886c81e18..5d38aed6a37 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -27,6 +27,7 @@ #include <stdarg.h> #include <stdlib.h> #include <time.h> +#include "rational.h"
#include <windef.h> #include <winbase.h> @@ -995,8 +996,8 @@ struct obj_locator
struct shared_cursor { - int x; /* cursor position */ - int y; + rational_t x; /* cursor position */ + rational_t y; unsigned int last_change; /* time of last position change */ struct rectangle clip; /* cursor clip rectangle */ }; @@ -2377,8 +2378,8 @@ enum message_type @REPLY int wait; /* do we need to wait for a reply? */ int moved; /* previous cursor position != new cursor position */ - int new_x; /* new cursor position */ - int new_y; + rational_t new_x; /* new cursor position */ + rational_t new_y; @END #define SEND_HWMSG_INJECTED 0x01
@@ -2399,8 +2400,8 @@ enum message_type lparam_t wparam; /* parameters */ lparam_t lparam; /* parameters */ int type; /* message type */ - int x; /* message x position */ - int y; /* message y position */ + rational_t x; /* message x position */ + rational_t y; /* message y position */ unsigned int time; /* message time */ data_size_t total; /* total size of extra data */ VARARG(data,message_data); /* message data for sent messages */ @@ -3996,15 +3997,15 @@ struct handle_info unsigned int flags; /* flags for fields to set (see below) */ user_handle_t handle; /* handle to the cursor */ int show_count; /* show count increment/decrement */ - int x; /* cursor position */ - int y; + rational_t x; /* cursor position */ + rational_t y; struct rectangle clip; /* cursor clip rectangle */ @REPLY user_handle_t prev_handle; /* previous handle */ int prev_count; /* previous show count */ int moved; /* previous position != new position */ - int new_x; /* new position */ - int new_y; + rational_t new_x; /* new position */ + rational_t new_y; struct rectangle new_clip; /* new clip rectangle */ unsigned int last_change; /* time of last position change */ @END diff --git a/server/queue.c b/server/queue.c index 2168c3ca117..beac8fca9b2 100644 --- a/server/queue.c +++ b/server/queue.c @@ -85,8 +85,8 @@ struct message unsigned int msg; /* message code */ lparam_t wparam; /* parameters */ lparam_t lparam; /* parameters */ - int x; /* message position */ - int y; + rational_t x; /* message position */ + rational_t y; unsigned int time; /* message time */ void *data; /* message data for sent messages */ unsigned int data_size; /* size of message data */ @@ -540,18 +540,18 @@ static int update_desktop_cursor_window( struct desktop *desktop, user_handle_t return updated; }
-static int update_desktop_cursor_pos( struct desktop *desktop, user_handle_t win, int x, int y ) +static int update_desktop_cursor_pos( struct desktop *desktop, user_handle_t win, rational_t x, rational_t y ) { desktop_shm_t *desktop_shm = desktop->shared; int updated; unsigned int time = get_tick_count();
- x = max( min( x, desktop_shm->cursor.clip.right - 1 ), desktop_shm->cursor.clip.left ); - y = max( min( y, desktop_shm->cursor.clip.bottom - 1 ), desktop_shm->cursor.clip.top ); + x = rational_min_max_int( x, desktop_shm->cursor.clip.right - 1, desktop_shm->cursor.clip.left ); + y = rational_min_max_int( y, desktop_shm->cursor.clip.bottom - 1, desktop_shm->cursor.clip.top );
SHARED_WRITE_BEGIN( desktop_shm, desktop_shm_t ) { - updated = shared->cursor.x != x || shared->cursor.y != y; + updated = !rational_is_equal( shared->cursor.x, x ) || !rational_is_equal( shared->cursor.y, y ); shared->cursor.x = x; shared->cursor.y = y; shared->cursor.last_change = time; @@ -577,7 +577,7 @@ static void update_desktop_cursor_handle( struct desktop *desktop, struct thread }
/* set the cursor position and queue the corresponding mouse message */ -static void set_cursor_pos( struct desktop *desktop, int x, int y ) +static void set_cursor_pos( struct desktop *desktop, rational_t x, rational_t y ) { static const struct hw_msg_source source = { IMDT_UNAVAILABLE, IMO_SYSTEM }; const struct rawinput_device *device; @@ -607,7 +607,7 @@ void update_cursor_pos( struct desktop *desktop ) }
/* retrieve default position and time for synthesized messages */ -static void get_message_defaults( struct msg_queue *queue, int *x, int *y, unsigned int *time ) +static void get_message_defaults( struct msg_queue *queue, rational_t *x, rational_t *y, unsigned int *time ) { struct desktop *desktop = queue->input->desktop; desktop_shm_t *desktop_shm = desktop->shared; @@ -623,7 +623,7 @@ void set_clip_rectangle( struct desktop *desktop, const struct rectangle *rect, desktop_shm_t *desktop_shm = desktop->shared; struct rectangle top_rect, new_rect; unsigned int old_flags; - int x, y; + rational_t x, y;
get_virtual_screen_rect( desktop, &top_rect, 1 ); if (rect) @@ -647,9 +647,9 @@ void set_clip_rectangle( struct desktop *desktop, const struct rectangle *rect, desktop->clip_flags = flags;
/* warp the mouse to be inside the clip rect */ - x = max( min( desktop_shm->cursor.x, new_rect.right - 1 ), new_rect.left ); - y = max( min( desktop_shm->cursor.y, new_rect.bottom - 1 ), new_rect.top ); - if (x != desktop_shm->cursor.x || y != desktop_shm->cursor.y) set_cursor_pos( desktop, x, y ); + x = rational_min_max_int( desktop_shm->cursor.x, new_rect.right - 1, new_rect.left ); + y = rational_min_max_int( desktop_shm->cursor.y, new_rect.bottom - 1, new_rect.top ); + if (!rational_is_equal( x, desktop_shm->cursor.x ) || !rational_is_equal( y, desktop_shm->cursor.y )) set_cursor_pos( desktop, x, y );
/* request clip cursor rectangle reset to the desktop thread */ if (reset) post_desktop_message( desktop, WM_WINE_CLIPCURSOR, flags, FALSE ); @@ -850,7 +850,7 @@ static int merge_mousewheel( struct thread_input *input, const struct message *m int delta;
if (!(prev = find_mouse_message( input, msg ))) return 0; - if (prev->x != msg->x || prev->y != msg->y) return 0; /* don't merge if cursor has moved */ + if (!rational_is_equal( prev->x, msg->x ) || !rational_is_equal( prev->y, msg->y )) return 0; /* don't merge if cursor has moved */
/* accumulate wheel delta */ delta = GET_WHEEL_DELTA_WPARAM(prev->wparam) + GET_WHEEL_DELTA_WPARAM(msg->wparam); @@ -1913,7 +1913,7 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg msg->lparam &= ~(KF_EXTENDED << 16); break; case QS_MOUSEMOVE: - prepend_cursor_history( msg->x, msg->y, msg->time, msg_data->info ); + prepend_cursor_history( rational_round_to_int( msg->x ), rational_round_to_int( msg->y ), msg->time, msg_data->info ); /* fallthrough */ case QS_MOUSEBUTTON: if (update_desktop_cursor_pos( desktop, msg->win, msg->x, msg->y )) always_queue = 1; @@ -2217,7 +2217,8 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons unsigned int i, time = get_tick_count(), flags; struct hw_msg_source source = { IMDT_MOUSE, origin }; lparam_t wparam = input->mouse.data << 16; - int wait = 0, x, y; + rational_t x, y; + int wait = 0;
static const unsigned int messages[] = { @@ -2250,15 +2251,15 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons { if (flags & MOUSEEVENTF_ABSOLUTE) { - x = input->mouse.x; - y = input->mouse.y; + x = rational_from_int( input->mouse.x ); + y = rational_from_int( input->mouse.y ); } else { - x = desktop_shm->cursor.x + input->mouse.x; - y = desktop_shm->cursor.y + input->mouse.y; + x = rational_add_int( desktop_shm->cursor.x, input->mouse.x ); + y = rational_add_int( desktop_shm->cursor.y, input->mouse.y ); } - if (x == desktop_shm->cursor.x && y == desktop_shm->cursor.y) + if (rational_is_equal( x, desktop_shm->cursor.x ) && rational_is_equal( y, desktop_shm->cursor.y )) flags &= ~MOUSEEVENTF_MOVE; } else @@ -2275,7 +2276,9 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons raw_msg.time = time; raw_msg.message = WM_INPUT; raw_msg.flags = flags; - rawmouse_init( &raw_msg.rawinput, &raw_msg.data.mouse, x - desktop_shm->cursor.x, y - desktop_shm->cursor.y, + rawmouse_init( &raw_msg.rawinput, &raw_msg.data.mouse, + rational_round_to_int( rational_sub( x, desktop_shm->cursor.x ) ), + rational_round_to_int( rational_sub( y, desktop_shm->cursor.y ) ), raw_msg.flags, input->mouse.data, input->mouse.info );
dispatch_rawinput_message( desktop, &raw_msg ); @@ -2564,8 +2567,8 @@ static void queue_pointer_message( struct pointer *pointer, int repeated ) msg->msg = message; msg->wparam = 0; msg->lparam = 0; - msg->x = x; - msg->y = y; + msg->x = rational_from_int( x ); + msg->y = rational_from_int( y );
if (!send_hook_ll_message( desktop, msg, WH_MOUSE_LL, 0, NULL )) queue_hardware_message( desktop, msg, 0 ); @@ -3239,7 +3242,7 @@ DECL_HANDLER(send_hardware_message) unsigned int origin = (req->flags & SEND_HWMSG_INJECTED ? IMO_INJECTED : IMO_HARDWARE); struct msg_queue *sender = req->flags & SEND_HWMSG_INJECTED ? get_current_queue() : NULL; desktop_shm_t *desktop_shm; - int prev_x, prev_y; + rational_t prev_x, prev_y; int wait = 0;
if (!(desktop = get_hardware_input_desktop( req->win ))) return; @@ -3273,7 +3276,7 @@ DECL_HANDLER(send_hardware_message) reply->wait = sender ? wait : 0; reply->new_x = desktop_shm->cursor.x; reply->new_y = desktop_shm->cursor.y; - reply->moved = prev_x != reply->new_x || prev_y != reply->new_y; + reply->moved = !rational_is_equal( prev_x, reply->new_x ) || !rational_is_equal( prev_y, reply->new_y ); release_object( desktop ); }
@@ -4012,7 +4015,7 @@ DECL_HANDLER(set_cursor) input_shm_t *input_shm; struct desktop *desktop; desktop_shm_t *desktop_shm; - int prev_x, prev_y; + rational_t prev_x, prev_y;
if (!queue) return; input = queue->input; @@ -4054,7 +4057,7 @@ DECL_HANDLER(set_cursor)
reply->new_x = desktop_shm->cursor.x; reply->new_y = desktop_shm->cursor.y; - reply->moved = prev_x != reply->new_x || prev_y != reply->new_y; + reply->moved = !rational_is_equal( prev_x, reply->new_x ) || !rational_is_equal( prev_y, reply->new_y ); reply->new_clip = desktop_shm->cursor.clip; reply->last_change = desktop_shm->cursor.last_change; } diff --git a/server/request_handlers.h b/server/request_handlers.h index fe0b04897c4..ed19bbad566 100644 --- a/server/request_handlers.h +++ b/server/request_handlers.h @@ -638,6 +638,7 @@ C_ASSERT( sizeof(mod_handle_t) == 8 ); C_ASSERT( sizeof(obj_handle_t) == 4 ); C_ASSERT( sizeof(object_id_t) == 8 ); C_ASSERT( sizeof(process_id_t) == 4 ); +C_ASSERT( sizeof(rational_t) == 8 ); C_ASSERT( sizeof(short int) == 2 ); C_ASSERT( sizeof(struct async_data) == 40 ); C_ASSERT( sizeof(struct context_data) == 1720 ); @@ -1348,8 +1349,8 @@ C_ASSERT( sizeof(struct send_hardware_message_request) == 64 ); C_ASSERT( offsetof(struct send_hardware_message_reply, wait) == 8 ); C_ASSERT( offsetof(struct send_hardware_message_reply, moved) == 12 ); C_ASSERT( offsetof(struct send_hardware_message_reply, new_x) == 16 ); -C_ASSERT( offsetof(struct send_hardware_message_reply, new_y) == 20 ); -C_ASSERT( sizeof(struct send_hardware_message_reply) == 24 ); +C_ASSERT( offsetof(struct send_hardware_message_reply, new_y) == 24 ); +C_ASSERT( sizeof(struct send_hardware_message_reply) == 32 ); C_ASSERT( offsetof(struct get_message_request, flags) == 12 ); C_ASSERT( offsetof(struct get_message_request, get_win) == 16 ); C_ASSERT( offsetof(struct get_message_request, get_first) == 20 ); @@ -1365,10 +1366,10 @@ C_ASSERT( offsetof(struct get_message_reply, wparam) == 16 ); C_ASSERT( offsetof(struct get_message_reply, lparam) == 24 ); C_ASSERT( offsetof(struct get_message_reply, type) == 32 ); C_ASSERT( offsetof(struct get_message_reply, x) == 36 ); -C_ASSERT( offsetof(struct get_message_reply, y) == 40 ); -C_ASSERT( offsetof(struct get_message_reply, time) == 44 ); -C_ASSERT( offsetof(struct get_message_reply, total) == 48 ); -C_ASSERT( sizeof(struct get_message_reply) == 56 ); +C_ASSERT( offsetof(struct get_message_reply, y) == 44 ); +C_ASSERT( offsetof(struct get_message_reply, time) == 52 ); +C_ASSERT( offsetof(struct get_message_reply, total) == 56 ); +C_ASSERT( sizeof(struct get_message_reply) == 64 ); C_ASSERT( offsetof(struct reply_message_request, remove) == 12 ); C_ASSERT( offsetof(struct reply_message_request, result) == 16 ); C_ASSERT( sizeof(struct reply_message_request) == 24 ); @@ -2222,17 +2223,17 @@ C_ASSERT( offsetof(struct set_cursor_request, flags) == 12 ); C_ASSERT( offsetof(struct set_cursor_request, handle) == 16 ); C_ASSERT( offsetof(struct set_cursor_request, show_count) == 20 ); C_ASSERT( offsetof(struct set_cursor_request, x) == 24 ); -C_ASSERT( offsetof(struct set_cursor_request, y) == 28 ); -C_ASSERT( offsetof(struct set_cursor_request, clip) == 32 ); -C_ASSERT( sizeof(struct set_cursor_request) == 48 ); +C_ASSERT( offsetof(struct set_cursor_request, y) == 32 ); +C_ASSERT( offsetof(struct set_cursor_request, clip) == 40 ); +C_ASSERT( sizeof(struct set_cursor_request) == 56 ); C_ASSERT( offsetof(struct set_cursor_reply, prev_handle) == 8 ); C_ASSERT( offsetof(struct set_cursor_reply, prev_count) == 12 ); C_ASSERT( offsetof(struct set_cursor_reply, moved) == 16 ); C_ASSERT( offsetof(struct set_cursor_reply, new_x) == 20 ); -C_ASSERT( offsetof(struct set_cursor_reply, new_y) == 24 ); -C_ASSERT( offsetof(struct set_cursor_reply, new_clip) == 28 ); -C_ASSERT( offsetof(struct set_cursor_reply, last_change) == 44 ); -C_ASSERT( sizeof(struct set_cursor_reply) == 48 ); +C_ASSERT( offsetof(struct set_cursor_reply, new_y) == 28 ); +C_ASSERT( offsetof(struct set_cursor_reply, new_clip) == 36 ); +C_ASSERT( offsetof(struct set_cursor_reply, last_change) == 52 ); +C_ASSERT( sizeof(struct set_cursor_reply) == 56 ); C_ASSERT( sizeof(struct get_cursor_history_request) == 16 ); C_ASSERT( sizeof(struct get_cursor_history_reply) == 8 ); C_ASSERT( offsetof(struct get_rawinput_buffer_request, header_size) == 12 ); diff --git a/server/request_trace.h b/server/request_trace.h index f7aad2c33e8..edee99db80a 100644 --- a/server/request_trace.h +++ b/server/request_trace.h @@ -14,6 +14,7 @@ static void dump_ioctl_code( const char *prefix, const ioctl_code_t *val ); static void dump_irp_params( const char *prefix, const union irp_params *val ); static void dump_luid( const char *prefix, const struct luid *val ); static void dump_obj_locator( const char *prefix, const struct obj_locator *val ); +static void dump_rational( const char *prefix, const rational_t *val ); static void dump_rectangle( const char *prefix, const struct rectangle *val ); static void dump_timeout( const char *prefix, const timeout_t *val ); static void dump_uint64( const char *prefix, const unsigned __int64 *val ); @@ -1444,8 +1445,8 @@ static void dump_send_hardware_message_reply( const struct send_hardware_message { fprintf( stderr, " wait=%d", req->wait ); fprintf( stderr, ", moved=%d", req->moved ); - fprintf( stderr, ", new_x=%d", req->new_x ); - fprintf( stderr, ", new_y=%d", req->new_y ); + dump_rational( ", new_x=", &req->new_x ); + dump_rational( ", new_y=", &req->new_y ); }
static void dump_get_message_request( const struct get_message_request *req ) @@ -1467,8 +1468,8 @@ static void dump_get_message_reply( const struct get_message_reply *req ) dump_uint64( ", wparam=", &req->wparam ); dump_uint64( ", lparam=", &req->lparam ); fprintf( stderr, ", type=%d", req->type ); - fprintf( stderr, ", x=%d", req->x ); - fprintf( stderr, ", y=%d", req->y ); + dump_rational( ", x=", &req->x ); + dump_rational( ", y=", &req->y ); fprintf( stderr, ", time=%08x", req->time ); fprintf( stderr, ", total=%u", req->total ); dump_varargs_message_data( ", data=", cur_size ); @@ -3211,8 +3212,8 @@ static void dump_set_cursor_request( const struct set_cursor_request *req ) fprintf( stderr, " flags=%08x", req->flags ); fprintf( stderr, ", handle=%08x", req->handle ); fprintf( stderr, ", show_count=%d", req->show_count ); - fprintf( stderr, ", x=%d", req->x ); - fprintf( stderr, ", y=%d", req->y ); + dump_rational( ", x=", &req->x ); + dump_rational( ", y=", &req->y ); dump_rectangle( ", clip=", &req->clip ); }
@@ -3221,8 +3222,8 @@ static void dump_set_cursor_reply( const struct set_cursor_reply *req ) fprintf( stderr, " prev_handle=%08x", req->prev_handle ); fprintf( stderr, ", prev_count=%d", req->prev_count ); fprintf( stderr, ", moved=%d", req->moved ); - fprintf( stderr, ", new_x=%d", req->new_x ); - fprintf( stderr, ", new_y=%d", req->new_y ); + dump_rational( ", new_x=", &req->new_x ); + dump_rational( ", new_y=", &req->new_y ); dump_rectangle( ", new_clip=", &req->new_clip ); fprintf( stderr, ", last_change=%08x", req->last_change ); } diff --git a/server/trace.c b/server/trace.c index 8f0f622fb48..10fc9da6b73 100644 --- a/server/trace.c +++ b/server/trace.c @@ -150,6 +150,15 @@ static void dump_uints64( const char *prefix, const unsigned __int64 *ptr, int l fputc( '}', stderr ); }
+static void dump_rational( const char *prefix, const rational_t *val ) +{ + if (val->den > 1) + fprintf( stderr, "%s%d/%u(%d.%03u)", prefix, val->num, val->den, val->num / val->den, + val->num % val->den * 1000 / val->den ); + else + fprintf( stderr, "%s%d", prefix, val->num ); +} + static void dump_rectangle( const char *prefix, const struct rectangle *rect ) { fprintf( stderr, "%s{%d,%d;%d,%d}", prefix, diff --git a/server/user.h b/server/user.h index 73b10aaf5ac..02fd47b53cd 100644 --- a/server/user.h +++ b/server/user.h @@ -168,6 +168,8 @@ extern int rect_in_region( struct region *region, const struct rectangle *rect )
/* window functions */
+extern void map_rational_point_raw_to_virt( struct desktop *desktop, rational_t *x, rational_t *y ); +extern void map_rational_point_virt_to_raw( struct desktop *desktop, rational_t *x, rational_t *y ); extern struct process *get_top_window_owner( struct desktop *desktop ); extern void get_virtual_screen_rect( struct desktop *desktop, struct rectangle *rect, int is_raw ); extern void post_desktop_message( struct desktop *desktop, unsigned int message, @@ -180,8 +182,8 @@ extern int is_window_visible( user_handle_t window ); extern int is_window_transparent( user_handle_t window ); extern int make_window_active( user_handle_t window ); extern struct thread *get_window_thread( user_handle_t handle ); -extern user_handle_t shallow_window_from_point( struct desktop *desktop, int x, int y ); -extern struct thread *window_thread_from_point( user_handle_t scope, int x, int y ); +extern user_handle_t shallow_window_from_point( struct desktop *desktop, rational_t x, rational_t y ); +extern struct thread *window_thread_from_point( user_handle_t scope, rational_t x, rational_t y ); extern user_handle_t find_window_to_repaint( user_handle_t parent, struct thread *thread ); extern struct window_class *get_window_class( user_handle_t window );
diff --git a/server/window.c b/server/window.c index d9a2689ae5a..cc52087c851 100644 --- a/server/window.c +++ b/server/window.c @@ -307,25 +307,54 @@ static struct monitor_info *get_monitor_from_rect( struct winstation *winstation return found ? found : nearest; }
-static void map_point_raw_to_virt( struct desktop *desktop, int *x, int *y ) +static void rect_map_rational_point( const struct rectangle *rect_to, const struct rectangle *rect_from, + rational_t *x, rational_t *y ) { + rational_t centre_x_from, centre_y_from, centre_x_to, centre_y_to; int width_from, height_from, width_to, height_to; - struct rectangle rect = {*x, *y, *x + 1, *y + 1}; + + width_to = rect_to->right - rect_to->left; + height_to = rect_to->bottom - rect_to->top; + width_from = rect_from->right - rect_from->left; + height_from = rect_from->bottom - rect_from->top; + centre_x_to = rational_div( rational_from_int( rect_to->left * 2 + width_to ), 2 ); + centre_y_to = rational_div( rational_from_int( rect_to->top * 2 + height_to ), 2 ); + centre_x_from = rational_div( rational_from_int( rect_from->left * 2 + width_from ), 2 ); + centre_y_from = rational_div( rational_from_int( rect_from->top * 2 + height_from ), 2 ); + + *x = rational_sub( *x, centre_x_from ); + *x = rational_mul_div_int( *x, width_to, width_from ); + *x = rational_add( *x, centre_x_to ); + + *y = rational_sub( *y, centre_y_from ); + *y = rational_mul_div_int( *y, height_to, height_from ); + *y = rational_add( *y, centre_y_to ); +} + +void map_rational_point_raw_to_virt( struct desktop *desktop, rational_t *x, rational_t *y ) +{ struct monitor_info *monitor; + struct rectangle rect;
- if (!(monitor = get_monitor_from_rect( desktop->winstation, &rect, 1 ))) return; - width_to = monitor->virt.right - monitor->virt.left; - height_to = monitor->virt.bottom - monitor->virt.top; - width_from = monitor->raw.right - monitor->raw.left; - height_from = monitor->raw.bottom - monitor->raw.top; + rect.left = rational_round_to_int( *x ); + rect.top = rational_round_to_int( *y ); + rect.right = rect.left + 1; + rect.bottom = rect.top + 1; + if ((monitor = get_monitor_from_rect( desktop->winstation, &rect, 1 ))) + rect_map_rational_point( &monitor->virt, &monitor->raw, x, y); +}
- *x = *x * 2 - (monitor->raw.left * 2 + width_from); - *x = (*x * width_to * 2 + width_from) / (width_from * 2); - *x = (*x + monitor->virt.left * 2 + width_to) / 2; +void map_rational_point_virt_to_raw( struct desktop *desktop, rational_t *x, rational_t *y ) +{ + struct monitor_info *monitor; + struct rectangle rect;
- *y = *y * 2 - (monitor->raw.top * 2 + height_from); - *y = (*y * height_to * 2 + height_from) / (height_from * 2); - *y = (*y + monitor->virt.top * 2 + height_to) / 2; + rect.left = rational_round_to_int( *x ); + rect.top = rational_round_to_int( *y ); + rect.right = rect.left + 1; + rect.bottom = rect.top + 1; + if ((monitor = get_monitor_from_rect( desktop->winstation, &rect, 0 ))) + rect_map_rational_point( &monitor->raw, &monitor->virt, x, y); }
/* get the per-monitor DPI for a window */ @@ -1028,17 +1057,17 @@ static int get_window_children_from_point( struct window *parent, int x, int y, }
/* get handle of root of top-most window containing point (in absolute raw coords) */ -user_handle_t shallow_window_from_point( struct desktop *desktop, int x, int y ) +user_handle_t shallow_window_from_point( struct desktop *desktop, rational_t x, rational_t y ) { struct window *ptr;
if (!desktop->top_window) return 0;
- map_point_raw_to_virt( desktop, &x, &y ); + map_rational_point_raw_to_virt( desktop, &x, &y );
LIST_FOR_EACH_ENTRY( ptr, &desktop->top_window->children, struct window, entry ) { - int x_child = x, y_child = y; + int x_child = rational_round_to_int( x ), y_child = rational_round_to_int( y );
if (!is_point_in_window( ptr, &x_child, &y_child, 0 )) continue; /* skip it */ return ptr->handle; @@ -1047,14 +1076,17 @@ user_handle_t shallow_window_from_point( struct desktop *desktop, int x, int y ) }
/* return thread of top-most window containing point (in absolute raw coords) */ -struct thread *window_thread_from_point( user_handle_t scope, int x, int y ) +struct thread *window_thread_from_point( user_handle_t scope, rational_t r_x, rational_t r_y ) { struct window *win = get_user_object( scope, NTUSER_OBJ_WINDOW ); + int x, y;
if (!win) return NULL;
- map_point_raw_to_virt( win->desktop, &x, &y ); + map_rational_point_raw_to_virt( win->desktop, &r_x, &r_y );
+ x = rational_round_to_int( r_x ); + y = rational_round_to_int( r_y ); screen_to_client( win, &x, &y, 0 ); win = child_window_from_point( win, x, y ); if (!win->thread) return NULL; diff --git a/server/winstation.c b/server/winstation.c index 52c3f1ce1eb..133963abc26 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -317,8 +317,8 @@ static struct desktop *create_desktop( const struct unicode_str *name, unsigned SHARED_WRITE_BEGIN( desktop->shared, desktop_shm_t ) { shared->flags = flags; - shared->cursor.x = 0; - shared->cursor.y = 0; + shared->cursor.x = rational_from_int( 0 ); + shared->cursor.y = rational_from_int( 0 ); shared->cursor.last_change = 0; shared->cursor.clip.left = 0; shared->cursor.clip.top = 0; diff --git a/tools/make_requests b/tools/make_requests index 17e425537b5..99232c66a26 100755 --- a/tools/make_requests +++ b/tools/make_requests @@ -36,6 +36,7 @@ my %formats = "thread_id_t" => [ 4, 4, "%04x" ], "d3dkmt_handle_t"=>[ 4, 4, "%08x" ], "unsigned __int64" => [ 8, 8, "&uint64" ], + "rational_t" => [ 8, 4 ], "timeout_t" => [ 8, 8 ], "abstime_t" => [ 8, 8 ], "ioctl_code_t" => [ 4, 4 ],