ime.cpp

来自「Windows CE 6.0 Word Application 源码」· C++ 代码 · 共 2,215 行 · 第 1/5 页

CPP
2,215
字号
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
/*
 *	@doc	INTERNAL
 *
 *	@module ime.cpp -- support for Win95 IME API |
 *	
 *		Most everything to do with FE composition string editing passes
 *		through here.
 *	
 *	Authors: <nl>
 *		Jon Matousek <nl>
 *		Hon Wah Chan <nl>
 *		Justin Voskuhl <nl>
 *
 *	History: <nl>
 *		10/18/1995		jonmat	Cleaned up level 2 code and converted it into
 *								a class hierarchy supporting level 3.
 *
 *
 */								

#include "_common.h"
#include "_font.h"
#include "_edit.h"
#include "_select.h"
#include "_m_undo.h"
#include "_dispml.h"

#include "_ime.h"
#include "_rtfconv.h"	// Needed for GetCodePage

BOOL forceLevel2 = FALSE;

ASSERTDATA

#define HAVE_COMPOSITION_STRING ( 0 != (lparam & (GCS_COMPSTR | GCS_COMPATTR)))
#define CLEANUP_COMPOSITION_STRING ( 0 == lparam )
#define HAVE_RESULT_STRING ( 0 != (lparam & GCS_RESULTSTR))


/*
 *	HRESULT StartCompositionGlue ( CTxtEdit &ed, IUndoBuilder &undobldr )
 *	
 *	@func
 *		Initiates an IME composition string edit.
 *	@comm
 *		Called from the message loop to handle WM_IME_STARTCOMPOSITION.
 *		This is a glue routine into the IME object hierarchy.
 *
 *	@devnote
 *		We decide if we are going to do a level 2 or level 3 IME
 *		composition string edit. Currently, the only reason to
 *		create a level 2 IME is if the IME has a special UI, or it is
 *		a "near caret" IME, such as the ones found in PRC and Taiwan.
 *		Near caret simply means that a very small window opens up
 *		near the caret, but not on or at the caret.
 *
 *	@rdesc
 *		HRESULT-S_FALSE for DefWindowProc processing, S_OK if not.
 */
HRESULT StartCompositionGlue (
	CTxtEdit &ed,				// @parm the containing text edit.
	BOOL	 fIsNotProtected,	// @parm TRUE if Not Protected Nor ReadOnly
	IUndoBuilder &undobldr)		// @parm required to modify the text.
{
	TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "StartCompositionGlue");

	// note that in some locales (PRC), we may still be in composition mode
	// when a new start composition call comes in.  Just reset our state
	// and go on.

	if ( fHaveIMMProcs && !ed.IsIMEComposition() )
	{
		if ( fIsNotProtected )
		{

			// if a special UI, or IME is "near caret", then drop into lev. 2 mode.
			DWORD	imeProperties;

			imeProperties = pImmGetProperty( GetKeyboardLayout(0), IGP_PROPERTY );

			if ( 0 != ( imeProperties & IME_PROP_SPECIAL_UI )
				|| 0 == ( imeProperties & IME_PROP_AT_CARET )
				|| forceLevel2 )
			{
				ed._ime = new CIme_Lev2 ( ed );		// level 2 IME.
			}
			else
			{
				ed._ime = new CIme_Lev3 ( ed );		// level 3 IME->TrueInline.
			}
		}
		else
		{
			// protect or read-only, need to ignore all ime input
			ed._ime = new CIme_Protected;
		}
	}

	if ( ed.IsIMEComposition() )					// make the method call.
	{
		return ed._ime->StartComposition ( ed, undobldr );
	}

	return S_FALSE;
}

/*
 *	HRESULT CompositionStringGlue ( const LPARAM lparam, CTxtEdit &ed,
 *		IUndoBuilder &undobldr )
 *	
 *	@func
 *		Handle all intermediary and final composition strings.
 *
 *	@comm
 *		Called from the message loop to handle WM_IME_COMPOSITION.
 *		This is a glue routine into the IME object hierarchy.
 *		We may be called independently of a WM_IME_STARTCOMPOSITION
 *		message, in which case we return S_FALSE to allow the
 *		DefWindowProc to return WM_IME_CHAR messages.
 *
 *	@devnote
 *		Side Effect: the _ime object may be deleted if composition
 *		string processing is finished.
 *		
 *	@rdesc
 *		HRESULT-S_FALSE for DefWindowProc processing, S_OK if not.
 */
HRESULT CompositionStringGlue (
	const LPARAM lparam,		// @parm associated with message.
	CTxtEdit &ed,				// @parm the containing text edit.
	IUndoBuilder &undobldr )	// @parm required to modify the text.
{
	TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CompositionStringGlue");

	HRESULT hr = S_FALSE;

	if ( ed.IsIMEComposition() )					// A priori fHaveIMMProcs.
	{
		ed._ime->_compMessageRefCount++;			// For proper deletion.

													// Make the method call.
		hr = ed._ime->CompositionString(lparam, ed, undobldr);

		ed._ime->_compMessageRefCount--;			// For proper deletion.
		Assert ( ed._ime->_compMessageRefCount >= 0);

		CheckDestroyIME ( ed );						// Finished processing?
	}
	else // even when not in composition mode, we may receive a result string.
	{
		CIme::CheckKeyboardFontMatching ( GetKeyboardCodePage(), ed, NULL );
		hr = CIme::CheckInsertResultString( lparam, ed, undobldr );
	}

	return hr;
}

/*
 *	HRESULT EndCompositionGlue ( CTxtEdit &ed, IUndoBuilder &undobldr )
 *
 *	@func
 *		Composition string processing is about to end.
 *
 *	@comm
 *		Called from the message loop to handle WM_IME_ENDCOMPOSITION.
 *		This is a glue routine into the IME object hierarchy.
 *
 *	@devnote
 *		The only time we have to handle WM_IME_ENDCOMPOSITION is when the
 *		user changes input method during typing.  For such case, we will get
 *		a WM_IME_ENDCOMPOSITION message without getting a WM_IME_COMPOSITION
 *		message with GCS_RESULTSTR later.  So, we will call CompositionStringGlue
 *		with GCS_RESULTSTR to let CompositionString to get rid of the string.
 *		
 *	@rdesc
 *		HRESULT-S_FALSE for DefWindowProc processing, S_OK if not.
 */
HRESULT EndCompositionGlue (
	CTxtEdit &ed,				// @parm the containing text edit.
	IUndoBuilder &undobldr)	// @parm required to modify the text.
{
	TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "EndCompositionGlue");

	if ( ed.IsIMEComposition() )
	{
		// set this flag. If we are still in composition mode, then
		// let the CompositionStringGlue() to destroy the ime object.
		ed._ime->_fDestroy = TRUE;

		// remove any remaining composition string.
		CompositionStringGlue( GCS_COMPSTR , ed, undobldr );

		// finished with IME, destroy it.
		CheckDestroyIME ( ed );
		
	}
	return S_FALSE;
}

/*
 *	void CheckDestroyIME ( CTxtEdit &ed )
 *
 *	@func
 *		Check for IME and see detroy if it needs it..
 *
 */
void CheckDestroyIME (
	CTxtEdit &ed )
{
	TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CheckDestroyIME");
	
	if ( ed.IsIMEComposition() && ed._ime->_fDestroy )
	{
		if ( 0 == ed._ime->_compMessageRefCount )
		{
			BOOL bKorean = ed._ime->IsKoreanMode();

		 	delete ed._ime;							// All done with object.
			ed._ime = NULL;

			CTxtSelection	*psel = ed.GetSel();
			if ( psel )
			{
				if ( bKorean )
				{
					// reset the caret position
					DWORD cp = psel->GetCp();
					psel->SetSelection (cp, cp);
				}

				psel->ShowCaret(TRUE);
			}

			if ( !ed.IsRich() )						// For nonRich, make sure
			{										//  to nuke runs.
				// Tell document to dump its format runs
				ed.HandleIMEToPlain();
			}
		}
	}
}

/*
 *	void PostIMECharGlue ( CTxtEdit &ed )
 *
 *	@func
 *		Called after processing a single WM_IME_CHAR in order to
 *		update the position of the IME's composition window. This
 *		is glue code to call the CIME virtual equivalent.
 */
void PostIMECharGlue (
	CTxtEdit &ed )				// @parm the containing text edit.
{
	TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "PostIMECharGlue");

	if ( ed.IsIMEComposition() )
	{
		ed._ime->PostIMEChar( ed );
	}
}

/*
 *	HRESULT IMENotifyGlue ( const WPARAM wparam, const LPARAM lparam,
 *				CTxtEdit &ed )
 *
 *	@func
 *		IME is going to change some state.
 *
 *	@comm
 *		Currently we are interested in knowing when the candidate
 *		window is about to be opened.
 *		
 *	@rdesc
 *		HRESULT-S_FALSE for DefWindowProc processing, S_OK if not.
 */
HRESULT IMENotifyGlue (
	const WPARAM wparam,		// @parm associated with message.
	const LPARAM lparam,		// @parm associated with message.
	CTxtEdit &ed )				// @parm the containing text edit.
{
	TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "IMENotifyGlue");

