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
22 #include "imm_private.h"
24 WINE_DEFAULT_DEBUG_CHANNEL(imm
);
32 static const char *debugstr_imn( WPARAM 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
)
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
;
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
) );
90 ImmUnlockIMCC( ctx
->hCompStr
);
94 static void input_context_set_comp_str( INPUTCONTEXT
*ctx
, const WCHAR
*str
, UINT len
)
96 COMPOSITIONSTRING
*compstr
;
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" );
112 memset( compstr
, 0, sizeof(*compstr
) );
113 compstr
->dwSize
= sizeof(*compstr
);
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
;
147 if (!(priv
= ImmLockIMCC( ctx
->hPrivate
))) return NULL
;
148 if (priv
->hfont
) font
= SelectObject( hdc
, priv
->hfont
);
149 ImmUnlockIMCC( ctx
->hPrivate
);
153 static void ime_send_message( HIMC himc
, UINT message
, WPARAM wparam
, LPARAM lparam
)
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" );
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
;
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
);
194 static void ime_ui_paint( HIMC himc
, HWND hwnd
)
200 MONITORINFO mon_info
;
206 if (!(ctx
= ImmLockIMC( himc
))) return;
208 hdc
= BeginPaint( hwnd
, &ps
);
210 GetClientRect( hwnd
, &rect
);
211 FillRect( hdc
, &rect
, (HBRUSH
)(COLOR_WINDOW
+ 1) );
214 if ((str
= input_context_get_comp_str( ctx
, FALSE
, &len
)))
216 HFONT font
= input_context_select_ui_font( ctx
, hdc
);
220 GetTextExtentPoint32W( hdc
, str
, len
, &size
);
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
);
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
;
280 rect
.bottom
-= shift
;
284 rect
.right
-= rect
.left
;
287 if (rect
.right
> mon_info
.rcWork
.right
)
289 int shift
= rect
.right
- mon_info
.rcWork
.right
;
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
);
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
);
318 if (!string
|| string
->dwCompStrLen
== 0)
319 ShowWindow( hwnd
, SW_HIDE
);
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
)
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
)
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
)
355 TRANSMSG TransMsg
[10];
358 } buffer
= {.uMsgCount
= ARRAY_SIZE(buffer
.TransMsg
)};
364 TRACE( "himc %p\n", himc
);
366 if (!(ctx
= ImmLockIMC( himc
))) return 0;
368 count
= ImeToAsciiEx( VK_PROCESSKEY
, lparam
, NULL
, &buffer
.list
, 0, himc
);
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" );
379 memcpy( msgs
+ ctx
->dwNumMsgBuf
, buffer
.TransMsg
, count
* sizeof(*msgs
) );
380 ImmUnlockIMCC( ctx
->hMsgBuf
);
381 ctx
->dwNumMsgBuf
+= count
;
384 ImmUnlockIMC( himc
);
385 ImmGenerateMessage( himc
);
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
);
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
);
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
);
417 ime_ui_paint( himc
, hwnd
);
420 if (wparam
) SetFocus( (HWND
)wparam
);
421 else FIXME( "Received focus, should never have focus\n" );
423 case WM_IME_COMPOSITION
:
424 ime_ui_composition( himc
, hwnd
, lparam
);
426 case WM_IME_STARTCOMPOSITION
:
427 ime_ui_start_composition( himc
, hwnd
);
429 case WM_IME_ENDCOMPOSITION
:
430 ShowWindow( hwnd
, SW_HIDE
);
433 return ime_ui_notify( himc
, hwnd
, wparam
, lparam
);
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
);
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
;
476 BOOL WINAPI
ImeDestroy( UINT force
)
478 TRACE( "force %u\n", force
);
479 UnregisterClassW( ime_ui_class
.lpszClassName
, imm32_module
);
483 BOOL WINAPI
ImeSelect( HIMC himc
, BOOL select
)
485 struct ime_private
*priv
;
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
);
505 BOOL WINAPI
ImeSetActiveContext( HIMC himc
, BOOL flag
)
507 TRACE( "himc %p, flag %#x stub!\n", himc
, flag
);
511 BOOL WINAPI
ImeProcessKey( HIMC himc
, UINT vkey
, LPARAM lparam
, BYTE
*state
)
513 struct ime_driver_call_params params
= {.himc
= himc
, .state
= state
};
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
, ¶ms
,
521 NtUserImeDriverCall
, FALSE
);
522 ImmUnlockIMC( himc
);
527 UINT WINAPI
ImeToAsciiEx( UINT vkey
, UINT vsc
, BYTE
*state
, TRANSMSGLIST
*msgs
, UINT flags
, HIMC himc
)
529 COMPOSITIONSTRING
*compstr
;
530 UINT size
, count
= 0;
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
};
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
, ¶ms
,
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
);
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
);
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
);
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
);
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
);
605 BOOL WINAPI
ImeSetCompositionString( HIMC himc
, DWORD index
, const void *comp
, DWORD comp_len
,
606 const void *read
, DWORD read_len
)
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
);
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
);
633 BOOL WINAPI
NotifyIME( HIMC himc
, DWORD action
, DWORD index
, DWORD value
)
635 struct ime_private
*priv
;
639 TRACE( "himc %p, action %#lx, index %#lx, value %#lx stub!\n", himc
, action
, index
, value
);
641 if (!(ctx
= ImmLockIMC( himc
))) return FALSE
;
645 case NI_CONTEXTUPDATED
:
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
);
656 case IMC_SETOPENSTATUS
:
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
);
667 case NI_COMPOSITIONSTR
:
672 COMPOSITIONSTRING
*compstr
;
674 if (!(compstr
= ImmLockIMCC( ctx
->hCompStr
)))
675 WARN( "Failed to lock input context composition string\n" );
678 WCHAR wchr
= *(WCHAR
*)((BYTE
*)compstr
+ compstr
->dwCompStrOffset
);
679 COMPOSITIONSTRING tmp
= *compstr
;
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
);
699 input_context_set_comp_str( ctx
, NULL
, 0 );
700 ImmSetOpenStatus( himc
, FALSE
);
703 FIXME( "himc %p, action %#lx, index %#lx, value %#lx stub!\n", himc
, action
, index
, value
);
709 FIXME( "himc %p, action %#lx, index %#lx, value %#lx stub!\n", himc
, action
, index
, value
);
713 ImmUnlockIMC( himc
);
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
);
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
);
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
);
740 UINT WINAPI
ImeGetRegisterWordStyle( UINT item
, STYLEBUFW
*style
)
742 FIXME( "item %u, style %p stub!\n", item
, style
);
743 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
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
);
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
);