4 * Copyright 1993 Alexandre Julliard
6 * Copyright 2011, 2012, 2013 Ken Thomases for CodeWeavers Inc.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #define WIN32_NO_STATUS
34 WINE_DEFAULT_DEBUG_CHANNEL(event
);
35 WINE_DECLARE_DEBUG_CHANNEL(imm
);
37 /* IME works synchronously, key input is passed from ImeProcessKey, to the
38 * host IME. We wait for it to be handled, or not, which is notified using
39 * the sent_text_input event. Meanwhile, while processing the key, the host
40 * IME may send one or more im_set_text events to update the input text.
42 * If ImeProcessKey returns TRUE, ImeToAsciiEx is then be called to retrieve
43 * the composition string updates. We use ime_update.comp_str != NULL as flag that
44 * composition is started, even if the preedit text is empty.
46 * If ImeProcessKey returns FALSE, ImeToAsciiEx will not be called.
54 static struct ime_update ime_update
;
56 /* return the name of an Mac event */
57 static const char *dbgstr_event(int type
)
59 static const char * const event_names
[] = {
69 "LOST_PASTEBOARD_OWNERSHIP",
71 "MOUSE_MOVED_RELATIVE",
72 "MOUSE_MOVED_ABSOLUTE",
75 "QUERY_EVENT_NO_PREEMPT_WAIT",
76 "REASSERT_WINDOW_POSITION",
79 "STATUS_ITEM_MOUSE_BUTTON",
80 "STATUS_ITEM_MOUSE_MOVE",
81 "WINDOW_BROUGHT_FORWARD",
82 "WINDOW_CLOSE_REQUESTED",
83 "WINDOW_DID_UNMINIMIZE",
86 "WINDOW_FRAME_CHANGED",
89 "WINDOW_MAXIMIZE_REQUESTED",
90 "WINDOW_MINIMIZE_REQUESTED",
91 "WINDOW_RESIZE_ENDED",
92 "WINDOW_RESTORE_REQUESTED",
95 if (0 <= type
&& type
< NUM_EVENT_TYPES
) return event_names
[type
];
96 return wine_dbg_sprintf("Unknown event %d", type
);
100 /***********************************************************************
103 static macdrv_event_mask
get_event_mask(DWORD mask
)
105 macdrv_event_mask event_mask
= 0;
107 if ((mask
& QS_ALLINPUT
) == QS_ALLINPUT
) return -1;
109 if (mask
& QS_HOTKEY
)
110 event_mask
|= event_mask_for_type(HOTKEY_PRESS
);
114 event_mask
|= event_mask_for_type(KEY_PRESS
);
115 event_mask
|= event_mask_for_type(KEY_RELEASE
);
116 event_mask
|= event_mask_for_type(KEYBOARD_CHANGED
);
119 if (mask
& QS_MOUSEBUTTON
)
121 event_mask
|= event_mask_for_type(MOUSE_BUTTON
);
122 event_mask
|= event_mask_for_type(MOUSE_SCROLL
);
125 if (mask
& QS_MOUSEMOVE
)
127 event_mask
|= event_mask_for_type(MOUSE_MOVED_RELATIVE
);
128 event_mask
|= event_mask_for_type(MOUSE_MOVED_ABSOLUTE
);
131 if (mask
& QS_POSTMESSAGE
)
133 event_mask
|= event_mask_for_type(APP_ACTIVATED
);
134 event_mask
|= event_mask_for_type(APP_DEACTIVATED
);
135 event_mask
|= event_mask_for_type(APP_QUIT_REQUESTED
);
136 event_mask
|= event_mask_for_type(DISPLAYS_CHANGED
);
137 event_mask
|= event_mask_for_type(IM_SET_TEXT
);
138 event_mask
|= event_mask_for_type(LOST_PASTEBOARD_OWNERSHIP
);
139 event_mask
|= event_mask_for_type(STATUS_ITEM_MOUSE_BUTTON
);
140 event_mask
|= event_mask_for_type(STATUS_ITEM_MOUSE_MOVE
);
141 event_mask
|= event_mask_for_type(WINDOW_DID_UNMINIMIZE
);
142 event_mask
|= event_mask_for_type(WINDOW_FRAME_CHANGED
);
143 event_mask
|= event_mask_for_type(WINDOW_GOT_FOCUS
);
144 event_mask
|= event_mask_for_type(WINDOW_LOST_FOCUS
);
147 if (mask
& QS_SENDMESSAGE
)
149 event_mask
|= event_mask_for_type(QUERY_EVENT
);
150 event_mask
|= event_mask_for_type(QUERY_EVENT_NO_PREEMPT_WAIT
);
151 event_mask
|= event_mask_for_type(REASSERT_WINDOW_POSITION
);
152 event_mask
|= event_mask_for_type(RELEASE_CAPTURE
);
153 event_mask
|= event_mask_for_type(SENT_TEXT_INPUT
);
154 event_mask
|= event_mask_for_type(WINDOW_BROUGHT_FORWARD
);
155 event_mask
|= event_mask_for_type(WINDOW_CLOSE_REQUESTED
);
156 event_mask
|= event_mask_for_type(WINDOW_DRAG_BEGIN
);
157 event_mask
|= event_mask_for_type(WINDOW_DRAG_END
);
158 event_mask
|= event_mask_for_type(WINDOW_MAXIMIZE_REQUESTED
);
159 event_mask
|= event_mask_for_type(WINDOW_MINIMIZE_REQUESTED
);
160 event_mask
|= event_mask_for_type(WINDOW_RESIZE_ENDED
);
161 event_mask
|= event_mask_for_type(WINDOW_RESTORE_REQUESTED
);
168 /***********************************************************************
171 static void macdrv_im_set_text(const macdrv_event
*event
)
173 HWND hwnd
= macdrv_get_window_hwnd(event
->window
);
177 TRACE_(imm
)("win %p/%p himc %p text %s complete %u\n", hwnd
, event
->window
, event
->im_set_text
.himc
,
178 debugstr_cf(event
->im_set_text
.text
), event
->im_set_text
.complete
);
180 if (event
->im_set_text
.text
)
182 length
= CFStringGetLength(event
->im_set_text
.text
);
183 if (!(text
= malloc((length
+ 1) * sizeof(WCHAR
)))) return;
184 if (length
) CFStringGetCharacters(event
->im_set_text
.text
, CFRangeMake(0, length
), text
);
188 /* discard any pending comp text */
189 free(ime_update
.comp_str
);
190 ime_update
.comp_str
= NULL
;
191 ime_update
.cursor_pos
= -1;
193 if (event
->im_set_text
.complete
)
195 free(ime_update
.result_str
);
196 ime_update
.result_str
= text
;
200 ime_update
.comp_str
= text
;
201 ime_update
.cursor_pos
= event
->im_set_text
.cursor_pos
;
205 /***********************************************************************
206 * macdrv_sent_text_input
208 static void macdrv_sent_text_input(const macdrv_event
*event
)
210 TRACE_(imm
)("handled: %s\n", event
->sent_text_input
.handled
? "TRUE" : "FALSE");
211 *event
->sent_text_input
.done
= event
->sent_text_input
.handled
|| ime_update
.result_str
? 1 : -1;
215 /***********************************************************************
216 * ImeToAsciiEx (MACDRV.@)
218 UINT
macdrv_ImeToAsciiEx(UINT vkey
, UINT vsc
, const BYTE
*state
, COMPOSITIONSTRING
*compstr
, HIMC himc
)
220 UINT needed
= sizeof(COMPOSITIONSTRING
), comp_len
, result_len
;
221 struct ime_update
*update
= &ime_update
;
224 TRACE_(imm
)("vkey %#x, vsc %#x, state %p, compstr %p, himc %p\n", vkey
, vsc
, state
, compstr
, himc
);
226 if (!update
->comp_str
) comp_len
= 0;
229 comp_len
= wcslen(update
->comp_str
);
230 needed
+= comp_len
* sizeof(WCHAR
); /* GCS_COMPSTR */
231 needed
+= comp_len
; /* GCS_COMPATTR */
232 needed
+= 2 * sizeof(DWORD
); /* GCS_COMPCLAUSE */
235 if (!update
->result_str
) result_len
= 0;
238 result_len
= wcslen(update
->result_str
);
239 needed
+= result_len
* sizeof(WCHAR
); /* GCS_RESULTSTR */
240 needed
+= 2 * sizeof(DWORD
); /* GCS_RESULTCLAUSE */
243 if (compstr
->dwSize
< needed
)
245 compstr
->dwSize
= needed
;
246 return STATUS_BUFFER_TOO_SMALL
;
249 memset( compstr
, 0, sizeof(*compstr
) );
250 compstr
->dwSize
= sizeof(*compstr
);
252 if (update
->comp_str
)
254 compstr
->dwCursorPos
= update
->cursor_pos
;
256 compstr
->dwCompStrLen
= comp_len
;
257 compstr
->dwCompStrOffset
= compstr
->dwSize
;
258 dst
= (BYTE
*)compstr
+ compstr
->dwCompStrOffset
;
259 memcpy(dst
, update
->comp_str
, compstr
->dwCompStrLen
* sizeof(WCHAR
));
260 compstr
->dwSize
+= compstr
->dwCompStrLen
* sizeof(WCHAR
);
262 compstr
->dwCompClauseLen
= 2 * sizeof(DWORD
);
263 compstr
->dwCompClauseOffset
= compstr
->dwSize
;
264 dst
= (BYTE
*)compstr
+ compstr
->dwCompClauseOffset
;
265 *((DWORD
*)dst
+ 0) = 0;
266 *((DWORD
*)dst
+ 1) = compstr
->dwCompStrLen
;
267 compstr
->dwSize
+= compstr
->dwCompClauseLen
;
269 compstr
->dwCompAttrLen
= compstr
->dwCompStrLen
;
270 compstr
->dwCompAttrOffset
= compstr
->dwSize
;
271 dst
= (BYTE
*)compstr
+ compstr
->dwCompAttrOffset
;
272 memset(dst
, ATTR_INPUT
, compstr
->dwCompAttrLen
);
273 compstr
->dwSize
+= compstr
->dwCompAttrLen
;
276 if (update
->result_str
)
278 compstr
->dwResultStrLen
= result_len
;
279 compstr
->dwResultStrOffset
= compstr
->dwSize
;
280 dst
= (BYTE
*)compstr
+ compstr
->dwResultStrOffset
;
281 memcpy(dst
, update
->result_str
, compstr
->dwResultStrLen
* sizeof(WCHAR
));
282 compstr
->dwSize
+= compstr
->dwResultStrLen
* sizeof(WCHAR
);
284 compstr
->dwResultClauseLen
= 2 * sizeof(DWORD
);
285 compstr
->dwResultClauseOffset
= compstr
->dwSize
;
286 dst
= (BYTE
*)compstr
+ compstr
->dwResultClauseOffset
;
287 *((DWORD
*)dst
+ 0) = 0;
288 *((DWORD
*)dst
+ 1) = compstr
->dwResultStrLen
;
289 compstr
->dwSize
+= compstr
->dwResultClauseLen
;
292 free(update
->result_str
);
293 update
->result_str
= NULL
;
298 /**************************************************************************
299 * drag_operations_to_dropeffects
301 static DWORD
drag_operations_to_dropeffects(uint32_t ops
)
304 if (ops
& (DRAG_OP_COPY
| DRAG_OP_GENERIC
))
305 effects
|= DROPEFFECT_COPY
;
306 if (ops
& DRAG_OP_MOVE
)
307 effects
|= DROPEFFECT_MOVE
;
308 if (ops
& (DRAG_OP_LINK
| DRAG_OP_GENERIC
))
309 effects
|= DROPEFFECT_LINK
;
314 /**************************************************************************
315 * dropeffect_to_drag_operation
317 static uint32_t dropeffect_to_drag_operation(DWORD effect
, uint32_t ops
)
319 if (effect
& DROPEFFECT_LINK
&& ops
& DRAG_OP_LINK
) return DRAG_OP_LINK
;
320 if (effect
& DROPEFFECT_COPY
&& ops
& DRAG_OP_COPY
) return DRAG_OP_COPY
;
321 if (effect
& DROPEFFECT_MOVE
&& ops
& DRAG_OP_MOVE
) return DRAG_OP_MOVE
;
322 if (effect
& DROPEFFECT_LINK
&& ops
& DRAG_OP_GENERIC
) return DRAG_OP_GENERIC
;
323 if (effect
& DROPEFFECT_COPY
&& ops
& DRAG_OP_GENERIC
) return DRAG_OP_GENERIC
;
329 /**************************************************************************
332 static BOOL
query_drag_drop(macdrv_query
*query
)
334 HWND hwnd
= macdrv_get_window_hwnd(query
->window
);
335 struct macdrv_win_data
*data
= get_win_data(hwnd
);
336 struct dnd_query_drop_params params
;
340 WARN("no win_data for win %p/%p\n", hwnd
, query
->window
);
344 params
.hwnd
= HandleToUlong(hwnd
);
345 params
.effect
= drag_operations_to_dropeffects(query
->drag_drop
.op
);
346 params
.x
= query
->drag_drop
.x
+ data
->whole_rect
.left
;
347 params
.y
= query
->drag_drop
.y
+ data
->whole_rect
.top
;
348 params
.handle
= (UINT_PTR
)query
->drag_drop
.pasteboard
;
349 release_win_data(data
);
350 return macdrv_client_func(client_func_dnd_query_drop
, ¶ms
, sizeof(params
));
353 /**************************************************************************
356 static BOOL
query_drag_exited(macdrv_query
*query
)
358 struct dnd_query_exited_params params
;
359 params
.hwnd
= HandleToUlong(macdrv_get_window_hwnd(query
->window
));
360 return macdrv_client_func(client_func_dnd_query_exited
, ¶ms
, sizeof(params
));
364 /**************************************************************************
365 * query_drag_operation
367 static BOOL
query_drag_operation(macdrv_query
*query
)
369 struct dnd_query_drag_params params
;
370 HWND hwnd
= macdrv_get_window_hwnd(query
->window
);
371 struct macdrv_win_data
*data
= get_win_data(hwnd
);
376 WARN("no win_data for win %p/%p\n", hwnd
, query
->window
);
380 params
.hwnd
= HandleToUlong(hwnd
);
381 params
.effect
= drag_operations_to_dropeffects(query
->drag_operation
.offered_ops
);
382 params
.x
= query
->drag_operation
.x
+ data
->whole_rect
.left
;
383 params
.y
= query
->drag_operation
.y
+ data
->whole_rect
.top
;
384 params
.handle
= (UINT_PTR
)query
->drag_operation
.pasteboard
;
385 release_win_data(data
);
387 effect
= macdrv_client_func(client_func_dnd_query_drag
, ¶ms
, sizeof(params
));
388 if (!effect
) return FALSE
;
390 query
->drag_operation
.accepted_op
= dropeffect_to_drag_operation(effect
,
391 query
->drag_operation
.offered_ops
);
396 /**************************************************************************
397 * query_ime_char_rect
399 BOOL
query_ime_char_rect(macdrv_query
* query
)
401 HWND hwnd
= macdrv_get_window_hwnd(query
->window
);
402 void *himc
= query
->ime_char_rect
.himc
;
403 CFRange
*range
= &query
->ime_char_rect
.range
;
404 GUITHREADINFO info
= {.cbSize
= sizeof(info
)};
407 TRACE_(imm
)("win %p/%p himc %p range %ld-%ld\n", hwnd
, query
->window
, himc
, range
->location
,
410 if (NtUserGetGUIThreadInfo(0, &info
))
412 NtUserMapWindowPoints(info
.hwndCaret
, 0, (POINT
*)&info
.rcCaret
, 2);
413 if (range
->length
&& info
.rcCaret
.left
== info
.rcCaret
.right
) info
.rcCaret
.right
++;
414 query
->ime_char_rect
.rect
= cgrect_from_rect(info
.rcCaret
);
417 TRACE_(imm
)(" -> %s range %ld-%ld rect %s\n", ret
? "TRUE" : "FALSE", range
->location
,
418 range
->length
, wine_dbgstr_cgrect(query
->ime_char_rect
.rect
));
424 /***********************************************************************
425 * NotifyIMEStatus (X11DRV.@)
427 void macdrv_NotifyIMEStatus( HWND hwnd
, UINT status
)
429 TRACE_(imm
)( "hwnd %p, status %#x\n", hwnd
, status
);
430 if (!status
) macdrv_clear_ime_text();
434 /***********************************************************************
437 * Handler for QUERY_EVENT and QUERY_EVENT_NO_PREEMPT_WAIT queries.
439 static void macdrv_query_event(HWND hwnd
, const macdrv_event
*event
)
441 BOOL success
= FALSE
;
442 macdrv_query
*query
= event
->query_event
.query
;
446 case QUERY_DRAG_DROP
:
447 TRACE("QUERY_DRAG_DROP\n");
448 success
= query_drag_drop(query
);
450 case QUERY_DRAG_EXITED
:
451 TRACE("QUERY_DRAG_EXITED\n");
452 success
= query_drag_exited(query
);
454 case QUERY_DRAG_OPERATION
:
455 TRACE("QUERY_DRAG_OPERATION\n");
456 success
= query_drag_operation(query
);
458 case QUERY_IME_CHAR_RECT
:
459 TRACE("QUERY_IME_CHAR_RECT\n");
460 success
= query_ime_char_rect(query
);
462 case QUERY_PASTEBOARD_DATA
:
463 TRACE("QUERY_PASTEBOARD_DATA\n");
464 success
= query_pasteboard_data(hwnd
, query
->pasteboard_data
.type
);
466 case QUERY_RESIZE_SIZE
:
467 TRACE("QUERY_RESIZE_SIZE\n");
468 success
= query_resize_size(hwnd
, query
);
470 case QUERY_RESIZE_START
:
471 TRACE("QUERY_RESIZE_START\n");
472 success
= query_resize_start(hwnd
);
474 case QUERY_MIN_MAX_INFO
:
475 TRACE("QUERY_MIN_MAX_INFO\n");
476 success
= query_min_max_info(hwnd
);
479 FIXME("unrecognized query type %d\n", query
->type
);
483 TRACE("success %d\n", success
);
484 query
->status
= success
;
485 macdrv_set_query_done(query
);
489 /***********************************************************************
490 * macdrv_handle_event
492 void macdrv_handle_event(const macdrv_event
*event
)
494 HWND hwnd
= macdrv_get_window_hwnd(event
->window
);
495 const macdrv_event
*prev
;
496 struct macdrv_thread_data
*thread_data
= macdrv_thread_data();
498 TRACE("%s for hwnd/window %p/%p\n", dbgstr_event(event
->type
), hwnd
,
501 prev
= thread_data
->current_event
;
502 thread_data
->current_event
= event
;
507 macdrv_app_activated();
509 case APP_DEACTIVATED
:
510 macdrv_app_deactivated();
512 case APP_QUIT_REQUESTED
:
513 macdrv_app_quit_requested(event
);
515 case DISPLAYS_CHANGED
:
516 macdrv_displays_changed(event
);
519 macdrv_hotkey_press(event
);
522 macdrv_im_set_text(event
);
526 macdrv_key_event(hwnd
, event
);
528 case KEYBOARD_CHANGED
:
529 macdrv_keyboard_changed(event
);
531 case LOST_PASTEBOARD_OWNERSHIP
:
532 macdrv_lost_pasteboard_ownership(hwnd
);
535 macdrv_mouse_button(hwnd
, event
);
537 case MOUSE_MOVED_RELATIVE
:
538 case MOUSE_MOVED_ABSOLUTE
:
539 macdrv_mouse_moved(hwnd
, event
);
542 macdrv_mouse_scroll(hwnd
, event
);
545 case QUERY_EVENT_NO_PREEMPT_WAIT
:
546 macdrv_query_event(hwnd
, event
);
548 case REASSERT_WINDOW_POSITION
:
549 macdrv_reassert_window_position(hwnd
);
551 case RELEASE_CAPTURE
:
552 macdrv_release_capture(hwnd
, event
);
554 case SENT_TEXT_INPUT
:
555 macdrv_sent_text_input(event
);
557 case STATUS_ITEM_MOUSE_BUTTON
:
558 macdrv_status_item_mouse_button(event
);
560 case STATUS_ITEM_MOUSE_MOVE
:
561 macdrv_status_item_mouse_move(event
);
563 case WINDOW_BROUGHT_FORWARD
:
564 macdrv_window_brought_forward(hwnd
);
566 case WINDOW_CLOSE_REQUESTED
:
567 macdrv_window_close_requested(hwnd
);
569 case WINDOW_DID_MINIMIZE
:
570 macdrv_window_did_minimize(hwnd
);
572 case WINDOW_DID_UNMINIMIZE
:
573 macdrv_window_did_unminimize(hwnd
);
575 case WINDOW_DRAG_BEGIN
:
576 macdrv_window_drag_begin(hwnd
, event
);
578 case WINDOW_DRAG_END
:
579 macdrv_window_drag_end(hwnd
);
581 case WINDOW_FRAME_CHANGED
:
582 macdrv_window_frame_changed(hwnd
, event
);
584 case WINDOW_GOT_FOCUS
:
585 macdrv_window_got_focus(hwnd
, event
);
587 case WINDOW_LOST_FOCUS
:
588 macdrv_window_lost_focus(hwnd
, event
);
590 case WINDOW_MAXIMIZE_REQUESTED
:
591 macdrv_window_maximize_requested(hwnd
);
593 case WINDOW_MINIMIZE_REQUESTED
:
594 macdrv_window_minimize_requested(hwnd
);
596 case WINDOW_RESIZE_ENDED
:
597 macdrv_window_resize_ended(hwnd
);
599 case WINDOW_RESTORE_REQUESTED
:
600 macdrv_window_restore_requested(hwnd
, event
);
603 TRACE(" ignoring\n");
607 thread_data
->current_event
= prev
;
611 /***********************************************************************
614 static int process_events(macdrv_event_queue queue
, macdrv_event_mask mask
)
619 while (macdrv_copy_event_from_queue(queue
, mask
, &event
))
622 macdrv_handle_event(event
);
623 macdrv_release_event(event
);
625 if (count
) TRACE("processed %d events\n", count
);
630 /***********************************************************************
631 * ProcessEvents (MACDRV.@)
633 BOOL
macdrv_ProcessEvents(DWORD mask
)
635 struct macdrv_thread_data
*data
= macdrv_thread_data();
636 macdrv_event_mask event_mask
= get_event_mask(mask
);
638 TRACE("mask %x\n", (unsigned int)mask
);
640 if (!data
) return FALSE
;
642 if (data
->current_event
&& data
->current_event
->type
!= QUERY_EVENT
&&
643 data
->current_event
->type
!= QUERY_EVENT_NO_PREEMPT_WAIT
&&
644 data
->current_event
->type
!= APP_QUIT_REQUESTED
&&
645 data
->current_event
->type
!= WINDOW_DRAG_BEGIN
)
646 event_mask
= 0; /* don't process nested events */
648 return process_events(data
->queue
, event_mask
);