⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ime.cpp

📁 《OpenGL游戏编程》这本书的配套源码。
💻 CPP
字号:
//======================================================================
/**
*  @file      Ime.cpp
*
*  项目描述: 构造游戏引擎
*   
*  文件描述:  输入法IME类
*  适用平台: Windows98/2000/NT/XP
*  
*  作者:     WWBOSS
*  电子邮件:  wwboss123@gmail.com
*  创建日期: 2007-07-24	
*  修改日期: 2007-07-24
*/																			
//======================================================================


#include "stdafx.h" 
#include "ime.h"

CIme* CIme::m_pIme=NULL;


CIme::CIme():m_lpCandList(NULL),m_iImeCaret(-1),m_iWordCaret(-1),
			m_bReceive(true),m_iMaxLen(STR_MAX_LENGTH)
{
	m_pIme=this;
	m_chResultStr[0] =0 ;
	Disable(); 	//通过Disable初始化一些数据
}


void CIme::Release()
{
	Disable();
	if( m_lpCandList )
	{
		GlobalFree( (HANDLE)m_lpCandList );
		m_lpCandList = NULL;
	}
}



bool CIme::OnWM_INPUTLANGCHANGE( HWND hWnd)
{
	//输入法改变
	HKL hKL = GetKeyboardLayout( 0 );
	if( ImmIsIME( hKL ))
	{
		HIMC hIMC = ImmGetContext( hWnd );

		DWORD dwConversion;
		ImmGetConversionStatus( hIMC, &dwConversion,NULL );
		m_bSharp = ( dwConversion & IME_CMODE_FULLSHAPE )? true : false;//取得全角标志
		m_bSymbol = ( dwConversion & IME_CMODE_SYMBOL )? true : false;//取得中文标点标志

		ImmEscape( hKL, hIMC, IME_ESC_IME_NAME, m_szName );//取得新输入法名字
		ImmReleaseContext( hWnd, hIMC );
	}
	else//英文输入
		//m_szImeName[ 0 ] = 0;
		strcpy(m_szName,"英文");
	return false;//总是返回false,因为需要窗口函数调用DefWindowProc继续处理
}


bool CIme::OnWM_IME_NOTIFY( HWND hWnd, WPARAM wParam )
{
	HIMC hIMC;
	DWORD dwSize;
	DWORD dwConversion, dwSentence;
	switch( wParam )
	{
	case IMN_SETCONVERSIONMODE://全角/半角,中/英文标点改变
		hIMC = ImmGetContext( hWnd );
		ImmGetConversionStatus( hIMC, &dwConversion, &dwSentence );
		m_bSharp = ( dwConversion & IME_CMODE_FULLSHAPE )? true : false;
		m_bSymbol = ( dwConversion & IME_CMODE_SYMBOL )? true : false;
		ImmReleaseContext( hWnd, hIMC );
		break;

		//case IMN_OPENCANDIDATE://进入选字状态
	case IMN_CHANGECANDIDATE://选字表翻页
		hIMC = ImmGetContext( hWnd );
		if( m_lpCandList )
		{
			GlobalFree( (HANDLE)m_lpCandList );
			m_lpCandList = NULL;
		}//释放以前的选字表
		if( dwSize = ImmGetCandidateList( hIMC, 0, NULL, 0 ))
		{
			m_lpCandList = (LPCANDIDATELIST)GlobalAlloc( GPTR, dwSize );
			if( m_lpCandList )
				ImmGetCandidateList( hIMC, 0, m_lpCandList, dwSize );
		}//得到新的选字表
		ImmReleaseContext( hWnd, hIMC );
		if( m_lpCandList )
			ConvertCandList( m_lpCandList, m_szCandList );//选字表整理成串
		break;

	case IMN_CLOSECANDIDATE://关闭选字表
		if( m_lpCandList )
		{
			GlobalFree( (HANDLE)m_lpCandList );
			m_lpCandList = NULL;
		}//释放
		m_szCandList[ 0 ] = 0;
		break;
	}

	return true;//总是返回true,防止ime窗口打开
}


