imm32: Use DrawTextW to wrap IME composition string.
[wine.git] / dlls / imm32 / ime.c
blobc10db8958f722c453d558d34f8b23fb2713401da
1 /*
2 * Copyright 2023 RĂ©mi Bernon for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <stdarg.h>
20 #include <stddef.h>
22 #include "imm_private.h"
24 WINE_DEFAULT_DEBUG_CHANNEL(imm);
26 static const char *debugstr_imn( WPARAM wparam )
28 switch (wparam)
30 case IMN_OPENSTATUSWINDOW: return "IMN_OPENSTATUSWINDOW";
31 case IMN_CLOSESTATUSWINDOW: return "IMN_CLOSESTATUSWINDOW";
32 case IMN_OPENCANDIDATE: return "IMN_OPENCANDIDATE";
33 case IMN_CHANGECANDIDATE: return "IMN_CHANGECANDIDATE";
34 case IMN_CLOSECANDIDATE: return "IMN_CLOSECANDIDATE";
35 case IMN_SETCONVERSIONMODE: return "IMN_SETCONVERSIONMODE";
36 case IMN_SETSENTENCEMODE: return "IMN_SETSENTENCEMODE";
37 case IMN_SETOPENSTATUS: return "IMN_SETOPENSTATUS";
38 case IMN_SETCANDIDATEPOS: return "IMN_SETCANDIDATEPOS";
39 case IMN_SETCOMPOSITIONFONT: return "IMN_SETCOMPOSITIONFONT";
40 case IMN_SETCOMPOSITIONWINDOW: return "IMN_SETCOMPOSITIONWINDOW";
41 case IMN_GUIDELINE: return "IMN_GUIDELINE";
42 case IMN_SETSTATUSWINDOWPOS: return "IMN_SETSTATUSWINDOWPOS";
43 default: return wine_dbg_sprintf( "%#Ix", wparam );
47 static const char *debugstr_imc( WPARAM wparam )
49 switch (wparam)
51 case IMC_GETCANDIDATEPOS: return "IMC_GETCANDIDATEPOS";
52 case IMC_SETCANDIDATEPOS: return "IMC_SETCANDIDATEPOS";
53 case IMC_GETCOMPOSITIONFONT: return "IMC_GETCOMPOSITIONFONT";
54 case IMC_SETCOMPOSITIONFONT: return "IMC_SETCOMPOSITIONFONT";
55 case IMC_GETCOMPOSITIONWINDOW: return "IMC_GETCOMPOSITIONWINDOW";
56 case IMC_SETCOMPOSITIONWINDOW: return "IMC_SETCOMPOSITIONWINDOW";
57 case IMC_GETSTATUSWINDOWPOS: return "IMC_GETSTATUSWINDOWPOS";
58 case IMC_SETSTATUSWINDOWPOS: return "IMC_SETSTATUSWINDOWPOS";
59 case IMC_CLOSESTATUSWINDOW: return "IMC_CLOSESTATUSWINDOW";
60 case IMC_OPENSTATUSWINDOW: return "IMC_OPENSTATUSWINDOW";
61 default: return wine_dbg_sprintf( "%#Ix", wparam );
65 static WCHAR *input_context_get_comp_str( INPUTCONTEXT *ctx, BOOL result, UINT *length )
67 COMPOSITIONSTRING *string;
68 WCHAR *text = NULL;
69 UINT len, off;
71 if (!(string = ImmLockIMCC( ctx->hCompStr ))) return NULL;
72 len = result ? string->dwResultStrLen : string->dwCompStrLen;
73 off = result ? string->dwResultStrOffset : string->dwCompStrOffset;
75 if (len && off && (text = malloc( (len + 1) * sizeof(WCHAR) )))
77 memcpy( text, (BYTE *)string + off, len * sizeof(WCHAR) );
78 text[len] = 0;
79 *length = len;
82 ImmUnlockIMCC( ctx->hCompStr );
83 return text;
86 static void input_context_set_comp_str( INPUTCONTEXT *ctx, const WCHAR *str, UINT len )
88 COMPOSITIONSTRING *compstr;
89 HIMCC himcc;
90 UINT size;
91 BYTE *dst;
93 size = sizeof(*compstr);
94 size += len * sizeof(WCHAR); /* GCS_COMPSTR */
95 size += len; /* GCS_COMPSTRATTR */
96 size += 2 * sizeof(DWORD); /* GCS_COMPSTRCLAUSE */
98 if (!(himcc = ImmReSizeIMCC( ctx->hCompStr, size )))
99 WARN( "Failed to resize input context composition string\n" );
100 else if (!(compstr = ImmLockIMCC( (ctx->hCompStr = himcc) )))
101 WARN( "Failed to lock input context composition string\n" );
102 else
104 memset( compstr, 0, sizeof(*compstr) );
105 compstr->dwSize = sizeof(*compstr);
107 if (len)
109 compstr->dwCursorPos = len;
111 compstr->dwCompStrLen = len;
112 compstr->dwCompStrOffset = compstr->dwSize;
113 dst = (BYTE *)compstr + compstr->dwCompStrOffset;
114 memcpy( dst, str, compstr->dwCompStrLen * sizeof(WCHAR) );
115 compstr->dwSize += compstr->dwCompStrLen * sizeof(WCHAR);
117 compstr->dwCompClauseLen = 2 * sizeof(DWORD);
118 compstr->dwCompClauseOffset = compstr->dwSize;
119 dst = (BYTE *)compstr + compstr->dwCompClauseOffset;
120 *((DWORD *)dst + 0) = 0;
121 *((DWORD *)dst + 1) = compstr->dwCompStrLen;
122 compstr->dwSize += compstr->dwCompClauseLen;
124 compstr->dwCompAttrLen = compstr->dwCompStrLen;
125 compstr->dwCompAttrOffset = compstr->dwSize;
126 dst = (BYTE *)compstr + compstr->dwCompAttrOffset;
127 memset( dst, ATTR_INPUT, compstr->dwCompAttrLen );
128 compstr->dwSize += compstr->dwCompAttrLen;
131 ImmUnlockIMCC( ctx->hCompStr );
135 static HFONT input_context_select_ui_font( INPUTCONTEXT *ctx, HDC hdc )
137 struct ime_private *priv;
138 HFONT font = NULL;
139 if (!(priv = ImmLockIMCC( ctx->hPrivate ))) return NULL;
140 if (priv->textfont) font = SelectObject( hdc, priv->textfont );
141 ImmUnlockIMCC( ctx->hPrivate );
142 return font;
145 static void ime_send_message( HIMC himc, UINT message, WPARAM wparam, LPARAM lparam )
147 INPUTCONTEXT *ctx;
148 TRANSMSG *msgs;
149 HIMCC himcc;
151 if (!(ctx = ImmLockIMC( himc ))) return;
152 if (!(himcc = ImmReSizeIMCC( ctx->hMsgBuf, (ctx->dwNumMsgBuf + 1) * sizeof(*msgs) )))
153 WARN( "Failed to resize input context message buffer\n" );
154 else if (!(msgs = ImmLockIMCC( (ctx->hMsgBuf = himcc) )))
155 WARN( "Failed to lock input context message buffer\n" );
156 else
158 TRANSMSG msg = {.message = message, .wParam = wparam, .lParam = lparam};
159 msgs[ctx->dwNumMsgBuf++] = msg;
160 ImmUnlockIMCC( ctx->hMsgBuf );
163 ImmUnlockIMC( himc );
164 ImmGenerateMessage( himc );
167 static UINT ime_set_composition_status( HIMC himc, BOOL composition )
169 struct ime_private *priv;
170 INPUTCONTEXT *ctx;
171 UINT msg = 0;
173 if (!(ctx = ImmLockIMC( himc ))) return 0;
174 if ((priv = ImmLockIMCC( ctx->hPrivate )))
176 if (!priv->bInComposition && composition) msg = WM_IME_STARTCOMPOSITION;
177 else if (priv->bInComposition && !composition) msg = WM_IME_ENDCOMPOSITION;
178 priv->bInComposition = composition;
179 ImmUnlockIMCC( ctx->hPrivate );
181 ImmUnlockIMC( himc );
183 return msg;
186 static void ime_ui_paint( HIMC himc, HWND hwnd )
188 PAINTSTRUCT ps;
189 RECT rect, new_rect;
190 HDC hdc;
191 HMONITOR monitor;
192 MONITORINFO mon_info;
193 INPUTCONTEXT *ctx;
194 POINT offset;
195 WCHAR *str;
196 UINT len;
198 if (!(ctx = ImmLockIMC( himc ))) return;
200 hdc = BeginPaint( hwnd, &ps );
202 GetClientRect( hwnd, &rect );
203 FillRect( hdc, &rect, (HBRUSH)(COLOR_WINDOW + 1) );
204 new_rect = rect;
206 if ((str = input_context_get_comp_str( ctx, FALSE, &len )))
208 HFONT font = input_context_select_ui_font( ctx, hdc );
209 SIZE size;
210 POINT pt;
212 GetTextExtentPoint32W( hdc, str, len, &size );
213 pt.x = size.cx;
214 pt.y = size.cy;
215 LPtoDP( hdc, &pt, 1 );
218 * How this works based on tests on windows:
219 * CFS_POINT: then we start our window at the point and grow it as large
220 * as it needs to be for the string.
221 * CFS_RECT: we still use the ptCurrentPos as a starting point and our
222 * window is only as large as we need for the string, but we do not
223 * grow such that our window exceeds the given rect. Wrapping if
224 * needed and possible. If our ptCurrentPos is outside of our rect
225 * then no window is displayed.
226 * CFS_FORCE_POSITION: appears to behave just like CFS_POINT
227 * maybe because the default MSIME does not do any IME adjusting.
229 if (ctx->cfCompForm.dwStyle != CFS_DEFAULT)
231 POINT cpt = ctx->cfCompForm.ptCurrentPos;
232 ClientToScreen( ctx->hWnd, &cpt );
233 rect.left = cpt.x;
234 rect.top = cpt.y;
235 rect.right = rect.left + pt.x;
236 rect.bottom = rect.top + pt.y;
237 offset.x = offset.y = 0;
238 monitor = MonitorFromPoint( cpt, MONITOR_DEFAULTTOPRIMARY );
240 else /* CFS_DEFAULT */
242 /* Windows places the default IME window in the bottom left */
243 HWND target = ctx->hWnd;
244 if (!target) target = GetFocus();
246 GetWindowRect( target, &rect );
247 rect.top = rect.bottom;
248 rect.right = rect.left + pt.x + 20;
249 rect.bottom = rect.top + pt.y + 20;
250 offset.x = offset.y = 10;
251 monitor = MonitorFromWindow( target, MONITOR_DEFAULTTOPRIMARY );
254 if (ctx->cfCompForm.dwStyle == CFS_RECT)
256 RECT client = ctx->cfCompForm.rcArea;
257 MapWindowPoints( ctx->hWnd, 0, (POINT *)&client, 2 );
258 IntersectRect( &rect, &rect, &client );
259 DrawTextW( hdc, str, len, &rect, DT_WORDBREAK | DT_CALCRECT );
262 if (ctx->cfCompForm.dwStyle == CFS_DEFAULT)
264 /* make sure we are on the desktop */
265 mon_info.cbSize = sizeof(mon_info);
266 GetMonitorInfoW( monitor, &mon_info );
268 if (rect.bottom > mon_info.rcWork.bottom)
270 int shift = rect.bottom - mon_info.rcWork.bottom;
271 rect.top -= shift;
272 rect.bottom -= shift;
274 if (rect.left < 0)
276 rect.right -= rect.left;
277 rect.left = 0;
279 if (rect.right > mon_info.rcWork.right)
281 int shift = rect.right - mon_info.rcWork.right;
282 rect.left -= shift;
283 rect.right -= shift;
287 new_rect = rect;
288 OffsetRect( &rect, offset.x - rect.left, offset.y - rect.top );
289 DrawTextW( hdc, str, len, &rect, DT_WORDBREAK );
291 if (font) SelectObject( hdc, font );
292 free( str );
295 EndPaint( hwnd, &ps );
296 ImmUnlockIMC( himc );
298 if (!EqualRect( &rect, &new_rect ))
299 SetWindowPos( hwnd, HWND_TOPMOST, new_rect.left, new_rect.top, new_rect.right - new_rect.left,
300 new_rect.bottom - new_rect.top, SWP_NOACTIVATE );
303 static void ime_ui_update_window( INPUTCONTEXT *ctx, HWND hwnd )
305 COMPOSITIONSTRING *string;
307 if (ctx->hCompStr) string = ImmLockIMCC( ctx->hCompStr );
308 else string = NULL;
310 if (!string || string->dwCompStrLen == 0)
311 ShowWindow( hwnd, SW_HIDE );
312 else
314 ShowWindow( hwnd, SW_SHOWNOACTIVATE );
315 RedrawWindow( hwnd, NULL, NULL, RDW_ERASENOW | RDW_INVALIDATE );
318 if (string) ImmUnlockIMCC( ctx->hCompStr );
320 ctx->hWnd = GetFocus();
323 static void ime_ui_composition( HIMC himc, HWND hwnd, LPARAM lparam )
325 INPUTCONTEXT *ctx;
326 if (lparam & GCS_RESULTSTR) return;
327 if (!(ctx = ImmLockIMC( himc ))) return;
328 ime_ui_update_window( ctx, hwnd );
329 ImmUnlockIMC( himc );
332 static void ime_ui_start_composition( HIMC himc, HWND hwnd )
334 INPUTCONTEXT *ctx;
335 if (!(ctx = ImmLockIMC( himc ))) return;
336 ime_ui_update_window( ctx, hwnd );
337 ImmUnlockIMC( himc );
340 static LRESULT WINAPI ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
342 HIMC himc = (HIMC)GetWindowLongPtrW( hwnd, IMMGWL_IMC );
343 INPUTCONTEXT *ctx;
345 TRACE( "hwnd %p, himc %p, msg %s, wparam %#Ix, lparam %#Ix\n",
346 hwnd, himc, debugstr_wm_ime(msg), wparam, lparam );
348 switch (msg)
350 case WM_CREATE:
352 struct ime_private *priv;
354 SetWindowTextA( hwnd, "Wine Ime Active" );
356 if (!(ctx = ImmLockIMC( himc ))) return TRUE;
357 if ((priv = ImmLockIMCC( ctx->hPrivate )))
359 priv->hwndDefault = hwnd;
360 ImmUnlockIMCC( ctx->hPrivate );
362 ImmUnlockIMC( himc );
363 return TRUE;
365 case WM_PAINT:
366 ime_ui_paint( himc, hwnd );
367 return FALSE;
368 case WM_SETFOCUS:
369 if (wparam) SetFocus( (HWND)wparam );
370 else FIXME( "Received focus, should never have focus\n" );
371 break;
372 case WM_IME_COMPOSITION:
373 ime_ui_composition( himc, hwnd, lparam );
374 break;
375 case WM_IME_STARTCOMPOSITION:
376 ime_ui_start_composition( himc, hwnd );
377 break;
378 case WM_IME_ENDCOMPOSITION:
379 ShowWindow( hwnd, SW_HIDE );
380 break;
381 case WM_IME_NOTIFY:
382 FIXME( "hwnd %p, himc %p, msg %s, wparam %s, lparam %#Ix stub!\n", hwnd, himc,
383 debugstr_wm_ime(msg), debugstr_imn(wparam), lparam );
384 return 0;
385 case WM_IME_CONTROL:
386 FIXME( "hwnd %p, himc %p, msg %s, wparam %s, lparam %#Ix stub!\n", hwnd, himc,
387 debugstr_wm_ime(msg), debugstr_imc(wparam), lparam );
388 return 1;
391 return DefWindowProcW( hwnd, msg, wparam, lparam );
394 static WNDCLASSEXW ime_ui_class =
396 .cbSize = sizeof(WNDCLASSEXW),
397 .style = CS_GLOBALCLASS | CS_IME | CS_HREDRAW | CS_VREDRAW,
398 .lpfnWndProc = ime_ui_window_proc,
399 .cbWndExtra = 2 * sizeof(LONG_PTR),
400 .lpszClassName = L"Wine IME",
401 .hbrBackground = (HBRUSH)(COLOR_WINDOW + 1),
404 BOOL WINAPI ImeInquire( IMEINFO *info, WCHAR *ui_class, DWORD flags )
406 TRACE( "info %p, ui_class %p, flags %#lx\n", info, ui_class, flags );
408 ime_ui_class.hInstance = imm32_module;
409 ime_ui_class.hCursor = LoadCursorW( NULL, (LPWSTR)IDC_ARROW );
410 ime_ui_class.hIcon = LoadIconW( NULL, (LPWSTR)IDI_APPLICATION );
411 RegisterClassExW( &ime_ui_class );
413 wcscpy( ui_class, ime_ui_class.lpszClassName );
414 memset( info, 0, sizeof(*info) );
415 info->dwPrivateDataSize = sizeof(IMEPRIVATE);
416 info->fdwProperty = IME_PROP_UNICODE | IME_PROP_AT_CARET;
417 info->fdwConversionCaps = IME_CMODE_NATIVE | IME_CMODE_FULLSHAPE;
418 info->fdwSentenceCaps = IME_SMODE_AUTOMATIC;
419 info->fdwUICaps = UI_CAP_2700;
420 /* Tell App we cannot accept ImeSetCompositionString calls */
421 info->fdwSCSCaps = 0;
422 info->fdwSelectCaps = SELECT_CAP_CONVERSION;
424 return TRUE;
427 BOOL WINAPI ImeDestroy( UINT force )
429 TRACE( "force %u\n", force );
430 UnregisterClassW( ime_ui_class.lpszClassName, imm32_module );
431 return TRUE;
434 BOOL WINAPI ImeSelect( HIMC himc, BOOL select )
436 FIXME( "himc %p, select %d semi-stub!\n", himc, select );
437 return TRUE;
440 BOOL WINAPI ImeSetActiveContext( HIMC himc, BOOL flag )
442 static int once;
443 if (!once++) FIXME( "himc %p, flag %#x stub!\n", himc, flag );
444 return TRUE;
447 BOOL WINAPI ImeProcessKey( HIMC himc, UINT vkey, LPARAM lparam, BYTE *state )
449 struct ime_driver_call_params params = {.himc = himc, .state = state};
450 INPUTCONTEXT *ctx;
451 LRESULT ret;
453 TRACE( "himc %p, vkey %#x, lparam %#Ix, state %p\n", himc, vkey, lparam, state );
455 if (!(ctx = ImmLockIMC( himc ))) return FALSE;
456 ret = NtUserMessageCall( ctx->hWnd, WINE_IME_PROCESS_KEY, vkey, lparam, &params,
457 NtUserImeDriverCall, FALSE );
458 ImmUnlockIMC( himc );
460 return ret;
463 UINT WINAPI ImeToAsciiEx( UINT vkey, UINT vsc, BYTE *state, TRANSMSGLIST *msgs, UINT flags, HIMC himc )
465 COMPOSITIONSTRING *compstr;
466 UINT size, count = 0;
467 INPUTCONTEXT *ctx;
468 NTSTATUS status;
470 TRACE( "vkey %#x, vsc %#x, state %p, msgs %p, flags %#x, himc %p\n",
471 vkey, vsc, state, msgs, flags, himc );
473 if (!(ctx = ImmLockIMC( himc ))) return 0;
474 if (!(compstr = ImmLockIMCC( ctx->hCompStr ))) goto done;
475 size = compstr->dwSize;
479 struct ime_driver_call_params params = {.himc = himc, .state = state};
480 HIMCC himcc;
482 ImmUnlockIMCC( ctx->hCompStr );
483 if (!(himcc = ImmReSizeIMCC( ctx->hCompStr, size ))) goto done;
484 if (!(compstr = ImmLockIMCC( (ctx->hCompStr = himcc) ))) goto done;
486 params.compstr = compstr;
487 status = NtUserMessageCall( ctx->hWnd, WINE_IME_TO_ASCII_EX, vkey, vsc, &params,
488 NtUserImeDriverCall, FALSE );
489 size = compstr->dwSize;
490 } while (status == STATUS_BUFFER_TOO_SMALL);
492 if (status) WARN( "WINE_IME_TO_ASCII_EX returned status %#lx\n", status );
493 else
495 TRANSMSG status_msg = {.message = ime_set_composition_status( himc, !!compstr->dwCompStrOffset )};
496 if (status_msg.message) msgs->TransMsg[count++] = status_msg;
498 if (compstr->dwResultStrLen)
500 const WCHAR *result = (WCHAR *)((BYTE *)compstr + compstr->dwResultStrOffset);
501 TRANSMSG msg = {.message = WM_IME_COMPOSITION, .wParam = result[0], .lParam = GCS_RESULTSTR};
502 if (compstr->dwResultClauseOffset) msg.lParam |= GCS_RESULTCLAUSE;
503 msgs->TransMsg[count++] = msg;
506 if (compstr->dwCompStrLen)
508 const WCHAR *comp = (WCHAR *)((BYTE *)compstr + compstr->dwCompStrOffset);
509 TRANSMSG msg = {.message = WM_IME_COMPOSITION, .wParam = comp[0], .lParam = GCS_COMPSTR | GCS_CURSORPOS | GCS_DELTASTART};
510 if (compstr->dwCompAttrOffset) msg.lParam |= GCS_COMPATTR;
511 if (compstr->dwCompClauseOffset) msg.lParam |= GCS_COMPCLAUSE;
512 else msg.lParam |= CS_INSERTCHAR|CS_NOMOVECARET;
513 msgs->TransMsg[count++] = msg;
517 ImmUnlockIMCC( ctx->hCompStr );
519 done:
520 if (count >= msgs->uMsgCount) FIXME( "More than %u messages queued, messages possibly lost\n", msgs->uMsgCount );
521 else TRACE( "Returning %u messages queued\n", count );
522 ImmUnlockIMC( himc );
523 return count;
526 BOOL WINAPI ImeConfigure( HKL hkl, HWND hwnd, DWORD mode, void *data )
528 FIXME( "hkl %p, hwnd %p, mode %lu, data %p stub!\n", hkl, hwnd, mode, data );
529 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
530 return FALSE;
533 DWORD WINAPI ImeConversionList( HIMC himc, const WCHAR *source, CANDIDATELIST *dest, DWORD dest_len, UINT flag )
535 FIXME( "himc %p, source %s, dest %p, dest_len %lu, flag %#x stub!\n",
536 himc, debugstr_w(source), dest, dest_len, flag );
537 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
538 return 0;
541 BOOL WINAPI ImeSetCompositionString( HIMC himc, DWORD index, const void *comp, DWORD comp_len,
542 const void *read, DWORD read_len )
544 INPUTCONTEXT *ctx;
546 FIXME( "himc %p, index %lu, comp %p, comp_len %lu, read %p, read_len %lu semi-stub!\n",
547 himc, index, comp, comp_len, read, read_len );
548 if (read && read_len) FIXME( "Read string unimplemented\n" );
549 if (index != SCS_SETSTR && index != SCS_CHANGECLAUSE && index != SCS_CHANGEATTR) return FALSE;
551 if (!(ctx = ImmLockIMC( himc ))) return FALSE;
553 if (index != SCS_SETSTR)
554 FIXME( "index %#lx not implemented\n", index );
555 else
557 UINT msg, flags = GCS_COMPSTR | GCS_COMPCLAUSE | GCS_COMPATTR | GCS_DELTASTART | GCS_CURSORPOS;
558 WCHAR wparam = comp && comp_len >= sizeof(WCHAR) ? *(WCHAR *)comp : 0;
559 input_context_set_comp_str( ctx, comp, comp_len / sizeof(WCHAR) );
560 if ((msg = ime_set_composition_status( himc, TRUE ))) ime_send_message( himc, msg, 0, 0 );
561 ime_send_message( himc, WM_IME_COMPOSITION, wparam, flags );
564 ImmUnlockIMC( himc );
566 return TRUE;
569 BOOL WINAPI NotifyIME( HIMC himc, DWORD action, DWORD index, DWORD value )
571 struct ime_private *priv;
572 INPUTCONTEXT *ctx;
573 UINT msg;
575 TRACE( "himc %p, action %#lx, index %#lx, value %#lx stub!\n", himc, action, index, value );
577 if (!(ctx = ImmLockIMC( himc ))) return FALSE;
579 switch (action)
581 case NI_CONTEXTUPDATED:
582 switch (value)
584 case IMC_SETCOMPOSITIONFONT:
585 if ((priv = ImmLockIMCC( ctx->hPrivate )))
587 if (priv->textfont) DeleteObject( priv->textfont );
588 priv->textfont = CreateFontIndirectW( &ctx->lfFont.W );
589 ImmUnlockIMCC( ctx->hPrivate );
591 break;
592 case IMC_SETOPENSTATUS:
593 if (!ctx->fOpen)
595 input_context_set_comp_str( ctx, NULL, 0 );
596 if ((msg = ime_set_composition_status( himc, TRUE ))) ime_send_message( himc, msg, 0, 0 );
598 NtUserNotifyIMEStatus( ctx->hWnd, ctx->fOpen );
599 break;
600 default:
601 FIXME( "himc %p, action %#lx, index %#lx, value %#lx stub!\n", himc, action, index, value );
602 break;
604 break;
606 case NI_COMPOSITIONSTR:
607 switch (index)
609 case CPS_COMPLETE:
611 COMPOSITIONSTRING *compstr;
613 if (!(compstr = ImmLockIMCC( ctx->hCompStr )))
614 WARN( "Failed to lock input context composition string\n" );
615 else
617 WCHAR wchr = *(WCHAR *)((BYTE *)compstr + compstr->dwCompStrOffset);
618 COMPOSITIONSTRING tmp = *compstr;
619 UINT flags = 0;
621 memset( compstr, 0, sizeof(*compstr) );
622 compstr->dwSize = tmp.dwSize;
623 compstr->dwResultStrLen = tmp.dwCompStrLen;
624 compstr->dwResultStrOffset = tmp.dwCompStrOffset;
625 compstr->dwResultClauseLen = tmp.dwCompClauseLen;
626 compstr->dwResultClauseOffset = tmp.dwCompClauseOffset;
627 ImmUnlockIMCC( ctx->hCompStr );
629 if (tmp.dwCompStrLen) flags |= GCS_RESULTSTR;
630 if (tmp.dwCompClauseLen) flags |= GCS_RESULTCLAUSE;
631 if (flags) ime_send_message( himc, WM_IME_COMPOSITION, wchr, flags );
634 ImmSetOpenStatus( himc, FALSE );
635 break;
637 case CPS_CANCEL:
638 input_context_set_comp_str( ctx, NULL, 0 );
639 ImmSetOpenStatus( himc, FALSE );
640 break;
641 default:
642 FIXME( "himc %p, action %#lx, index %#lx, value %#lx stub!\n", himc, action, index, value );
643 break;
645 break;
647 default:
648 FIXME( "himc %p, action %#lx, index %#lx, value %#lx stub!\n", himc, action, index, value );
649 break;
652 ImmUnlockIMC( himc );
653 return TRUE;
656 LRESULT WINAPI ImeEscape( HIMC himc, UINT escape, void *data )
658 FIXME( "himc %p, escape %#x, data %p stub!\n", himc, escape, data );
659 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
660 return 0;
663 DWORD WINAPI ImeGetImeMenuItems( HIMC himc, DWORD flags, DWORD type, IMEMENUITEMINFOW *parent,
664 IMEMENUITEMINFOW *menu, DWORD size )
666 FIXME( "himc %p, flags %#lx, type %lu, parent %p, menu %p, size %#lx stub!\n",
667 himc, flags, type, parent, menu, size );
668 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
669 return 0;
672 BOOL WINAPI ImeRegisterWord( const WCHAR *reading, DWORD style, const WCHAR *string )
674 FIXME( "reading %s, style %lu, string %s stub!\n", debugstr_w(reading), style, debugstr_w(string) );
675 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
676 return FALSE;
679 UINT WINAPI ImeGetRegisterWordStyle( UINT item, STYLEBUFW *style )
681 FIXME( "item %u, style %p stub!\n", item, style );
682 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
683 return 0;
686 BOOL WINAPI ImeUnregisterWord( const WCHAR *reading, DWORD style, const WCHAR *string )
688 FIXME( "reading %s, style %lu, string %s stub!\n", debugstr_w(reading), style, debugstr_w(string) );
689 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
690 return FALSE;
693 UINT WINAPI ImeEnumRegisterWord( REGISTERWORDENUMPROCW proc, const WCHAR *reading, DWORD style,
694 const WCHAR *string, void *data )
696 FIXME( "proc %p, reading %s, style %lu, string %s, data %p stub!\n",
697 proc, debugstr_w(reading), style, debugstr_w(string), data );
698 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
699 return 0;