Various cosmetic changes.
[wine] / dlls / imm32 / imekl.c
1 /*
2  *      IME Keyboard Layout
3  *
4  *      Copyright 2000 Hidenori Takeshima
5  */
6
7 #include "config.h"
8
9 #include <string.h>
10 #include "winbase.h"
11 #include "windef.h"
12 #include "wingdi.h"
13 #include "winuser.h"
14 #include "winerror.h"
15 #include "winnls.h"
16 #include "winreg.h"
17 #include "immddk.h"
18
19 #include "debugtools.h"
20 DEFAULT_DEBUG_CHANNEL(imm);
21
22 #include "imm_private.h"
23
24 static const char       IMM32_szRegKL[] =
25         "System\\CurrentControlSet\\Control\\keyboard layouts";
26 static const char       IMM32_szIME_File[] = "IME file";
27 static const char       IMM32_szLayout_File[] = "layout file";
28
29 static IMM32_IMEKL*     IMM32_pklFirst = NULL;
30
31
32 static LONG IMM32_RegOpenKey( HKL hkl, PHKEY phkRet )
33 {
34         CHAR    szRegPath[ sizeof(IMM32_szRegKL)+16 ];
35
36         wsprintfA( szRegPath, "%s\\%08x", IMM32_szRegKL, (unsigned)hkl );
37         return RegOpenKeyExA( HKEY_LOCAL_MACHINE, szRegPath,
38                               0, KEY_READ, phkRet );
39 }
40
41 static LONG IMM32_RegCreateKey( HKL hkl, PHKEY phkRet,
42                                 LPDWORD lpdwDisposition )
43 {
44         CHAR    szRegPath[ sizeof(IMM32_szRegKL)+16 ];
45
46         wsprintfA( szRegPath, "%s\\%08x", IMM32_szRegKL, (unsigned)hkl );
47         return RegCreateKeyExA( HKEY_LOCAL_MACHINE, szRegPath,
48                                 0, "REG_SZ",
49                                 REG_OPTION_NON_VOLATILE,
50                                 KEY_ALL_ACCESS, NULL,
51                                 phkRet, lpdwDisposition );
52 }
53
54 static DWORD IMM32_GetIMEFileName( HKL hkl, LPSTR lpBuf, INT nBufLen )
55 {
56         HKEY    hkey;
57         LONG    nError;
58         DWORD   dwType;
59         DWORD   cbData;
60         CHAR    szValueName[ sizeof(IMM32_szIME_File) ];
61
62         TRACE( "hkl = %08x\n", (unsigned)hkl );
63
64         nError = IMM32_RegOpenKey( hkl, &hkey );
65         if ( nError != ERROR_SUCCESS )
66         {
67                 SetLastError( nError );
68                 return 0;
69         }
70         memcpy( szValueName, IMM32_szIME_File, sizeof(IMM32_szIME_File) );
71
72         nError = RegQueryValueExA( hkey, szValueName, NULL,
73                                    &dwType, NULL, &cbData );
74         if ( nError == ERROR_SUCCESS && dwType != REG_SZ )
75                 nError = ERROR_FILE_NOT_FOUND; /* FIXME? */
76         if ( nError == ERROR_SUCCESS && lpBuf != NULL && nBufLen != 0 )
77         {
78                 if ( nBufLen < (INT)cbData )
79                         nError = ERROR_INSUFFICIENT_BUFFER;
80                 else
81                         nError = RegQueryValueExA( hkey, szValueName, NULL,
82                                                    &dwType, lpBuf, &cbData );
83         }
84
85         RegCloseKey( hkey );
86
87         if ( nError != ERROR_SUCCESS )
88         {
89                 SetLastError( nError );
90                 return 0;
91         }
92
93         return cbData;
94 }
95
96
97 static
98 BOOL IMM32_GetIMEHandlersA( HINSTANCE hInstIME,
99                             struct IMM32_IME_EXPORTED_HANDLERS* phandlers )
100 {
101         BOOL    fError;
102
103         #define FE(name)                                                \
104                 phandlers->p##name = (IMM32_p##name)                    \
105                         GetProcAddress(hInstIME,#name);                 \
106                 if ( phandlers->p##name == NULL ) fError = TRUE;
107         #define FE_(name)                                               \
108                 phandlers->p##name.A = (IMM32_p##name##A)               \
109                         GetProcAddress(hInstIME,#name);                 \
110                 if ( phandlers->p##name.A == NULL ) fError = TRUE;
111
112         fError = FALSE;
113
114         FE_(ImeInquire)
115         FE_(ImeConfigure)
116         FE_(ImeConversionList)
117         FE(ImeDestroy)
118         FE_(ImeEnumRegisterWord)
119         FE_(ImeGetRegisterWordStyle)
120         FE_(ImeEscape)
121         FE(ImeProcessKey)
122         FE_(ImeRegisterWord)
123         FE(ImeSelect)
124         FE(ImeSetActiveContext)
125         FE_(ImeSetCompositionString)
126         FE(ImeToAsciiEx)
127         FE_(ImeUnregisterWord)
128         FE(NotifyIME)
129
130         if ( fError )
131                 return FALSE;
132
133         FE_(ImeGetImeMenuItems)
134
135         #undef  FE
136         #undef  FE_
137
138         return TRUE;
139 }
140
141 static
142 BOOL IMM32_GetIMEHandlersW( HINSTANCE hInstIME,
143                             struct IMM32_IME_EXPORTED_HANDLERS* phandlers )
144 {
145         BOOL    fError;
146
147         #define FE(name)                                                \
148                 phandlers->p##name = (IMM32_p##name)                    \
149                         GetProcAddress(hInstIME,#name);                 \
150                 if ( phandlers->p##name == NULL ) fError = TRUE;
151         #define FE_(name)                                               \
152                 phandlers->p##name.W = (IMM32_p##name##W)               \
153                         GetProcAddress(hInstIME,#name);                 \
154                 if ( phandlers->p##name.W == NULL ) fError = TRUE;
155
156         fError = FALSE;
157
158         FE_(ImeInquire)
159         FE_(ImeConfigure)
160         FE_(ImeConversionList)
161         FE(ImeDestroy)
162         FE_(ImeEnumRegisterWord)
163         FE_(ImeGetRegisterWordStyle)
164         FE_(ImeEscape)
165         FE(ImeProcessKey)
166         FE_(ImeRegisterWord)
167         FE(ImeSelect)
168         FE(ImeSetActiveContext)
169         FE_(ImeSetCompositionString)
170         FE(ImeToAsciiEx)
171         FE_(ImeUnregisterWord)
172         FE(NotifyIME)
173
174         if ( fError )
175                 return FALSE;
176
177         FE_(ImeGetImeMenuItems)
178
179         #undef  FE
180         #undef  FE_
181
182         return TRUE;
183 }
184
185
186 static IMM32_IMEKL* IMM32_LoadIME( HKL hkl )
187 {
188         IMM32_IMEKL*    pkl = NULL;
189         BOOL    fInitialized = FALSE;
190         CHAR*   pszFileName = NULL;
191         DWORD   dwBufLen;
192         IMM32_pImeInquireA      pImeInquire;
193         IMM32_pImeDestroy       pImeDestroy = NULL;
194         CHAR    szUIClassName[ (IMM32_UICLASSNAME_MAX+1)*sizeof(WCHAR) ];
195
196         dwBufLen = IMM32_GetIMEFileName( hkl, NULL, 0 );
197         if ( dwBufLen == 0 )
198                 goto err;
199         pszFileName = (CHAR*)IMM32_HeapAlloc( 0, sizeof(CHAR)*(dwBufLen+1) );
200         if ( pszFileName == NULL )
201         {
202                 SetLastError( ERROR_OUTOFMEMORY );
203                 goto err;
204         }
205         if ( !IMM32_GetIMEFileName( hkl, pszFileName, dwBufLen + 1 ) )
206                 goto err;
207
208         pkl = (IMM32_IMEKL*)
209                 IMM32_HeapAlloc( HEAP_ZERO_MEMORY, sizeof(IMM32_IMEKL) );
210         if ( pkl == NULL )
211         {
212                 SetLastError( ERROR_OUTOFMEMORY );
213                 goto err;
214         }
215
216         pkl->pNext = NULL;
217         pkl->hkl = hkl;
218         pkl->hInstIME = LoadLibraryA( pszFileName );
219         if ( pkl->hInstIME == (HINSTANCE)NULL )
220                 goto err;
221
222         pImeInquire = (IMM32_pImeInquireA)GetProcAddress
223                                         ( pkl->hInstIME, "ImeInquire" );
224         pImeDestroy = (IMM32_pImeDestroy)GetProcAddress
225                                         ( pkl->hInstIME, "ImeDestroy" );
226         if ( pImeInquire == NULL || pImeDestroy == NULL )
227                 goto err;
228
229         if ( !pImeInquire( &(pkl->imeinfo), szUIClassName, NULL ) )
230         {
231                 SetLastError( ERROR_DLL_INIT_FAILED ); /* FIXME? */
232                 goto err;
233         }
234         fInitialized = TRUE;
235
236         /* FIXME: Is this correct??? */
237         if ( pkl->imeinfo.fdwProperty & IME_PROP_UNICODE )
238                 pkl->fUnicode = TRUE;
239         else
240                 pkl->fUnicode = FALSE;
241
242         if ( pkl->fUnicode )
243         {
244                 if ( !IMM32_GetIMEHandlersW( pkl->hInstIME, &pkl->handlers ) )
245                         goto err;
246                 memcpy( pkl->UIClassName.W, szUIClassName,
247                         IMM32_UICLASSNAME_MAX*sizeof(WCHAR) );
248                 TRACE( "UI class name(Unicode): %s\n",
249                         debugstr_w(pkl->UIClassName.W) );
250         }
251         else
252         {
253                 if ( !IMM32_GetIMEHandlersA( pkl->hInstIME, &pkl->handlers ) )
254                         goto err;
255                 memcpy( pkl->UIClassName.A, szUIClassName,
256                         IMM32_UICLASSNAME_MAX*sizeof(CHAR) );
257                 TRACE( "UI class name(ASCII): %s\n",
258                         debugstr_a(pkl->UIClassName.A) );
259         }
260
261         /* The IME is loaded successfully. */
262         pkl->pszIMEFileName = pszFileName; pszFileName = NULL;
263         return pkl;
264
265 err:
266         IMM32_HeapFree( pszFileName );
267         if ( pkl != NULL )
268         {
269                 if ( pkl->hInstIME != (HINSTANCE)NULL )
270                 {
271                         if ( fInitialized )
272                                 (void)pImeDestroy(0);
273                         FreeLibrary( pkl->hInstIME );
274                 }
275                 IMM32_HeapFree( pkl );
276         }
277
278         return NULL;
279 }
280
281
282 const IMM32_IMEKL* IMM32_GetIME( HKL hkl )
283 {
284         IMM32_IMEKL*    pkl;
285
286         IMM32_Lock();
287
288         pkl = IMM32_pklFirst;
289         while ( pkl != NULL )
290         {
291                 if ( pkl->hkl == hkl )
292                         goto end;
293                 pkl = pkl->pNext;
294         }
295
296         pkl = IMM32_LoadIME( hkl );
297         if ( pkl != NULL )
298         {
299                 pkl->pNext = IMM32_pklFirst;
300                 IMM32_pklFirst = pkl;
301         }
302
303 end:
304         IMM32_Unlock();
305
306         return pkl;
307 }
308
309 void IMM32_UnloadAllIMEs( void )
310 {
311         IMM32_IMEKL*    pkl;
312         IMM32_IMEKL*    pklNext;
313
314         IMM32_Lock();
315
316         pkl = IMM32_pklFirst;
317         while ( pkl != NULL )
318         {
319                 TRACE( "hkl = %08x\n", (unsigned)pkl->hkl );
320
321                 pklNext = pkl->pNext;
322                 (void)pkl->handlers.pImeDestroy(0);
323                 FreeLibrary( pkl->hInstIME );
324                 IMM32_HeapFree( pkl->pszIMEFileName );
325                 IMM32_HeapFree( pkl );
326                 pkl = pklNext;
327         }
328         IMM32_pklFirst = NULL;
329
330         IMM32_Unlock();
331 }
332
333
334
335 /***********************************************************************
336  *              ImmInstallIMEA (IMM32.@)
337  */
338 HKL WINAPI ImmInstallIMEA(
339         LPCSTR lpszIMEFileName, LPCSTR lpszLayoutText)
340 {
341         HKL     hkl;
342         DWORD   dwLCID;
343         DWORD   dwTryCount;
344         LONG    nError;
345         HKEY    hkey;
346         DWORD   dwDisposition;
347         DWORD   cbData;
348         CHAR    szValueName[ sizeof(IMM32_szIME_File) ];
349
350         TRACE("(%s, %s)\n",
351                 debugstr_a(lpszIMEFileName), debugstr_a(lpszLayoutText) );
352
353         dwLCID = (DWORD)GetThreadLocale();
354         dwTryCount = 0;
355
356         FIXME( "IMEs don't work correctly now since\n"
357                "wine/windows/input.c doesn't handle HKL correctly.\n" );
358
359         while ( 1 )
360         {
361                 hkl = (HKL)(((0xe000|dwTryCount)<<16) | (dwLCID));
362
363                 nError = IMM32_RegCreateKey( hkl, &hkey, &dwDisposition );
364                 if ( nError != ERROR_SUCCESS )
365                         break;
366
367                 memcpy( szValueName, IMM32_szIME_File,
368                         sizeof(IMM32_szIME_File) );
369
370                 nError = RegQueryValueExA( hkey, szValueName, NULL,
371                                            NULL, NULL, &cbData );
372                 if ( nError == ERROR_SUCCESS && cbData > 0 )
373                 {
374                         RegCloseKey( hkey );
375
376                         /* try to assign an other HKL. */
377                         dwTryCount ++;
378                         if ( dwTryCount >= 0x100 )
379                         {
380                                 nError = ERROR_ACCESS_DENIED; /* FIXME */
381                                 break;
382                         }
383                         continue;
384                 }
385
386                 nError = RegSetValueExA( hkey, IMM32_szIME_File, 0,
387                                          REG_SZ, lpszIMEFileName,
388                                          strlen(lpszIMEFileName)+1 );
389                 if ( nError == ERROR_SUCCESS )
390                         nError = RegSetValueExA( hkey, IMM32_szLayout_File, 0,
391                                                  REG_SZ, lpszLayoutText,
392                                                  strlen(lpszLayoutText)+1 );
393                 RegCloseKey( hkey );
394                 break;
395         }
396
397         if ( nError != ERROR_SUCCESS )
398         {
399                 SetLastError( nError );
400                 return (HKL)NULL;
401         }
402
403         return hkl;
404 }
405
406 /***********************************************************************
407  *              ImmInstallIMEW (IMM32.@)
408  */
409 HKL WINAPI ImmInstallIMEW(
410         LPCWSTR lpszIMEFileName, LPCWSTR lpszLayoutText)
411 {
412         LPSTR   lpszParam1;
413         LPSTR   lpszParam2;
414         HKL     hkl;
415
416         TRACE("(%s, %s)\n",
417                 debugstr_w(lpszIMEFileName), debugstr_w(lpszLayoutText) );
418
419         lpszParam1 = IMM32_strdupWtoA( lpszIMEFileName );
420         lpszParam2 = IMM32_strdupWtoA( lpszLayoutText );
421         if ( ( lpszParam1 == NULL ) || ( lpszParam2 == NULL ) )
422         {
423                 SetLastError( ERROR_OUTOFMEMORY );
424                 hkl = (HKL)NULL;
425         }
426         else
427         {
428                 hkl = ImmInstallIMEA( lpszParam1, lpszParam2 );
429         }
430         IMM32_HeapFree( lpszParam1 );
431         IMM32_HeapFree( lpszParam2 );
432
433         return hkl;
434 }
435
436
437 /***********************************************************************
438  *              ImmIsIME (IMM32.@)
439  */
440 BOOL WINAPI ImmIsIME(HKL hkl)
441 {
442         const IMM32_IMEKL*      pkl;
443
444         TRACE("(0x%08x)\n", hkl);
445
446         pkl = IMM32_GetIME( hkl );
447         if ( pkl == NULL )
448                 return FALSE;
449
450         return TRUE;
451 }
452
453
454 /***********************************************************************
455  *              ImmGetIMEFileNameA (IMM32.@)
456  */
457 UINT WINAPI ImmGetIMEFileNameA(HKL hkl, LPSTR lpszFileName, UINT uBufLen)
458 {
459         const IMM32_IMEKL*      pkl;
460         UINT                    uIMEFileNameLen;
461
462         TRACE("(%08x,%p,%u)\n",hkl,lpszFileName,uBufLen);
463
464         pkl = IMM32_GetIME( hkl );
465         if ( pkl == NULL )
466                 return 0;
467
468         uIMEFileNameLen = strlen(pkl->pszIMEFileName);
469         if ( uBufLen == 0 )
470                 return uIMEFileNameLen;
471         if ( uBufLen <= uIMEFileNameLen )
472         {
473                 SetLastError(ERROR_INSUFFICIENT_BUFFER);
474                 return 0;
475         }
476         memcpy( lpszFileName, pkl->pszIMEFileName,
477                 sizeof(CHAR)*(uIMEFileNameLen+1) );
478
479         return uIMEFileNameLen;
480 }
481
482 /***********************************************************************
483  *              ImmGetIMEFileNameW (IMM32.@)
484  */
485 UINT WINAPI ImmGetIMEFileNameW(HKL hkl, LPWSTR lpszFileName, UINT uBufLen)
486 {
487         const IMM32_IMEKL*      pkl;
488         UINT                    uIMEFileNameLen;
489
490         TRACE("(%08x,%p,%u)\n",hkl,lpszFileName,uBufLen);
491
492         pkl = IMM32_GetIME( hkl );
493         if ( pkl == NULL )
494                 return 0;
495
496         uIMEFileNameLen = IMM32_strlenAtoW(pkl->pszIMEFileName);
497         if ( uBufLen == 0 )
498                 return uIMEFileNameLen;
499         if ( uBufLen <= uIMEFileNameLen )
500         {
501                 SetLastError(ERROR_INSUFFICIENT_BUFFER);
502                 return 0;
503         }
504         IMM32_strncpyAtoW( lpszFileName, pkl->pszIMEFileName, uBufLen );
505
506         return uIMEFileNameLen;
507 }
508
509 /***********************************************************************
510  *              ImmGetProperty (IMM32.@)
511  */
512 DWORD WINAPI ImmGetProperty(HKL hkl, DWORD fdwIndex)
513 {
514         const IMM32_IMEKL*      pkl;
515         DWORD                   dwRet;
516
517         TRACE("(0x%08x, %ld)\n", hkl, fdwIndex);
518
519         pkl = IMM32_GetIME( hkl );
520         if ( pkl == NULL )
521                 return 0;
522
523         switch ( fdwIndex )
524         {
525         case IGP_GETIMEVERSION:
526                 dwRet = IMEVER_0400;
527                 break;
528         case IGP_PROPERTY:
529                 dwRet = pkl->imeinfo.fdwProperty;
530                 break;
531         case IGP_CONVERSION:
532                 dwRet = pkl->imeinfo.fdwConversionCaps;
533                 break;
534         case IGP_SENTENCE:
535                 dwRet = pkl->imeinfo.fdwSentenceCaps;
536                 break;
537         case IGP_UI:
538                 dwRet = pkl->imeinfo.fdwUICaps;
539                 break;
540         case IGP_SETCOMPSTR:
541                 dwRet = pkl->imeinfo.fdwSCSCaps;
542                 break;
543         case IGP_SELECT:
544                 dwRet = pkl->imeinfo.fdwSelectCaps;
545                 break;
546         default:
547                 FIXME("(0x%08x, %ld): invalid/unknown property.\n",
548                       hkl, fdwIndex);
549                 SetLastError( ERROR_INVALID_PARAMETER );
550                 dwRet = 0;
551         }
552
553         return dwRet;
554 }
555
556
557 /***********************************************************************
558  *              ImmEnumRegisterWordA (IMM32.@)
559  */
560 UINT WINAPI ImmEnumRegisterWordA(
561         HKL hkl, REGISTERWORDENUMPROCA lpfnEnumProc,
562         LPCSTR lpszReading, DWORD dwStyle,
563         LPCSTR lpszRegister, LPVOID lpData)
564 {
565         const IMM32_IMEKL*      pkl;
566
567         TRACE("(0x%08x, %p, %s, %ld, %s, %p)\n",
568                 hkl, lpfnEnumProc, 
569                 debugstr_a(lpszReading), dwStyle,
570                 debugstr_a(lpszRegister), lpData);
571
572         pkl = IMM32_GetIME( hkl );
573         if ( pkl == NULL )
574                 return 0;
575
576         if ( pkl->fUnicode )
577         {
578                 FIXME( "please implement UNICODE->ANSI\n" );
579                 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
580                 return 0;
581         }
582         else
583         {
584                 return pkl->handlers.pImeEnumRegisterWord.A
585                         ( lpfnEnumProc, lpszReading, dwStyle,
586                           lpszRegister, lpData );
587         }
588 }
589
590 /***********************************************************************
591  *              ImmEnumRegisterWordW (IMM32.@)
592  */
593 UINT WINAPI ImmEnumRegisterWordW(
594         HKL hkl, REGISTERWORDENUMPROCW lpfnEnumProc,
595         LPCWSTR lpszReading, DWORD dwStyle,
596         LPCWSTR lpszRegister, LPVOID lpData)
597 {
598         const IMM32_IMEKL*      pkl;
599
600         TRACE("(0x%08x, %p, %s, %ld, %s, %p): stub\n",
601                 hkl, lpfnEnumProc, 
602                 debugstr_w(lpszReading), dwStyle,
603                 debugstr_w(lpszRegister), lpData);
604
605         pkl = IMM32_GetIME( hkl );
606         if ( pkl == NULL )
607                 return 0;
608
609         if ( pkl->fUnicode )
610         {
611                 return pkl->handlers.pImeEnumRegisterWord.W
612                         ( lpfnEnumProc, lpszReading, dwStyle,
613                           lpszRegister, lpData );
614         }
615         else
616         {
617                 FIXME( "please implement ANSI->UNICODE\n" );
618                 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
619                 return 0;
620         }
621 }
622
623
624 /***********************************************************************
625  *              ImmGetRegisterWordStyleA (IMM32.@)
626  */
627 UINT WINAPI ImmGetRegisterWordStyleA(
628         HKL hkl, UINT nItem, LPSTYLEBUFA lpStyleBuf)
629 {
630         const IMM32_IMEKL*      pkl;
631
632         TRACE("(0x%08x, %d, %p)\n", hkl, nItem, lpStyleBuf);
633
634         pkl = IMM32_GetIME( hkl );
635         if ( pkl == NULL )
636                 return 0;
637
638         if ( pkl->fUnicode )
639         {
640                 FIXME( "please implement UNICODE->ANSI\n" );
641                 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
642                 return 0;
643         }
644         else
645         {
646                 return pkl->handlers.pImeGetRegisterWordStyle.A
647                         ( nItem, lpStyleBuf );
648         }
649 }
650
651 /***********************************************************************
652  *              ImmGetRegisterWordStyleW (IMM32.@)
653  */
654 UINT WINAPI ImmGetRegisterWordStyleW(
655         HKL hkl, UINT nItem, LPSTYLEBUFW lpStyleBuf)
656 {
657         const IMM32_IMEKL*      pkl;
658
659         TRACE("(0x%08x, %d, %p)\n", hkl, nItem, lpStyleBuf);
660
661         pkl = IMM32_GetIME( hkl );
662         if ( pkl == NULL )
663                 return 0;
664
665         if ( pkl->fUnicode )
666         {
667                 return pkl->handlers.pImeGetRegisterWordStyle.W
668                         ( nItem, lpStyleBuf );
669         }
670         else
671         {
672                 FIXME( "please implement ANSI->UNICODE\n" );
673                 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
674                 return 0;
675         }
676 }
677
678