bool CIme::OnWM_IME_COMPOSITION( HWND hWnd, LPARAM lParam )
{//输入改变
	HIMC hIMC;
	DWORD dwSize;
	hIMC = ImmGetContext( hWnd );
	//取得szCompStr
	if( (DWORD)lParam & GCS_COMPSTR )
	{
		dwSize = ImmGetCompositionString( hIMC, GCS_COMPSTR, (void*)m_szCompStr, sizeof( m_szCompStr ));
		m_szCompStr[ dwSize ] = 0;
	}
	//取得szCompReadStr
	if( (DWORD)lParam & GCS_COMPREADSTR )
	{
		dwSize = ImmGetCompositionString( hIMC, GCS_COMPREADSTR, (void*)m_szCompReadStr, sizeof( m_szCompReadStr ));
		m_szCompReadStr[ dwSize ] = 0;
	}
	//取得nImeCursor
	if( lParam & GCS_CURSORPOS )
	{
		m_nCursor = 0xffff & ImmGetCompositionString( hIMC, GCS_CURSORPOS, NULL, 0 );
	}

	if( lParam & GCS_RESULTSTR )
	{
		char str[ MAX_PATH ];
		dwSize = ImmGetCompositionString( hIMC, GCS_RESULTSTR, (void*)str, sizeof( str ));//取得汉字输入串
		str[ dwSize ] = 0;
		ReceiveChar( str, dwSize );
	}

	ImmReleaseContext( hWnd, hIMC );
	return true;//总是返回true,防止ime窗口打开
}


void  CIme::Disable()
{
	//while( ImmIsIME( GetKeyboardLayout( 0 )))
	//	ActivateKeyboardLayout(( HKL )HKL_NEXT, 0 );//如果ime打开通过循环切换到下一个关闭
	m_bIme = false;
	m_szName[ 0 ] = 0;

	m_szCompReadStr[ 0 ] = 0;
	m_szCandList[ 0 ] = 0;
	m_nCursor = 0;

	m_chResultStr[0] = 0;
	m_iImeCaret=-1;
	m_iWordCaret=-1;
	m_bReceive=true;
	m_bReturn=false;
}


void CIme::ConvertCandList( CANDIDATELIST *pCandList, char *pszCandList )
{//转换CandidateList到一个串,\t分隔每一项
	unsigned int i;
	if( pCandList->dwCount < pCandList->dwSelection )
	{
		pszCandList[ 0 ] = 0;
		return;
	}

	//待选字序号超出总数,微软拼音第二次到选字表最后一页后再按PageDown会出现这种情况,并且会退出选字状态,开始一个新的输入
	//但微软拼音自己的ime窗口可以解决这个问题,估计微软拼音实现了更多的接口,所以使用了这种不太标准的数据
	//我现在无法解决这个问题,而且实际使用中也很少遇到这种事,而且其它标准输入法不会引起这种bug
	//非标准输入法估计实现的接口比较少,所以应该也不会引起这种bug
	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++ = '\t';//项之间以'\t'分隔
	}
	*( pszCandList - 1 )= 0;//串尾,并覆盖最后一个'\t'
}


void CIme::ReceiveChar(TCHAR _iCharCode)
{
	if(!m_bIme)return;
	if(!m_bReceive&&_iCharCode!='\b')return;

	if( !_iCharCode )return;

	switch(_iCharCode) 
	{
	case '\b':
		BackspaceKey();
		break;
	case '\r':break;
	case '\t':break;
	case VK_ESCAPE:break;
	default:
		{
			int t_iLen = (int)strlen(m_chResultStr);

			if(t_iLen >= m_iMaxLen-1)
			{
				t_iLen = m_iMaxLen-1;
			}
			if( m_iImeCaret < m_iMaxLen-1 
				&& (int)strlen(m_chResultStr) < m_iMaxLen )
			{
				++m_iImeCaret;
				++m_iWordCaret;//////////////

				//将插入符后面的每个字符向后移动一位
				for(int i = t_iLen; i>=m_iImeCaret; i--)
				{
					m_chResultStr[i+1] = m_chResultStr[i];
				}
				m_chResultStr[m_iImeCaret] = (char)_iCharCode;
			}
			break;
		}
	}
}

void CIme::ReceiveChar(char* _Char, DWORD _dwSize)
{
	if(!m_bIme)return;
	if(!m_bReceive&&_Char[0]!='\b')return;

	int t_iLen;
	int t_iLen2 = (int)strlen(_Char);

	while ( (int)strlen(m_chResultStr)+t_iLen2 > m_iMaxLen )
	{
		t_iLen2 -= 2;
	}
	
	m_iWordCaret+=(t_iLen2%2==1)?((t_iLen2+1)/2):(t_iLen2/2);/////////////

	for(int i=0; i<t_iLen2; ++i )
	{
		t_iLen = (int)strlen(m_chResultStr);

		if( t_iLen >= m_iMaxLen-1 )
		{
			t_iLen = m_iMaxLen-1;
		}
		if( m_iImeCaret < m_iMaxLen-1 )
		{
			++m_iImeCaret;
			//将插入符后面的每个字符向后移动一位
			for(int j = t_iLen; j>=m_iImeCaret; j--)
			{
				m_chResultStr[j+1] = m_chResultStr[j];
			}
			if( m_iImeCaret < m_iMaxLen )
				m_chResultStr[m_iImeCaret] = _Char[i];
		}
	}

}


/** \brief
* "向右"方向键的处理
*/
void CIme::RightKey( void )
{
	int t_iLen = (int)strlen(m_chResultStr);

	if( m_iImeCaret < t_iLen-2 )
	{
		// 判断是否是汉字
		if( (BYTE)m_chResultStr[m_iImeCaret+1] > 160
			&& (BYTE)m_chResultStr[m_iImeCaret+2] > 160 )
			m_iImeCaret +=2;
		else
            ++m_iImeCaret;
		++m_iWordCaret;/////////////
	}
	else if( m_iImeCaret < t_iLen-1 )
	{
		++m_iImeCaret;
		++m_iWordCaret;/////////////
	}
}

/** \brief
* "向左"方向键的处理
*/
void CIme::LeftKey( void )
{
	//判断汉字
	if( m_iImeCaret-1 > -1 )
	{
		if( (BYTE)m_chResultStr[m_iImeCaret-1] > 160
			&& (BYTE)m_chResultStr[m_iImeCaret] > 160 )
		{
			m_iImeCaret -=2;
		}
		else
			m_iImeCaret--;
		m_iWordCaret--;////////////
	}
	else if( m_iImeCaret > -1 )
	{
		m_iImeCaret--;
		m_iWordCaret--;////////////
	}
}

/** \brief
* "回退" 键处理
*/
void CIme::BackspaceKey(void)
{
	int t_iLen = (int)strlen(m_chResultStr);
	//判断汉字
	if( m_iImeCaret-1 > -1 )
	{
		//删除汉字
		if( (BYTE)m_chResultStr[m_iImeCaret-1] > 160
			&& (BYTE)m_chResultStr[m_iImeCaret] > 160 )
		{
			for(int i = m_iImeCaret; i<t_iLen; ++i)
			{
				m_chResultStr[i] = m_chResultStr[i+1];
			}
			m_iImeCaret--;
			for(int i = m_iImeCaret; i<t_iLen; ++i)
			{
				m_chResultStr[i] = m_chResultStr[i+1];
			}
			m_iImeCaret--;
		}
		else//删除一个字母
		{
			for(int i = m_iImeCaret; i<t_iLen; ++i)
			{
				m_chResultStr[i] = m_chResultStr[i+1];
			}
			m_iImeCaret--;
		}
		m_iWordCaret--;//////////////
	}
	else if( m_iImeCaret > -1 )
	{
		for(int i = m_iImeCaret; i<t_iLen; ++i)
		{
			m_chResultStr[i] = m_chResultStr[i+1];
		}
		m_iImeCaret--;
		m_iWordCaret--;////////////
	}
	if(m_iWordCaret<-1)m_iWordCaret=-1;///////////
}


/** \brief
* "DEL" 键处理
*/
void CIme::DeleteKey(void)
{
	int t_iLen = (int)strlen(m_chResultStr);

	if( m_iImeCaret < t_iLen-2 )
	{
		// 判断是否是汉字
		if( (BYTE)m_chResultStr[m_iImeCaret+1] > 160
			&& (BYTE)m_chResultStr[m_iImeCaret+2] > 160 )
		{
			//将插入符后面的每个字符向前移动二位
			for(int i = m_iImeCaret+1; i<t_iLen-1; ++i)
			{
				m_chResultStr[i] = m_chResultStr[i+2];
			}
		}
		else
		{
			//将插入符后面的每个字符向前移动一位
			for(int i = m_iImeCaret+1; i<t_iLen; ++i)
			{
				m_chResultStr[i] = m_chResultStr[i+1];
			}
		}
	}
	else if( m_iImeCaret < t_iLen-1 )
	{
		//将插入符后面的每个字符向前移动一位
		for(int i = m_iImeCaret+1; i<t_iLen; ++i)
		{
			m_chResultStr[i] = m_chResultStr[i+1];
		}
	}

	if(m_iWordCaret<-1)m_iWordCaret=-1;////////////
}


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -