📄 winime.cc
字号:
////////////////////////////////////////////////////////////////////////////////////
//platformIME.h 平台输入法,李亦编写.2005.11.18
/// 由于微软拼音实现了很多自己的东西,PlatformIME和它的兼容性有些问题
/// 1、在函数 PlatformIME::ConvertCandList 中所说的选字表的问题
/// 2、函数 PlatformIME::GetIMEInput 返回的 szCompReadStr 显然经过了加工而不是最初的键盘输入
/// 它的每个可组合的输入占以空格补足的8byte,且新的不可组合的输入存为0xa1
/// 我们可以在输入法名字中有子串"微软拼音"时,只显示末尾的一组8byte,如果有0xa1就什么都不显示,也可以直接用TextOut显示所有的
//#include "platform/platform.h"
//#include <windows.h>
#include "platformWin32/platformWin32.h"
//#include "rpg/RPGTextParse.h"
#include "platform/platformIME.h"
#include "gui/utility/guiIMECtrl.h"
#include "gui/core/guiCanvas.h"
#include "gui/controls/guiMLTextCtrl.h"
#include <imm.h>
#pragma comment ( lib, "imm32.lib" )
/////////////////////////////////////////////////////////////////////////////////////////
#define COMPOS_SEP '\n'
CANDIDATELIST *g_lpCandList = NULL; ///> 存储标准的选字表
class CandListMan
{
public:
//RPG::RPGTextParse m_textParse;
public:
CandListMan(){}
~CandListMan();
void ConvertCandList( CANDIDATELIST *pCandList/*, char *pszCandList*/ );
};
CandListMan g_CandListMan;
CandListMan::~CandListMan()
{
if( g_lpCandList )
{
GlobalFree( (HANDLE)g_lpCandList );
g_lpCandList = NULL;
}
}
/// 转换CandidateList到一个串,COMPOS_SEP分隔每一项
void CandListMan::ConvertCandList( CANDIDATELIST *pCandList/*, char *pszCandList*/ )
{
U32 i;
S32 nNum;
S8 cIndex;
if(g_pIME == NULL)
return;
g_pIME->m_textParse.BeginParse();
if( pCandList->dwCount < pCandList->dwSelection )
{
//pszCandList[ 0 ] = 0;
return;
}
//g_pIME->m_textParse << Con::getVariable("$RPG::IMEStyle");
//待选字序号超出总数,微软拼音第二次到选字表最后一页后再按PageDown会出现这种情况,
//并且会退出选字状态,开始一个新的输入
//但微软拼音自己的ime窗口可以解决这个问题,估计微软拼音实现了更多的接口,所以使用了这种不太标准的数据
//我现在无法解决这个问题,而且实际使用中也很少遇到这种事,而且其它标准输入法不会引起这种bug
//非标准输入法估计实现的接口比较少,所以应该也不会引起这种bug
nNum = getMin((U32)(pCandList->dwCount - pCandList->dwSelection), (U32)pCandList->dwPageSize);
for( i = 0; i <nNum ; i++ )
{
cIndex = ( i % 10 != 9 )? i % 10 + '1' : '0';
g_pIME->m_textParse << cIndex;//每项对应的数字键
g_pIME->m_textParse << (S8)'.';
g_pIME->m_textParse << (char*)pCandList + pCandList->dwOffset[ pCandList->dwSelection + i ];
if(i < nNum -1)
g_pIME->m_textParse << "\n";
}
//for( i = 0; ( i < pCandList->dwCount - pCandList->dwSelection )&&( i < pCandList->dwPageSize ); i++ )
//{
// *pszCandList++ = ( i % 10 != 9 )? i % 10 + '1' : '0';//每项对应的数字键
// // *pszCandList++ = '.';//用'.'分隔
// strcpy( pszCandList, (char*)pCandList
// + pCandList->dwOffset[ pCandList->dwSelection + i ] );//每项实际的内容
// pszCandList += strlen( pszCandList );
// *pszCandList++ = COMPOS_SEP;//项之间以'\t'分隔
//}
//*( pszCandList - 1 )= 0;//串尾,并覆盖最后一个'\t'
}
void PlatformIME::NextIME()
{
if( m_bIME)
ActivateKeyboardLayout(( HKL )HKL_NEXT, 0 );
}
void PlatformIME::SharpIME( )
{
if(m_bIME)
ImmSimulateHotKey( (HWND)m_hWnd, IME_CHOTKEY_SHAPE_TOGGLE );
}
void PlatformIME::SymbolIME( )
{
if(m_bIME)
ImmSimulateHotKey( (HWND)m_hWnd, IME_CHOTKEY_SYMBOL_TOGGLE );
}
void PlatformIME::DisableIME()
{
m_bIME = false;//先关闭IME功能
HideIME();
}
void PlatformIME::HideIME()
{
while( ImmIsIME( GetKeyboardLayout( 0 )))
ActivateKeyboardLayout(( HKL )HKL_NEXT, 0 );//如果ime打开通过循环切换到下一个关闭
m_szIMEName[ 0 ] = 0;
m_szCompStr[ 0 ] = 0;
m_szCompReadStr[ 0 ] = 0;
m_szCandList[ 0 ] = 0;
m_nIMECursor = 0;
m_textParse.ClearParse();
//if(m_pIMECtrl)
// m_pIMECtrl->OnInputLangChange(false);
}
bool PlatformIME::OnWM_INPUTLANGCHANGE( UWND hWnd )
{
if(!m_bIME)
return false;
m_hWnd = hWnd;
//ime改变
HKL hKL = GetKeyboardLayout( 0 );
if( ImmIsIME( hKL ))
{
HIMC hIMC = ImmGetContext( (HWND)hWnd );
ImmEscape( hKL, hIMC, IME_ESC_IME_NAME, m_szIMEName );//取得新输入法名字
DWORD dwConversion, dwSentence;
ImmGetConversionStatus( hIMC, &dwConversion, &dwSentence );
m_bIMESharp = ( dwConversion & IME_CMODE_FULLSHAPE )? true : false;//取得全角标志
m_bIMESymbol = ( dwConversion & IME_CMODE_SYMBOL )? true : false;//取得中文标点标志
ImmReleaseContext( (HWND)hWnd, hIMC );
}
else//英文输入
m_szIMEName[ 0 ] = 0;
//{
// m_pIMECtrl = new GuiIMECtrl();
// m_pIMECtrl->InitDefaultIME();
//}
//if(m_pIMECtrl)
if(m_pIMECtrl == NULL)
{
Con::printf("需要建立GuiIMECtrl面板");
return true;
}
m_pIMECtrl->OnInputLangChange(m_szIMEName[ 0 ] != 0);
return false;//总是返回false,因为需要窗口函数调用DefWindowProc继续处理
}
bool PlatformIME::OnWM_IME_NOTIFY( UWND hWnd, U32 wParam )
{
if(!m_bIME)
return true;
HIMC hIMC;
DWORD dwSize;
DWORD dwConversion, dwSentence;
m_hWnd = hWnd;
switch( wParam )
{
case IMN_SETCONVERSIONMODE://全角/半角,中/英文标点改变
hIMC = ImmGetContext( (HWND)hWnd );
ImmGetConversionStatus( hIMC, &dwConversion, &dwSentence );
m_bIMESharp = ( dwConversion & IME_CMODE_FULLSHAPE )? true : false;
m_bIMESymbol = ( dwConversion & IME_CMODE_SYMBOL )? true : false;
ImmReleaseContext( (HWND)hWnd, hIMC );
break;
case IMN_OPENCANDIDATE://进入选字状态
case IMN_CHANGECANDIDATE://选字表翻页
hIMC = ImmGetContext( (HWND)hWnd );
if( g_lpCandList )
{
GlobalFree( (HANDLE)g_lpCandList );
g_lpCandList = NULL;
}//释放以前的选字表
if( dwSize = ImmGetCandidateList( hIMC, 0, NULL, 0 ))
{
g_lpCandList = (LPCANDIDATELIST)GlobalAlloc( GPTR, dwSize );
if( g_lpCandList )
ImmGetCandidateList( hIMC, 0, g_lpCandList, dwSize );
}//得到新的选字表
ImmReleaseContext( (HWND)hWnd, hIMC );
if( g_lpCandList )
g_CandListMan.ConvertCandList( g_lpCandList/*, m_szCandList*/ );//选字表整理成串
break;
case IMN_CLOSECANDIDATE://关闭选字表
if( g_lpCandList )
{
GlobalFree( (HANDLE)g_lpCandList );
g_lpCandList = NULL;
}//释放
m_szCandList[ 0 ] = 0;
m_textParse.ClearParse();
//HideIME();
break;
}
if(m_pIMECtrl == NULL)
{
Con::printf("需要建立GuiIMECtrl面板");
return false;
}
m_pIMECtrl->OnIMENotify(wParam);
return true;//总是返回true,防止ime窗口打开
}
bool PlatformIME::OnWM_IME_COMPOSITION( UWND hWnd, U32 lParam )
{//输入改变
if(!m_bIME)
return true;
HIMC hIMC;
DWORD dwSize;
hIMC = ImmGetContext( (HWND)hWnd );
m_hWnd = hWnd;
if( lParam & GCS_COMPSTR )
{
dwSize = ImmGetCompositionString( hIMC, GCS_COMPSTR, (void*)m_szCompStr, sizeof( m_szCompStr ));
m_szCompStr[ dwSize ] = 0;
}//取得szCompStr
if( lParam & GCS_COMPREADSTR )
{
dwSize = ImmGetCompositionString( hIMC, GCS_COMPREADSTR, (void*)m_szCompReadStr, sizeof( m_szCompReadStr ));
m_szCompReadStr[ dwSize ] = 0;
}//取得szCompReadStr
if( lParam & GCS_CURSORPOS )
{
m_nIMECursor = 0xffff & ImmGetCompositionString( hIMC, GCS_CURSORPOS, NULL, 0 );
}//取得nIMECursor
if( lParam & GCS_RESULTSTR )
{
unsigned char str[ MAX_PATH ];
dwSize = ImmGetCompositionString( hIMC, GCS_RESULTSTR, (void*)str, sizeof( str ));//取得汉字输入串
str[ dwSize ] = 0;
unsigned char *p = str;
while( *p )
PostMessage( (HWND)hWnd, WM_CHAR, (WPARAM)(*p++), 1 );//转成WM_CHAR消息
}
ImmReleaseContext( (HWND)hWnd, hIMC );
if(m_pIMECtrl == NULL)
{
Con::printf("需要建立GuiIMECtrl面板");
return false;
}
m_pIMECtrl->OnIMEComposition(lParam);
return true;//总是返回true,防止ime窗口打开
}
void PlatformIME::GetIMEInput( char **pszCompStr, char **pszCompReadStr, int *pnIMECursor, char **pszCandList )
{
if(!m_bIME)
return;
if( pszCompStr )
*pszCompStr = m_szCompStr;
if( pszCompReadStr )
*pszCompReadStr = m_szCompReadStr;
if( pnIMECursor )
*pnIMECursor = m_nIMECursor;
if( pszCandList )
{
*pszCandList = (char*)g_pIME->m_textParse.GetParseText();
//*pszCandList = m_szCandList;
}
}
void GuiIMECtrl::OnInputLangChange(bool bOpen)
{
if(bOpen)
{
setText(g_pIME->GetIMEName());
Canvas->PushIMEControl(this);//m_pContainer);
//Canvas->pushDialogControl(m_pContainer,0);
}
else
{
Canvas->PopIMEControl();
//Canvas->popDialogControl(m_pContainer);
}
setVisible(bOpen);
}
void GuiIMECtrl::OnIMENotify(U32 uCode)
{
//以下为默认处理
switch( uCode )
{
case IMN_SETCONVERSIONMODE://全角/半角,中/英文标点改变
if(m_bDefault)
{
ToggleCtrl(E_SHARP,g_pIME->m_bIMESharp);
ToggleCtrl(E_SYMBOL,g_pIME->m_bIMESymbol);
}
break;
case IMN_OPENCANDIDATE://进入选字状态
case IMN_CHANGECANDIDATE://选字表翻页
case IMN_CLOSECANDIDATE://关闭选字表
SetIMEText(E_LIST, g_pIME->m_textParse.GetParseText());
//static_cast<GuiMLTextCtrl*>(m_arCtrls[E_LIST])->setText(g_pIME->m_szCandList,-1);
//static_cast<GuiTextCtrl*>(m_arCtrls[E_LIST])->setText(g_pIME->m_szCandList);
break;
}
}
void GuiIMECtrl::OnIMEComposition(U32 uFlag)
{
if( uFlag & GCS_COMPSTR )
{
SetIMEText(E_INPUT, g_pIME->m_szCompStr);
//if(m_arCtrls[E_INPUT])
// static_cast<GuiMLTextCtrl*>(m_arCtrls[E_INPUT])->setText(g_pIME->m_szCompStr,-1);
//static_cast<GuiTextCtrl*>(m_arCtrls[E_INPUT])->setText(g_pIME->m_szCompStr);
//m_arCtrls[E_INPUT]->setField("text",g_pIME->m_szCompStr);
}//取得szCompStr
if( uFlag & GCS_COMPREADSTR )
{
SetIMEText(E_INPUT2, g_pIME->m_szCompReadStr);
//if(m_arCtrls[E_INPUT2])
// static_cast<GuiMLTextCtrl*>(m_arCtrls[E_INPUT2])->setText(g_pIME->m_szCompReadStr,-1);
//static_cast<GuiTextCtrl*>(m_arCtrls[E_INPUT2])->setText(g_pIME->m_szCompReadStr);
}//取得szCompReadStr
if( uFlag & GCS_CURSORPOS )
{
FitPosByCursor(g_pIME->GetCursorPos());
}//取得nIMECursor
if( uFlag & GCS_RESULTSTR )
{
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -