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
;
80 static HIMC
RealIMC(HIMC hIMC
)
82 if (hIMC
== FROM_MACDRV
)
85 HWND wnd
= GetFocus();
86 HIMC winHimc
= ImmGetContext(wnd
);
87 for (i
= 0; i
< hSelectedCount
; i
++)
88 if (winHimc
== hSelectedFrom
[i
])
96 static LPINPUTCONTEXT
LockRealIMC(HIMC hIMC
)
98 HIMC real_imc
= RealIMC(hIMC
);
100 return ImmLockIMC(real_imc
);
105 static BOOL
UnlockRealIMC(HIMC hIMC
)
107 HIMC real_imc
= RealIMC(hIMC
);
109 return ImmUnlockIMC(real_imc
);
114 static HIMCC
ImeCreateBlankCompStr(void)
117 LPCOMPOSITIONSTRING ptr
;
118 rc
= ImmCreateIMCC(sizeof(COMPOSITIONSTRING
));
119 ptr
= ImmLockIMCC(rc
);
120 memset(ptr
, 0, sizeof(COMPOSITIONSTRING
));
121 ptr
->dwSize
= sizeof(COMPOSITIONSTRING
);
126 static int updateField(DWORD origLen
, DWORD origOffset
, DWORD currentOffset
,
127 LPBYTE target
, LPBYTE source
, DWORD
* lenParam
,
128 DWORD
* offsetParam
, BOOL wchars
)
130 if (origLen
> 0 && origOffset
> 0)
132 int truelen
= origLen
;
134 truelen
*= sizeof(WCHAR
);
136 memcpy(&target
[currentOffset
], &source
[origOffset
], truelen
);
139 *offsetParam
= currentOffset
;
140 currentOffset
+= truelen
;
142 return currentOffset
;
145 static HIMCC
updateCompStr(HIMCC old
, LPCWSTR compstr
, DWORD len
, DWORD
*flags
)
147 /* we need to make sure the CompStr, CompClaus and CompAttr fields are all
151 LPBYTE newdata
= NULL
;
152 LPBYTE olddata
= NULL
;
153 LPCOMPOSITIONSTRING new_one
;
154 LPCOMPOSITIONSTRING lpcs
= NULL
;
155 INT current_offset
= 0;
157 TRACE("%s, %i\n", debugstr_wn(compstr
, len
), len
);
159 if (old
== NULL
&& compstr
== NULL
&& len
== 0)
162 if (compstr
== NULL
&& len
!= 0)
164 ERR("compstr is NULL however we have a len! Please report\n");
170 olddata
= ImmLockIMCC(old
);
171 lpcs
= (LPCOMPOSITIONSTRING
)olddata
;
174 needed_size
= sizeof(COMPOSITIONSTRING
) + len
* sizeof(WCHAR
) +
175 len
+ sizeof(DWORD
) * 2;
179 needed_size
+= lpcs
->dwCompReadAttrLen
;
180 needed_size
+= lpcs
->dwCompReadClauseLen
;
181 needed_size
+= lpcs
->dwCompReadStrLen
* sizeof(DWORD
);
182 needed_size
+= lpcs
->dwResultReadClauseLen
;
183 needed_size
+= lpcs
->dwResultReadStrLen
* sizeof(DWORD
);
184 needed_size
+= lpcs
->dwResultClauseLen
;
185 needed_size
+= lpcs
->dwResultStrLen
* sizeof(DWORD
);
186 needed_size
+= lpcs
->dwPrivateSize
;
188 rc
= ImmCreateIMCC(needed_size
);
189 newdata
= ImmLockIMCC(rc
);
190 new_one
= (LPCOMPOSITIONSTRING
)newdata
;
192 new_one
->dwSize
= needed_size
;
193 current_offset
= sizeof(COMPOSITIONSTRING
);
196 current_offset
= updateField(lpcs
->dwCompReadAttrLen
,
197 lpcs
->dwCompReadAttrOffset
,
198 current_offset
, newdata
, olddata
,
199 &new_one
->dwCompReadAttrLen
,
200 &new_one
->dwCompReadAttrOffset
, FALSE
);
202 current_offset
= updateField(lpcs
->dwCompReadClauseLen
,
203 lpcs
->dwCompReadClauseOffset
,
204 current_offset
, newdata
, olddata
,
205 &new_one
->dwCompReadClauseLen
,
206 &new_one
->dwCompReadClauseOffset
, FALSE
);
208 current_offset
= updateField(lpcs
->dwCompReadStrLen
,
209 lpcs
->dwCompReadStrOffset
,
210 current_offset
, newdata
, olddata
,
211 &new_one
->dwCompReadStrLen
,
212 &new_one
->dwCompReadStrOffset
, TRUE
);
214 /* new CompAttr, CompClause, CompStr, dwCursorPos */
215 new_one
->dwDeltaStart
= 0;
216 new_one
->dwCursorPos
= lpcs
->dwCursorPos
;
218 current_offset
= updateField(lpcs
->dwResultReadClauseLen
,
219 lpcs
->dwResultReadClauseOffset
,
220 current_offset
, newdata
, olddata
,
221 &new_one
->dwResultReadClauseLen
,
222 &new_one
->dwResultReadClauseOffset
, FALSE
);
224 current_offset
= updateField(lpcs
->dwResultReadStrLen
,
225 lpcs
->dwResultReadStrOffset
,
226 current_offset
, newdata
, olddata
,
227 &new_one
->dwResultReadStrLen
,
228 &new_one
->dwResultReadStrOffset
, TRUE
);
230 current_offset
= updateField(lpcs
->dwResultClauseLen
,
231 lpcs
->dwResultClauseOffset
,
232 current_offset
, newdata
, olddata
,
233 &new_one
->dwResultClauseLen
,
234 &new_one
->dwResultClauseOffset
, FALSE
);
236 current_offset
= updateField(lpcs
->dwResultStrLen
,
237 lpcs
->dwResultStrOffset
,
238 current_offset
, newdata
, olddata
,
239 &new_one
->dwResultStrLen
,
240 &new_one
->dwResultStrOffset
, TRUE
);
242 current_offset
= updateField(lpcs
->dwPrivateSize
,
243 lpcs
->dwPrivateOffset
,
244 current_offset
, newdata
, olddata
,
245 &new_one
->dwPrivateSize
,
246 &new_one
->dwPrivateOffset
, FALSE
);
250 new_one
->dwCursorPos
= len
;
251 *flags
|= GCS_CURSORPOS
;
256 new_one
->dwCompAttrLen
= len
;
259 new_one
->dwCompAttrOffset
= current_offset
;
260 memset(&newdata
[current_offset
], ATTR_INPUT
, len
);
261 current_offset
+= len
;
267 new_one
->dwCompClauseLen
= sizeof(DWORD
) * 2;
268 new_one
->dwCompClauseOffset
= current_offset
;
269 *(DWORD
*)&newdata
[current_offset
] = 0;
270 current_offset
+= sizeof(DWORD
);
271 *(DWORD
*)&newdata
[current_offset
] = len
;
272 current_offset
+= sizeof(DWORD
);
276 new_one
->dwCompStrLen
= len
;
279 new_one
->dwCompStrOffset
= current_offset
;
280 memcpy(&newdata
[current_offset
], compstr
, len
* sizeof(WCHAR
));
291 static HIMCC
updateResultStr(HIMCC old
, LPWSTR resultstr
, DWORD len
)
293 /* we need to make sure the ResultStr and ResultClause fields are all
297 LPBYTE newdata
= NULL
;
298 LPBYTE olddata
= NULL
;
299 LPCOMPOSITIONSTRING new_one
;
300 LPCOMPOSITIONSTRING lpcs
= NULL
;
301 INT current_offset
= 0;
303 TRACE("%s, %i\n", debugstr_wn(resultstr
, len
), len
);
305 if (old
== NULL
&& resultstr
== NULL
&& len
== 0)
308 if (resultstr
== NULL
&& len
!= 0)
310 ERR("resultstr is NULL however we have a len! Please report\n");
316 olddata
= ImmLockIMCC(old
);
317 lpcs
= (LPCOMPOSITIONSTRING
)olddata
;
320 needed_size
= sizeof(COMPOSITIONSTRING
) + len
* sizeof(WCHAR
) +
325 needed_size
+= lpcs
->dwCompReadAttrLen
;
326 needed_size
+= lpcs
->dwCompReadClauseLen
;
327 needed_size
+= lpcs
->dwCompReadStrLen
* sizeof(DWORD
);
328 needed_size
+= lpcs
->dwCompAttrLen
;
329 needed_size
+= lpcs
->dwCompClauseLen
;
330 needed_size
+= lpcs
->dwCompStrLen
* sizeof(DWORD
);
331 needed_size
+= lpcs
->dwResultReadClauseLen
;
332 needed_size
+= lpcs
->dwResultReadStrLen
* sizeof(DWORD
);
333 needed_size
+= lpcs
->dwPrivateSize
;
335 rc
= ImmCreateIMCC(needed_size
);
336 newdata
= ImmLockIMCC(rc
);
337 new_one
= (LPCOMPOSITIONSTRING
)newdata
;
339 new_one
->dwSize
= needed_size
;
340 current_offset
= sizeof(COMPOSITIONSTRING
);
343 current_offset
= updateField(lpcs
->dwCompReadAttrLen
,
344 lpcs
->dwCompReadAttrOffset
,
345 current_offset
, newdata
, olddata
,
346 &new_one
->dwCompReadAttrLen
,
347 &new_one
->dwCompReadAttrOffset
, FALSE
);
349 current_offset
= updateField(lpcs
->dwCompReadClauseLen
,
350 lpcs
->dwCompReadClauseOffset
,
351 current_offset
, newdata
, olddata
,
352 &new_one
->dwCompReadClauseLen
,
353 &new_one
->dwCompReadClauseOffset
, FALSE
);
355 current_offset
= updateField(lpcs
->dwCompReadStrLen
,
356 lpcs
->dwCompReadStrOffset
,
357 current_offset
, newdata
, olddata
,
358 &new_one
->dwCompReadStrLen
,
359 &new_one
->dwCompReadStrOffset
, TRUE
);
361 current_offset
= updateField(lpcs
->dwCompAttrLen
,
362 lpcs
->dwCompAttrOffset
,
363 current_offset
, newdata
, olddata
,
364 &new_one
->dwCompAttrLen
,
365 &new_one
->dwCompAttrOffset
, FALSE
);
367 current_offset
= updateField(lpcs
->dwCompClauseLen
,
368 lpcs
->dwCompClauseOffset
,
369 current_offset
, newdata
, olddata
,
370 &new_one
->dwCompClauseLen
,
371 &new_one
->dwCompClauseOffset
, FALSE
);
373 current_offset
= updateField(lpcs
->dwCompStrLen
,
374 lpcs
->dwCompStrOffset
,
375 current_offset
, newdata
, olddata
,
376 &new_one
->dwCompStrLen
,
377 &new_one
->dwCompStrOffset
, TRUE
);
379 new_one
->dwCursorPos
= lpcs
->dwCursorPos
;
380 new_one
->dwDeltaStart
= 0;
382 current_offset
= updateField(lpcs
->dwResultReadClauseLen
,
383 lpcs
->dwResultReadClauseOffset
,
384 current_offset
, newdata
, olddata
,
385 &new_one
->dwResultReadClauseLen
,
386 &new_one
->dwResultReadClauseOffset
, FALSE
);
388 current_offset
= updateField(lpcs
->dwResultReadStrLen
,
389 lpcs
->dwResultReadStrOffset
,
390 current_offset
, newdata
, olddata
,
391 &new_one
->dwResultReadStrLen
,
392 &new_one
->dwResultReadStrOffset
, TRUE
);
394 /* new ResultClause , ResultStr */
396 current_offset
= updateField(lpcs
->dwPrivateSize
,
397 lpcs
->dwPrivateOffset
,
398 current_offset
, newdata
, olddata
,
399 &new_one
->dwPrivateSize
,
400 &new_one
->dwPrivateOffset
, FALSE
);
407 new_one
->dwResultClauseLen
= sizeof(DWORD
) * 2;
408 new_one
->dwResultClauseOffset
= current_offset
;
409 *(DWORD
*)&newdata
[current_offset
] = 0;
410 current_offset
+= sizeof(DWORD
);
411 *(DWORD
*)&newdata
[current_offset
] = len
;
412 current_offset
+= sizeof(DWORD
);
416 new_one
->dwResultStrLen
= len
;
419 new_one
->dwResultStrOffset
= current_offset
;
420 memcpy(&newdata
[current_offset
], resultstr
, len
* sizeof(WCHAR
));
429 static void GenerateIMEMessage(HIMC hIMC
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
431 LPINPUTCONTEXT lpIMC
;
432 LPTRANSMSG lpTransMsg
;
434 lpIMC
= LockRealIMC(hIMC
);
438 lpIMC
->hMsgBuf
= ImmReSizeIMCC(lpIMC
->hMsgBuf
, (lpIMC
->dwNumMsgBuf
+ 1) * sizeof(TRANSMSG
));
442 lpTransMsg
= ImmLockIMCC(lpIMC
->hMsgBuf
);
446 lpTransMsg
+= lpIMC
->dwNumMsgBuf
;
447 lpTransMsg
->message
= msg
;
448 lpTransMsg
->wParam
= wParam
;
449 lpTransMsg
->lParam
= lParam
;
451 ImmUnlockIMCC(lpIMC
->hMsgBuf
);
452 lpIMC
->dwNumMsgBuf
++;
454 ImmGenerateMessage(RealIMC(hIMC
));
458 static void GenerateIMECHARMessages(HIMC hIMC
, LPWSTR String
, DWORD length
)
460 LPINPUTCONTEXT lpIMC
;
461 LPTRANSMSG lpTransMsg
;
467 lpIMC
= LockRealIMC(hIMC
);
471 lpIMC
->hMsgBuf
= ImmReSizeIMCC(lpIMC
->hMsgBuf
, (lpIMC
->dwNumMsgBuf
+ length
) * sizeof(TRANSMSG
));
475 lpTransMsg
= ImmLockIMCC(lpIMC
->hMsgBuf
);
479 lpTransMsg
+= lpIMC
->dwNumMsgBuf
;
480 for (i
= 0; i
< length
; i
++)
482 lpTransMsg
->message
= WM_IME_CHAR
;
483 lpTransMsg
->wParam
= String
[i
];
484 lpTransMsg
->lParam
= 1;
488 ImmUnlockIMCC(lpIMC
->hMsgBuf
);
489 lpIMC
->dwNumMsgBuf
+= length
;
491 ImmGenerateMessage(RealIMC(hIMC
));
495 static BOOL
GenerateMessageToTransKey(LPDWORD lpTransBuf
, UINT
*uNumTranMsgs
,
496 UINT msg
, WPARAM wParam
, LPARAM lParam
)
500 if (*uNumTranMsgs
+ 1 >= (UINT
)*lpTransBuf
)
503 ptr
= (LPTRANSMSG
)(lpTransBuf
+ 1 + *uNumTranMsgs
* 3);
505 ptr
->wParam
= wParam
;
506 ptr
->lParam
= lParam
;
513 static BOOL
IME_RemoveFromSelected(HIMC hIMC
)
516 for (i
= 0; i
< hSelectedCount
; i
++)
518 if (hSelectedFrom
[i
] == hIMC
)
520 if (i
< hSelectedCount
- 1)
521 memmove(&hSelectedFrom
[i
], &hSelectedFrom
[i
+ 1], (hSelectedCount
- i
- 1) * sizeof(HIMC
));
529 static void IME_AddToSelected(HIMC hIMC
)
533 hSelectedFrom
= HeapReAlloc(GetProcessHeap(), 0, hSelectedFrom
, hSelectedCount
* sizeof(HIMC
));
535 hSelectedFrom
= HeapAlloc(GetProcessHeap(), 0, sizeof(HIMC
));
536 hSelectedFrom
[hSelectedCount
- 1] = hIMC
;
539 static void UpdateDataInDefaultIMEWindow(HIMC hIMC
, HWND hwnd
, BOOL showable
)
541 LPCOMPOSITIONSTRING compstr
;
542 LPINPUTCONTEXT lpIMC
;
544 lpIMC
= LockRealIMC(hIMC
);
549 compstr
= ImmLockIMCC(lpIMC
->hCompStr
);
553 if (compstr
== NULL
|| compstr
->dwCompStrLen
== 0)
554 ShowWindow(hwnd
, SW_HIDE
);
556 ShowWindow(hwnd
, SW_SHOWNOACTIVATE
);
558 RedrawWindow(hwnd
, NULL
, NULL
, RDW_ERASENOW
| RDW_INVALIDATE
);
561 ImmUnlockIMCC(lpIMC
->hCompStr
);
566 BOOL WINAPI
ImeInquire(LPIMEINFO lpIMEInfo
, LPWSTR lpszUIClass
, LPCWSTR lpszOption
)
569 lpIMEInfo
->dwPrivateDataSize
= sizeof(IMEPRIVATE
);
570 lpIMEInfo
->fdwProperty
= IME_PROP_UNICODE
| IME_PROP_AT_CARET
;
571 lpIMEInfo
->fdwConversionCaps
= IME_CMODE_NATIVE
;
572 lpIMEInfo
->fdwSentenceCaps
= IME_SMODE_AUTOMATIC
;
573 lpIMEInfo
->fdwUICaps
= UI_CAP_2700
;
574 /* Tell App we cannot accept ImeSetCompositionString calls */
576 lpIMEInfo
->fdwSCSCaps
= 0;
577 lpIMEInfo
->fdwSelectCaps
= SELECT_CAP_CONVERSION
;
579 lstrcpyW(lpszUIClass
, UI_CLASS_NAME
);
584 BOOL WINAPI
ImeConfigure(HKL hKL
, HWND hWnd
, DWORD dwMode
, LPVOID lpData
)
586 FIXME("(%p, %p, %d, %p): stub\n", hKL
, hWnd
, dwMode
, lpData
);
587 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
591 DWORD WINAPI
ImeConversionList(HIMC hIMC
, LPCWSTR lpSource
, LPCANDIDATELIST lpCandList
,
592 DWORD dwBufLen
, UINT uFlag
)
595 FIXME("(%p, %s, %p, %d, %d): stub\n", hIMC
, debugstr_w(lpSource
), lpCandList
,
597 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
601 BOOL WINAPI
ImeDestroy(UINT uForce
)
604 HeapFree(GetProcessHeap(), 0, hSelectedFrom
);
605 hSelectedFrom
= NULL
;
610 LRESULT WINAPI
ImeEscape(HIMC hIMC
, UINT uSubFunc
, LPVOID lpData
)
612 TRACE("%x %p\n", uSubFunc
, lpData
);
616 BOOL WINAPI
ImeProcessKey(HIMC hIMC
, UINT vKey
, LPARAM lKeyData
, CONST LPBYTE lpbKeyState
)
618 LPINPUTCONTEXT lpIMC
;
621 TRACE("hIMC %p vKey 0x%04x lKeyData 0x%08lx lpbKeyState %p\n", hIMC
, vKey
, lKeyData
, lpbKeyState
);
632 inIME
= macdrv_using_input_method();
633 lpIMC
= LockRealIMC(hIMC
);
636 LPIMEPRIVATE myPrivate
;
637 myPrivate
= ImmLockIMCC(lpIMC
->hPrivate
);
639 if (inIME
&& !myPrivate
->bInternalState
)
640 ImmSetOpenStatus(RealIMC(FROM_MACDRV
), TRUE
);
641 else if (!inIME
&& myPrivate
->bInternalState
)
643 ShowWindow(myPrivate
->hwndDefault
, SW_HIDE
);
644 ImmDestroyIMCC(lpIMC
->hCompStr
);
645 lpIMC
->hCompStr
= ImeCreateBlankCompStr();
646 ImmSetOpenStatus(RealIMC(FROM_MACDRV
), FALSE
);
649 myPrivate
->repeat
= (lKeyData
>> 30) & 0x1;
651 myPrivate
->bInternalState
= inIME
;
652 ImmUnlockIMCC(lpIMC
->hPrivate
);
659 BOOL WINAPI
ImeSelect(HIMC hIMC
, BOOL fSelect
)
661 LPINPUTCONTEXT lpIMC
;
662 TRACE("%p %s\n", hIMC
, fSelect
? "TRUE" : "FALSE");
664 if (hIMC
== FROM_MACDRV
)
666 ERR("ImeSelect should never be called from Cocoa\n");
675 return IME_RemoveFromSelected(hIMC
);
677 IME_AddToSelected(hIMC
);
679 /* Initialize our structures */
680 lpIMC
= LockRealIMC(hIMC
);
683 LPIMEPRIVATE myPrivate
;
684 myPrivate
= ImmLockIMCC(lpIMC
->hPrivate
);
685 myPrivate
->bInComposition
= FALSE
;
686 myPrivate
->bInternalState
= FALSE
;
687 myPrivate
->textfont
= NULL
;
688 myPrivate
->hwndDefault
= NULL
;
689 myPrivate
->repeat
= 0;
690 ImmUnlockIMCC(lpIMC
->hPrivate
);
697 BOOL WINAPI
ImeSetActiveContext(HIMC hIMC
, BOOL fFlag
)
699 FIXME("(%p, %x): stub\n", hIMC
, fFlag
);
703 UINT WINAPI
ImeToAsciiEx(UINT uVKey
, UINT uScanCode
, CONST LPBYTE lpbKeyState
,
704 LPDWORD lpdwTransKey
, UINT fuState
, HIMC hIMC
)
707 LPINPUTCONTEXT lpIMC
;
708 LPIMEPRIVATE myPrivate
;
713 TRACE("uVKey 0x%04x uScanCode 0x%04x fuState %u hIMC %p\n", uVKey
, uScanCode
, fuState
, hIMC
);
715 vkey
= LOWORD(uVKey
);
717 if (vkey
== VK_KANA
|| vkey
== VK_KANJI
|| vkey
== VK_MENU
)
719 TRACE("Skipping metakey\n");
723 lpIMC
= LockRealIMC(hIMC
);
724 myPrivate
= ImmLockIMCC(lpIMC
->hPrivate
);
725 if (!myPrivate
->bInternalState
)
727 ImmUnlockIMCC(lpIMC
->hPrivate
);
732 repeat
= myPrivate
->repeat
;
733 hwndDefault
= myPrivate
->hwndDefault
;
734 ImmUnlockIMCC(lpIMC
->hPrivate
);
737 TRACE("Processing Mac 0x%04x\n", vkey
);
738 rc
= macdrv_process_text_input(uVKey
, uScanCode
, repeat
, lpbKeyState
, hIMC
);
743 UINT msg
= (uScanCode
& 0x8000) ? WM_KEYUP
: WM_KEYDOWN
;
745 /* KeyStroke not processed by the IME
746 * so we need to rebuild the KeyDown message and pass it on to WINE
748 if (!GenerateMessageToTransKey(lpdwTransKey
, &msgs
, msg
, vkey
, MAKELONG(0x0001, uScanCode
)))
749 GenerateIMEMessage(hIMC
, msg
, vkey
, MAKELONG(0x0001, uScanCode
));
754 UpdateDataInDefaultIMEWindow(hIMC
, hwndDefault
, FALSE
);
758 BOOL WINAPI
NotifyIME(HIMC hIMC
, DWORD dwAction
, DWORD dwIndex
, DWORD dwValue
)
761 LPINPUTCONTEXT lpIMC
;
763 TRACE("%p %i %i %i\n", hIMC
, dwAction
, dwIndex
, dwValue
);
765 lpIMC
= LockRealIMC(hIMC
);
771 case NI_OPENCANDIDATE
: FIXME("NI_OPENCANDIDATE\n"); break;
772 case NI_CLOSECANDIDATE
: FIXME("NI_CLOSECANDIDATE\n"); break;
773 case NI_SELECTCANDIDATESTR
: FIXME("NI_SELECTCANDIDATESTR\n"); break;
774 case NI_CHANGECANDIDATELIST
: FIXME("NI_CHANGECANDIDATELIST\n"); break;
775 case NI_SETCANDIDATE_PAGESTART
: FIXME("NI_SETCANDIDATE_PAGESTART\n"); break;
776 case NI_SETCANDIDATE_PAGESIZE
: FIXME("NI_SETCANDIDATE_PAGESIZE\n"); break;
777 case NI_CONTEXTUPDATED
:
780 case IMC_SETCOMPOSITIONWINDOW
: FIXME("NI_CONTEXTUPDATED: IMC_SETCOMPOSITIONWINDOW\n"); break;
781 case IMC_SETCONVERSIONMODE
: FIXME("NI_CONTEXTUPDATED: IMC_SETCONVERSIONMODE\n"); break;
782 case IMC_SETSENTENCEMODE
: FIXME("NI_CONTEXTUPDATED: IMC_SETSENTENCEMODE\n"); break;
783 case IMC_SETCANDIDATEPOS
: FIXME("NI_CONTEXTUPDATED: IMC_SETCANDIDATEPOS\n"); break;
784 case IMC_SETCOMPOSITIONFONT
:
786 LPIMEPRIVATE myPrivate
;
787 TRACE("NI_CONTEXTUPDATED: IMC_SETCOMPOSITIONFONT\n");
789 myPrivate
= ImmLockIMCC(lpIMC
->hPrivate
);
790 if (myPrivate
->textfont
)
792 DeleteObject(myPrivate
->textfont
);
793 myPrivate
->textfont
= NULL
;
795 myPrivate
->textfont
= CreateFontIndirectW(&lpIMC
->lfFont
.W
);
796 ImmUnlockIMCC(lpIMC
->hPrivate
);
799 case IMC_SETOPENSTATUS
:
801 LPIMEPRIVATE myPrivate
;
802 TRACE("NI_CONTEXTUPDATED: IMC_SETOPENSTATUS\n");
804 myPrivate
= ImmLockIMCC(lpIMC
->hPrivate
);
805 if (lpIMC
->fOpen
!= myPrivate
->bInternalState
&& myPrivate
->bInComposition
)
807 if(lpIMC
->fOpen
== FALSE
)
809 GenerateIMEMessage(hIMC
, WM_IME_ENDCOMPOSITION
, 0, 0);
810 myPrivate
->bInComposition
= FALSE
;
814 GenerateIMEMessage(hIMC
, WM_IME_STARTCOMPOSITION
, 0, 0);
815 GenerateIMEMessage(hIMC
, WM_IME_COMPOSITION
, 0, 0);
818 myPrivate
->bInternalState
= lpIMC
->fOpen
;
822 default: FIXME("NI_CONTEXTUPDATED: Unknown\n"); break;
825 case NI_COMPOSITIONSTR
:
833 LPCOMPOSITIONSTRING cs
= NULL
;
835 LPIMEPRIVATE myPrivate
;
837 TRACE("NI_COMPOSITIONSTR: CPS_COMPLETE\n");
839 /* clear existing result */
840 newCompStr
= updateResultStr(lpIMC
->hCompStr
, NULL
, 0);
842 ImmDestroyIMCC(lpIMC
->hCompStr
);
843 lpIMC
->hCompStr
= newCompStr
;
847 cdata
= ImmLockIMCC(lpIMC
->hCompStr
);
848 cs
= (LPCOMPOSITIONSTRING
)cdata
;
849 cplen
= cs
->dwCompStrLen
;
850 cpstr
= (LPWSTR
)&cdata
[cs
->dwCompStrOffset
];
851 ImmUnlockIMCC(lpIMC
->hCompStr
);
855 WCHAR param
= cpstr
[0];
856 DWORD flags
= GCS_COMPSTR
;
858 newCompStr
= updateResultStr(lpIMC
->hCompStr
, cpstr
, cplen
);
859 ImmDestroyIMCC(lpIMC
->hCompStr
);
860 lpIMC
->hCompStr
= newCompStr
;
861 newCompStr
= updateCompStr(lpIMC
->hCompStr
, NULL
, 0, &flags
);
862 ImmDestroyIMCC(lpIMC
->hCompStr
);
863 lpIMC
->hCompStr
= newCompStr
;
865 GenerateIMEMessage(hIMC
, WM_IME_COMPOSITION
, 0, flags
);
867 GenerateIMEMessage(hIMC
, WM_IME_COMPOSITION
, param
,
868 GCS_RESULTSTR
| GCS_RESULTCLAUSE
);
871 GenerateIMEMessage(hIMC
, WM_IME_ENDCOMPOSITION
, 0, 0);
873 myPrivate
= ImmLockIMCC(lpIMC
->hPrivate
);
874 myPrivate
->bInComposition
= FALSE
;
875 ImmUnlockIMCC(lpIMC
->hPrivate
);
880 case CPS_CONVERT
: FIXME("NI_COMPOSITIONSTR: CPS_CONVERT\n"); break;
881 case CPS_REVERT
: FIXME("NI_COMPOSITIONSTR: CPS_REVERT\n"); break;
884 LPIMEPRIVATE myPrivate
;
886 TRACE("NI_COMPOSITIONSTR: CPS_CANCEL\n");
889 ImmDestroyIMCC(lpIMC
->hCompStr
);
891 lpIMC
->hCompStr
= ImeCreateBlankCompStr();
893 myPrivate
= ImmLockIMCC(lpIMC
->hPrivate
);
894 if (myPrivate
->bInComposition
)
896 GenerateIMEMessage(hIMC
, WM_IME_ENDCOMPOSITION
, 0, 0);
897 myPrivate
->bInComposition
= FALSE
;
899 ImmUnlockIMCC(lpIMC
->hPrivate
);
903 default: FIXME("NI_COMPOSITIONSTR: Unknown\n"); break;
906 default: FIXME("Unknown Message\n"); break;
913 BOOL WINAPI
ImeRegisterWord(LPCWSTR lpszReading
, DWORD dwStyle
, LPCWSTR lpszRegister
)
915 FIXME("(%s, %d, %s): stub\n", debugstr_w(lpszReading
), dwStyle
, debugstr_w(lpszRegister
));
916 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
920 BOOL WINAPI
ImeUnregisterWord(LPCWSTR lpszReading
, DWORD dwStyle
, LPCWSTR lpszUnregister
)
922 FIXME("(%s, %d, %s): stub\n", debugstr_w(lpszReading
), dwStyle
, debugstr_w(lpszUnregister
));
923 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
927 UINT WINAPI
ImeGetRegisterWordStyle(UINT nItem
, LPSTYLEBUFW lpStyleBuf
)
929 FIXME("(%d, %p): stub\n", nItem
, lpStyleBuf
);
930 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
934 UINT WINAPI
ImeEnumRegisterWord(REGISTERWORDENUMPROCW lpfnEnumProc
, LPCWSTR lpszReading
,
935 DWORD dwStyle
, LPCWSTR lpszRegister
, LPVOID lpData
)
937 FIXME("(%p, %s, %d, %s, %p): stub\n", lpfnEnumProc
, debugstr_w(lpszReading
), dwStyle
,
938 debugstr_w(lpszRegister
), lpData
);
939 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
943 BOOL WINAPI
ImeSetCompositionString(HIMC hIMC
, DWORD dwIndex
, LPCVOID lpComp
, DWORD dwCompLen
,
944 LPCVOID lpRead
, DWORD dwReadLen
)
946 LPINPUTCONTEXT lpIMC
;
949 LPIMEPRIVATE myPrivate
;
951 TRACE("(%p, %d, %p, %d, %p, %d):\n", hIMC
, dwIndex
, lpComp
, dwCompLen
, lpRead
, dwReadLen
);
955 * this sets the composition string in the imm32.dll level
956 * of the composition buffer.
957 * TODO: set the Cocoa window's marked text string and tell text input context
960 if (lpRead
&& dwReadLen
)
961 FIXME("Reading string unimplemented\n");
963 lpIMC
= LockRealIMC(hIMC
);
968 myPrivate
= ImmLockIMCC(lpIMC
->hPrivate
);
970 if (dwIndex
== SCS_SETSTR
)
974 if (!myPrivate
->bInComposition
)
976 GenerateIMEMessage(hIMC
, WM_IME_STARTCOMPOSITION
, 0, 0);
977 myPrivate
->bInComposition
= TRUE
;
982 if (dwCompLen
&& lpComp
)
984 newCompStr
= updateCompStr(lpIMC
->hCompStr
, (LPCWSTR
)lpComp
, dwCompLen
/ sizeof(WCHAR
), &flags
);
985 ImmDestroyIMCC(lpIMC
->hCompStr
);
986 lpIMC
->hCompStr
= newCompStr
;
988 wParam
= ((const WCHAR
*)lpComp
)[0];
989 flags
|= GCS_COMPCLAUSE
| GCS_COMPATTR
| GCS_DELTASTART
;
993 newCompStr
= updateCompStr(lpIMC
->hCompStr
, NULL
, 0, &flags
);
994 ImmDestroyIMCC(lpIMC
->hCompStr
);
995 lpIMC
->hCompStr
= newCompStr
;
999 GenerateIMEMessage(hIMC
, WM_IME_COMPOSITION
, wParam
, flags
);
1000 ImmUnlockIMCC(lpIMC
->hPrivate
);
1001 UnlockRealIMC(hIMC
);
1006 DWORD WINAPI
ImeGetImeMenuItems(HIMC hIMC
, DWORD dwFlags
, DWORD dwType
, LPIMEMENUITEMINFOW lpImeParentMenu
,
1007 LPIMEMENUITEMINFOW lpImeMenu
, DWORD dwSize
)
1009 FIXME("(%p, %x %x %p %p %x): stub\n", hIMC
, dwFlags
, dwType
, lpImeParentMenu
, lpImeMenu
, dwSize
);
1010 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1014 static void IME_SetCursorPos(void* hIMC
, DWORD pos
)
1016 LPINPUTCONTEXT lpIMC
;
1017 LPCOMPOSITIONSTRING compstr
;
1022 lpIMC
= LockRealIMC(hIMC
);
1026 compstr
= ImmLockIMCC(lpIMC
->hCompStr
);
1029 UnlockRealIMC(hIMC
);
1033 compstr
->dwCursorPos
= pos
;
1034 ImmUnlockIMCC(lpIMC
->hCompStr
);
1035 UnlockRealIMC(hIMC
);
1036 GenerateIMEMessage(FROM_MACDRV
, WM_IME_COMPOSITION
, pos
, GCS_CURSORPOS
);
1041 static void IME_SetCompositionString(void* hIMC
, LPCVOID lpComp
, DWORD dwCompLen
)
1043 ImeSetCompositionString(hIMC
, SCS_SETSTR
, lpComp
, dwCompLen
, NULL
, 0);
1046 static void IME_NotifyComplete(void* hIMC
)
1048 NotifyIME(hIMC
, NI_COMPOSITIONSTR
, CPS_COMPLETE
, 0);
1052 * Internal functions to help with IME window management
1054 static void PaintDefaultIMEWnd(HIMC hIMC
, HWND hwnd
)
1059 LPCOMPOSITIONSTRING compstr
;
1060 LPBYTE compdata
= NULL
;
1062 MONITORINFO mon_info
;
1063 INT offX
= 0, offY
= 0;
1064 LPINPUTCONTEXT lpIMC
;
1066 lpIMC
= LockRealIMC(hIMC
);
1070 hdc
= BeginPaint(hwnd
, &ps
);
1072 GetClientRect(hwnd
, &rect
);
1073 FillRect(hdc
, &rect
, (HBRUSH
)(COLOR_WINDOW
+ 1));
1075 compdata
= ImmLockIMCC(lpIMC
->hCompStr
);
1076 compstr
= (LPCOMPOSITIONSTRING
)compdata
;
1078 if (compstr
->dwCompStrLen
&& compstr
->dwCompStrOffset
)
1082 HFONT oldfont
= NULL
;
1084 LPIMEPRIVATE myPrivate
;
1086 CompString
= (LPWSTR
)(compdata
+ compstr
->dwCompStrOffset
);
1087 myPrivate
= ImmLockIMCC(lpIMC
->hPrivate
);
1089 if (myPrivate
->textfont
)
1090 oldfont
= SelectObject(hdc
, myPrivate
->textfont
);
1092 ImmUnlockIMCC(lpIMC
->hPrivate
);
1094 GetTextExtentPoint32W(hdc
, CompString
, compstr
->dwCompStrLen
, &size
);
1097 LPtoDP(hdc
, &pt
, 1);
1100 * How this works based on tests on windows:
1101 * CFS_POINT: then we start our window at the point and grow it as large
1102 * as it needs to be for the string.
1103 * CFS_RECT: we still use the ptCurrentPos as a starting point and our
1104 * window is only as large as we need for the string, but we do not
1105 * grow such that our window exceeds the given rect. Wrapping if
1106 * needed and possible. If our ptCurrentPos is outside of our rect
1107 * then no window is displayed.
1108 * CFS_FORCE_POSITION: appears to behave just like CFS_POINT
1109 * maybe because the default MSIME does not do any IME adjusting.
1111 if (lpIMC
->cfCompForm
.dwStyle
!= CFS_DEFAULT
)
1113 POINT cpt
= lpIMC
->cfCompForm
.ptCurrentPos
;
1114 ClientToScreen(lpIMC
->hWnd
, &cpt
);
1117 rect
.right
= rect
.left
+ pt
.x
;
1118 rect
.bottom
= rect
.top
+ pt
.y
;
1119 monitor
= MonitorFromPoint(cpt
, MONITOR_DEFAULTTOPRIMARY
);
1121 else /* CFS_DEFAULT */
1123 /* Windows places the default IME window in the bottom left */
1124 HWND target
= lpIMC
->hWnd
;
1125 if (!target
) target
= GetFocus();
1127 GetWindowRect(target
, &rect
);
1128 rect
.top
= rect
.bottom
;
1129 rect
.right
= rect
.left
+ pt
.x
+ 20;
1130 rect
.bottom
= rect
.top
+ pt
.y
+ 20;
1132 monitor
= MonitorFromWindow(target
, MONITOR_DEFAULTTOPRIMARY
);
1135 if (lpIMC
->cfCompForm
.dwStyle
== CFS_RECT
)
1138 client
=lpIMC
->cfCompForm
.rcArea
;
1139 MapWindowPoints(lpIMC
->hWnd
, 0, (POINT
*)&client
, 2);
1140 IntersectRect(&rect
, &rect
, &client
);
1141 /* TODO: Wrap the input if needed */
1144 if (lpIMC
->cfCompForm
.dwStyle
== CFS_DEFAULT
)
1146 /* make sure we are on the desktop */
1147 mon_info
.cbSize
= sizeof(mon_info
);
1148 GetMonitorInfoW(monitor
, &mon_info
);
1150 if (rect
.bottom
> mon_info
.rcWork
.bottom
)
1152 int shift
= rect
.bottom
- mon_info
.rcWork
.bottom
;
1154 rect
.bottom
-= shift
;
1158 rect
.right
-= rect
.left
;
1161 if (rect
.right
> mon_info
.rcWork
.right
)
1163 int shift
= rect
.right
- mon_info
.rcWork
.right
;
1165 rect
.right
-= shift
;
1169 SetWindowPos(hwnd
, HWND_TOPMOST
, rect
.left
, rect
.top
, rect
.right
- rect
.left
,
1170 rect
.bottom
- rect
.top
, SWP_NOACTIVATE
);
1172 TextOutW(hdc
, offX
, offY
, CompString
, compstr
->dwCompStrLen
);
1175 SelectObject(hdc
, oldfont
);
1178 ImmUnlockIMCC(lpIMC
->hCompStr
);
1180 EndPaint(hwnd
, &ps
);
1181 UnlockRealIMC(hIMC
);
1184 static void DefaultIMEComposition(HIMC hIMC
, HWND hwnd
, LPARAM lParam
)
1186 TRACE("IME message WM_IME_COMPOSITION 0x%lx\n", lParam
);
1187 if (lParam
& GCS_RESULTSTR
)
1189 LPCOMPOSITIONSTRING compstr
;
1193 LPINPUTCONTEXT lpIMC
;
1195 lpIMC
= LockRealIMC(hIMC
);
1199 TRACE("Posting result as IME_CHAR\n");
1200 compdata
= ImmLockIMCC(lpIMC
->hCompStr
);
1201 compstr
= (LPCOMPOSITIONSTRING
)compdata
;
1202 ResultStr
= (LPWSTR
)(compdata
+ compstr
->dwResultStrOffset
);
1203 GenerateIMECHARMessages(hIMC
, ResultStr
, compstr
->dwResultStrLen
);
1204 ImmUnlockIMCC(lpIMC
->hCompStr
);
1206 /* clear the buffer */
1207 newCompStr
= updateResultStr(lpIMC
->hCompStr
, NULL
, 0);
1208 ImmDestroyIMCC(lpIMC
->hCompStr
);
1209 lpIMC
->hCompStr
= newCompStr
;
1210 UnlockRealIMC(hIMC
);
1213 UpdateDataInDefaultIMEWindow(hIMC
, hwnd
, TRUE
);
1216 static void DefaultIMEStartComposition(HIMC hIMC
, HWND hwnd
)
1218 LPINPUTCONTEXT lpIMC
;
1220 lpIMC
= LockRealIMC(hIMC
);
1224 TRACE("IME message WM_IME_STARTCOMPOSITION\n");
1225 lpIMC
->hWnd
= GetFocus();
1226 ShowWindow(hwnd
, SW_SHOWNOACTIVATE
);
1227 UnlockRealIMC(hIMC
);
1230 static LRESULT
ImeHandleNotify(HIMC hIMC
, HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1234 case IMN_OPENSTATUSWINDOW
:
1235 FIXME("WM_IME_NOTIFY:IMN_OPENSTATUSWINDOW\n");
1237 case IMN_CLOSESTATUSWINDOW
:
1238 FIXME("WM_IME_NOTIFY:IMN_CLOSESTATUSWINDOW\n");
1240 case IMN_OPENCANDIDATE
:
1241 FIXME("WM_IME_NOTIFY:IMN_OPENCANDIDATE\n");
1243 case IMN_CHANGECANDIDATE
:
1244 FIXME("WM_IME_NOTIFY:IMN_CHANGECANDIDATE\n");
1246 case IMN_CLOSECANDIDATE
:
1247 FIXME("WM_IME_NOTIFY:IMN_CLOSECANDIDATE\n");
1249 case IMN_SETCONVERSIONMODE
:
1250 FIXME("WM_IME_NOTIFY:IMN_SETCONVERSIONMODE\n");
1252 case IMN_SETSENTENCEMODE
:
1253 FIXME("WM_IME_NOTIFY:IMN_SETSENTENCEMODE\n");
1255 case IMN_SETOPENSTATUS
:
1256 FIXME("WM_IME_NOTIFY:IMN_SETOPENSTATUS\n");
1258 case IMN_SETCANDIDATEPOS
:
1259 FIXME("WM_IME_NOTIFY:IMN_SETCANDIDATEPOS\n");
1261 case IMN_SETCOMPOSITIONFONT
:
1262 FIXME("WM_IME_NOTIFY:IMN_SETCOMPOSITIONFONT\n");
1264 case IMN_SETCOMPOSITIONWINDOW
:
1265 FIXME("WM_IME_NOTIFY:IMN_SETCOMPOSITIONWINDOW\n");
1268 FIXME("WM_IME_NOTIFY:IMN_GUIDELINE\n");
1270 case IMN_SETSTATUSWINDOWPOS
:
1271 FIXME("WM_IME_NOTIFY:IMN_SETSTATUSWINDOWPOS\n");
1274 FIXME("WM_IME_NOTIFY:<Unknown 0x%lx>\n", wParam
);
1280 static LRESULT WINAPI
IME_WindowProc(HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1285 TRACE("Incoming Message 0x%x (0x%08lx, 0x%08lx)\n", msg
, wParam
, lParam
);
1288 * Each UI window contains the current Input Context.
1289 * This Input Context can be obtained by calling GetWindowLong
1290 * with IMMGWL_IMC when the UI window receives a WM_IME_xxx message.
1291 * The UI window can refer to this Input Context and handles the
1295 hIMC
= (HIMC
)GetWindowLongPtrW(hwnd
, IMMGWL_IMC
);
1297 hIMC
= RealIMC(FROM_MACDRV
);
1299 /* if we have no hIMC there are many messages we cannot process */
1303 case WM_IME_STARTCOMPOSITION
:
1304 case WM_IME_ENDCOMPOSITION
:
1305 case WM_IME_COMPOSITION
:
1307 case WM_IME_CONTROL
:
1308 case WM_IME_COMPOSITIONFULL
:
1321 LPIMEPRIVATE myPrivate
;
1322 LPINPUTCONTEXT lpIMC
;
1324 SetWindowTextA(hwnd
, "Wine Ime Active");
1326 lpIMC
= LockRealIMC(hIMC
);
1329 myPrivate
= ImmLockIMCC(lpIMC
->hPrivate
);
1330 myPrivate
->hwndDefault
= hwnd
;
1331 ImmUnlockIMCC(lpIMC
->hPrivate
);
1333 UnlockRealIMC(hIMC
);
1338 PaintDefaultIMEWnd(hIMC
, hwnd
);
1346 SetFocus((HWND
)wParam
);
1348 FIXME("Received focus, should never have focus\n");
1350 case WM_IME_COMPOSITION
:
1351 DefaultIMEComposition(hIMC
, hwnd
, lParam
);
1353 case WM_IME_STARTCOMPOSITION
:
1354 DefaultIMEStartComposition(hIMC
, hwnd
);
1356 case WM_IME_ENDCOMPOSITION
:
1357 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_IME_ENDCOMPOSITION", wParam
, lParam
);
1358 ShowWindow(hwnd
, SW_HIDE
);
1361 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_IME_SELECT", wParam
, lParam
);
1363 case WM_IME_CONTROL
:
1364 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_IME_CONTROL", wParam
, lParam
);
1368 rc
= ImeHandleNotify(hIMC
, hwnd
, msg
, wParam
, lParam
);
1371 TRACE("Non-standard message 0x%x\n", msg
);
1373 /* check the MSIME messages */
1374 if (msg
== WM_MSIME_SERVICE
)
1376 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_MSIME_SERVICE", wParam
, lParam
);
1379 else if (msg
== WM_MSIME_RECONVERTOPTIONS
)
1381 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_MSIME_RECONVERTOPTIONS", wParam
, lParam
);
1383 else if (msg
== WM_MSIME_MOUSE
)
1385 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_MSIME_MOUSE", wParam
, lParam
);
1387 else if (msg
== WM_MSIME_RECONVERTREQUEST
)
1389 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_MSIME_RECONVERTREQUEST", wParam
, lParam
);
1391 else if (msg
== WM_MSIME_RECONVERT
)
1393 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_MSIME_RECONVERT", wParam
, lParam
);
1395 else if (msg
== WM_MSIME_QUERYPOSITION
)
1397 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_MSIME_QUERYPOSITION", wParam
, lParam
);
1399 else if (msg
== WM_MSIME_DOCUMENTFEED
)
1401 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_MSIME_DOCUMENTFEED", wParam
, lParam
);
1403 /* DefWndProc if not an IME message */
1404 if (!rc
&& !((msg
>= WM_IME_STARTCOMPOSITION
&& msg
<= WM_IME_KEYLAST
) ||
1405 (msg
>= WM_IME_SETCONTEXT
&& msg
<= WM_IME_KEYUP
)))
1406 rc
= DefWindowProcW(hwnd
, msg
, wParam
, lParam
);
1412 /* Interfaces to other parts of the Mac driver */
1414 void IME_RegisterClasses(HINSTANCE hImeInst
)
1417 ZeroMemory(&wndClass
, sizeof(WNDCLASSW
));
1418 wndClass
.style
= CS_GLOBALCLASS
| CS_IME
| CS_HREDRAW
| CS_VREDRAW
;
1419 wndClass
.lpfnWndProc
= (WNDPROC
) IME_WindowProc
;
1420 wndClass
.cbClsExtra
= 0;
1421 wndClass
.cbWndExtra
= 2 * sizeof(LONG_PTR
);
1422 wndClass
.hInstance
= hImeInst
;
1423 wndClass
.hCursor
= LoadCursorW(NULL
, (LPWSTR
)IDC_ARROW
);
1424 wndClass
.hIcon
= LoadIconW(NULL
, (LPWSTR
)IDI_APPLICATION
);
1425 wndClass
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
1426 wndClass
.lpszMenuName
= 0;
1427 wndClass
.lpszClassName
= UI_CLASS_NAME
;
1429 RegisterClassW(&wndClass
);
1431 WM_MSIME_SERVICE
= RegisterWindowMessageA("MSIMEService");
1432 WM_MSIME_RECONVERTOPTIONS
= RegisterWindowMessageA("MSIMEReconvertOptions");
1433 WM_MSIME_MOUSE
= RegisterWindowMessageA("MSIMEMouseOperation");
1434 WM_MSIME_RECONVERTREQUEST
= RegisterWindowMessageA("MSIMEReconvertRequest");
1435 WM_MSIME_RECONVERT
= RegisterWindowMessageA("MSIMEReconvert");
1436 WM_MSIME_QUERYPOSITION
= RegisterWindowMessageA("MSIMEQueryPosition");
1437 WM_MSIME_DOCUMENTFEED
= RegisterWindowMessageA("MSIMEDocumentFeed");
1441 /***********************************************************************
1442 * macdrv_im_set_cursor_pos
1444 void macdrv_im_set_cursor_pos(const macdrv_event
*event
)
1446 HWND hwnd
= macdrv_get_window_hwnd(event
->window
);
1447 void *himc
= event
->im_set_cursor_pos
.data
;
1449 TRACE("win %p/%p himc %p pos %u\n", hwnd
, event
->window
, himc
, event
->im_set_cursor_pos
.pos
);
1451 if (!himc
) himc
= RealIMC(FROM_MACDRV
);
1453 IME_SetCursorPos(himc
, event
->im_set_cursor_pos
.pos
);
1457 /***********************************************************************
1458 * macdrv_im_set_text
1460 void macdrv_im_set_text(const macdrv_event
*event
)
1462 HWND hwnd
= macdrv_get_window_hwnd(event
->window
);
1463 void *himc
= event
->im_set_text
.data
;
1465 TRACE("win %p/%p himc %p text %s complete %u\n", hwnd
, event
->window
, himc
,
1466 debugstr_cf(event
->im_set_text
.text
), event
->im_set_text
.complete
);
1468 if (!himc
) himc
= RealIMC(FROM_MACDRV
);
1470 if (event
->im_set_text
.text
)
1472 CFIndex length
= CFStringGetLength(event
->im_set_text
.text
);
1473 const UniChar
*chars
= CFStringGetCharactersPtr(event
->im_set_text
.text
);
1474 UniChar
*buffer
= NULL
;
1478 buffer
= HeapAlloc(GetProcessHeap(), 0, length
* sizeof(*buffer
));
1479 CFStringGetCharacters(event
->im_set_text
.text
, CFRangeMake(0, length
), buffer
);
1484 IME_SetCompositionString(himc
, chars
, length
* sizeof(*chars
));
1490 input
.type
= INPUT_KEYBOARD
;
1493 input
.ki
.dwExtraInfo
= 0;
1495 for (i
= 0; i
< length
; i
++)
1497 input
.ki
.wScan
= chars
[i
];
1498 input
.ki
.dwFlags
= KEYEVENTF_UNICODE
;
1499 __wine_send_input(hwnd
, &input
);
1501 input
.ki
.dwFlags
= KEYEVENTF_UNICODE
| KEYEVENTF_KEYUP
;
1502 __wine_send_input(hwnd
, &input
);
1506 HeapFree(GetProcessHeap(), 0, buffer
);
1509 if (event
->im_set_text
.complete
)
1510 IME_NotifyComplete(himc
);