📄 im.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Module Name:
im.cpp
--*/
#include <windows.h>
#include <commctrl.h>
#ifndef UNDER_CE
#include "wchar.h"
#endif
#include "resource.h"
#include "dllmain.h"
#include "im.h"
#include "multibox.h"
#include "recog.h"
// Globals.
IIMCallback *g_pIMCallback;
IIMCallbackEx *g_pIMCallbackEx;
// Privates
static int g_nDown;
static HIMAGELIST g_hImagelistWide = NULL;
static HIMAGELIST g_hImagelistNarrow;
static const TCHAR szHwxPadClass[] = TEXT("HWXPad");
static const TCHAR szWPadClass[] = TEXT("WPad");
static BOOL v_bNumLock;
static TCHAR const gpwszRegKey[] = TEXT("CLSID\\{0CBEA010-F68E-11D1-8C63-0060977B4593}");
static TCHAR const gpwszTimeout[] = TEXT("Timeout");
HANDLE g_hFontFix;
extern "C"
{
HWND g_hwndMain;
HWND g_hwndWPad;
HWND g_hwndHelp;
HWXGLOBAL glob;
BOOL gbTimeout;
int gnTimeout;
int giMode;
int giSuji;
HANDLE vhThread;
DWORD v_rThreadID;
HINSTANCE v_hModDll; // DLL Instance
HBITMAP v_hbmCtrl; // Control bitmaps
HDC g_hdcCtrl; // Off screen DC for control bitmaps
BOOL CALLBACK HelpDlgProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp);
}
// Main window procedure.
LRESULT WINAPI
ImWndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_COMMAND:
if (g_hwndHelp)
PostMessage(g_hwndHelp, HELP_WM_COMMAND, wParam, 0);
else
{
// Now do per button processing after syncronizing.
switch (wParam) {
case IDC_RECOG:
SendMessage(g_hwndWPad, PAD_WM_DETERMINE, 0, 0);
break;
case IDC_BACKSP : // Backspace button
SendMessage(g_hwndWPad, PAD_WM_DETERMINE, 0, 0);
PostThreadMessage(v_rThreadID, THRDMSG_CHAR, VK_BACK, 0);
break;
case IDC_ENTER : // Return button
SendMessage(g_hwndWPad, PAD_WM_DETERMINE, 0, 0);
PostThreadMessage(v_rThreadID, THRDMSG_CHAR, VK_RETURN, 0);
break;
case IDC_CONVERT: // convert button
SendMessage(g_hwndWPad, PAD_WM_DETERMINE, 0, 0);
PostThreadMessage(v_rThreadID, THRDMSG_CHAR, VK_CONVERT, 0);
break;
case IDC_SPACE: // space button
SendMessage(g_hwndWPad, PAD_WM_DETERMINE, 0, 0);
PostThreadMessage(v_rThreadID, THRDMSG_CHAR, VK_SPACE, 0);
break;
case IDC_ESCAPE: // escape button
SendMessage(g_hwndWPad, PAD_WM_DETERMINE, 0, 0);
PostThreadMessage(v_rThreadID, THRDMSG_CHAR, VK_ESCAPE, 0);
break;
case IDC_WIDTH: // Half/Full width button
SendMessage(g_hwndWPad, PAD_WM_DETERMINE, 0, 0);
PostThreadMessage(v_rThreadID, THRDMSG_CHAR, VK_KANA, 1 - giMode);
giMode = 1 - giMode;
break;
case IDC_SUJI: // Numeric button
SendMessage(g_hwndWPad, PAD_WM_DETERMINE, 0, 0);
PostThreadMessage(v_rThreadID, THRDMSG_CHAR, VK_NUMLOCK, 1 - giSuji);
giSuji = 1 - giSuji;
break;
case IDC_QUERY:
SendMessage(g_hwndWPad, PAD_WM_DETERMINE, 0, 0);
g_hwndHelp = CreateDialog(g_hInstDll, MAKEINTRESOURCE(IDD_HELP), (HWND) NULL, HelpDlgProc);
PostMessage(g_hwndHelp, HELP_WM_START, 0, 0);
break;
}
}
break;
case HELP_WM_QUIT:
DestroyWindow(g_hwndHelp);
g_hwndHelp = (HWND) NULL;
break;
} // switch( message )
return DefWindowProc( hwnd, msg, wParam, lParam );
}
//
// IInputMethod implementation.
//
//
// Ctor, Dtor.
//
CInputMethod::CInputMethod( IUnknown *pUnkOuter, HINSTANCE hInstance )
{
m_cRef = 0;
g_dwObjectCount++;
if( !pUnkOuter ) {
m_pUnkOuter = this;
} else {
m_pUnkOuter = pUnkOuter;
}
return;
}
CInputMethod::~CInputMethod()
{
g_dwObjectCount--;
return;
}
void ReadRegistry()
{
long retval;
DWORD dwData;
DWORD dwType;
DWORD cbData;
HKEY hKey;
retval = RegCreateKeyEx(HKEY_CLASSES_ROOT, gpwszRegKey, 0, NULL,
REG_OPTION_NON_VOLATILE,
(REGSAM) NULL, NULL, &hKey, &dwData);
cbData = 4;
dwType = REG_DWORD;
if (retval == ERROR_SUCCESS)
{
RegQueryValueEx(hKey,
gpwszTimeout,
0,
&dwType,
(BYTE *) &dwData,
&cbData);
gnTimeout = ((int) dwData) * 1000;
if (gnTimeout <= 0)
{
gbTimeout = FALSE;
gnTimeout = -gnTimeout;
}
else
gbTimeout = TRUE;
RegCloseKey(hKey);
}
}
void WriteRegistry()
{
long retval;
DWORD dwDisp;
HKEY hKey;
DWORD dwData = gbTimeout ? (DWORD) (gnTimeout / 1000) : (DWORD) (-gnTimeout / 1000);
// RETAILMSG(1, (TEXT("Multibox: WriteRegistry writing data 0x%08x\r\n"), dwData));
retval = RegCreateKeyEx(HKEY_CLASSES_ROOT, gpwszRegKey, 0, NULL,
REG_OPTION_NON_VOLATILE,
(REGSAM) NULL, NULL, &hKey, &dwDisp);
if (retval == ERROR_SUCCESS)
{
RegSetValueEx(hKey,
gpwszTimeout,
0,
REG_DWORD,
(CONST BYTE *)&dwData,
sizeof(DWORD));
RegCloseKey(hKey);
}
}
BOOL CALLBACK OptionsDlg(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
BOOL fRetVal = TRUE;
CInputMethod *pIM;
WCHAR awc[10];
WCHAR fwc[10];
switch (msg)
{
case WM_INITDIALOG:
ReadRegistry();
wsprintf(awc, TEXT("%d"), gnTimeout / 1000);
SendDlgItemMessage(hDlg, IDC_TIMEOUT, WM_SETTEXT, 0, (LPARAM) awc);
SendDlgItemMessage(hDlg, IDC_ENABLE, BM_SETCHECK, gbTimeout ? BST_CHECKED : BST_UNCHECKED, 0);
SetWindowLong(hDlg, GWL_USERDATA, lParam);
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
pIM = (CInputMethod *) GetWindowLong(hDlg, GWL_USERDATA);
if (pIM)
{
SendDlgItemMessage(hDlg, IDC_TIMEOUT, WM_GETTEXT, 10, (LPARAM) awc);
FoldString(MAP_FOLDCZONE, awc, -1, fwc, 10);
gnTimeout = wcstol(fwc, NULL, 10) * 1000;
gbTimeout = (BST_CHECKED == SendDlgItemMessage(hDlg, IDC_ENABLE, BM_GETCHECK, 0, 0));
WriteRegistry();
}
case IDCANCEL:
EndDialog(hDlg, TRUE);
fRetVal = TRUE;
break;
default:
break;
}
break;
default:
fRetVal = FALSE;
break;
}
return fRetVal;
}
//
// IInputMethod methods.
//
STDMETHODIMP CInputMethod::Select( HWND hwndSip )
{
static const LOGFONT lf = {
16, // ??? EditHeight - 2
0,
0,
0,
FW_NORMAL,
FALSE,
FALSE,
FALSE,
DEFAULT_CHARSET,
0,
0,
0,
0,
TEXT("Courier New")
};
WNDCLASS wc;
vhThread = CreateThread( NULL, 0, RecogThreadFn, NULL, 0, &v_rThreadID);
// If we return here, the caller should be able to retrieve the error
// by calling GetLastError() and get the error code set by CreateThread.
//
if(!vhThread)
return E_FAIL;
ZeroMemory( &wc, sizeof(wc) );
wc.lpfnWndProc = ImWndProc;
wc.hInstance = g_hInstDll;
wc.hbrBackground = (HBRUSH) GetStockObject(LTGRAY_BRUSH);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszClassName = szHwxPadClass;
RegisterClass( &wc );
wc.lpfnWndProc = WPadWndProc;
wc.lpszClassName = szWPadClass;
RegisterClass( &wc );
// Create the main window.
g_hwndMain = CreateWindow(
szHwxPadClass,
TEXT(""),
WS_CHILD,
0,
0,
DisplayWidth,
DisplayHeight,
hwndSip,
(HMENU)NULL,
g_hInstDll,
NULL
);
// Load the bitmaps for the buttons
v_hbmCtrl = LoadBitmap(g_hInstDll, MAKEINTRESOURCE(IDB_CONTROLS));
if (v_hbmCtrl == (HBITMAP) NULL)
return E_FAIL;
// Create the offscreen DCs, make it compatible with the display
HDC hdc = GetDC(g_hwndMain);
g_hdcCtrl = CreateCompatibleDC(hdc);
ReleaseDC(g_hwndMain, hdc);
if (g_hdcCtrl == (HDC) NULL)
{
// JRB: Should clean up!!
return E_FAIL;
}
// Read the registry for the timeout value
ReadRegistry();
// Select the controls into the offscreen bitmap, and the same for scroll buttons
v_hbmCtrl = (HBITMAP) SelectObject(g_hdcCtrl, v_hbmCtrl);
// Create the window that actually accepts the ink
g_hwndWPad = CreateWindowEx( 0,
szWPadClass,
TEXT(""),
WS_CHILD | WS_VISIBLE,
PadWindX, PadWindY,
PadWindWidth, PadWindHeight,
g_hwndMain,
NULL,
g_hInstDll,
NULL
);
ShowWindow( g_hwndMain, SW_SHOWNOACTIVATE );
// Turn the IME on
if ( !ImmGetOpenStatus(NULL) )
{
DWORD dwConversion, dwSentence;
ImmGetConversionStatus(NULL, &dwConversion, &dwSentence);
if (dwConversion != 0x19)
ImmSetOpenStatus(NULL,TRUE);
}
// Last, but not least, set the ALC for recognition
PostThreadMessage(v_rThreadID, THRDMSG_SETMASK, (WPARAM) ALC_JPN_COMMON, 0);
return NOERROR;
}
STDMETHODIMP CInputMethod::Deselect( void )
{
// Politely ask the other thread to exit.
SendMessage(g_hwndWPad, PAD_WM_ERASE, 0, 0);
PostThreadMessage(v_rThreadID, THRDMSG_EXIT, 0, 0);
// Give the auxillary thread 50ms to terminate before brutally murdering it.
if (WaitForSingleObject(vhThread, 50) == WAIT_TIMEOUT)
if (TerminateThread(vhThread, 0))
CloseHandle(vhThread);
// SendMessage(g_hwndWPad, PAD_WM_CLEAR, 0, 0);
SendMessage(g_hwndMain, HELP_WM_QUIT, 0, 0);
glob.bInked = FALSE;
DestroyWindow( g_hwndMain );
// Should we destroy the other windows???
UnregisterClass( szHwxPadClass, g_hInstDll );
UnregisterClass( szWPadClass, g_hInstDll );
// Release the bitmaps, DCs, and imagelists
ImageList_Destroy( g_hImagelistWide );
ImageList_Destroy( g_hImagelistNarrow );
g_hImagelistWide = NULL;
g_hImagelistNarrow = NULL;
if (g_hdcCtrl != (HDC) NULL)
v_hbmCtrl = (HBITMAP) SelectObject(g_hdcCtrl, v_hbmCtrl);
if (g_hdcCtrl)
DeleteDC(g_hdcCtrl);
if (v_hbmCtrl)
DeleteObject(v_hbmCtrl);
return NOERROR;
}
STDMETHODIMP CInputMethod::Showing( void )
{
if(!glob.pstrk){
glob.bInked = FALSE;
}
return NOERROR;
}
STDMETHODIMP CInputMethod::Hiding( void )
{
SendMessage(g_hwndMain, HELP_WM_QUIT, 0, 0);
return NOERROR;
}
STDMETHODIMP CInputMethod::GetInfo( IMINFO *pimi )
{
HBITMAP hbmp;
if( !g_hImagelistWide )
{
g_hImagelistWide = ImageList_Create(
32,
16,
ILC_COLOR | ILC_MASK,
1,
1 );
g_hImagelistNarrow = ImageList_Create(
16,
16,
ILC_COLOR | ILC_MASK,
1,
1 );
hbmp = LoadBitmap( g_hInstDll, MAKEINTRESOURCE(IDB_WIDE) );
ImageList_AddMasked(
g_hImagelistWide,
hbmp,
RGB(192,192,192) );
DeleteObject(hbmp);
hbmp = LoadBitmap( g_hInstDll, MAKEINTRESOURCE(IDB_NARROW) );
ImageList_AddMasked(
g_hImagelistNarrow,
hbmp,
RGB(192,192,192) );
DeleteObject(hbmp);
}
pimi->fdwFlags = SIPF_DOCKED;
pimi->hImageNarrow = (HANDLE)g_hImagelistNarrow;
pimi->hImageWide = (HANDLE)g_hImagelistWide;
pimi->iNarrow = pimi->iWide = 0;
pimi->rcSipRect.left = pimi->rcSipRect.top = 0;
pimi->rcSipRect.right = DisplayWidth;
pimi->rcSipRect.bottom = DisplayHeight;
return NOERROR;
}
STDMETHODIMP CInputMethod::ReceiveSipInfo( SIPINFO *psi )
{
MoveWindow(
g_hwndMain,
0,
0,
psi->rcSipRect.right - psi->rcSipRect.left,
psi->rcSipRect.bottom - psi->rcSipRect.top,
FALSE );
return NOERROR;
}
STDMETHODIMP CInputMethod::RegisterCallback( IIMCallback *pIMCallback )
{
g_pIMCallback = pIMCallback;
return NOERROR;
}
STDMETHODIMP CInputMethod::GetImData( DWORD dwSize, void *pvImData )
{
return E_NOTIMPL;
}
STDMETHODIMP CInputMethod::SetImData( DWORD dwSize, void *pvImData )
{
return E_NOTIMPL;
}
STDMETHODIMP CInputMethod::UserOptionsDlg( HWND hwndParent )
{
DialogBoxParam(g_hInstDll,
MAKEINTRESOURCE(IDD_OPTIONS),
hwndParent,
OptionsDlg,
(LPARAM) this);
return NOERROR;
}
// IInputMethodEx methods
STDMETHODIMP CInputMethod::RegisterCallbackEx( IIMCallbackEx *pIMCallbackEx )
{
g_pIMCallbackEx = pIMCallbackEx;
return NOERROR;
}
STDMETHODIMP CInputMethod::SetIMMActiveContext(HWND hwnd,BOOL bOpen,DWORD dwConversion,DWORD dwSentence,DWORD hkl)
{
// Not implemented for this IM.
return NOERROR;
}
//
// IUnknown methods.
//
STDMETHODIMP CInputMethod::QueryInterface( REFIID riid, LPVOID FAR* ppobj )
{
if( IID_IUnknown == riid || IID_IInputMethod == riid || IID_IInputMethodEx == riid)
{
*ppobj = this;
AddRef();
return NOERROR;
}
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) CInputMethod::AddRef( void )
{
return ++m_cRef;
}
STDMETHODIMP_(ULONG) CInputMethod::Release( void )
{
if( --m_cRef ) {
return m_cRef;
}
delete this;
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -