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.
46 WINE_DEFAULT_DEBUG_CHANNEL(imm
);
48 #define FROM_MACDRV ((HIMC)0xcafe1337)
50 typedef struct _IMEPRIVATE
{
57 } IMEPRIVATE
, *LPIMEPRIVATE
;
59 typedef struct _tagTRANSMSG
{
63 } TRANSMSG
, *LPTRANSMSG
;
65 static const WCHAR UI_CLASS_NAME
[] = {'W','i','n','e',' ','M','a','c',' ','I','M','E',0};
67 static HIMC
*hSelectedFrom
= NULL
;
68 static INT hSelectedCount
= 0;
71 static UINT WM_MSIME_SERVICE
;
72 static UINT WM_MSIME_RECONVERTOPTIONS
;
73 static UINT WM_MSIME_MOUSE
;
74 static UINT WM_MSIME_RECONVERTREQUEST
;
75 static UINT WM_MSIME_RECONVERT
;
76 static UINT WM_MSIME_QUERYPOSITION
;
77 static UINT WM_MSIME_DOCUMENTFEED
;
79 static HIMC
RealIMC(HIMC hIMC
)
81 if (hIMC
== FROM_MACDRV
)
84 HWND wnd
= GetFocus();
85 HIMC winHimc
= ImmGetContext(wnd
);
86 for (i
= 0; i
< hSelectedCount
; i
++)
87 if (winHimc
== hSelectedFrom
[i
])
95 static LPINPUTCONTEXT
LockRealIMC(HIMC hIMC
)
97 HIMC real_imc
= RealIMC(hIMC
);
99 return ImmLockIMC(real_imc
);
104 static BOOL
UnlockRealIMC(HIMC hIMC
)
106 HIMC real_imc
= RealIMC(hIMC
);
108 return ImmUnlockIMC(real_imc
);
113 static HIMCC
ImeCreateBlankCompStr(void)
116 LPCOMPOSITIONSTRING ptr
;
117 rc
= ImmCreateIMCC(sizeof(COMPOSITIONSTRING
));
118 ptr
= ImmLockIMCC(rc
);
119 memset(ptr
, 0, sizeof(COMPOSITIONSTRING
));
120 ptr
->dwSize
= sizeof(COMPOSITIONSTRING
);
125 static int updateField(DWORD origLen
, DWORD origOffset
, DWORD currentOffset
,
126 LPBYTE target
, LPBYTE source
, DWORD
* lenParam
,
127 DWORD
* offsetParam
, BOOL wchars
)
129 if (origLen
> 0 && origOffset
> 0)
131 int truelen
= origLen
;
133 truelen
*= sizeof(WCHAR
);
135 memcpy(&target
[currentOffset
], &source
[origOffset
], truelen
);
138 *offsetParam
= currentOffset
;
139 currentOffset
+= truelen
;
141 return currentOffset
;
144 static HIMCC
updateCompStr(HIMCC old
, LPCWSTR compstr
, DWORD len
, DWORD
*flags
)
146 /* We need to make sure the CompStr, CompClause and CompAttr fields are all
147 * set and correct. */
150 LPBYTE newdata
= NULL
;
151 LPBYTE olddata
= NULL
;
152 LPCOMPOSITIONSTRING new_one
;
153 LPCOMPOSITIONSTRING lpcs
= NULL
;
154 INT current_offset
= 0;
156 TRACE("%s, %i\n", debugstr_wn(compstr
, len
), len
);
158 if (old
== NULL
&& compstr
== NULL
&& len
== 0)
161 if (compstr
== NULL
&& len
!= 0)
163 ERR("compstr is NULL however we have a len! Please report\n");
169 olddata
= ImmLockIMCC(old
);
170 lpcs
= (LPCOMPOSITIONSTRING
)olddata
;
173 needed_size
= sizeof(COMPOSITIONSTRING
) + len
* sizeof(WCHAR
) +
174 len
+ sizeof(DWORD
) * 2;
178 needed_size
+= lpcs
->dwCompReadAttrLen
;
179 needed_size
+= lpcs
->dwCompReadClauseLen
;
180 needed_size
+= lpcs
->dwCompReadStrLen
* sizeof(WCHAR
);
181 needed_size
+= lpcs
->dwResultReadClauseLen
;
182 needed_size
+= lpcs
->dwResultReadStrLen
* sizeof(WCHAR
);
183 needed_size
+= lpcs
->dwResultClauseLen
;
184 needed_size
+= lpcs
->dwResultStrLen
* sizeof(WCHAR
);
185 needed_size
+= lpcs
->dwPrivateSize
;
187 rc
= ImmCreateIMCC(needed_size
);
188 newdata
= ImmLockIMCC(rc
);
189 new_one
= (LPCOMPOSITIONSTRING
)newdata
;
191 new_one
->dwSize
= needed_size
;
192 current_offset
= sizeof(COMPOSITIONSTRING
);
195 current_offset
= updateField(lpcs
->dwCompReadAttrLen
,
196 lpcs
->dwCompReadAttrOffset
,
197 current_offset
, newdata
, olddata
,
198 &new_one
->dwCompReadAttrLen
,
199 &new_one
->dwCompReadAttrOffset
, FALSE
);
201 current_offset
= updateField(lpcs
->dwCompReadClauseLen
,
202 lpcs
->dwCompReadClauseOffset
,
203 current_offset
, newdata
, olddata
,
204 &new_one
->dwCompReadClauseLen
,
205 &new_one
->dwCompReadClauseOffset
, FALSE
);
207 current_offset
= updateField(lpcs
->dwCompReadStrLen
,
208 lpcs
->dwCompReadStrOffset
,
209 current_offset
, newdata
, olddata
,
210 &new_one
->dwCompReadStrLen
,
211 &new_one
->dwCompReadStrOffset
, TRUE
);
213 /* new CompAttr, CompClause, CompStr, dwCursorPos */
214 new_one
->dwDeltaStart
= 0;
215 new_one
->dwCursorPos
= lpcs
->dwCursorPos
;
217 current_offset
= updateField(lpcs
->dwResultReadClauseLen
,
218 lpcs
->dwResultReadClauseOffset
,
219 current_offset
, newdata
, olddata
,
220 &new_one
->dwResultReadClauseLen
,
221 &new_one
->dwResultReadClauseOffset
, FALSE
);
223 current_offset
= updateField(lpcs
->dwResultReadStrLen
,
224 lpcs
->dwResultReadStrOffset
,
225 current_offset
, newdata
, olddata
,
226 &new_one
->dwResultReadStrLen
,
227 &new_one
->dwResultReadStrOffset
, TRUE
);
229 current_offset
= updateField(lpcs
->dwResultClauseLen
,
230 lpcs
->dwResultClauseOffset
,
231 current_offset
, newdata
, olddata
,
232 &new_one
->dwResultClauseLen
,
233 &new_one
->dwResultClauseOffset
, FALSE
);
235 current_offset
= updateField(lpcs
->dwResultStrLen
,
236 lpcs
->dwResultStrOffset
,
237 current_offset
, newdata
, olddata
,
238 &new_one
->dwResultStrLen
,
239 &new_one
->dwResultStrOffset
, TRUE
);
241 current_offset
= updateField(lpcs
->dwPrivateSize
,
242 lpcs
->dwPrivateOffset
,
243 current_offset
, newdata
, olddata
,
244 &new_one
->dwPrivateSize
,
245 &new_one
->dwPrivateOffset
, FALSE
);
249 new_one
->dwCursorPos
= len
;
250 *flags
|= GCS_CURSORPOS
;
255 new_one
->dwCompAttrLen
= len
;
258 new_one
->dwCompAttrOffset
= current_offset
;
259 memset(&newdata
[current_offset
], ATTR_INPUT
, len
);
260 current_offset
+= len
;
266 new_one
->dwCompClauseLen
= sizeof(DWORD
) * 2;
267 new_one
->dwCompClauseOffset
= current_offset
;
268 *(DWORD
*)&newdata
[current_offset
] = 0;
269 current_offset
+= sizeof(DWORD
);
270 *(DWORD
*)&newdata
[current_offset
] = len
;
271 current_offset
+= sizeof(DWORD
);
274 new_one
->dwCompClauseLen
= 0;
277 new_one
->dwCompStrLen
= len
;
280 new_one
->dwCompStrOffset
= current_offset
;
281 memcpy(&newdata
[current_offset
], compstr
, len
* sizeof(WCHAR
));
292 static HIMCC
updateResultStr(HIMCC old
, LPWSTR resultstr
, DWORD len
)
294 /* we need to make sure the ResultStr and ResultClause fields are all
298 LPBYTE newdata
= NULL
;
299 LPBYTE olddata
= NULL
;
300 LPCOMPOSITIONSTRING new_one
;
301 LPCOMPOSITIONSTRING lpcs
= NULL
;
302 INT current_offset
= 0;
304 TRACE("%s, %i\n", debugstr_wn(resultstr
, len
), len
);
306 if (old
== NULL
&& resultstr
== NULL
&& len
== 0)
309 if (resultstr
== NULL
&& len
!= 0)
311 ERR("resultstr is NULL however we have a len! Please report\n");
317 olddata
= ImmLockIMCC(old
);
318 lpcs
= (LPCOMPOSITIONSTRING
)olddata
;
321 needed_size
= sizeof(COMPOSITIONSTRING
) + len
* sizeof(WCHAR
) +
326 needed_size
+= lpcs
->dwCompReadAttrLen
;
327 needed_size
+= lpcs
->dwCompReadClauseLen
;
328 needed_size
+= lpcs
->dwCompReadStrLen
* sizeof(WCHAR
);
329 needed_size
+= lpcs
->dwCompAttrLen
;
330 needed_size
+= lpcs
->dwCompClauseLen
;
331 needed_size
+= lpcs
->dwCompStrLen
* sizeof(WCHAR
);
332 needed_size
+= lpcs
->dwResultReadClauseLen
;
333 needed_size
+= lpcs
->dwResultReadStrLen
* sizeof(WCHAR
);
334 needed_size
+= lpcs
->dwPrivateSize
;
336 rc
= ImmCreateIMCC(needed_size
);
337 newdata
= ImmLockIMCC(rc
);
338 new_one
= (LPCOMPOSITIONSTRING
)newdata
;
340 new_one
->dwSize
= needed_size
;
341 current_offset
= sizeof(COMPOSITIONSTRING
);
344 current_offset
= updateField(lpcs
->dwCompReadAttrLen
,
345 lpcs
->dwCompReadAttrOffset
,
346 current_offset
, newdata
, olddata
,
347 &new_one
->dwCompReadAttrLen
,
348 &new_one
->dwCompReadAttrOffset
, FALSE
);
350 current_offset
= updateField(lpcs
->dwCompReadClauseLen
,
351 lpcs
->dwCompReadClauseOffset
,
352 current_offset
, newdata
, olddata
,
353 &new_one
->dwCompReadClauseLen
,
354 &new_one
->dwCompReadClauseOffset
, FALSE
);
356 current_offset
= updateField(lpcs
->dwCompReadStrLen
,
357 lpcs
->dwCompReadStrOffset
,
358 current_offset
, newdata
, olddata
,
359 &new_one
->dwCompReadStrLen
,
360 &new_one
->dwCompReadStrOffset
, TRUE
);
362 current_offset
= updateField(lpcs
->dwCompAttrLen
,
363 lpcs
->dwCompAttrOffset
,
364 current_offset
, newdata
, olddata
,
365 &new_one
->dwCompAttrLen
,
366 &new_one
->dwCompAttrOffset
, FALSE
);
368 current_offset
= updateField(lpcs
->dwCompClauseLen
,
369 lpcs
->dwCompClauseOffset
,
370 current_offset
, newdata
, olddata
,
371 &new_one
->dwCompClauseLen
,
372 &new_one
->dwCompClauseOffset
, FALSE
);
374 current_offset
= updateField(lpcs
->dwCompStrLen
,
375 lpcs
->dwCompStrOffset
,
376 current_offset
, newdata
, olddata
,
377 &new_one
->dwCompStrLen
,
378 &new_one
->dwCompStrOffset
, TRUE
);
380 new_one
->dwCursorPos
= lpcs
->dwCursorPos
;
381 new_one
->dwDeltaStart
= 0;
383 current_offset
= updateField(lpcs
->dwResultReadClauseLen
,
384 lpcs
->dwResultReadClauseOffset
,
385 current_offset
, newdata
, olddata
,
386 &new_one
->dwResultReadClauseLen
,
387 &new_one
->dwResultReadClauseOffset
, FALSE
);
389 current_offset
= updateField(lpcs
->dwResultReadStrLen
,
390 lpcs
->dwResultReadStrOffset
,
391 current_offset
, newdata
, olddata
,
392 &new_one
->dwResultReadStrLen
,
393 &new_one
->dwResultReadStrOffset
, TRUE
);
395 /* new ResultClause , ResultStr */
397 current_offset
= updateField(lpcs
->dwPrivateSize
,
398 lpcs
->dwPrivateOffset
,
399 current_offset
, newdata
, olddata
,
400 &new_one
->dwPrivateSize
,
401 &new_one
->dwPrivateOffset
, FALSE
);
408 new_one
->dwResultClauseLen
= sizeof(DWORD
) * 2;
409 new_one
->dwResultClauseOffset
= current_offset
;
410 *(DWORD
*)&newdata
[current_offset
] = 0;
411 current_offset
+= sizeof(DWORD
);
412 *(DWORD
*)&newdata
[current_offset
] = len
;
413 current_offset
+= sizeof(DWORD
);
416 new_one
->dwResultClauseLen
= 0;
419 new_one
->dwResultStrLen
= len
;
422 new_one
->dwResultStrOffset
= current_offset
;
423 memcpy(&newdata
[current_offset
], resultstr
, len
* sizeof(WCHAR
));
432 static void GenerateIMEMessage(HIMC hIMC
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
434 LPINPUTCONTEXT lpIMC
;
435 LPTRANSMSG lpTransMsg
;
437 lpIMC
= LockRealIMC(hIMC
);
441 lpIMC
->hMsgBuf
= ImmReSizeIMCC(lpIMC
->hMsgBuf
, (lpIMC
->dwNumMsgBuf
+ 1) * sizeof(TRANSMSG
));
445 lpTransMsg
= ImmLockIMCC(lpIMC
->hMsgBuf
);
449 lpTransMsg
+= lpIMC
->dwNumMsgBuf
;
450 lpTransMsg
->message
= msg
;
451 lpTransMsg
->wParam
= wParam
;
452 lpTransMsg
->lParam
= lParam
;
454 ImmUnlockIMCC(lpIMC
->hMsgBuf
);
455 lpIMC
->dwNumMsgBuf
++;
457 ImmGenerateMessage(RealIMC(hIMC
));
461 static BOOL
GenerateMessageToTransKey(LPDWORD lpTransBuf
, UINT
*uNumTranMsgs
,
462 UINT msg
, WPARAM wParam
, LPARAM lParam
)
466 if (*uNumTranMsgs
+ 1 >= (UINT
)*lpTransBuf
)
469 ptr
= (LPTRANSMSG
)(lpTransBuf
+ 1 + *uNumTranMsgs
* 3);
471 ptr
->wParam
= wParam
;
472 ptr
->lParam
= lParam
;
479 static BOOL
IME_RemoveFromSelected(HIMC hIMC
)
482 for (i
= 0; i
< hSelectedCount
; i
++)
484 if (hSelectedFrom
[i
] == hIMC
)
486 if (i
< hSelectedCount
- 1)
487 memmove(&hSelectedFrom
[i
], &hSelectedFrom
[i
+ 1], (hSelectedCount
- i
- 1) * sizeof(HIMC
));
495 static void IME_AddToSelected(HIMC hIMC
)
499 hSelectedFrom
= HeapReAlloc(GetProcessHeap(), 0, hSelectedFrom
, hSelectedCount
* sizeof(HIMC
));
501 hSelectedFrom
= HeapAlloc(GetProcessHeap(), 0, sizeof(HIMC
));
502 hSelectedFrom
[hSelectedCount
- 1] = hIMC
;
505 static void UpdateDataInDefaultIMEWindow(HIMC hIMC
, HWND hwnd
, BOOL showable
)
507 LPCOMPOSITIONSTRING compstr
;
508 LPINPUTCONTEXT lpIMC
;
510 lpIMC
= LockRealIMC(hIMC
);
515 compstr
= ImmLockIMCC(lpIMC
->hCompStr
);
519 if (compstr
== NULL
|| compstr
->dwCompStrLen
== 0)
520 ShowWindow(hwnd
, SW_HIDE
);
522 ShowWindow(hwnd
, SW_SHOWNOACTIVATE
);
524 RedrawWindow(hwnd
, NULL
, NULL
, RDW_ERASENOW
| RDW_INVALIDATE
);
527 ImmUnlockIMCC(lpIMC
->hCompStr
);
532 BOOL WINAPI
ImeConfigure(HKL hKL
, HWND hWnd
, DWORD dwMode
, LPVOID lpData
)
534 FIXME("(%p, %p, %d, %p): stub\n", hKL
, hWnd
, dwMode
, lpData
);
535 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
539 DWORD WINAPI
ImeConversionList(HIMC hIMC
, LPCWSTR lpSource
, LPCANDIDATELIST lpCandList
,
540 DWORD dwBufLen
, UINT uFlag
)
543 FIXME("(%p, %s, %p, %d, %d): stub\n", hIMC
, debugstr_w(lpSource
), lpCandList
,
545 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
549 BOOL WINAPI
ImeDestroy(UINT uForce
)
552 HeapFree(GetProcessHeap(), 0, hSelectedFrom
);
553 hSelectedFrom
= NULL
;
558 LRESULT WINAPI
ImeEscape(HIMC hIMC
, UINT uSubFunc
, LPVOID lpData
)
560 TRACE("%x %p\n", uSubFunc
, lpData
);
564 BOOL WINAPI
ImeProcessKey(HIMC hIMC
, UINT vKey
, LPARAM lKeyData
, const LPBYTE lpbKeyState
)
566 LPINPUTCONTEXT lpIMC
;
569 TRACE("hIMC %p vKey 0x%04x lKeyData 0x%08lx lpbKeyState %p\n", hIMC
, vKey
, lKeyData
, lpbKeyState
);
580 inIME
= macdrv_using_input_method();
581 lpIMC
= LockRealIMC(hIMC
);
584 LPIMEPRIVATE myPrivate
;
585 myPrivate
= ImmLockIMCC(lpIMC
->hPrivate
);
587 if (inIME
&& !myPrivate
->bInternalState
)
588 ImmSetOpenStatus(RealIMC(FROM_MACDRV
), TRUE
);
589 else if (!inIME
&& myPrivate
->bInternalState
)
591 ShowWindow(myPrivate
->hwndDefault
, SW_HIDE
);
592 ImmDestroyIMCC(lpIMC
->hCompStr
);
593 lpIMC
->hCompStr
= ImeCreateBlankCompStr();
594 ImmSetOpenStatus(RealIMC(FROM_MACDRV
), FALSE
);
597 myPrivate
->repeat
= (lKeyData
>> 30) & 0x1;
599 myPrivate
->bInternalState
= inIME
;
600 ImmUnlockIMCC(lpIMC
->hPrivate
);
607 BOOL WINAPI
ImeSelect(HIMC hIMC
, BOOL fSelect
)
609 LPINPUTCONTEXT lpIMC
;
610 TRACE("%p %s\n", hIMC
, fSelect
? "TRUE" : "FALSE");
612 if (hIMC
== FROM_MACDRV
)
614 ERR("ImeSelect should never be called from Cocoa\n");
623 return IME_RemoveFromSelected(hIMC
);
625 IME_AddToSelected(hIMC
);
627 /* Initialize our structures */
628 lpIMC
= LockRealIMC(hIMC
);
631 LPIMEPRIVATE myPrivate
;
632 myPrivate
= ImmLockIMCC(lpIMC
->hPrivate
);
633 if (myPrivate
->bInComposition
)
634 GenerateIMEMessage(hIMC
, WM_IME_ENDCOMPOSITION
, 0, 0);
635 if (myPrivate
->bInternalState
)
636 ImmSetOpenStatus(RealIMC(FROM_MACDRV
), FALSE
);
637 myPrivate
->bInComposition
= FALSE
;
638 myPrivate
->bInternalState
= FALSE
;
639 myPrivate
->textfont
= NULL
;
640 myPrivate
->hwndDefault
= NULL
;
641 myPrivate
->repeat
= 0;
642 ImmUnlockIMCC(lpIMC
->hPrivate
);
649 BOOL WINAPI
ImeSetActiveContext(HIMC hIMC
, BOOL fFlag
)
651 FIXME("(%p, %x): stub\n", hIMC
, fFlag
);
655 UINT WINAPI
ImeToAsciiEx(UINT uVKey
, UINT uScanCode
, const LPBYTE lpbKeyState
,
656 LPDWORD lpdwTransKey
, UINT fuState
, HIMC hIMC
)
659 LPINPUTCONTEXT lpIMC
;
660 LPIMEPRIVATE myPrivate
;
665 TRACE("uVKey 0x%04x uScanCode 0x%04x fuState %u hIMC %p\n", uVKey
, uScanCode
, fuState
, hIMC
);
667 vkey
= LOWORD(uVKey
);
669 if (vkey
== VK_KANA
|| vkey
== VK_KANJI
|| vkey
== VK_MENU
)
671 TRACE("Skipping metakey\n");
675 lpIMC
= LockRealIMC(hIMC
);
676 myPrivate
= ImmLockIMCC(lpIMC
->hPrivate
);
677 if (!myPrivate
->bInternalState
)
679 ImmUnlockIMCC(lpIMC
->hPrivate
);
684 repeat
= myPrivate
->repeat
;
685 hwndDefault
= myPrivate
->hwndDefault
;
686 ImmUnlockIMCC(lpIMC
->hPrivate
);
689 TRACE("Processing Mac 0x%04x\n", vkey
);
690 macdrv_process_text_input(uVKey
, uScanCode
, repeat
, lpbKeyState
, hIMC
, &done
);
693 MsgWaitForMultipleObjectsEx(0, NULL
, INFINITE
, QS_POSTMESSAGE
| QS_SENDMESSAGE
, 0);
698 UINT msg
= (uScanCode
& 0x8000) ? WM_KEYUP
: WM_KEYDOWN
;
700 /* KeyStroke not processed by the IME
701 * so we need to rebuild the KeyDown message and pass it on to WINE
703 if (!GenerateMessageToTransKey(lpdwTransKey
, &msgs
, msg
, vkey
, MAKELONG(0x0001, uScanCode
)))
704 GenerateIMEMessage(hIMC
, msg
, vkey
, MAKELONG(0x0001, uScanCode
));
709 UpdateDataInDefaultIMEWindow(hIMC
, hwndDefault
, FALSE
);
713 BOOL WINAPI
NotifyIME(HIMC hIMC
, DWORD dwAction
, DWORD dwIndex
, DWORD dwValue
)
716 LPINPUTCONTEXT lpIMC
;
718 TRACE("%p %i %i %i\n", hIMC
, dwAction
, dwIndex
, dwValue
);
720 lpIMC
= LockRealIMC(hIMC
);
726 case NI_OPENCANDIDATE
: FIXME("NI_OPENCANDIDATE\n"); break;
727 case NI_CLOSECANDIDATE
: FIXME("NI_CLOSECANDIDATE\n"); break;
728 case NI_SELECTCANDIDATESTR
: FIXME("NI_SELECTCANDIDATESTR\n"); break;
729 case NI_CHANGECANDIDATELIST
: FIXME("NI_CHANGECANDIDATELIST\n"); break;
730 case NI_SETCANDIDATE_PAGESTART
: FIXME("NI_SETCANDIDATE_PAGESTART\n"); break;
731 case NI_SETCANDIDATE_PAGESIZE
: FIXME("NI_SETCANDIDATE_PAGESIZE\n"); break;
732 case NI_CONTEXTUPDATED
:
735 case IMC_SETCOMPOSITIONWINDOW
: FIXME("NI_CONTEXTUPDATED: IMC_SETCOMPOSITIONWINDOW\n"); break;
736 case IMC_SETCONVERSIONMODE
: FIXME("NI_CONTEXTUPDATED: IMC_SETCONVERSIONMODE\n"); break;
737 case IMC_SETSENTENCEMODE
: FIXME("NI_CONTEXTUPDATED: IMC_SETSENTENCEMODE\n"); break;
738 case IMC_SETCANDIDATEPOS
: FIXME("NI_CONTEXTUPDATED: IMC_SETCANDIDATEPOS\n"); break;
739 case IMC_SETCOMPOSITIONFONT
:
741 LPIMEPRIVATE myPrivate
;
742 TRACE("NI_CONTEXTUPDATED: IMC_SETCOMPOSITIONFONT\n");
744 myPrivate
= ImmLockIMCC(lpIMC
->hPrivate
);
745 if (myPrivate
->textfont
)
747 DeleteObject(myPrivate
->textfont
);
748 myPrivate
->textfont
= NULL
;
750 myPrivate
->textfont
= CreateFontIndirectW(&lpIMC
->lfFont
.W
);
751 ImmUnlockIMCC(lpIMC
->hPrivate
);
754 case IMC_SETOPENSTATUS
:
756 LPIMEPRIVATE myPrivate
;
757 TRACE("NI_CONTEXTUPDATED: IMC_SETOPENSTATUS\n");
759 myPrivate
= ImmLockIMCC(lpIMC
->hPrivate
);
760 if (lpIMC
->fOpen
!= myPrivate
->bInternalState
&& myPrivate
->bInComposition
)
762 if(lpIMC
->fOpen
== FALSE
)
764 GenerateIMEMessage(hIMC
, WM_IME_ENDCOMPOSITION
, 0, 0);
765 myPrivate
->bInComposition
= FALSE
;
769 GenerateIMEMessage(hIMC
, WM_IME_STARTCOMPOSITION
, 0, 0);
770 GenerateIMEMessage(hIMC
, WM_IME_COMPOSITION
, 0, 0);
773 myPrivate
->bInternalState
= lpIMC
->fOpen
;
777 default: FIXME("NI_CONTEXTUPDATED: Unknown\n"); break;
780 case NI_COMPOSITIONSTR
:
788 LPCOMPOSITIONSTRING cs
= NULL
;
790 LPIMEPRIVATE myPrivate
;
792 TRACE("NI_COMPOSITIONSTR: CPS_COMPLETE\n");
794 /* clear existing result */
795 newCompStr
= updateResultStr(lpIMC
->hCompStr
, NULL
, 0);
797 ImmDestroyIMCC(lpIMC
->hCompStr
);
798 lpIMC
->hCompStr
= newCompStr
;
802 cdata
= ImmLockIMCC(lpIMC
->hCompStr
);
803 cs
= (LPCOMPOSITIONSTRING
)cdata
;
804 cplen
= cs
->dwCompStrLen
;
805 cpstr
= (LPWSTR
)&cdata
[cs
->dwCompStrOffset
];
806 ImmUnlockIMCC(lpIMC
->hCompStr
);
808 myPrivate
= ImmLockIMCC(lpIMC
->hPrivate
);
811 WCHAR param
= cpstr
[0];
812 DWORD flags
= GCS_COMPSTR
;
814 newCompStr
= updateResultStr(lpIMC
->hCompStr
, cpstr
, cplen
);
815 ImmDestroyIMCC(lpIMC
->hCompStr
);
816 lpIMC
->hCompStr
= newCompStr
;
817 newCompStr
= updateCompStr(lpIMC
->hCompStr
, NULL
, 0, &flags
);
818 ImmDestroyIMCC(lpIMC
->hCompStr
);
819 lpIMC
->hCompStr
= newCompStr
;
821 GenerateIMEMessage(hIMC
, WM_IME_COMPOSITION
, 0, flags
);
823 GenerateIMEMessage(hIMC
, WM_IME_COMPOSITION
, param
,
824 GCS_RESULTSTR
| GCS_RESULTCLAUSE
);
826 GenerateIMEMessage(hIMC
, WM_IME_ENDCOMPOSITION
, 0, 0);
828 else if (myPrivate
->bInComposition
)
829 GenerateIMEMessage(hIMC
, WM_IME_ENDCOMPOSITION
, 0, 0);
832 myPrivate
->bInComposition
= FALSE
;
833 ImmUnlockIMCC(lpIMC
->hPrivate
);
838 case CPS_CONVERT
: FIXME("NI_COMPOSITIONSTR: CPS_CONVERT\n"); break;
839 case CPS_REVERT
: FIXME("NI_COMPOSITIONSTR: CPS_REVERT\n"); break;
842 LPIMEPRIVATE myPrivate
;
844 TRACE("NI_COMPOSITIONSTR: CPS_CANCEL\n");
846 macdrv_clear_ime_text();
848 ImmDestroyIMCC(lpIMC
->hCompStr
);
850 lpIMC
->hCompStr
= ImeCreateBlankCompStr();
852 myPrivate
= ImmLockIMCC(lpIMC
->hPrivate
);
853 if (myPrivate
->bInComposition
)
855 GenerateIMEMessage(hIMC
, WM_IME_ENDCOMPOSITION
, 0, 0);
856 myPrivate
->bInComposition
= FALSE
;
858 ImmUnlockIMCC(lpIMC
->hPrivate
);
862 default: FIXME("NI_COMPOSITIONSTR: Unknown\n"); break;
865 default: FIXME("Unknown Message\n"); break;
872 BOOL WINAPI
ImeRegisterWord(LPCWSTR lpszReading
, DWORD dwStyle
, LPCWSTR lpszRegister
)
874 FIXME("(%s, %d, %s): stub\n", debugstr_w(lpszReading
), dwStyle
, debugstr_w(lpszRegister
));
875 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
879 BOOL WINAPI
ImeUnregisterWord(LPCWSTR lpszReading
, DWORD dwStyle
, LPCWSTR lpszUnregister
)
881 FIXME("(%s, %d, %s): stub\n", debugstr_w(lpszReading
), dwStyle
, debugstr_w(lpszUnregister
));
882 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
886 UINT WINAPI
ImeGetRegisterWordStyle(UINT nItem
, LPSTYLEBUFW lpStyleBuf
)
888 FIXME("(%d, %p): stub\n", nItem
, lpStyleBuf
);
889 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
893 UINT WINAPI
ImeEnumRegisterWord(REGISTERWORDENUMPROCW lpfnEnumProc
, LPCWSTR lpszReading
,
894 DWORD dwStyle
, LPCWSTR lpszRegister
, LPVOID lpData
)
896 FIXME("(%p, %s, %d, %s, %p): stub\n", lpfnEnumProc
, debugstr_w(lpszReading
), dwStyle
,
897 debugstr_w(lpszRegister
), lpData
);
898 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
902 static BOOL
IME_SetCompositionString(void* hIMC
, DWORD dwIndex
, LPCVOID lpComp
, DWORD dwCompLen
, DWORD cursor_pos
, BOOL cursor_valid
)
904 LPINPUTCONTEXT lpIMC
;
907 LPIMEPRIVATE myPrivate
;
908 BOOL sendMessage
= TRUE
;
910 TRACE("(%p, %d, %p, %d):\n", hIMC
, dwIndex
, lpComp
, dwCompLen
);
914 * this sets the composition string in the imm32.dll level
915 * of the composition buffer.
916 * TODO: set the Cocoa window's marked text string and tell text input context
919 lpIMC
= LockRealIMC(hIMC
);
924 myPrivate
= ImmLockIMCC(lpIMC
->hPrivate
);
926 if (dwIndex
== SCS_SETSTR
)
930 if (!myPrivate
->bInComposition
)
932 GenerateIMEMessage(hIMC
, WM_IME_STARTCOMPOSITION
, 0, 0);
933 myPrivate
->bInComposition
= TRUE
;
936 /* clear existing result */
937 newCompStr
= updateResultStr(lpIMC
->hCompStr
, NULL
, 0);
938 ImmDestroyIMCC(lpIMC
->hCompStr
);
939 lpIMC
->hCompStr
= newCompStr
;
943 if (dwCompLen
&& lpComp
)
945 newCompStr
= updateCompStr(lpIMC
->hCompStr
, (LPCWSTR
)lpComp
, dwCompLen
/ sizeof(WCHAR
), &flags
);
946 ImmDestroyIMCC(lpIMC
->hCompStr
);
947 lpIMC
->hCompStr
= newCompStr
;
949 wParam
= ((const WCHAR
*)lpComp
)[0];
950 flags
|= GCS_COMPCLAUSE
| GCS_COMPATTR
| GCS_DELTASTART
;
954 LPCOMPOSITIONSTRING compstr
;
955 compstr
= ImmLockIMCC(lpIMC
->hCompStr
);
956 compstr
->dwCursorPos
= cursor_pos
;
957 ImmUnlockIMCC(lpIMC
->hCompStr
);
958 flags
|= GCS_CURSORPOS
;
963 NotifyIME(hIMC
, NI_COMPOSITIONSTR
, CPS_CANCEL
, 0);
970 GenerateIMEMessage(hIMC
, WM_IME_COMPOSITION
, wParam
, flags
);
971 ImmUnlockIMCC(lpIMC
->hPrivate
);
978 BOOL WINAPI
ImeSetCompositionString(HIMC hIMC
, DWORD dwIndex
, LPCVOID lpComp
, DWORD dwCompLen
,
979 LPCVOID lpRead
, DWORD dwReadLen
)
981 TRACE("(%p, %d, %p, %d, %p, %d):\n", hIMC
, dwIndex
, lpComp
, dwCompLen
, lpRead
, dwReadLen
);
983 if (lpRead
&& dwReadLen
)
984 FIXME("Reading string unimplemented\n");
986 return IME_SetCompositionString(hIMC
, dwIndex
, lpComp
, dwCompLen
, 0, FALSE
);
989 DWORD WINAPI
ImeGetImeMenuItems(HIMC hIMC
, DWORD dwFlags
, DWORD dwType
, LPIMEMENUITEMINFOW lpImeParentMenu
,
990 LPIMEMENUITEMINFOW lpImeMenu
, DWORD dwSize
)
992 FIXME("(%p, %x %x %p %p %x): stub\n", hIMC
, dwFlags
, dwType
, lpImeParentMenu
, lpImeMenu
, dwSize
);
993 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
997 static void IME_NotifyComplete(void* hIMC
)
999 NotifyIME(hIMC
, NI_COMPOSITIONSTR
, CPS_COMPLETE
, 0);
1003 * Internal functions to help with IME window management
1005 static void PaintDefaultIMEWnd(HIMC hIMC
, HWND hwnd
)
1010 LPCOMPOSITIONSTRING compstr
;
1011 LPBYTE compdata
= NULL
;
1013 MONITORINFO mon_info
;
1014 INT offX
= 0, offY
= 0;
1015 LPINPUTCONTEXT lpIMC
;
1017 lpIMC
= LockRealIMC(hIMC
);
1021 hdc
= BeginPaint(hwnd
, &ps
);
1023 GetClientRect(hwnd
, &rect
);
1024 FillRect(hdc
, &rect
, (HBRUSH
)(COLOR_WINDOW
+ 1));
1026 compdata
= ImmLockIMCC(lpIMC
->hCompStr
);
1027 compstr
= (LPCOMPOSITIONSTRING
)compdata
;
1029 if (compstr
->dwCompStrLen
&& compstr
->dwCompStrOffset
)
1033 HFONT oldfont
= NULL
;
1035 LPIMEPRIVATE myPrivate
;
1037 CompString
= (LPWSTR
)(compdata
+ compstr
->dwCompStrOffset
);
1038 myPrivate
= ImmLockIMCC(lpIMC
->hPrivate
);
1040 if (myPrivate
->textfont
)
1041 oldfont
= SelectObject(hdc
, myPrivate
->textfont
);
1043 ImmUnlockIMCC(lpIMC
->hPrivate
);
1045 GetTextExtentPoint32W(hdc
, CompString
, compstr
->dwCompStrLen
, &size
);
1048 LPtoDP(hdc
, &pt
, 1);
1051 * How this works based on tests on windows:
1052 * CFS_POINT: then we start our window at the point and grow it as large
1053 * as it needs to be for the string.
1054 * CFS_RECT: we still use the ptCurrentPos as a starting point and our
1055 * window is only as large as we need for the string, but we do not
1056 * grow such that our window exceeds the given rect. Wrapping if
1057 * needed and possible. If our ptCurrentPos is outside of our rect
1058 * then no window is displayed.
1059 * CFS_FORCE_POSITION: appears to behave just like CFS_POINT
1060 * maybe because the default MSIME does not do any IME adjusting.
1062 if (lpIMC
->cfCompForm
.dwStyle
!= CFS_DEFAULT
)
1064 POINT cpt
= lpIMC
->cfCompForm
.ptCurrentPos
;
1065 ClientToScreen(lpIMC
->hWnd
, &cpt
);
1068 rect
.right
= rect
.left
+ pt
.x
;
1069 rect
.bottom
= rect
.top
+ pt
.y
;
1070 monitor
= MonitorFromPoint(cpt
, MONITOR_DEFAULTTOPRIMARY
);
1072 else /* CFS_DEFAULT */
1074 /* Windows places the default IME window in the bottom left */
1075 HWND target
= lpIMC
->hWnd
;
1076 if (!target
) target
= GetFocus();
1078 GetWindowRect(target
, &rect
);
1079 rect
.top
= rect
.bottom
;
1080 rect
.right
= rect
.left
+ pt
.x
+ 20;
1081 rect
.bottom
= rect
.top
+ pt
.y
+ 20;
1083 monitor
= MonitorFromWindow(target
, MONITOR_DEFAULTTOPRIMARY
);
1086 if (lpIMC
->cfCompForm
.dwStyle
== CFS_RECT
)
1089 client
=lpIMC
->cfCompForm
.rcArea
;
1090 MapWindowPoints(lpIMC
->hWnd
, 0, (POINT
*)&client
, 2);
1091 IntersectRect(&rect
, &rect
, &client
);
1092 /* TODO: Wrap the input if needed */
1095 if (lpIMC
->cfCompForm
.dwStyle
== CFS_DEFAULT
)
1097 /* make sure we are on the desktop */
1098 mon_info
.cbSize
= sizeof(mon_info
);
1099 GetMonitorInfoW(monitor
, &mon_info
);
1101 if (rect
.bottom
> mon_info
.rcWork
.bottom
)
1103 int shift
= rect
.bottom
- mon_info
.rcWork
.bottom
;
1105 rect
.bottom
-= shift
;
1109 rect
.right
-= rect
.left
;
1112 if (rect
.right
> mon_info
.rcWork
.right
)
1114 int shift
= rect
.right
- mon_info
.rcWork
.right
;
1116 rect
.right
-= shift
;
1120 SetWindowPos(hwnd
, HWND_TOPMOST
, rect
.left
, rect
.top
, rect
.right
- rect
.left
,
1121 rect
.bottom
- rect
.top
, SWP_NOACTIVATE
);
1123 TextOutW(hdc
, offX
, offY
, CompString
, compstr
->dwCompStrLen
);
1126 SelectObject(hdc
, oldfont
);
1129 ImmUnlockIMCC(lpIMC
->hCompStr
);
1131 EndPaint(hwnd
, &ps
);
1132 UnlockRealIMC(hIMC
);
1135 static void DefaultIMEComposition(HIMC hIMC
, HWND hwnd
, LPARAM lParam
)
1137 TRACE("IME message WM_IME_COMPOSITION 0x%lx\n", lParam
);
1138 if (!(lParam
& GCS_RESULTSTR
))
1139 UpdateDataInDefaultIMEWindow(hIMC
, hwnd
, TRUE
);
1142 static void DefaultIMEStartComposition(HIMC hIMC
, HWND hwnd
)
1144 LPINPUTCONTEXT lpIMC
;
1146 lpIMC
= LockRealIMC(hIMC
);
1150 TRACE("IME message WM_IME_STARTCOMPOSITION\n");
1151 lpIMC
->hWnd
= GetFocus();
1152 ShowWindow(hwnd
, SW_SHOWNOACTIVATE
);
1153 UnlockRealIMC(hIMC
);
1156 static LRESULT
ImeHandleNotify(HIMC hIMC
, HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1160 case IMN_OPENSTATUSWINDOW
:
1161 FIXME("WM_IME_NOTIFY:IMN_OPENSTATUSWINDOW\n");
1163 case IMN_CLOSESTATUSWINDOW
:
1164 FIXME("WM_IME_NOTIFY:IMN_CLOSESTATUSWINDOW\n");
1166 case IMN_OPENCANDIDATE
:
1167 FIXME("WM_IME_NOTIFY:IMN_OPENCANDIDATE\n");
1169 case IMN_CHANGECANDIDATE
:
1170 FIXME("WM_IME_NOTIFY:IMN_CHANGECANDIDATE\n");
1172 case IMN_CLOSECANDIDATE
:
1173 FIXME("WM_IME_NOTIFY:IMN_CLOSECANDIDATE\n");
1175 case IMN_SETCONVERSIONMODE
:
1176 FIXME("WM_IME_NOTIFY:IMN_SETCONVERSIONMODE\n");
1178 case IMN_SETSENTENCEMODE
:
1179 FIXME("WM_IME_NOTIFY:IMN_SETSENTENCEMODE\n");
1181 case IMN_SETOPENSTATUS
:
1182 FIXME("WM_IME_NOTIFY:IMN_SETOPENSTATUS\n");
1184 case IMN_SETCANDIDATEPOS
:
1185 FIXME("WM_IME_NOTIFY:IMN_SETCANDIDATEPOS\n");
1187 case IMN_SETCOMPOSITIONFONT
:
1188 FIXME("WM_IME_NOTIFY:IMN_SETCOMPOSITIONFONT\n");
1190 case IMN_SETCOMPOSITIONWINDOW
:
1191 FIXME("WM_IME_NOTIFY:IMN_SETCOMPOSITIONWINDOW\n");
1194 FIXME("WM_IME_NOTIFY:IMN_GUIDELINE\n");
1196 case IMN_SETSTATUSWINDOWPOS
:
1197 FIXME("WM_IME_NOTIFY:IMN_SETSTATUSWINDOWPOS\n");
1200 FIXME("WM_IME_NOTIFY:<Unknown 0x%lx>\n", wParam
);
1206 static LRESULT WINAPI
IME_WindowProc(HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1211 TRACE("Incoming Message 0x%x (0x%08lx, 0x%08lx)\n", msg
, wParam
, lParam
);
1214 * Each UI window contains the current Input Context.
1215 * This Input Context can be obtained by calling GetWindowLong
1216 * with IMMGWL_IMC when the UI window receives a WM_IME_xxx message.
1217 * The UI window can refer to this Input Context and handles the
1221 hIMC
= (HIMC
)GetWindowLongPtrW(hwnd
, IMMGWL_IMC
);
1223 hIMC
= RealIMC(FROM_MACDRV
);
1225 /* if we have no hIMC there are many messages we cannot process */
1229 case WM_IME_STARTCOMPOSITION
:
1230 case WM_IME_ENDCOMPOSITION
:
1231 case WM_IME_COMPOSITION
:
1233 case WM_IME_CONTROL
:
1234 case WM_IME_COMPOSITIONFULL
:
1247 LPIMEPRIVATE myPrivate
;
1248 LPINPUTCONTEXT lpIMC
;
1250 SetWindowTextA(hwnd
, "Wine Ime Active");
1252 lpIMC
= LockRealIMC(hIMC
);
1255 myPrivate
= ImmLockIMCC(lpIMC
->hPrivate
);
1256 myPrivate
->hwndDefault
= hwnd
;
1257 ImmUnlockIMCC(lpIMC
->hPrivate
);
1259 UnlockRealIMC(hIMC
);
1264 PaintDefaultIMEWnd(hIMC
, hwnd
);
1272 SetFocus((HWND
)wParam
);
1274 FIXME("Received focus, should never have focus\n");
1276 case WM_IME_COMPOSITION
:
1277 DefaultIMEComposition(hIMC
, hwnd
, lParam
);
1279 case WM_IME_STARTCOMPOSITION
:
1280 DefaultIMEStartComposition(hIMC
, hwnd
);
1282 case WM_IME_ENDCOMPOSITION
:
1283 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_IME_ENDCOMPOSITION", wParam
, lParam
);
1284 ShowWindow(hwnd
, SW_HIDE
);
1287 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_IME_SELECT", wParam
, lParam
);
1289 case WM_IME_CONTROL
:
1290 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_IME_CONTROL", wParam
, lParam
);
1294 rc
= ImeHandleNotify(hIMC
, hwnd
, msg
, wParam
, lParam
);
1297 TRACE("Non-standard message 0x%x\n", msg
);
1299 /* check the MSIME messages */
1300 if (msg
== WM_MSIME_SERVICE
)
1302 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_MSIME_SERVICE", wParam
, lParam
);
1305 else if (msg
== WM_MSIME_RECONVERTOPTIONS
)
1307 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_MSIME_RECONVERTOPTIONS", wParam
, lParam
);
1309 else if (msg
== WM_MSIME_MOUSE
)
1311 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_MSIME_MOUSE", wParam
, lParam
);
1313 else if (msg
== WM_MSIME_RECONVERTREQUEST
)
1315 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_MSIME_RECONVERTREQUEST", wParam
, lParam
);
1317 else if (msg
== WM_MSIME_RECONVERT
)
1319 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_MSIME_RECONVERT", wParam
, lParam
);
1321 else if (msg
== WM_MSIME_QUERYPOSITION
)
1323 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_MSIME_QUERYPOSITION", wParam
, lParam
);
1325 else if (msg
== WM_MSIME_DOCUMENTFEED
)
1327 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_MSIME_DOCUMENTFEED", wParam
, lParam
);
1329 /* DefWndProc if not an IME message */
1330 if (!rc
&& !((msg
>= WM_IME_STARTCOMPOSITION
&& msg
<= WM_IME_KEYLAST
) ||
1331 (msg
>= WM_IME_SETCONTEXT
&& msg
<= WM_IME_KEYUP
)))
1332 rc
= DefWindowProcW(hwnd
, msg
, wParam
, lParam
);
1337 static BOOL WINAPI
register_classes( INIT_ONCE
*once
, void *param
, void **context
)
1340 ZeroMemory(&wndClass
, sizeof(WNDCLASSW
));
1341 wndClass
.style
= CS_GLOBALCLASS
| CS_IME
| CS_HREDRAW
| CS_VREDRAW
;
1342 wndClass
.lpfnWndProc
= (WNDPROC
) IME_WindowProc
;
1343 wndClass
.cbClsExtra
= 0;
1344 wndClass
.cbWndExtra
= 2 * sizeof(LONG_PTR
);
1345 wndClass
.hInstance
= macdrv_module
;
1346 wndClass
.hCursor
= LoadCursorW(NULL
, (LPWSTR
)IDC_ARROW
);
1347 wndClass
.hIcon
= LoadIconW(NULL
, (LPWSTR
)IDI_APPLICATION
);
1348 wndClass
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
1349 wndClass
.lpszMenuName
= 0;
1350 wndClass
.lpszClassName
= UI_CLASS_NAME
;
1352 RegisterClassW(&wndClass
);
1354 WM_MSIME_SERVICE
= RegisterWindowMessageA("MSIMEService");
1355 WM_MSIME_RECONVERTOPTIONS
= RegisterWindowMessageA("MSIMEReconvertOptions");
1356 WM_MSIME_MOUSE
= RegisterWindowMessageA("MSIMEMouseOperation");
1357 WM_MSIME_RECONVERTREQUEST
= RegisterWindowMessageA("MSIMEReconvertRequest");
1358 WM_MSIME_RECONVERT
= RegisterWindowMessageA("MSIMEReconvert");
1359 WM_MSIME_QUERYPOSITION
= RegisterWindowMessageA("MSIMEQueryPosition");
1360 WM_MSIME_DOCUMENTFEED
= RegisterWindowMessageA("MSIMEDocumentFeed");
1364 BOOL WINAPI
ImeInquire(LPIMEINFO lpIMEInfo
, LPWSTR lpszUIClass
, LPCWSTR lpszOption
)
1366 static INIT_ONCE init_once
= INIT_ONCE_STATIC_INIT
;
1369 InitOnceExecuteOnce( &init_once
, register_classes
, NULL
, NULL
);
1370 lpIMEInfo
->dwPrivateDataSize
= sizeof(IMEPRIVATE
);
1371 lpIMEInfo
->fdwProperty
= IME_PROP_UNICODE
| IME_PROP_AT_CARET
;
1372 lpIMEInfo
->fdwConversionCaps
= IME_CMODE_NATIVE
| IME_CMODE_FULLSHAPE
;
1373 lpIMEInfo
->fdwSentenceCaps
= IME_SMODE_AUTOMATIC
;
1374 lpIMEInfo
->fdwUICaps
= UI_CAP_2700
;
1375 /* Tell App we cannot accept ImeSetCompositionString calls */
1376 /* FIXME: Can we? */
1377 lpIMEInfo
->fdwSCSCaps
= 0;
1378 lpIMEInfo
->fdwSelectCaps
= SELECT_CAP_CONVERSION
;
1380 lstrcpyW(lpszUIClass
, UI_CLASS_NAME
);
1385 /* Interfaces to other parts of the Mac driver */
1387 /***********************************************************************
1388 * macdrv_im_set_text
1390 void macdrv_im_set_text(const macdrv_event
*event
)
1392 HWND hwnd
= macdrv_get_window_hwnd(event
->window
);
1393 void *himc
= event
->im_set_text
.data
;
1395 TRACE("win %p/%p himc %p text %s complete %u\n", hwnd
, event
->window
, himc
,
1396 debugstr_cf(event
->im_set_text
.text
), event
->im_set_text
.complete
);
1398 if (!himc
) himc
= RealIMC(FROM_MACDRV
);
1400 if (event
->im_set_text
.text
)
1402 CFIndex length
= CFStringGetLength(event
->im_set_text
.text
);
1403 const UniChar
*chars
= CFStringGetCharactersPtr(event
->im_set_text
.text
);
1404 UniChar
*buffer
= NULL
;
1408 buffer
= HeapAlloc(GetProcessHeap(), 0, length
* sizeof(*buffer
));
1409 CFStringGetCharacters(event
->im_set_text
.text
, CFRangeMake(0, length
), buffer
);
1414 IME_SetCompositionString(himc
, SCS_SETSTR
, chars
, length
* sizeof(*chars
),
1415 event
->im_set_text
.cursor_pos
, !event
->im_set_text
.complete
);
1421 input
.type
= INPUT_KEYBOARD
;
1424 input
.ki
.dwExtraInfo
= 0;
1426 for (i
= 0; i
< length
; i
++)
1428 input
.ki
.wScan
= chars
[i
];
1429 input
.ki
.dwFlags
= KEYEVENTF_UNICODE
;
1430 __wine_send_input(hwnd
, &input
);
1432 input
.ki
.dwFlags
= KEYEVENTF_UNICODE
| KEYEVENTF_KEYUP
;
1433 __wine_send_input(hwnd
, &input
);
1437 HeapFree(GetProcessHeap(), 0, buffer
);
1440 if (event
->im_set_text
.complete
)
1441 IME_NotifyComplete(himc
);
1444 /***********************************************************************
1445 * macdrv_sent_text_input
1447 void macdrv_sent_text_input(const macdrv_event
*event
)
1449 TRACE("handled: %s\n", event
->sent_text_input
.handled
? "TRUE" : "FALSE");
1450 *event
->sent_text_input
.done
= event
->sent_text_input
.handled
? 1 : -1;
1454 /**************************************************************************
1455 * query_ime_char_rect
1457 BOOL
query_ime_char_rect(macdrv_query
* query
)
1459 HWND hwnd
= macdrv_get_window_hwnd(query
->window
);
1460 void *himc
= query
->ime_char_rect
.data
;
1461 CFRange
* range
= &query
->ime_char_rect
.range
;
1462 CGRect
* rect
= &query
->ime_char_rect
.rect
;
1463 IMECHARPOSITION charpos
;
1466 TRACE("win %p/%p himc %p range %ld-%ld\n", hwnd
, query
->window
, himc
, range
->location
,
1469 if (!himc
) himc
= RealIMC(FROM_MACDRV
);
1471 charpos
.dwSize
= sizeof(charpos
);
1472 charpos
.dwCharPos
= range
->location
;
1473 if (ImmRequestMessageW(himc
, IMR_QUERYCHARPOSITION
, (ULONG_PTR
)&charpos
))
1477 *rect
= CGRectMake(charpos
.pt
.x
, charpos
.pt
.y
, 0, charpos
.cLineHeight
);
1479 /* iterate over rest of length to extend rect */
1480 for (i
= 1; i
< range
->length
; i
++)
1482 charpos
.dwSize
= sizeof(charpos
);
1483 charpos
.dwCharPos
= range
->location
+ i
;
1484 if (!ImmRequestMessageW(himc
, IMR_QUERYCHARPOSITION
, (ULONG_PTR
)&charpos
) ||
1485 charpos
.pt
.y
!= rect
->origin
.y
)
1491 rect
->size
.width
= charpos
.pt
.x
- rect
->origin
.x
;
1499 LPINPUTCONTEXT ic
= ImmLockIMC(himc
);
1503 LPIMEPRIVATE
private = ImmLockIMCC(ic
->hPrivate
);
1504 LPBYTE compdata
= ImmLockIMCC(ic
->hCompStr
);
1505 LPCOMPOSITIONSTRING compstr
= (LPCOMPOSITIONSTRING
)compdata
;
1506 LPWSTR str
= (LPWSTR
)(compdata
+ compstr
->dwCompStrOffset
);
1508 if (private->hwndDefault
&& compstr
->dwCompStrOffset
&&
1509 IsWindowVisible(private->hwndDefault
))
1511 HDC dc
= GetDC(private->hwndDefault
);
1512 HFONT oldfont
= NULL
;
1515 if (private->textfont
)
1516 oldfont
= SelectObject(dc
, private->textfont
);
1518 if (range
->location
> compstr
->dwCompStrLen
)
1519 range
->location
= compstr
->dwCompStrLen
;
1520 if (range
->location
+ range
->length
> compstr
->dwCompStrLen
)
1521 range
->length
= compstr
->dwCompStrLen
- range
->location
;
1523 GetTextExtentPoint32W(dc
, str
, range
->location
, &size
);
1524 charpos
.rcDocument
.left
= size
.cx
;
1525 charpos
.rcDocument
.top
= 0;
1526 GetTextExtentPoint32W(dc
, str
, range
->location
+ range
->length
, &size
);
1527 charpos
.rcDocument
.right
= size
.cx
;
1528 charpos
.rcDocument
.bottom
= size
.cy
;
1530 if (ic
->cfCompForm
.dwStyle
== CFS_DEFAULT
)
1531 OffsetRect(&charpos
.rcDocument
, 10, 10);
1533 LPtoDP(dc
, (POINT
*)&charpos
.rcDocument
, 2);
1534 MapWindowPoints(private->hwndDefault
, 0, (POINT
*)&charpos
.rcDocument
, 2);
1535 *rect
= cgrect_from_rect(charpos
.rcDocument
);
1539 SelectObject(dc
, oldfont
);
1540 ReleaseDC(private->hwndDefault
, dc
);
1543 ImmUnlockIMCC(ic
->hCompStr
);
1544 ImmUnlockIMCC(ic
->hPrivate
);
1553 gti
.cbSize
= sizeof(gti
);
1554 if (GetGUIThreadInfo(0, >i
))
1556 MapWindowPoints(gti
.hwndCaret
, 0, (POINT
*)>i
.rcCaret
, 2);
1557 *rect
= cgrect_from_rect(gti
.rcCaret
);
1562 if (ret
&& range
->length
&& !rect
->size
.width
)
1563 rect
->size
.width
= 1;
1565 TRACE(" -> %s range %ld-%ld rect %s\n", ret
? "TRUE" : "FALSE", range
->location
,
1566 range
->length
, wine_dbgstr_cgrect(*rect
));