#if 0
	if (IMN_SETOPENSTATUS == wparam)
	{
		if (!pImmGetOpenStatus(ed.TxImmGetContext()))
		{
			// change to English keyboard if KANA mode is not on
			if (!(GetKeyState(VK_KANA) & 0x1))
				ed._ime->CheckKeyboardFontMatching ( 1252, ed, NULL );
		}
	}
#endif

	if ( ed.IsIMEComposition() )					// A priori fHaveIMMProcs.
	{												// Make the method call.
		return ed._ime->IMENotify ( wparam, lparam, ed );
	}
	
	return S_FALSE;
}

/*
 *	void IMECompositionFull ( CTxtEdit &ed )
 *
 *	@func
 *		Current IME Composition window is full.
 *
 *	@comm
 *		Called from the message loop to handle WM_IME_COMPOSITIONFULL.
 *		This message applied to Level 2 only.  We will use the default
 *		IME Composition window.
 *
 */
void IMECompositionFull (
	CTxtEdit &ed)				// @parm the containing text edit.
{
	TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "IMECompositionFull");

	if ( ed.IsIMEComposition() )
	{
#ifndef MACPORT
		HIMC 				hIMC	= ed.TxImmGetContext();
		COMPOSITIONFORM		cf;

		if ( hIMC )
		{																									
			// no room for text input in the current level 2 IME window,
			// fall back to use the default IME window for input.
			cf.dwStyle = CFS_DEFAULT;
			pImmSetCompositionWindow( hIMC, &cf );	// Set composition window.
			ed.TxImmReleaseContext( hIMC );			// Done with IME context.
		}
#endif
 	}
}

/*
 *	LRESULT OnGetIMECompositionMode ( CTxtEdit &ed )
 *
 *	@mfunc
 *		Returns whether or not IME composition is being handled by RE,
 *		and if so, what level of processing.
 *		
 *	@rdesc
 *		One of ICM_NOTOPEN, ICM_LEVEL2_5, ICM_LEVEL2_SUI, ICM_LEVEL2, ICM_LEVEL3.
 */
LRESULT OnGetIMECompositionMode (
	CTxtEdit &ed )	  	// @parm the containing text edit.
{
	LRESULT lres;

	lres = ICM_NOTOPEN;
	if ( ed.IsIMEComposition() )
	{
		if ( IME_LEVEL_2 == ed._ime->_imeLevel )
		{
#ifndef MACPORT
			DWORD imeProperties;

			imeProperties = pImmGetProperty( GetKeyboardLayout(0), IGP_PROPERTY );
			if ( imeProperties & IME_PROP_AT_CARET)
				lres = ICM_LEVEL2_5;				// level 2.5.
			else if	( imeProperties & IME_PROP_SPECIAL_UI )
				lres = ICM_LEVEL2_SUI;				// special UI.
			else
#endif
				lres = ICM_LEVEL2;					// stock level 2.
		}
		else if ( IME_LEVEL_3 == ed._ime->_imeLevel )
		{
			lres = ICM_LEVEL3;
		}
	}

	return lres;
}

/*
 *	BOOL IMECheckGetInvertRange(CTxtEdit *ed, LONG &invertMin, LONG &invertMost)
 *
 *	@func
 *		helper func that returns the min invertMin and max invertMost across a
 *		range of IME composition characters. This is required by the renderer to
 *		know if to treat the current line as a line that contains a selection
 *		as we use the renderer's invert selection code to invert the IME text.
 *
 *	@comm
 *		Unlike a single selection, there can be noncontiguous IME inverted
 *		selections.
 */
BOOL IMECheckGetInvertRange(CTxtEdit *ed, LONG &invertMin, LONG &invertMost)
{
	TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "IMECheckGetInvertRange");

	if ( ed && ed->IsIMEComposition() )
	{
		 invertMin		= ed->_ime->_invertMin;
		 invertMost		= ed->_ime->_invertMost;

		 return TRUE;
	}

	return FALSE;
}

/*
 *	void CIme::CheckKeyboardFontMatching ( CTxtEdit &ed, LONG *piFormat )
 *	
 *	@mfunc
 *		Check if the current font matches the keyboard Codepage.
 *
 *	@comm
 *		Called from CIme_Lev2::CIme_Lev2 and CompositionStringGlue
 *
 *	@devnote
 *		We need to switch to a preferred font for the keyboard during IME input.
 *		Otherwise, we will dispay garbage.
 *		
 */
void CIme::CheckKeyboardFontMatching (
	UINT cp,
	CTxtEdit &ed,
	LONG	*piFormat )
{
	CTxtSelection		* const psel	= ed.GetSel();

	Assert ( psel );

	if ( psel && ed.IsRich() )
	{

⌨️ 快捷键说明

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