wine/dlls/imm32/imekl.c
Alexandre Julliard 0799c1a780 Added LGPL standard comment, and copyright notices where necessary.
Global replacement of debugtools.h by wine/debug.h.
2002-03-09 23:29:33 +00:00

693 lines
15 KiB
C

/*
* IME Keyboard Layout
*
* Copyright 2000 Hidenori Takeshima
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <string.h>
#include "winbase.h"
#include "windef.h"
#include "wingdi.h"
#include "winuser.h"
#include "winerror.h"
#include "winnls.h"
#include "winreg.h"
#include "immddk.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(imm);
#include "imm_private.h"
static const char IMM32_szRegKL[] =
"System\\CurrentControlSet\\Control\\keyboard layouts";
static const char IMM32_szIME_File[] = "IME file";
static const char IMM32_szLayout_File[] = "layout file";
static IMM32_IMEKL* IMM32_pklFirst = NULL;
static LONG IMM32_RegOpenKey( HKL hkl, PHKEY phkRet )
{
CHAR szRegPath[ sizeof(IMM32_szRegKL)+16 ];
wsprintfA( szRegPath, "%s\\%08x", IMM32_szRegKL, (unsigned)hkl );
return RegOpenKeyExA( HKEY_LOCAL_MACHINE, szRegPath,
0, KEY_READ, phkRet );
}
static LONG IMM32_RegCreateKey( HKL hkl, PHKEY phkRet,
LPDWORD lpdwDisposition )
{
CHAR szRegPath[ sizeof(IMM32_szRegKL)+16 ];
wsprintfA( szRegPath, "%s\\%08x", IMM32_szRegKL, (unsigned)hkl );
return RegCreateKeyExA( HKEY_LOCAL_MACHINE, szRegPath,
0, "REG_SZ",
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS, NULL,
phkRet, lpdwDisposition );
}
static DWORD IMM32_GetIMEFileName( HKL hkl, LPSTR lpBuf, INT nBufLen )
{
HKEY hkey;
LONG nError;
DWORD dwType;
DWORD cbData;
CHAR szValueName[ sizeof(IMM32_szIME_File) ];
TRACE( "hkl = %08x\n", (unsigned)hkl );
nError = IMM32_RegOpenKey( hkl, &hkey );
if ( nError != ERROR_SUCCESS )
{
SetLastError( nError );
return 0;
}
memcpy( szValueName, IMM32_szIME_File, sizeof(IMM32_szIME_File) );
nError = RegQueryValueExA( hkey, szValueName, NULL,
&dwType, NULL, &cbData );
if ( nError == ERROR_SUCCESS && dwType != REG_SZ )
nError = ERROR_FILE_NOT_FOUND; /* FIXME? */
if ( nError == ERROR_SUCCESS && lpBuf != NULL && nBufLen != 0 )
{
if ( nBufLen < (INT)cbData )
nError = ERROR_INSUFFICIENT_BUFFER;
else
nError = RegQueryValueExA( hkey, szValueName, NULL,
&dwType, lpBuf, &cbData );
}
RegCloseKey( hkey );
if ( nError != ERROR_SUCCESS )
{
SetLastError( nError );
return 0;
}
return cbData;
}
static
BOOL IMM32_GetIMEHandlersA( HINSTANCE hInstIME,
struct IMM32_IME_EXPORTED_HANDLERS* phandlers )
{
BOOL fError;
#define FE(name) \
phandlers->p##name = (IMM32_p##name) \
GetProcAddress(hInstIME,#name); \
if ( phandlers->p##name == NULL ) fError = TRUE;
#define FE_(name) \
phandlers->p##name.A = (IMM32_p##name##A) \
GetProcAddress(hInstIME,#name); \
if ( phandlers->p##name.A == NULL ) fError = TRUE;
fError = FALSE;
FE_(ImeInquire)
FE_(ImeConfigure)
FE_(ImeConversionList)
FE(ImeDestroy)
FE_(ImeEnumRegisterWord)
FE_(ImeGetRegisterWordStyle)
FE_(ImeEscape)
FE(ImeProcessKey)
FE_(ImeRegisterWord)
FE(ImeSelect)
FE(ImeSetActiveContext)
FE_(ImeSetCompositionString)
FE(ImeToAsciiEx)
FE_(ImeUnregisterWord)
FE(NotifyIME)
if ( fError )
return FALSE;
FE_(ImeGetImeMenuItems)
#undef FE
#undef FE_
return TRUE;
}
static
BOOL IMM32_GetIMEHandlersW( HINSTANCE hInstIME,
struct IMM32_IME_EXPORTED_HANDLERS* phandlers )
{
BOOL fError;
#define FE(name) \
phandlers->p##name = (IMM32_p##name) \
GetProcAddress(hInstIME,#name); \
if ( phandlers->p##name == NULL ) fError = TRUE;
#define FE_(name) \
phandlers->p##name.W = (IMM32_p##name##W) \
GetProcAddress(hInstIME,#name); \
if ( phandlers->p##name.W == NULL ) fError = TRUE;
fError = FALSE;
FE_(ImeInquire)
FE_(ImeConfigure)
FE_(ImeConversionList)
FE(ImeDestroy)
FE_(ImeEnumRegisterWord)
FE_(ImeGetRegisterWordStyle)
FE_(ImeEscape)
FE(ImeProcessKey)
FE_(ImeRegisterWord)
FE(ImeSelect)
FE(ImeSetActiveContext)
FE_(ImeSetCompositionString)
FE(ImeToAsciiEx)
FE_(ImeUnregisterWord)
FE(NotifyIME)
if ( fError )
return FALSE;
FE_(ImeGetImeMenuItems)
#undef FE
#undef FE_
return TRUE;
}
static IMM32_IMEKL* IMM32_LoadIME( HKL hkl )
{
IMM32_IMEKL* pkl = NULL;
BOOL fInitialized = FALSE;
CHAR* pszFileName = NULL;
DWORD dwBufLen;
IMM32_pImeInquireA pImeInquire;
IMM32_pImeDestroy pImeDestroy = NULL;
CHAR szUIClassName[ (IMM32_UICLASSNAME_MAX+1)*sizeof(WCHAR) ];
dwBufLen = IMM32_GetIMEFileName( hkl, NULL, 0 );
if ( dwBufLen == 0 )
goto err;
pszFileName = (CHAR*)IMM32_HeapAlloc( 0, sizeof(CHAR)*(dwBufLen+1) );
if ( pszFileName == NULL )
{
SetLastError( ERROR_OUTOFMEMORY );
goto err;
}
if ( !IMM32_GetIMEFileName( hkl, pszFileName, dwBufLen + 1 ) )
goto err;
pkl = (IMM32_IMEKL*)
IMM32_HeapAlloc( HEAP_ZERO_MEMORY, sizeof(IMM32_IMEKL) );
if ( pkl == NULL )
{
SetLastError( ERROR_OUTOFMEMORY );
goto err;
}
pkl->pNext = NULL;
pkl->hkl = hkl;
pkl->hInstIME = LoadLibraryA( pszFileName );
if ( pkl->hInstIME == (HINSTANCE)NULL )
goto err;
pImeInquire = (IMM32_pImeInquireA)GetProcAddress
( pkl->hInstIME, "ImeInquire" );
pImeDestroy = (IMM32_pImeDestroy)GetProcAddress
( pkl->hInstIME, "ImeDestroy" );
if ( pImeInquire == NULL || pImeDestroy == NULL )
goto err;
if ( !pImeInquire( &(pkl->imeinfo), szUIClassName, NULL ) )
{
SetLastError( ERROR_DLL_INIT_FAILED ); /* FIXME? */
goto err;
}
fInitialized = TRUE;
/* FIXME: Is this correct??? */
if ( pkl->imeinfo.fdwProperty & IME_PROP_UNICODE )
pkl->fUnicode = TRUE;
else
pkl->fUnicode = FALSE;
if ( pkl->fUnicode )
{
if ( !IMM32_GetIMEHandlersW( pkl->hInstIME, &pkl->handlers ) )
goto err;
memcpy( pkl->UIClassName.W, szUIClassName,
IMM32_UICLASSNAME_MAX*sizeof(WCHAR) );
TRACE( "UI class name(Unicode): %s\n",
debugstr_w(pkl->UIClassName.W) );
}
else
{
if ( !IMM32_GetIMEHandlersA( pkl->hInstIME, &pkl->handlers ) )
goto err;
memcpy( pkl->UIClassName.A, szUIClassName,
IMM32_UICLASSNAME_MAX*sizeof(CHAR) );
TRACE( "UI class name(ASCII): %s\n",
debugstr_a(pkl->UIClassName.A) );
}
/* The IME is loaded successfully. */
pkl->pszIMEFileName = pszFileName; pszFileName = NULL;
return pkl;
err:
IMM32_HeapFree( pszFileName );
if ( pkl != NULL )
{
if ( pkl->hInstIME != (HINSTANCE)NULL )
{
if ( fInitialized )
(void)pImeDestroy(0);
FreeLibrary( pkl->hInstIME );
}
IMM32_HeapFree( pkl );
}
return NULL;
}
const IMM32_IMEKL* IMM32_GetIME( HKL hkl )
{
IMM32_IMEKL* pkl;
IMM32_Lock();
pkl = IMM32_pklFirst;
while ( pkl != NULL )
{
if ( pkl->hkl == hkl )
goto end;
pkl = pkl->pNext;
}
pkl = IMM32_LoadIME( hkl );
if ( pkl != NULL )
{
pkl->pNext = IMM32_pklFirst;
IMM32_pklFirst = pkl;
}
end:
IMM32_Unlock();
return pkl;
}
void IMM32_UnloadAllIMEs( void )
{
IMM32_IMEKL* pkl;
IMM32_IMEKL* pklNext;
IMM32_Lock();
pkl = IMM32_pklFirst;
while ( pkl != NULL )
{
TRACE( "hkl = %08x\n", (unsigned)pkl->hkl );
pklNext = pkl->pNext;
(void)pkl->handlers.pImeDestroy(0);
FreeLibrary( pkl->hInstIME );
IMM32_HeapFree( pkl->pszIMEFileName );
IMM32_HeapFree( pkl );
pkl = pklNext;
}
IMM32_pklFirst = NULL;
IMM32_Unlock();
}
/***********************************************************************
* ImmInstallIMEA (IMM32.@)
*/
HKL WINAPI ImmInstallIMEA(
LPCSTR lpszIMEFileName, LPCSTR lpszLayoutText)
{
HKL hkl;
DWORD dwLCID;
DWORD dwTryCount;
LONG nError;
HKEY hkey;
DWORD dwDisposition;
DWORD cbData;
CHAR szValueName[ sizeof(IMM32_szIME_File) ];
TRACE("(%s, %s)\n",
debugstr_a(lpszIMEFileName), debugstr_a(lpszLayoutText) );
dwLCID = (DWORD)GetThreadLocale();
dwTryCount = 0;
FIXME( "IMEs don't work correctly now since\n"
"wine/windows/input.c doesn't handle HKL correctly.\n" );
while ( 1 )
{
hkl = (HKL)(((0xe000|dwTryCount)<<16) | (dwLCID));
nError = IMM32_RegCreateKey( hkl, &hkey, &dwDisposition );
if ( nError != ERROR_SUCCESS )
break;
memcpy( szValueName, IMM32_szIME_File,
sizeof(IMM32_szIME_File) );
nError = RegQueryValueExA( hkey, szValueName, NULL,
NULL, NULL, &cbData );
if ( nError == ERROR_SUCCESS && cbData > 0 )
{
RegCloseKey( hkey );
/* try to assign an other HKL. */
dwTryCount ++;
if ( dwTryCount >= 0x100 )
{
nError = ERROR_ACCESS_DENIED; /* FIXME */
break;
}
continue;
}
nError = RegSetValueExA( hkey, IMM32_szIME_File, 0,
REG_SZ, lpszIMEFileName,
strlen(lpszIMEFileName)+1 );
if ( nError == ERROR_SUCCESS )
nError = RegSetValueExA( hkey, IMM32_szLayout_File, 0,
REG_SZ, lpszLayoutText,
strlen(lpszLayoutText)+1 );
RegCloseKey( hkey );
break;
}
if ( nError != ERROR_SUCCESS )
{
SetLastError( nError );
return (HKL)NULL;
}
return hkl;
}
/***********************************************************************
* ImmInstallIMEW (IMM32.@)
*/
HKL WINAPI ImmInstallIMEW(
LPCWSTR lpszIMEFileName, LPCWSTR lpszLayoutText)
{
LPSTR lpszParam1;
LPSTR lpszParam2;
HKL hkl;
TRACE("(%s, %s)\n",
debugstr_w(lpszIMEFileName), debugstr_w(lpszLayoutText) );
lpszParam1 = IMM32_strdupWtoA( lpszIMEFileName );
lpszParam2 = IMM32_strdupWtoA( lpszLayoutText );
if ( ( lpszParam1 == NULL ) || ( lpszParam2 == NULL ) )
{
SetLastError( ERROR_OUTOFMEMORY );
hkl = (HKL)NULL;
}
else
{
hkl = ImmInstallIMEA( lpszParam1, lpszParam2 );
}
IMM32_HeapFree( lpszParam1 );
IMM32_HeapFree( lpszParam2 );
return hkl;
}
/***********************************************************************
* ImmIsIME (IMM32.@)
*/
BOOL WINAPI ImmIsIME(HKL hkl)
{
const IMM32_IMEKL* pkl;
TRACE("(0x%08x)\n", hkl);
pkl = IMM32_GetIME( hkl );
if ( pkl == NULL )
return FALSE;
return TRUE;
}
/***********************************************************************
* ImmGetIMEFileNameA (IMM32.@)
*/
UINT WINAPI ImmGetIMEFileNameA(HKL hkl, LPSTR lpszFileName, UINT uBufLen)
{
const IMM32_IMEKL* pkl;
UINT uIMEFileNameLen;
TRACE("(%08x,%p,%u)\n",hkl,lpszFileName,uBufLen);
pkl = IMM32_GetIME( hkl );
if ( pkl == NULL )
return 0;
uIMEFileNameLen = strlen(pkl->pszIMEFileName);
if ( uBufLen == 0 )
return uIMEFileNameLen;
if ( uBufLen <= uIMEFileNameLen )
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return 0;
}
memcpy( lpszFileName, pkl->pszIMEFileName,
sizeof(CHAR)*(uIMEFileNameLen+1) );
return uIMEFileNameLen;
}
/***********************************************************************
* ImmGetIMEFileNameW (IMM32.@)
*/
UINT WINAPI ImmGetIMEFileNameW(HKL hkl, LPWSTR lpszFileName, UINT uBufLen)
{
const IMM32_IMEKL* pkl;
UINT uIMEFileNameLen;
TRACE("(%08x,%p,%u)\n",hkl,lpszFileName,uBufLen);
pkl = IMM32_GetIME( hkl );
if ( pkl == NULL )
return 0;
uIMEFileNameLen = IMM32_strlenAtoW(pkl->pszIMEFileName);
if ( uBufLen == 0 )
return uIMEFileNameLen;
if ( uBufLen <= uIMEFileNameLen )
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return 0;
}
IMM32_strncpyAtoW( lpszFileName, pkl->pszIMEFileName, uBufLen );
return uIMEFileNameLen;
}
/***********************************************************************
* ImmGetProperty (IMM32.@)
*/
DWORD WINAPI ImmGetProperty(HKL hkl, DWORD fdwIndex)
{
const IMM32_IMEKL* pkl;
DWORD dwRet;
TRACE("(0x%08x, %ld)\n", hkl, fdwIndex);
pkl = IMM32_GetIME( hkl );
if ( pkl == NULL )
return 0;
switch ( fdwIndex )
{
case IGP_GETIMEVERSION:
dwRet = IMEVER_0400;
break;
case IGP_PROPERTY:
dwRet = pkl->imeinfo.fdwProperty;
break;
case IGP_CONVERSION:
dwRet = pkl->imeinfo.fdwConversionCaps;
break;
case IGP_SENTENCE:
dwRet = pkl->imeinfo.fdwSentenceCaps;
break;
case IGP_UI:
dwRet = pkl->imeinfo.fdwUICaps;
break;
case IGP_SETCOMPSTR:
dwRet = pkl->imeinfo.fdwSCSCaps;
break;
case IGP_SELECT:
dwRet = pkl->imeinfo.fdwSelectCaps;
break;
default:
FIXME("(0x%08x, %ld): invalid/unknown property.\n",
hkl, fdwIndex);
SetLastError( ERROR_INVALID_PARAMETER );
dwRet = 0;
}
return dwRet;
}
/***********************************************************************
* ImmEnumRegisterWordA (IMM32.@)
*/
UINT WINAPI ImmEnumRegisterWordA(
HKL hkl, REGISTERWORDENUMPROCA lpfnEnumProc,
LPCSTR lpszReading, DWORD dwStyle,
LPCSTR lpszRegister, LPVOID lpData)
{
const IMM32_IMEKL* pkl;
TRACE("(0x%08x, %p, %s, %ld, %s, %p)\n",
hkl, lpfnEnumProc,
debugstr_a(lpszReading), dwStyle,
debugstr_a(lpszRegister), lpData);
pkl = IMM32_GetIME( hkl );
if ( pkl == NULL )
return 0;
if ( pkl->fUnicode )
{
FIXME( "please implement UNICODE->ANSI\n" );
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return 0;
}
else
{
return pkl->handlers.pImeEnumRegisterWord.A
( lpfnEnumProc, lpszReading, dwStyle,
lpszRegister, lpData );
}
}
/***********************************************************************
* ImmEnumRegisterWordW (IMM32.@)
*/
UINT WINAPI ImmEnumRegisterWordW(
HKL hkl, REGISTERWORDENUMPROCW lpfnEnumProc,
LPCWSTR lpszReading, DWORD dwStyle,
LPCWSTR lpszRegister, LPVOID lpData)
{
const IMM32_IMEKL* pkl;
TRACE("(0x%08x, %p, %s, %ld, %s, %p): stub\n",
hkl, lpfnEnumProc,
debugstr_w(lpszReading), dwStyle,
debugstr_w(lpszRegister), lpData);
pkl = IMM32_GetIME( hkl );
if ( pkl == NULL )
return 0;
if ( pkl->fUnicode )
{
return pkl->handlers.pImeEnumRegisterWord.W
( lpfnEnumProc, lpszReading, dwStyle,
lpszRegister, lpData );
}
else
{
FIXME( "please implement ANSI->UNICODE\n" );
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return 0;
}
}
/***********************************************************************
* ImmGetRegisterWordStyleA (IMM32.@)
*/
UINT WINAPI ImmGetRegisterWordStyleA(
HKL hkl, UINT nItem, LPSTYLEBUFA lpStyleBuf)
{
const IMM32_IMEKL* pkl;
TRACE("(0x%08x, %d, %p)\n", hkl, nItem, lpStyleBuf);
pkl = IMM32_GetIME( hkl );
if ( pkl == NULL )
return 0;
if ( pkl->fUnicode )
{
FIXME( "please implement UNICODE->ANSI\n" );
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return 0;
}
else
{
return pkl->handlers.pImeGetRegisterWordStyle.A
( nItem, lpStyleBuf );
}
}
/***********************************************************************
* ImmGetRegisterWordStyleW (IMM32.@)
*/
UINT WINAPI ImmGetRegisterWordStyleW(
HKL hkl, UINT nItem, LPSTYLEBUFW lpStyleBuf)
{
const IMM32_IMEKL* pkl;
TRACE("(0x%08x, %d, %p)\n", hkl, nItem, lpStyleBuf);
pkl = IMM32_GetIME( hkl );
if ( pkl == NULL )
return 0;
if ( pkl->fUnicode )
{
return pkl->handlers.pImeGetRegisterWordStyle.W
( nItem, lpStyleBuf );
}
else
{
FIXME( "please implement ANSI->UNICODE\n" );
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return 0;
}
}