Implement GetGlyphIndices. Tweak GetCharacterPlacement to use it.
[wine/testsucceed.git] / dlls / imm32 / imekl.c
blobc21ce2c77b6b8f0dc8e55ccdab5ab83de99aa247
1 /*
2 * IME Keyboard Layout
4 * Copyright 2000 Hidenori Takeshima
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "config.h"
23 #include <string.h>
24 #include "winbase.h"
25 #include "windef.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winerror.h"
29 #include "winnls.h"
30 #include "winreg.h"
31 #include "immddk.h"
33 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(imm);
36 #include "imm_private.h"
38 static const char IMM32_szRegKL[] =
39 "System\\CurrentControlSet\\Control\\keyboard layouts";
40 static const char IMM32_szIME_File[] = "IME file";
41 static const char IMM32_szLayout_File[] = "layout file";
43 static IMM32_IMEKL* IMM32_pklFirst = NULL;
46 static LONG IMM32_RegOpenKey( HKL hkl, PHKEY phkRet )
48 CHAR szRegPath[ sizeof(IMM32_szRegKL)+16 ];
50 wsprintfA( szRegPath, "%s\\%08x", IMM32_szRegKL, (unsigned)hkl );
51 return RegOpenKeyExA( HKEY_LOCAL_MACHINE, szRegPath,
52 0, KEY_READ, phkRet );
55 static LONG IMM32_RegCreateKey( HKL hkl, PHKEY phkRet,
56 LPDWORD lpdwDisposition )
58 CHAR szRegPath[ sizeof(IMM32_szRegKL)+16 ];
60 wsprintfA( szRegPath, "%s\\%08x", IMM32_szRegKL, (unsigned)hkl );
61 return RegCreateKeyExA( HKEY_LOCAL_MACHINE, szRegPath,
62 0, "REG_SZ",
63 REG_OPTION_NON_VOLATILE,
64 KEY_ALL_ACCESS, NULL,
65 phkRet, lpdwDisposition );
68 static DWORD IMM32_GetIMEFileName( HKL hkl, LPSTR lpBuf, INT nBufLen )
70 HKEY hkey;
71 LONG nError;
72 DWORD dwType;
73 DWORD cbData;
74 CHAR szValueName[ sizeof(IMM32_szIME_File) ];
76 TRACE( "hkl = %08x\n", (unsigned)hkl );
78 nError = IMM32_RegOpenKey( hkl, &hkey );
79 if ( nError != ERROR_SUCCESS )
81 SetLastError( nError );
82 return 0;
84 memcpy( szValueName, IMM32_szIME_File, sizeof(IMM32_szIME_File) );
86 nError = RegQueryValueExA( hkey, szValueName, NULL,
87 &dwType, NULL, &cbData );
88 if ( nError == ERROR_SUCCESS && dwType != REG_SZ )
89 nError = ERROR_FILE_NOT_FOUND; /* FIXME? */
90 if ( nError == ERROR_SUCCESS && lpBuf != NULL && nBufLen != 0 )
92 if ( nBufLen < (INT)cbData )
93 nError = ERROR_INSUFFICIENT_BUFFER;
94 else
95 nError = RegQueryValueExA( hkey, szValueName, NULL,
96 &dwType, lpBuf, &cbData );
99 RegCloseKey( hkey );
101 if ( nError != ERROR_SUCCESS )
103 SetLastError( nError );
104 return 0;
107 return cbData;
111 static
112 BOOL IMM32_GetIMEHandlersA( HINSTANCE hInstIME,
113 struct IMM32_IME_EXPORTED_HANDLERS* phandlers )
115 BOOL fError;
117 #define FE(name) \
118 phandlers->p##name = (IMM32_p##name) \
119 GetProcAddress(hInstIME,#name); \
120 if ( phandlers->p##name == NULL ) fError = TRUE;
121 #define FE_(name) \
122 phandlers->p##name.A = (IMM32_p##name##A) \
123 GetProcAddress(hInstIME,#name); \
124 if ( phandlers->p##name.A == NULL ) fError = TRUE;
126 fError = FALSE;
128 FE_(ImeInquire)
129 FE_(ImeConfigure)
130 FE_(ImeConversionList)
131 FE(ImeDestroy)
132 FE_(ImeEnumRegisterWord)
133 FE_(ImeGetRegisterWordStyle)
134 FE_(ImeEscape)
135 FE(ImeProcessKey)
136 FE_(ImeRegisterWord)
137 FE(ImeSelect)
138 FE(ImeSetActiveContext)
139 FE_(ImeSetCompositionString)
140 FE(ImeToAsciiEx)
141 FE_(ImeUnregisterWord)
142 FE(NotifyIME)
144 if ( fError )
145 return FALSE;
147 FE_(ImeGetImeMenuItems)
149 #undef FE
150 #undef FE_
152 return TRUE;
155 static
156 BOOL IMM32_GetIMEHandlersW( HINSTANCE hInstIME,
157 struct IMM32_IME_EXPORTED_HANDLERS* phandlers )
159 BOOL fError;
161 #define FE(name) \
162 phandlers->p##name = (IMM32_p##name) \
163 GetProcAddress(hInstIME,#name); \
164 if ( phandlers->p##name == NULL ) fError = TRUE;
165 #define FE_(name) \
166 phandlers->p##name.W = (IMM32_p##name##W) \
167 GetProcAddress(hInstIME,#name); \
168 if ( phandlers->p##name.W == NULL ) fError = TRUE;
170 fError = FALSE;
172 FE_(ImeInquire)
173 FE_(ImeConfigure)
174 FE_(ImeConversionList)
175 FE(ImeDestroy)
176 FE_(ImeEnumRegisterWord)
177 FE_(ImeGetRegisterWordStyle)
178 FE_(ImeEscape)
179 FE(ImeProcessKey)
180 FE_(ImeRegisterWord)
181 FE(ImeSelect)
182 FE(ImeSetActiveContext)
183 FE_(ImeSetCompositionString)
184 FE(ImeToAsciiEx)
185 FE_(ImeUnregisterWord)
186 FE(NotifyIME)
188 if ( fError )
189 return FALSE;
191 FE_(ImeGetImeMenuItems)
193 #undef FE
194 #undef FE_
196 return TRUE;
200 static IMM32_IMEKL* IMM32_LoadIME( HKL hkl )
202 IMM32_IMEKL* pkl = NULL;
203 BOOL fInitialized = FALSE;
204 CHAR* pszFileName = NULL;
205 DWORD dwBufLen;
206 IMM32_pImeInquireA pImeInquire;
207 IMM32_pImeDestroy pImeDestroy = NULL;
208 CHAR szUIClassName[ (IMM32_UICLASSNAME_MAX+1)*sizeof(WCHAR) ];
210 dwBufLen = IMM32_GetIMEFileName( hkl, NULL, 0 );
211 if ( dwBufLen == 0 )
212 goto err;
213 pszFileName = (CHAR*)IMM32_HeapAlloc( 0, sizeof(CHAR)*(dwBufLen+1) );
214 if ( pszFileName == NULL )
216 SetLastError( ERROR_OUTOFMEMORY );
217 goto err;
219 if ( !IMM32_GetIMEFileName( hkl, pszFileName, dwBufLen + 1 ) )
220 goto err;
222 pkl = (IMM32_IMEKL*)
223 IMM32_HeapAlloc( HEAP_ZERO_MEMORY, sizeof(IMM32_IMEKL) );
224 if ( pkl == NULL )
226 SetLastError( ERROR_OUTOFMEMORY );
227 goto err;
230 pkl->pNext = NULL;
231 pkl->hkl = hkl;
232 pkl->hInstIME = LoadLibraryA( pszFileName );
233 if ( pkl->hInstIME == (HINSTANCE)NULL )
234 goto err;
236 pImeInquire = (IMM32_pImeInquireA)GetProcAddress
237 ( pkl->hInstIME, "ImeInquire" );
238 pImeDestroy = (IMM32_pImeDestroy)GetProcAddress
239 ( pkl->hInstIME, "ImeDestroy" );
240 if ( pImeInquire == NULL || pImeDestroy == NULL )
241 goto err;
243 if ( !pImeInquire( &(pkl->imeinfo), szUIClassName, NULL ) )
245 SetLastError( ERROR_DLL_INIT_FAILED ); /* FIXME? */
246 goto err;
248 fInitialized = TRUE;
250 /* FIXME: Is this correct??? */
251 if ( pkl->imeinfo.fdwProperty & IME_PROP_UNICODE )
252 pkl->fUnicode = TRUE;
253 else
254 pkl->fUnicode = FALSE;
256 if ( pkl->fUnicode )
258 if ( !IMM32_GetIMEHandlersW( pkl->hInstIME, &pkl->handlers ) )
259 goto err;
260 memcpy( pkl->UIClassName.W, szUIClassName,
261 IMM32_UICLASSNAME_MAX*sizeof(WCHAR) );
262 TRACE( "UI class name(Unicode): %s\n",
263 debugstr_w(pkl->UIClassName.W) );
265 else
267 if ( !IMM32_GetIMEHandlersA( pkl->hInstIME, &pkl->handlers ) )
268 goto err;
269 memcpy( pkl->UIClassName.A, szUIClassName,
270 IMM32_UICLASSNAME_MAX*sizeof(CHAR) );
271 TRACE( "UI class name(ASCII): %s\n",
272 debugstr_a(pkl->UIClassName.A) );
275 /* The IME is loaded successfully. */
276 pkl->pszIMEFileName = pszFileName; pszFileName = NULL;
277 return pkl;
279 err:
280 IMM32_HeapFree( pszFileName );
281 if ( pkl != NULL )
283 if ( pkl->hInstIME != (HINSTANCE)NULL )
285 if ( fInitialized )
286 (void)pImeDestroy(0);
287 FreeLibrary( pkl->hInstIME );
289 IMM32_HeapFree( pkl );
292 return NULL;
296 const IMM32_IMEKL* IMM32_GetIME( HKL hkl )
298 IMM32_IMEKL* pkl;
300 IMM32_Lock();
302 pkl = IMM32_pklFirst;
303 while ( pkl != NULL )
305 if ( pkl->hkl == hkl )
306 goto end;
307 pkl = pkl->pNext;
310 pkl = IMM32_LoadIME( hkl );
311 if ( pkl != NULL )
313 pkl->pNext = IMM32_pklFirst;
314 IMM32_pklFirst = pkl;
317 end:
318 IMM32_Unlock();
320 return pkl;
323 void IMM32_UnloadAllIMEs( void )
325 IMM32_IMEKL* pkl;
326 IMM32_IMEKL* pklNext;
328 IMM32_Lock();
330 pkl = IMM32_pklFirst;
331 while ( pkl != NULL )
333 TRACE( "hkl = %08x\n", (unsigned)pkl->hkl );
335 pklNext = pkl->pNext;
336 (void)pkl->handlers.pImeDestroy(0);
337 FreeLibrary( pkl->hInstIME );
338 IMM32_HeapFree( pkl->pszIMEFileName );
339 IMM32_HeapFree( pkl );
340 pkl = pklNext;
342 IMM32_pklFirst = NULL;
344 IMM32_Unlock();
349 /***********************************************************************
350 * ImmInstallIMEA (IMM32.@)
352 HKL WINAPI ImmInstallIMEA(
353 LPCSTR lpszIMEFileName, LPCSTR lpszLayoutText)
355 HKL hkl;
356 DWORD dwLCID;
357 DWORD dwTryCount;
358 LONG nError;
359 HKEY hkey;
360 DWORD dwDisposition;
361 DWORD cbData;
362 CHAR szValueName[ sizeof(IMM32_szIME_File) ];
364 TRACE("(%s, %s)\n",
365 debugstr_a(lpszIMEFileName), debugstr_a(lpszLayoutText) );
367 dwLCID = (DWORD)GetThreadLocale();
368 dwTryCount = 0;
370 FIXME( "IMEs don't work correctly now since\n"
371 "wine/windows/input.c doesn't handle HKL correctly.\n" );
373 while ( 1 )
375 hkl = (HKL)(((0xe000|dwTryCount)<<16) | (dwLCID));
377 nError = IMM32_RegCreateKey( hkl, &hkey, &dwDisposition );
378 if ( nError != ERROR_SUCCESS )
379 break;
381 memcpy( szValueName, IMM32_szIME_File,
382 sizeof(IMM32_szIME_File) );
384 nError = RegQueryValueExA( hkey, szValueName, NULL,
385 NULL, NULL, &cbData );
386 if ( nError == ERROR_SUCCESS && cbData > 0 )
388 RegCloseKey( hkey );
390 /* try to assign an other HKL. */
391 dwTryCount ++;
392 if ( dwTryCount >= 0x100 )
394 nError = ERROR_ACCESS_DENIED; /* FIXME */
395 break;
397 continue;
400 nError = RegSetValueExA( hkey, IMM32_szIME_File, 0,
401 REG_SZ, lpszIMEFileName,
402 strlen(lpszIMEFileName)+1 );
403 if ( nError == ERROR_SUCCESS )
404 nError = RegSetValueExA( hkey, IMM32_szLayout_File, 0,
405 REG_SZ, lpszLayoutText,
406 strlen(lpszLayoutText)+1 );
407 RegCloseKey( hkey );
408 break;
411 if ( nError != ERROR_SUCCESS )
413 SetLastError( nError );
414 return (HKL)NULL;
417 return hkl;
420 /***********************************************************************
421 * ImmInstallIMEW (IMM32.@)
423 HKL WINAPI ImmInstallIMEW(
424 LPCWSTR lpszIMEFileName, LPCWSTR lpszLayoutText)
426 LPSTR lpszParam1;
427 LPSTR lpszParam2;
428 HKL hkl;
430 TRACE("(%s, %s)\n",
431 debugstr_w(lpszIMEFileName), debugstr_w(lpszLayoutText) );
433 lpszParam1 = IMM32_strdupWtoA( lpszIMEFileName );
434 lpszParam2 = IMM32_strdupWtoA( lpszLayoutText );
435 if ( ( lpszParam1 == NULL ) || ( lpszParam2 == NULL ) )
437 SetLastError( ERROR_OUTOFMEMORY );
438 hkl = (HKL)NULL;
440 else
442 hkl = ImmInstallIMEA( lpszParam1, lpszParam2 );
444 IMM32_HeapFree( lpszParam1 );
445 IMM32_HeapFree( lpszParam2 );
447 return hkl;
451 /***********************************************************************
452 * ImmIsIME (IMM32.@)
454 BOOL WINAPI ImmIsIME(HKL hkl)
456 const IMM32_IMEKL* pkl;
458 TRACE("(0x%08x)\n", hkl);
460 pkl = IMM32_GetIME( hkl );
461 if ( pkl == NULL )
462 return FALSE;
464 return TRUE;
468 /***********************************************************************
469 * ImmGetIMEFileNameA (IMM32.@)
471 UINT WINAPI ImmGetIMEFileNameA(HKL hkl, LPSTR lpszFileName, UINT uBufLen)
473 const IMM32_IMEKL* pkl;
474 UINT uIMEFileNameLen;
476 TRACE("(%08x,%p,%u)\n",hkl,lpszFileName,uBufLen);
478 pkl = IMM32_GetIME( hkl );
479 if ( pkl == NULL )
480 return 0;
482 uIMEFileNameLen = strlen(pkl->pszIMEFileName);
483 if ( uBufLen == 0 )
484 return uIMEFileNameLen;
485 if ( uBufLen <= uIMEFileNameLen )
487 SetLastError(ERROR_INSUFFICIENT_BUFFER);
488 return 0;
490 memcpy( lpszFileName, pkl->pszIMEFileName,
491 sizeof(CHAR)*(uIMEFileNameLen+1) );
493 return uIMEFileNameLen;
496 /***********************************************************************
497 * ImmGetIMEFileNameW (IMM32.@)
499 UINT WINAPI ImmGetIMEFileNameW(HKL hkl, LPWSTR lpszFileName, UINT uBufLen)
501 const IMM32_IMEKL* pkl;
502 UINT uIMEFileNameLen;
504 TRACE("(%08x,%p,%u)\n",hkl,lpszFileName,uBufLen);
506 pkl = IMM32_GetIME( hkl );
507 if ( pkl == NULL )
508 return 0;
510 uIMEFileNameLen = IMM32_strlenAtoW(pkl->pszIMEFileName);
511 if ( uBufLen == 0 )
512 return uIMEFileNameLen;
513 if ( uBufLen <= uIMEFileNameLen )
515 SetLastError(ERROR_INSUFFICIENT_BUFFER);
516 return 0;
518 IMM32_strncpyAtoW( lpszFileName, pkl->pszIMEFileName, uBufLen );
520 return uIMEFileNameLen;
523 /***********************************************************************
524 * ImmGetProperty (IMM32.@)
526 DWORD WINAPI ImmGetProperty(HKL hkl, DWORD fdwIndex)
528 const IMM32_IMEKL* pkl;
529 DWORD dwRet;
531 TRACE("(0x%08x, %ld)\n", hkl, fdwIndex);
533 pkl = IMM32_GetIME( hkl );
534 if ( pkl == NULL )
535 return 0;
537 switch ( fdwIndex )
539 case IGP_GETIMEVERSION:
540 dwRet = IMEVER_0400;
541 break;
542 case IGP_PROPERTY:
543 dwRet = pkl->imeinfo.fdwProperty;
544 break;
545 case IGP_CONVERSION:
546 dwRet = pkl->imeinfo.fdwConversionCaps;
547 break;
548 case IGP_SENTENCE:
549 dwRet = pkl->imeinfo.fdwSentenceCaps;
550 break;
551 case IGP_UI:
552 dwRet = pkl->imeinfo.fdwUICaps;
553 break;
554 case IGP_SETCOMPSTR:
555 dwRet = pkl->imeinfo.fdwSCSCaps;
556 break;
557 case IGP_SELECT:
558 dwRet = pkl->imeinfo.fdwSelectCaps;
559 break;
560 default:
561 FIXME("(0x%08x, %ld): invalid/unknown property.\n",
562 hkl, fdwIndex);
563 SetLastError( ERROR_INVALID_PARAMETER );
564 dwRet = 0;
567 return dwRet;
571 /***********************************************************************
572 * ImmEnumRegisterWordA (IMM32.@)
574 UINT WINAPI ImmEnumRegisterWordA(
575 HKL hkl, REGISTERWORDENUMPROCA lpfnEnumProc,
576 LPCSTR lpszReading, DWORD dwStyle,
577 LPCSTR lpszRegister, LPVOID lpData)
579 const IMM32_IMEKL* pkl;
581 TRACE("(0x%08x, %p, %s, %ld, %s, %p)\n",
582 hkl, lpfnEnumProc,
583 debugstr_a(lpszReading), dwStyle,
584 debugstr_a(lpszRegister), lpData);
586 pkl = IMM32_GetIME( hkl );
587 if ( pkl == NULL )
588 return 0;
590 if ( pkl->fUnicode )
592 FIXME( "please implement UNICODE->ANSI\n" );
593 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
594 return 0;
596 else
598 return pkl->handlers.pImeEnumRegisterWord.A
599 ( lpfnEnumProc, lpszReading, dwStyle,
600 lpszRegister, lpData );
604 /***********************************************************************
605 * ImmEnumRegisterWordW (IMM32.@)
607 UINT WINAPI ImmEnumRegisterWordW(
608 HKL hkl, REGISTERWORDENUMPROCW lpfnEnumProc,
609 LPCWSTR lpszReading, DWORD dwStyle,
610 LPCWSTR lpszRegister, LPVOID lpData)
612 const IMM32_IMEKL* pkl;
614 TRACE("(0x%08x, %p, %s, %ld, %s, %p): stub\n",
615 hkl, lpfnEnumProc,
616 debugstr_w(lpszReading), dwStyle,
617 debugstr_w(lpszRegister), lpData);
619 pkl = IMM32_GetIME( hkl );
620 if ( pkl == NULL )
621 return 0;
623 if ( pkl->fUnicode )
625 return pkl->handlers.pImeEnumRegisterWord.W
626 ( lpfnEnumProc, lpszReading, dwStyle,
627 lpszRegister, lpData );
629 else
631 FIXME( "please implement ANSI->UNICODE\n" );
632 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
633 return 0;
638 /***********************************************************************
639 * ImmGetRegisterWordStyleA (IMM32.@)
641 UINT WINAPI ImmGetRegisterWordStyleA(
642 HKL hkl, UINT nItem, LPSTYLEBUFA lpStyleBuf)
644 const IMM32_IMEKL* pkl;
646 TRACE("(0x%08x, %d, %p)\n", hkl, nItem, lpStyleBuf);
648 pkl = IMM32_GetIME( hkl );
649 if ( pkl == NULL )
650 return 0;
652 if ( pkl->fUnicode )
654 FIXME( "please implement UNICODE->ANSI\n" );
655 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
656 return 0;
658 else
660 return pkl->handlers.pImeGetRegisterWordStyle.A
661 ( nItem, lpStyleBuf );
665 /***********************************************************************
666 * ImmGetRegisterWordStyleW (IMM32.@)
668 UINT WINAPI ImmGetRegisterWordStyleW(
669 HKL hkl, UINT nItem, LPSTYLEBUFW lpStyleBuf)
671 const IMM32_IMEKL* pkl;
673 TRACE("(0x%08x, %d, %p)\n", hkl, nItem, lpStyleBuf);
675 pkl = IMM32_GetIME( hkl );
676 if ( pkl == NULL )
677 return 0;
679 if ( pkl->fUnicode )
681 return pkl->handlers.pImeGetRegisterWordStyle.W
682 ( nItem, lpStyleBuf );
684 else
686 FIXME( "please implement ANSI->UNICODE\n" );
687 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
688 return 0;