2 * The IME for interfacing with Mac input methods
4 * Copyright 2008, 2013 CodeWeavers, Aric Stewart
5 * Copyright 2013 Ken Thomases for CodeWeavers Inc.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 * The normal flow for IMM/IME Processing is as follows.
25 * 1) The Keyboard Driver generates key messages which are first passed to
26 * the IMM and then to IME via ImeProcessKey. If the IME returns 0 then
27 * it does not want the key and the keyboard driver then generates the
28 * WM_KEYUP/WM_KEYDOWN messages. However if the IME is going to process the
29 * key it returns non-zero.
30 * 2) If the IME is going to process the key then the IMM calls ImeToAsciiEx to
31 * process the key. the IME modifies the HIMC structure to reflect the
32 * current state and generates any messages it needs the IMM to process.
33 * 3) IMM checks the messages and send them to the application in question. From
34 * here the IMM level deals with if the application is IME aware or not.
37 #include "macdrv_dll.h"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(imm
);
44 #define FROM_MACDRV ((HIMC)0xcafe1337)
46 typedef struct ime_private
54 } IMEPRIVATE
, *LPIMEPRIVATE
;
56 static const WCHAR UI_CLASS_NAME
[] = {'W','i','n','e',' ','M','a','c',' ','I','M','E',0};
58 static HIMC
*hSelectedFrom
= NULL
;
59 static INT hSelectedCount
= 0;
62 static UINT WM_MSIME_SERVICE
;
63 static UINT WM_MSIME_RECONVERTOPTIONS
;
64 static UINT WM_MSIME_MOUSE
;
65 static UINT WM_MSIME_RECONVERTREQUEST
;
66 static UINT WM_MSIME_RECONVERT
;
67 static UINT WM_MSIME_QUERYPOSITION
;
68 static UINT WM_MSIME_DOCUMENTFEED
;
70 static WCHAR
*input_context_get_comp_str( INPUTCONTEXT
*ctx
, BOOL result
, UINT
*length
)
72 COMPOSITIONSTRING
*string
;
76 if (!(string
= ImmLockIMCC( ctx
->hCompStr
))) return NULL
;
77 len
= result
? string
->dwResultStrLen
: string
->dwCompStrLen
;
78 off
= result
? string
->dwResultStrOffset
: string
->dwCompStrOffset
;
80 if (len
&& off
&& (text
= malloc( (len
+ 1) * sizeof(WCHAR
) )))
82 memcpy( text
, (BYTE
*)string
+ off
, len
* sizeof(WCHAR
) );
87 ImmUnlockIMCC( ctx
->hCompStr
);
91 static HWND
input_context_get_ui_hwnd( INPUTCONTEXT
*ctx
)
93 struct ime_private
*priv
;
95 if (!(priv
= ImmLockIMCC( ctx
->hPrivate
))) return NULL
;
96 hwnd
= priv
->hwndDefault
;
97 ImmUnlockIMCC( ctx
->hPrivate
);
101 static HFONT
input_context_select_ui_font( INPUTCONTEXT
*ctx
, HDC hdc
)
103 struct ime_private
*priv
;
105 if (!(priv
= ImmLockIMCC( ctx
->hPrivate
))) return NULL
;
106 if (priv
->textfont
) font
= SelectObject( hdc
, priv
->textfont
);
107 ImmUnlockIMCC( ctx
->hPrivate
);
111 static HIMC
RealIMC(HIMC hIMC
)
113 if (hIMC
== FROM_MACDRV
)
116 HWND wnd
= GetFocus();
117 HIMC winHimc
= ImmGetContext(wnd
);
118 for (i
= 0; i
< hSelectedCount
; i
++)
119 if (winHimc
== hSelectedFrom
[i
])
127 static LPINPUTCONTEXT
LockRealIMC(HIMC hIMC
)
129 HIMC real_imc
= RealIMC(hIMC
);
131 return ImmLockIMC(real_imc
);
136 static BOOL
UnlockRealIMC(HIMC hIMC
)
138 HIMC real_imc
= RealIMC(hIMC
);
140 return ImmUnlockIMC(real_imc
);
145 static HIMCC
ImeCreateBlankCompStr(void)
148 LPCOMPOSITIONSTRING ptr
;
149 rc
= ImmCreateIMCC(sizeof(COMPOSITIONSTRING
));
150 ptr
= ImmLockIMCC(rc
);
151 memset(ptr
, 0, sizeof(COMPOSITIONSTRING
));
152 ptr
->dwSize
= sizeof(COMPOSITIONSTRING
);
157 static int updateField(DWORD origLen
, DWORD origOffset
, DWORD currentOffset
,
158 LPBYTE target
, LPBYTE source
, DWORD
* lenParam
,
159 DWORD
* offsetParam
, BOOL wchars
)
161 if (origLen
> 0 && origOffset
> 0)
163 int truelen
= origLen
;
165 truelen
*= sizeof(WCHAR
);
167 memcpy(&target
[currentOffset
], &source
[origOffset
], truelen
);
170 *offsetParam
= currentOffset
;
171 currentOffset
+= truelen
;
173 return currentOffset
;
176 static HIMCC
updateCompStr(HIMCC old
, LPCWSTR compstr
, DWORD len
, DWORD
*flags
)
178 /* We need to make sure the CompStr, CompClause and CompAttr fields are all
179 * set and correct. */
182 LPBYTE newdata
= NULL
;
183 LPBYTE olddata
= NULL
;
184 LPCOMPOSITIONSTRING new_one
;
185 LPCOMPOSITIONSTRING lpcs
= NULL
;
186 INT current_offset
= 0;
188 TRACE("%s, %li\n", debugstr_wn(compstr
, len
), len
);
190 if (old
== NULL
&& compstr
== NULL
&& len
== 0)
193 if (compstr
== NULL
&& len
!= 0)
195 ERR("compstr is NULL however we have a len! Please report\n");
201 olddata
= ImmLockIMCC(old
);
202 lpcs
= (LPCOMPOSITIONSTRING
)olddata
;
205 needed_size
= sizeof(COMPOSITIONSTRING
) + len
* sizeof(WCHAR
) +
206 len
+ sizeof(DWORD
) * 2;
210 needed_size
+= lpcs
->dwCompReadAttrLen
;
211 needed_size
+= lpcs
->dwCompReadClauseLen
;
212 needed_size
+= lpcs
->dwCompReadStrLen
* sizeof(WCHAR
);
213 needed_size
+= lpcs
->dwResultReadClauseLen
;
214 needed_size
+= lpcs
->dwResultReadStrLen
* sizeof(WCHAR
);
215 needed_size
+= lpcs
->dwResultClauseLen
;
216 needed_size
+= lpcs
->dwResultStrLen
* sizeof(WCHAR
);
217 needed_size
+= lpcs
->dwPrivateSize
;
219 rc
= ImmCreateIMCC(needed_size
);
220 newdata
= ImmLockIMCC(rc
);
221 new_one
= (LPCOMPOSITIONSTRING
)newdata
;
223 new_one
->dwSize
= needed_size
;
224 current_offset
= sizeof(COMPOSITIONSTRING
);
227 current_offset
= updateField(lpcs
->dwCompReadAttrLen
,
228 lpcs
->dwCompReadAttrOffset
,
229 current_offset
, newdata
, olddata
,
230 &new_one
->dwCompReadAttrLen
,
231 &new_one
->dwCompReadAttrOffset
, FALSE
);
233 current_offset
= updateField(lpcs
->dwCompReadClauseLen
,
234 lpcs
->dwCompReadClauseOffset
,
235 current_offset
, newdata
, olddata
,
236 &new_one
->dwCompReadClauseLen
,
237 &new_one
->dwCompReadClauseOffset
, FALSE
);
239 current_offset
= updateField(lpcs
->dwCompReadStrLen
,
240 lpcs
->dwCompReadStrOffset
,
241 current_offset
, newdata
, olddata
,
242 &new_one
->dwCompReadStrLen
,
243 &new_one
->dwCompReadStrOffset
, TRUE
);
245 /* new CompAttr, CompClause, CompStr, dwCursorPos */
246 new_one
->dwDeltaStart
= 0;
247 new_one
->dwCursorPos
= lpcs
->dwCursorPos
;
249 current_offset
= updateField(lpcs
->dwResultReadClauseLen
,
250 lpcs
->dwResultReadClauseOffset
,
251 current_offset
, newdata
, olddata
,
252 &new_one
->dwResultReadClauseLen
,
253 &new_one
->dwResultReadClauseOffset
, FALSE
);
255 current_offset
= updateField(lpcs
->dwResultReadStrLen
,
256 lpcs
->dwResultReadStrOffset
,
257 current_offset
, newdata
, olddata
,
258 &new_one
->dwResultReadStrLen
,
259 &new_one
->dwResultReadStrOffset
, TRUE
);
261 current_offset
= updateField(lpcs
->dwResultClauseLen
,
262 lpcs
->dwResultClauseOffset
,
263 current_offset
, newdata
, olddata
,
264 &new_one
->dwResultClauseLen
,
265 &new_one
->dwResultClauseOffset
, FALSE
);
267 current_offset
= updateField(lpcs
->dwResultStrLen
,
268 lpcs
->dwResultStrOffset
,
269 current_offset
, newdata
, olddata
,
270 &new_one
->dwResultStrLen
,
271 &new_one
->dwResultStrOffset
, TRUE
);
273 current_offset
= updateField(lpcs
->dwPrivateSize
,
274 lpcs
->dwPrivateOffset
,
275 current_offset
, newdata
, olddata
,
276 &new_one
->dwPrivateSize
,
277 &new_one
->dwPrivateOffset
, FALSE
);
281 new_one
->dwCursorPos
= len
;
282 *flags
|= GCS_CURSORPOS
;
287 new_one
->dwCompAttrLen
= len
;
290 new_one
->dwCompAttrOffset
= current_offset
;
291 memset(&newdata
[current_offset
], ATTR_INPUT
, len
);
292 current_offset
+= len
;
298 new_one
->dwCompClauseLen
= sizeof(DWORD
) * 2;
299 new_one
->dwCompClauseOffset
= current_offset
;
300 *(DWORD
*)&newdata
[current_offset
] = 0;
301 current_offset
+= sizeof(DWORD
);
302 *(DWORD
*)&newdata
[current_offset
] = len
;
303 current_offset
+= sizeof(DWORD
);
306 new_one
->dwCompClauseLen
= 0;
309 new_one
->dwCompStrLen
= len
;
312 new_one
->dwCompStrOffset
= current_offset
;
313 memcpy(&newdata
[current_offset
], compstr
, len
* sizeof(WCHAR
));
324 static HIMCC
updateResultStr(HIMCC old
, LPWSTR resultstr
, DWORD len
)
326 /* we need to make sure the ResultStr and ResultClause fields are all
330 LPBYTE newdata
= NULL
;
331 LPBYTE olddata
= NULL
;
332 LPCOMPOSITIONSTRING new_one
;
333 LPCOMPOSITIONSTRING lpcs
= NULL
;
334 INT current_offset
= 0;
336 TRACE("%s, %li\n", debugstr_wn(resultstr
, len
), len
);
338 if (old
== NULL
&& resultstr
== NULL
&& len
== 0)
341 if (resultstr
== NULL
&& len
!= 0)
343 ERR("resultstr is NULL however we have a len! Please report\n");
349 olddata
= ImmLockIMCC(old
);
350 lpcs
= (LPCOMPOSITIONSTRING
)olddata
;
353 needed_size
= sizeof(COMPOSITIONSTRING
) + len
* sizeof(WCHAR
) +
358 needed_size
+= lpcs
->dwCompReadAttrLen
;
359 needed_size
+= lpcs
->dwCompReadClauseLen
;
360 needed_size
+= lpcs
->dwCompReadStrLen
* sizeof(WCHAR
);
361 needed_size
+= lpcs
->dwCompAttrLen
;
362 needed_size
+= lpcs
->dwCompClauseLen
;
363 needed_size
+= lpcs
->dwCompStrLen
* sizeof(WCHAR
);
364 needed_size
+= lpcs
->dwResultReadClauseLen
;
365 needed_size
+= lpcs
->dwResultReadStrLen
* sizeof(WCHAR
);
366 needed_size
+= lpcs
->dwPrivateSize
;
368 rc
= ImmCreateIMCC(needed_size
);
369 newdata
= ImmLockIMCC(rc
);
370 new_one
= (LPCOMPOSITIONSTRING
)newdata
;
372 new_one
->dwSize
= needed_size
;
373 current_offset
= sizeof(COMPOSITIONSTRING
);
376 current_offset
= updateField(lpcs
->dwCompReadAttrLen
,
377 lpcs
->dwCompReadAttrOffset
,
378 current_offset
, newdata
, olddata
,
379 &new_one
->dwCompReadAttrLen
,
380 &new_one
->dwCompReadAttrOffset
, FALSE
);
382 current_offset
= updateField(lpcs
->dwCompReadClauseLen
,
383 lpcs
->dwCompReadClauseOffset
,
384 current_offset
, newdata
, olddata
,
385 &new_one
->dwCompReadClauseLen
,
386 &new_one
->dwCompReadClauseOffset
, FALSE
);
388 current_offset
= updateField(lpcs
->dwCompReadStrLen
,
389 lpcs
->dwCompReadStrOffset
,
390 current_offset
, newdata
, olddata
,
391 &new_one
->dwCompReadStrLen
,
392 &new_one
->dwCompReadStrOffset
, TRUE
);
394 current_offset
= updateField(lpcs
->dwCompAttrLen
,
395 lpcs
->dwCompAttrOffset
,
396 current_offset
, newdata
, olddata
,
397 &new_one
->dwCompAttrLen
,
398 &new_one
->dwCompAttrOffset
, FALSE
);
400 current_offset
= updateField(lpcs
->dwCompClauseLen
,
401 lpcs
->dwCompClauseOffset
,
402 current_offset
, newdata
, olddata
,
403 &new_one
->dwCompClauseLen
,
404 &new_one
->dwCompClauseOffset
, FALSE
);
406 current_offset
= updateField(lpcs
->dwCompStrLen
,
407 lpcs
->dwCompStrOffset
,
408 current_offset
, newdata
, olddata
,
409 &new_one
->dwCompStrLen
,
410 &new_one
->dwCompStrOffset
, TRUE
);
412 new_one
->dwCursorPos
= lpcs
->dwCursorPos
;
413 new_one
->dwDeltaStart
= 0;
415 current_offset
= updateField(lpcs
->dwResultReadClauseLen
,
416 lpcs
->dwResultReadClauseOffset
,
417 current_offset
, newdata
, olddata
,
418 &new_one
->dwResultReadClauseLen
,
419 &new_one
->dwResultReadClauseOffset
, FALSE
);
421 current_offset
= updateField(lpcs
->dwResultReadStrLen
,
422 lpcs
->dwResultReadStrOffset
,
423 current_offset
, newdata
, olddata
,
424 &new_one
->dwResultReadStrLen
,
425 &new_one
->dwResultReadStrOffset
, TRUE
);
427 /* new ResultClause , ResultStr */
429 current_offset
= updateField(lpcs
->dwPrivateSize
,
430 lpcs
->dwPrivateOffset
,
431 current_offset
, newdata
, olddata
,
432 &new_one
->dwPrivateSize
,
433 &new_one
->dwPrivateOffset
, FALSE
);
440 new_one
->dwResultClauseLen
= sizeof(DWORD
) * 2;
441 new_one
->dwResultClauseOffset
= current_offset
;
442 *(DWORD
*)&newdata
[current_offset
] = 0;
443 current_offset
+= sizeof(DWORD
);
444 *(DWORD
*)&newdata
[current_offset
] = len
;
445 current_offset
+= sizeof(DWORD
);
448 new_one
->dwResultClauseLen
= 0;
451 new_one
->dwResultStrLen
= len
;
454 new_one
->dwResultStrOffset
= current_offset
;
455 memcpy(&newdata
[current_offset
], resultstr
, len
* sizeof(WCHAR
));
464 static void GenerateIMEMessage(HIMC hIMC
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
466 LPINPUTCONTEXT lpIMC
;
467 LPTRANSMSG lpTransMsg
;
469 lpIMC
= LockRealIMC(hIMC
);
473 lpIMC
->hMsgBuf
= ImmReSizeIMCC(lpIMC
->hMsgBuf
, (lpIMC
->dwNumMsgBuf
+ 1) * sizeof(TRANSMSG
));
477 lpTransMsg
= ImmLockIMCC(lpIMC
->hMsgBuf
);
481 lpTransMsg
+= lpIMC
->dwNumMsgBuf
;
482 lpTransMsg
->message
= msg
;
483 lpTransMsg
->wParam
= wParam
;
484 lpTransMsg
->lParam
= lParam
;
486 ImmUnlockIMCC(lpIMC
->hMsgBuf
);
487 lpIMC
->dwNumMsgBuf
++;
489 ImmGenerateMessage(RealIMC(hIMC
));
493 static BOOL
GenerateMessageToTransKey(TRANSMSGLIST
*lpTransBuf
, UINT
*uNumTranMsgs
,
494 UINT msg
, WPARAM wParam
, LPARAM lParam
)
498 if (*uNumTranMsgs
+ 1 >= lpTransBuf
->uMsgCount
)
501 ptr
= lpTransBuf
->TransMsg
+ *uNumTranMsgs
;
503 ptr
->wParam
= wParam
;
504 ptr
->lParam
= lParam
;
511 static BOOL
IME_RemoveFromSelected(HIMC hIMC
)
514 for (i
= 0; i
< hSelectedCount
; i
++)
516 if (hSelectedFrom
[i
] == hIMC
)
518 if (i
< hSelectedCount
- 1)
519 memmove(&hSelectedFrom
[i
], &hSelectedFrom
[i
+ 1], (hSelectedCount
- i
- 1) * sizeof(HIMC
));
527 static void IME_AddToSelected(HIMC hIMC
)
531 hSelectedFrom
= HeapReAlloc(GetProcessHeap(), 0, hSelectedFrom
, hSelectedCount
* sizeof(HIMC
));
533 hSelectedFrom
= HeapAlloc(GetProcessHeap(), 0, sizeof(HIMC
));
534 hSelectedFrom
[hSelectedCount
- 1] = hIMC
;
537 static void UpdateDataInDefaultIMEWindow(INPUTCONTEXT
*lpIMC
, HWND hwnd
, BOOL showable
)
539 LPCOMPOSITIONSTRING compstr
;
542 compstr
= ImmLockIMCC(lpIMC
->hCompStr
);
546 if (compstr
== NULL
|| compstr
->dwCompStrLen
== 0)
547 ShowWindow(hwnd
, SW_HIDE
);
549 ShowWindow(hwnd
, SW_SHOWNOACTIVATE
);
551 RedrawWindow(hwnd
, NULL
, NULL
, RDW_ERASENOW
| RDW_INVALIDATE
);
554 ImmUnlockIMCC(lpIMC
->hCompStr
);
557 BOOL WINAPI
ImeDestroy(UINT uForce
)
560 HeapFree(GetProcessHeap(), 0, hSelectedFrom
);
561 hSelectedFrom
= NULL
;
566 BOOL WINAPI
ImeProcessKey(HIMC hIMC
, UINT vKey
, LPARAM lKeyData
, const LPBYTE lpbKeyState
)
568 LPINPUTCONTEXT lpIMC
;
571 TRACE("hIMC %p vKey 0x%04x lKeyData 0x%08Ix lpbKeyState %p\n", hIMC
, vKey
, lKeyData
, lpbKeyState
);
582 inIME
= MACDRV_CALL(ime_using_input_method
, NULL
);
583 lpIMC
= LockRealIMC(hIMC
);
586 LPIMEPRIVATE myPrivate
;
587 HWND hwnd
= input_context_get_ui_hwnd( lpIMC
);
588 myPrivate
= ImmLockIMCC(lpIMC
->hPrivate
);
590 if (inIME
&& !myPrivate
->bInternalState
)
591 ImmSetOpenStatus(RealIMC(FROM_MACDRV
), TRUE
);
592 else if (!inIME
&& myPrivate
->bInternalState
)
594 ShowWindow( hwnd
, SW_HIDE
);
595 ImmDestroyIMCC(lpIMC
->hCompStr
);
596 lpIMC
->hCompStr
= ImeCreateBlankCompStr();
597 ImmSetOpenStatus(RealIMC(FROM_MACDRV
), FALSE
);
600 myPrivate
->repeat
= (lKeyData
>> 30) & 0x1;
602 myPrivate
->bInternalState
= inIME
;
603 ImmUnlockIMCC(lpIMC
->hPrivate
);
610 BOOL WINAPI
ImeSelect(HIMC hIMC
, BOOL fSelect
)
612 LPINPUTCONTEXT lpIMC
;
613 TRACE("%p %s\n", hIMC
, fSelect
? "TRUE" : "FALSE");
615 if (hIMC
== FROM_MACDRV
)
617 ERR("ImeSelect should never be called from Cocoa\n");
626 return IME_RemoveFromSelected(hIMC
);
628 IME_AddToSelected(hIMC
);
630 /* Initialize our structures */
631 lpIMC
= LockRealIMC(hIMC
);
634 LPIMEPRIVATE myPrivate
;
635 myPrivate
= ImmLockIMCC(lpIMC
->hPrivate
);
636 if (myPrivate
->bInComposition
)
637 GenerateIMEMessage(hIMC
, WM_IME_ENDCOMPOSITION
, 0, 0);
638 if (myPrivate
->bInternalState
)
639 ImmSetOpenStatus(RealIMC(FROM_MACDRV
), FALSE
);
640 myPrivate
->bInComposition
= FALSE
;
641 myPrivate
->bInternalState
= FALSE
;
642 myPrivate
->textfont
= NULL
;
643 myPrivate
->hwndDefault
= NULL
;
644 myPrivate
->repeat
= 0;
645 ImmUnlockIMCC(lpIMC
->hPrivate
);
652 UINT WINAPI
ImeToAsciiEx(UINT uVKey
, UINT uScanCode
, const LPBYTE lpbKeyState
,
653 TRANSMSGLIST
*lpdwTransKey
, UINT fuState
, HIMC hIMC
)
655 struct process_text_input_params params
;
657 LPINPUTCONTEXT lpIMC
;
658 LPIMEPRIVATE myPrivate
;
663 TRACE("uVKey 0x%04x uScanCode 0x%04x fuState %u hIMC %p\n", uVKey
, uScanCode
, fuState
, hIMC
);
665 vkey
= LOWORD(uVKey
);
667 if (vkey
== VK_KANA
|| vkey
== VK_KANJI
|| vkey
== VK_MENU
)
669 TRACE("Skipping metakey\n");
673 lpIMC
= LockRealIMC(hIMC
);
674 hwnd
= input_context_get_ui_hwnd( lpIMC
);
675 myPrivate
= ImmLockIMCC(lpIMC
->hPrivate
);
676 if (!myPrivate
->bInternalState
)
678 ImmUnlockIMCC(lpIMC
->hPrivate
);
683 repeat
= myPrivate
->repeat
;
684 ImmUnlockIMCC(lpIMC
->hPrivate
);
687 TRACE("Processing Mac 0x%04x\n", vkey
);
688 params
.himc
= HandleToULong(hIMC
);
690 params
.scan
= uScanCode
;
691 params
.repeat
= repeat
;
692 params
.key_state
= lpbKeyState
;
694 MACDRV_CALL(ime_process_text_input
, ¶ms
);
697 MsgWaitForMultipleObjectsEx(0, NULL
, INFINITE
, QS_POSTMESSAGE
| QS_SENDMESSAGE
, 0);
702 UINT msg
= (uScanCode
& 0x8000) ? WM_KEYUP
: WM_KEYDOWN
;
704 /* KeyStroke not processed by the IME
705 * so we need to rebuild the KeyDown message and pass it on to WINE
707 if (!GenerateMessageToTransKey(lpdwTransKey
, &msgs
, msg
, vkey
, MAKELONG(0x0001, uScanCode
)))
708 GenerateIMEMessage(hIMC
, msg
, vkey
, MAKELONG(0x0001, uScanCode
));
712 else if ((lpIMC
= LockRealIMC(hIMC
)))
714 UpdateDataInDefaultIMEWindow( lpIMC
, hwnd
, FALSE
);
720 BOOL WINAPI
NotifyIME(HIMC hIMC
, DWORD dwAction
, DWORD dwIndex
, DWORD dwValue
)
723 LPINPUTCONTEXT lpIMC
;
725 TRACE("%p %li %li %li\n", hIMC
, dwAction
, dwIndex
, dwValue
);
727 lpIMC
= LockRealIMC(hIMC
);
733 case NI_OPENCANDIDATE
: FIXME("NI_OPENCANDIDATE\n"); break;
734 case NI_CLOSECANDIDATE
: FIXME("NI_CLOSECANDIDATE\n"); break;
735 case NI_SELECTCANDIDATESTR
: FIXME("NI_SELECTCANDIDATESTR\n"); break;
736 case NI_CHANGECANDIDATELIST
: FIXME("NI_CHANGECANDIDATELIST\n"); break;
737 case NI_SETCANDIDATE_PAGESTART
: FIXME("NI_SETCANDIDATE_PAGESTART\n"); break;
738 case NI_SETCANDIDATE_PAGESIZE
: FIXME("NI_SETCANDIDATE_PAGESIZE\n"); break;
739 case NI_CONTEXTUPDATED
:
742 case IMC_SETCOMPOSITIONWINDOW
: FIXME("NI_CONTEXTUPDATED: IMC_SETCOMPOSITIONWINDOW\n"); break;
743 case IMC_SETCONVERSIONMODE
: FIXME("NI_CONTEXTUPDATED: IMC_SETCONVERSIONMODE\n"); break;
744 case IMC_SETSENTENCEMODE
: FIXME("NI_CONTEXTUPDATED: IMC_SETSENTENCEMODE\n"); break;
745 case IMC_SETCANDIDATEPOS
: FIXME("NI_CONTEXTUPDATED: IMC_SETCANDIDATEPOS\n"); break;
746 case IMC_SETCOMPOSITIONFONT
:
748 LPIMEPRIVATE myPrivate
;
749 TRACE("NI_CONTEXTUPDATED: IMC_SETCOMPOSITIONFONT\n");
751 myPrivate
= ImmLockIMCC(lpIMC
->hPrivate
);
752 if (myPrivate
->textfont
)
754 DeleteObject(myPrivate
->textfont
);
755 myPrivate
->textfont
= NULL
;
757 myPrivate
->textfont
= CreateFontIndirectW(&lpIMC
->lfFont
.W
);
758 ImmUnlockIMCC(lpIMC
->hPrivate
);
761 case IMC_SETOPENSTATUS
:
763 LPIMEPRIVATE myPrivate
;
764 TRACE("NI_CONTEXTUPDATED: IMC_SETOPENSTATUS\n");
766 myPrivate
= ImmLockIMCC(lpIMC
->hPrivate
);
767 if (lpIMC
->fOpen
!= myPrivate
->bInternalState
&& myPrivate
->bInComposition
)
769 if(lpIMC
->fOpen
== FALSE
)
771 GenerateIMEMessage(hIMC
, WM_IME_ENDCOMPOSITION
, 0, 0);
772 myPrivate
->bInComposition
= FALSE
;
776 GenerateIMEMessage(hIMC
, WM_IME_STARTCOMPOSITION
, 0, 0);
777 GenerateIMEMessage(hIMC
, WM_IME_COMPOSITION
, 0, 0);
780 myPrivate
->bInternalState
= lpIMC
->fOpen
;
784 default: FIXME("NI_CONTEXTUPDATED: Unknown\n"); break;
787 case NI_COMPOSITIONSTR
:
793 LPIMEPRIVATE myPrivate
;
797 TRACE("NI_COMPOSITIONSTR: CPS_COMPLETE\n");
799 /* clear existing result */
800 newCompStr
= updateResultStr(lpIMC
->hCompStr
, NULL
, 0);
802 ImmDestroyIMCC(lpIMC
->hCompStr
);
803 lpIMC
->hCompStr
= newCompStr
;
805 myPrivate
= ImmLockIMCC(lpIMC
->hPrivate
);
806 if ((str
= input_context_get_comp_str( lpIMC
, FALSE
, &len
)))
808 WCHAR param
= str
[0];
809 DWORD flags
= GCS_COMPSTR
;
811 newCompStr
= updateResultStr( lpIMC
->hCompStr
, str
, len
);
812 ImmDestroyIMCC(lpIMC
->hCompStr
);
813 lpIMC
->hCompStr
= newCompStr
;
814 newCompStr
= updateCompStr(lpIMC
->hCompStr
, NULL
, 0, &flags
);
815 ImmDestroyIMCC(lpIMC
->hCompStr
);
816 lpIMC
->hCompStr
= newCompStr
;
818 GenerateIMEMessage(hIMC
, WM_IME_COMPOSITION
, 0, flags
);
820 GenerateIMEMessage(hIMC
, WM_IME_COMPOSITION
, param
,
821 GCS_RESULTSTR
| GCS_RESULTCLAUSE
);
823 GenerateIMEMessage(hIMC
, WM_IME_ENDCOMPOSITION
, 0, 0);
826 else if (myPrivate
->bInComposition
)
827 GenerateIMEMessage(hIMC
, WM_IME_ENDCOMPOSITION
, 0, 0);
830 myPrivate
->bInComposition
= FALSE
;
831 ImmUnlockIMCC(lpIMC
->hPrivate
);
836 case CPS_CONVERT
: FIXME("NI_COMPOSITIONSTR: CPS_CONVERT\n"); break;
837 case CPS_REVERT
: FIXME("NI_COMPOSITIONSTR: CPS_REVERT\n"); break;
840 LPIMEPRIVATE myPrivate
;
842 TRACE("NI_COMPOSITIONSTR: CPS_CANCEL\n");
844 MACDRV_CALL(ime_clear
, NULL
);
846 ImmDestroyIMCC(lpIMC
->hCompStr
);
848 lpIMC
->hCompStr
= ImeCreateBlankCompStr();
850 myPrivate
= ImmLockIMCC(lpIMC
->hPrivate
);
851 if (myPrivate
->bInComposition
)
853 GenerateIMEMessage(hIMC
, WM_IME_ENDCOMPOSITION
, 0, 0);
854 myPrivate
->bInComposition
= FALSE
;
856 ImmUnlockIMCC(lpIMC
->hPrivate
);
860 default: FIXME("NI_COMPOSITIONSTR: Unknown\n"); break;
863 default: FIXME("Unknown Message\n"); break;
870 static BOOL
IME_SetCompositionString(void* hIMC
, DWORD dwIndex
, LPCVOID lpComp
, DWORD dwCompLen
, DWORD cursor_pos
, BOOL cursor_valid
)
872 LPINPUTCONTEXT lpIMC
;
875 LPIMEPRIVATE myPrivate
;
876 BOOL sendMessage
= TRUE
;
878 TRACE("(%p, %ld, %p, %ld):\n", hIMC
, dwIndex
, lpComp
, dwCompLen
);
882 * this sets the composition string in the imm32.dll level
883 * of the composition buffer.
884 * TODO: set the Cocoa window's marked text string and tell text input context
887 lpIMC
= LockRealIMC(hIMC
);
892 myPrivate
= ImmLockIMCC(lpIMC
->hPrivate
);
894 if (dwIndex
== SCS_SETSTR
)
898 if (!myPrivate
->bInComposition
)
900 GenerateIMEMessage(hIMC
, WM_IME_STARTCOMPOSITION
, 0, 0);
901 myPrivate
->bInComposition
= TRUE
;
904 /* clear existing result */
905 newCompStr
= updateResultStr(lpIMC
->hCompStr
, NULL
, 0);
906 ImmDestroyIMCC(lpIMC
->hCompStr
);
907 lpIMC
->hCompStr
= newCompStr
;
911 if (dwCompLen
&& lpComp
)
913 newCompStr
= updateCompStr(lpIMC
->hCompStr
, (LPCWSTR
)lpComp
, dwCompLen
/ sizeof(WCHAR
), &flags
);
914 ImmDestroyIMCC(lpIMC
->hCompStr
);
915 lpIMC
->hCompStr
= newCompStr
;
917 wParam
= ((const WCHAR
*)lpComp
)[0];
918 flags
|= GCS_COMPCLAUSE
| GCS_COMPATTR
| GCS_DELTASTART
;
922 LPCOMPOSITIONSTRING compstr
;
923 compstr
= ImmLockIMCC(lpIMC
->hCompStr
);
924 compstr
->dwCursorPos
= cursor_pos
;
925 ImmUnlockIMCC(lpIMC
->hCompStr
);
926 flags
|= GCS_CURSORPOS
;
931 NotifyIME(hIMC
, NI_COMPOSITIONSTR
, CPS_CANCEL
, 0);
938 GenerateIMEMessage(hIMC
, WM_IME_COMPOSITION
, wParam
, flags
);
939 ImmUnlockIMCC(lpIMC
->hPrivate
);
946 BOOL WINAPI
ImeSetCompositionString(HIMC hIMC
, DWORD dwIndex
, LPCVOID lpComp
, DWORD dwCompLen
,
947 LPCVOID lpRead
, DWORD dwReadLen
)
949 TRACE("(%p, %ld, %p, %ld, %p, %ld):\n", hIMC
, dwIndex
, lpComp
, dwCompLen
, lpRead
, dwReadLen
);
951 if (lpRead
&& dwReadLen
)
952 FIXME("Reading string unimplemented\n");
954 return IME_SetCompositionString(hIMC
, dwIndex
, lpComp
, dwCompLen
, 0, FALSE
);
957 static void IME_NotifyComplete(void* hIMC
)
959 NotifyIME(hIMC
, NI_COMPOSITIONSTR
, CPS_COMPLETE
, 0);
963 * Internal functions to help with IME window management
965 static void PaintDefaultIMEWnd(HIMC hIMC
, HWND hwnd
)
971 MONITORINFO mon_info
;
972 INT offX
= 0, offY
= 0;
973 LPINPUTCONTEXT lpIMC
;
977 lpIMC
= ImmLockIMC(hIMC
);
981 hdc
= BeginPaint(hwnd
, &ps
);
983 GetClientRect(hwnd
, &rect
);
984 FillRect(hdc
, &rect
, (HBRUSH
)(COLOR_WINDOW
+ 1));
986 if ((str
= input_context_get_comp_str( lpIMC
, FALSE
, &len
)))
988 HFONT font
= input_context_select_ui_font( lpIMC
, hdc
);
992 GetTextExtentPoint32W( hdc
, str
, len
, &size
);
998 * How this works based on tests on windows:
999 * CFS_POINT: then we start our window at the point and grow it as large
1000 * as it needs to be for the string.
1001 * CFS_RECT: we still use the ptCurrentPos as a starting point and our
1002 * window is only as large as we need for the string, but we do not
1003 * grow such that our window exceeds the given rect. Wrapping if
1004 * needed and possible. If our ptCurrentPos is outside of our rect
1005 * then no window is displayed.
1006 * CFS_FORCE_POSITION: appears to behave just like CFS_POINT
1007 * maybe because the default MSIME does not do any IME adjusting.
1009 if (lpIMC
->cfCompForm
.dwStyle
!= CFS_DEFAULT
)
1011 POINT cpt
= lpIMC
->cfCompForm
.ptCurrentPos
;
1012 ClientToScreen(lpIMC
->hWnd
, &cpt
);
1015 rect
.right
= rect
.left
+ pt
.x
;
1016 rect
.bottom
= rect
.top
+ pt
.y
;
1017 monitor
= MonitorFromPoint(cpt
, MONITOR_DEFAULTTOPRIMARY
);
1019 else /* CFS_DEFAULT */
1021 /* Windows places the default IME window in the bottom left */
1022 HWND target
= lpIMC
->hWnd
;
1023 if (!target
) target
= GetFocus();
1025 GetWindowRect(target
, &rect
);
1026 rect
.top
= rect
.bottom
;
1027 rect
.right
= rect
.left
+ pt
.x
+ 20;
1028 rect
.bottom
= rect
.top
+ pt
.y
+ 20;
1030 monitor
= MonitorFromWindow(target
, MONITOR_DEFAULTTOPRIMARY
);
1033 if (lpIMC
->cfCompForm
.dwStyle
== CFS_RECT
)
1036 client
=lpIMC
->cfCompForm
.rcArea
;
1037 MapWindowPoints(lpIMC
->hWnd
, 0, (POINT
*)&client
, 2);
1038 IntersectRect(&rect
, &rect
, &client
);
1039 /* TODO: Wrap the input if needed */
1042 if (lpIMC
->cfCompForm
.dwStyle
== CFS_DEFAULT
)
1044 /* make sure we are on the desktop */
1045 mon_info
.cbSize
= sizeof(mon_info
);
1046 GetMonitorInfoW(monitor
, &mon_info
);
1048 if (rect
.bottom
> mon_info
.rcWork
.bottom
)
1050 int shift
= rect
.bottom
- mon_info
.rcWork
.bottom
;
1052 rect
.bottom
-= shift
;
1056 rect
.right
-= rect
.left
;
1059 if (rect
.right
> mon_info
.rcWork
.right
)
1061 int shift
= rect
.right
- mon_info
.rcWork
.right
;
1063 rect
.right
-= shift
;
1067 SetWindowPos(hwnd
, HWND_TOPMOST
, rect
.left
, rect
.top
, rect
.right
- rect
.left
,
1068 rect
.bottom
- rect
.top
, SWP_NOACTIVATE
);
1070 TextOutW( hdc
, offX
, offY
, str
, len
);
1072 if (font
) SelectObject( hdc
, font
);
1076 ImmUnlockIMCC(lpIMC
->hCompStr
);
1078 EndPaint(hwnd
, &ps
);
1082 static void DefaultIMEComposition(HIMC hIMC
, HWND hwnd
, LPARAM lParam
)
1085 TRACE("IME message WM_IME_COMPOSITION 0x%Ix\n", lParam
);
1086 if (lParam
& GCS_RESULTSTR
) return;
1087 if (!(ctx
= ImmLockIMC( hIMC
))) return;
1088 UpdateDataInDefaultIMEWindow( ctx
, hwnd
, TRUE
);
1092 static void DefaultIMEStartComposition(HIMC hIMC
, HWND hwnd
)
1094 LPINPUTCONTEXT lpIMC
;
1096 lpIMC
= ImmLockIMC(hIMC
);
1100 TRACE("IME message WM_IME_STARTCOMPOSITION\n");
1101 lpIMC
->hWnd
= GetFocus();
1102 ShowWindow(hwnd
, SW_SHOWNOACTIVATE
);
1106 static LRESULT
ImeHandleNotify(HIMC hIMC
, HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1110 case IMN_OPENSTATUSWINDOW
:
1111 FIXME("WM_IME_NOTIFY:IMN_OPENSTATUSWINDOW\n");
1113 case IMN_CLOSESTATUSWINDOW
:
1114 FIXME("WM_IME_NOTIFY:IMN_CLOSESTATUSWINDOW\n");
1116 case IMN_OPENCANDIDATE
:
1117 FIXME("WM_IME_NOTIFY:IMN_OPENCANDIDATE\n");
1119 case IMN_CHANGECANDIDATE
:
1120 FIXME("WM_IME_NOTIFY:IMN_CHANGECANDIDATE\n");
1122 case IMN_CLOSECANDIDATE
:
1123 FIXME("WM_IME_NOTIFY:IMN_CLOSECANDIDATE\n");
1125 case IMN_SETCONVERSIONMODE
:
1126 FIXME("WM_IME_NOTIFY:IMN_SETCONVERSIONMODE\n");
1128 case IMN_SETSENTENCEMODE
:
1129 FIXME("WM_IME_NOTIFY:IMN_SETSENTENCEMODE\n");
1131 case IMN_SETOPENSTATUS
:
1132 FIXME("WM_IME_NOTIFY:IMN_SETOPENSTATUS\n");
1134 case IMN_SETCANDIDATEPOS
:
1135 FIXME("WM_IME_NOTIFY:IMN_SETCANDIDATEPOS\n");
1137 case IMN_SETCOMPOSITIONFONT
:
1138 FIXME("WM_IME_NOTIFY:IMN_SETCOMPOSITIONFONT\n");
1140 case IMN_SETCOMPOSITIONWINDOW
:
1141 FIXME("WM_IME_NOTIFY:IMN_SETCOMPOSITIONWINDOW\n");
1144 FIXME("WM_IME_NOTIFY:IMN_GUIDELINE\n");
1146 case IMN_SETSTATUSWINDOWPOS
:
1147 FIXME("WM_IME_NOTIFY:IMN_SETSTATUSWINDOWPOS\n");
1150 FIXME("WM_IME_NOTIFY:<Unknown 0x%Ix>\n", wParam
);
1156 static LRESULT WINAPI
IME_WindowProc(HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1161 TRACE("Incoming Message 0x%x (0x%08Ix, 0x%08Ix)\n", msg
, wParam
, lParam
);
1164 * Each UI window contains the current Input Context.
1165 * This Input Context can be obtained by calling GetWindowLong
1166 * with IMMGWL_IMC when the UI window receives a WM_IME_xxx message.
1167 * The UI window can refer to this Input Context and handles the
1171 hIMC
= (HIMC
)GetWindowLongPtrW(hwnd
, IMMGWL_IMC
);
1173 /* if we have no hIMC there are many messages we cannot process */
1177 case WM_IME_STARTCOMPOSITION
:
1178 case WM_IME_ENDCOMPOSITION
:
1179 case WM_IME_COMPOSITION
:
1181 case WM_IME_CONTROL
:
1182 case WM_IME_COMPOSITIONFULL
:
1195 LPIMEPRIVATE myPrivate
;
1196 LPINPUTCONTEXT lpIMC
;
1198 SetWindowTextA(hwnd
, "Wine Ime Active");
1200 lpIMC
= ImmLockIMC(hIMC
);
1203 myPrivate
= ImmLockIMCC(lpIMC
->hPrivate
);
1204 myPrivate
->hwndDefault
= hwnd
;
1205 ImmUnlockIMCC(lpIMC
->hPrivate
);
1212 PaintDefaultIMEWnd(hIMC
, hwnd
);
1220 SetFocus((HWND
)wParam
);
1222 FIXME("Received focus, should never have focus\n");
1224 case WM_IME_COMPOSITION
:
1225 DefaultIMEComposition(hIMC
, hwnd
, lParam
);
1227 case WM_IME_STARTCOMPOSITION
:
1228 DefaultIMEStartComposition(hIMC
, hwnd
);
1230 case WM_IME_ENDCOMPOSITION
:
1231 TRACE("IME message %s, 0x%Ix, 0x%Ix\n", "WM_IME_ENDCOMPOSITION", wParam
, lParam
);
1232 ShowWindow(hwnd
, SW_HIDE
);
1235 TRACE("IME message %s, 0x%Ix, 0x%Ix\n", "WM_IME_SELECT", wParam
, lParam
);
1237 case WM_IME_CONTROL
:
1238 TRACE("IME message %s, 0x%Ix, 0x%Ix\n", "WM_IME_CONTROL", wParam
, lParam
);
1242 rc
= ImeHandleNotify(hIMC
, hwnd
, msg
, wParam
, lParam
);
1245 TRACE("Non-standard message 0x%x\n", msg
);
1247 /* check the MSIME messages */
1248 if (msg
== WM_MSIME_SERVICE
)
1250 TRACE("IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_SERVICE", wParam
, lParam
);
1253 else if (msg
== WM_MSIME_RECONVERTOPTIONS
)
1255 TRACE("IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_RECONVERTOPTIONS", wParam
, lParam
);
1257 else if (msg
== WM_MSIME_MOUSE
)
1259 TRACE("IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_MOUSE", wParam
, lParam
);
1261 else if (msg
== WM_MSIME_RECONVERTREQUEST
)
1263 TRACE("IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_RECONVERTREQUEST", wParam
, lParam
);
1265 else if (msg
== WM_MSIME_RECONVERT
)
1267 TRACE("IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_RECONVERT", wParam
, lParam
);
1269 else if (msg
== WM_MSIME_QUERYPOSITION
)
1271 TRACE("IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_QUERYPOSITION", wParam
, lParam
);
1273 else if (msg
== WM_MSIME_DOCUMENTFEED
)
1275 TRACE("IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_DOCUMENTFEED", wParam
, lParam
);
1277 /* DefWndProc if not an IME message */
1278 if (!rc
&& !((msg
>= WM_IME_STARTCOMPOSITION
&& msg
<= WM_IME_KEYLAST
) ||
1279 (msg
>= WM_IME_SETCONTEXT
&& msg
<= WM_IME_KEYUP
)))
1280 rc
= DefWindowProcW(hwnd
, msg
, wParam
, lParam
);
1285 static BOOL WINAPI
register_classes( INIT_ONCE
*once
, void *param
, void **context
)
1288 ZeroMemory(&wndClass
, sizeof(WNDCLASSW
));
1289 wndClass
.style
= CS_GLOBALCLASS
| CS_IME
| CS_HREDRAW
| CS_VREDRAW
;
1290 wndClass
.lpfnWndProc
= (WNDPROC
) IME_WindowProc
;
1291 wndClass
.cbClsExtra
= 0;
1292 wndClass
.cbWndExtra
= 2 * sizeof(LONG_PTR
);
1293 wndClass
.hInstance
= macdrv_module
;
1294 wndClass
.hCursor
= LoadCursorW(NULL
, (LPWSTR
)IDC_ARROW
);
1295 wndClass
.hIcon
= LoadIconW(NULL
, (LPWSTR
)IDI_APPLICATION
);
1296 wndClass
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
1297 wndClass
.lpszMenuName
= 0;
1298 wndClass
.lpszClassName
= UI_CLASS_NAME
;
1300 RegisterClassW(&wndClass
);
1302 WM_MSIME_SERVICE
= RegisterWindowMessageA("MSIMEService");
1303 WM_MSIME_RECONVERTOPTIONS
= RegisterWindowMessageA("MSIMEReconvertOptions");
1304 WM_MSIME_MOUSE
= RegisterWindowMessageA("MSIMEMouseOperation");
1305 WM_MSIME_RECONVERTREQUEST
= RegisterWindowMessageA("MSIMEReconvertRequest");
1306 WM_MSIME_RECONVERT
= RegisterWindowMessageA("MSIMEReconvert");
1307 WM_MSIME_QUERYPOSITION
= RegisterWindowMessageA("MSIMEQueryPosition");
1308 WM_MSIME_DOCUMENTFEED
= RegisterWindowMessageA("MSIMEDocumentFeed");
1312 BOOL WINAPI
ImeInquire(LPIMEINFO lpIMEInfo
, LPWSTR lpszUIClass
, DWORD flags
)
1314 static INIT_ONCE init_once
= INIT_ONCE_STATIC_INIT
;
1317 InitOnceExecuteOnce( &init_once
, register_classes
, NULL
, NULL
);
1318 lpIMEInfo
->dwPrivateDataSize
= sizeof(IMEPRIVATE
);
1319 lpIMEInfo
->fdwProperty
= IME_PROP_UNICODE
| IME_PROP_AT_CARET
;
1320 lpIMEInfo
->fdwConversionCaps
= IME_CMODE_NATIVE
| IME_CMODE_FULLSHAPE
;
1321 lpIMEInfo
->fdwSentenceCaps
= IME_SMODE_AUTOMATIC
;
1322 lpIMEInfo
->fdwUICaps
= UI_CAP_2700
;
1323 /* Tell App we cannot accept ImeSetCompositionString calls */
1324 /* FIXME: Can we? */
1325 lpIMEInfo
->fdwSCSCaps
= 0;
1326 lpIMEInfo
->fdwSelectCaps
= SELECT_CAP_CONVERSION
;
1328 lstrcpyW(lpszUIClass
, UI_CLASS_NAME
);
1333 /* Interfaces to other parts of the Mac driver */
1335 /***********************************************************************
1336 * macdrv_ime_set_text
1338 NTSTATUS WINAPI
macdrv_ime_set_text(void *arg
, ULONG size
)
1340 struct ime_set_text_params
*params
= arg
;
1341 ULONG length
= (size
- offsetof(struct ime_set_text_params
, text
)) / sizeof(WCHAR
);
1342 void *himc
= param_ptr(params
->himc
);
1343 HWND hwnd
= UlongToHandle(params
->hwnd
);
1345 if (!himc
) himc
= RealIMC(FROM_MACDRV
);
1350 IME_SetCompositionString(himc
, SCS_SETSTR
, params
->text
, length
* sizeof(WCHAR
),
1351 params
->cursor_pos
, !params
->complete
);
1357 input
.type
= INPUT_KEYBOARD
;
1360 input
.ki
.dwExtraInfo
= 0;
1362 for (i
= 0; i
< length
; i
++)
1364 input
.ki
.wScan
= params
->text
[i
];
1365 input
.ki
.dwFlags
= KEYEVENTF_UNICODE
;
1366 __wine_send_input(hwnd
, &input
, NULL
);
1368 input
.ki
.dwFlags
= KEYEVENTF_UNICODE
| KEYEVENTF_KEYUP
;
1369 __wine_send_input(hwnd
, &input
, NULL
);
1374 if (params
->complete
)
1375 IME_NotifyComplete(himc
);
1379 /**************************************************************************
1380 * macdrv_ime_query_char_rect
1382 NTSTATUS WINAPI
macdrv_ime_query_char_rect(void *arg
, ULONG size
)
1384 struct ime_query_char_rect_params
*params
= arg
;
1385 struct ime_query_char_rect_result
*result
= param_ptr(params
->result
);
1386 void *himc
= param_ptr(params
->himc
);
1387 IMECHARPOSITION charpos
;
1390 result
->location
= params
->location
;
1391 result
->length
= params
->length
;
1393 if (!himc
) himc
= RealIMC(FROM_MACDRV
);
1395 charpos
.dwSize
= sizeof(charpos
);
1396 charpos
.dwCharPos
= params
->location
;
1397 if (ImmRequestMessageW(himc
, IMR_QUERYCHARPOSITION
, (ULONG_PTR
)&charpos
))
1401 SetRect(&result
->rect
, charpos
.pt
.x
, charpos
.pt
.y
, 0, charpos
.pt
.y
+ charpos
.cLineHeight
);
1403 /* iterate over rest of length to extend rect */
1404 for (i
= 1; i
< params
->length
; i
++)
1406 charpos
.dwSize
= sizeof(charpos
);
1407 charpos
.dwCharPos
= params
->location
+ i
;
1408 if (!ImmRequestMessageW(himc
, IMR_QUERYCHARPOSITION
, (ULONG_PTR
)&charpos
) ||
1409 charpos
.pt
.y
!= result
->rect
.top
)
1415 result
->rect
.right
= charpos
.pt
.x
;
1423 LPINPUTCONTEXT ic
= ImmLockIMC(himc
);
1431 if ((hwnd
= input_context_get_ui_hwnd( ic
)) && IsWindowVisible( hwnd
) &&
1432 (str
= input_context_get_comp_str( ic
, FALSE
, &len
)))
1434 HDC dc
= GetDC( hwnd
);
1435 HFONT font
= input_context_select_ui_font( ic
, dc
);
1438 if (result
->location
> len
) result
->location
= len
;
1439 if (result
->location
+ result
->length
> len
) result
->length
= len
- result
->location
;
1441 GetTextExtentPoint32W( dc
, str
, result
->location
, &size
);
1442 charpos
.rcDocument
.left
= size
.cx
;
1443 charpos
.rcDocument
.top
= 0;
1444 GetTextExtentPoint32W( dc
, str
, result
->location
+ result
->length
, &size
);
1445 charpos
.rcDocument
.right
= size
.cx
;
1446 charpos
.rcDocument
.bottom
= size
.cy
;
1448 if (ic
->cfCompForm
.dwStyle
== CFS_DEFAULT
)
1449 OffsetRect(&charpos
.rcDocument
, 10, 10);
1451 LPtoDP(dc
, (POINT
*)&charpos
.rcDocument
, 2);
1452 MapWindowPoints( hwnd
, 0, (POINT
*)&charpos
.rcDocument
, 2 );
1453 result
->rect
= charpos
.rcDocument
;
1456 if (font
) SelectObject( dc
, font
);
1457 ReleaseDC( hwnd
, dc
);
1468 gti
.cbSize
= sizeof(gti
);
1469 if (GetGUIThreadInfo(0, >i
))
1471 MapWindowPoints(gti
.hwndCaret
, 0, (POINT
*)>i
.rcCaret
, 2);
1472 result
->rect
= gti
.rcCaret
;
1477 if (ret
&& result
->length
&& result
->rect
.left
== result
->rect
.right
)
1478 result
->rect
.right
++;