377 lines
8.6 KiB
C
377 lines
8.6 KiB
C
/*
|
|
* Implementation of the 'IME window' class
|
|
*
|
|
* Copyright 2000 Hidenori Takeshima
|
|
*
|
|
*
|
|
* FIXME:
|
|
* - handle all messages.
|
|
* - handle all notifications.
|
|
*
|
|
* 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 "winbase.h"
|
|
#include "windef.h"
|
|
#include "wingdi.h"
|
|
#include "winuser.h"
|
|
#include "winerror.h"
|
|
#include "immddk.h"
|
|
|
|
#include "wine/debug.h"
|
|
WINE_DEFAULT_DEBUG_CHANNEL(imm);
|
|
|
|
#include "imm_private.h"
|
|
|
|
#define IMM32_CONVERSION_BUFSIZE 200
|
|
|
|
static CHAR IMM32_szIMEClass[] = "IME";
|
|
static CHAR IMM32_szIMEWindowName[] = "Default IME";
|
|
|
|
typedef struct
|
|
{
|
|
HWND hwndSelf;
|
|
HWND hwndActive;
|
|
DWORD dwBufUsed;
|
|
union
|
|
{
|
|
CHAR A[IMM32_CONVERSION_BUFSIZE];
|
|
WCHAR W[IMM32_CONVERSION_BUFSIZE];
|
|
} buf;
|
|
} IMM32_IMEWNDPARAM;
|
|
|
|
|
|
static BOOL IMM32_IsUIMessage( UINT nMsg );
|
|
|
|
static
|
|
LRESULT IMM32_IMEWnd_WM_KEYDOWN( IMM32_IMEWNDPARAM* pParam,
|
|
WPARAM wParam, LPARAM lParam )
|
|
{
|
|
BYTE bKeyState[ 256 ];
|
|
DWORD dwTransBufSize;
|
|
UINT nNumOfMsg;
|
|
LRESULT lr;
|
|
HIMC hIMC;
|
|
IMM32_IMC* pIMC;
|
|
const IMM32_IMEKL* pkl;
|
|
|
|
if ( pParam->hwndActive == (HWND)NULL )
|
|
return 0;
|
|
|
|
/* get context -> get pkl. */
|
|
hIMC = ImmGetContext( pParam->hwndActive );
|
|
if ( hIMC == NULLIMC )
|
|
return 0;
|
|
pIMC = IMM32_LockIMC( hIMC );
|
|
if ( pIMC == NULL )
|
|
{
|
|
ImmReleaseContext( pParam->hwndActive, hIMC );
|
|
return 0;
|
|
}
|
|
pkl = pIMC->pkl;
|
|
|
|
GetKeyboardState( bKeyState );
|
|
if ( !pkl->handlers.pImeProcessKey
|
|
( hIMC, wParam, lParam, bKeyState ) )
|
|
{
|
|
lr = SendMessageA( pParam->hwndActive, WM_IME_KEYDOWN,
|
|
wParam, lParam );
|
|
goto end;
|
|
}
|
|
|
|
dwTransBufSize = 0;
|
|
nNumOfMsg = pkl->handlers.pImeToAsciiEx
|
|
( wParam, (lParam>>16)&0xff,
|
|
bKeyState, &dwTransBufSize,
|
|
0, /* FIXME!!! - 1 if a menu is active */
|
|
hIMC );
|
|
|
|
/* FIXME - process generated messages */
|
|
/* I cannot use ImmGenerateMessage() since
|
|
* the IME window must handle generated messages. */
|
|
|
|
/* NOTE - I must check pkl->fUnicode. */
|
|
FIXME( "%d messages generated.\n", nNumOfMsg );
|
|
|
|
lr = 0;
|
|
end:
|
|
IMM32_UnlockIMC( hIMC );
|
|
ImmReleaseContext( pParam->hwndActive, hIMC );
|
|
|
|
return lr;
|
|
}
|
|
|
|
static
|
|
LRESULT IMM32_IMEWnd_WM_KEYUP( IMM32_IMEWNDPARAM* pParam,
|
|
WPARAM wParam, LPARAM lParam )
|
|
{
|
|
BYTE bKeyState[ 256 ];
|
|
LRESULT lr;
|
|
HIMC hIMC;
|
|
IMM32_IMC* pIMC;
|
|
const IMM32_IMEKL* pkl;
|
|
|
|
if ( pParam->hwndActive == (HWND)NULL )
|
|
return 0;
|
|
|
|
/* get context -> get pkl. */
|
|
hIMC = ImmGetContext( pParam->hwndActive );
|
|
if ( hIMC == NULLIMC )
|
|
return 0;
|
|
pIMC = IMM32_LockIMC( hIMC );
|
|
if ( pIMC == NULL )
|
|
{
|
|
ImmReleaseContext( pParam->hwndActive, hIMC );
|
|
return 0;
|
|
}
|
|
pkl = pIMC->pkl;
|
|
|
|
GetKeyboardState( bKeyState );
|
|
if ( !pkl->handlers.pImeProcessKey
|
|
( hIMC, wParam, lParam, bKeyState ) )
|
|
{
|
|
lr = SendMessageA( pParam->hwndActive, WM_IME_KEYUP,
|
|
wParam, lParam );
|
|
goto end;
|
|
}
|
|
|
|
lr = 0;
|
|
end:
|
|
IMM32_UnlockIMC( hIMC );
|
|
ImmReleaseContext( pParam->hwndActive, hIMC );
|
|
|
|
return lr;
|
|
}
|
|
|
|
|
|
static
|
|
LRESULT CALLBACK IMM32_IMEWndProc( HWND hwnd, UINT nMsg,
|
|
WPARAM wParam, LPARAM lParam )
|
|
{
|
|
IMM32_IMEWNDPARAM* pParam =
|
|
(IMM32_IMEWNDPARAM*)GetWindowLongA( hwnd, 0L );
|
|
|
|
if ( nMsg == WM_CREATE )
|
|
{
|
|
pParam = (IMM32_IMEWNDPARAM*)IMM32_HeapAlloc(
|
|
HEAP_ZERO_MEMORY, sizeof(IMM32_IMEWNDPARAM) );
|
|
if ( pParam == NULL )
|
|
return -1L;
|
|
SetWindowLongA( hwnd, 0L, (LONG)pParam );
|
|
|
|
/* Initialize pParam. */
|
|
pParam->hwndSelf = hwnd;
|
|
pParam->hwndActive = (HWND)NULL;
|
|
pParam->dwBufUsed = 0;
|
|
|
|
return 0;
|
|
}
|
|
else if ( nMsg == WM_DESTROY )
|
|
{
|
|
/* Uninitialize pParam. */
|
|
|
|
IMM32_HeapFree( pParam );
|
|
SetWindowLongA( hwnd, 0L, (LONG)NULL );
|
|
return 0;
|
|
}
|
|
|
|
if ( pParam == NULL )
|
|
{
|
|
if ( IMM32_IsUIMessage( nMsg ) )
|
|
return 0;
|
|
return DefWindowProcA( hwnd, nMsg, wParam, lParam );
|
|
}
|
|
|
|
/* FIXME - handle all messages. */
|
|
/* FIXME - handle all notifications. */
|
|
switch ( nMsg )
|
|
{
|
|
case WM_KEYDOWN:
|
|
return IMM32_IMEWnd_WM_KEYDOWN( pParam, wParam, lParam );
|
|
case WM_KEYUP:
|
|
return IMM32_IMEWnd_WM_KEYUP( pParam, wParam, lParam );
|
|
case WM_IME_KEYDOWN:
|
|
ERR( "Why WM_IME_KEYDOWN is generated?\n" );
|
|
return 0;
|
|
case WM_IME_KEYUP:
|
|
ERR( "Why WM_IME_KEYUP is generated?\n" );
|
|
return 0;
|
|
case WM_IME_CHAR:
|
|
FIXME( "ignore WM_IME_CHAR - wParam %08x, lParam %08lx.\n",
|
|
wParam, lParam );
|
|
return 0;
|
|
case WM_CHAR:
|
|
/* TranslateMessage don't support IME HKL. - FIXME? */
|
|
FIXME( "ignore WM_CHAR - wParam %08x, lParam %08lx.\n",
|
|
wParam, lParam );
|
|
return 0;
|
|
case WM_IME_CONTROL:
|
|
case WM_IME_REQUEST:
|
|
case WM_IME_STARTCOMPOSITION:
|
|
case WM_IME_ENDCOMPOSITION:
|
|
case WM_IME_COMPOSITION:
|
|
case WM_IME_SETCONTEXT:
|
|
case WM_IME_NOTIFY:
|
|
case WM_IME_COMPOSITIONFULL:
|
|
case WM_IME_SELECT:
|
|
case 0x287: /* What is this message? IMM32.DLL returns TRUE. */
|
|
FIXME( "handle message %08x\n", nMsg );
|
|
return 0;
|
|
}
|
|
|
|
return DefWindowProcA( hwnd, nMsg, wParam, lParam );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* IMM32_RegisterClass (internal)
|
|
*/
|
|
BOOL IMM32_RegisterIMEWndClass( HINSTANCE hInstDLL )
|
|
{
|
|
WNDCLASSA wc;
|
|
|
|
/* SDK says the "IME" window class is a system global class. */
|
|
wc.style = CS_GLOBALCLASS;
|
|
wc.lpfnWndProc = IMM32_IMEWndProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = sizeof(LONG);
|
|
wc.hInstance = hInstDLL;
|
|
wc.hIcon = (HICON)NULL;
|
|
wc.hCursor = LoadCursorA((HINSTANCE)NULL,IDC_ARROWA);
|
|
wc.hbrBackground = (HBRUSH)NULL;
|
|
wc.lpszMenuName = NULL;
|
|
wc.lpszClassName = IMM32_szIMEClass;
|
|
if ( !RegisterClassA( &wc ) )
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* IMM32_UnregisterClass (internal)
|
|
*/
|
|
void IMM32_UnregisterIMEWndClass( HINSTANCE hInstDLL )
|
|
{
|
|
(void)UnregisterClassA( IMM32_szIMEClass, hInstDLL );
|
|
}
|
|
|
|
/***********************************************************************
|
|
* IMM32_CreateDefaultIMEWnd (internal)
|
|
*/
|
|
|
|
HWND IMM32_CreateDefaultIMEWnd( void )
|
|
{
|
|
return CreateWindowExA( 0L,
|
|
IMM32_szIMEClass,
|
|
IMM32_szIMEWindowName,
|
|
WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED,
|
|
0, 0, 0, 0,
|
|
(HWND)NULL,
|
|
(HMENU)NULL,
|
|
(HINSTANCE)GetModuleHandleA(NULL),
|
|
NULL );
|
|
}
|
|
|
|
static BOOL IMM32_IsUIMessage( UINT nMsg )
|
|
{
|
|
switch ( nMsg )
|
|
{
|
|
case WM_IME_STARTCOMPOSITION:
|
|
case WM_IME_ENDCOMPOSITION:
|
|
case WM_IME_COMPOSITION:
|
|
case WM_IME_SETCONTEXT:
|
|
case WM_IME_NOTIFY:
|
|
case WM_IME_COMPOSITIONFULL:
|
|
case WM_IME_SELECT:
|
|
case 0x287: /* What is this message? IMM32.DLL returns TRUE. */
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* ImmIsUIMessageA (IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmIsUIMessageA(
|
|
HWND hwndIME, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
TRACE("(0x%08x, %d, %d, %ld)\n",
|
|
hwndIME, msg, wParam, lParam);
|
|
|
|
if ( !IMM32_IsUIMessage( msg ) )
|
|
return FALSE;
|
|
if ( hwndIME == (HWND)NULL )
|
|
return TRUE;
|
|
|
|
switch ( msg )
|
|
{
|
|
case WM_IME_STARTCOMPOSITION:
|
|
case WM_IME_ENDCOMPOSITION:
|
|
case WM_IME_COMPOSITION:
|
|
case WM_IME_SETCONTEXT:
|
|
case WM_IME_NOTIFY:
|
|
case WM_IME_COMPOSITIONFULL:
|
|
case WM_IME_SELECT:
|
|
SendMessageA( hwndIME, msg, wParam, lParam );
|
|
break;
|
|
case 0x287: /* What is this message? */
|
|
FIXME("(0x%08x, %d, %d, %ld) - unknown message 0x287.\n",
|
|
hwndIME, msg, wParam, lParam);
|
|
SendMessageA( hwndIME, msg, wParam, lParam );
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmIsUIMessageW (IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmIsUIMessageW(
|
|
HWND hwndIME, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
TRACE("(0x%08x, %d, %d, %ld)\n",
|
|
hwndIME, msg, wParam, lParam);
|
|
|
|
if ( !IMM32_IsUIMessage( msg ) )
|
|
return FALSE;
|
|
if ( hwndIME == (HWND)NULL )
|
|
return TRUE;
|
|
|
|
switch ( msg )
|
|
{
|
|
case WM_IME_STARTCOMPOSITION:
|
|
case WM_IME_ENDCOMPOSITION:
|
|
case WM_IME_COMPOSITION:
|
|
case WM_IME_SETCONTEXT:
|
|
case WM_IME_NOTIFY:
|
|
case WM_IME_COMPOSITIONFULL:
|
|
case WM_IME_SELECT:
|
|
SendMessageW( hwndIME, msg, wParam, lParam );
|
|
break;
|
|
case 0x287: /* What is this message? */
|
|
FIXME("(0x%08x, %d, %d, %ld) - unknown message 0x287.\n",
|
|
hwndIME, msg, wParam, lParam);
|
|
SendMessageW( hwndIME, msg, wParam, lParam );
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|