winemac: Return the caret position in query_ime_char_rect.
[wine.git] / dlls / winemac.drv / event.c
blob11f5dd3314cfdb79c001ef330bd295f414ee7baa
1 /*
2 * MACDRV event driver
4 * Copyright 1993 Alexandre Julliard
5 * 1999 Noel Borthwick
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
23 #if 0
24 #pragma makedep unix
25 #endif
27 #include "config.h"
29 #include "ntstatus.h"
30 #define WIN32_NO_STATUS
31 #include "macdrv.h"
32 #include "oleidl.h"
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.
48 struct ime_update
50 DWORD cursor_pos;
51 WCHAR *comp_str;
52 WCHAR *result_str;
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[] = {
60 "APP_ACTIVATED",
61 "APP_DEACTIVATED",
62 "APP_QUIT_REQUESTED",
63 "DISPLAYS_CHANGED",
64 "HOTKEY_PRESS",
65 "IM_SET_TEXT",
66 "KEY_PRESS",
67 "KEY_RELEASE",
68 "KEYBOARD_CHANGED",
69 "LOST_PASTEBOARD_OWNERSHIP",
70 "MOUSE_BUTTON",
71 "MOUSE_MOVED_RELATIVE",
72 "MOUSE_MOVED_ABSOLUTE",
73 "MOUSE_SCROLL",
74 "QUERY_EVENT",
75 "QUERY_EVENT_NO_PREEMPT_WAIT",
76 "REASSERT_WINDOW_POSITION",
77 "RELEASE_CAPTURE",
78 "SENT_TEXT_INPUT",
79 "STATUS_ITEM_MOUSE_BUTTON",
80 "STATUS_ITEM_MOUSE_MOVE",
81 "WINDOW_BROUGHT_FORWARD",
82 "WINDOW_CLOSE_REQUESTED",
83 "WINDOW_DID_UNMINIMIZE",
84 "WINDOW_DRAG_BEGIN",
85 "WINDOW_DRAG_END",
86 "WINDOW_FRAME_CHANGED",
87 "WINDOW_GOT_FOCUS",
88 "WINDOW_LOST_FOCUS",
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 /***********************************************************************
101 * get_event_mask
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);
112 if (mask & QS_KEY)
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);
164 return event_mask;
168 /***********************************************************************
169 * macdrv_im_set_text
171 static void macdrv_im_set_text(const macdrv_event *event)
173 HWND hwnd = macdrv_get_window_hwnd(event->window);
174 CFIndex length = 0;
175 WCHAR *text = NULL;
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);
185 text[length] = 0;
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;
198 else
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;
222 void *dst;
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;
227 else
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;
236 else
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;
294 return 0;
298 /**************************************************************************
299 * drag_operations_to_dropeffects
301 static DWORD drag_operations_to_dropeffects(uint32_t ops)
303 DWORD effects = 0;
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;
310 return effects;
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;
325 return DRAG_OP_NONE;
329 /**************************************************************************
330 * query_drag_drop
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;
338 if (!data)
340 WARN("no win_data for win %p/%p\n", hwnd, query->window);
341 return FALSE;
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, &params, sizeof(params));
353 /**************************************************************************
354 * query_drag_exited
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, &params, 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);
372 DWORD effect;
374 if (!data)
376 WARN("no win_data for win %p/%p\n", hwnd, query->window);
377 return FALSE;
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, &params, sizeof(params));
388 if (!effect) return FALSE;
390 query->drag_operation.accepted_op = dropeffect_to_drag_operation(effect,
391 query->drag_operation.offered_ops);
392 return TRUE;
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)};
405 BOOL ret = FALSE;
407 TRACE_(imm)("win %p/%p himc %p range %ld-%ld\n", hwnd, query->window, himc, range->location,
408 range->length);
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));
420 return ret;
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 /***********************************************************************
435 * macdrv_query_event
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;
444 switch (query->type)
446 case QUERY_DRAG_DROP:
447 TRACE("QUERY_DRAG_DROP\n");
448 success = query_drag_drop(query);
449 break;
450 case QUERY_DRAG_EXITED:
451 TRACE("QUERY_DRAG_EXITED\n");
452 success = query_drag_exited(query);
453 break;
454 case QUERY_DRAG_OPERATION:
455 TRACE("QUERY_DRAG_OPERATION\n");
456 success = query_drag_operation(query);
457 break;
458 case QUERY_IME_CHAR_RECT:
459 TRACE("QUERY_IME_CHAR_RECT\n");
460 success = query_ime_char_rect(query);
461 break;
462 case QUERY_PASTEBOARD_DATA:
463 TRACE("QUERY_PASTEBOARD_DATA\n");
464 success = query_pasteboard_data(hwnd, query->pasteboard_data.type);
465 break;
466 case QUERY_RESIZE_SIZE:
467 TRACE("QUERY_RESIZE_SIZE\n");
468 success = query_resize_size(hwnd, query);
469 break;
470 case QUERY_RESIZE_START:
471 TRACE("QUERY_RESIZE_START\n");
472 success = query_resize_start(hwnd);
473 break;
474 case QUERY_MIN_MAX_INFO:
475 TRACE("QUERY_MIN_MAX_INFO\n");
476 success = query_min_max_info(hwnd);
477 break;
478 default:
479 FIXME("unrecognized query type %d\n", query->type);
480 break;
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,
499 event->window);
501 prev = thread_data->current_event;
502 thread_data->current_event = event;
504 switch (event->type)
506 case APP_ACTIVATED:
507 macdrv_app_activated();
508 break;
509 case APP_DEACTIVATED:
510 macdrv_app_deactivated();
511 break;
512 case APP_QUIT_REQUESTED:
513 macdrv_app_quit_requested(event);
514 break;
515 case DISPLAYS_CHANGED:
516 macdrv_displays_changed(event);
517 break;
518 case HOTKEY_PRESS:
519 macdrv_hotkey_press(event);
520 break;
521 case IM_SET_TEXT:
522 macdrv_im_set_text(event);
523 break;
524 case KEY_PRESS:
525 case KEY_RELEASE:
526 macdrv_key_event(hwnd, event);
527 break;
528 case KEYBOARD_CHANGED:
529 macdrv_keyboard_changed(event);
530 break;
531 case LOST_PASTEBOARD_OWNERSHIP:
532 macdrv_lost_pasteboard_ownership(hwnd);
533 break;
534 case MOUSE_BUTTON:
535 macdrv_mouse_button(hwnd, event);
536 break;
537 case MOUSE_MOVED_RELATIVE:
538 case MOUSE_MOVED_ABSOLUTE:
539 macdrv_mouse_moved(hwnd, event);
540 break;
541 case MOUSE_SCROLL:
542 macdrv_mouse_scroll(hwnd, event);
543 break;
544 case QUERY_EVENT:
545 case QUERY_EVENT_NO_PREEMPT_WAIT:
546 macdrv_query_event(hwnd, event);
547 break;
548 case REASSERT_WINDOW_POSITION:
549 macdrv_reassert_window_position(hwnd);
550 break;
551 case RELEASE_CAPTURE:
552 macdrv_release_capture(hwnd, event);
553 break;
554 case SENT_TEXT_INPUT:
555 macdrv_sent_text_input(event);
556 break;
557 case STATUS_ITEM_MOUSE_BUTTON:
558 macdrv_status_item_mouse_button(event);
559 break;
560 case STATUS_ITEM_MOUSE_MOVE:
561 macdrv_status_item_mouse_move(event);
562 break;
563 case WINDOW_BROUGHT_FORWARD:
564 macdrv_window_brought_forward(hwnd);
565 break;
566 case WINDOW_CLOSE_REQUESTED:
567 macdrv_window_close_requested(hwnd);
568 break;
569 case WINDOW_DID_MINIMIZE:
570 macdrv_window_did_minimize(hwnd);
571 break;
572 case WINDOW_DID_UNMINIMIZE:
573 macdrv_window_did_unminimize(hwnd);
574 break;
575 case WINDOW_DRAG_BEGIN:
576 macdrv_window_drag_begin(hwnd, event);
577 break;
578 case WINDOW_DRAG_END:
579 macdrv_window_drag_end(hwnd);
580 break;
581 case WINDOW_FRAME_CHANGED:
582 macdrv_window_frame_changed(hwnd, event);
583 break;
584 case WINDOW_GOT_FOCUS:
585 macdrv_window_got_focus(hwnd, event);
586 break;
587 case WINDOW_LOST_FOCUS:
588 macdrv_window_lost_focus(hwnd, event);
589 break;
590 case WINDOW_MAXIMIZE_REQUESTED:
591 macdrv_window_maximize_requested(hwnd);
592 break;
593 case WINDOW_MINIMIZE_REQUESTED:
594 macdrv_window_minimize_requested(hwnd);
595 break;
596 case WINDOW_RESIZE_ENDED:
597 macdrv_window_resize_ended(hwnd);
598 break;
599 case WINDOW_RESTORE_REQUESTED:
600 macdrv_window_restore_requested(hwnd, event);
601 break;
602 default:
603 TRACE(" ignoring\n");
604 break;
607 thread_data->current_event = prev;
611 /***********************************************************************
612 * process_events
614 static int process_events(macdrv_event_queue queue, macdrv_event_mask mask)
616 macdrv_event *event;
617 int count = 0;
619 while (macdrv_copy_event_from_queue(queue, mask, &event))
621 count++;
622 macdrv_handle_event(event);
623 macdrv_release_event(event);
625 if (count) TRACE("processed %d events\n", count);
626 return 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);