| /* |
| * 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; |
| } |