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 TRACE( "ctx %p, str %s\n", ctx
, debugstr_wn( str
, len
) );
103 size
= sizeof(*compstr
);
104 size
+= len
* sizeof(WCHAR
); /* GCS_COMPSTR */
105 size
+= len
; /* GCS_COMPSTRATTR */
106 size
+= 2 * sizeof(DWORD
); /* GCS_COMPSTRCLAUSE */
108 if (!(himcc
= ImmReSizeIMCC( ctx
->hCompStr
, size
)))
109 WARN( "Failed to resize input context composition string\n" );
110 else if (!(compstr
= ImmLockIMCC( (ctx
->hCompStr
= himcc
) )))
111 WARN( "Failed to lock input context composition string\n" );
114 memset( compstr
, 0, sizeof(*compstr
) );
115 compstr
->dwSize
= sizeof(*compstr
);
119 compstr
->dwCursorPos
= len
;
121 compstr
->dwCompStrLen
= len
;
122 compstr
->dwCompStrOffset
= compstr
->dwSize
;
123 dst
= (BYTE
*)compstr
+ compstr
->dwCompStrOffset
;
124 memcpy( dst
, str
, compstr
->dwCompStrLen
* sizeof(WCHAR
) );
125 compstr
->dwSize
+= compstr
->dwCompStrLen
* sizeof(WCHAR
);
127 compstr
->dwCompClauseLen
= 2 * sizeof(DWORD
);
128 compstr
->dwCompClauseOffset
= compstr
->dwSize
;
129 dst
= (BYTE
*)compstr
+ compstr
->dwCompClauseOffset
;
130 *((DWORD
*)dst
+ 0) = 0;
131 *((DWORD
*)dst
+ 1) = compstr
->dwCompStrLen
;
132 compstr
->dwSize
+= compstr
->dwCompClauseLen
;
134 compstr
->dwCompAttrLen
= compstr
->dwCompStrLen
;
135 compstr
->dwCompAttrOffset
= compstr
->dwSize
;
136 dst
= (BYTE
*)compstr
+ compstr
->dwCompAttrOffset
;
137 memset( dst
, ATTR_INPUT
, compstr
->dwCompAttrLen
);
138 compstr
->dwSize
+= compstr
->dwCompAttrLen
;
141 ImmUnlockIMCC( ctx
->hCompStr
);
145 static HFONT
input_context_select_ui_font( INPUTCONTEXT
*ctx
, HDC hdc
)
147 struct ime_private
*priv
;
149 if (!(priv
= ImmLockIMCC( ctx
->hPrivate
))) return NULL
;
150 if (priv
->hfont
) font
= SelectObject( hdc
, priv
->hfont
);
151 ImmUnlockIMCC( ctx
->hPrivate
);
155 static void ime_send_message( HIMC himc
, UINT message
, WPARAM wparam
, LPARAM lparam
)
161 if (!(ctx
= ImmLockIMC( himc
))) return;
162 if (!(himcc
= ImmReSizeIMCC( ctx
->hMsgBuf
, (ctx
->dwNumMsgBuf
+ 1) * sizeof(*msgs
) )))
163 WARN( "Failed to resize input context message buffer\n" );
164 else if (!(msgs
= ImmLockIMCC( (ctx
->hMsgBuf
= himcc
) )))
165 WARN( "Failed to lock input context message buffer\n" );
168 TRANSMSG msg
= {.message
= message
, .wParam
= wparam
, .lParam
= lparam
};
169 msgs
[ctx
->dwNumMsgBuf
++] = msg
;
170 ImmUnlockIMCC( ctx
->hMsgBuf
);
173 ImmUnlockIMC( himc
);
174 ImmGenerateMessage( himc
);
177 static UINT
ime_set_composition_status( HIMC himc
, BOOL composition
)
179 struct ime_private
*priv
;
183 if (!(ctx
= ImmLockIMC( himc
))) return 0;
184 if ((priv
= ImmLockIMCC( ctx
->hPrivate
)))
186 if (!priv
->in_composition
&& composition
) msg
= WM_IME_STARTCOMPOSITION
;
187 else if (priv
->in_composition
&& !composition
) msg
= WM_IME_ENDCOMPOSITION
;
188 priv
->in_composition
= composition
;
189 ImmUnlockIMCC( ctx
->hPrivate
);
191 ImmUnlockIMC( himc
);
196 static void ime_ui_paint( HIMC himc
, HWND hwnd
)
202 MONITORINFO mon_info
;
208 if (!(ctx
= ImmLockIMC( himc
))) return;
210 hdc
= BeginPaint( hwnd
, &ps
);
212 GetClientRect( hwnd
, &rect
);
213 FillRect( hdc
, &rect
, (HBRUSH
)(COLOR_WINDOW
+ 1) );
216 if ((str
= input_context_get_comp_str( ctx
, FALSE
, &len
)))
218 HFONT font
= input_context_select_ui_font( ctx
, hdc
);
222 GetTextExtentPoint32W( hdc
, str
, len
, &size
);
225 LPtoDP( hdc
, &pt
, 1 );
228 * How this works based on tests on windows:
229 * CFS_POINT: then we start our window at the point and grow it as large
230 * as it needs to be for the string.
231 * CFS_RECT: we still use the ptCurrentPos as a starting point and our
232 * window is only as large as we need for the string, but we do not
233 * grow such that our window exceeds the given rect. Wrapping if
234 * needed and possible. If our ptCurrentPos is outside of our rect
235 * then no window is displayed.
236 * CFS_FORCE_POSITION: appears to behave just like CFS_POINT
237 * maybe because the default MSIME does not do any IME adjusting.
239 if (ctx
->cfCompForm
.dwStyle
!= CFS_DEFAULT
)
241 POINT cpt
= ctx
->cfCompForm
.ptCurrentPos
;
242 ClientToScreen( ctx
->hWnd
, &cpt
);
245 rect
.right
= rect
.left
+ pt
.x
;
246 rect
.bottom
= rect
.top
+ pt
.y
;
247 offset
.x
= offset
.y
= 0;
248 monitor
= MonitorFromPoint( cpt
, MONITOR_DEFAULTTOPRIMARY
);
250 else /* CFS_DEFAULT */
252 /* Windows places the default IME window in the bottom left */
253 HWND target
= ctx
->hWnd
;
254 if (!target
) target
= GetFocus();
256 GetWindowRect( target
, &rect
);
257 rect
.top
= rect
.bottom
;
258 rect
.right
= rect
.left
+ pt
.x
+ 20;
259 rect
.bottom
= rect
.top
+ pt
.y
+ 20;
260 offset
.x
= offset
.y
= 10;
261 monitor
= MonitorFromWindow( target
, MONITOR_DEFAULTTOPRIMARY
);
264 if (ctx
->cfCompForm
.dwStyle
== CFS_RECT
)
266 RECT client
= ctx
->cfCompForm
.rcArea
;
267 MapWindowPoints( ctx
->hWnd
, 0, (POINT
*)&client
, 2 );
268 IntersectRect( &rect
, &rect
, &client
);
269 DrawTextW( hdc
, str
, len
, &rect
, DT_WORDBREAK
| DT_CALCRECT
);
272 if (ctx
->cfCompForm
.dwStyle
== CFS_DEFAULT
)
274 /* make sure we are on the desktop */
275 mon_info
.cbSize
= sizeof(mon_info
);
276 GetMonitorInfoW( monitor
, &mon_info
);
278 if (rect
.bottom
> mon_info
.rcWork
.bottom
)
280 int shift
= rect
.bottom
- mon_info
.rcWork
.bottom
;
282 rect
.bottom
-= shift
;
286 rect
.right
-= rect
.left
;
289 if (rect
.right
> mon_info
.rcWork
.right
)
291 int shift
= rect
.right
- mon_info
.rcWork
.right
;
298 OffsetRect( &rect
, offset
.x
- rect
.left
, offset
.y
- rect
.top
);
299 DrawTextW( hdc
, str
, len
, &rect
, DT_WORDBREAK
);
301 if (font
) SelectObject( hdc
, font
);
305 EndPaint( hwnd
, &ps
);
306 ImmUnlockIMC( himc
);
308 if (!EqualRect( &rect
, &new_rect
))
309 SetWindowPos( hwnd
, HWND_TOPMOST
, new_rect
.left
, new_rect
.top
, new_rect
.right
- new_rect
.left
,
310 new_rect
.bottom
- new_rect
.top
, SWP_NOACTIVATE
);
313 static void ime_ui_update_window( INPUTCONTEXT
*ctx
, HWND hwnd
)
318 if (!(str
= input_context_get_comp_str( ctx
, FALSE
, &len
)) || !*str
)
319 ShowWindow( hwnd
, SW_HIDE
);
322 ShowWindow( hwnd
, SW_SHOWNOACTIVATE
);
323 RedrawWindow( hwnd
, NULL
, NULL
, RDW_ERASENOW
| RDW_INVALIDATE
);
327 ctx
->hWnd
= GetFocus();
330 static void ime_ui_composition( HIMC himc
, HWND hwnd
, LPARAM lparam
)
333 if (lparam
& GCS_RESULTSTR
) return;
334 if (!(ctx
= ImmLockIMC( himc
))) return;
335 ime_ui_update_window( ctx
, hwnd
);
336 ImmUnlockIMC( himc
);
339 static void ime_ui_start_composition( HIMC himc
, HWND hwnd
)
342 if (!(ctx
= ImmLockIMC( himc
))) return;
343 ime_ui_update_window( ctx
, hwnd
);
344 ImmUnlockIMC( himc
);
347 static UINT
ime_set_comp_string( HIMC himc
, LPARAM lparam
)
354 TRANSMSG TransMsg
[10];
357 } buffer
= {.uMsgCount
= ARRAY_SIZE(buffer
.TransMsg
)};
363 TRACE( "himc %p\n", himc
);
365 if (!(ctx
= ImmLockIMC( himc
))) return 0;
367 count
= ImeToAsciiEx( VK_PROCESSKEY
, lparam
, NULL
, &buffer
.list
, 0, himc
);
369 TRACE( "ImeToAsciiEx returned no messages\n" );
370 else if (count
>= buffer
.uMsgCount
)
371 WARN( "ImeToAsciiEx returned %#x messages\n", count
);
372 else if (!(himcc
= ImmReSizeIMCC( ctx
->hMsgBuf
, (ctx
->dwNumMsgBuf
+ count
) * sizeof(*msgs
) )))
373 WARN( "Failed to resize input context message buffer\n" );
374 else if (!(msgs
= ImmLockIMCC( (ctx
->hMsgBuf
= himcc
) )))
375 WARN( "Failed to lock input context message buffer\n" );
378 memcpy( msgs
+ ctx
->dwNumMsgBuf
, buffer
.TransMsg
, count
* sizeof(*msgs
) );
379 ImmUnlockIMCC( ctx
->hMsgBuf
);
380 ctx
->dwNumMsgBuf
+= count
;
383 ImmUnlockIMC( himc
);
384 ImmGenerateMessage( himc
);
389 static LRESULT
ime_ui_notify( HIMC himc
, HWND hwnd
, WPARAM wparam
, LPARAM lparam
)
391 TRACE( "himc %p, hwnd %p, wparam %s, lparam %#Ix\n", hwnd
, himc
, debugstr_imn(wparam
), lparam
);
395 case IMN_WINE_SET_OPEN_STATUS
:
396 return ImmSetOpenStatus( himc
, lparam
);
397 case IMN_WINE_SET_COMP_STRING
:
398 return ime_set_comp_string( himc
, lparam
);
404 static LRESULT WINAPI
ime_ui_window_proc( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
406 HIMC himc
= (HIMC
)GetWindowLongPtrW( hwnd
, IMMGWL_IMC
);
408 TRACE( "hwnd %p, himc %p, msg %s, wparam %#Ix, lparam %#Ix\n",
409 hwnd
, himc
, debugstr_wm_ime(msg
), wparam
, lparam
);
416 ime_ui_paint( himc
, hwnd
);
419 if (wparam
) SetFocus( (HWND
)wparam
);
420 else FIXME( "Received focus, should never have focus\n" );
422 case WM_IME_COMPOSITION
:
423 ime_ui_composition( himc
, hwnd
, lparam
);
425 case WM_IME_STARTCOMPOSITION
:
426 ime_ui_start_composition( himc
, hwnd
);
428 case WM_IME_ENDCOMPOSITION
:
429 ShowWindow( hwnd
, SW_HIDE
);
432 return ime_ui_notify( himc
, hwnd
, wparam
, lparam
);
434 FIXME( "hwnd %p, himc %p, msg %s, wparam %s, lparam %#Ix stub!\n", hwnd
, himc
,
435 debugstr_wm_ime(msg
), debugstr_imc(wparam
), lparam
);
439 return DefWindowProcW( hwnd
, msg
, wparam
, lparam
);
442 static WNDCLASSEXW ime_ui_class
=
444 .cbSize
= sizeof(WNDCLASSEXW
),
445 .style
= CS_GLOBALCLASS
| CS_IME
| CS_HREDRAW
| CS_VREDRAW
,
446 .lpfnWndProc
= ime_ui_window_proc
,
447 .cbWndExtra
= 2 * sizeof(LONG_PTR
),
448 .lpszClassName
= L
"Wine IME",
449 .hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1),
452 BOOL WINAPI
ImeInquire( IMEINFO
*info
, WCHAR
*ui_class
, DWORD flags
)
454 TRACE( "info %p, ui_class %p, flags %#lx\n", info
, ui_class
, flags
);
456 ime_ui_class
.hInstance
= imm32_module
;
457 ime_ui_class
.hCursor
= LoadCursorW( NULL
, (LPWSTR
)IDC_ARROW
);
458 ime_ui_class
.hIcon
= LoadIconW( NULL
, (LPWSTR
)IDI_APPLICATION
);
459 RegisterClassExW( &ime_ui_class
);
461 wcscpy( ui_class
, ime_ui_class
.lpszClassName
);
462 memset( info
, 0, sizeof(*info
) );
463 info
->dwPrivateDataSize
= sizeof(struct ime_private
);
464 info
->fdwProperty
= IME_PROP_UNICODE
| IME_PROP_AT_CARET
;
465 info
->fdwConversionCaps
= IME_CMODE_NATIVE
| IME_CMODE_FULLSHAPE
;
466 info
->fdwSentenceCaps
= IME_SMODE_AUTOMATIC
;
467 info
->fdwUICaps
= UI_CAP_2700
;
468 /* Tell App we cannot accept ImeSetCompositionString calls */
469 info
->fdwSCSCaps
= 0;
470 info
->fdwSelectCaps
= SELECT_CAP_CONVERSION
;
475 BOOL WINAPI
ImeDestroy( UINT force
)
477 TRACE( "force %u\n", force
);
478 UnregisterClassW( ime_ui_class
.lpszClassName
, imm32_module
);
482 BOOL WINAPI
ImeSelect( HIMC himc
, BOOL select
)
484 struct ime_private
*priv
;
487 TRACE( "himc %p, select %u\n", himc
, select
);
489 if (!himc
|| !select
) return TRUE
;
490 if (!(ctx
= ImmLockIMC( himc
))) return FALSE
;
492 ImmSetOpenStatus( himc
, FALSE
);
494 if ((priv
= ImmLockIMCC( ctx
->hPrivate
)))
496 memset( priv
, 0, sizeof(*priv
) );
497 ImmUnlockIMCC( ctx
->hPrivate
);
500 ImmUnlockIMC( himc
);
504 BOOL WINAPI
ImeSetActiveContext( HIMC himc
, BOOL flag
)
506 TRACE( "himc %p, flag %#x stub!\n", himc
, flag
);
510 BOOL WINAPI
ImeProcessKey( HIMC himc
, UINT vkey
, LPARAM lparam
, BYTE
*state
)
512 struct ime_driver_call_params params
= {.himc
= himc
, .state
= state
};
516 TRACE( "himc %p, vkey %#x, lparam %#Ix, state %p\n", himc
, vkey
, lparam
, state
);
518 if (!(ctx
= ImmLockIMC( himc
))) return FALSE
;
519 ret
= NtUserMessageCall( ctx
->hWnd
, WINE_IME_PROCESS_KEY
, vkey
, lparam
, ¶ms
,
520 NtUserImeDriverCall
, FALSE
);
521 ImmUnlockIMC( himc
);
526 UINT WINAPI
ImeToAsciiEx( UINT vkey
, UINT vsc
, BYTE
*state
, TRANSMSGLIST
*msgs
, UINT flags
, HIMC himc
)
528 COMPOSITIONSTRING
*compstr
;
529 UINT size
, count
= 0;
533 TRACE( "vkey %#x, vsc %#x, state %p, msgs %p, flags %#x, himc %p\n",
534 vkey
, vsc
, state
, msgs
, flags
, himc
);
536 if (!(ctx
= ImmLockIMC( himc
))) return 0;
537 if (!(compstr
= ImmLockIMCC( ctx
->hCompStr
))) goto done
;
538 size
= max( compstr
->dwSize
, sizeof(COMPOSITIONSTRING
) );
542 struct ime_driver_call_params params
= {.himc
= himc
, .state
= state
};
545 ImmUnlockIMCC( ctx
->hCompStr
);
546 if (!(himcc
= ImmReSizeIMCC( ctx
->hCompStr
, size
))) goto done
;
547 if (!(compstr
= ImmLockIMCC( (ctx
->hCompStr
= himcc
) ))) goto done
;
549 params
.compstr
= compstr
;
550 status
= NtUserMessageCall( ctx
->hWnd
, WINE_IME_TO_ASCII_EX
, vkey
, vsc
, ¶ms
,
551 NtUserImeDriverCall
, FALSE
);
552 size
= compstr
->dwSize
;
553 } while (status
== STATUS_BUFFER_TOO_SMALL
);
555 if (status
) WARN( "WINE_IME_TO_ASCII_EX returned status %#lx\n", status
);
558 TRANSMSG status_msg
= {.message
= ime_set_composition_status( himc
, !!compstr
->dwCompStrOffset
)};
559 if (status_msg
.message
) msgs
->TransMsg
[count
++] = status_msg
;
561 if (compstr
->dwResultStrOffset
)
563 const WCHAR
*result
= (WCHAR
*)((BYTE
*)compstr
+ compstr
->dwResultStrOffset
);
564 TRANSMSG msg
= {.message
= WM_IME_COMPOSITION
, .wParam
= result
[0], .lParam
= GCS_RESULTSTR
};
565 if (compstr
->dwResultClauseOffset
) msg
.lParam
|= GCS_RESULTCLAUSE
;
566 msgs
->TransMsg
[count
++] = msg
;
569 if (compstr
->dwCompStrOffset
)
571 const WCHAR
*comp
= (WCHAR
*)((BYTE
*)compstr
+ compstr
->dwCompStrOffset
);
572 TRANSMSG msg
= {.message
= WM_IME_COMPOSITION
, .wParam
= comp
[0], .lParam
= GCS_COMPSTR
| GCS_CURSORPOS
| GCS_DELTASTART
};
573 if (compstr
->dwCompAttrOffset
) msg
.lParam
|= GCS_COMPATTR
;
574 if (compstr
->dwCompClauseOffset
) msg
.lParam
|= GCS_COMPCLAUSE
;
575 else msg
.lParam
|= CS_INSERTCHAR
|CS_NOMOVECARET
;
576 msgs
->TransMsg
[count
++] = msg
;
580 ImmUnlockIMCC( ctx
->hCompStr
);
583 if (count
>= msgs
->uMsgCount
) FIXME( "More than %u messages queued, messages possibly lost\n", msgs
->uMsgCount
);
584 else TRACE( "Returning %u messages queued\n", count
);
585 ImmUnlockIMC( himc
);
589 BOOL WINAPI
ImeConfigure( HKL hkl
, HWND hwnd
, DWORD mode
, void *data
)
591 FIXME( "hkl %p, hwnd %p, mode %lu, data %p stub!\n", hkl
, hwnd
, mode
, data
);
592 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
596 DWORD WINAPI
ImeConversionList( HIMC himc
, const WCHAR
*source
, CANDIDATELIST
*dest
, DWORD dest_len
, UINT flag
)
598 FIXME( "himc %p, source %s, dest %p, dest_len %lu, flag %#x stub!\n",
599 himc
, debugstr_w(source
), dest
, dest_len
, flag
);
600 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
604 BOOL WINAPI
ImeSetCompositionString( HIMC himc
, DWORD index
, const void *comp
, DWORD comp_len
,
605 const void *read
, DWORD read_len
)
609 FIXME( "himc %p, index %lu, comp %p, comp_len %lu, read %p, read_len %lu semi-stub!\n",
610 himc
, index
, comp
, comp_len
, read
, read_len
);
611 if (read
&& read_len
) FIXME( "Read string unimplemented\n" );
612 if (index
!= SCS_SETSTR
&& index
!= SCS_CHANGECLAUSE
&& index
!= SCS_CHANGEATTR
) return FALSE
;
614 if (!(ctx
= ImmLockIMC( himc
))) return FALSE
;
616 if (index
!= SCS_SETSTR
)
617 FIXME( "index %#lx not implemented\n", index
);
620 UINT msg
, flags
= GCS_COMPSTR
| GCS_COMPCLAUSE
| GCS_COMPATTR
| GCS_DELTASTART
| GCS_CURSORPOS
;
621 WCHAR wparam
= comp
&& comp_len
>= sizeof(WCHAR
) ? *(WCHAR
*)comp
: 0;
622 input_context_set_comp_str( ctx
, comp
, comp_len
/ sizeof(WCHAR
) );
623 if ((msg
= ime_set_composition_status( himc
, TRUE
))) ime_send_message( himc
, msg
, 0, 0 );
624 ime_send_message( himc
, WM_IME_COMPOSITION
, wparam
, flags
);
627 ImmUnlockIMC( himc
);
632 BOOL WINAPI
NotifyIME( HIMC himc
, DWORD action
, DWORD index
, DWORD value
)
634 struct ime_private
*priv
;
638 TRACE( "himc %p, action %#lx, index %#lx, value %#lx stub!\n", himc
, action
, index
, value
);
640 if (!(ctx
= ImmLockIMC( himc
))) return FALSE
;
644 case NI_CONTEXTUPDATED
:
647 case IMC_SETCOMPOSITIONFONT
:
648 if ((priv
= ImmLockIMCC( ctx
->hPrivate
)))
650 if (priv
->hfont
) DeleteObject( priv
->hfont
);
651 priv
->hfont
= CreateFontIndirectW( &ctx
->lfFont
.W
);
652 ImmUnlockIMCC( ctx
->hPrivate
);
655 case IMC_SETOPENSTATUS
:
656 if (!ctx
->fOpen
) ImmNotifyIME( himc
, NI_COMPOSITIONSTR
, CPS_COMPLETE
, 0 );
657 NtUserNotifyIMEStatus( ctx
->hWnd
, ctx
->fOpen
);
662 case NI_COMPOSITIONSTR
:
667 COMPOSITIONSTRING
*compstr
;
669 if (!(compstr
= ImmLockIMCC( ctx
->hCompStr
)))
670 WARN( "Failed to lock input context composition string\n" );
673 WCHAR wchr
= *(WCHAR
*)((BYTE
*)compstr
+ compstr
->dwCompStrOffset
);
674 COMPOSITIONSTRING tmp
= *compstr
;
677 memset( compstr
, 0, sizeof(*compstr
) );
678 compstr
->dwSize
= tmp
.dwSize
;
679 compstr
->dwResultStrLen
= tmp
.dwCompStrLen
;
680 compstr
->dwResultStrOffset
= tmp
.dwCompStrOffset
;
681 compstr
->dwResultClauseLen
= tmp
.dwCompClauseLen
;
682 compstr
->dwResultClauseOffset
= tmp
.dwCompClauseOffset
;
683 ImmUnlockIMCC( ctx
->hCompStr
);
685 if (tmp
.dwCompStrLen
) flags
|= GCS_RESULTSTR
;
686 if (tmp
.dwCompClauseLen
) flags
|= GCS_RESULTCLAUSE
;
687 if (flags
) ime_send_message( himc
, WM_IME_COMPOSITION
, wchr
, flags
);
693 input_context_set_comp_str( ctx
, NULL
, 0 );
694 if ((msg
= ime_set_composition_status( himc
, FALSE
)))
695 ime_send_message( himc
, msg
, 0, 0 );
698 FIXME( "himc %p, action %#lx, index %#lx, value %#lx stub!\n", himc
, action
, index
, value
);
704 FIXME( "himc %p, action %#lx, index %#lx, value %#lx stub!\n", himc
, action
, index
, value
);
708 ImmUnlockIMC( himc
);
712 LRESULT WINAPI
ImeEscape( HIMC himc
, UINT escape
, void *data
)
714 FIXME( "himc %p, escape %#x, data %p stub!\n", himc
, escape
, data
);
715 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
719 DWORD WINAPI
ImeGetImeMenuItems( HIMC himc
, DWORD flags
, DWORD type
, IMEMENUITEMINFOW
*parent
,
720 IMEMENUITEMINFOW
*menu
, DWORD size
)
722 FIXME( "himc %p, flags %#lx, type %lu, parent %p, menu %p, size %#lx stub!\n",
723 himc
, flags
, type
, parent
, menu
, size
);
724 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
728 BOOL WINAPI
ImeRegisterWord( const WCHAR
*reading
, DWORD style
, const WCHAR
*string
)
730 FIXME( "reading %s, style %lu, string %s stub!\n", debugstr_w(reading
), style
, debugstr_w(string
) );
731 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
735 UINT WINAPI
ImeGetRegisterWordStyle( UINT item
, STYLEBUFW
*style
)
737 FIXME( "item %u, style %p stub!\n", item
, style
);
738 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
742 BOOL WINAPI
ImeUnregisterWord( const WCHAR
*reading
, DWORD style
, const WCHAR
*string
)
744 FIXME( "reading %s, style %lu, string %s stub!\n", debugstr_w(reading
), style
, debugstr_w(string
) );
745 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
749 UINT WINAPI
ImeEnumRegisterWord( REGISTERWORDENUMPROCW proc
, const WCHAR
*reading
, DWORD style
,
750 const WCHAR
*string
, void *data
)
752 FIXME( "proc %p, reading %s, style %lu, string %s, data %p stub!\n",
753 proc
, debugstr_w(reading
), style
, debugstr_w(string
), data
);
754 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);