include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / server / queue.c
blobee03ceb55c89a156f036ea2010593090aca29760
1 /*
2 * Server-side message queues
4 * Copyright (C) 2000 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
23 #include <assert.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <poll.h>
30 #include "ntstatus.h"
31 #define WIN32_NO_STATUS
32 #include "windef.h"
33 #include "winbase.h"
34 #include "wingdi.h"
35 #include "winuser.h"
36 #include "winternl.h"
37 #include "ntuser.h"
38 #include "hidusage.h"
39 #include "kbd.h"
41 #include "handle.h"
42 #include "file.h"
43 #include "thread.h"
44 #include "process.h"
45 #include "request.h"
46 #include "user.h"
48 #define WM_NCMOUSEFIRST WM_NCMOUSEMOVE
49 #define WM_NCMOUSELAST (WM_NCMOUSEFIRST+(WM_MOUSELAST-WM_MOUSEFIRST))
51 enum message_kind { SEND_MESSAGE, POST_MESSAGE };
52 #define NB_MSG_KINDS (POST_MESSAGE+1)
54 /* list of processes registered for rawinput in the input desktop */
55 static struct list rawinput_processes = LIST_INIT(rawinput_processes);
57 struct message_result
59 struct list sender_entry; /* entry in sender list */
60 struct message *msg; /* message the result is for */
61 struct message_result *recv_next; /* next in receiver list */
62 struct msg_queue *sender; /* sender queue */
63 struct msg_queue *receiver; /* receiver queue */
64 int replied; /* has it been replied to? */
65 unsigned int error; /* error code to pass back to sender */
66 lparam_t result; /* reply result */
67 struct message *hardware_msg; /* hardware message if low-level hook result */
68 struct desktop *desktop; /* desktop for hardware message */
69 struct message *callback_msg; /* message to queue for callback */
70 void *data; /* message reply data */
71 unsigned int data_size; /* size of message reply data */
72 struct timeout_user *timeout; /* result timeout */
75 struct message
77 struct list entry; /* entry in message list */
78 enum message_type type; /* message type */
79 user_handle_t win; /* window handle */
80 unsigned int msg; /* message code */
81 lparam_t wparam; /* parameters */
82 lparam_t lparam; /* parameters */
83 int x; /* message position */
84 int y;
85 unsigned int time; /* message time */
86 void *data; /* message data for sent messages */
87 unsigned int data_size; /* size of message data */
88 unsigned int unique_id; /* unique id for nested hw message waits */
89 struct message_result *result; /* result in sender queue */
92 struct timer
94 struct list entry; /* entry in timer list */
95 abstime_t when; /* next expiration */
96 unsigned int rate; /* timer rate in ms */
97 user_handle_t win; /* window handle */
98 unsigned int msg; /* message to post */
99 lparam_t id; /* timer id */
100 lparam_t lparam; /* lparam for message */
103 struct thread_input
105 struct object obj; /* object header */
106 struct desktop *desktop; /* desktop that this thread input belongs to */
107 int caret_hide; /* caret hide count */
108 int caret_state; /* caret on/off state */
109 struct list msg_list; /* list of hardware messages */
110 unsigned char keystate[256]; /* state of each key */
111 unsigned char desktop_keystate[256]; /* desktop keystate when keystate was synced */
112 int keystate_lock; /* keystate is locked */
113 const input_shm_t *shared; /* thread input in session shared memory */
116 struct msg_queue
118 struct object obj; /* object header */
119 struct fd *fd; /* optional file descriptor to poll */
120 int paint_count; /* pending paint messages count */
121 int hotkey_count; /* pending hotkey messages count */
122 int quit_message; /* is there a pending quit message? */
123 int exit_code; /* exit code of pending quit message */
124 int cursor_count; /* per-queue cursor show count */
125 struct list msg_list[NB_MSG_KINDS]; /* lists of messages */
126 struct list send_result; /* stack of sent messages waiting for result */
127 struct list callback_result; /* list of callback messages waiting for result */
128 struct message_result *recv_result; /* stack of received messages waiting for result */
129 struct list pending_timers; /* list of pending timers */
130 struct list expired_timers; /* list of expired timers */
131 lparam_t next_timer_id; /* id for the next timer with a 0 window */
132 struct timeout_user *timeout; /* timeout for next timer to expire */
133 struct thread_input *input; /* thread input descriptor */
134 struct hook_table *hooks; /* hook table */
135 timeout_t last_get_msg; /* time of last get message call */
136 int keystate_lock; /* owns an input keystate lock */
137 const queue_shm_t *shared; /* queue in session shared memory */
140 struct hotkey
142 struct list entry; /* entry in desktop hotkey list */
143 struct msg_queue *queue; /* queue owning this hotkey */
144 user_handle_t win; /* window handle */
145 int id; /* hotkey id */
146 unsigned int vkey; /* virtual key code */
147 unsigned int flags; /* key modifiers */
150 static void msg_queue_dump( struct object *obj, int verbose );
151 static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *entry );
152 static void msg_queue_remove_queue( struct object *obj, struct wait_queue_entry *entry );
153 static int msg_queue_signaled( struct object *obj, struct wait_queue_entry *entry );
154 static void msg_queue_satisfied( struct object *obj, struct wait_queue_entry *entry );
155 static void msg_queue_destroy( struct object *obj );
156 static void msg_queue_poll_event( struct fd *fd, int event );
157 static void thread_input_dump( struct object *obj, int verbose );
158 static void thread_input_destroy( struct object *obj );
159 static void timer_callback( void *private );
161 static const struct object_ops msg_queue_ops =
163 sizeof(struct msg_queue), /* size */
164 &no_type, /* type */
165 msg_queue_dump, /* dump */
166 msg_queue_add_queue, /* add_queue */
167 msg_queue_remove_queue, /* remove_queue */
168 msg_queue_signaled, /* signaled */
169 msg_queue_satisfied, /* satisfied */
170 no_signal, /* signal */
171 no_get_fd, /* get_fd */
172 default_map_access, /* map_access */
173 default_get_sd, /* get_sd */
174 default_set_sd, /* set_sd */
175 no_get_full_name, /* get_full_name */
176 no_lookup_name, /* lookup_name */
177 no_link_name, /* link_name */
178 NULL, /* unlink_name */
179 no_open_file, /* open_file */
180 no_kernel_obj_list, /* get_kernel_obj_list */
181 no_close_handle, /* close_handle */
182 msg_queue_destroy /* destroy */
185 static const struct fd_ops msg_queue_fd_ops =
187 NULL, /* get_poll_events */
188 msg_queue_poll_event, /* poll_event */
189 NULL, /* flush */
190 NULL, /* get_fd_type */
191 NULL, /* ioctl */
192 NULL, /* queue_async */
193 NULL, /* reselect_async */
194 NULL /* cancel async */
198 static const struct object_ops thread_input_ops =
200 sizeof(struct thread_input), /* size */
201 &no_type, /* type */
202 thread_input_dump, /* dump */
203 no_add_queue, /* add_queue */
204 NULL, /* remove_queue */
205 NULL, /* signaled */
206 NULL, /* satisfied */
207 no_signal, /* signal */
208 no_get_fd, /* get_fd */
209 default_map_access, /* map_access */
210 default_get_sd, /* get_sd */
211 default_set_sd, /* set_sd */
212 no_get_full_name, /* get_full_name */
213 no_lookup_name, /* lookup_name */
214 no_link_name, /* link_name */
215 NULL, /* unlink_name */
216 no_open_file, /* open_file */
217 no_kernel_obj_list, /* get_kernel_obj_list */
218 no_close_handle, /* close_handle */
219 thread_input_destroy /* destroy */
222 /* pointer to input structure of foreground thread */
223 static unsigned int last_input_time;
225 static cursor_pos_t cursor_history[64];
226 static unsigned int cursor_history_latest;
228 static void queue_hardware_message( struct desktop *desktop, struct message *msg, int always_queue );
229 static void free_message( struct message *msg );
231 /* set the caret window in a given thread input, requires write lock on the thread input shared member */
232 static void set_caret_window( struct thread_input *input, input_shm_t *shared, user_handle_t win )
234 if (!win || win != shared->caret)
236 shared->caret_rect.left = 0;
237 shared->caret_rect.top = 0;
238 shared->caret_rect.right = 0;
239 shared->caret_rect.bottom = 0;
241 shared->caret = win;
242 input->caret_hide = 1;
243 input->caret_state = 0;
246 /* create a thread input object */
247 static struct thread_input *create_thread_input( struct thread *thread )
249 struct thread_input *input;
251 if ((input = alloc_object( &thread_input_ops )))
253 list_init( &input->msg_list );
254 memset( input->keystate, 0, sizeof(input->keystate) );
255 input->keystate_lock = 0;
256 input->shared = NULL;
258 if (!(input->desktop = get_thread_desktop( thread, 0 /* FIXME: access rights */ )))
260 release_object( input );
261 return NULL;
263 memcpy( input->desktop_keystate, (const void *)input->desktop->shared->keystate,
264 sizeof(input->desktop_keystate) );
266 if (!(input->shared = alloc_shared_object()))
268 release_object( input );
269 return NULL;
272 SHARED_WRITE_BEGIN( input->shared, input_shm_t )
274 shared->foreground = 0;
275 shared->active = 0;
276 shared->focus = 0;
277 shared->capture = 0;
278 shared->menu_owner = 0;
279 shared->move_size = 0;
280 set_caret_window( input, shared, 0 );
281 shared->cursor = 0;
282 shared->cursor_count = 0;
284 SHARED_WRITE_END;
286 return input;
289 /* create a message queue object */
290 static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_input *input )
292 struct thread_input *new_input = NULL;
293 struct msg_queue *queue;
294 struct desktop *desktop;
295 int i;
297 if (!input)
299 if (!(new_input = create_thread_input( thread ))) return NULL;
300 input = new_input;
303 if ((queue = alloc_object( &msg_queue_ops )))
305 queue->fd = NULL;
306 queue->paint_count = 0;
307 queue->hotkey_count = 0;
308 queue->quit_message = 0;
309 queue->cursor_count = 0;
310 queue->recv_result = NULL;
311 queue->next_timer_id = 0x7fff;
312 queue->timeout = NULL;
313 queue->input = (struct thread_input *)grab_object( input );
314 queue->hooks = NULL;
315 queue->last_get_msg = current_time;
316 queue->keystate_lock = 0;
317 list_init( &queue->send_result );
318 list_init( &queue->callback_result );
319 list_init( &queue->pending_timers );
320 list_init( &queue->expired_timers );
321 for (i = 0; i < NB_MSG_KINDS; i++) list_init( &queue->msg_list[i] );
323 if (!(queue->shared = alloc_shared_object()))
325 release_object( queue );
326 return NULL;
329 SHARED_WRITE_BEGIN( queue->shared, queue_shm_t )
331 memset( (void *)shared->hooks_count, 0, sizeof(shared->hooks_count) );
332 shared->wake_mask = 0;
333 shared->wake_bits = 0;
334 shared->changed_mask = 0;
335 shared->changed_bits = 0;
337 SHARED_WRITE_END;
339 thread->queue = queue;
341 if ((desktop = get_thread_desktop( thread, 0 )))
343 add_desktop_hook_count( desktop, thread, 1 );
344 release_object( desktop );
347 if (new_input) release_object( new_input );
348 return queue;
351 /* free the message queue of a thread at thread exit */
352 void free_msg_queue( struct thread *thread )
354 remove_thread_hooks( thread );
355 if (!thread->queue) return;
356 release_object( thread->queue );
357 thread->queue = NULL;
360 /* synchronize thread input keystate with the desktop */
361 static void sync_input_keystate( struct thread_input *input )
363 const desktop_shm_t *desktop_shm;
364 int i;
366 if (!input->desktop || input->keystate_lock) return;
367 desktop_shm = input->desktop->shared;
369 for (i = 0; i < sizeof(input->keystate); ++i)
371 if (input->desktop_keystate[i] == desktop_shm->keystate[i]) continue;
372 input->keystate[i] = input->desktop_keystate[i] = desktop_shm->keystate[i];
376 /* locks thread input keystate to prevent synchronization */
377 static void lock_input_keystate( struct thread_input *input )
379 input->keystate_lock++;
382 /* unlock the thread input keystate and synchronize it again */
383 static void unlock_input_keystate( struct thread_input *input )
385 input->keystate_lock--;
386 if (!input->keystate_lock) sync_input_keystate( input );
389 /* change the thread input data of a given thread */
390 static int assign_thread_input( struct thread *thread, struct thread_input *new_input )
392 struct msg_queue *queue = thread->queue;
393 const input_shm_t *input_shm;
395 if (!queue)
397 thread->queue = create_msg_queue( thread, new_input );
398 return thread->queue != NULL;
400 if (queue->input)
402 input_shm = queue->input->shared;
404 SHARED_WRITE_BEGIN( input_shm, input_shm_t )
406 shared->cursor_count -= queue->cursor_count;
408 SHARED_WRITE_END;
410 if (queue->keystate_lock) unlock_input_keystate( queue->input );
412 /* invalidate the old object to force clients to refresh their cached thread input */
413 invalidate_shared_object( queue->input->shared );
414 release_object( queue->input );
416 queue->input = (struct thread_input *)grab_object( new_input );
417 if (queue->keystate_lock) lock_input_keystate( queue->input );
419 input_shm = new_input->shared;
420 SHARED_WRITE_BEGIN( input_shm, input_shm_t )
422 shared->cursor_count += queue->cursor_count;
424 SHARED_WRITE_END;
426 return 1;
429 /* allocate a hardware message and its data */
430 static struct message *alloc_hardware_message( lparam_t info, struct hw_msg_source source,
431 unsigned int time, data_size_t extra_size )
433 struct hardware_msg_data *msg_data;
434 struct message *msg;
436 if (!(msg = mem_alloc( sizeof(*msg) ))) return NULL;
437 if (!(msg_data = mem_alloc( sizeof(*msg_data) + extra_size )))
439 free( msg );
440 return NULL;
442 memset( msg, 0, sizeof(*msg) );
443 msg->type = MSG_HARDWARE;
444 msg->time = time;
445 msg->data = msg_data;
446 msg->data_size = sizeof(*msg_data) + extra_size;
448 memset( msg_data, 0, sizeof(*msg_data) + extra_size );
449 msg_data->info = info;
450 msg_data->size = msg->data_size;
451 msg_data->source = source;
452 return msg;
455 static int is_cursor_clipped( struct desktop *desktop )
457 const desktop_shm_t *desktop_shm = desktop->shared;
458 rectangle_t top_rect, clip_rect = desktop_shm->cursor.clip;
459 get_top_window_rectangle( desktop, &top_rect );
460 return !is_rect_equal( &clip_rect, &top_rect );
463 static void queue_cursor_message( struct desktop *desktop, user_handle_t win, unsigned int message,
464 lparam_t wparam, lparam_t lparam )
466 static const struct hw_msg_source source = { IMDT_UNAVAILABLE, IMO_SYSTEM };
467 const desktop_shm_t *desktop_shm = desktop->shared;
468 struct thread_input *input;
469 struct message *msg;
471 if (!(msg = alloc_hardware_message( 0, source, get_tick_count(), 0 ))) return;
473 msg->msg = message;
474 msg->wparam = wparam;
475 msg->lparam = lparam;
476 msg->x = desktop_shm->cursor.x;
477 msg->y = desktop_shm->cursor.y;
478 if (!(msg->win = win) && (input = desktop->foreground_input)) msg->win = input->shared->active;
479 queue_hardware_message( desktop, msg, 1 );
482 static struct thread_input *get_desktop_cursor_thread_input( struct desktop *desktop )
484 struct thread_input *input = NULL;
485 struct thread *thread;
487 if ((thread = get_window_thread( desktop->cursor_win )))
489 if (thread->queue) input = thread->queue->input;
490 release_object( thread );
493 return input;
496 static int update_desktop_cursor_window( struct desktop *desktop, user_handle_t win )
498 int updated = win != desktop->cursor_win;
499 struct thread_input *input;
500 desktop->cursor_win = win;
502 if (updated && (input = get_desktop_cursor_thread_input( desktop )))
504 const input_shm_t *input_shm = input->shared;
505 user_handle_t handle = input_shm->cursor_count < 0 ? 0 : input_shm->cursor;
506 /* when clipping send the message to the foreground window as well, as some driver have an artificial overlay window */
507 if (is_cursor_clipped( desktop )) queue_cursor_message( desktop, 0, WM_WINE_SETCURSOR, win, handle );
508 queue_cursor_message( desktop, win, WM_WINE_SETCURSOR, win, handle );
511 return updated;
514 static int update_desktop_cursor_pos( struct desktop *desktop, user_handle_t win, int x, int y )
516 const desktop_shm_t *desktop_shm = desktop->shared;
517 int updated;
518 unsigned int time = get_tick_count();
520 x = max( min( x, desktop_shm->cursor.clip.right - 1 ), desktop_shm->cursor.clip.left );
521 y = max( min( y, desktop_shm->cursor.clip.bottom - 1 ), desktop_shm->cursor.clip.top );
523 SHARED_WRITE_BEGIN( desktop_shm, desktop_shm_t )
525 updated = shared->cursor.x != x || shared->cursor.y != y;
526 shared->cursor.x = x;
527 shared->cursor.y = y;
528 shared->cursor.last_change = time;
530 SHARED_WRITE_END;
532 if (!win || !is_window_visible( win ) || is_window_transparent( win ))
533 win = shallow_window_from_point( desktop, x, y );
534 if (update_desktop_cursor_window( desktop, win )) updated = 1;
536 return updated;
539 static void update_desktop_cursor_handle( struct desktop *desktop, struct thread_input *input, user_handle_t handle )
541 if (input == get_desktop_cursor_thread_input( desktop ))
543 user_handle_t win = desktop->cursor_win;
544 /* when clipping send the message to the foreground window as well, as some driver have an artificial overlay window */
545 if (is_cursor_clipped( desktop )) queue_cursor_message( desktop, 0, WM_WINE_SETCURSOR, win, handle );
546 queue_cursor_message( desktop, win, WM_WINE_SETCURSOR, win, handle );
550 /* set the cursor position and queue the corresponding mouse message */
551 static void set_cursor_pos( struct desktop *desktop, int x, int y )
553 static const struct hw_msg_source source = { IMDT_UNAVAILABLE, IMO_SYSTEM };
554 const struct rawinput_device *device;
555 struct message *msg;
557 if ((device = current->process->rawinput_mouse) && (device->flags & RIDEV_NOLEGACY))
559 update_desktop_cursor_pos( desktop, 0, x, y );
560 return;
563 if (!(msg = alloc_hardware_message( 0, source, get_tick_count(), 0 ))) return;
565 msg->msg = WM_MOUSEMOVE;
566 msg->x = x;
567 msg->y = y;
568 queue_hardware_message( desktop, msg, 1 );
571 /* retrieve default position and time for synthesized messages */
572 static void get_message_defaults( struct msg_queue *queue, int *x, int *y, unsigned int *time )
574 struct desktop *desktop = queue->input->desktop;
575 const desktop_shm_t *desktop_shm = desktop->shared;
577 *x = desktop_shm->cursor.x;
578 *y = desktop_shm->cursor.y;
579 *time = get_tick_count();
582 /* set the cursor clip rectangle */
583 void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, unsigned int flags, int reset )
585 const desktop_shm_t *desktop_shm = desktop->shared;
586 rectangle_t top_rect, new_rect;
587 unsigned int old_flags;
588 int x, y;
590 get_top_window_rectangle( desktop, &top_rect );
591 if (rect)
593 new_rect = *rect;
594 if (new_rect.left < top_rect.left) new_rect.left = top_rect.left;
595 if (new_rect.right > top_rect.right) new_rect.right = top_rect.right;
596 if (new_rect.top < top_rect.top) new_rect.top = top_rect.top;
597 if (new_rect.bottom > top_rect.bottom) new_rect.bottom = top_rect.bottom;
598 if (new_rect.left > new_rect.right || new_rect.top > new_rect.bottom) new_rect = top_rect;
600 else new_rect = top_rect;
602 SHARED_WRITE_BEGIN( desktop_shm, desktop_shm_t )
604 shared->cursor.clip = new_rect;
606 SHARED_WRITE_END;
608 old_flags = desktop->clip_flags;
609 desktop->clip_flags = flags;
611 /* warp the mouse to be inside the clip rect */
612 x = max( min( desktop_shm->cursor.x, new_rect.right - 1 ), new_rect.left );
613 y = max( min( desktop_shm->cursor.y, new_rect.bottom - 1 ), new_rect.top );
614 if (x != desktop_shm->cursor.x || y != desktop_shm->cursor.y) set_cursor_pos( desktop, x, y );
616 /* request clip cursor rectangle reset to the desktop thread */
617 if (reset) post_desktop_message( desktop, WM_WINE_CLIPCURSOR, flags, FALSE );
619 /* notify foreground thread of reset, clipped, or released cursor rect */
620 if (reset || flags != SET_CURSOR_NOCLIP || old_flags != SET_CURSOR_NOCLIP)
621 queue_cursor_message( desktop, 0, WM_WINE_CLIPCURSOR, flags, reset );
624 /* change the foreground input and reset the cursor clip rect */
625 static void set_foreground_input( struct desktop *desktop, struct thread_input *input )
627 const input_shm_t *input_shm, *old_input_shm;
628 shared_object_t dummy_obj = {0};
630 if (desktop->foreground_input == input) return;
631 input_shm = input ? input->shared : &dummy_obj.shm.input;
632 old_input_shm = desktop->foreground_input ? desktop->foreground_input->shared : &dummy_obj.shm.input;
634 set_clip_rectangle( desktop, NULL, SET_CURSOR_NOCLIP, 1 );
635 desktop->foreground_input = input;
637 SHARED_WRITE_BEGIN( old_input_shm, input_shm_t )
639 input_shm_t *old_shared = shared;
640 SHARED_WRITE_BEGIN( input_shm, input_shm_t )
642 old_shared->foreground = 0;
643 shared->foreground = 1;
645 SHARED_WRITE_END;
647 SHARED_WRITE_END;
650 /* get the hook table for a given thread */
651 struct hook_table *get_queue_hooks( struct thread *thread )
653 if (!thread->queue) return NULL;
654 return thread->queue->hooks;
657 /* set the hook table for a given thread, allocating the queue if needed */
658 void set_queue_hooks( struct thread *thread, struct hook_table *hooks )
660 struct msg_queue *queue = thread->queue;
661 if (!queue && !(queue = create_msg_queue( thread, NULL ))) return;
662 if (queue->hooks) release_object( queue->hooks );
663 queue->hooks = hooks;
666 /* update the thread message queue hooks counters */
667 void add_queue_hook_count( struct thread *thread, unsigned int index, int count )
669 if (!thread->queue) return;
671 SHARED_WRITE_BEGIN( thread->queue->shared, queue_shm_t )
673 shared->hooks_count[index] += count;
675 SHARED_WRITE_END;
677 assert( thread->queue->shared->hooks_count[index] >= 0 );
680 /* check the queue status */
681 static inline int is_signaled( struct msg_queue *queue )
683 const queue_shm_t *queue_shm = queue->shared;
684 return (queue_shm->wake_bits & queue_shm->wake_mask) ||
685 (queue_shm->changed_bits & queue_shm->changed_mask);
688 /* set some queue bits */
689 static inline void set_queue_bits( struct msg_queue *queue, unsigned int bits )
691 const queue_shm_t *queue_shm = queue->shared;
693 if (bits & (QS_KEY | QS_MOUSEBUTTON))
695 if (!queue->keystate_lock) lock_input_keystate( queue->input );
696 queue->keystate_lock = 1;
699 SHARED_WRITE_BEGIN( queue_shm, queue_shm_t )
701 shared->wake_bits |= bits;
702 shared->changed_bits |= bits;
704 SHARED_WRITE_END;
706 if (is_signaled( queue )) wake_up( &queue->obj, 0 );
709 /* clear some queue bits */
710 static inline void clear_queue_bits( struct msg_queue *queue, unsigned int bits )
712 const queue_shm_t *queue_shm = queue->shared;
714 SHARED_WRITE_BEGIN( queue_shm, queue_shm_t )
716 shared->wake_bits &= ~bits;
717 shared->changed_bits &= ~bits;
719 SHARED_WRITE_END;
721 if (!(queue_shm->wake_bits & (QS_KEY | QS_MOUSEBUTTON)))
723 if (queue->keystate_lock) unlock_input_keystate( queue->input );
724 queue->keystate_lock = 0;
728 /* check if message is matched by the filter */
729 static inline int check_msg_filter( unsigned int msg, unsigned int first, unsigned int last )
731 return (msg >= first && msg <= last);
734 /* check whether a message filter contains at least one potential hardware message */
735 static inline int filter_contains_hw_range( unsigned int first, unsigned int last )
737 /* hardware message ranges are (in numerical order):
738 * WM_NCMOUSEFIRST .. WM_NCMOUSELAST
739 * WM_INPUT_DEVICE_CHANGE .. WM_KEYLAST
740 * WM_MOUSEFIRST .. WM_MOUSELAST
742 if (last < WM_NCMOUSEFIRST) return 0;
743 if (first > WM_NCMOUSELAST && last < WM_INPUT_DEVICE_CHANGE) return 0;
744 if (first > WM_KEYLAST && last < WM_MOUSEFIRST) return 0;
745 if (first > WM_MOUSELAST) return 0;
746 return 1;
749 /* get the QS_* bit corresponding to a given hardware message */
750 static inline int get_hardware_msg_bit( unsigned int message )
752 if (message >= WM_POINTERUPDATE && message <= WM_POINTERLEAVE) return QS_POINTER;
753 if (message == WM_INPUT_DEVICE_CHANGE || message == WM_INPUT) return QS_RAWINPUT;
754 if (message == WM_MOUSEMOVE || message == WM_NCMOUSEMOVE) return QS_MOUSEMOVE;
755 if (message >= WM_KEYFIRST && message <= WM_KEYLAST) return QS_KEY;
756 if (message == WM_WINE_CLIPCURSOR) return QS_RAWINPUT;
757 if (message == WM_WINE_SETCURSOR) return QS_RAWINPUT;
758 return QS_MOUSEBUTTON;
761 /* get the current thread queue, creating it if needed */
762 static inline struct msg_queue *get_current_queue(void)
764 struct msg_queue *queue = current->queue;
765 if (!queue) queue = create_msg_queue( current, NULL );
766 return queue;
769 /* get a (pseudo-)unique id to tag hardware messages */
770 static inline unsigned int get_unique_id(void)
772 static unsigned int id;
773 if (!++id) id = 1; /* avoid an id of 0 */
774 return id;
777 /* try to merge a WM_MOUSEMOVE message with the last in the list; return 1 if successful */
778 static int merge_mousemove( struct thread_input *input, const struct message *msg )
780 struct message *prev;
781 struct list *ptr;
783 for (ptr = list_tail( &input->msg_list ); ptr; ptr = list_prev( &input->msg_list, ptr ))
785 prev = LIST_ENTRY( ptr, struct message, entry );
786 if (prev->msg != WM_INPUT) break;
788 if (!ptr) return 0;
789 if (prev->result) return 0;
790 if (prev->win && msg->win && prev->win != msg->win) return 0;
791 if (prev->msg != msg->msg) return 0;
792 if (prev->type != msg->type) return 0;
793 /* now we can merge it */
794 prev->wparam = msg->wparam;
795 prev->lparam = msg->lparam;
796 prev->x = msg->x;
797 prev->y = msg->y;
798 prev->time = msg->time;
799 if (msg->type == MSG_HARDWARE && prev->data && msg->data)
801 struct hardware_msg_data *prev_data = prev->data;
802 struct hardware_msg_data *msg_data = msg->data;
803 prev_data->info = msg_data->info;
805 list_remove( ptr );
806 list_add_tail( &input->msg_list, ptr );
807 return 1;
810 /* try to merge a unique message with the last in the list; return 1 if successful */
811 static int merge_unique_message( struct thread_input *input, unsigned int message, const struct message *msg )
813 struct message *prev;
815 LIST_FOR_EACH_ENTRY_REV( prev, &input->msg_list, struct message, entry )
816 if (prev->msg == message) break;
817 if (&prev->entry == &input->msg_list) return 0;
819 if (prev->result) return 0;
820 if (prev->win != msg->win) return 0;
821 if (prev->type != msg->type) return 0;
823 /* now we can merge it */
824 prev->wparam = msg->wparam;
825 prev->lparam = msg->lparam;
826 prev->x = msg->x;
827 prev->y = msg->y;
828 prev->time = msg->time;
829 list_remove( &prev->entry );
830 list_add_tail( &input->msg_list, &prev->entry );
832 return 1;
835 /* try to merge a message with the messages in the list; return 1 if successful */
836 static int merge_message( struct thread_input *input, const struct message *msg )
838 if (msg->msg == WM_MOUSEMOVE) return merge_mousemove( input, msg );
839 if (msg->msg == WM_WINE_CLIPCURSOR) return merge_unique_message( input, WM_WINE_CLIPCURSOR, msg );
840 if (msg->msg == WM_WINE_SETCURSOR) return merge_unique_message( input, WM_WINE_SETCURSOR, msg );
841 return 0;
844 /* free a result structure */
845 static void free_result( struct message_result *result )
847 if (result->timeout) remove_timeout_user( result->timeout );
848 free( result->data );
849 if (result->callback_msg) free_message( result->callback_msg );
850 if (result->hardware_msg) free_message( result->hardware_msg );
851 if (result->desktop) release_object( result->desktop );
852 free( result );
855 /* remove the result from the sender list it is on */
856 static inline void remove_result_from_sender( struct message_result *result )
858 assert( result->sender );
860 list_remove( &result->sender_entry );
861 result->sender = NULL;
862 if (!result->receiver) free_result( result );
865 /* store the message result in the appropriate structure */
866 static void store_message_result( struct message_result *res, lparam_t result, unsigned int error )
868 res->result = result;
869 res->error = error;
870 res->replied = 1;
871 if (res->timeout)
873 remove_timeout_user( res->timeout );
874 res->timeout = NULL;
877 if (res->hardware_msg)
879 if (!error && result) /* rejected by the hook */
880 free_message( res->hardware_msg );
881 else
882 queue_hardware_message( res->desktop, res->hardware_msg, 0 );
884 res->hardware_msg = NULL;
887 if (res->sender)
889 if (res->callback_msg)
891 /* queue the callback message in the sender queue */
892 struct callback_msg_data *data = res->callback_msg->data;
893 data->result = result;
894 list_add_tail( &res->sender->msg_list[SEND_MESSAGE], &res->callback_msg->entry );
895 set_queue_bits( res->sender, QS_SENDMESSAGE );
896 res->callback_msg = NULL;
897 remove_result_from_sender( res );
899 else
901 /* wake sender queue if waiting on this result */
902 if (list_head(&res->sender->send_result) == &res->sender_entry)
903 set_queue_bits( res->sender, QS_SMRESULT );
906 else if (!res->receiver) free_result( res );
909 /* free a message when deleting a queue or window */
910 static void free_message( struct message *msg )
912 struct message_result *result = msg->result;
913 if (result)
915 result->msg = NULL;
916 result->receiver = NULL;
917 store_message_result( result, 0, STATUS_ACCESS_DENIED /*FIXME*/ );
919 free( msg->data );
920 free( msg );
923 /* remove (and free) a message from a message list */
924 static void remove_queue_message( struct msg_queue *queue, struct message *msg,
925 enum message_kind kind )
927 list_remove( &msg->entry );
928 switch(kind)
930 case SEND_MESSAGE:
931 if (list_empty( &queue->msg_list[kind] )) clear_queue_bits( queue, QS_SENDMESSAGE );
932 break;
933 case POST_MESSAGE:
934 if (list_empty( &queue->msg_list[kind] ) && !queue->quit_message)
935 clear_queue_bits( queue, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE );
936 if (msg->msg == WM_HOTKEY && --queue->hotkey_count == 0)
937 clear_queue_bits( queue, QS_HOTKEY );
938 break;
940 free_message( msg );
943 /* message timed out without getting a reply */
944 static void result_timeout( void *private )
946 struct message_result *result = private;
948 assert( !result->replied );
950 result->timeout = NULL;
952 if (result->msg) /* not received yet */
954 struct message *msg = result->msg;
956 result->msg = NULL;
957 msg->result = NULL;
958 remove_queue_message( result->receiver, msg, SEND_MESSAGE );
959 result->receiver = NULL;
961 store_message_result( result, 0, STATUS_TIMEOUT );
964 /* allocate and fill a message result structure */
965 static struct message_result *alloc_message_result( struct msg_queue *send_queue,
966 struct msg_queue *recv_queue,
967 struct message *msg, timeout_t timeout )
969 struct message_result *result = mem_alloc( sizeof(*result) );
970 if (result)
972 result->msg = msg;
973 result->sender = send_queue;
974 result->receiver = recv_queue;
975 result->replied = 0;
976 result->data = NULL;
977 result->data_size = 0;
978 result->timeout = NULL;
979 result->hardware_msg = NULL;
980 result->desktop = NULL;
981 result->callback_msg = NULL;
983 if (msg->type == MSG_CALLBACK)
985 struct message *callback_msg = mem_alloc( sizeof(*callback_msg) );
987 if (!callback_msg)
989 free( result );
990 return NULL;
992 callback_msg->type = MSG_CALLBACK_RESULT;
993 callback_msg->win = msg->win;
994 callback_msg->msg = msg->msg;
995 callback_msg->wparam = 0;
996 callback_msg->lparam = 0;
997 callback_msg->time = get_tick_count();
998 callback_msg->result = NULL;
999 /* steal the data from the original message */
1000 callback_msg->data = msg->data;
1001 callback_msg->data_size = msg->data_size;
1002 msg->data = NULL;
1003 msg->data_size = 0;
1005 result->callback_msg = callback_msg;
1006 list_add_head( &send_queue->callback_result, &result->sender_entry );
1008 else if (send_queue)
1010 list_add_head( &send_queue->send_result, &result->sender_entry );
1011 clear_queue_bits( send_queue, QS_SMRESULT );
1014 if (timeout != TIMEOUT_INFINITE)
1015 result->timeout = add_timeout_user( timeout, result_timeout, result );
1017 return result;
1020 /* receive a message, removing it from the sent queue */
1021 static void receive_message( struct msg_queue *queue, struct message *msg,
1022 struct get_message_reply *reply )
1024 struct message_result *result = msg->result;
1026 reply->total = msg->data_size;
1027 if (msg->data_size > get_reply_max_size())
1029 set_error( STATUS_BUFFER_OVERFLOW );
1030 return;
1032 reply->type = msg->type;
1033 reply->win = msg->win;
1034 reply->msg = msg->msg;
1035 reply->wparam = msg->wparam;
1036 reply->lparam = msg->lparam;
1037 reply->x = msg->x;
1038 reply->y = msg->y;
1039 reply->time = msg->time;
1041 if (msg->data) set_reply_data_ptr( msg->data, msg->data_size );
1043 list_remove( &msg->entry );
1044 /* put the result on the receiver result stack */
1045 if (result)
1047 result->msg = NULL;
1048 result->recv_next = queue->recv_result;
1049 queue->recv_result = result;
1051 free( msg );
1052 if (list_empty( &queue->msg_list[SEND_MESSAGE] )) clear_queue_bits( queue, QS_SENDMESSAGE );
1055 /* set the result of the current received message */
1056 static void reply_message( struct msg_queue *queue, lparam_t result,
1057 unsigned int error, int remove, const void *data, data_size_t len )
1059 struct message_result *res = queue->recv_result;
1061 if (remove)
1063 queue->recv_result = res->recv_next;
1064 res->receiver = NULL;
1065 if (!res->sender && !res->hardware_msg) /* no one waiting for it */
1067 free_result( res );
1068 return;
1071 if (!res->replied)
1073 if (len && (res->data = memdup( data, len ))) res->data_size = len;
1074 store_message_result( res, result, error );
1078 static int match_window( user_handle_t win, user_handle_t msg_win )
1080 if (!win) return 1;
1081 if (win == -1 || win == 1) return !msg_win;
1082 if (msg_win == win) return 1;
1083 return is_child_window( win, msg_win );
1086 /* retrieve a posted message */
1087 static int get_posted_message( struct msg_queue *queue, user_handle_t win,
1088 unsigned int first, unsigned int last, unsigned int flags,
1089 struct get_message_reply *reply )
1091 struct message *msg;
1093 /* check against the filters */
1094 LIST_FOR_EACH_ENTRY( msg, &queue->msg_list[POST_MESSAGE], struct message, entry )
1096 if (!match_window( win, msg->win )) continue;
1097 if (!check_msg_filter( msg->msg, first, last )) continue;
1098 goto found; /* found one */
1100 return 0;
1102 /* return it to the app */
1103 found:
1104 reply->total = msg->data_size;
1105 if (msg->data_size > get_reply_max_size())
1107 set_error( STATUS_BUFFER_OVERFLOW );
1108 return 1;
1110 reply->type = msg->type;
1111 reply->win = msg->win;
1112 reply->msg = msg->msg;
1113 reply->wparam = msg->wparam;
1114 reply->lparam = msg->lparam;
1115 reply->x = msg->x;
1116 reply->y = msg->y;
1117 reply->time = msg->time;
1119 if (flags & PM_REMOVE)
1121 if (msg->data)
1123 set_reply_data_ptr( msg->data, msg->data_size );
1124 msg->data = NULL;
1125 msg->data_size = 0;
1127 remove_queue_message( queue, msg, POST_MESSAGE );
1129 else if (msg->data) set_reply_data( msg->data, msg->data_size );
1131 return 1;
1134 static int get_quit_message( struct msg_queue *queue, unsigned int flags,
1135 struct get_message_reply *reply )
1137 if (queue->quit_message)
1139 reply->total = 0;
1140 reply->type = MSG_POSTED;
1141 reply->win = 0;
1142 reply->msg = WM_QUIT;
1143 reply->wparam = queue->exit_code;
1144 reply->lparam = 0;
1146 get_message_defaults( queue, &reply->x, &reply->y, &reply->time );
1148 if (flags & PM_REMOVE)
1150 queue->quit_message = 0;
1151 if (list_empty( &queue->msg_list[POST_MESSAGE] ))
1152 clear_queue_bits( queue, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE );
1154 return 1;
1156 else
1157 return 0;
1160 /* empty a message list and free all the messages */
1161 static void empty_msg_list( struct list *list )
1163 struct list *ptr;
1165 while ((ptr = list_head( list )) != NULL)
1167 struct message *msg = LIST_ENTRY( ptr, struct message, entry );
1168 list_remove( &msg->entry );
1169 free_message( msg );
1173 /* cleanup all pending results when deleting a queue */
1174 static void cleanup_results( struct msg_queue *queue )
1176 struct list *entry;
1178 while ((entry = list_head( &queue->send_result )) != NULL)
1180 remove_result_from_sender( LIST_ENTRY( entry, struct message_result, sender_entry ) );
1183 while ((entry = list_head( &queue->callback_result )) != NULL)
1185 remove_result_from_sender( LIST_ENTRY( entry, struct message_result, sender_entry ) );
1188 while (queue->recv_result)
1189 reply_message( queue, 0, STATUS_ACCESS_DENIED /*FIXME*/, 1, NULL, 0 );
1192 /* check if the thread owning the queue is hung (not checking for messages) */
1193 static int is_queue_hung( struct msg_queue *queue )
1195 struct wait_queue_entry *entry;
1197 if (current_time - queue->last_get_msg <= 5 * TICKS_PER_SEC)
1198 return 0; /* less than 5 seconds since last get message -> not hung */
1200 LIST_FOR_EACH_ENTRY( entry, &queue->obj.wait_queue, struct wait_queue_entry, entry )
1202 if (get_wait_queue_thread(entry)->queue == queue)
1203 return 0; /* thread is waiting on queue -> not hung */
1205 return 1;
1208 static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *entry )
1210 struct msg_queue *queue = (struct msg_queue *)obj;
1212 /* a thread can only wait on its own queue */
1213 if (get_wait_queue_thread(entry)->queue != queue)
1215 set_error( STATUS_ACCESS_DENIED );
1216 return 0;
1219 if (queue->fd && list_empty( &obj->wait_queue )) /* first on the queue */
1220 set_fd_events( queue->fd, POLLIN );
1221 add_queue( obj, entry );
1222 return 1;
1225 static void msg_queue_remove_queue(struct object *obj, struct wait_queue_entry *entry )
1227 struct msg_queue *queue = (struct msg_queue *)obj;
1229 remove_queue( obj, entry );
1230 if (queue->fd && list_empty( &obj->wait_queue )) /* last on the queue is gone */
1231 set_fd_events( queue->fd, 0 );
1234 static void msg_queue_dump( struct object *obj, int verbose )
1236 struct msg_queue *queue = (struct msg_queue *)obj;
1237 const queue_shm_t *queue_shm = queue->shared;
1238 fprintf( stderr, "Msg queue bits=%x mask=%x\n",
1239 queue_shm->wake_bits, queue_shm->wake_mask );
1242 static int msg_queue_signaled( struct object *obj, struct wait_queue_entry *entry )
1244 struct msg_queue *queue = (struct msg_queue *)obj;
1245 int ret = 0;
1247 if (queue->fd)
1249 if ((ret = check_fd_events( queue->fd, POLLIN )))
1250 /* stop waiting on select() if we are signaled */
1251 set_fd_events( queue->fd, 0 );
1252 else if (!list_empty( &obj->wait_queue ))
1253 /* restart waiting on poll() if we are no longer signaled */
1254 set_fd_events( queue->fd, POLLIN );
1256 return ret || is_signaled( queue );
1259 static void msg_queue_satisfied( struct object *obj, struct wait_queue_entry *entry )
1261 struct msg_queue *queue = (struct msg_queue *)obj;
1262 const queue_shm_t *queue_shm = queue->shared;
1264 SHARED_WRITE_BEGIN( queue_shm, queue_shm_t )
1266 shared->wake_mask = 0;
1267 shared->changed_mask = 0;
1269 SHARED_WRITE_END;
1272 static void msg_queue_destroy( struct object *obj )
1274 struct msg_queue *queue = (struct msg_queue *)obj;
1275 struct list *ptr;
1276 struct hotkey *hotkey, *hotkey2;
1277 const input_shm_t *input_shm = queue->input->shared;
1278 int i;
1280 cleanup_results( queue );
1281 for (i = 0; i < NB_MSG_KINDS; i++) empty_msg_list( &queue->msg_list[i] );
1283 LIST_FOR_EACH_ENTRY_SAFE( hotkey, hotkey2, &queue->input->desktop->hotkeys, struct hotkey, entry )
1285 if (hotkey->queue == queue)
1287 list_remove( &hotkey->entry );
1288 free( hotkey );
1292 while ((ptr = list_head( &queue->pending_timers )))
1294 struct timer *timer = LIST_ENTRY( ptr, struct timer, entry );
1295 list_remove( &timer->entry );
1296 free( timer );
1298 while ((ptr = list_head( &queue->expired_timers )))
1300 struct timer *timer = LIST_ENTRY( ptr, struct timer, entry );
1301 list_remove( &timer->entry );
1302 free( timer );
1304 if (queue->timeout) remove_timeout_user( queue->timeout );
1305 SHARED_WRITE_BEGIN( input_shm, input_shm_t )
1307 shared->cursor_count -= queue->cursor_count;
1309 SHARED_WRITE_END;
1310 if (queue->keystate_lock) unlock_input_keystate( queue->input );
1311 release_object( queue->input );
1312 if (queue->hooks) release_object( queue->hooks );
1313 if (queue->fd) release_object( queue->fd );
1314 if (queue->shared) free_shared_object( queue->shared );
1317 static void msg_queue_poll_event( struct fd *fd, int event )
1319 struct msg_queue *queue = get_fd_user( fd );
1320 assert( queue->obj.ops == &msg_queue_ops );
1322 if (event & (POLLERR | POLLHUP)) set_fd_events( fd, -1 );
1323 else set_fd_events( queue->fd, 0 );
1324 wake_up( &queue->obj, 0 );
1327 static void thread_input_dump( struct object *obj, int verbose )
1329 struct thread_input *input = (struct thread_input *)obj;
1330 const input_shm_t *input_shm = input->shared;
1331 fprintf( stderr, "Thread input focus=%08x capture=%08x active=%08x\n",
1332 input_shm->focus, input_shm->capture, input_shm->active );
1335 static void thread_input_destroy( struct object *obj )
1337 struct thread_input *input = (struct thread_input *)obj;
1338 struct desktop *desktop;
1340 empty_msg_list( &input->msg_list );
1341 if ((desktop = input->desktop))
1343 if (desktop->foreground_input == input) desktop->foreground_input = NULL;
1344 release_object( desktop );
1346 if (input->shared) free_shared_object( input->shared );
1349 /* fix the thread input data when a window is destroyed */
1350 static inline void thread_input_cleanup_window( struct msg_queue *queue, user_handle_t window )
1352 struct thread_input *input = queue->input;
1353 const input_shm_t *input_shm = input->shared;
1355 SHARED_WRITE_BEGIN( input_shm, input_shm_t )
1357 if (window == shared->focus) shared->focus = 0;
1358 if (window == shared->capture) shared->capture = 0;
1359 if (window == shared->active) shared->active = 0;
1360 if (window == shared->menu_owner) shared->menu_owner = 0;
1361 if (window == shared->move_size) shared->move_size = 0;
1362 if (window == shared->caret) set_caret_window( input, shared, 0 );
1364 SHARED_WRITE_END;
1368 /* check if the specified window can be set in the input data of a given queue */
1369 static int check_queue_input_window( struct msg_queue *queue, user_handle_t window )
1371 struct thread *thread;
1372 int ret = 0;
1374 if (!window) return 1; /* we can always clear the data */
1376 if ((thread = get_window_thread( window )))
1378 ret = (queue->input == thread->queue->input);
1379 if (!ret) set_error( STATUS_ACCESS_DENIED );
1380 release_object( thread );
1382 else set_error( STATUS_INVALID_HANDLE );
1384 return ret;
1387 /* check if the thread queue is idle and set the process idle event if so */
1388 void check_thread_queue_idle( struct thread *thread )
1390 struct msg_queue *queue = thread->queue;
1391 const queue_shm_t *queue_shm = queue->shared;
1393 if ((queue_shm->wake_mask & QS_SMRESULT)) return;
1394 if (thread->process->idle_event) set_event( thread->process->idle_event );
1397 /* make sure the specified thread has a queue */
1398 int init_thread_queue( struct thread *thread )
1400 if (thread->queue) return 1;
1401 return (create_msg_queue( thread, NULL ) != NULL);
1404 /* attach two thread input data structures */
1405 int attach_thread_input( struct thread *thread_from, struct thread *thread_to )
1407 struct desktop *desktop;
1408 struct thread_input *input, *old_input;
1409 int ret;
1411 if (!thread_to->queue && !(thread_to->queue = create_msg_queue( thread_to, NULL ))) return 0;
1412 if (!(desktop = get_thread_desktop( thread_from, 0 ))) return 0;
1413 input = (struct thread_input *)grab_object( thread_to->queue->input );
1414 if (input->desktop != desktop)
1416 set_error( STATUS_ACCESS_DENIED );
1417 release_object( input );
1418 release_object( desktop );
1419 return 0;
1421 release_object( desktop );
1423 if (thread_from->queue)
1425 const input_shm_t *old_input_shm, *input_shm;
1426 old_input = thread_from->queue->input;
1427 old_input_shm = old_input->shared;
1428 input_shm = input->shared;
1430 SHARED_WRITE_BEGIN( input_shm, input_shm_t )
1432 if (!shared->active) shared->active = old_input_shm->active;
1433 if (!shared->focus) shared->focus = old_input_shm->focus;
1435 SHARED_WRITE_END;
1438 ret = assign_thread_input( thread_from, input );
1439 if (ret) memset( input->keystate, 0, sizeof(input->keystate) );
1440 release_object( input );
1441 return ret;
1444 /* detach two thread input data structures */
1445 void detach_thread_input( struct thread *thread_from )
1447 struct thread *thread;
1448 struct thread_input *input, *old_input = thread_from->queue->input;
1450 if ((input = create_thread_input( thread_from )))
1452 const input_shm_t *old_input_shm, *input_shm;
1453 old_input_shm = old_input->shared;
1454 input_shm = input->shared;
1456 if (old_input_shm->focus && (thread = get_window_thread( old_input_shm->focus )))
1458 if (thread == thread_from)
1460 SHARED_WRITE_BEGIN( old_input_shm, input_shm_t )
1462 input_shm_t *old_shared = shared;
1463 SHARED_WRITE_BEGIN( input_shm, input_shm_t )
1465 shared->focus = old_shared->focus;
1466 old_shared->focus = 0;
1468 SHARED_WRITE_END;
1470 SHARED_WRITE_END;
1472 release_object( thread );
1474 if (old_input_shm->active && (thread = get_window_thread( old_input_shm->active )))
1476 if (thread == thread_from)
1478 SHARED_WRITE_BEGIN( old_input_shm, input_shm_t )
1480 input_shm_t *old_shared = shared;
1481 SHARED_WRITE_BEGIN( input_shm, input_shm_t )
1483 shared->active = old_shared->active;
1484 old_shared->active = 0;
1486 SHARED_WRITE_END;
1488 SHARED_WRITE_END;
1490 release_object( thread );
1492 assign_thread_input( thread_from, input );
1493 release_object( input );
1498 /* set the next timer to expire */
1499 static void set_next_timer( struct msg_queue *queue )
1501 struct list *ptr;
1503 if (queue->timeout)
1505 remove_timeout_user( queue->timeout );
1506 queue->timeout = NULL;
1508 if ((ptr = list_head( &queue->pending_timers )))
1510 struct timer *timer = LIST_ENTRY( ptr, struct timer, entry );
1511 queue->timeout = add_timeout_user( abstime_to_timeout(timer->when), timer_callback, queue );
1513 /* set/clear QS_TIMER bit */
1514 if (list_empty( &queue->expired_timers ))
1515 clear_queue_bits( queue, QS_TIMER );
1516 else
1517 set_queue_bits( queue, QS_TIMER );
1520 /* find a timer from its window and id */
1521 static struct timer *find_timer( struct msg_queue *queue, user_handle_t win,
1522 unsigned int msg, lparam_t id )
1524 struct list *ptr;
1526 /* we need to search both lists */
1528 LIST_FOR_EACH( ptr, &queue->pending_timers )
1530 struct timer *timer = LIST_ENTRY( ptr, struct timer, entry );
1531 if (timer->win == win && timer->msg == msg && timer->id == id) return timer;
1533 LIST_FOR_EACH( ptr, &queue->expired_timers )
1535 struct timer *timer = LIST_ENTRY( ptr, struct timer, entry );
1536 if (timer->win == win && timer->msg == msg && timer->id == id) return timer;
1538 return NULL;
1541 /* callback for the next timer expiration */
1542 static void timer_callback( void *private )
1544 struct msg_queue *queue = private;
1545 struct list *ptr;
1547 queue->timeout = NULL;
1548 /* move on to the next timer */
1549 ptr = list_head( &queue->pending_timers );
1550 list_remove( ptr );
1551 list_add_tail( &queue->expired_timers, ptr );
1552 set_next_timer( queue );
1555 /* link a timer at its rightful place in the queue list */
1556 static void link_timer( struct msg_queue *queue, struct timer *timer )
1558 struct list *ptr;
1560 for (ptr = queue->pending_timers.next; ptr != &queue->pending_timers; ptr = ptr->next)
1562 struct timer *t = LIST_ENTRY( ptr, struct timer, entry );
1563 if (t->when <= timer->when) break;
1565 list_add_before( ptr, &timer->entry );
1568 /* remove a timer from the queue timer list and free it */
1569 static void free_timer( struct msg_queue *queue, struct timer *timer )
1571 list_remove( &timer->entry );
1572 free( timer );
1573 set_next_timer( queue );
1576 /* restart an expired timer */
1577 static void restart_timer( struct msg_queue *queue, struct timer *timer )
1579 list_remove( &timer->entry );
1580 while (-timer->when <= monotonic_time) timer->when -= (timeout_t)timer->rate * 10000;
1581 link_timer( queue, timer );
1582 set_next_timer( queue );
1585 /* find an expired timer matching the filtering parameters */
1586 static struct timer *find_expired_timer( struct msg_queue *queue, user_handle_t win,
1587 unsigned int get_first, unsigned int get_last,
1588 int remove )
1590 struct list *ptr;
1592 LIST_FOR_EACH( ptr, &queue->expired_timers )
1594 struct timer *timer = LIST_ENTRY( ptr, struct timer, entry );
1595 if (win && timer->win != win) continue;
1596 if (check_msg_filter( timer->msg, get_first, get_last ))
1598 if (remove) restart_timer( queue, timer );
1599 return timer;
1602 return NULL;
1605 /* add a timer */
1606 static struct timer *set_timer( struct msg_queue *queue, unsigned int rate )
1608 struct timer *timer = mem_alloc( sizeof(*timer) );
1609 if (timer)
1611 timer->rate = max( rate, 1 );
1612 timer->when = -monotonic_time - (timeout_t)timer->rate * 10000;
1613 link_timer( queue, timer );
1614 /* check if we replaced the next timer */
1615 if (list_head( &queue->pending_timers ) == &timer->entry) set_next_timer( queue );
1617 return timer;
1620 /* change the input key state for a given key */
1621 static void set_input_key_state( volatile unsigned char *keystate, unsigned char key, unsigned char down )
1623 if (down)
1625 if (!(keystate[key] & 0x80)) keystate[key] ^= 0x01;
1626 keystate[key] |= down;
1628 else keystate[key] &= ~0x80;
1631 /* update the input key state for a keyboard message */
1632 static void update_key_state( volatile unsigned char *keystate, unsigned int msg,
1633 lparam_t wparam, int desktop )
1635 unsigned char key, down = 0, down_val = desktop ? 0xc0 : 0x80;
1637 switch (msg)
1639 case WM_LBUTTONDOWN:
1640 down = down_val;
1641 /* fall through */
1642 case WM_LBUTTONUP:
1643 set_input_key_state( keystate, VK_LBUTTON, down );
1644 break;
1645 case WM_MBUTTONDOWN:
1646 down = down_val;
1647 /* fall through */
1648 case WM_MBUTTONUP:
1649 set_input_key_state( keystate, VK_MBUTTON, down );
1650 break;
1651 case WM_RBUTTONDOWN:
1652 down = down_val;
1653 /* fall through */
1654 case WM_RBUTTONUP:
1655 set_input_key_state( keystate, VK_RBUTTON, down );
1656 break;
1657 case WM_XBUTTONDOWN:
1658 down = down_val;
1659 /* fall through */
1660 case WM_XBUTTONUP:
1661 if (wparam >> 16 == XBUTTON1) set_input_key_state( keystate, VK_XBUTTON1, down );
1662 else if (wparam >> 16 == XBUTTON2) set_input_key_state( keystate, VK_XBUTTON2, down );
1663 break;
1664 case WM_KEYDOWN:
1665 case WM_SYSKEYDOWN:
1666 down = down_val;
1667 /* fall through */
1668 case WM_KEYUP:
1669 case WM_SYSKEYUP:
1670 key = (unsigned char)wparam;
1671 set_input_key_state( keystate, key, down );
1672 switch(key)
1674 case VK_LCONTROL:
1675 case VK_RCONTROL:
1676 down = (keystate[VK_LCONTROL] | keystate[VK_RCONTROL]) & 0x80;
1677 set_input_key_state( keystate, VK_CONTROL, down );
1678 break;
1679 case VK_LMENU:
1680 case VK_RMENU:
1681 down = (keystate[VK_LMENU] | keystate[VK_RMENU]) & 0x80;
1682 set_input_key_state( keystate, VK_MENU, down );
1683 break;
1684 case VK_LSHIFT:
1685 case VK_RSHIFT:
1686 down = (keystate[VK_LSHIFT] | keystate[VK_RSHIFT]) & 0x80;
1687 set_input_key_state( keystate, VK_SHIFT, down );
1688 break;
1690 break;
1694 static void update_thread_input_key_state( struct thread_input *input, unsigned int msg, lparam_t wparam )
1696 update_key_state( input->keystate, msg, wparam, 0 );
1699 static void update_desktop_key_state( struct desktop *desktop, unsigned int msg, lparam_t wparam )
1701 SHARED_WRITE_BEGIN( desktop->shared, desktop_shm_t )
1703 update_key_state( shared->keystate, msg, wparam, 1 );
1705 SHARED_WRITE_END;
1708 /* release the hardware message currently being processed by the given thread */
1709 static void release_hardware_message( struct msg_queue *queue, unsigned int hw_id )
1711 struct thread_input *input = queue->input;
1712 struct message *msg, *other;
1713 int clr_bit;
1715 LIST_FOR_EACH_ENTRY( msg, &input->msg_list, struct message, entry )
1717 if (msg->unique_id == hw_id) break;
1719 if (&msg->entry == &input->msg_list) return; /* not found */
1721 /* clear the queue bit for that message */
1722 clr_bit = get_hardware_msg_bit( msg->msg );
1723 LIST_FOR_EACH_ENTRY( other, &input->msg_list, struct message, entry )
1725 if (other != msg && get_hardware_msg_bit( other->msg ) == clr_bit)
1727 clr_bit = 0;
1728 break;
1731 if (clr_bit) clear_queue_bits( queue, clr_bit );
1733 update_thread_input_key_state( input, msg->msg, msg->wparam );
1734 list_remove( &msg->entry );
1735 free_message( msg );
1738 static int queue_hotkey_message( struct desktop *desktop, struct message *msg )
1740 const desktop_shm_t *desktop_shm = desktop->shared;
1741 struct hotkey *hotkey;
1742 unsigned int modifiers = 0;
1744 if (msg->msg != WM_KEYDOWN && msg->msg != WM_SYSKEYDOWN) return 0;
1746 if (desktop_shm->keystate[VK_MENU] & 0x80) modifiers |= MOD_ALT;
1747 if (desktop_shm->keystate[VK_CONTROL] & 0x80) modifiers |= MOD_CONTROL;
1748 if (desktop_shm->keystate[VK_SHIFT] & 0x80) modifiers |= MOD_SHIFT;
1749 if ((desktop_shm->keystate[VK_LWIN] & 0x80) || (desktop_shm->keystate[VK_RWIN] & 0x80)) modifiers |= MOD_WIN;
1751 LIST_FOR_EACH_ENTRY( hotkey, &desktop->hotkeys, struct hotkey, entry )
1753 if (hotkey->vkey != msg->wparam) continue;
1754 if ((hotkey->flags & (MOD_ALT|MOD_CONTROL|MOD_SHIFT|MOD_WIN)) == modifiers) goto found;
1757 return 0;
1759 found:
1760 msg->type = MSG_POSTED;
1761 msg->win = hotkey->win;
1762 msg->msg = WM_HOTKEY;
1763 msg->wparam = hotkey->id;
1764 msg->lparam = ((hotkey->vkey & 0xffff) << 16) | modifiers;
1766 free( msg->data );
1767 msg->data = NULL;
1768 msg->data_size = 0;
1770 list_add_tail( &hotkey->queue->msg_list[POST_MESSAGE], &msg->entry );
1771 set_queue_bits( hotkey->queue, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE|QS_HOTKEY );
1772 hotkey->queue->hotkey_count++;
1773 return 1;
1776 /* find the window that should receive a given hardware message */
1777 static user_handle_t find_hardware_message_window( struct desktop *desktop, struct thread_input *input,
1778 struct message *msg, unsigned int *msg_code,
1779 struct thread **thread )
1781 const input_shm_t *input_shm = input ? input->shared : NULL;
1782 user_handle_t win = 0;
1784 *thread = NULL;
1785 *msg_code = msg->msg;
1786 switch (get_hardware_msg_bit( msg->msg ))
1788 case QS_POINTER:
1789 case QS_RAWINPUT:
1790 if (!(win = msg->win) && input) win = input_shm->focus;
1791 break;
1792 case QS_KEY:
1793 if (input && !(win = input_shm->focus))
1795 win = input_shm->active;
1796 if (*msg_code < WM_SYSKEYDOWN) *msg_code += WM_SYSKEYDOWN - WM_KEYDOWN;
1798 break;
1799 case QS_MOUSEMOVE:
1800 case QS_MOUSEBUTTON:
1801 if (!input || !(win = input_shm->capture))
1803 if (is_window_visible( msg->win ) && !is_window_transparent( msg->win )) win = msg->win;
1804 else win = shallow_window_from_point( desktop, msg->x, msg->y );
1805 *thread = window_thread_from_point( win, msg->x, msg->y );
1807 break;
1810 if (!*thread)
1811 *thread = get_window_thread( win );
1812 return win;
1815 static struct rawinput_device *find_rawinput_device( struct process *process, unsigned int usage )
1817 struct rawinput_device *device, *end;
1819 for (device = process->rawinput_devices, end = device + process->rawinput_device_count; device != end; device++)
1821 if (device->usage != usage) continue;
1822 return device;
1825 return NULL;
1828 static void prepend_cursor_history( int x, int y, unsigned int time, lparam_t info )
1830 cursor_pos_t *pos = &cursor_history[--cursor_history_latest % ARRAY_SIZE(cursor_history)];
1832 pos->x = x;
1833 pos->y = y;
1834 pos->time = time;
1835 pos->info = info;
1838 static unsigned int get_rawinput_device_flags( struct process *process, struct message *msg )
1840 switch (get_hardware_msg_bit( msg->msg ))
1842 case QS_KEY:
1843 return process->rawinput_kbd ? process->rawinput_kbd->flags : 0;
1844 case QS_MOUSEMOVE:
1845 case QS_MOUSEBUTTON:
1846 return process->rawinput_mouse ? process->rawinput_mouse->flags : 0;
1848 return 0;
1851 /* queue a hardware message into a given thread input */
1852 static void queue_hardware_message( struct desktop *desktop, struct message *msg, int always_queue )
1854 const desktop_shm_t *desktop_shm = desktop->shared;
1855 user_handle_t win;
1856 struct thread *thread;
1857 struct thread_input *input;
1858 struct hardware_msg_data *msg_data = msg->data;
1859 unsigned int msg_code;
1860 int flags;
1862 update_desktop_key_state( desktop, msg->msg, msg->wparam );
1863 last_input_time = get_tick_count();
1864 if (msg->msg != WM_MOUSEMOVE) always_queue = 1;
1866 switch (get_hardware_msg_bit( msg->msg ))
1868 case QS_KEY:
1869 if (queue_hotkey_message( desktop, msg )) return;
1870 if (desktop_shm->keystate[VK_MENU] & 0x80) msg->lparam |= KF_ALTDOWN << 16;
1871 if (msg->wparam == VK_SHIFT || msg->wparam == VK_LSHIFT || msg->wparam == VK_RSHIFT)
1872 msg->lparam &= ~(KF_EXTENDED << 16);
1873 break;
1874 case QS_MOUSEMOVE:
1875 prepend_cursor_history( msg->x, msg->y, msg->time, msg_data->info );
1876 /* fallthrough */
1877 case QS_MOUSEBUTTON:
1878 if (update_desktop_cursor_pos( desktop, msg->win, msg->x, msg->y )) always_queue = 1;
1879 if (desktop_shm->keystate[VK_LBUTTON] & 0x80) msg->wparam |= MK_LBUTTON;
1880 if (desktop_shm->keystate[VK_MBUTTON] & 0x80) msg->wparam |= MK_MBUTTON;
1881 if (desktop_shm->keystate[VK_RBUTTON] & 0x80) msg->wparam |= MK_RBUTTON;
1882 if (desktop_shm->keystate[VK_SHIFT] & 0x80) msg->wparam |= MK_SHIFT;
1883 if (desktop_shm->keystate[VK_CONTROL] & 0x80) msg->wparam |= MK_CONTROL;
1884 if (desktop_shm->keystate[VK_XBUTTON1] & 0x80) msg->wparam |= MK_XBUTTON1;
1885 if (desktop_shm->keystate[VK_XBUTTON2] & 0x80) msg->wparam |= MK_XBUTTON2;
1886 break;
1888 msg->x = desktop_shm->cursor.x;
1889 msg->y = desktop_shm->cursor.y;
1891 if (msg->win && (thread = get_window_thread( msg->win )))
1893 input = thread->queue->input;
1894 release_object( thread );
1896 else input = desktop->foreground_input;
1898 win = find_hardware_message_window( desktop, input, msg, &msg_code, &thread );
1899 flags = thread ? get_rawinput_device_flags( thread->process, msg ) : 0;
1900 if (!win || !thread || (flags & RIDEV_NOLEGACY))
1902 if (input && !(flags & RIDEV_NOLEGACY)) update_thread_input_key_state( input, msg->msg, msg->wparam );
1903 free_message( msg );
1904 return;
1907 input = thread->queue->input;
1909 if (win != msg->win) always_queue = 1;
1910 if (!always_queue || merge_message( input, msg )) free_message( msg );
1911 else
1913 msg->unique_id = 0; /* will be set once we return it to the app */
1914 list_add_tail( &input->msg_list, &msg->entry );
1915 set_queue_bits( thread->queue, get_hardware_msg_bit( msg->msg ) );
1917 release_object( thread );
1920 /* send the low-level hook message for a given hardware message */
1921 static int send_hook_ll_message( struct desktop *desktop, struct message *hardware_msg,
1922 int id, lparam_t lparam, struct msg_queue *sender )
1924 struct thread *hook_thread;
1925 struct msg_queue *queue;
1926 struct message *msg;
1927 timeout_t timeout = 2000 * -10000; /* FIXME: load from registry */
1929 if (!(hook_thread = get_first_global_hook( desktop, id ))) return 0;
1930 if (!(queue = hook_thread->queue)) return 0;
1931 if (is_queue_hung( queue )) return 0;
1933 if (!(msg = mem_alloc( sizeof(*msg) ))) return 0;
1935 msg->type = MSG_HOOK_LL;
1936 msg->win = 0;
1937 msg->msg = id;
1938 msg->wparam = hardware_msg->msg;
1939 msg->lparam = lparam;
1940 msg->x = hardware_msg->x;
1941 msg->y = hardware_msg->y;
1942 msg->time = hardware_msg->time;
1943 msg->data_size = hardware_msg->data_size;
1944 msg->result = NULL;
1946 if (!(msg->data = memdup( hardware_msg->data, hardware_msg->data_size )) ||
1947 !(msg->result = alloc_message_result( sender, queue, msg, timeout )))
1949 free_message( msg );
1950 return 0;
1952 msg->result->hardware_msg = hardware_msg;
1953 msg->result->desktop = (struct desktop *)grab_object( desktop );
1954 list_add_tail( &queue->msg_list[SEND_MESSAGE], &msg->entry );
1955 set_queue_bits( queue, QS_SENDMESSAGE );
1956 return 1;
1959 /* get the foreground thread for a desktop and a window receiving input */
1960 static struct thread *get_foreground_thread( struct desktop *desktop, user_handle_t window )
1962 /* if desktop has no foreground process, assume the receiving window is */
1963 if (desktop->foreground_input)
1965 const input_shm_t *input_shm = desktop->foreground_input->shared;
1966 return get_window_thread( input_shm->focus );
1968 if (window) return get_window_thread( window );
1969 return NULL;
1972 /* user32 reserves 1 & 2 for winemouse and winekeyboard,
1973 * keep this in sync with user_private.h */
1974 #define WINE_MOUSE_HANDLE 1
1975 #define WINE_KEYBOARD_HANDLE 2
1977 static void rawmouse_init( struct rawinput *header, RAWMOUSE *rawmouse, int x, int y, unsigned int flags,
1978 unsigned int buttons, lparam_t info )
1980 static const unsigned int button_flags[] =
1982 0, /* MOUSEEVENTF_MOVE */
1983 RI_MOUSE_LEFT_BUTTON_DOWN, /* MOUSEEVENTF_LEFTDOWN */
1984 RI_MOUSE_LEFT_BUTTON_UP, /* MOUSEEVENTF_LEFTUP */
1985 RI_MOUSE_RIGHT_BUTTON_DOWN, /* MOUSEEVENTF_RIGHTDOWN */
1986 RI_MOUSE_RIGHT_BUTTON_UP, /* MOUSEEVENTF_RIGHTUP */
1987 RI_MOUSE_MIDDLE_BUTTON_DOWN, /* MOUSEEVENTF_MIDDLEDOWN */
1988 RI_MOUSE_MIDDLE_BUTTON_UP, /* MOUSEEVENTF_MIDDLEUP */
1990 unsigned int i;
1992 header->type = RIM_TYPEMOUSE;
1993 header->device = WINE_MOUSE_HANDLE;
1994 header->wparam = 0;
1995 header->usage = MAKELONG(HID_USAGE_GENERIC_MOUSE, HID_USAGE_PAGE_GENERIC);
1997 rawmouse->usFlags = MOUSE_MOVE_RELATIVE;
1998 rawmouse->usButtonFlags = 0;
1999 rawmouse->usButtonData = 0;
2000 for (i = 1; i < ARRAY_SIZE(button_flags); ++i)
2002 if (flags & (1 << i)) rawmouse->usButtonFlags |= button_flags[i];
2004 if (flags & MOUSEEVENTF_WHEEL)
2006 rawmouse->usButtonFlags |= RI_MOUSE_WHEEL;
2007 rawmouse->usButtonData = buttons;
2009 if (flags & MOUSEEVENTF_HWHEEL)
2011 rawmouse->usButtonFlags |= RI_MOUSE_HORIZONTAL_WHEEL;
2012 rawmouse->usButtonData = buttons;
2014 if (flags & MOUSEEVENTF_XDOWN)
2016 if (buttons == XBUTTON1) rawmouse->usButtonFlags |= RI_MOUSE_BUTTON_4_DOWN;
2017 if (buttons == XBUTTON2) rawmouse->usButtonFlags |= RI_MOUSE_BUTTON_5_DOWN;
2019 if (flags & MOUSEEVENTF_XUP)
2021 if (buttons == XBUTTON1) rawmouse->usButtonFlags |= RI_MOUSE_BUTTON_4_UP;
2022 if (buttons == XBUTTON2) rawmouse->usButtonFlags |= RI_MOUSE_BUTTON_5_UP;
2025 rawmouse->ulRawButtons = 0;
2026 rawmouse->lLastX = x;
2027 rawmouse->lLastY = y;
2028 rawmouse->ulExtraInformation = info;
2031 static void rawkeyboard_init( struct rawinput *rawinput, RAWKEYBOARD *keyboard, unsigned short scan, unsigned short vkey,
2032 unsigned int flags, unsigned int message, lparam_t info )
2034 rawinput->type = RIM_TYPEKEYBOARD;
2035 rawinput->device = WINE_KEYBOARD_HANDLE;
2036 rawinput->wparam = 0;
2037 rawinput->usage = MAKELONG(HID_USAGE_GENERIC_KEYBOARD, HID_USAGE_PAGE_GENERIC);
2039 keyboard->MakeCode = scan;
2040 keyboard->Flags = (flags & KEYEVENTF_KEYUP) ? RI_KEY_BREAK : RI_KEY_MAKE;
2041 if (flags & KEYEVENTF_EXTENDEDKEY) keyboard->Flags |= RI_KEY_E0;
2042 keyboard->Reserved = 0;
2044 switch (vkey)
2046 case VK_LSHIFT:
2047 case VK_RSHIFT:
2048 keyboard->VKey = VK_SHIFT;
2049 keyboard->Flags &= ~RI_KEY_E0;
2050 break;
2052 case VK_LCONTROL:
2053 case VK_RCONTROL:
2054 keyboard->VKey = VK_CONTROL;
2055 break;
2056 case VK_LMENU:
2057 case VK_RMENU:
2058 keyboard->VKey = VK_MENU;
2059 break;
2061 default:
2062 keyboard->VKey = vkey;
2063 break;
2066 keyboard->Message = message;
2067 keyboard->ExtraInformation = info;
2070 static void rawhid_init( struct rawinput *rawinput, RAWHID *hid, const hw_input_t *input )
2072 rawinput->type = RIM_TYPEHID;
2073 rawinput->device = input->hw.hid.device;
2074 rawinput->wparam = input->hw.wparam;
2075 rawinput->usage = input->hw.hid.usage;
2077 hid->dwCount = input->hw.hid.count;
2078 hid->dwSizeHid = input->hw.hid.length;
2081 struct rawinput_message
2083 struct thread *foreground;
2084 struct hw_msg_source source;
2085 unsigned int time;
2086 unsigned int message;
2087 unsigned int flags;
2088 struct rawinput rawinput;
2089 union
2091 RAWKEYBOARD keyboard;
2092 RAWMOUSE mouse;
2093 RAWHID hid;
2094 } data;
2095 const void *hid_report;
2098 /* check if process is supposed to receive a WM_INPUT message and eventually queue it */
2099 static void queue_rawinput_message( struct desktop *desktop, struct process *process, void *args )
2101 const struct rawinput_message *raw_msg = args;
2102 const struct rawinput_device *device;
2103 struct hardware_msg_data *msg_data;
2104 struct message *msg;
2105 data_size_t report_size = 0, data_size = 0;
2106 int wparam = RIM_INPUT;
2107 lparam_t info = 0;
2109 if (raw_msg->rawinput.type == RIM_TYPEMOUSE)
2111 device = process->rawinput_mouse;
2112 data_size = sizeof(raw_msg->data.mouse);
2113 info = raw_msg->data.mouse.ulExtraInformation;
2115 else if (raw_msg->rawinput.type == RIM_TYPEKEYBOARD)
2117 device = process->rawinput_kbd;
2118 data_size = sizeof(raw_msg->data.keyboard);
2119 info = raw_msg->data.keyboard.ExtraInformation;
2121 else
2123 device = find_rawinput_device( process, raw_msg->rawinput.usage );
2124 data_size = offsetof(RAWHID, bRawData[0]);
2125 report_size = raw_msg->data.hid.dwCount * raw_msg->data.hid.dwSizeHid;
2127 if (!device) return;
2129 if (raw_msg->message == WM_INPUT_DEVICE_CHANGE && !(device->flags & RIDEV_DEVNOTIFY)) return;
2130 if (process != raw_msg->foreground->process)
2132 if (raw_msg->message == WM_INPUT && !(device->flags & RIDEV_INPUTSINK)) return;
2133 wparam = RIM_INPUTSINK;
2136 if (!(msg = alloc_hardware_message( info, raw_msg->source, raw_msg->time, data_size + report_size ))) return;
2137 msg->win = device->target;
2138 msg->msg = raw_msg->message;
2139 msg->wparam = wparam;
2140 msg->lparam = 0;
2142 msg_data = msg->data;
2143 msg_data->flags = raw_msg->flags;
2144 msg_data->rawinput = raw_msg->rawinput;
2145 memcpy( msg_data + 1, &raw_msg->data, data_size );
2146 if (report_size) memcpy( (char *)(msg_data + 1) + data_size, raw_msg->hid_report, report_size );
2148 if (raw_msg->message == WM_INPUT_DEVICE_CHANGE && raw_msg->rawinput.type == RIM_TYPEHID)
2150 msg->wparam = raw_msg->rawinput.wparam;
2151 msg->lparam = raw_msg->rawinput.device;
2154 queue_hardware_message( desktop, msg, 1 );
2157 static void dispatch_rawinput_message( struct desktop *desktop, struct rawinput_message *raw_msg )
2159 struct process *process;
2161 LIST_FOR_EACH_ENTRY( process, &rawinput_processes, struct process, rawinput_entry )
2162 queue_rawinput_message( desktop, process, raw_msg );
2165 /* queue a hardware message for a mouse event */
2166 static int queue_mouse_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input,
2167 unsigned int origin, struct msg_queue *sender )
2169 const desktop_shm_t *desktop_shm = desktop->shared;
2170 struct hardware_msg_data *msg_data;
2171 struct rawinput_message raw_msg;
2172 struct message *msg;
2173 struct thread *foreground;
2174 unsigned int i, time = get_tick_count(), flags;
2175 struct hw_msg_source source = { IMDT_MOUSE, origin };
2176 lparam_t wparam = input->mouse.data << 16;
2177 int wait = 0, x, y;
2179 static const unsigned int messages[] =
2181 WM_MOUSEMOVE, /* 0x0001 = MOUSEEVENTF_MOVE */
2182 WM_LBUTTONDOWN, /* 0x0002 = MOUSEEVENTF_LEFTDOWN */
2183 WM_LBUTTONUP, /* 0x0004 = MOUSEEVENTF_LEFTUP */
2184 WM_RBUTTONDOWN, /* 0x0008 = MOUSEEVENTF_RIGHTDOWN */
2185 WM_RBUTTONUP, /* 0x0010 = MOUSEEVENTF_RIGHTUP */
2186 WM_MBUTTONDOWN, /* 0x0020 = MOUSEEVENTF_MIDDLEDOWN */
2187 WM_MBUTTONUP, /* 0x0040 = MOUSEEVENTF_MIDDLEUP */
2188 WM_XBUTTONDOWN, /* 0x0080 = MOUSEEVENTF_XDOWN */
2189 WM_XBUTTONUP, /* 0x0100 = MOUSEEVENTF_XUP */
2190 0, /* 0x0200 = unused */
2191 0, /* 0x0400 = unused */
2192 WM_MOUSEWHEEL, /* 0x0800 = MOUSEEVENTF_WHEEL */
2193 WM_MOUSEHWHEEL /* 0x1000 = MOUSEEVENTF_HWHEEL */
2196 SHARED_WRITE_BEGIN( desktop_shm, desktop_shm_t )
2198 shared->cursor.last_change = time;
2200 SHARED_WRITE_END;
2202 flags = input->mouse.flags;
2203 time = input->mouse.time;
2204 if (!time) time = desktop_shm->cursor.last_change;
2206 if (flags & MOUSEEVENTF_MOVE)
2208 if (flags & MOUSEEVENTF_ABSOLUTE)
2210 x = input->mouse.x;
2211 y = input->mouse.y;
2212 if (flags & ~(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE) &&
2213 x == desktop_shm->cursor.x && y == desktop_shm->cursor.y)
2214 flags &= ~MOUSEEVENTF_MOVE;
2216 else
2218 x = desktop_shm->cursor.x + input->mouse.x;
2219 y = desktop_shm->cursor.y + input->mouse.y;
2222 else
2224 x = desktop_shm->cursor.x;
2225 y = desktop_shm->cursor.y;
2228 if ((foreground = get_foreground_thread( desktop, win )))
2230 memset( &raw_msg, 0, sizeof(raw_msg) );
2231 raw_msg.foreground = foreground;
2232 raw_msg.source = source;
2233 raw_msg.time = time;
2234 raw_msg.message = WM_INPUT;
2235 raw_msg.flags = flags;
2236 rawmouse_init( &raw_msg.rawinput, &raw_msg.data.mouse, x - desktop_shm->cursor.x, y - desktop_shm->cursor.y,
2237 raw_msg.flags, input->mouse.data, input->mouse.info );
2239 dispatch_rawinput_message( desktop, &raw_msg );
2240 release_object( foreground );
2243 for (i = 0; i < ARRAY_SIZE( messages ); i++)
2245 if (!messages[i]) continue;
2246 if (!(flags & (1 << i))) continue;
2247 flags &= ~(1 << i);
2249 if (!(msg = alloc_hardware_message( input->mouse.info, source, time, 0 ))) return 0;
2250 msg_data = msg->data;
2252 msg->win = get_user_full_handle( win );
2253 msg->msg = messages[i];
2254 msg->wparam = wparam;
2255 msg->lparam = 0;
2256 msg->x = x;
2257 msg->y = y;
2258 if (origin == IMO_INJECTED) msg_data->flags = LLMHF_INJECTED;
2260 /* specify a sender only when sending the last message */
2261 if (!(flags & ((1 << ARRAY_SIZE( messages )) - 1)))
2263 if (!(wait = send_hook_ll_message( desktop, msg, WH_MOUSE_LL, wparam, sender )))
2264 queue_hardware_message( desktop, msg, 0 );
2266 else if (!send_hook_ll_message( desktop, msg, WH_MOUSE_LL, wparam, NULL ))
2267 queue_hardware_message( desktop, msg, 0 );
2269 return wait;
2272 static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input,
2273 unsigned int origin, struct msg_queue *sender, int repeat );
2275 static void key_repeat_timeout( void *private )
2277 struct desktop *desktop = private;
2279 desktop->key_repeat.timeout = NULL;
2280 queue_keyboard_message( desktop, desktop->key_repeat.win, &desktop->key_repeat.input, IMO_HARDWARE, NULL, 1 );
2283 static void stop_key_repeat( struct desktop *desktop )
2285 if (desktop->key_repeat.timeout) remove_timeout_user( desktop->key_repeat.timeout );
2286 desktop->key_repeat.timeout = NULL;
2287 desktop->key_repeat.win = 0;
2288 memset( &desktop->key_repeat.input, 0, sizeof(desktop->key_repeat.input) );
2291 /* queue a hardware message for a keyboard event */
2292 static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input,
2293 unsigned int origin, struct msg_queue *sender, int repeat )
2295 const desktop_shm_t *desktop_shm = desktop->shared;
2296 struct hw_msg_source source = { IMDT_KEYBOARD, origin };
2297 struct hardware_msg_data *msg_data;
2298 struct message *msg;
2299 struct thread *foreground;
2300 unsigned char vkey = input->kbd.vkey, hook_vkey = vkey;
2301 unsigned int message_code, time;
2302 lparam_t lparam = input->kbd.scan << 16;
2303 unsigned int flags = 0;
2304 BOOL unicode = input->kbd.flags & KEYEVENTF_UNICODE;
2305 int wait;
2307 if (!(time = input->kbd.time)) time = get_tick_count();
2309 switch (vkey)
2311 case 0:
2312 if (unicode) vkey = hook_vkey = VK_PACKET;
2313 break;
2314 case VK_MENU:
2315 case VK_LMENU:
2316 case VK_RMENU:
2317 vkey = (input->kbd.flags & KEYEVENTF_EXTENDEDKEY) ? VK_RMENU : VK_LMENU;
2318 if ((input->kbd.vkey & 0xff) == VK_MENU) hook_vkey = vkey;
2319 break;
2320 case VK_CONTROL:
2321 case VK_LCONTROL:
2322 case VK_RCONTROL:
2323 vkey = (input->kbd.flags & KEYEVENTF_EXTENDEDKEY) ? VK_RCONTROL : VK_LCONTROL;
2324 if ((input->kbd.vkey & 0xff) == VK_CONTROL) hook_vkey = vkey;
2325 break;
2326 case VK_SHIFT:
2327 case VK_LSHIFT:
2328 case VK_RSHIFT:
2329 vkey = (input->kbd.flags & KEYEVENTF_EXTENDEDKEY) ? VK_RSHIFT : VK_LSHIFT;
2330 if ((input->kbd.vkey & 0xff) == VK_SHIFT) hook_vkey = vkey;
2331 break;
2334 message_code = (input->kbd.flags & KEYEVENTF_KEYUP) ? WM_KEYUP : WM_KEYDOWN;
2335 switch (vkey)
2337 case VK_LMENU:
2338 case VK_RMENU:
2339 if (input->kbd.flags & KEYEVENTF_KEYUP)
2341 /* send WM_SYSKEYUP if Alt still pressed and no other key in between */
2342 if (!(desktop_shm->keystate[VK_MENU] & 0x80) || !desktop->alt_pressed) break;
2343 message_code = WM_SYSKEYUP;
2344 desktop->alt_pressed = 0;
2346 else
2348 /* send WM_SYSKEYDOWN for Alt except with Ctrl */
2349 if (desktop_shm->keystate[VK_CONTROL] & 0x80) break;
2350 message_code = WM_SYSKEYDOWN;
2351 desktop->alt_pressed = 1;
2353 break;
2355 case VK_LCONTROL:
2356 case VK_RCONTROL:
2357 /* send WM_SYSKEYUP on release if Alt still pressed */
2358 if (!(input->kbd.flags & KEYEVENTF_KEYUP)) break;
2359 if (!(desktop_shm->keystate[VK_MENU] & 0x80)) break;
2360 message_code = WM_SYSKEYUP;
2361 desktop->alt_pressed = 0;
2362 break;
2364 default:
2365 /* send WM_SYSKEY for Alt-anykey and for F10 */
2366 if (desktop_shm->keystate[VK_CONTROL] & 0x80) break;
2367 if (!(desktop_shm->keystate[VK_MENU] & 0x80)) break;
2368 /* fall through */
2369 case VK_F10:
2370 message_code = (input->kbd.flags & KEYEVENTF_KEYUP) ? WM_SYSKEYUP : WM_SYSKEYDOWN;
2371 desktop->alt_pressed = 0;
2372 break;
2375 /* send numpad vkeys if NumLock is active */
2376 if ((input->kbd.vkey & KBDNUMPAD) && (desktop->keystate[VK_NUMLOCK] & 0x01) &&
2377 !(desktop->keystate[VK_SHIFT] & 0x80))
2379 switch (vkey)
2381 case VK_INSERT: hook_vkey = vkey = VK_NUMPAD0; break;
2382 case VK_END: hook_vkey = vkey = VK_NUMPAD1; break;
2383 case VK_DOWN: hook_vkey = vkey = VK_NUMPAD2; break;
2384 case VK_NEXT: hook_vkey = vkey = VK_NUMPAD3; break;
2385 case VK_LEFT: hook_vkey = vkey = VK_NUMPAD4; break;
2386 case VK_CLEAR: hook_vkey = vkey = VK_NUMPAD5; break;
2387 case VK_RIGHT: hook_vkey = vkey = VK_NUMPAD6; break;
2388 case VK_HOME: hook_vkey = vkey = VK_NUMPAD7; break;
2389 case VK_UP: hook_vkey = vkey = VK_NUMPAD8; break;
2390 case VK_PRIOR: hook_vkey = vkey = VK_NUMPAD9; break;
2391 case VK_DELETE: hook_vkey = vkey = VK_DECIMAL; break;
2392 default: break;
2396 if (origin == IMO_HARDWARE)
2398 /* if the repeat key is released, stop auto-repeating */
2399 if (((input->kbd.flags & KEYEVENTF_KEYUP) &&
2400 (input->kbd.scan == desktop->key_repeat.input.kbd.scan)))
2402 stop_key_repeat( desktop );
2404 /* if a key is down, start or continue auto-repeating */
2405 if (!(input->kbd.flags & KEYEVENTF_KEYUP) && desktop->key_repeat.enable)
2407 timeout_t timeout = repeat ? desktop->key_repeat.period : desktop->key_repeat.delay;
2408 desktop->key_repeat.input = *input;
2409 desktop->key_repeat.input.kbd.time = 0;
2410 desktop->key_repeat.win = win;
2411 if (desktop->key_repeat.timeout) remove_timeout_user( desktop->key_repeat.timeout );
2412 desktop->key_repeat.timeout = add_timeout_user( timeout, key_repeat_timeout, desktop );
2416 if (!unicode && (foreground = get_foreground_thread( desktop, win )))
2418 struct rawinput_message raw_msg = {0};
2419 raw_msg.foreground = foreground;
2420 raw_msg.source = source;
2421 raw_msg.time = time;
2422 raw_msg.message = WM_INPUT;
2423 raw_msg.flags = input->kbd.flags;
2424 rawkeyboard_init( &raw_msg.rawinput, &raw_msg.data.keyboard, input->kbd.scan, vkey,
2425 raw_msg.flags, message_code, input->kbd.info );
2427 dispatch_rawinput_message( desktop, &raw_msg );
2428 release_object( foreground );
2431 if (!(msg = alloc_hardware_message( input->kbd.info, source, time, 0 ))) return 0;
2432 msg_data = msg->data;
2434 msg->win = get_user_full_handle( win );
2435 msg->msg = message_code;
2436 if (origin == IMO_INJECTED) msg_data->flags = LLKHF_INJECTED;
2438 if (!unicode || input->kbd.vkey)
2440 if (input->kbd.flags & KEYEVENTF_EXTENDEDKEY) flags |= KF_EXTENDED;
2441 /* FIXME: set KF_DLGMODE and KF_MENUMODE when needed */
2442 if (input->kbd.flags & KEYEVENTF_KEYUP) flags |= KF_REPEAT | KF_UP;
2443 else if (desktop_shm->keystate[vkey] & 0x80) flags |= KF_REPEAT;
2445 lparam &= 0xff0000; /* mask off scan code high bits for non-unicode input */
2446 msg_data->flags |= (flags & (KF_EXTENDED | KF_ALTDOWN | KF_UP)) >> 8;
2449 msg->wparam = vkey;
2450 msg->lparam = (flags << 16) | lparam | 1u /* repeat count */;
2452 if (!(wait = send_hook_ll_message( desktop, msg, WH_KEYBOARD_LL, lparam | hook_vkey, sender )))
2453 queue_hardware_message( desktop, msg, 1 );
2455 return wait;
2458 struct pointer
2460 struct list entry;
2461 struct timeout_user *timeout;
2462 struct desktop *desktop;
2463 user_handle_t win;
2464 int primary;
2465 hw_input_t input;
2468 static void queue_pointer_message( struct pointer *pointer, int repeated );
2470 static void pointer_message_timeout( void *private )
2472 struct pointer *pointer = private;
2473 queue_pointer_message( pointer, 1 );
2476 static void queue_pointer_message( struct pointer *pointer, int repeated )
2478 static const unsigned int messages[][2] =
2480 {WM_POINTERUPDATE, 0},
2481 {WM_POINTERENTER, WM_POINTERDOWN},
2482 {WM_POINTERUP, WM_POINTERLEAVE},
2484 struct hw_msg_source source = { IMDT_UNAVAILABLE, IMDT_TOUCH };
2485 struct desktop *desktop = pointer->desktop;
2486 const desktop_shm_t *desktop_shm = desktop->shared;
2487 const hw_input_t *input = &pointer->input;
2488 unsigned int i, wparam = input->hw.wparam;
2489 timeout_t time = get_tick_count();
2490 user_handle_t win = pointer->win;
2491 rectangle_t top_rect;
2492 struct message *msg;
2493 int x, y;
2495 get_top_window_rectangle( desktop, &top_rect );
2496 x = LOWORD(input->hw.lparam) * (top_rect.right - top_rect.left) / 65535;
2497 y = HIWORD(input->hw.lparam) * (top_rect.bottom - top_rect.top) / 65535;
2499 if (pointer->primary) wparam |= POINTER_MESSAGE_FLAG_PRIMARY << 16;
2501 for (i = 0; i < 2 && messages[input->hw.msg - WM_POINTERUPDATE][i]; i++)
2503 if (!(msg = alloc_hardware_message( 0, source, time, 0 ))) return;
2505 msg->win = get_user_full_handle( win );
2506 msg->msg = messages[input->hw.msg - WM_POINTERUPDATE][i];
2507 msg->wparam = wparam;
2508 msg->lparam = MAKELONG(x, y);
2509 msg->x = desktop_shm->cursor.x;
2510 msg->y = desktop_shm->cursor.y;
2512 queue_hardware_message( desktop, msg, 1 );
2515 if (!repeated && pointer->primary && (msg = alloc_hardware_message( 0xff515700, source, time, 0 )))
2517 unsigned int message = WM_MOUSEMOVE;
2518 if (input->hw.msg == WM_POINTERDOWN) message = WM_LBUTTONDOWN;
2519 else if (input->hw.msg == WM_POINTERUP) message = WM_LBUTTONUP;
2521 msg->win = get_user_full_handle( win );
2522 msg->msg = message;
2523 msg->wparam = 0;
2524 msg->lparam = 0;
2525 msg->x = x;
2526 msg->y = y;
2528 if (!send_hook_ll_message( desktop, msg, WH_MOUSE_LL, 0, NULL ))
2529 queue_hardware_message( desktop, msg, 0 );
2532 if (input->hw.msg != WM_POINTERUP)
2534 pointer->input.hw.msg = WM_POINTERUPDATE;
2535 pointer->input.hw.wparam &= ~(POINTER_MESSAGE_FLAG_NEW << 16);
2536 pointer->timeout = add_timeout_user( -160000, pointer_message_timeout, pointer );
2538 else
2540 list_remove( &pointer->entry );
2541 free( pointer );
2545 static struct pointer *find_pointer_from_id( struct desktop *desktop, unsigned int id )
2547 struct pointer *pointer;
2549 LIST_FOR_EACH_ENTRY( pointer, &desktop->pointers, struct pointer, entry )
2550 if (LOWORD(pointer->input.hw.wparam) == id) return pointer;
2552 pointer = mem_alloc( sizeof(struct pointer) );
2553 pointer->timeout = NULL;
2554 pointer->desktop = desktop;
2555 pointer->primary = list_empty( &desktop->pointers );
2556 list_add_tail( &desktop->pointers, &pointer->entry );
2558 return pointer;
2561 /* queue a hardware message for a custom type of event */
2562 static void queue_custom_hardware_message( struct desktop *desktop, user_handle_t win,
2563 unsigned int origin, const hw_input_t *input )
2565 const desktop_shm_t *desktop_shm = desktop->shared;
2566 struct hw_msg_source source = { IMDT_UNAVAILABLE, origin };
2567 struct thread *foreground;
2568 struct pointer *pointer;
2569 struct message *msg;
2571 switch (input->hw.msg)
2573 case WM_INPUT:
2574 case WM_INPUT_DEVICE_CHANGE:
2575 if (input->hw.hid.length * input->hw.hid.count != get_req_data_size())
2576 set_error( STATUS_INVALID_PARAMETER );
2577 else if ((foreground = get_foreground_thread( desktop, win )))
2579 struct rawinput_message raw_msg = {0};
2580 raw_msg.foreground = foreground;
2581 raw_msg.source = source;
2582 raw_msg.time = get_tick_count();
2583 raw_msg.message = input->hw.msg;
2584 raw_msg.hid_report = get_req_data();
2585 rawhid_init( &raw_msg.rawinput, &raw_msg.data.hid, input );
2587 dispatch_rawinput_message( desktop, &raw_msg );
2588 release_object( foreground );
2590 return;
2593 if (input->hw.msg == WM_POINTERDOWN || input->hw.msg == WM_POINTERUP || input->hw.msg == WM_POINTERUPDATE)
2595 pointer = find_pointer_from_id( desktop, LOWORD(input->hw.wparam) );
2596 if (pointer->timeout) remove_timeout_user( pointer->timeout );
2597 pointer->input = *input;
2598 pointer->win = win;
2600 queue_pointer_message( pointer, 0 );
2601 return;
2604 if (!(msg = alloc_hardware_message( 0, source, get_tick_count(), 0 ))) return;
2606 msg->win = get_user_full_handle( win );
2607 msg->msg = input->hw.msg;
2608 msg->wparam = input->hw.wparam;
2609 msg->lparam = input->hw.lparam;
2610 msg->x = desktop_shm->cursor.x;
2611 msg->y = desktop_shm->cursor.y;
2613 queue_hardware_message( desktop, msg, 1 );
2616 /* check message filter for a hardware message */
2617 static int check_hw_message_filter( user_handle_t win, unsigned int msg_code,
2618 user_handle_t filter_win, unsigned int first, unsigned int last )
2620 switch (get_hardware_msg_bit( msg_code ))
2622 case QS_KEY:
2623 /* we can only test the window for a keyboard message since the
2624 * dest window for a mouse message depends on hittest */
2625 if (filter_win && win != filter_win && !is_child_window( filter_win, win ))
2626 return 0;
2627 /* the message code is final for a keyboard message, we can simply check it */
2628 return check_msg_filter( msg_code, first, last );
2630 case QS_MOUSEMOVE:
2631 case QS_MOUSEBUTTON:
2632 /* we need to check all possible values that the message can have in the end */
2633 if (check_msg_filter( msg_code, first, last )) return 1;
2634 if (msg_code == WM_MOUSEWHEEL) return 0; /* no other possible value for this one */
2636 /* all other messages can become non-client messages */
2637 if (check_msg_filter( msg_code + (WM_NCMOUSEFIRST - WM_MOUSEFIRST), first, last )) return 1;
2639 /* clicks can become double-clicks or non-client double-clicks */
2640 if (msg_code == WM_LBUTTONDOWN || msg_code == WM_MBUTTONDOWN ||
2641 msg_code == WM_RBUTTONDOWN || msg_code == WM_XBUTTONDOWN)
2643 if (check_msg_filter( msg_code + (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN), first, last )) return 1;
2644 if (check_msg_filter( msg_code + (WM_NCLBUTTONDBLCLK - WM_LBUTTONDOWN), first, last )) return 1;
2646 return 0;
2648 default:
2649 return check_msg_filter( msg_code, first, last );
2653 /* is this message an internal driver notification message */
2654 static inline BOOL is_internal_hardware_message( unsigned int message )
2656 return (message >= WM_WINE_FIRST_DRIVER_MSG && message <= WM_WINE_LAST_DRIVER_MSG);
2659 /* find a hardware message for the given queue */
2660 static int get_hardware_message( struct thread *thread, unsigned int hw_id, user_handle_t filter_win,
2661 unsigned int first, unsigned int last, unsigned int flags,
2662 struct get_message_reply *reply )
2664 struct thread_input *input = thread->queue->input;
2665 struct thread *win_thread;
2666 struct list *ptr;
2667 user_handle_t win;
2668 int clear_bits, got_one = 0;
2669 unsigned int msg_code;
2671 ptr = list_head( &input->msg_list );
2672 if (hw_id)
2674 while (ptr)
2676 struct message *msg = LIST_ENTRY( ptr, struct message, entry );
2677 if (msg->unique_id == hw_id) break;
2678 ptr = list_next( &input->msg_list, ptr );
2680 if (!ptr) ptr = list_head( &input->msg_list );
2681 else ptr = list_next( &input->msg_list, ptr ); /* start from the next one */
2684 if (ptr == list_head( &input->msg_list ))
2685 clear_bits = QS_INPUT;
2686 else
2687 clear_bits = 0; /* don't clear bits if we don't go through the whole list */
2689 while (ptr)
2691 struct message *msg = LIST_ENTRY( ptr, struct message, entry );
2692 struct hardware_msg_data *data = msg->data;
2694 ptr = list_next( &input->msg_list, ptr );
2695 win = find_hardware_message_window( input->desktop, input, msg, &msg_code, &win_thread );
2696 if (!win || !win_thread)
2698 /* no window at all, remove it */
2699 update_thread_input_key_state( input, msg->msg, msg->wparam );
2700 list_remove( &msg->entry );
2701 free_message( msg );
2702 continue;
2704 if (win_thread != thread)
2706 if (win_thread->queue->input == input)
2708 /* wake the other thread */
2709 set_queue_bits( win_thread->queue, get_hardware_msg_bit( msg->msg ) );
2710 got_one = 1;
2712 else
2714 /* for another thread input, drop it */
2715 update_thread_input_key_state( input, msg->msg, msg->wparam );
2716 list_remove( &msg->entry );
2717 free_message( msg );
2719 release_object( win_thread );
2720 continue;
2722 release_object( win_thread );
2724 /* if we already got a message for another thread, or if it doesn't
2725 * match the filter we skip it */
2726 if (got_one || !check_hw_message_filter( win, msg_code, filter_win, first, last ))
2728 clear_bits &= ~get_hardware_msg_bit( msg->msg );
2729 continue;
2732 reply->total = msg->data_size;
2733 if (msg->data_size > get_reply_max_size())
2735 set_error( STATUS_BUFFER_OVERFLOW );
2736 return 1;
2739 /* now we can return it */
2740 if (!msg->unique_id) msg->unique_id = get_unique_id();
2741 reply->type = MSG_HARDWARE;
2742 reply->win = win;
2743 reply->msg = msg_code;
2744 reply->wparam = msg->wparam;
2745 reply->lparam = msg->lparam;
2746 reply->x = msg->x;
2747 reply->y = msg->y;
2748 reply->time = msg->time;
2750 data->hw_id = msg->unique_id;
2751 set_reply_data( msg->data, msg->data_size );
2752 if ((get_hardware_msg_bit( msg->msg ) & (QS_RAWINPUT | QS_POINTER) && (flags & PM_REMOVE)) ||
2753 is_internal_hardware_message( msg->msg ))
2754 release_hardware_message( current->queue, data->hw_id );
2755 return 1;
2757 /* nothing found, clear the hardware queue bits */
2758 clear_queue_bits( thread->queue, clear_bits );
2759 return 0;
2762 /* increment (or decrement if 'incr' is negative) the queue paint count */
2763 void inc_queue_paint_count( struct thread *thread, int incr )
2765 struct msg_queue *queue = thread->queue;
2767 assert( queue );
2769 if ((queue->paint_count += incr) < 0) queue->paint_count = 0;
2771 if (queue->paint_count)
2772 set_queue_bits( queue, QS_PAINT );
2773 else
2774 clear_queue_bits( queue, QS_PAINT );
2778 /* remove all messages and timers belonging to a certain window */
2779 void queue_cleanup_window( struct thread *thread, user_handle_t win )
2781 struct msg_queue *queue = thread->queue;
2782 struct list *ptr;
2783 int i;
2785 if (!queue) return;
2787 /* remove timers */
2789 ptr = list_head( &queue->pending_timers );
2790 while (ptr)
2792 struct list *next = list_next( &queue->pending_timers, ptr );
2793 struct timer *timer = LIST_ENTRY( ptr, struct timer, entry );
2794 if (timer->win == win) free_timer( queue, timer );
2795 ptr = next;
2797 ptr = list_head( &queue->expired_timers );
2798 while (ptr)
2800 struct list *next = list_next( &queue->expired_timers, ptr );
2801 struct timer *timer = LIST_ENTRY( ptr, struct timer, entry );
2802 if (timer->win == win) free_timer( queue, timer );
2803 ptr = next;
2806 /* remove messages */
2807 for (i = 0; i < NB_MSG_KINDS; i++)
2809 struct list *ptr, *next;
2811 LIST_FOR_EACH_SAFE( ptr, next, &queue->msg_list[i] )
2813 struct message *msg = LIST_ENTRY( ptr, struct message, entry );
2814 if (msg->win == win)
2816 if (msg->msg == WM_QUIT && !queue->quit_message)
2818 queue->quit_message = 1;
2819 queue->exit_code = msg->wparam;
2821 remove_queue_message( queue, msg, i );
2826 thread_input_cleanup_window( queue, win );
2829 /* post a message to a window */
2830 void post_message( user_handle_t win, unsigned int message, lparam_t wparam, lparam_t lparam )
2832 struct message *msg;
2833 struct thread *thread = get_window_thread( win );
2835 if (!thread) return;
2837 if (thread->queue && (msg = mem_alloc( sizeof(*msg) )))
2839 msg->type = MSG_POSTED;
2840 msg->win = get_user_full_handle( win );
2841 msg->msg = message;
2842 msg->wparam = wparam;
2843 msg->lparam = lparam;
2844 msg->result = NULL;
2845 msg->data = NULL;
2846 msg->data_size = 0;
2848 get_message_defaults( thread->queue, &msg->x, &msg->y, &msg->time );
2850 list_add_tail( &thread->queue->msg_list[POST_MESSAGE], &msg->entry );
2851 set_queue_bits( thread->queue, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE );
2852 if (message == WM_HOTKEY)
2854 set_queue_bits( thread->queue, QS_HOTKEY );
2855 thread->queue->hotkey_count++;
2858 release_object( thread );
2861 /* send a notify message to a window */
2862 void send_notify_message( user_handle_t win, unsigned int message, lparam_t wparam, lparam_t lparam )
2864 struct message *msg;
2865 struct thread *thread = get_window_thread( win );
2867 if (!thread) return;
2869 if (thread->queue && (msg = mem_alloc( sizeof(*msg) )))
2871 msg->type = MSG_NOTIFY;
2872 msg->win = get_user_full_handle( win );
2873 msg->msg = message;
2874 msg->wparam = wparam;
2875 msg->lparam = lparam;
2876 msg->result = NULL;
2877 msg->data = NULL;
2878 msg->data_size = 0;
2880 get_message_defaults( thread->queue, &msg->x, &msg->y, &msg->time );
2882 list_add_tail( &thread->queue->msg_list[SEND_MESSAGE], &msg->entry );
2883 set_queue_bits( thread->queue, QS_SENDMESSAGE );
2885 release_object( thread );
2888 /* post a win event */
2889 void post_win_event( struct thread *thread, unsigned int event,
2890 user_handle_t win, unsigned int object_id,
2891 unsigned int child_id, client_ptr_t hook_proc,
2892 const WCHAR *module, data_size_t module_size,
2893 user_handle_t hook)
2895 struct message *msg;
2897 if (thread->queue && (msg = mem_alloc( sizeof(*msg) )))
2899 struct winevent_msg_data *data;
2901 msg->type = MSG_WINEVENT;
2902 msg->win = get_user_full_handle( win );
2903 msg->msg = event;
2904 msg->wparam = object_id;
2905 msg->lparam = child_id;
2906 msg->time = get_tick_count();
2907 msg->result = NULL;
2909 if ((data = malloc( sizeof(*data) + module_size )))
2911 data->hook = hook;
2912 data->tid = get_thread_id( current );
2913 data->hook_proc = hook_proc;
2914 memcpy( data + 1, module, module_size );
2916 msg->data = data;
2917 msg->data_size = sizeof(*data) + module_size;
2919 if (debug_level > 1)
2920 fprintf( stderr, "post_win_event: tid %04x event %04x win %08x object_id %d child_id %d\n",
2921 get_thread_id(thread), event, win, object_id, child_id );
2922 list_add_tail( &thread->queue->msg_list[SEND_MESSAGE], &msg->entry );
2923 set_queue_bits( thread->queue, QS_SENDMESSAGE );
2925 else
2926 free( msg );
2930 void free_pointers( struct desktop *desktop )
2932 struct pointer *pointer, *next;
2934 LIST_FOR_EACH_ENTRY_SAFE( pointer, next, &desktop->pointers, struct pointer, entry )
2936 list_remove( &pointer->entry );
2937 if (pointer->timeout) remove_timeout_user( pointer->timeout );
2938 free( pointer );
2942 /* free all hotkeys on a desktop, optionally filtering by window */
2943 void free_hotkeys( struct desktop *desktop, user_handle_t window )
2945 struct hotkey *hotkey, *hotkey2;
2947 LIST_FOR_EACH_ENTRY_SAFE( hotkey, hotkey2, &desktop->hotkeys, struct hotkey, entry )
2949 if (!window || hotkey->win == window)
2951 list_remove( &hotkey->entry );
2952 free( hotkey );
2957 /* retrieve the desktop which should receive some hardware input event */
2958 static struct desktop *get_hardware_input_desktop( user_handle_t win )
2960 struct winstation *winstation;
2961 struct desktop *desktop;
2962 struct thread *thread;
2964 if (!win || !(thread = get_window_thread( win )))
2966 if (!(winstation = get_visible_winstation())) return NULL;
2967 return get_input_desktop( winstation );
2969 else
2971 /* if window is specified, use its desktop to make it the input desktop */
2972 desktop = (struct desktop *)grab_object( thread->queue->input->desktop );
2973 release_object( thread );
2976 return desktop;
2979 /* enable or disable rawinput for a given process */
2980 void set_rawinput_process( struct process *process, int enable )
2982 list_remove( &process->rawinput_entry ); /* remove it first, it might already be in the list */
2983 if (!process->rawinput_device_count || !enable) list_init( &process->rawinput_entry );
2984 else list_add_tail( &rawinput_processes, &process->rawinput_entry );
2988 /* check if the thread owning the window is hung */
2989 DECL_HANDLER(is_window_hung)
2991 struct thread *thread;
2993 thread = get_window_thread( req->win );
2994 if (thread)
2996 reply->is_hung = is_queue_hung( thread->queue );
2997 release_object( thread );
2999 else reply->is_hung = 0;
3003 /* get a handle for the current thread message queue */
3004 DECL_HANDLER(get_msg_queue_handle)
3006 struct msg_queue *queue = get_current_queue();
3008 reply->handle = 0;
3009 if (queue) reply->handle = alloc_handle( current->process, queue, SYNCHRONIZE, 0 );
3013 /* get the message queue of the current thread */
3014 DECL_HANDLER(get_msg_queue)
3016 struct msg_queue *queue = get_current_queue();
3017 if (queue) reply->locator = get_shared_object_locator( queue->shared );
3021 /* set the file descriptor associated to the current thread queue */
3022 DECL_HANDLER(set_queue_fd)
3024 struct msg_queue *queue = get_current_queue();
3025 struct file *file;
3026 int unix_fd;
3028 if (queue->fd) /* fd can only be set once */
3030 set_error( STATUS_ACCESS_DENIED );
3031 return;
3033 if (!(file = get_file_obj( current->process, req->handle, SYNCHRONIZE ))) return;
3035 if ((unix_fd = get_file_unix_fd( file )) != -1)
3037 if ((unix_fd = dup( unix_fd )) != -1)
3038 queue->fd = create_anonymous_fd( &msg_queue_fd_ops, unix_fd, &queue->obj, 0 );
3039 else
3040 file_set_error();
3042 release_object( file );
3046 /* set the current message queue wakeup mask */
3047 DECL_HANDLER(set_queue_mask)
3049 struct msg_queue *queue = get_current_queue();
3051 if (queue)
3053 const queue_shm_t *queue_shm = queue->shared;
3055 SHARED_WRITE_BEGIN( queue_shm, queue_shm_t )
3057 shared->wake_mask = req->wake_mask;
3058 shared->changed_mask = req->changed_mask;
3060 SHARED_WRITE_END;
3062 reply->wake_bits = queue_shm->wake_bits;
3063 reply->changed_bits = queue_shm->changed_bits;
3065 if (is_signaled( queue ))
3067 /* if skip wait is set, do what would have been done in the subsequent wait */
3068 if (req->skip_wait)
3070 SHARED_WRITE_BEGIN( queue_shm, queue_shm_t )
3072 shared->wake_mask = 0;
3073 shared->changed_mask = 0;
3075 SHARED_WRITE_END;
3077 else wake_up( &queue->obj, 0 );
3083 /* get the current message queue status */
3084 DECL_HANDLER(get_queue_status)
3086 struct msg_queue *queue = current->queue;
3087 if (queue)
3089 const queue_shm_t *queue_shm = queue->shared;
3091 reply->wake_bits = queue_shm->wake_bits;
3092 reply->changed_bits = queue_shm->changed_bits;
3094 SHARED_WRITE_BEGIN( queue_shm, queue_shm_t )
3096 shared->changed_bits &= ~req->clear_bits;
3098 SHARED_WRITE_END;
3100 else reply->wake_bits = reply->changed_bits = 0;
3104 /* send a message to a thread queue */
3105 DECL_HANDLER(send_message)
3107 struct message *msg;
3108 struct msg_queue *send_queue = get_current_queue();
3109 struct msg_queue *recv_queue = NULL;
3110 struct thread *thread = NULL;
3112 if (!(thread = get_thread_from_id( req->id ))) return;
3114 if (!(recv_queue = thread->queue))
3116 set_error( STATUS_INVALID_PARAMETER );
3117 release_object( thread );
3118 return;
3120 if ((req->flags & SEND_MSG_ABORT_IF_HUNG) && is_queue_hung(recv_queue))
3122 set_error( STATUS_TIMEOUT );
3123 release_object( thread );
3124 return;
3127 if ((msg = mem_alloc( sizeof(*msg) )))
3129 msg->type = req->type;
3130 msg->win = get_user_full_handle( req->win );
3131 msg->msg = req->msg;
3132 msg->wparam = req->wparam;
3133 msg->lparam = req->lparam;
3134 msg->result = NULL;
3135 msg->data = NULL;
3136 msg->data_size = get_req_data_size();
3138 get_message_defaults( recv_queue, &msg->x, &msg->y, &msg->time );
3140 if (msg->data_size && !(msg->data = memdup( get_req_data(), msg->data_size )))
3142 free( msg );
3143 release_object( thread );
3144 return;
3147 switch(msg->type)
3149 case MSG_OTHER_PROCESS:
3150 case MSG_ASCII:
3151 case MSG_UNICODE:
3152 case MSG_CALLBACK:
3153 if (!(msg->result = alloc_message_result( send_queue, recv_queue, msg, req->timeout )))
3155 free_message( msg );
3156 break;
3158 /* fall through */
3159 case MSG_NOTIFY:
3160 list_add_tail( &recv_queue->msg_list[SEND_MESSAGE], &msg->entry );
3161 set_queue_bits( recv_queue, QS_SENDMESSAGE );
3162 break;
3163 case MSG_POSTED:
3164 list_add_tail( &recv_queue->msg_list[POST_MESSAGE], &msg->entry );
3165 set_queue_bits( recv_queue, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE );
3166 if (msg->msg == WM_HOTKEY)
3168 set_queue_bits( recv_queue, QS_HOTKEY );
3169 recv_queue->hotkey_count++;
3171 break;
3172 case MSG_HARDWARE: /* should use send_hardware_message instead */
3173 case MSG_CALLBACK_RESULT: /* cannot send this one */
3174 case MSG_HOOK_LL: /* generated internally */
3175 default:
3176 set_error( STATUS_INVALID_PARAMETER );
3177 free( msg );
3178 break;
3181 release_object( thread );
3184 /* send a hardware message to a thread queue */
3185 DECL_HANDLER(send_hardware_message)
3187 struct desktop *desktop;
3188 unsigned int origin = (req->flags & SEND_HWMSG_INJECTED ? IMO_INJECTED : IMO_HARDWARE);
3189 struct msg_queue *sender = req->flags & SEND_HWMSG_INJECTED ? get_current_queue() : NULL;
3190 const desktop_shm_t *desktop_shm;
3191 int wait = 0;
3193 if (!(desktop = get_hardware_input_desktop( req->win ))) return;
3194 if ((origin == IMO_INJECTED && desktop != current->queue->input->desktop) ||
3195 !set_input_desktop( desktop->winstation, desktop ))
3197 release_object( desktop );
3198 set_error( STATUS_ACCESS_DENIED );
3199 return;
3201 desktop_shm = desktop->shared;
3203 reply->prev_x = desktop_shm->cursor.x;
3204 reply->prev_y = desktop_shm->cursor.y;
3206 switch (req->input.type)
3208 case INPUT_MOUSE:
3209 wait = queue_mouse_message( desktop, req->win, &req->input, origin, sender );
3210 break;
3211 case INPUT_KEYBOARD:
3212 wait = queue_keyboard_message( desktop, req->win, &req->input, origin, sender, 0 );
3213 break;
3214 case INPUT_HARDWARE:
3215 queue_custom_hardware_message( desktop, req->win, origin, &req->input );
3216 break;
3217 default:
3218 set_error( STATUS_INVALID_PARAMETER );
3221 reply->wait = sender ? wait : 0;
3222 reply->new_x = desktop_shm->cursor.x;
3223 reply->new_y = desktop_shm->cursor.y;
3224 release_object( desktop );
3227 /* post a quit message to the current queue */
3228 DECL_HANDLER(post_quit_message)
3230 struct msg_queue *queue = get_current_queue();
3232 if (!queue)
3233 return;
3235 queue->quit_message = 1;
3236 queue->exit_code = req->exit_code;
3237 set_queue_bits( queue, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE );
3240 /* get a message from the current queue */
3241 DECL_HANDLER(get_message)
3243 struct timer *timer;
3244 struct list *ptr;
3245 struct msg_queue *queue = get_current_queue();
3246 user_handle_t get_win = get_user_full_handle( req->get_win );
3247 const queue_shm_t *queue_shm;
3248 unsigned int filter;
3250 if (get_win && get_win != 1 && get_win != -1 && !get_user_object( get_win, USER_WINDOW ))
3252 set_win32_error( ERROR_INVALID_WINDOW_HANDLE );
3253 return;
3256 if (!queue) return;
3257 queue_shm = queue->shared;
3259 /* check for any hardware internal message */
3260 if (get_hardware_message( current, req->hw_id, get_win, WM_WINE_FIRST_DRIVER_MSG,
3261 WM_WINE_LAST_DRIVER_MSG, req->flags, reply ))
3262 return;
3264 if (req->internal) /* check for internal messages only, leave queue flags unchanged */
3266 set_error( STATUS_PENDING );
3267 return;
3270 queue->last_get_msg = current_time;
3272 /* first check for sent messages */
3273 if ((ptr = list_head( &queue->msg_list[SEND_MESSAGE] )))
3275 struct message *msg = LIST_ENTRY( ptr, struct message, entry );
3276 receive_message( queue, msg, reply );
3277 return;
3280 /* use the same logic as in win32u/message.c peek_message */
3281 if (!(filter = req->flags >> 16)) filter = QS_ALLINPUT;
3283 /* clear changed bits so we can wait on them if we don't find a message */
3284 SHARED_WRITE_BEGIN( queue_shm, queue_shm_t )
3286 if (filter & QS_POSTMESSAGE)
3288 shared->changed_bits &= ~(QS_POSTMESSAGE | QS_HOTKEY | QS_TIMER);
3289 if (req->get_first == 0 && req->get_last == ~0U) shared->changed_bits &= ~QS_ALLPOSTMESSAGE;
3291 if (filter & QS_INPUT) shared->changed_bits &= ~QS_INPUT;
3292 if (filter & QS_PAINT) shared->changed_bits &= ~QS_PAINT;
3294 SHARED_WRITE_END;
3296 /* then check for posted messages */
3297 if ((filter & QS_POSTMESSAGE) &&
3298 get_posted_message( queue, get_win, req->get_first, req->get_last, req->flags, reply ))
3299 return;
3301 if ((filter & QS_HOTKEY) && queue->hotkey_count &&
3302 req->get_first <= WM_HOTKEY && req->get_last >= WM_HOTKEY &&
3303 get_posted_message( queue, get_win, WM_HOTKEY, WM_HOTKEY, req->flags, reply ))
3304 return;
3306 /* only check for quit messages if not posted messages pending */
3307 if ((filter & QS_POSTMESSAGE) && get_quit_message( queue, req->flags, reply ))
3308 return;
3310 /* then check for any raw hardware message */
3311 if ((filter & QS_INPUT) &&
3312 filter_contains_hw_range( req->get_first, req->get_last ) &&
3313 get_hardware_message( current, req->hw_id, get_win, req->get_first, req->get_last, req->flags, reply ))
3314 return;
3316 /* now check for WM_PAINT */
3317 if ((filter & QS_PAINT) &&
3318 queue->paint_count &&
3319 check_msg_filter( WM_PAINT, req->get_first, req->get_last ) &&
3320 (reply->win = find_window_to_repaint( get_win, current )))
3322 reply->type = MSG_POSTED;
3323 reply->msg = WM_PAINT;
3324 reply->wparam = 0;
3325 reply->lparam = 0;
3326 get_message_defaults( queue, &reply->x, &reply->y, &reply->time );
3327 return;
3330 /* now check for timer */
3331 if ((filter & QS_TIMER) &&
3332 (timer = find_expired_timer( queue, get_win, req->get_first,
3333 req->get_last, (req->flags & PM_REMOVE) )))
3335 reply->type = MSG_POSTED;
3336 reply->win = timer->win;
3337 reply->msg = timer->msg;
3338 reply->wparam = timer->id;
3339 reply->lparam = timer->lparam;
3340 get_message_defaults( queue, &reply->x, &reply->y, &reply->time );
3341 if (!(req->flags & PM_NOYIELD) && current->process->idle_event)
3342 set_event( current->process->idle_event );
3343 return;
3346 if (get_win == -1 && current->process->idle_event) set_event( current->process->idle_event );
3348 SHARED_WRITE_BEGIN( queue_shm, queue_shm_t )
3350 shared->wake_mask = req->wake_mask;
3351 shared->changed_mask = req->changed_mask;
3353 SHARED_WRITE_END;
3355 set_error( STATUS_PENDING ); /* FIXME */
3359 /* reply to a sent message */
3360 DECL_HANDLER(reply_message)
3362 if (!current->queue) set_error( STATUS_ACCESS_DENIED );
3363 else if (current->queue->recv_result)
3364 reply_message( current->queue, req->result, 0, req->remove,
3365 get_req_data(), get_req_data_size() );
3369 /* accept the current hardware message */
3370 DECL_HANDLER(accept_hardware_message)
3372 if (current->queue)
3373 release_hardware_message( current->queue, req->hw_id );
3374 else
3375 set_error( STATUS_ACCESS_DENIED );
3379 /* retrieve the reply for the last message sent */
3380 DECL_HANDLER(get_message_reply)
3382 struct message_result *result;
3383 struct list *entry;
3384 struct msg_queue *queue = current->queue;
3386 if (queue)
3388 set_error( STATUS_PENDING );
3389 reply->result = 0;
3391 if (!(entry = list_head( &queue->send_result ))) return; /* no reply ready */
3393 result = LIST_ENTRY( entry, struct message_result, sender_entry );
3394 if (result->replied || req->cancel)
3396 if (result->replied)
3398 reply->result = result->result;
3399 set_error( result->error );
3400 if (result->data)
3402 data_size_t data_len = min( result->data_size, get_reply_max_size() );
3403 set_reply_data_ptr( result->data, data_len );
3404 result->data = NULL;
3405 result->data_size = 0;
3408 remove_result_from_sender( result );
3410 entry = list_head( &queue->send_result );
3411 if (!entry) clear_queue_bits( queue, QS_SMRESULT );
3412 else
3414 result = LIST_ENTRY( entry, struct message_result, sender_entry );
3415 if (result->replied) set_queue_bits( queue, QS_SMRESULT );
3416 else clear_queue_bits( queue, QS_SMRESULT );
3420 else set_error( STATUS_ACCESS_DENIED );
3424 /* set a window timer */
3425 DECL_HANDLER(set_win_timer)
3427 struct timer *timer;
3428 struct msg_queue *queue;
3429 struct thread *thread = NULL;
3430 user_handle_t win = 0;
3431 lparam_t id = req->id;
3433 if (req->win)
3435 if (!(win = get_user_full_handle( req->win )) || !(thread = get_window_thread( win )))
3437 set_error( STATUS_INVALID_HANDLE );
3438 return;
3440 if (thread->process != current->process)
3442 release_object( thread );
3443 set_error( STATUS_ACCESS_DENIED );
3444 return;
3446 queue = thread->queue;
3447 /* remove it if it existed already */
3448 if ((timer = find_timer( queue, win, req->msg, id ))) free_timer( queue, timer );
3450 else
3452 queue = get_current_queue();
3453 /* look for a timer with this id */
3454 if (id && (timer = find_timer( queue, 0, req->msg, id )))
3456 /* free and reuse id */
3457 free_timer( queue, timer );
3459 else
3461 lparam_t end_id = queue->next_timer_id;
3463 /* find a free id for it */
3464 while (1)
3466 id = queue->next_timer_id;
3467 if (--queue->next_timer_id <= 0x100) queue->next_timer_id = 0x7fff;
3469 if (!find_timer( queue, 0, req->msg, id )) break;
3470 if (queue->next_timer_id == end_id)
3472 set_win32_error( ERROR_NO_MORE_USER_HANDLES );
3473 return;
3479 if ((timer = set_timer( queue, req->rate )))
3481 timer->win = win;
3482 timer->msg = req->msg;
3483 timer->id = id;
3484 timer->lparam = req->lparam;
3485 reply->id = id;
3487 if (thread) release_object( thread );
3490 /* kill a window timer */
3491 DECL_HANDLER(kill_win_timer)
3493 struct timer *timer;
3494 struct thread *thread;
3495 user_handle_t win = 0;
3497 if (req->win)
3499 if (!(win = get_user_full_handle( req->win )) || !(thread = get_window_thread( win )))
3501 set_error( STATUS_INVALID_HANDLE );
3502 return;
3504 if (thread->process != current->process)
3506 release_object( thread );
3507 set_error( STATUS_ACCESS_DENIED );
3508 return;
3511 else thread = (struct thread *)grab_object( current );
3513 if (thread->queue && (timer = find_timer( thread->queue, win, req->msg, req->id )))
3514 free_timer( thread->queue, timer );
3515 else
3516 set_error( STATUS_INVALID_PARAMETER );
3518 release_object( thread );
3521 DECL_HANDLER(register_hotkey)
3523 struct desktop *desktop;
3524 user_handle_t win_handle = req->window;
3525 struct hotkey *hotkey;
3526 struct hotkey *new_hotkey = NULL;
3527 struct thread *thread;
3528 const int modifier_flags = MOD_ALT|MOD_CONTROL|MOD_SHIFT|MOD_WIN;
3530 if (!(desktop = get_thread_desktop( current, 0 ))) return;
3532 if (win_handle)
3534 if (!(win_handle = get_valid_window_handle( win_handle )))
3536 release_object( desktop );
3537 return;
3540 thread = get_window_thread( win_handle );
3541 if (thread) release_object( thread );
3543 if (thread != current)
3545 release_object( desktop );
3546 set_win32_error( ERROR_WINDOW_OF_OTHER_THREAD );
3547 return;
3551 LIST_FOR_EACH_ENTRY( hotkey, &desktop->hotkeys, struct hotkey, entry )
3553 if (req->vkey == hotkey->vkey &&
3554 (req->flags & modifier_flags) == (hotkey->flags & modifier_flags))
3556 release_object( desktop );
3557 set_win32_error( ERROR_HOTKEY_ALREADY_REGISTERED );
3558 return;
3560 if (current->queue == hotkey->queue && win_handle == hotkey->win && req->id == hotkey->id)
3561 new_hotkey = hotkey;
3564 if (new_hotkey)
3566 reply->replaced = 1;
3567 reply->flags = new_hotkey->flags;
3568 reply->vkey = new_hotkey->vkey;
3570 else
3572 new_hotkey = mem_alloc( sizeof(*new_hotkey) );
3573 if (new_hotkey)
3575 list_add_tail( &desktop->hotkeys, &new_hotkey->entry );
3576 new_hotkey->queue = current->queue;
3577 new_hotkey->win = win_handle;
3578 new_hotkey->id = req->id;
3582 if (new_hotkey)
3584 new_hotkey->flags = req->flags;
3585 new_hotkey->vkey = req->vkey;
3588 release_object( desktop );
3591 DECL_HANDLER(unregister_hotkey)
3593 struct desktop *desktop;
3594 user_handle_t win_handle = req->window;
3595 struct hotkey *hotkey;
3596 struct thread *thread;
3598 if (!(desktop = get_thread_desktop( current, 0 ))) return;
3600 if (win_handle)
3602 if (!(win_handle = get_valid_window_handle( win_handle )))
3604 release_object( desktop );
3605 return;
3608 thread = get_window_thread( win_handle );
3609 if (thread) release_object( thread );
3611 if (thread != current)
3613 release_object( desktop );
3614 set_win32_error( ERROR_WINDOW_OF_OTHER_THREAD );
3615 return;
3619 LIST_FOR_EACH_ENTRY( hotkey, &desktop->hotkeys, struct hotkey, entry )
3621 if (current->queue == hotkey->queue && win_handle == hotkey->win && req->id == hotkey->id)
3622 goto found;
3625 release_object( desktop );
3626 set_win32_error( ERROR_HOTKEY_NOT_REGISTERED );
3627 return;
3629 found:
3630 reply->flags = hotkey->flags;
3631 reply->vkey = hotkey->vkey;
3632 list_remove( &hotkey->entry );
3633 free( hotkey );
3634 release_object( desktop );
3637 /* attach (or detach) thread inputs */
3638 DECL_HANDLER(attach_thread_input)
3640 struct thread *thread_from = get_thread_from_id( req->tid_from );
3641 struct thread *thread_to = get_thread_from_id( req->tid_to );
3643 if (!thread_from || !thread_to)
3645 if (thread_from) release_object( thread_from );
3646 if (thread_to) release_object( thread_to );
3647 return;
3649 if (thread_from != thread_to)
3651 if (req->attach)
3653 if ((thread_to->queue || thread_to == current) &&
3654 (thread_from->queue || thread_from == current))
3655 attach_thread_input( thread_from, thread_to );
3656 else
3657 set_error( STATUS_INVALID_PARAMETER );
3659 else
3661 if (thread_from->queue && thread_to->queue &&
3662 thread_from->queue->input == thread_to->queue->input)
3663 detach_thread_input( thread_from );
3664 else
3665 set_error( STATUS_ACCESS_DENIED );
3668 else set_error( STATUS_ACCESS_DENIED );
3669 release_object( thread_from );
3670 release_object( thread_to );
3674 /* get the thread input of the given thread */
3675 DECL_HANDLER(get_thread_input)
3677 struct thread_input *input;
3679 if (req->tid)
3681 struct thread *thread;
3682 if (!(thread = get_thread_from_id( req->tid ))) return;
3683 input = thread->queue ? thread->queue->input : NULL;
3684 release_object( thread );
3686 else
3688 struct desktop *desktop;
3689 if (!(desktop = get_thread_desktop( current, 0 ))) return;
3690 input = desktop->foreground_input; /* get the foreground thread info */
3691 release_object( desktop );
3694 if (input && input->shared) reply->locator = get_shared_object_locator( input->shared );
3698 /* retrieve queue keyboard state for current thread or global async state */
3699 DECL_HANDLER(get_key_state)
3701 struct desktop *desktop;
3702 data_size_t size = min( 256, get_reply_max_size() );
3704 if (req->async) /* get global async key state */
3706 if (!(desktop = get_thread_desktop( current, 0 ))) return;
3707 if (req->key >= 0)
3709 SHARED_WRITE_BEGIN( desktop->shared, desktop_shm_t )
3711 reply->state = shared->keystate[req->key & 0xff];
3712 shared->keystate[req->key & 0xff] &= ~0x40;
3714 SHARED_WRITE_END;
3716 set_reply_data( (const void *)desktop->shared->keystate, size );
3717 release_object( desktop );
3719 else
3721 struct msg_queue *queue = get_current_queue();
3722 unsigned char *keystate = queue->input->keystate;
3723 if (req->key >= 0)
3725 sync_input_keystate( queue->input );
3726 reply->state = keystate[req->key & 0xff];
3728 set_reply_data( keystate, size );
3733 /* set queue keyboard state for current thread */
3734 DECL_HANDLER(set_key_state)
3736 struct msg_queue *queue = get_current_queue();
3737 struct desktop *desktop = queue->input->desktop;
3738 data_size_t size = min( 256, get_req_data_size() );
3740 memcpy( queue->input->keystate, get_req_data(), size );
3741 memcpy( queue->input->desktop_keystate, (const void *)desktop->shared->keystate,
3742 sizeof(queue->input->desktop_keystate) );
3744 if (req->async && (desktop = get_thread_desktop( current, 0 )))
3746 SHARED_WRITE_BEGIN( desktop->shared, desktop_shm_t )
3748 memcpy( (void *)shared->keystate, get_req_data(), size );
3750 SHARED_WRITE_END;
3751 release_object( desktop );
3756 /* set the system foreground window */
3757 DECL_HANDLER(set_foreground_window)
3759 struct thread *thread = NULL;
3760 struct desktop *desktop;
3761 struct thread_input *input;
3762 struct msg_queue *queue = get_current_queue();
3764 if (!(desktop = get_thread_desktop( current, 0 ))) return;
3766 if (!(input = desktop->foreground_input)) reply->previous = 0;
3767 else reply->previous = input->shared->active;
3769 reply->send_msg_old = (reply->previous && desktop->foreground_input != queue->input);
3770 reply->send_msg_new = FALSE;
3772 if (is_valid_foreground_window( req->handle ) &&
3773 (thread = get_window_thread( req->handle )) &&
3774 thread->queue->input->desktop == desktop)
3776 set_foreground_input( desktop, thread->queue->input );
3777 reply->send_msg_new = (desktop->foreground_input != queue->input);
3779 else set_win32_error( ERROR_INVALID_WINDOW_HANDLE );
3781 if (thread) release_object( thread );
3782 release_object( desktop );
3786 /* set the current thread focus window */
3787 DECL_HANDLER(set_focus_window)
3789 struct msg_queue *queue = get_current_queue();
3791 reply->previous = 0;
3792 if (queue && check_queue_input_window( queue, req->handle ))
3794 const input_shm_t *input_shm = queue->input->shared;
3795 SHARED_WRITE_BEGIN( input_shm, input_shm_t )
3797 reply->previous = shared->focus;
3798 shared->focus = get_user_full_handle( req->handle );
3800 SHARED_WRITE_END;
3805 /* set the current thread active window */
3806 DECL_HANDLER(set_active_window)
3808 struct msg_queue *queue = get_current_queue();
3810 reply->previous = 0;
3811 if (queue && check_queue_input_window( queue, req->handle ))
3813 if (!req->handle || make_window_active( req->handle ))
3815 const input_shm_t *input_shm = queue->input->shared;
3816 SHARED_WRITE_BEGIN( input_shm, input_shm_t )
3818 reply->previous = shared->active;
3819 shared->active = get_user_full_handle( req->handle );
3821 SHARED_WRITE_END;
3823 else set_error( STATUS_INVALID_HANDLE );
3828 /* set the current thread capture window */
3829 DECL_HANDLER(set_capture_window)
3831 struct msg_queue *queue = get_current_queue();
3833 reply->previous = reply->full_handle = 0;
3834 if (queue && check_queue_input_window( queue, req->handle ))
3836 struct thread_input *input = queue->input;
3837 const input_shm_t *input_shm = input->shared;
3839 /* if in menu mode, reject all requests to change focus, except if the menu bit is set */
3840 if (input_shm->menu_owner && !(req->flags & CAPTURE_MENU))
3842 set_error(STATUS_ACCESS_DENIED);
3843 return;
3845 SHARED_WRITE_BEGIN( input_shm, input_shm_t )
3847 reply->previous = shared->capture;
3848 shared->capture = get_user_full_handle( req->handle );
3849 shared->menu_owner = (req->flags & CAPTURE_MENU) ? shared->capture : 0;
3850 shared->move_size = (req->flags & CAPTURE_MOVESIZE) ? shared->capture : 0;
3851 reply->full_handle = shared->capture;
3853 SHARED_WRITE_END;
3858 /* Set the current thread caret window */
3859 DECL_HANDLER(set_caret_window)
3861 struct msg_queue *queue = get_current_queue();
3863 reply->previous = 0;
3864 if (queue && check_queue_input_window( queue, req->handle ))
3866 struct thread_input *input = queue->input;
3867 const input_shm_t *input_shm = input->shared;
3868 user_handle_t caret = get_user_full_handle(req->handle);
3870 reply->previous = input_shm->caret;
3871 reply->old_rect = input_shm->caret_rect;
3872 reply->old_hide = input->caret_hide;
3873 reply->old_state = input->caret_state;
3875 SHARED_WRITE_BEGIN( input_shm, input_shm_t )
3877 set_caret_window( input, shared, caret );
3878 shared->caret_rect.right = shared->caret_rect.left + req->width;
3879 shared->caret_rect.bottom = shared->caret_rect.top + req->height;
3881 SHARED_WRITE_END;
3886 /* Set the current thread caret information */
3887 DECL_HANDLER(set_caret_info)
3889 struct msg_queue *queue = get_current_queue();
3890 const input_shm_t *input_shm;
3891 struct thread_input *input;
3893 if (!queue) return;
3894 input = queue->input;
3895 input_shm = input->shared;
3896 reply->full_handle = input_shm->caret;
3897 reply->old_rect = input_shm->caret_rect;
3898 reply->old_hide = input->caret_hide;
3899 reply->old_state = input->caret_state;
3901 if (req->handle && get_user_full_handle(req->handle) != input_shm->caret)
3903 set_error( STATUS_ACCESS_DENIED );
3904 return;
3906 if (req->flags & SET_CARET_POS)
3908 SHARED_WRITE_BEGIN( input_shm, input_shm_t )
3910 shared->caret_rect.right += req->x - shared->caret_rect.left;
3911 shared->caret_rect.bottom += req->y - shared->caret_rect.top;
3912 shared->caret_rect.left = req->x;
3913 shared->caret_rect.top = req->y;
3915 SHARED_WRITE_END;
3917 if (req->flags & SET_CARET_HIDE)
3919 input->caret_hide += req->hide;
3920 if (input->caret_hide < 0) input->caret_hide = 0;
3922 if (req->flags & SET_CARET_STATE)
3924 switch (req->state)
3926 case CARET_STATE_OFF: input->caret_state = 0; break;
3927 case CARET_STATE_ON: input->caret_state = 1; break;
3928 case CARET_STATE_TOGGLE: input->caret_state = !input->caret_state; break;
3929 case CARET_STATE_ON_IF_MOVED:
3930 if (req->x != reply->old_rect.left || req->y != reply->old_rect.top) input->caret_state = 1;
3931 break;
3937 /* get the time of the last input event */
3938 DECL_HANDLER(get_last_input_time)
3940 reply->time = last_input_time;
3943 /* set/get the current cursor */
3944 DECL_HANDLER(set_cursor)
3946 struct msg_queue *queue = get_current_queue();
3947 user_handle_t prev_cursor, new_cursor;
3948 struct thread_input *input;
3949 const input_shm_t *input_shm;
3950 struct desktop *desktop;
3951 const desktop_shm_t *desktop_shm;
3953 if (!queue) return;
3954 input = queue->input;
3955 input_shm = input->shared;
3956 desktop = input->desktop;
3957 desktop_shm = desktop->shared;
3958 prev_cursor = input_shm->cursor_count < 0 ? 0 : input_shm->cursor;
3960 reply->prev_handle = input_shm->cursor;
3961 reply->prev_count = input_shm->cursor_count;
3962 reply->prev_x = desktop_shm->cursor.x;
3963 reply->prev_y = desktop_shm->cursor.y;
3965 if ((req->flags & SET_CURSOR_HANDLE) && req->handle &&
3966 !get_user_object( req->handle, USER_CLIENT ))
3968 set_win32_error( ERROR_INVALID_CURSOR_HANDLE );
3969 return;
3972 SHARED_WRITE_BEGIN( input_shm, input_shm_t )
3974 if (req->flags & SET_CURSOR_HANDLE)
3975 shared->cursor = req->handle;
3976 if (req->flags & SET_CURSOR_COUNT)
3978 queue->cursor_count += req->show_count;
3979 shared->cursor_count += req->show_count;
3982 SHARED_WRITE_END;
3984 if (req->flags & SET_CURSOR_POS) set_cursor_pos( desktop, req->x, req->y );
3985 if (req->flags & SET_CURSOR_CLIP) set_clip_rectangle( desktop, &req->clip, req->flags, 0 );
3986 if (req->flags & SET_CURSOR_NOCLIP) set_clip_rectangle( desktop, NULL, SET_CURSOR_NOCLIP, 0 );
3988 new_cursor = input_shm->cursor_count < 0 ? 0 : input_shm->cursor;
3989 if (prev_cursor != new_cursor) update_desktop_cursor_handle( desktop, input, new_cursor );
3991 reply->new_x = desktop_shm->cursor.x;
3992 reply->new_y = desktop_shm->cursor.y;
3993 reply->new_clip = desktop_shm->cursor.clip;
3994 reply->last_change = desktop_shm->cursor.last_change;
3997 /* Get the history of the 64 last cursor positions */
3998 DECL_HANDLER(get_cursor_history)
4000 cursor_pos_t *pos;
4001 unsigned int i, count = min( 64, get_reply_max_size() / sizeof(*pos) );
4003 if ((pos = set_reply_data_size( count * sizeof(*pos) )))
4004 for (i = 0; i < count; i++)
4005 pos[i] = cursor_history[(i + cursor_history_latest) % ARRAY_SIZE(cursor_history)];
4008 DECL_HANDLER(get_rawinput_buffer)
4010 const size_t align = is_machine_64bit( current->process->machine ) ? 7 : 3;
4011 data_size_t buffer_size = get_reply_max_size() & ~align;
4012 struct thread_input *input = current->queue->input;
4013 struct message *msg, *next_msg;
4014 int count = 0;
4015 char *buffer;
4017 if (req->header_size != sizeof(RAWINPUTHEADER))
4019 set_error( STATUS_INVALID_PARAMETER );
4020 return;
4023 if (!req->read_data)
4025 LIST_FOR_EACH_ENTRY( msg, &input->msg_list, struct message, entry )
4027 if (msg->msg == WM_INPUT)
4029 struct hardware_msg_data *msg_data = msg->data;
4030 data_size_t size = msg_data->size - sizeof(*msg_data);
4031 reply->next_size = sizeof(RAWINPUTHEADER) + size;
4032 break;
4037 else if ((buffer = mem_alloc( buffer_size )))
4039 size_t total_size = 0, next_size = 0;
4041 reply->next_size = get_reply_max_size();
4043 LIST_FOR_EACH_ENTRY_SAFE( msg, next_msg, &input->msg_list, struct message, entry )
4045 if (msg->msg == WM_INPUT)
4047 RAWINPUT *rawinput = (RAWINPUT *)(buffer + total_size);
4048 struct hardware_msg_data *msg_data = msg->data;
4049 data_size_t data_size = msg_data->size - sizeof(*msg_data);
4051 if (total_size + sizeof(RAWINPUTHEADER) + data_size > buffer_size)
4053 next_size = sizeof(RAWINPUTHEADER) + data_size;
4054 break;
4057 rawinput->header.dwSize = sizeof(RAWINPUTHEADER) + data_size;
4058 rawinput->header.dwType = msg_data->rawinput.type;
4059 rawinput->header.hDevice = UlongToHandle(msg_data->rawinput.device);
4060 rawinput->header.wParam = msg_data->rawinput.wparam;
4061 memcpy( &rawinput->header + 1, msg_data + 1, data_size );
4063 total_size += (rawinput->header.dwSize + align) & ~align;
4064 reply->time = msg->time;
4065 list_remove( &msg->entry );
4066 free_message( msg );
4067 count++;
4071 if (!next_size)
4073 if (count) next_size = sizeof(RAWINPUT);
4074 else reply->next_size = 0;
4077 if (next_size && get_reply_max_size() <= next_size)
4079 set_error( STATUS_BUFFER_TOO_SMALL );
4080 reply->next_size = next_size;
4083 reply->count = count;
4084 set_reply_data_ptr( buffer, total_size );
4088 DECL_HANDLER(update_rawinput_devices)
4090 const struct rawinput_device *tmp, *devices = get_req_data();
4091 unsigned int device_count = get_req_data_size() / sizeof (*devices);
4092 size_t size = device_count * sizeof(*devices);
4093 struct process *process = current->process;
4094 struct winstation *winstation;
4095 struct desktop *desktop;
4097 if (!size)
4099 process->rawinput_device_count = 0;
4100 process->rawinput_mouse = NULL;
4101 process->rawinput_kbd = NULL;
4102 set_rawinput_process( process, 0 );
4103 return;
4106 if (!(tmp = realloc( process->rawinput_devices, size )))
4108 set_error( STATUS_NO_MEMORY );
4109 return;
4111 process->rawinput_devices = (struct rawinput_device *)tmp;
4112 process->rawinput_device_count = device_count;
4113 memcpy( process->rawinput_devices, devices, size );
4115 process->rawinput_mouse = find_rawinput_device( process, MAKELONG(HID_USAGE_GENERIC_MOUSE, HID_USAGE_PAGE_GENERIC) );
4116 process->rawinput_kbd = find_rawinput_device( process, MAKELONG(HID_USAGE_GENERIC_KEYBOARD, HID_USAGE_PAGE_GENERIC) );
4118 if ((winstation = get_visible_winstation()) && (desktop = get_input_desktop( winstation )))
4120 struct thread *thread;
4122 /* one of the process thread might be connected to the input desktop, update the full list */
4123 LIST_FOR_EACH_ENTRY( thread, &desktop->threads, struct thread, desktop_entry )
4124 set_rawinput_process( thread->process, 1 );
4126 release_object( desktop );
4130 DECL_HANDLER(set_keyboard_repeat)
4132 struct desktop *desktop;
4134 if (!(desktop = get_thread_desktop( current, 0 ))) return;
4136 /* report previous values */
4137 reply->enable = desktop->key_repeat.enable;
4139 /* ignore negative values to allow partial updates */
4140 if (req->enable >= 0) desktop->key_repeat.enable = req->enable;
4141 if (req->delay >= 0) desktop->key_repeat.delay = -req->delay * 10000;
4142 if (req->period >= 0) desktop->key_repeat.period = -req->period * 10000;
4144 if (!desktop->key_repeat.enable) stop_key_repeat( desktop );
4146 release_object( desktop );