explorerframe: Remove DECLSPEC_HIDDEN usage.
[wine.git] / dlls / imm32 / ime.c
blob0470f3b6d6c59e1b39887d43f609df8c4e989a9b
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 struct ime_private
28 BOOL in_composition;
29 HFONT hfont;
32 static const char *debugstr_imn( WPARAM wparam )
34 switch (wparam)
36 case IMN_OPENSTATUSWINDOW: return "IMN_OPENSTATUSWINDOW";
37 case IMN_CLOSESTATUSWINDOW: return "IMN_CLOSESTATUSWINDOW";
38 case IMN_OPENCANDIDATE: return "IMN_OPENCANDIDATE";
39 case IMN_CHANGECANDIDATE: return "IMN_CHANGECANDIDATE";
40 case IMN_CLOSECANDIDATE: return "IMN_CLOSECANDIDATE";
41 case IMN_SETCONVERSIONMODE: return "IMN_SETCONVERSIONMODE";
42 case IMN_SETSENTENCEMODE: return "IMN_SETSENTENCEMODE";
43 case IMN_SETOPENSTATUS: return "IMN_SETOPENSTATUS";
44 case IMN_SETCANDIDATEPOS: return "IMN_SETCANDIDATEPOS";
45 case IMN_SETCOMPOSITIONFONT: return "IMN_SETCOMPOSITIONFONT";
46 case IMN_SETCOMPOSITIONWINDOW: return "IMN_SETCOMPOSITIONWINDOW";
47 case IMN_GUIDELINE: return "IMN_GUIDELINE";
48 case IMN_SETSTATUSWINDOWPOS: return "IMN_SETSTATUSWINDOWPOS";
49 case IMN_WINE_SET_OPEN_STATUS: return "IMN_WINE_SET_OPEN_STATUS";
50 case IMN_WINE_SET_COMP_STRING: return "IMN_WINE_SET_COMP_STRING";
51 default: return wine_dbg_sprintf( "%#Ix", wparam );
55 static const char *debugstr_imc( WPARAM wparam )
57 switch (wparam)
59 case IMC_GETCANDIDATEPOS: return "IMC_GETCANDIDATEPOS";
60 case IMC_SETCANDIDATEPOS: return "IMC_SETCANDIDATEPOS";
61 case IMC_GETCOMPOSITIONFONT: return "IMC_GETCOMPOSITIONFONT";
62 case IMC_SETCOMPOSITIONFONT: return "IMC_SETCOMPOSITIONFONT";
63 case IMC_GETCOMPOSITIONWINDOW: return "IMC_GETCOMPOSITIONWINDOW";
64 case IMC_SETCOMPOSITIONWINDOW: return "IMC_SETCOMPOSITIONWINDOW";
65 case IMC_GETSTATUSWINDOWPOS: return "IMC_GETSTATUSWINDOWPOS";
66 case IMC_SETSTATUSWINDOWPOS: return "IMC_SETSTATUSWINDOWPOS";
67 case IMC_CLOSESTATUSWINDOW: return "IMC_CLOSESTATUSWINDOW";
68 case IMC_OPENSTATUSWINDOW: return "IMC_OPENSTATUSWINDOW";
69 default: return wine_dbg_sprintf( "%#Ix", wparam );
73 static WCHAR *input_context_get_comp_str( INPUTCONTEXT *ctx, BOOL result, UINT *length )
75 COMPOSITIONSTRING *string;
76 WCHAR *text = NULL;
77 UINT len, off;
79 if (!(string = ImmLockIMCC( ctx->hCompStr ))) return NULL;
80 len = result ? string->dwResultStrLen : string->dwCompStrLen;
81 off = result ? string->dwResultStrOffset : string->dwCompStrOffset;
83 if (len && off && (text = malloc( (len + 1) * sizeof(WCHAR) )))
85 memcpy( text, (BYTE *)string + off, len * sizeof(WCHAR) );
86 text[len] = 0;
87 *length = len;
90 ImmUnlockIMCC( ctx->hCompStr );
91 return text;
94 static void input_context_set_comp_str( INPUTCONTEXT *ctx, const WCHAR *str, UINT len )
96 COMPOSITIONSTRING *compstr;
97 HIMCC himcc;
98 UINT size;
99 BYTE *dst;
101 size = sizeof(*compstr);
102 size += len * sizeof(WCHAR); /* GCS_COMPSTR */
103 size += len; /* GCS_COMPSTRATTR */
104 size += 2 * sizeof(DWORD); /* GCS_COMPSTRCLAUSE */
106 if (!(himcc = ImmReSizeIMCC( ctx->hCompStr, size )))
107 WARN( "Failed to resize input context composition string\n" );
108 else if (!(compstr = ImmLockIMCC( (ctx->hCompStr = himcc) )))
109 WARN( "Failed to lock input context composition string\n" );
110 else
112 memset( compstr, 0, sizeof(*compstr) );
113 compstr->dwSize = sizeof(*compstr);
115 if (len)
117 compstr->dwCursorPos = len;
119 compstr->dwCompStrLen = len;
120 compstr->dwCompStrOffset = compstr->dwSize;
121 dst = (BYTE *)compstr + compstr->dwCompStrOffset;
122 memcpy( dst, str, compstr->dwCompStrLen * sizeof(WCHAR) );
123 compstr->dwSize += compstr->dwCompStrLen * sizeof(WCHAR);
125 compstr->dwCompClauseLen = 2 * sizeof(DWORD);
126 compstr->dwCompClauseOffset = compstr->dwSize;
127 dst = (BYTE *)compstr + compstr->dwCompClauseOffset;
128 *((DWORD *)dst + 0) = 0;
129 *((DWORD *)dst + 1) = compstr->dwCompStrLen;
130 compstr->dwSize += compstr->dwCompClauseLen;
132 compstr->dwCompAttrLen = compstr->dwCompStrLen;
133 compstr->dwCompAttrOffset = compstr->dwSize;
134 dst = (BYTE *)compstr + compstr->dwCompAttrOffset;
135 memset( dst, ATTR_INPUT, compstr->dwCompAttrLen );
136 compstr->dwSize += compstr->dwCompAttrLen;
139 ImmUnlockIMCC( ctx->hCompStr );
143 static HFONT input_context_select_ui_font( INPUTCONTEXT *ctx, HDC hdc )
145 struct ime_private *priv;
146 HFONT font = NULL;
147 if (!(priv = ImmLockIMCC( ctx->hPrivate ))) return NULL;
148 if (priv->hfont) font = SelectObject( hdc, priv->hfont );
149 ImmUnlockIMCC( ctx->hPrivate );
150 return font;
153 static void ime_send_message( HIMC himc, UINT message, WPARAM wparam, LPARAM lparam )
155 INPUTCONTEXT *ctx;
156 TRANSMSG *msgs;
157 HIMCC himcc;
159 if (!(ctx = ImmLockIMC( himc ))) return;
160 if (!(himcc = ImmReSizeIMCC( ctx->hMsgBuf, (ctx->dwNumMsgBuf + 1) * sizeof(*msgs) )))
161 WARN( "Failed to resize input context message buffer\n" );
162 else if (!(msgs = ImmLockIMCC( (ctx->hMsgBuf = himcc) )))
163 WARN( "Failed to lock input context message buffer\n" );
164 else
166 TRANSMSG msg = {.message = message, .wParam = wparam, .lParam = lparam};
167 msgs[ctx->dwNumMsgBuf++] = msg;
168 ImmUnlockIMCC( ctx->hMsgBuf );
171 ImmUnlockIMC( himc );
172 ImmGenerateMessage( himc );
175 static UINT ime_set_composition_status( HIMC himc, BOOL composition )
177 struct ime_private *priv;
178 INPUTCONTEXT *ctx;
179 UINT msg = 0;
181 if (!(ctx = ImmLockIMC( himc ))) return 0;
182 if ((priv = ImmLockIMCC( ctx->hPrivate )))
184 if (!priv->in_composition && composition) msg = WM_IME_STARTCOMPOSITION;
185 else if (priv->in_composition && !composition) msg = WM_IME_ENDCOMPOSITION;
186 priv->in_composition = composition;
187 ImmUnlockIMCC( ctx->hPrivate );
189 ImmUnlockIMC( himc );
191 return msg;
194 static void ime_ui_paint( HIMC himc, HWND hwnd )
196 PAINTSTRUCT ps;
197 RECT rect, new_rect;
198 HDC hdc;
199 HMONITOR monitor;
200 MONITORINFO mon_info;
201 INPUTCONTEXT *ctx;
202 POINT offset;
203 WCHAR *str;
204 UINT len;
206 if (!(ctx = ImmLockIMC( himc ))) return;
208 hdc = BeginPaint( hwnd, &ps );
210 GetClientRect( hwnd, &rect );
211 FillRect( hdc, &rect, (HBRUSH)(COLOR_WINDOW + 1) );
212 new_rect = rect;
214 if ((str = input_context_get_comp_str( ctx, FALSE, &len )))
216 HFONT font = input_context_select_ui_font( ctx, hdc );
217 SIZE size;
218 POINT pt;
220 GetTextExtentPoint32W( hdc, str, len, &size );
221 pt.x = size.cx;
222 pt.y = size.cy;
223 LPtoDP( hdc, &pt, 1 );
226 * How this works based on tests on windows:
227 * CFS_POINT: then we start our window at the point and grow it as large
228 * as it needs to be for the string.
229 * CFS_RECT: we still use the ptCurrentPos as a starting point and our
230 * window is only as large as we need for the string, but we do not
231 * grow such that our window exceeds the given rect. Wrapping if
232 * needed and possible. If our ptCurrentPos is outside of our rect
233 * then no window is displayed.
234 * CFS_FORCE_POSITION: appears to behave just like CFS_POINT
235 * maybe because the default MSIME does not do any IME adjusting.
237 if (ctx->cfCompForm.dwStyle != CFS_DEFAULT)
239 POINT cpt = ctx->cfCompForm.ptCurrentPos;
240 ClientToScreen( ctx->hWnd, &cpt );
241 rect.left = cpt.x;
242 rect.top = cpt.y;
243 rect.right = rect.left + pt.x;
244 rect.bottom = rect.top + pt.y;
245 offset.x = offset.y = 0;
246 monitor = MonitorFromPoint( cpt, MONITOR_DEFAULTTOPRIMARY );
248 else /* CFS_DEFAULT */
250 /* Windows places the default IME window in the bottom left */
251 HWND target = ctx->hWnd;
252 if (!target) target = GetFocus();
254 GetWindowRect( target, &rect );
255 rect.top = rect.bottom;
256 rect.right = rect.left + pt.x + 20;
257 rect.bottom = rect.top + pt.y + 20;
258 offset.x = offset.y = 10;
259 monitor = MonitorFromWindow( target, MONITOR_DEFAULTTOPRIMARY );
262 if (ctx->cfCompForm.dwStyle == CFS_RECT)
264 RECT client = ctx->cfCompForm.rcArea;
265 MapWindowPoints( ctx->hWnd, 0, (POINT *)&client, 2 );
266 IntersectRect( &rect, &rect, &client );
267 DrawTextW( hdc, str, len, &rect, DT_WORDBREAK | DT_CALCRECT );
270 if (ctx->cfCompForm.dwStyle == CFS_DEFAULT)
272 /* make sure we are on the desktop */
273 mon_info.cbSize = sizeof(mon_info);
274 GetMonitorInfoW( monitor, &mon_info );
276 if (rect.bottom > mon_info.rcWork.bottom)
278 int shift = rect.bottom - mon_info.rcWork.bottom;
279 rect.top -= shift;
280 rect.bottom -= shift;
282 if (rect.left < 0)
284 rect.right -= rect.left;
285 rect.left = 0;
287 if (rect.right > mon_info.rcWork.right)
289 int shift = rect.right - mon_info.rcWork.right;
290 rect.left -= shift;
291 rect.right -= shift;
295 new_rect = rect;
296 OffsetRect( &rect, offset.x - rect.left, offset.y - rect.top );
297 DrawTextW( hdc, str, len, &rect, DT_WORDBREAK );
299 if (font) SelectObject( hdc, font );
300 free( str );
303 EndPaint( hwnd, &ps );
304 ImmUnlockIMC( himc );
306 if (!EqualRect( &rect, &new_rect ))
307 SetWindowPos( hwnd, HWND_TOPMOST, new_rect.left, new_rect.top, new_rect.right - new_rect.left,
308 new_rect.bottom - new_rect.top, SWP_NOACTIVATE );
311 static void ime_ui_update_window( INPUTCONTEXT *ctx, HWND hwnd )
313 COMPOSITIONSTRING *string;
315 if (ctx->hCompStr) string = ImmLockIMCC( ctx->hCompStr );
316 else string = NULL;
318 if (!string || string->dwCompStrLen == 0)
319 ShowWindow( hwnd, SW_HIDE );
320 else
322 ShowWindow( hwnd, SW_SHOWNOACTIVATE );
323 RedrawWindow( hwnd, NULL, NULL, RDW_ERASENOW | RDW_INVALIDATE );
326 if (string) ImmUnlockIMCC( ctx->hCompStr );
328 ctx->hWnd = GetFocus();
331 static void ime_ui_composition( HIMC himc, HWND hwnd, LPARAM lparam )
333 INPUTCONTEXT *ctx;
334 if (lparam & GCS_RESULTSTR) return;
335 if (!(ctx = ImmLockIMC( himc ))) return;
336 ime_ui_update_window( ctx, hwnd );
337 ImmUnlockIMC( himc );
340 static void ime_ui_start_composition( HIMC himc, HWND hwnd )
342 INPUTCONTEXT *ctx;
343 if (!(ctx = ImmLockIMC( himc ))) return;
344 ime_ui_update_window( ctx, hwnd );
345 ImmUnlockIMC( himc );
348 static UINT ime_set_comp_string( HIMC himc, LPARAM lparam )
350 union
352 struct
354 UINT uMsgCount;
355 TRANSMSG TransMsg[10];
357 TRANSMSGLIST list;
358 } buffer = {.uMsgCount = ARRAY_SIZE(buffer.TransMsg)};
359 INPUTCONTEXT *ctx;
360 TRANSMSG *msgs;
361 HIMCC himcc;
362 UINT count;
364 TRACE( "himc %p\n", himc );
366 if (!(ctx = ImmLockIMC( himc ))) return 0;
368 count = ImeToAsciiEx( VK_PROCESSKEY, lparam, NULL, &buffer.list, 0, himc );
369 if (!count)
370 TRACE( "ImeToAsciiEx returned no messages\n" );
371 else if (count >= buffer.uMsgCount)
372 WARN( "ImeToAsciiEx returned %#x messages\n", count );
373 else if (!(himcc = ImmReSizeIMCC( ctx->hMsgBuf, (ctx->dwNumMsgBuf + count) * sizeof(*msgs) )))
374 WARN( "Failed to resize input context message buffer\n" );
375 else if (!(msgs = ImmLockIMCC( (ctx->hMsgBuf = himcc) )))
376 WARN( "Failed to lock input context message buffer\n" );
377 else
379 memcpy( msgs + ctx->dwNumMsgBuf, buffer.TransMsg, count * sizeof(*msgs) );
380 ImmUnlockIMCC( ctx->hMsgBuf );
381 ctx->dwNumMsgBuf += count;
384 ImmUnlockIMC( himc );
385 ImmGenerateMessage( himc );
387 return count;
390 static LRESULT ime_ui_notify( HIMC himc, HWND hwnd, WPARAM wparam, LPARAM lparam )
392 TRACE( "himc %p, hwnd %p, wparam %s, lparam %#Ix\n", hwnd, himc, debugstr_imn(wparam), lparam );
394 switch (wparam)
396 case IMN_WINE_SET_OPEN_STATUS:
397 return ImmSetOpenStatus( himc, lparam );
398 case IMN_WINE_SET_COMP_STRING:
399 return ime_set_comp_string( himc, lparam );
400 default:
401 return 0;
405 static LRESULT WINAPI ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
407 HIMC himc = (HIMC)GetWindowLongPtrW( hwnd, IMMGWL_IMC );
409 TRACE( "hwnd %p, himc %p, msg %s, wparam %#Ix, lparam %#Ix\n",
410 hwnd, himc, debugstr_wm_ime(msg), wparam, lparam );
412 switch (msg)
414 case WM_CREATE:
415 return TRUE;
416 case WM_PAINT:
417 ime_ui_paint( himc, hwnd );
418 return FALSE;
419 case WM_SETFOCUS:
420 if (wparam) SetFocus( (HWND)wparam );
421 else FIXME( "Received focus, should never have focus\n" );
422 break;
423 case WM_IME_COMPOSITION:
424 ime_ui_composition( himc, hwnd, lparam );
425 break;
426 case WM_IME_STARTCOMPOSITION:
427 ime_ui_start_composition( himc, hwnd );
428 break;
429 case WM_IME_ENDCOMPOSITION:
430 ShowWindow( hwnd, SW_HIDE );
431 break;
432 case WM_IME_NOTIFY:
433 return ime_ui_notify( himc, hwnd, wparam, lparam );
434 case WM_IME_CONTROL:
435 FIXME( "hwnd %p, himc %p, msg %s, wparam %s, lparam %#Ix stub!\n", hwnd, himc,
436 debugstr_wm_ime(msg), debugstr_imc(wparam), lparam );
437 return 1;
440 return DefWindowProcW( hwnd, msg, wparam, lparam );
443 static WNDCLASSEXW ime_ui_class =
445 .cbSize = sizeof(WNDCLASSEXW),
446 .style = CS_GLOBALCLASS | CS_IME | CS_HREDRAW | CS_VREDRAW,
447 .lpfnWndProc = ime_ui_window_proc,
448 .cbWndExtra = 2 * sizeof(LONG_PTR),
449 .lpszClassName = L"Wine IME",
450 .hbrBackground = (HBRUSH)(COLOR_WINDOW + 1),
453 BOOL WINAPI ImeInquire( IMEINFO *info, WCHAR *ui_class, DWORD flags )
455 TRACE( "info %p, ui_class %p, flags %#lx\n", info, ui_class, flags );
457 ime_ui_class.hInstance = imm32_module;
458 ime_ui_class.hCursor = LoadCursorW( NULL, (LPWSTR)IDC_ARROW );
459 ime_ui_class.hIcon = LoadIconW( NULL, (LPWSTR)IDI_APPLICATION );
460 RegisterClassExW( &ime_ui_class );
462 wcscpy( ui_class, ime_ui_class.lpszClassName );
463 memset( info, 0, sizeof(*info) );
464 info->dwPrivateDataSize = sizeof(struct ime_private);
465 info->fdwProperty = IME_PROP_UNICODE | IME_PROP_AT_CARET;
466 info->fdwConversionCaps = IME_CMODE_NATIVE | IME_CMODE_FULLSHAPE;
467 info->fdwSentenceCaps = IME_SMODE_AUTOMATIC;
468 info->fdwUICaps = UI_CAP_2700;
469 /* Tell App we cannot accept ImeSetCompositionString calls */
470 info->fdwSCSCaps = 0;
471 info->fdwSelectCaps = SELECT_CAP_CONVERSION;
473 return TRUE;
476 BOOL WINAPI ImeDestroy( UINT force )
478 TRACE( "force %u\n", force );
479 UnregisterClassW( ime_ui_class.lpszClassName, imm32_module );
480 return TRUE;
483 BOOL WINAPI ImeSelect( HIMC himc, BOOL select )
485 struct ime_private *priv;
486 INPUTCONTEXT *ctx;
488 TRACE( "himc %p, select %u\n", himc, select );
490 if (!himc || !select) return TRUE;
491 if (!(ctx = ImmLockIMC( himc ))) return FALSE;
493 ImmSetOpenStatus( himc, FALSE );
495 if ((priv = ImmLockIMCC( ctx->hPrivate )))
497 memset( priv, 0, sizeof(*priv) );
498 ImmUnlockIMCC( ctx->hPrivate );
501 ImmUnlockIMC( himc );
502 return TRUE;
505 BOOL WINAPI ImeSetActiveContext( HIMC himc, BOOL flag )
507 TRACE( "himc %p, flag %#x stub!\n", himc, flag );
508 return TRUE;
511 BOOL WINAPI ImeProcessKey( HIMC himc, UINT vkey, LPARAM lparam, BYTE *state )
513 struct ime_driver_call_params params = {.himc = himc, .state = state};
514 INPUTCONTEXT *ctx;
515 LRESULT ret;
517 TRACE( "himc %p, vkey %#x, lparam %#Ix, state %p\n", himc, vkey, lparam, state );
519 if (!(ctx = ImmLockIMC( himc ))) return FALSE;
520 ret = NtUserMessageCall( ctx->hWnd, WINE_IME_PROCESS_KEY, vkey, lparam, &params,
521 NtUserImeDriverCall, FALSE );
522 ImmUnlockIMC( himc );
524 return ret;
527 UINT WINAPI ImeToAsciiEx( UINT vkey, UINT vsc, BYTE *state, TRANSMSGLIST *msgs, UINT flags, HIMC himc )
529 COMPOSITIONSTRING *compstr;
530 UINT size, count = 0;
531 INPUTCONTEXT *ctx;
532 NTSTATUS status;
534 TRACE( "vkey %#x, vsc %#x, state %p, msgs %p, flags %#x, himc %p\n",
535 vkey, vsc, state, msgs, flags, himc );
537 if (!(ctx = ImmLockIMC( himc ))) return 0;
538 if (!(compstr = ImmLockIMCC( ctx->hCompStr ))) goto done;
539 size = max( compstr->dwSize, sizeof(COMPOSITIONSTRING) );
543 struct ime_driver_call_params params = {.himc = himc, .state = state};
544 HIMCC himcc;
546 ImmUnlockIMCC( ctx->hCompStr );
547 if (!(himcc = ImmReSizeIMCC( ctx->hCompStr, size ))) goto done;
548 if (!(compstr = ImmLockIMCC( (ctx->hCompStr = himcc) ))) goto done;
550 params.compstr = compstr;
551 status = NtUserMessageCall( ctx->hWnd, WINE_IME_TO_ASCII_EX, vkey, vsc, &params,
552 NtUserImeDriverCall, FALSE );
553 size = compstr->dwSize;
554 } while (status == STATUS_BUFFER_TOO_SMALL);
556 if (status) WARN( "WINE_IME_TO_ASCII_EX returned status %#lx\n", status );
557 else
559 TRANSMSG status_msg = {.message = ime_set_composition_status( himc, !!compstr->dwCompStrOffset )};
560 if (status_msg.message) msgs->TransMsg[count++] = status_msg;
562 if (compstr->dwResultStrOffset)
564 const WCHAR *result = (WCHAR *)((BYTE *)compstr + compstr->dwResultStrOffset);
565 TRANSMSG msg = {.message = WM_IME_COMPOSITION, .wParam = result[0], .lParam = GCS_RESULTSTR};
566 if (compstr->dwResultClauseOffset) msg.lParam |= GCS_RESULTCLAUSE;
567 msgs->TransMsg[count++] = msg;
570 if (compstr->dwCompStrOffset)
572 const WCHAR *comp = (WCHAR *)((BYTE *)compstr + compstr->dwCompStrOffset);
573 TRANSMSG msg = {.message = WM_IME_COMPOSITION, .wParam = comp[0], .lParam = GCS_COMPSTR | GCS_CURSORPOS | GCS_DELTASTART};
574 if (compstr->dwCompAttrOffset) msg.lParam |= GCS_COMPATTR;
575 if (compstr->dwCompClauseOffset) msg.lParam |= GCS_COMPCLAUSE;
576 else msg.lParam |= CS_INSERTCHAR|CS_NOMOVECARET;
577 msgs->TransMsg[count++] = msg;
581 ImmUnlockIMCC( ctx->hCompStr );
583 done:
584 if (count >= msgs->uMsgCount) FIXME( "More than %u messages queued, messages possibly lost\n", msgs->uMsgCount );
585 else TRACE( "Returning %u messages queued\n", count );
586 ImmUnlockIMC( himc );
587 return count;
590 BOOL WINAPI ImeConfigure( HKL hkl, HWND hwnd, DWORD mode, void *data )
592 FIXME( "hkl %p, hwnd %p, mode %lu, data %p stub!\n", hkl, hwnd, mode, data );
593 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
594 return FALSE;
597 DWORD WINAPI ImeConversionList( HIMC himc, const WCHAR *source, CANDIDATELIST *dest, DWORD dest_len, UINT flag )
599 FIXME( "himc %p, source %s, dest %p, dest_len %lu, flag %#x stub!\n",
600 himc, debugstr_w(source), dest, dest_len, flag );
601 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
602 return 0;
605 BOOL WINAPI ImeSetCompositionString( HIMC himc, DWORD index, const void *comp, DWORD comp_len,
606 const void *read, DWORD read_len )
608 INPUTCONTEXT *ctx;
610 FIXME( "himc %p, index %lu, comp %p, comp_len %lu, read %p, read_len %lu semi-stub!\n",
611 himc, index, comp, comp_len, read, read_len );
612 if (read && read_len) FIXME( "Read string unimplemented\n" );
613 if (index != SCS_SETSTR && index != SCS_CHANGECLAUSE && index != SCS_CHANGEATTR) return FALSE;
615 if (!(ctx = ImmLockIMC( himc ))) return FALSE;
617 if (index != SCS_SETSTR)
618 FIXME( "index %#lx not implemented\n", index );
619 else
621 UINT msg, flags = GCS_COMPSTR | GCS_COMPCLAUSE | GCS_COMPATTR | GCS_DELTASTART | GCS_CURSORPOS;
622 WCHAR wparam = comp && comp_len >= sizeof(WCHAR) ? *(WCHAR *)comp : 0;
623 input_context_set_comp_str( ctx, comp, comp_len / sizeof(WCHAR) );
624 if ((msg = ime_set_composition_status( himc, TRUE ))) ime_send_message( himc, msg, 0, 0 );
625 ime_send_message( himc, WM_IME_COMPOSITION, wparam, flags );
628 ImmUnlockIMC( himc );
630 return TRUE;
633 BOOL WINAPI NotifyIME( HIMC himc, DWORD action, DWORD index, DWORD value )
635 struct ime_private *priv;
636 INPUTCONTEXT *ctx;
637 UINT msg;
639 TRACE( "himc %p, action %#lx, index %#lx, value %#lx stub!\n", himc, action, index, value );
641 if (!(ctx = ImmLockIMC( himc ))) return FALSE;
643 switch (action)
645 case NI_CONTEXTUPDATED:
646 switch (value)
648 case IMC_SETCOMPOSITIONFONT:
649 if ((priv = ImmLockIMCC( ctx->hPrivate )))
651 if (priv->hfont) DeleteObject( priv->hfont );
652 priv->hfont = CreateFontIndirectW( &ctx->lfFont.W );
653 ImmUnlockIMCC( ctx->hPrivate );
655 break;
656 case IMC_SETOPENSTATUS:
657 if (!ctx->fOpen)
659 input_context_set_comp_str( ctx, NULL, 0 );
660 if ((msg = ime_set_composition_status( himc, FALSE ))) ime_send_message( himc, msg, 0, 0 );
662 NtUserNotifyIMEStatus( ctx->hWnd, ctx->fOpen );
663 break;
665 break;
667 case NI_COMPOSITIONSTR:
668 switch (index)
670 case CPS_COMPLETE:
672 COMPOSITIONSTRING *compstr;
674 if (!(compstr = ImmLockIMCC( ctx->hCompStr )))
675 WARN( "Failed to lock input context composition string\n" );
676 else
678 WCHAR wchr = *(WCHAR *)((BYTE *)compstr + compstr->dwCompStrOffset);
679 COMPOSITIONSTRING tmp = *compstr;
680 UINT flags = 0;
682 memset( compstr, 0, sizeof(*compstr) );
683 compstr->dwSize = tmp.dwSize;
684 compstr->dwResultStrLen = tmp.dwCompStrLen;
685 compstr->dwResultStrOffset = tmp.dwCompStrOffset;
686 compstr->dwResultClauseLen = tmp.dwCompClauseLen;
687 compstr->dwResultClauseOffset = tmp.dwCompClauseOffset;
688 ImmUnlockIMCC( ctx->hCompStr );
690 if (tmp.dwCompStrLen) flags |= GCS_RESULTSTR;
691 if (tmp.dwCompClauseLen) flags |= GCS_RESULTCLAUSE;
692 if (flags) ime_send_message( himc, WM_IME_COMPOSITION, wchr, flags );
695 ImmSetOpenStatus( himc, FALSE );
696 break;
698 case CPS_CANCEL:
699 input_context_set_comp_str( ctx, NULL, 0 );
700 ImmSetOpenStatus( himc, FALSE );
701 break;
702 default:
703 FIXME( "himc %p, action %#lx, index %#lx, value %#lx stub!\n", himc, action, index, value );
704 break;
706 break;
708 default:
709 FIXME( "himc %p, action %#lx, index %#lx, value %#lx stub!\n", himc, action, index, value );
710 break;
713 ImmUnlockIMC( himc );
714 return TRUE;
717 LRESULT WINAPI ImeEscape( HIMC himc, UINT escape, void *data )
719 FIXME( "himc %p, escape %#x, data %p stub!\n", himc, escape, data );
720 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
721 return 0;
724 DWORD WINAPI ImeGetImeMenuItems( HIMC himc, DWORD flags, DWORD type, IMEMENUITEMINFOW *parent,
725 IMEMENUITEMINFOW *menu, DWORD size )
727 FIXME( "himc %p, flags %#lx, type %lu, parent %p, menu %p, size %#lx stub!\n",
728 himc, flags, type, parent, menu, size );
729 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
730 return 0;
733 BOOL WINAPI ImeRegisterWord( const WCHAR *reading, DWORD style, const WCHAR *string )
735 FIXME( "reading %s, style %lu, string %s stub!\n", debugstr_w(reading), style, debugstr_w(string) );
736 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
737 return FALSE;
740 UINT WINAPI ImeGetRegisterWordStyle( UINT item, STYLEBUFW *style )
742 FIXME( "item %u, style %p stub!\n", item, style );
743 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
744 return 0;
747 BOOL WINAPI ImeUnregisterWord( const WCHAR *reading, DWORD style, const WCHAR *string )
749 FIXME( "reading %s, style %lu, string %s stub!\n", debugstr_w(reading), style, debugstr_w(string) );
750 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
751 return FALSE;
754 UINT WINAPI ImeEnumRegisterWord( REGISTERWORDENUMPROCW proc, const WCHAR *reading, DWORD style,
755 const WCHAR *string, void *data )
757 FIXME( "proc %p, reading %s, style %lu, string %s, data %p stub!\n",
758 proc, debugstr_w(reading), style, debugstr_w(string), data );
759 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
760 return 0;