?? ime.cpp
字號:
//
// 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 + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -