2303 lines
62 KiB
C++
2303 lines
62 KiB
C++
#include "StdAfx.h"
|
||
#include "IME.h"
|
||
#include "TextTag.h"
|
||
#include "../eterBase/Utils.h"
|
||
#include "msctf.h"
|
||
#include <oleauto.h>
|
||
|
||
#define COUNTOF(a) ( sizeof( a ) / sizeof( ( a )[0] ) )
|
||
|
||
int CIME::ms_compLen;
|
||
int CIME::ms_curpos;
|
||
int CIME::ms_lastpos;
|
||
wchar_t CIME::m_wText[IMESTR_MAXLEN];
|
||
|
||
#define MAKEIMEVERSION(major, minor) ((DWORD)(((BYTE)(major) << 24) | ((BYTE)(minor) << 16)))
|
||
#define IMEID_VER(dwId) ((dwId) & 0xffff0000)
|
||
#define IMEID_LANG(dwId) ((dwId) & 0x0000ffff)
|
||
|
||
#define GETLANG() LOWORD(CIME::ms_hklCurrent)
|
||
#define GETPRIMLANG() ((WORD)PRIMARYLANGID(GETLANG()))
|
||
#define GETSUBLANG() SUBLANGID(GETLANG())
|
||
|
||
#define LANG_CHT MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL)
|
||
#define LANG_CHS MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED)
|
||
|
||
// Chinese Traditional
|
||
#define _CHT_HKL_DAYI ((HKL)0xE0060404) // DaYi
|
||
#define _CHT_HKL_NEW_PHONETIC ((HKL)0xE0080404) // New Phonetic
|
||
#define _CHT_HKL_NEW_CHANG_JIE ((HKL)0xE0090404) // New Chang Jie
|
||
#define _CHT_HKL_NEW_QUICK ((HKL)0xE00A0404) // New Quick
|
||
#define _CHT_HKL_HK_CANTONESE ((HKL)0xE00B0404) // Hong Kong Cantonese
|
||
|
||
#define CHT_IMEFILENAME1 "TINTLGNT.IME" // New Phonetic
|
||
#define CHT_IMEFILENAME2 "CINTLGNT.IME" // New Chang Jie
|
||
#define CHT_IMEFILENAME3 "MSTCIPHA.IME" // Phonetic 5.1
|
||
|
||
#define IMEID_CHT_VER42 (LANG_CHT | MAKEIMEVERSION(4, 2)) // New(Phonetic/ChanJie)IME98 : 4.2.x.x // Win98
|
||
#define IMEID_CHT_VER43 (LANG_CHT | MAKEIMEVERSION(4, 3)) // New(Phonetic/ChanJie)IME98a : 4.3.x.x // Win2k
|
||
#define IMEID_CHT_VER44 (LANG_CHT | MAKEIMEVERSION(4, 4)) // New ChanJie IME98b : 4.4.x.x // WinXP
|
||
#define IMEID_CHT_VER50 (LANG_CHT | MAKEIMEVERSION(5, 0)) // New(Phonetic/ChanJie)IME5.0 : 5.0.x.x // WinME
|
||
#define IMEID_CHT_VER51 (LANG_CHT | MAKEIMEVERSION(5, 1)) // New(Phonetic/ChanJie)IME5.1 : 5.1.x.x // IME2002(w/OfficeXP)
|
||
#define IMEID_CHT_VER52 (LANG_CHT | MAKEIMEVERSION(5, 2)) // New(Phonetic/ChanJie)IME5.2 : 5.2.x.x // IME2002a(w/Whistler)
|
||
#define IMEID_CHT_VER60 (LANG_CHT | MAKEIMEVERSION(6, 0)) // New(Phonetic/ChanJie)IME6.0 : 6.0.x.x // IME XP(w/WinXP SP1)
|
||
#define IMEID_CHT_VER_VISTA (LANG_CHT | MAKEIMEVERSION(7, 0)) // All TSF TIP under Cicero UI-less mode: a hack to make GetImeId() return non-zero value
|
||
|
||
// Chinese Simplized
|
||
#define _CHS_HKL ((HKL)0xE00E0804) // MSPY
|
||
#define _CHS_HKL_QQPINYIN ((HKL)0xE0210804) // QQ PinYin
|
||
#define _CHS_HKL_SOGOU ((HKL)0xE0220804) // Sougou PinYin
|
||
#define _CHS_HKL_GOOGLEPINYIN ((HKL)0xE0230804) // Google PinYin
|
||
|
||
#define CHS_IMEFILENAME1 "PINTLGNT.IME" // MSPY1.5/2/3
|
||
#define CHS_IMEFILENAME2 "MSSCIPYA.IME" // MSPY3 for OfficeXP
|
||
#define CHS_IMEFILENAME_QQPINYIN "QQPINYIN.IME" // QQ PinYin
|
||
#define CHS_IMEFILENAME_SOGOUPY "SOGOUPY.IME" // Sougou PinYin
|
||
#define CHS_IMEFILENAME_GOOGLEPINYIN2 "GOOGLEPINYIN2.IME" // Google PinYin 2
|
||
|
||
#define IMEID_CHS_VER41 (LANG_CHS | MAKEIMEVERSION(4, 1)) // MSPY1.5 // SCIME97 or MSPY1.5 (w/Win98, Office97)
|
||
#define IMEID_CHS_VER42 (LANG_CHS | MAKEIMEVERSION(4, 2)) // MSPY2 // Win2k/WinME
|
||
#define IMEID_CHS_VER53 (LANG_CHS | MAKEIMEVERSION(5, 3)) // MSPY3 // WinXP
|
||
|
||
enum { INDICATOR_NON_IME, INDICATOR_CHS, INDICATOR_CHT, INDICATOR_KOREAN, INDICATOR_JAPANESE };
|
||
enum { IMEUI_STATE_OFF, IMEUI_STATE_ON, IMEUI_STATE_ENGLISH };
|
||
|
||
#define LCID_INVARIANT MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT)
|
||
|
||
wchar_t s_aszIndicator[5][3] =
|
||
{
|
||
L"En",
|
||
L"\x7B80",
|
||
L"\x7E41",
|
||
L"\xAC00",
|
||
L"\x3042",
|
||
};
|
||
|
||
INPUTCONTEXT* (WINAPI * CIME::_ImmLockIMC)( HIMC );
|
||
BOOL (WINAPI * CIME::_ImmUnlockIMC)( HIMC );
|
||
LPVOID (WINAPI * CIME::_ImmLockIMCC)( HIMCC );
|
||
BOOL (WINAPI * CIME::_ImmUnlockIMCC)( HIMCC );
|
||
|
||
UINT (WINAPI * CIME::_GetReadingString)( HIMC, UINT, LPWSTR, PINT, BOOL*, PUINT );
|
||
BOOL (WINAPI * CIME::_ShowReadingWindow)( HIMC, BOOL );
|
||
|
||
bool CIME::ms_bInitialized = false;
|
||
bool CIME::ms_bDisableIMECompletely = false;
|
||
bool CIME::ms_bImeEnabled = false;
|
||
bool CIME::ms_bUILessMode = false;
|
||
bool CIME::ms_bCaptureInput = false;
|
||
bool CIME::ms_bChineseIME = false;
|
||
bool CIME::ms_bUseIMMCandidate = false;
|
||
|
||
HWND CIME::ms_hWnd;
|
||
HKL CIME::ms_hklCurrent;
|
||
char CIME::ms_szKeyboardLayout[KL_NAMELENGTH+1];
|
||
OSVERSIONINFOA CIME::ms_stOSVI;
|
||
|
||
HINSTANCE CIME::ms_hImm32Dll;
|
||
HINSTANCE CIME::ms_hCurrentImeDll;
|
||
DWORD CIME::ms_dwImeState;
|
||
|
||
DWORD CIME::ms_adwId[2] = { 0, 0 };
|
||
|
||
// IME Level
|
||
DWORD CIME::ms_dwIMELevel;
|
||
DWORD CIME::ms_dwIMELevelSaved;
|
||
|
||
// Candidate List
|
||
bool CIME::ms_bCandidateList;
|
||
DWORD CIME::ms_dwCandidateCount;
|
||
bool CIME::ms_bVerticalCandidate;
|
||
int CIME::ms_iCandListIndexBase;
|
||
WCHAR CIME::ms_wszCandidate[CIME::MAX_CANDLIST][MAX_CANDIDATE_LENGTH];
|
||
DWORD CIME::ms_dwCandidateSelection;
|
||
DWORD CIME::ms_dwCandidatePageSize;
|
||
|
||
// Reading Window
|
||
bool CIME::ms_bReadingInformation;
|
||
int CIME::ms_iReadingError = 0;
|
||
bool CIME::ms_bHorizontalReading;
|
||
std::vector<wchar_t> CIME::ms_wstrReading;
|
||
|
||
// Indicator
|
||
wchar_t* CIME::ms_wszCurrentIndicator;
|
||
|
||
IIMEEventSink* CIME::ms_pEvent;
|
||
|
||
int CIME::ms_ulbegin;
|
||
int CIME::ms_ulend;
|
||
|
||
UINT CIME::ms_uOutputCodePage = 0;
|
||
UINT CIME::ms_uInputCodePage = 0;
|
||
|
||
extern DWORD gs_codePage=0;
|
||
extern DWORD GetDefaultCodePage();
|
||
extern int ReadToken(const char* token);
|
||
extern const char* FindToken(const char* begin, const char* end);
|
||
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
//
|
||
// CTsfUiLessMode
|
||
// Handles IME events using Text Service Framework (TSF). Before Vista,
|
||
// IMM (Input Method Manager) API has been used to handle IME events and
|
||
// inqueries. Some IMM functions lose backward compatibility due to design
|
||
// of TSF, so we have to use new TSF interfaces.
|
||
//
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
class CTsfUiLessMode
|
||
{
|
||
protected:
|
||
// Sink receives event notifications
|
||
class CUIElementSink : public ITfUIElementSink, public ITfInputProcessorProfileActivationSink, public ITfCompartmentEventSink
|
||
{
|
||
public:
|
||
CUIElementSink();
|
||
~CUIElementSink();
|
||
|
||
// IUnknown
|
||
STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj);
|
||
STDMETHODIMP_(ULONG) AddRef(void);
|
||
STDMETHODIMP_(ULONG) Release(void);
|
||
|
||
// ITfUIElementSink
|
||
// Notifications for Reading Window events. We could process candidate as well, but we'll use IMM for simplicity sake.
|
||
STDMETHODIMP BeginUIElement(DWORD dwUIElementId, BOOL *pbShow);
|
||
STDMETHODIMP UpdateUIElement(DWORD dwUIElementId);
|
||
STDMETHODIMP EndUIElement(DWORD dwUIElementId);
|
||
|
||
// ITfInputProcessorProfileActivationSink
|
||
// Notification for keyboard input locale change
|
||
STDMETHODIMP OnActivated(DWORD dwProfileType, LANGID langid, REFCLSID clsid, REFGUID catid,
|
||
REFGUID guidProfile, HKL hkl, DWORD dwFlags);
|
||
|
||
// ITfCompartmentEventSink
|
||
// Notification for open mode (toggle state) change
|
||
STDMETHODIMP OnChange(REFGUID rguid);
|
||
|
||
private:
|
||
LONG _cRef;
|
||
};
|
||
|
||
static void MakeReadingInformationString(ITfReadingInformationUIElement* preading);
|
||
static void MakeCandidateStrings(ITfCandidateListUIElement* pcandidate);
|
||
static ITfUIElement* GetUIElement(DWORD dwUIElementId);
|
||
static BOOL GetCompartments( ITfCompartmentMgr** ppcm, ITfCompartment** ppTfOpenMode, ITfCompartment** ppTfConvMode );
|
||
static BOOL SetupCompartmentSinks( BOOL bResetOnly = FALSE, ITfCompartment* pTfOpenMode = NULL, ITfCompartment* ppTfConvMode = NULL );
|
||
|
||
static ITfThreadMgrEx* m_tm;
|
||
static DWORD m_dwUIElementSinkCookie;
|
||
static DWORD m_dwAlpnSinkCookie;
|
||
static DWORD m_dwOpenModeSinkCookie;
|
||
static DWORD m_dwConvModeSinkCookie;
|
||
static CUIElementSink *m_TsfSink;
|
||
static int m_nCandidateRefCount; // Some IME shows multiple candidate lists but the Library doesn't support multiple candidate list.
|
||
// So track open / close events to make sure the candidate list opened last is shown.
|
||
CTsfUiLessMode() {} // this class can't be instanciated
|
||
|
||
public:
|
||
static BOOL SetupSinks();
|
||
static void ReleaseSinks();
|
||
static BOOL CurrentInputLocaleIsIme();
|
||
static void UpdateImeState(BOOL bResetCompartmentEventSink = FALSE);
|
||
static void EnableUiUpdates(bool bEnable);
|
||
};
|
||
|
||
ITfThreadMgrEx* CTsfUiLessMode::m_tm;
|
||
DWORD CTsfUiLessMode::m_dwUIElementSinkCookie = TF_INVALID_COOKIE;
|
||
DWORD CTsfUiLessMode::m_dwAlpnSinkCookie = TF_INVALID_COOKIE;
|
||
DWORD CTsfUiLessMode::m_dwOpenModeSinkCookie = TF_INVALID_COOKIE;
|
||
DWORD CTsfUiLessMode::m_dwConvModeSinkCookie = TF_INVALID_COOKIE;
|
||
CTsfUiLessMode::CUIElementSink* CTsfUiLessMode::m_TsfSink = NULL;
|
||
int CTsfUiLessMode::m_nCandidateRefCount = NULL;
|
||
|
||
// Class to disable Cicero in case ImmDisableTextFrameService() doesn't disable it completely
|
||
class CDisableCicero
|
||
{
|
||
public:
|
||
CDisableCicero() : m_ptim( NULL ), m_bComInit( false )
|
||
{
|
||
}
|
||
~CDisableCicero()
|
||
{
|
||
Uninitialize();
|
||
}
|
||
void Initialize()
|
||
{
|
||
if ( m_bComInit )
|
||
{
|
||
return;
|
||
}
|
||
HRESULT hr;
|
||
hr = CoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
|
||
if ( SUCCEEDED( hr ) )
|
||
{
|
||
m_bComInit = true;
|
||
hr = CoCreateInstance( CLSID_TF_ThreadMgr,
|
||
NULL,
|
||
CLSCTX_INPROC_SERVER,
|
||
__uuidof(ITfThreadMgr),
|
||
(void**)&m_ptim );
|
||
}
|
||
}
|
||
void Uninitialize()
|
||
{
|
||
if ( m_ptim )
|
||
{
|
||
m_ptim->Release();
|
||
m_ptim = NULL;
|
||
}
|
||
if ( m_bComInit )
|
||
CoUninitialize();
|
||
m_bComInit = false;
|
||
}
|
||
|
||
void DisableCiceroOnThisWnd( HWND hwnd )
|
||
{
|
||
if ( m_ptim == NULL )
|
||
return;
|
||
ITfDocumentMgr* pdimPrev; // the dim that is associated previously.
|
||
// Associate NULL dim to the window.
|
||
// When this window gets the focus, Cicero does not work and IMM32 IME
|
||
// will be activated.
|
||
if ( SUCCEEDED( m_ptim->AssociateFocus( hwnd, NULL, &pdimPrev ) ) )
|
||
{
|
||
if ( pdimPrev )
|
||
pdimPrev->Release();
|
||
}
|
||
}
|
||
private:
|
||
ITfThreadMgr* m_ptim;
|
||
bool m_bComInit;
|
||
};
|
||
static CDisableCicero g_disableCicero;
|
||
|
||
/*---------------------------------------------------------------------------*/ /* Public */
|
||
CIME::CIME()
|
||
{
|
||
ms_hWnd = NULL;
|
||
|
||
ms_bCandidateList = false;
|
||
ms_bReadingInformation = false;
|
||
|
||
Clear();
|
||
|
||
m_max = 0;
|
||
m_userMax = 0;
|
||
|
||
m_bOnlyNumberMode = FALSE;
|
||
m_hOrgIMC = NULL;
|
||
|
||
m_bEnablePaste = false;
|
||
m_bUseDefaultIME = false;
|
||
}
|
||
|
||
CIME::~CIME()
|
||
{
|
||
SAFE_FREE_LIBRARY(ms_hCurrentImeDll);
|
||
SAFE_FREE_LIBRARY(ms_hImm32Dll);
|
||
}
|
||
|
||
bool CIME::Initialize(HWND hWnd)
|
||
{
|
||
if(ms_bInitialized)
|
||
return true;
|
||
ms_hWnd = hWnd;
|
||
|
||
g_disableCicero.Initialize();
|
||
|
||
ms_stOSVI.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
|
||
GetVersionExA(&ms_stOSVI);
|
||
|
||
bool bUnicodeImm = false;
|
||
// IMM in NT or Win98 supports Unicode
|
||
if ( ms_stOSVI.dwPlatformId == VER_PLATFORM_WIN32_NT ||
|
||
( ms_stOSVI.dwMajorVersion > 4 ) ||
|
||
( ms_stOSVI.dwMajorVersion == 4 ) && ( ms_stOSVI.dwMinorVersion > 0 ) ) {
|
||
bUnicodeImm = true;
|
||
}
|
||
|
||
// Load ImmLock/ImmUnlock Function Proc
|
||
CHAR szPath[MAX_PATH+1];
|
||
ms_bDisableIMECompletely = false;
|
||
|
||
if(GetSystemDirectoryA(szPath, MAX_PATH+1)) {
|
||
strcat(szPath, "\\imm32.dll");
|
||
ms_hImm32Dll = LoadLibraryA(szPath);
|
||
if(ms_hImm32Dll)
|
||
{
|
||
_ImmLockIMC = (INPUTCONTEXT*(WINAPI *)(HIMC)) GetProcAddress(ms_hImm32Dll, "ImmLockIMC");
|
||
_ImmUnlockIMC = (BOOL(WINAPI *)(HIMC)) GetProcAddress(ms_hImm32Dll, "ImmUnlockIMC");
|
||
_ImmLockIMCC = (LPVOID(WINAPI *)(HIMCC)) GetProcAddress(ms_hImm32Dll, "ImmLockIMCC");
|
||
_ImmUnlockIMCC = (BOOL(WINAPI *)(HIMCC)) GetProcAddress(ms_hImm32Dll, "ImmUnlockIMCC");
|
||
BOOL (WINAPI* _ImmDisableTextFrameService)(DWORD) = (BOOL (WINAPI*)(DWORD))GetProcAddress(ms_hImm32Dll, "ImmDisableTextFrameService");
|
||
if ( _ImmDisableTextFrameService )
|
||
_ImmDisableTextFrameService( (DWORD)-1 );
|
||
} else {
|
||
ms_bDisableIMECompletely = true;
|
||
}
|
||
}
|
||
|
||
ms_bInitialized = true;
|
||
|
||
m_hOrgIMC = ImmGetContext( ms_hWnd );
|
||
ImmReleaseContext( ms_hWnd, m_hOrgIMC );
|
||
|
||
CheckInputLocale();
|
||
ChangeInputLanguageWorker();
|
||
SetSupportLevel(2);
|
||
|
||
ms_bUILessMode = CTsfUiLessMode::SetupSinks() != FALSE;
|
||
CheckToggleState();
|
||
if ( ms_bUILessMode )
|
||
{
|
||
ms_bChineseIME = ( GETPRIMLANG() == LANG_CHINESE ) && CTsfUiLessMode::CurrentInputLocaleIsIme();
|
||
CTsfUiLessMode::UpdateImeState();
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
void CIME::Uninitialize()
|
||
{
|
||
if ( !ms_bInitialized )
|
||
return;
|
||
CTsfUiLessMode::ReleaseSinks();
|
||
if ( ms_hWnd )
|
||
ImmAssociateContext(ms_hWnd, m_hOrgIMC);
|
||
ms_hWnd = NULL;
|
||
m_hOrgIMC = NULL;
|
||
SAFE_FREE_LIBRARY(ms_hCurrentImeDll);
|
||
SAFE_FREE_LIBRARY(ms_hImm32Dll);
|
||
g_disableCicero.Uninitialize();
|
||
ms_bInitialized = false;
|
||
}
|
||
|
||
void CIME::UseDefaultIME()
|
||
{
|
||
m_bUseDefaultIME = true;
|
||
}
|
||
|
||
bool CIME::IsIMEEnabled()
|
||
{
|
||
return ms_bImeEnabled;
|
||
}
|
||
|
||
void CIME::EnableIME(bool bEnable)
|
||
{
|
||
if (!ms_bInitialized || !ms_hWnd)
|
||
return;
|
||
if (ms_bDisableIMECompletely)
|
||
bEnable = false;
|
||
ImmAssociateContext(ms_hWnd, bEnable ? m_hOrgIMC : NULL);
|
||
ms_bImeEnabled = bEnable;
|
||
if (bEnable)
|
||
CheckToggleState();
|
||
CTsfUiLessMode::EnableUiUpdates(bEnable);
|
||
}
|
||
|
||
void CIME::DisableIME()
|
||
{
|
||
EnableIME(false);
|
||
}
|
||
|
||
void CIME::EnableCaptureInput()
|
||
{
|
||
ms_bCaptureInput = true;
|
||
}
|
||
|
||
void CIME::DisableCaptureInput()
|
||
{
|
||
ms_bCaptureInput = false;
|
||
}
|
||
|
||
bool CIME::IsCaptureEnabled()
|
||
{
|
||
return ms_bCaptureInput;
|
||
}
|
||
|
||
void CIME::Clear()
|
||
{
|
||
ms_lastpos = 0;
|
||
ms_curpos = 0;
|
||
|
||
ms_compLen = 0;
|
||
ms_ulbegin = 0;
|
||
ms_ulend = 0;
|
||
}
|
||
|
||
int CIME::GetReading(std::string & rstrText)
|
||
{
|
||
char reading[IMEREADING_MAXLEN];
|
||
|
||
if(ms_wstrReading.size() == 0)
|
||
return 0;
|
||
int readingLen = WideCharToMultiByte(ms_uOutputCodePage, 0, &ms_wstrReading[0], ms_wstrReading.size(), reading, sizeof(reading), NULL, NULL);
|
||
|
||
rstrText.append(GetCodePageText());
|
||
rstrText.append(reading, reading + readingLen);
|
||
|
||
return rstrText.size();
|
||
}
|
||
|
||
int CIME::GetReadingError()
|
||
{
|
||
return ms_iReadingError;
|
||
}
|
||
|
||
void CIME::SetMax(int iMax)
|
||
{
|
||
m_max = iMax;
|
||
}
|
||
|
||
void CIME::SetUserMax(int iMax)
|
||
{
|
||
m_userMax = iMax;
|
||
}
|
||
|
||
void CIME::SetText(const char* szText, int len)
|
||
{
|
||
ms_compLen = 0;
|
||
ms_ulbegin = 0;
|
||
ms_ulend = 0;
|
||
|
||
const char* begin = szText;
|
||
const char* end = begin + len;
|
||
const char* iter = FindToken(begin, end);
|
||
|
||
int m_wTextLen = sizeof(m_wText)/sizeof(wchar_t);
|
||
|
||
ms_lastpos = MultiByteToWideChar(ms_uInputCodePage, 0, begin, iter-begin, m_wText, m_wTextLen);
|
||
|
||
if (iter < end)
|
||
ms_lastpos += MultiByteToWideChar(ReadToken(iter), 0, (iter+5), end-(iter+5), m_wText+ms_lastpos, m_wTextLen-ms_lastpos);
|
||
|
||
ms_curpos = min(ms_curpos, ms_lastpos);
|
||
}
|
||
|
||
int CIME::GetText(std::string & rstrText, bool addCodePage)
|
||
{
|
||
int outCodePage = ms_uOutputCodePage;
|
||
int dataCodePage;
|
||
switch (outCodePage)
|
||
{
|
||
//case 1256: // ARABIC
|
||
case 1268: // VIETNAM
|
||
dataCodePage = CP_UTF8;
|
||
break;
|
||
default:
|
||
dataCodePage = outCodePage;
|
||
}
|
||
|
||
int len = 0;
|
||
char text[IMESTR_MAXLEN];
|
||
|
||
len += WideCharToMultiByte(dataCodePage, 0, m_wText, ms_curpos, text, sizeof(text)-len, NULL, NULL);
|
||
len += WideCharToMultiByte(dataCodePage, 0, m_wszComposition, ms_compLen, text+len, sizeof(text)-len, NULL, NULL);
|
||
len += WideCharToMultiByte(dataCodePage, 0, m_wText+ms_curpos, ms_lastpos-ms_curpos, text+len, sizeof(text)-len, NULL, NULL);
|
||
|
||
int i;
|
||
for(i=0; i<len; ++i)
|
||
if((BYTE)text[i] > 0x7F) break;
|
||
|
||
if(i == len)
|
||
{
|
||
rstrText.append(text, text+len);
|
||
}
|
||
else
|
||
{
|
||
rstrText.append(text, text+i);
|
||
|
||
//if (addCodePage)
|
||
// rstrText.append(GetCodePageText());
|
||
|
||
rstrText.append(text+i, text+len);
|
||
}
|
||
|
||
return rstrText.size();
|
||
}
|
||
|
||
const char* CIME::GetCodePageText()
|
||
{
|
||
static char szCodePage[16];
|
||
|
||
const int defCodePage = GetDefaultCodePage();
|
||
const int outCodePage = ms_uOutputCodePage;
|
||
|
||
if (outCodePage != defCodePage)
|
||
{
|
||
sprintf(szCodePage, "@%04d", outCodePage);
|
||
}
|
||
else
|
||
{
|
||
szCodePage[0] = 0;
|
||
}
|
||
|
||
return szCodePage;
|
||
}
|
||
|
||
int CIME::GetCodePage()
|
||
{
|
||
return ms_uOutputCodePage;
|
||
}
|
||
|
||
int CIME::GetCandidatePageCount()
|
||
{
|
||
return ms_dwCandidatePageSize;
|
||
}
|
||
|
||
int CIME::GetCandidateCount()
|
||
{
|
||
return ms_dwCandidateCount;
|
||
}
|
||
|
||
int CIME::GetCandidate(DWORD index, std::string & rstrText)
|
||
{
|
||
if(index >= MAX_CANDLIST)
|
||
return 0;
|
||
|
||
LPCWSTR wszText = ms_wszCandidate[index];
|
||
if(wszText == NULL)
|
||
return 0;
|
||
|
||
int wTextLen = wcslen(wszText);
|
||
if(wTextLen == 0)
|
||
return 0;
|
||
|
||
char text[IMESTR_MAXLEN];
|
||
int len = ::WideCharToMultiByte(CP_UTF8, 0, wszText, wTextLen, text, sizeof(text), 0, 0);
|
||
|
||
rstrText.append("@9999");
|
||
rstrText.append(text, text+len);
|
||
|
||
return wTextLen;
|
||
}
|
||
|
||
int CIME::GetCandidateSelection()
|
||
{
|
||
return ms_dwCandidateSelection;
|
||
}
|
||
|
||
void CIME::SetInputMode(DWORD dwMode)
|
||
{
|
||
HIMC hImc = ImmGetContext(ms_hWnd);
|
||
|
||
ImmSetConversionStatus(hImc, dwMode, IME_SMODE_AUTOMATIC);
|
||
|
||
ImmReleaseContext(ms_hWnd, hImc);
|
||
}
|
||
|
||
DWORD CIME::GetInputMode()
|
||
{
|
||
DWORD dwCMode, dwSMode;
|
||
|
||
HIMC hImc = ImmGetContext(ms_hWnd);
|
||
|
||
ImmGetConversionStatus(hImc, &dwCMode, &dwSMode);
|
||
|
||
ImmReleaseContext(ms_hWnd, hImc);
|
||
|
||
return dwCMode;
|
||
}
|
||
|
||
void CIME::SetNumberMode()
|
||
{
|
||
m_bOnlyNumberMode = TRUE;
|
||
}
|
||
|
||
void CIME::SetStringMode()
|
||
{
|
||
m_bOnlyNumberMode = FALSE;
|
||
}
|
||
|
||
void CIME::AddExceptKey(wchar_t key)
|
||
{
|
||
m_exceptKey.push_back(key);
|
||
}
|
||
|
||
void CIME::ClearExceptKey()
|
||
{
|
||
m_exceptKey.clear();
|
||
}
|
||
|
||
bool CIME::__IsWritable(wchar_t key)
|
||
{
|
||
if ( m_exceptKey.end() == std::find(m_exceptKey.begin(),m_exceptKey.end(),key) )
|
||
return true;
|
||
else
|
||
return false;
|
||
}
|
||
|
||
void CIME::EnablePaste(bool bFlag)
|
||
{
|
||
m_bEnablePaste = bFlag;
|
||
}
|
||
|
||
void CIME::PasteTextFromClipBoard()
|
||
{
|
||
if (!m_bEnablePaste)
|
||
return;
|
||
|
||
if (!OpenClipboard(NULL))
|
||
return;
|
||
|
||
HANDLE handle = GetClipboardData(CF_TEXT);
|
||
char * buffer = (char*)GlobalLock(handle);
|
||
std::string strClipboard = buffer;
|
||
GlobalUnlock(handle);
|
||
CloseClipboard();
|
||
|
||
if (strClipboard.empty())
|
||
return;
|
||
|
||
const char* begin = strClipboard.c_str();
|
||
const char* end = begin + strClipboard.length();
|
||
wchar_t m_wText[IMESTR_MAXLEN];
|
||
int wstrLen = MultiByteToWideChar(ms_uInputCodePage, 0, begin, end-begin, m_wText, IMESTR_MAXLEN);
|
||
|
||
InsertString(m_wText, wstrLen);
|
||
if(ms_pEvent)
|
||
ms_pEvent->OnUpdate();
|
||
}
|
||
|
||
void CIME::FinalizeString(bool bSend)
|
||
{
|
||
HIMC himc;
|
||
static bool s_bProcessing = false; // to avoid infinite recursion
|
||
if ( !ms_bInitialized || s_bProcessing || NULL == ( himc = ImmGetContext( ms_hWnd ) ) )
|
||
return;
|
||
s_bProcessing = true;
|
||
|
||
if (ms_dwIMELevel == 2 && bSend)
|
||
{
|
||
//// Send composition string to app.
|
||
//LONG lRet = lstrlenW( m_wszComposition );
|
||
////assert( lRet >= 2);
|
||
//// In case of CHT IME, don't send the trailing double byte space, if it exists.
|
||
//if ( GETLANG() == LANG_CHT && (lRet >= 1)
|
||
// && m_wszComposition[lRet - 1] == 0x3000 )
|
||
//{
|
||
// lRet--;
|
||
//}
|
||
//SendCompString();
|
||
}
|
||
|
||
//InitCompStringData();
|
||
// clear composition string in IME
|
||
ImmNotifyIME(himc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
|
||
if (ms_bUILessMode)
|
||
{
|
||
// For some reason ImmNotifyIME doesn't work on DaYi and Array CHT IMEs. Cancel composition string by setting zero-length string.
|
||
ImmSetCompositionStringW(himc, SCS_SETSTR, L"", sizeof(wchar_t), L"", sizeof(wchar_t));
|
||
}
|
||
// the following line is necessary as Korean IME doesn't close cand list when comp string is cancelled.
|
||
ImmNotifyIME( himc, NI_CLOSECANDIDATE, 0, 0 );
|
||
ImmReleaseContext(ms_hWnd, himc);
|
||
// Zooty2 RAID #4759: Sometimes application doesn't receive IMN_CLOSECANDIDATE on Alt+Tab
|
||
// So the same code for IMN_CLOSECANDIDATE is replicated here.
|
||
CloseCandidateList();
|
||
s_bProcessing = false;
|
||
}
|
||
|
||
int CIME::GetCompLen()
|
||
{
|
||
return ms_compLen;
|
||
}
|
||
|
||
int CIME::GetULBegin()
|
||
{
|
||
return ms_ulbegin;
|
||
}
|
||
|
||
int CIME::GetULEnd()
|
||
{
|
||
return ms_ulend;
|
||
}
|
||
|
||
void CIME::CloseCandidateList()
|
||
{
|
||
ms_bCandidateList = false;
|
||
ms_dwCandidateCount = 0;
|
||
memset(&ms_wszCandidate, 0, sizeof(ms_wszCandidate));
|
||
if(ms_pEvent)
|
||
ms_pEvent->OnCloseCandidateList();
|
||
}
|
||
|
||
void CIME::CloseReadingInformation()
|
||
{
|
||
CIME::ms_bReadingInformation = false;
|
||
if(CIME::ms_pEvent)
|
||
CIME::ms_pEvent->OnCloseReadingWnd();
|
||
}
|
||
|
||
void CIME::ChangeInputLanguage()
|
||
{
|
||
UINT uLanguage = (UINT) GETLANG();
|
||
CheckToggleState();
|
||
ChangeInputLanguageWorker();
|
||
if (uLanguage != GETLANG())
|
||
{
|
||
// Korean IME always uses level 3 support.
|
||
// Other languages use the level that is specified by ImeUi_SetSupportLevel()
|
||
SetSupportLevel( ( GETPRIMLANG() == LANG_KOREAN ) ? 3 : ms_dwIMELevelSaved );
|
||
}
|
||
|
||
if(ms_pEvent)
|
||
ms_pEvent->OnChangeCodePage();
|
||
|
||
//HWND hwndImeDef = ImmGetDefaultIMEWnd(ms_hWnd);
|
||
//if ( hwndImeDef )
|
||
//{
|
||
// // Fix for Zooty #3995: prevent CHT IME toobar from showing up
|
||
// SendMessageA(hwndImeDef, WM_IME_CONTROL, IMC_OPENSTATUSWINDOW, 0);
|
||
// SendMessageA(hwndImeDef, WM_IME_CONTROL, IMC_CLOSESTATUSWINDOW, 0);
|
||
//}
|
||
}
|
||
|
||
void CIME::ChangeInputLanguageWorker()
|
||
{
|
||
if ( !ms_bUILessMode )
|
||
ms_iCandListIndexBase = ( ms_hklCurrent == _CHT_HKL_DAYI ) ? 0 : 1;
|
||
SetupImeApi();
|
||
}
|
||
|
||
void CIME::SetSupportLevel( DWORD dwImeLevel )
|
||
{
|
||
if ( dwImeLevel < 2 || 3 < dwImeLevel )
|
||
return;
|
||
if ( GETPRIMLANG() == LANG_KOREAN )
|
||
{
|
||
dwImeLevel = 3;
|
||
}
|
||
ms_dwIMELevel = dwImeLevel;
|
||
// cancel current composition string.
|
||
FinalizeString();
|
||
//SetCompStringColor();
|
||
}
|
||
|
||
/*---------------------------------------------------------------------------*/ /* Protected */
|
||
void CIME::IncCurPos()
|
||
{
|
||
if (ms_curpos < ms_lastpos)
|
||
{
|
||
int pos = FindColorTagEndPosition(m_wText + ms_curpos, ms_lastpos - ms_curpos);
|
||
|
||
if (pos > 0)
|
||
ms_curpos = min(ms_lastpos, max(0, ms_curpos + (pos + 1)));
|
||
else
|
||
++ms_curpos;
|
||
//++ms_curpos;
|
||
}
|
||
}
|
||
|
||
void CIME::DecCurPos()
|
||
{
|
||
if (ms_curpos > 0)
|
||
{
|
||
int pos = FindColorTagStartPosition(m_wText + ms_curpos - 1, ms_curpos);
|
||
|
||
if (pos > 0)
|
||
ms_curpos = min(ms_lastpos, max(0, ms_curpos - (pos + 1)));
|
||
else
|
||
--ms_curpos;
|
||
//--ms_curpos;
|
||
}
|
||
}
|
||
|
||
int CIME::GetCurPos()
|
||
{
|
||
int pos = GetTextTagOutputLen(m_wText, ms_curpos);
|
||
return pos;
|
||
//return ms_curpos;
|
||
}
|
||
|
||
void CIME::SetCurPos(int offset)
|
||
{
|
||
if (offset < 0 || offset > ms_lastpos)
|
||
{
|
||
ms_curpos = ms_lastpos;
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
// offset<65><74> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ؽ<EFBFBD>Ʈ<EFBFBD><C6AE> <20><>ġ<EFBFBD><C4A1> <20>´<EFBFBD>. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ؾ<EFBFBD><D8BE><EFBFBD>.
|
||
//ms_curpos = min(ms_lastpos, offset);
|
||
ms_curpos = min(ms_lastpos, GetTextTagInternalPosFromRenderPos(m_wText, ms_lastpos, offset));
|
||
}
|
||
}
|
||
|
||
void CIME::DelCurPos()
|
||
{
|
||
if (ms_curpos < ms_lastpos)
|
||
{
|
||
int eraseCount = FindColorTagEndPosition(m_wText + ms_curpos, ms_lastpos - ms_curpos) + 1;
|
||
wcscpy(m_wText + ms_curpos, m_wText + ms_curpos + eraseCount);
|
||
ms_lastpos -= eraseCount;
|
||
ms_curpos = min(ms_lastpos, ms_curpos);
|
||
}
|
||
}
|
||
|
||
void CIME::PasteString(const char * str)
|
||
{
|
||
const char * begin = str;
|
||
const char * end = str + strlen(str);
|
||
wchar_t m_wText[IMESTR_MAXLEN];
|
||
int wstrLen = MultiByteToWideChar(ms_uInputCodePage, 0, begin, end - begin, m_wText, IMESTR_MAXLEN);
|
||
InsertString(m_wText, wstrLen);
|
||
if(ms_pEvent)
|
||
ms_pEvent->OnUpdate();
|
||
}
|
||
|
||
/*---------------------------------------------------------------------------*/ /* Private */
|
||
void CIME::InsertString(wchar_t* wString, int iSize)
|
||
{
|
||
if (IsMax(wString, iSize))
|
||
return;
|
||
|
||
if (ms_curpos < ms_lastpos)
|
||
memmove(m_wText+ms_curpos+iSize, m_wText+ms_curpos, sizeof(wchar_t)*(ms_lastpos-ms_curpos));
|
||
|
||
memcpy(m_wText+ms_curpos, wString, sizeof(wchar_t)*iSize);
|
||
|
||
ms_curpos += iSize;
|
||
ms_lastpos += iSize;
|
||
}
|
||
|
||
void CIME::OnChar(wchar_t c)
|
||
{
|
||
if (m_bOnlyNumberMode)
|
||
if (!iswdigit(c))
|
||
return;
|
||
|
||
if (!__IsWritable(c))
|
||
return;
|
||
|
||
InsertString(&c, 1);
|
||
}
|
||
|
||
UINT CIME::GetCodePageFromLang(LANGID langid)
|
||
{
|
||
unsigned pri_langid = PRIMARYLANGID(langid);
|
||
switch (pri_langid)
|
||
{
|
||
case LANG_JAPANESE:
|
||
//setlocale(LC_ALL, ".932");
|
||
return 932;
|
||
case LANG_KOREAN:
|
||
//setlocale(LC_ALL, ".949");
|
||
return 949;
|
||
case LANG_CHINESE:
|
||
{
|
||
switch (SUBLANGID(langid))
|
||
{
|
||
case SUBLANG_CHINESE_SIMPLIFIED:
|
||
case SUBLANG_CHINESE_SINGAPORE:
|
||
//setlocale(LC_ALL, ".936");
|
||
return 936;
|
||
case SUBLANG_CHINESE_TRADITIONAL:
|
||
case SUBLANG_CHINESE_MACAU:
|
||
case SUBLANG_CHINESE_HONGKONG:
|
||
//setlocale(LC_ALL, ".950");
|
||
return 950;
|
||
}
|
||
}
|
||
//setlocale(LC_ALL, ".936");
|
||
return 936;
|
||
case LANG_ARABIC:
|
||
return 1256;
|
||
case LANG_GREEK:
|
||
//setlocale(LC_ALL, ".1253");
|
||
return 1253;
|
||
case LANG_TURKISH:
|
||
//setlocale(LC_ALL, ".1254");
|
||
return 1254;
|
||
case LANG_HEBREW:
|
||
//setlocale(LC_ALL, ".1255");
|
||
return 1255;
|
||
case LANG_ESTONIAN:
|
||
case LANG_LATVIAN:
|
||
case LANG_LITHUANIAN:
|
||
//setlocale(LC_ALL, ".1257");
|
||
return 1257;
|
||
case LANG_VIETNAMESE:
|
||
return 1258;
|
||
case LANG_THAI:
|
||
//setlocale(LC_ALL, ".874");
|
||
return 874;
|
||
case LANG_CZECH:
|
||
case LANG_HUNGARIAN:
|
||
case LANG_POLISH:
|
||
case LANG_CROATIAN:
|
||
case LANG_MACEDONIAN:
|
||
case LANG_ROMANIAN:
|
||
case LANG_SLOVAK:
|
||
case LANG_SLOVENIAN:
|
||
//setlocale(LC_ALL, ".1250");
|
||
return 1250;
|
||
case LANG_RUSSIAN:
|
||
case LANG_BELARUSIAN:
|
||
case LANG_BULGARIAN:
|
||
case LANG_UKRAINIAN:
|
||
return 1251;
|
||
case LANG_GERMAN:
|
||
//_wsetlocale(LC_ALL, ".1252");
|
||
return 1252;
|
||
default:
|
||
//TraceError("UNKNOWN IME[%d]\n", langid);
|
||
//setlocale(LC_ALL, ".949");
|
||
return 1252;
|
||
}
|
||
}
|
||
|
||
void CIME::CompositionProcess(HIMC hImc)
|
||
{
|
||
ms_compLen = ImmGetCompositionStringW(hImc, GCS_COMPSTR, m_wszComposition, sizeof(m_wszComposition))/sizeof(wchar_t);
|
||
|
||
//OutputDebugStringW( L"Composition: " );
|
||
//OutputDebugStringW( m_wszComposition );
|
||
//for( int i=0; i < (int) ms_compLen * 2; i++ ) {
|
||
// LPBYTE pbyData = (LPBYTE) m_wszComposition;
|
||
// pbyData += i;
|
||
// WCHAR tszName[32];
|
||
|
||
// swprintf_s( tszName, L"%02X ", (unsigned int) *pbyData );
|
||
// OutputDebugStringW( tszName );
|
||
//}
|
||
//OutputDebugStringW( L"\n" );
|
||
|
||
if (IsMax(m_wszComposition, ms_compLen))
|
||
{
|
||
ImmNotifyIME(hImc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
|
||
ms_compLen = 0;
|
||
}
|
||
}
|
||
|
||
void CIME::CompositionProcessBuilding(HIMC hImc)
|
||
{
|
||
int textLen = WideCharToMultiByte(ms_uOutputCodePage, 0, m_wText, ms_lastpos, 0, 0, NULL, NULL);
|
||
|
||
if (textLen >= m_max)
|
||
{
|
||
ImmNotifyIME(hImc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
|
||
ms_compLen = 0;
|
||
return;
|
||
}
|
||
|
||
ms_compLen = ImmGetCompositionStringW(hImc, GCS_COMPSTR, m_wszComposition, sizeof(m_wszComposition))/sizeof(wchar_t);
|
||
|
||
//OutputDebugStringW( L"Composition: " );
|
||
//OutputDebugStringW( m_wszComposition );
|
||
//for( int i=0; i < (int) ms_compLen * 2; i++ ) {
|
||
// LPBYTE pbyData = (LPBYTE) m_wszComposition;
|
||
// pbyData += i;
|
||
// WCHAR tszName[32];
|
||
|
||
// swprintf_s( tszName, L"%02X ", (unsigned int) *pbyData );
|
||
// OutputDebugStringW( tszName );
|
||
//}
|
||
//OutputDebugStringW( L"\n" );
|
||
}
|
||
|
||
void CIME::ResultProcess(HIMC hImc)
|
||
{
|
||
wchar_t temp[IMESTR_MAXLEN];
|
||
|
||
int len = ImmGetCompositionStringW(hImc, GCS_RESULTSTR, temp, sizeof(temp))/sizeof(wchar_t);
|
||
|
||
if (len <= 0)
|
||
return;
|
||
|
||
InsertString(temp, len);
|
||
}
|
||
|
||
void CIME::AttributeProcess(HIMC hImc)
|
||
{
|
||
BYTE attribute[IMESTR_MAXLEN];
|
||
LONG attributeLen = ImmGetCompositionStringW(hImc, GCS_COMPATTR, &attribute, sizeof(attribute)) / sizeof(BYTE);
|
||
|
||
int start,end;
|
||
for(start=0; start<attributeLen; ++start) if(attribute[start]==ATTR_TARGET_CONVERTED || attribute[start]==ATTR_TARGET_NOTCONVERTED) break;
|
||
for(end=start; end<attributeLen; ++end) if(attribute[end]!=attribute[start]) break;
|
||
|
||
ms_ulbegin = start;
|
||
ms_ulend = end;
|
||
}
|
||
|
||
void CIME::CandidateProcess(HIMC hImc)
|
||
{
|
||
std::vector<BYTE> abyCandidate;
|
||
DWORD dwCandidateLen = ImmGetCandidateListW(hImc, 0, NULL, 0);
|
||
abyCandidate.resize(dwCandidateLen);
|
||
if(dwCandidateLen > 0) {
|
||
ms_bCandidateList = true;
|
||
|
||
CANDIDATELIST* lpCandidateList = (CANDIDATELIST*)(&abyCandidate[0]);
|
||
dwCandidateLen = ImmGetCandidateListW(hImc, 0, lpCandidateList, dwCandidateLen);
|
||
|
||
ms_dwCandidateSelection = lpCandidateList->dwSelection;
|
||
ms_dwCandidateCount = lpCandidateList->dwCount;
|
||
|
||
int iStartOfPage = 0;
|
||
|
||
if( GETLANG() == LANG_CHS ) {
|
||
// MSPY (CHS IME) has variable number of candidates in candidate window find where current page starts, and the size of current page
|
||
const int maxCandChar = 18 * (3 - sizeof(TCHAR));
|
||
UINT cChars = 0;
|
||
UINT i;
|
||
for (i = 0; i < ms_dwCandidateCount; i++)
|
||
{
|
||
UINT uLen = lstrlenW((LPWSTR)((DWORD)lpCandidateList + lpCandidateList->dwOffset[i])) + (3 - sizeof(WCHAR));
|
||
if (uLen + cChars > maxCandChar)
|
||
{
|
||
if (i > ms_dwCandidateSelection)
|
||
{
|
||
break;
|
||
}
|
||
iStartOfPage = i;
|
||
cChars = uLen;
|
||
}
|
||
else
|
||
{
|
||
cChars += uLen;
|
||
}
|
||
}
|
||
ms_dwCandidatePageSize = i - iStartOfPage;
|
||
} else {
|
||
ms_dwCandidatePageSize = MIN( lpCandidateList->dwPageSize, MAX_CANDLIST );
|
||
iStartOfPage = ms_bUILessMode ? lpCandidateList->dwPageStart : (ms_dwCandidateSelection / (MAX_CANDLIST - 1)) * (MAX_CANDLIST - 1);
|
||
}
|
||
|
||
ms_dwCandidateSelection = ( GETLANG() == LANG_CHS && !GetImeId() ) ? (DWORD)-1 : ms_dwCandidateSelection - iStartOfPage;
|
||
|
||
//printf( "SEL: %d, START: %d, PAGED: %d\n", ms_dwCandidateSelection, iStartOfPage, ms_dwCandidatePageSize );
|
||
memset(&ms_wszCandidate, 0, sizeof(ms_wszCandidate));
|
||
for(UINT i = iStartOfPage, j = 0; (DWORD)i < lpCandidateList->dwCount && j < ms_dwCandidatePageSize; i++, j++) {
|
||
wcscpy( ms_wszCandidate[j], (LPWSTR)( (DWORD)lpCandidateList + lpCandidateList->dwOffset[i] ) );
|
||
}
|
||
|
||
// don't display selection in candidate list in case of Korean and old Chinese IME.
|
||
if ( GETPRIMLANG() == LANG_KOREAN || GETLANG() == LANG_CHT && !GetImeId() )
|
||
ms_dwCandidateSelection = (DWORD) -1;
|
||
}
|
||
}
|
||
|
||
void CIME::ReadingProcess(HIMC hImc)
|
||
{
|
||
if (!ms_adwId[0])
|
||
{
|
||
return;
|
||
}
|
||
|
||
DWORD dwErr = 0;
|
||
|
||
if (_GetReadingString)
|
||
{
|
||
UINT uMaxUiLen;
|
||
BOOL bVertical;
|
||
// Obtain the reading string size
|
||
int wstrLen = _GetReadingString(hImc, 0, NULL, (PINT)&dwErr, &bVertical, &uMaxUiLen);
|
||
|
||
if(wstrLen == 0) {
|
||
ms_wstrReading.resize(0);
|
||
} else {
|
||
wchar_t *wstr = (wchar_t*)alloca(sizeof(wchar_t) * wstrLen);
|
||
_GetReadingString(hImc, wstrLen, wstr, (PINT)&dwErr, &bVertical, &uMaxUiLen);
|
||
ms_wstrReading.assign(wstr, wstr+wstrLen);
|
||
}
|
||
|
||
ms_bHorizontalReading = (bVertical == 0);
|
||
|
||
} else {
|
||
|
||
// IMEs that doesn't implement Reading String API
|
||
wchar_t* temp = NULL;
|
||
DWORD tempLen = 0;
|
||
bool bUnicodeIme = false;
|
||
INPUTCONTEXT *lpIC = _ImmLockIMC(hImc);
|
||
|
||
if (lpIC == NULL)
|
||
{
|
||
temp = NULL;
|
||
tempLen = 0;
|
||
}
|
||
else
|
||
{
|
||
LPBYTE p = 0;
|
||
switch(ms_adwId[0])
|
||
{
|
||
case IMEID_CHT_VER42: // New(Phonetic/ChanJie)IME98 : 4.2.x.x // Win98
|
||
case IMEID_CHT_VER43: // New(Phonetic/ChanJie)IME98a : 4.3.x.x // WinMe, Win2k
|
||
case IMEID_CHT_VER44: // New ChanJie IME98b : 4.4.x.x // WinXP
|
||
p = *(LPBYTE *)((LPBYTE)_ImmLockIMCC(lpIC->hPrivate) + 24);
|
||
if (!p) break;
|
||
tempLen = *(DWORD *)(p + 7 * 4 + 32 * 4);
|
||
dwErr = *(DWORD *)(p + 8 * 4 + 32 * 4);
|
||
temp = (wchar_t *)(p + 56);
|
||
bUnicodeIme = true;
|
||
break;
|
||
|
||
case IMEID_CHT_VER50: // 5.0.x.x // WinME
|
||
p = *(LPBYTE *)((LPBYTE)_ImmLockIMCC(lpIC->hPrivate) + 3 * 4);
|
||
if(!p) break;
|
||
p = *(LPBYTE *)((LPBYTE)p + 1*4 + 5*4 + 4*2);
|
||
if(!p) break;
|
||
tempLen = *(DWORD *)(p + 1*4 + (16*2+2*4) + 5*4 + 16);
|
||
dwErr = *(DWORD *)(p + 1*4 + (16*2+2*4) + 5*4 + 16 + 1*4);
|
||
temp = (wchar_t *)(p + 1*4 + (16*2+2*4) + 5*4);
|
||
bUnicodeIme = false;
|
||
break;
|
||
|
||
case IMEID_CHT_VER51: // 5.1.x.x // IME2002(w/OfficeXP)
|
||
case IMEID_CHT_VER52: // 5.2.x.x // (w/whistler)
|
||
case IMEID_CHS_VER53: // 5.3.x.x // SCIME2k or MSPY3 (w/OfficeXP and Whistler)
|
||
p = *(LPBYTE *)((LPBYTE)_ImmLockIMCC(lpIC->hPrivate) + 4);
|
||
if(!p) break;
|
||
p = *(LPBYTE *)((LPBYTE)p + 1*4 + 5*4);
|
||
if(!p) break;
|
||
tempLen = *(DWORD *)(p + 1*4 + (16*2+2*4) + 5*4 + 16 * 2);
|
||
dwErr = *(DWORD *)(p + 1*4 + (16*2+2*4) + 5*4 + 16 * 2 + 1*4);
|
||
temp = (wchar_t *) (p + 1*4 + (16*2+2*4) + 5*4);
|
||
bUnicodeIme = true;
|
||
break;
|
||
|
||
// the code tested only with Win 98 SE (MSPY 1.5/ ver 4.1.0.21)
|
||
case IMEID_CHS_VER41:
|
||
{
|
||
int nOffset;
|
||
nOffset = (ms_adwId[1] >= 0x00000002) ? 8 : 7;
|
||
|
||
p = *(LPBYTE *)((LPBYTE)_ImmLockIMCC(lpIC->hPrivate) + nOffset * 4);
|
||
if(!p) break;
|
||
tempLen = *(DWORD *)(p + 7*4 + 16*2*4);
|
||
dwErr = *(DWORD *)(p + 8*4 + 16*2*4);
|
||
dwErr = min(dwErr, tempLen);
|
||
temp = (wchar_t *)(p + 6*4 + 16*2*1);
|
||
bUnicodeIme = true;
|
||
}
|
||
break;
|
||
|
||
case IMEID_CHS_VER42: // 4.2.x.x // SCIME98 or MSPY2 (w/Office2k, Win2k, WinME, etc)
|
||
{
|
||
OSVERSIONINFOA osi;
|
||
osi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
|
||
GetVersionExA(&osi);
|
||
|
||
int nTcharSize = (osi.dwPlatformId == VER_PLATFORM_WIN32_NT) ? sizeof(wchar_t) : sizeof(char);
|
||
p = *(LPBYTE *)((LPBYTE)_ImmLockIMCC(lpIC->hPrivate) + 1*4 + 1*4 + 6*4);
|
||
if(!p) break;
|
||
tempLen = *(DWORD *)(p + 1*4 + (16*2+2*4) + 5*4 + 16 * nTcharSize);
|
||
dwErr = *(DWORD *)(p + 1*4 + (16*2+2*4) + 5*4 + 16 * nTcharSize + 1*4);
|
||
temp = (wchar_t *) (p + 1*4 + (16*2+2*4) + 5*4);
|
||
bUnicodeIme = (osi.dwPlatformId == VER_PLATFORM_WIN32_NT) ? true : false;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
temp = NULL;
|
||
tempLen = 0;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if(tempLen == 0) {
|
||
ms_wstrReading.resize(0);
|
||
} else {
|
||
if(bUnicodeIme) {
|
||
ms_wstrReading.assign(temp, temp+tempLen);
|
||
} else {
|
||
int wstrLen = MultiByteToWideChar(ms_uInputCodePage, 0, (char*)temp, tempLen, NULL, 0);
|
||
wchar_t* wstr = (wchar_t*)alloca(sizeof(wchar_t)*wstrLen);
|
||
MultiByteToWideChar(ms_uInputCodePage, 0, (char*)temp, tempLen, wstr, wstrLen);
|
||
ms_wstrReading.assign(wstr, wstr+wstrLen);
|
||
}
|
||
}
|
||
|
||
_ImmUnlockIMCC(lpIC->hPrivate);
|
||
_ImmUnlockIMC(hImc);
|
||
|
||
ms_bHorizontalReading = GetReadingWindowOrientation();
|
||
}
|
||
if (ms_wstrReading.size()) {
|
||
ms_bReadingInformation = true;
|
||
if(ms_pEvent)
|
||
ms_pEvent->OnOpenReadingWnd();
|
||
} else {
|
||
CloseReadingInformation();
|
||
}
|
||
}
|
||
|
||
bool CIME::IsMax(const wchar_t* wInput, int len)
|
||
{
|
||
if (ms_lastpos + len > IMESTR_MAXLEN)
|
||
return true;
|
||
|
||
int textLen = WideCharToMultiByte(ms_uOutputCodePage, 0, m_wText, ms_lastpos, 0, 0, NULL, NULL);
|
||
int inputLen = WideCharToMultiByte(ms_uOutputCodePage, 0, wInput, len, 0, 0, NULL, NULL);
|
||
//return textLen + inputLen > m_max;
|
||
|
||
if (textLen + inputLen > m_max)
|
||
return true;
|
||
else if (m_userMax != 0 && m_max != m_userMax)
|
||
{
|
||
std::wstring str = GetTextTagOutputString(m_wText, ms_lastpos);
|
||
std::wstring input = GetTextTagOutputString(wInput, len);
|
||
int textLen = WideCharToMultiByte(ms_uOutputCodePage, 0, str.c_str(), str.length(), 0, 0, NULL, NULL);
|
||
int inputLen = WideCharToMultiByte(ms_uOutputCodePage, 0, input.c_str(), input.length(), 0, 0, NULL, NULL);
|
||
return textLen + inputLen > m_userMax;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
DWORD CIME::GetImeId( UINT uIndex )
|
||
{
|
||
static HKL hklPrev = 0;
|
||
char szTmp[1024];
|
||
|
||
if (uIndex >= COUNTOF(ms_adwId))
|
||
return 0;
|
||
HKL hkl = ms_hklCurrent;
|
||
if(hklPrev == hkl)
|
||
return ms_adwId[uIndex];
|
||
hklPrev = hkl;
|
||
|
||
DWORD dwLang = ((DWORD)hkl & 0xffff);
|
||
|
||
if ( ms_bUILessMode && GETLANG() == LANG_CHT ) {
|
||
// In case of Vista, artifitial value is returned so that it's not considered as older IME.
|
||
ms_adwId[0] = IMEID_CHT_VER_VISTA;
|
||
ms_adwId[1] = 0;
|
||
return ms_adwId[0];
|
||
}
|
||
|
||
if (!((ms_hklCurrent == _CHT_HKL_NEW_PHONETIC) || (ms_hklCurrent == _CHT_HKL_NEW_CHANG_JIE) || (ms_hklCurrent == _CHT_HKL_NEW_QUICK) || (ms_hklCurrent == _CHT_HKL_HK_CANTONESE) || (ms_hklCurrent == _CHS_HKL))) {
|
||
ms_adwId[0] = ms_adwId[1] = 0;
|
||
return 0;
|
||
}
|
||
|
||
if (!ImmGetIMEFileNameA(ms_hklCurrent, szTmp, (sizeof(szTmp) / sizeof(szTmp[0])) - 1)) {
|
||
ms_adwId[0] = ms_adwId[1] = 0;
|
||
return 0;
|
||
}
|
||
|
||
if (!_GetReadingString)
|
||
{
|
||
if ((CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTmp, -1, CHT_IMEFILENAME1, -1) != CSTR_EQUAL) &&
|
||
(CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTmp, -1, CHT_IMEFILENAME2, -1) != CSTR_EQUAL) &&
|
||
(CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTmp, -1, CHT_IMEFILENAME3, -1) != CSTR_EQUAL) &&
|
||
(CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTmp, -1, CHS_IMEFILENAME1, -1) != CSTR_EQUAL) &&
|
||
(CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTmp, -1, CHS_IMEFILENAME2, -1) != CSTR_EQUAL))
|
||
{
|
||
ms_adwId[0] = ms_adwId[1] = 0;
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
DWORD dwVerHandle;
|
||
DWORD dwVerSize = GetFileVersionInfoSize(szTmp, &dwVerHandle);
|
||
LANGID langId = LOWORD(ms_hklCurrent);
|
||
|
||
if (dwVerSize)
|
||
{
|
||
LPVOID lpVerBuffer = alloca(dwVerSize);
|
||
|
||
if (GetFileVersionInfo(szTmp, dwVerHandle, dwVerSize, lpVerBuffer))
|
||
{
|
||
LPVOID lpVerData;
|
||
UINT cbVerData;
|
||
|
||
if(VerQueryValue(lpVerBuffer, "\\", &lpVerData, &cbVerData))
|
||
{
|
||
DWORD dwVer = ((VS_FIXEDFILEINFO*) lpVerData)->dwFileVersionMS;
|
||
dwVer = (dwVer & 0x00ff0000) << 8 | (dwVer & 0x000000ff) << 16;
|
||
|
||
if (_GetReadingString
|
||
||
|
||
(langId == LANG_CHT &&
|
||
(dwVer == MAKEIMEVERSION(4, 2) ||
|
||
dwVer == MAKEIMEVERSION(4, 3) ||
|
||
dwVer == MAKEIMEVERSION(4, 4) ||
|
||
dwVer == MAKEIMEVERSION(5, 0) ||
|
||
dwVer == MAKEIMEVERSION(5, 1) ||
|
||
dwVer == MAKEIMEVERSION(5, 2) ||
|
||
dwVer == MAKEIMEVERSION(6, 0)))
|
||
||
|
||
(langId == LANG_CHS &&
|
||
(dwVer == MAKEIMEVERSION(4, 1) ||
|
||
dwVer == MAKEIMEVERSION(4, 2) ||
|
||
dwVer == MAKEIMEVERSION(5, 3))))
|
||
{
|
||
ms_adwId[0] = dwVer | langId;
|
||
ms_adwId[1] = ((VS_FIXEDFILEINFO*)lpVerData)->dwFileVersionLS;
|
||
return ms_adwId[uIndex];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
ms_adwId[0] = ms_adwId[1] = 0;
|
||
return ms_adwId[0];
|
||
}
|
||
|
||
bool CIME::GetReadingWindowOrientation()
|
||
{
|
||
bool bHorizontalReading = (ms_hklCurrent == _CHS_HKL) || (ms_hklCurrent == _CHT_HKL_NEW_CHANG_JIE) || (ms_adwId[0] == 0);
|
||
if(!bHorizontalReading && (GETLANG() == LANG_CHT))
|
||
{
|
||
char szRegPath[MAX_PATH];
|
||
HKEY hKey;
|
||
DWORD dwVer = ms_adwId[0] & 0xFFFF0000;
|
||
strcpy(szRegPath, "software\\microsoft\\windows\\currentversion\\");
|
||
strcat(szRegPath, (dwVer >= MAKEIMEVERSION(5, 1)) ? "MSTCIPH" : "TINTLGNT");
|
||
LONG lRc = RegOpenKeyExA(HKEY_CURRENT_USER, szRegPath, 0, KEY_READ, &hKey);
|
||
if (lRc == ERROR_SUCCESS)
|
||
{
|
||
DWORD dwSize = sizeof(DWORD), dwMapping, dwType;
|
||
lRc = RegQueryValueExA(hKey, "Keyboard Mapping", NULL, &dwType, (PBYTE)&dwMapping, &dwSize);
|
||
if (lRc == ERROR_SUCCESS)
|
||
{
|
||
if ((dwVer <= MAKEIMEVERSION(5, 0) &&
|
||
((BYTE)dwMapping == 0x22 || (BYTE)dwMapping == 0x23))
|
||
||
|
||
((dwVer == MAKEIMEVERSION(5, 1) || dwVer == MAKEIMEVERSION(5, 2)) &&
|
||
(BYTE)dwMapping >= 0x22 && (BYTE)dwMapping <= 0x24)
|
||
)
|
||
{
|
||
bHorizontalReading = true;
|
||
}
|
||
}
|
||
RegCloseKey(hKey);
|
||
}
|
||
}
|
||
|
||
return bHorizontalReading;
|
||
}
|
||
|
||
void CIME::SetupImeApi()
|
||
{
|
||
char szImeFile[MAX_PATH + 1];
|
||
|
||
_GetReadingString = NULL;
|
||
_ShowReadingWindow = NULL;
|
||
ms_bUseIMMCandidate = false;
|
||
|
||
if(ImmGetIMEFileNameA(ms_hklCurrent, szImeFile, COUNTOF(szImeFile) - 1) == 0)
|
||
return;
|
||
if(stricmp(szImeFile, CHS_IMEFILENAME_QQPINYIN) == 0 || stricmp(szImeFile, CHS_IMEFILENAME_SOGOUPY) == 0 || stricmp(szImeFile, CHS_IMEFILENAME_GOOGLEPINYIN2) == 0)
|
||
ms_bUseIMMCandidate = true;
|
||
if (ms_bUILessMode)
|
||
return;
|
||
SAFE_FREE_LIBRARY(ms_hCurrentImeDll);
|
||
ms_hCurrentImeDll = LoadLibraryA(szImeFile);
|
||
|
||
if (ms_hCurrentImeDll) {
|
||
_GetReadingString = (UINT (WINAPI*)(HIMC, UINT, LPWSTR, PINT, BOOL*, PUINT)) (GetProcAddress(ms_hCurrentImeDll, "GetReadingString"));
|
||
_ShowReadingWindow =(BOOL (WINAPI*)(HIMC, BOOL)) (GetProcAddress(ms_hCurrentImeDll, "ShowReadingWindow"));
|
||
|
||
if(_ShowReadingWindow) {
|
||
HIMC hImc = ImmGetContext(ms_hWnd);
|
||
if(hImc) {
|
||
_ShowReadingWindow(hImc, false);
|
||
ImmReleaseContext(ms_hWnd, hImc);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
static unsigned long _strtoul( LPCSTR psz, LPTSTR*, int )
|
||
{
|
||
if ( !psz )
|
||
return 0;
|
||
|
||
ULONG ulRet = 0;
|
||
if ( psz[0] == '0' && ( psz[1] == 'x' || psz[1] == 'X' ) )
|
||
{
|
||
psz += 2;
|
||
ULONG ul = 0;
|
||
while ( *psz )
|
||
{
|
||
if ( '0' <= *psz && *psz <= '9' )
|
||
ul = *psz - '0';
|
||
else if ( 'A' <= *psz && *psz <= 'F' )
|
||
ul = *psz - 'A' + 10;
|
||
else if ( 'a' <= *psz && *psz <= 'f' )
|
||
ul = *psz - 'a' + 10;
|
||
else
|
||
break;
|
||
ulRet = ulRet * 16 + ul;
|
||
psz++;
|
||
}
|
||
}
|
||
else {
|
||
while ( *psz && ( '0' <= *psz && *psz <= '9' ) )
|
||
{
|
||
ulRet = ulRet * 10 + ( *psz - '0' );
|
||
psz++;
|
||
}
|
||
}
|
||
return ulRet;
|
||
}
|
||
|
||
void CIME::CheckInputLocale()
|
||
{
|
||
static UINT s_uPrevCodePage = 0xFFFF;
|
||
static HKL s_hklPrev = NULL;
|
||
|
||
ms_hklCurrent = GetKeyboardLayout( 0 );
|
||
if ( s_hklPrev == ms_hklCurrent )
|
||
return;
|
||
s_hklPrev = ms_hklCurrent;
|
||
|
||
char szCodePage[8];
|
||
int iRc = GetLocaleInfoA( MAKELCID( GETLANG(), SORT_DEFAULT ), LOCALE_IDEFAULTANSICODEPAGE, szCodePage, COUNTOF( szCodePage ) ); iRc;
|
||
ms_uInputCodePage = _strtoul( szCodePage, NULL, 0 );
|
||
if ( s_uPrevCodePage == ms_uInputCodePage )
|
||
return;
|
||
s_uPrevCodePage = ms_uInputCodePage;
|
||
|
||
GetKeyboardLayoutName(ms_szKeyboardLayout);
|
||
|
||
switch (GETPRIMLANG())
|
||
{
|
||
case LANG_KOREAN:
|
||
ms_bVerticalCandidate = false;
|
||
ms_wszCurrentIndicator = s_aszIndicator[INDICATOR_KOREAN];
|
||
break;
|
||
|
||
case LANG_JAPANESE:
|
||
ms_bVerticalCandidate = true;
|
||
ms_wszCurrentIndicator = s_aszIndicator[INDICATOR_JAPANESE];
|
||
break;
|
||
|
||
case LANG_CHINESE:
|
||
ms_bVerticalCandidate = true;
|
||
|
||
switch(GETSUBLANG())
|
||
{
|
||
case SUBLANG_CHINESE_SIMPLIFIED:
|
||
case SUBLANG_CHINESE_SINGAPORE:
|
||
//ms_bVerticalCandidate = (GetImeId() == 0);
|
||
ms_bVerticalCandidate = false;
|
||
ms_wszCurrentIndicator = s_aszIndicator[INDICATOR_CHS];
|
||
break;
|
||
|
||
case SUBLANG_CHINESE_TRADITIONAL:
|
||
case SUBLANG_CHINESE_HONGKONG:
|
||
case SUBLANG_CHINESE_MACAU:
|
||
ms_wszCurrentIndicator = s_aszIndicator[INDICATOR_CHT];
|
||
break;
|
||
|
||
default: // unsupported sub-language
|
||
ms_wszCurrentIndicator = s_aszIndicator[INDICATOR_NON_IME];
|
||
break;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
ms_wszCurrentIndicator = s_aszIndicator[INDICATOR_NON_IME];
|
||
break;
|
||
}
|
||
|
||
if (ms_wszCurrentIndicator == s_aszIndicator[INDICATOR_NON_IME])
|
||
{
|
||
char szLang[10];
|
||
GetLocaleInfoA(MAKELCID(GETLANG(), SORT_DEFAULT), LOCALE_SABBREVLANGNAME, szLang, sizeof(szLang));
|
||
ms_wszCurrentIndicator[0] = szLang[0];
|
||
ms_wszCurrentIndicator[1] = towlower(szLang[1]);
|
||
}
|
||
|
||
// <20>ƶ<EFBFBD><C6B6><EFBFBD><EEBFA1> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ڵ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ٲ<EFBFBD><D9B2><EFBFBD> <20>ʴ´<CAB4>
|
||
// <20><><EFBFBD>뵵 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ʴ´<CAB4>.
|
||
if(ms_uOutputCodePage != 1256) {
|
||
ms_uOutputCodePage = ms_uInputCodePage;
|
||
Clear();
|
||
}
|
||
|
||
//for ( int i = 0; i < 256; i++ )
|
||
//{
|
||
// LeadByteTable[i] = (BYTE)IsDBCSLeadByteEx( g_uCodePage, (BYTE)i );
|
||
//}
|
||
}
|
||
|
||
void CIME::CheckToggleState()
|
||
{
|
||
CheckInputLocale();
|
||
|
||
// In Vista, we have to use TSF since few IMM functions don't work as expected.
|
||
// WARNING: Because of timing, g_dwState and g_bChineseIME may not be updated
|
||
// immediately after the change on IME states by user.
|
||
if ( ms_bUILessMode )
|
||
return;
|
||
|
||
/* Check Toggle State */
|
||
bool bIme = ImmIsIME( ms_hklCurrent ) != 0
|
||
&& ( ( 0xF0000000 & (DWORD)ms_hklCurrent ) == 0xE0000000 ); // Hack to detect IME correctly. When IME is running as TIP, ImmIsIME() returns true for CHT US keyboard.
|
||
ms_bChineseIME = ( GETPRIMLANG() == LANG_CHINESE ) && bIme;
|
||
|
||
HIMC himc;
|
||
if (NULL != (himc = ImmGetContext(ms_hWnd))) {
|
||
if (ms_bChineseIME) {
|
||
DWORD dwConvMode, dwSentMode;
|
||
ImmGetConversionStatus(himc, &dwConvMode, &dwSentMode);
|
||
ms_dwImeState = ( dwConvMode & IME_CMODE_NATIVE ) ? IMEUI_STATE_ON : IMEUI_STATE_ENGLISH;
|
||
}
|
||
else
|
||
{
|
||
ms_dwImeState = ( bIme && ImmGetOpenStatus( himc ) != 0 ) ? IMEUI_STATE_ON : IMEUI_STATE_OFF;
|
||
}
|
||
ImmReleaseContext(ms_hWnd, himc);
|
||
}
|
||
else
|
||
ms_dwImeState = IMEUI_STATE_OFF;
|
||
}
|
||
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
//
|
||
// CTsfUiLessMode methods
|
||
//
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
|
||
//
|
||
// SetupSinks()
|
||
// Set up sinks. A sink is used to receive a Text Service Framework event.
|
||
// CUIElementSink implements multiple sink interfaces to receive few different TSF events.
|
||
//
|
||
BOOL CTsfUiLessMode::SetupSinks()
|
||
{
|
||
// ITfThreadMgrEx is available on Vista or later.
|
||
HRESULT hr;
|
||
hr = CoCreateInstance(CLSID_TF_ThreadMgr,
|
||
NULL,
|
||
CLSCTX_INPROC_SERVER,
|
||
__uuidof(ITfThreadMgrEx),
|
||
(void**)&m_tm);
|
||
|
||
if (hr != S_OK)
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
// ready to start interacting
|
||
TfClientId cid; // not used
|
||
if (FAILED(m_tm->ActivateEx(&cid, TF_TMAE_UIELEMENTENABLEDONLY)))
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
// Setup sinks
|
||
BOOL bRc = FALSE;
|
||
m_TsfSink = new CUIElementSink();
|
||
if (m_TsfSink)
|
||
{
|
||
ITfSource *srcTm;
|
||
if (SUCCEEDED(hr = m_tm->QueryInterface(__uuidof(ITfSource), (void **)&srcTm)))
|
||
{
|
||
// Sink for reading window change
|
||
if (SUCCEEDED(hr = srcTm->AdviseSink(__uuidof(ITfUIElementSink), (ITfUIElementSink*)m_TsfSink, &m_dwUIElementSinkCookie)))
|
||
{
|
||
// Sink for input locale change
|
||
if (SUCCEEDED(hr = srcTm->AdviseSink(__uuidof(ITfInputProcessorProfileActivationSink), (ITfInputProcessorProfileActivationSink*)m_TsfSink, &m_dwAlpnSinkCookie)))
|
||
{
|
||
if (SetupCompartmentSinks()) // Setup compartment sinks for the first time
|
||
{
|
||
bRc = TRUE;
|
||
}
|
||
}
|
||
}
|
||
srcTm->Release();
|
||
}
|
||
}
|
||
return bRc;
|
||
}
|
||
|
||
void CTsfUiLessMode::ReleaseSinks()
|
||
{
|
||
HRESULT hr;
|
||
ITfSource *source;
|
||
|
||
// Remove all sinks
|
||
if ( m_tm && SUCCEEDED(m_tm->QueryInterface(__uuidof(ITfSource), (void **)&source)))
|
||
{
|
||
hr = source->UnadviseSink(m_dwUIElementSinkCookie);
|
||
hr = source->UnadviseSink(m_dwAlpnSinkCookie);
|
||
source->Release();
|
||
SetupCompartmentSinks(TRUE); // Remove all compartment sinks
|
||
m_tm->Deactivate();
|
||
SAFE_RELEASE(m_tm);
|
||
SAFE_RELEASE(m_TsfSink);
|
||
}
|
||
}
|
||
|
||
CTsfUiLessMode::CUIElementSink::CUIElementSink()
|
||
{
|
||
_cRef = 1;
|
||
}
|
||
|
||
|
||
CTsfUiLessMode::CUIElementSink::~CUIElementSink()
|
||
{
|
||
}
|
||
|
||
STDAPI CTsfUiLessMode::CUIElementSink::QueryInterface(REFIID riid, void **ppvObj)
|
||
{
|
||
if (ppvObj == NULL)
|
||
return E_INVALIDARG;
|
||
|
||
*ppvObj = NULL;
|
||
|
||
if (IsEqualIID(riid, IID_IUnknown))
|
||
{
|
||
*ppvObj = reinterpret_cast<IUnknown *>(this);
|
||
}
|
||
else if (IsEqualIID(riid, __uuidof(ITfUIElementSink)))
|
||
{
|
||
*ppvObj = (ITfUIElementSink *)this;
|
||
}
|
||
else if (IsEqualIID(riid, __uuidof(ITfInputProcessorProfileActivationSink)))
|
||
{
|
||
*ppvObj = (ITfInputProcessorProfileActivationSink*)this;
|
||
}
|
||
else if (IsEqualIID(riid, __uuidof(ITfCompartmentEventSink)))
|
||
{
|
||
*ppvObj = (ITfCompartmentEventSink*)this;
|
||
}
|
||
|
||
if (*ppvObj)
|
||
{
|
||
AddRef();
|
||
return S_OK;
|
||
}
|
||
|
||
return E_NOINTERFACE;
|
||
}
|
||
|
||
STDAPI_(ULONG) CTsfUiLessMode::CUIElementSink::AddRef()
|
||
{
|
||
return ++_cRef;
|
||
}
|
||
|
||
STDAPI_(ULONG) CTsfUiLessMode::CUIElementSink::Release()
|
||
{
|
||
LONG cr = --_cRef;
|
||
|
||
if (_cRef == 0)
|
||
{
|
||
delete this;
|
||
}
|
||
|
||
return cr;
|
||
}
|
||
|
||
STDAPI CTsfUiLessMode::CUIElementSink::BeginUIElement(DWORD dwUIElementId, BOOL *pbShow)
|
||
{
|
||
ITfUIElement *pElement = GetUIElement(dwUIElementId);
|
||
if (!pElement)
|
||
return E_INVALIDARG;
|
||
|
||
ITfReadingInformationUIElement *preading = NULL;
|
||
ITfCandidateListUIElement *pcandidate = NULL;
|
||
*pbShow = FALSE;
|
||
|
||
//BSTR bstrDesc;
|
||
//OutputDebugStringW(L"BEGINUI: ");
|
||
//pElement->GetDescription(&bstrDesc);
|
||
//OutputDebugStringW(bstrDesc);
|
||
//OutputDebugStringW(L"\n");
|
||
|
||
if (SUCCEEDED(pElement->QueryInterface(__uuidof(ITfReadingInformationUIElement), (void **)&preading)))
|
||
{
|
||
MakeReadingInformationString(preading);
|
||
if(CIME::ms_pEvent)
|
||
CIME::ms_pEvent->OnOpenReadingWnd();
|
||
preading->Release();
|
||
}
|
||
else if (SUCCEEDED(pElement->QueryInterface(__uuidof(ITfCandidateListUIElement), (void **)&pcandidate)))
|
||
{
|
||
m_nCandidateRefCount++;
|
||
MakeCandidateStrings(pcandidate);
|
||
if(CIME::ms_pEvent)
|
||
CIME::ms_pEvent->OnOpenCandidateList();
|
||
pcandidate->Release();
|
||
}
|
||
|
||
pElement->Release();
|
||
return S_OK;
|
||
}
|
||
|
||
STDAPI CTsfUiLessMode::CUIElementSink::UpdateUIElement(DWORD dwUIElementId)
|
||
{
|
||
ITfUIElement *pElement = GetUIElement(dwUIElementId);
|
||
if (!pElement)
|
||
return E_INVALIDARG;
|
||
|
||
ITfReadingInformationUIElement *preading = NULL;
|
||
ITfCandidateListUIElement *pcandidate = NULL;
|
||
|
||
//BSTR bstrDesc;
|
||
//pElement->GetDescription(&bstrDesc);
|
||
//OutputDebugStringW(L"UPDATEUI: ");
|
||
//OutputDebugStringW(bstrDesc);
|
||
//OutputDebugStringW(L"\n");
|
||
|
||
if (SUCCEEDED(pElement->QueryInterface(__uuidof(ITfReadingInformationUIElement), (void **)&preading)))
|
||
{
|
||
MakeReadingInformationString(preading);
|
||
if(CIME::ms_pEvent)
|
||
CIME::ms_pEvent->OnOpenReadingWnd();
|
||
preading->Release();
|
||
}
|
||
else if (SUCCEEDED(pElement->QueryInterface(__uuidof(ITfCandidateListUIElement), (void **)&pcandidate)))
|
||
{
|
||
MakeCandidateStrings(pcandidate);
|
||
if(CIME::ms_pEvent)
|
||
CIME::ms_pEvent->OnOpenCandidateList();
|
||
pcandidate->Release();
|
||
}
|
||
|
||
pElement->Release();
|
||
return S_OK;
|
||
}
|
||
|
||
STDAPI CTsfUiLessMode::CUIElementSink::EndUIElement(DWORD dwUIElementId)
|
||
{
|
||
ITfUIElement *pElement = GetUIElement(dwUIElementId);
|
||
if (!pElement)
|
||
return E_INVALIDARG;
|
||
|
||
//BSTR bstrDesc;
|
||
//OutputDebugStringW(L"ENDUI: ");
|
||
//pElement->GetDescription(&bstrDesc);
|
||
//OutputDebugStringW(bstrDesc);
|
||
//OutputDebugStringW(L"\n");
|
||
|
||
ITfReadingInformationUIElement *preading = NULL;
|
||
if (SUCCEEDED(pElement->QueryInterface(__uuidof(ITfReadingInformationUIElement), (void **)&preading)))
|
||
{
|
||
CIME::CloseReadingInformation();
|
||
preading->Release();
|
||
}
|
||
|
||
ITfCandidateListUIElement *pcandidate = NULL;
|
||
if (SUCCEEDED(pElement->QueryInterface(__uuidof(ITfCandidateListUIElement), (void **)&pcandidate)))
|
||
{
|
||
m_nCandidateRefCount--;
|
||
if (m_nCandidateRefCount == 0)
|
||
CIME::CloseCandidateList();
|
||
pcandidate->Release();
|
||
}
|
||
|
||
pElement->Release();
|
||
return S_OK;
|
||
}
|
||
|
||
void CTsfUiLessMode::UpdateImeState(BOOL bResetCompartmentEventSink)
|
||
{
|
||
ITfCompartmentMgr* pcm;
|
||
ITfCompartment* pTfOpenMode = NULL;
|
||
ITfCompartment* pTfConvMode = NULL;
|
||
if ( GetCompartments( &pcm, &pTfOpenMode, &pTfConvMode ) )
|
||
{
|
||
VARIANT valOpenMode;
|
||
VARIANT valConvMode;
|
||
pTfOpenMode->GetValue( &valOpenMode );
|
||
pTfConvMode->GetValue( &valConvMode );
|
||
if ( valOpenMode.vt == VT_I4 )
|
||
{
|
||
if ( CIME::ms_bChineseIME )
|
||
{
|
||
CIME::ms_dwImeState = valOpenMode.lVal != 0 && valConvMode.lVal != 0 ? IMEUI_STATE_ON : IMEUI_STATE_ENGLISH;
|
||
}
|
||
else
|
||
{
|
||
CIME::ms_dwImeState = valOpenMode.lVal != 0 ? IMEUI_STATE_ON : IMEUI_STATE_OFF;
|
||
}
|
||
}
|
||
VariantClear( &valOpenMode );
|
||
VariantClear( &valConvMode );
|
||
|
||
if ( bResetCompartmentEventSink )
|
||
{
|
||
SetupCompartmentSinks( FALSE, pTfOpenMode, pTfConvMode ); // Reset compartment sinks
|
||
}
|
||
pTfOpenMode->Release();
|
||
pTfConvMode->Release();
|
||
pcm->Release();
|
||
}
|
||
}
|
||
|
||
STDAPI CTsfUiLessMode::CUIElementSink::OnActivated(DWORD dwProfileType, LANGID langid, REFCLSID clsid, REFGUID catid,
|
||
REFGUID guidProfile, HKL hkl, DWORD dwFlags)
|
||
{
|
||
static GUID TF_PROFILE_DAYI = { 0x037B2C25, 0x480C, 0x4D7F, 0xB0, 0x27, 0xD6, 0xCA, 0x6B, 0x69, 0x78, 0x8A };
|
||
CIME::ms_iCandListIndexBase = IsEqualGUID( TF_PROFILE_DAYI, guidProfile ) ? 0 : 1;
|
||
if ( IsEqualIID( catid, GUID_TFCAT_TIP_KEYBOARD ) && ( dwFlags & TF_IPSINK_FLAG_ACTIVE ) )
|
||
{
|
||
CIME::ms_bChineseIME = ( dwProfileType & TF_PROFILETYPE_INPUTPROCESSOR ) && langid == LANG_CHT;
|
||
if ( dwProfileType & TF_PROFILETYPE_INPUTPROCESSOR )
|
||
{
|
||
UpdateImeState(TRUE);
|
||
}
|
||
else
|
||
CIME::ms_dwImeState = IMEUI_STATE_OFF;
|
||
CIME::ChangeInputLanguage();
|
||
}
|
||
return S_OK;
|
||
}
|
||
|
||
STDAPI CTsfUiLessMode::CUIElementSink::OnChange(REFGUID rguid)
|
||
{
|
||
UpdateImeState();
|
||
return S_OK;
|
||
}
|
||
|
||
void CTsfUiLessMode::MakeReadingInformationString(ITfReadingInformationUIElement* preading)
|
||
{
|
||
UINT cchMax;
|
||
UINT uErrorIndex = 0;
|
||
BOOL fVertical;
|
||
DWORD dwFlags;
|
||
|
||
CIME::ms_wstrReading.resize(0);
|
||
preading->GetUpdatedFlags(&dwFlags);
|
||
preading->GetMaxReadingStringLength(&cchMax);
|
||
preading->GetErrorIndex(&uErrorIndex); // errorIndex is zero-based
|
||
preading->IsVerticalOrderPreferred(&fVertical);
|
||
CIME::ms_iReadingError = (int)uErrorIndex;
|
||
CIME::ms_bHorizontalReading = !fVertical;
|
||
CIME::ms_bReadingInformation = true;
|
||
BSTR bstr;
|
||
if (SUCCEEDED(preading->GetString(&bstr)))
|
||
{
|
||
if (bstr)
|
||
{
|
||
CIME::ms_wstrReading.assign( (wchar_t *) bstr, (wchar_t *) bstr+lstrlenW(bstr) );
|
||
LPCWSTR pszSource = &(CIME::ms_wstrReading[0]);
|
||
if ( fVertical )
|
||
{
|
||
CIME::ms_dwCandidatePageSize = CIME::MAX_CANDLIST;
|
||
// ms_iReadingError is used only in horizontal window, and has to be -1 if there's no error.
|
||
CIME::ms_dwCandidateSelection = CIME::ms_iReadingError ? CIME::ms_iReadingError - 1 : (DWORD)-1;
|
||
CIME::ms_dwCandidateCount = cchMax;
|
||
// for vertical reading window, copy each character to g_szCandidate array.
|
||
for ( UINT i = 0; i < cchMax; i++ )
|
||
{
|
||
LPWSTR pszDest = CIME::ms_wszCandidate[i];
|
||
if ( *pszSource )
|
||
{
|
||
LPWSTR pszNextSrc = CharNextW(pszSource);
|
||
SIZE_T size = (LPSTR)pszNextSrc - (LPSTR)pszSource;
|
||
CopyMemory( pszDest, pszSource, size );
|
||
pszSource = pszNextSrc;
|
||
pszDest += size;
|
||
}
|
||
*pszDest = 0;
|
||
}
|
||
}
|
||
//else
|
||
//{
|
||
// CIME::ms_wszCandidate[0][0] = L' '; // hack to make rendering happen
|
||
//}
|
||
SysFreeString(bstr);
|
||
}
|
||
}
|
||
}
|
||
|
||
void CTsfUiLessMode::MakeCandidateStrings(ITfCandidateListUIElement* pcandidate)
|
||
{
|
||
UINT uIndex = 0;
|
||
UINT uCount = 0;
|
||
UINT uCurrentPage = 0;
|
||
UINT *IndexList = NULL;
|
||
UINT uPageCnt = 0;
|
||
DWORD dwPageStart = 0;
|
||
DWORD dwPageSize = 0;
|
||
BSTR bstr;
|
||
|
||
pcandidate->GetSelection(&uIndex);
|
||
pcandidate->GetCount(&uCount);
|
||
pcandidate->GetCurrentPage(&uCurrentPage);
|
||
CIME::ms_dwCandidateSelection = (DWORD)uIndex;
|
||
CIME::ms_dwCandidateCount = (DWORD)uCount;
|
||
CIME::ms_bCandidateList = true;
|
||
|
||
pcandidate->GetPageIndex(NULL, 0, &uPageCnt);
|
||
if(uPageCnt > 0)
|
||
{
|
||
IndexList = (UINT *) malloc(sizeof(UINT)*uPageCnt);
|
||
if(IndexList)
|
||
{
|
||
pcandidate->GetPageIndex(IndexList, uPageCnt, &uPageCnt);
|
||
dwPageStart = IndexList[uCurrentPage];
|
||
dwPageSize = (uCurrentPage < uPageCnt-1) ?
|
||
min(uCount, IndexList[uCurrentPage+1]) - dwPageStart:
|
||
uCount - dwPageStart;
|
||
}
|
||
}
|
||
|
||
CIME::ms_dwCandidatePageSize = min(dwPageSize, CIME::MAX_CANDLIST);
|
||
CIME::ms_dwCandidateSelection = CIME::ms_dwCandidateSelection - dwPageStart;
|
||
|
||
memset(&CIME::ms_wszCandidate, 0, sizeof(CIME::ms_wszCandidate));
|
||
for (UINT i = dwPageStart, j = 0; (DWORD)i < CIME::ms_dwCandidateCount && j < CIME::ms_dwCandidatePageSize; i++, j++)
|
||
{
|
||
if (SUCCEEDED(pcandidate->GetString( i, &bstr )))
|
||
{
|
||
if(bstr)
|
||
{
|
||
wcscpy( CIME::ms_wszCandidate[j], bstr );
|
||
SysFreeString(bstr);
|
||
}
|
||
}
|
||
}
|
||
//OutputDebugStringW( L"\n" );
|
||
|
||
if (GETPRIMLANG() == LANG_KOREAN)
|
||
{
|
||
CIME::ms_dwCandidateSelection = (DWORD)-1;
|
||
}
|
||
|
||
if(IndexList)
|
||
{
|
||
free(IndexList);
|
||
}
|
||
}
|
||
|
||
ITfUIElement* CTsfUiLessMode::GetUIElement(DWORD dwUIElementId)
|
||
{
|
||
ITfUIElementMgr *puiem;
|
||
ITfUIElement *pElement = NULL;
|
||
|
||
if (SUCCEEDED(m_tm->QueryInterface(__uuidof(ITfUIElementMgr), (void **)&puiem)))
|
||
{
|
||
puiem->GetUIElement(dwUIElementId, &pElement);
|
||
puiem->Release();
|
||
}
|
||
|
||
return pElement;
|
||
}
|
||
|
||
BOOL CTsfUiLessMode::CurrentInputLocaleIsIme()
|
||
{
|
||
BOOL ret = FALSE;
|
||
HRESULT hr;
|
||
|
||
ITfInputProcessorProfiles *pProfiles;
|
||
hr = CoCreateInstance(CLSID_TF_InputProcessorProfiles, NULL, CLSCTX_INPROC_SERVER, __uuidof(ITfInputProcessorProfiles), (LPVOID*)&pProfiles);
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
ITfInputProcessorProfileMgr *pProfileMgr;
|
||
hr = pProfiles->QueryInterface(__uuidof(ITfInputProcessorProfileMgr), (LPVOID*)&pProfileMgr);
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
TF_INPUTPROCESSORPROFILE tip;
|
||
hr = pProfileMgr->GetActiveProfile( GUID_TFCAT_TIP_KEYBOARD, &tip );
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
ret = ( tip.dwProfileType & TF_PROFILETYPE_INPUTPROCESSOR ) != 0;
|
||
}
|
||
pProfileMgr->Release();
|
||
}
|
||
pProfiles->Release();
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
// Sets up or removes sink for UI element.
|
||
// UI element sink should be removed when IME is disabled,
|
||
// otherwise the sink can be triggered when a game has multiple instances of IME UI library.
|
||
void CTsfUiLessMode::EnableUiUpdates(bool bEnable)
|
||
{
|
||
if ( m_tm == NULL ||
|
||
( bEnable && m_dwUIElementSinkCookie != TF_INVALID_COOKIE ) ||
|
||
( !bEnable && m_dwUIElementSinkCookie == TF_INVALID_COOKIE ) )
|
||
{
|
||
return;
|
||
}
|
||
ITfSource *srcTm = NULL;
|
||
HRESULT hr = E_FAIL;
|
||
if (SUCCEEDED(hr = m_tm->QueryInterface(__uuidof(ITfSource), (void **)&srcTm)))
|
||
{
|
||
if ( bEnable )
|
||
{
|
||
hr = srcTm->AdviseSink(__uuidof(ITfUIElementSink), (ITfUIElementSink*)m_TsfSink, &m_dwUIElementSinkCookie);
|
||
}
|
||
else
|
||
{
|
||
hr = srcTm->UnadviseSink(m_dwUIElementSinkCookie);
|
||
m_dwUIElementSinkCookie = TF_INVALID_COOKIE;
|
||
}
|
||
srcTm->Release();
|
||
}
|
||
}
|
||
|
||
// Returns open mode compartments and compartment manager.
|
||
// Function fails if it fails to acquire any of the objects to be returned.
|
||
BOOL CTsfUiLessMode::GetCompartments( ITfCompartmentMgr** ppcm, ITfCompartment** ppTfOpenMode, ITfCompartment** ppTfConvMode )
|
||
{
|
||
ITfCompartmentMgr* pcm = NULL;
|
||
ITfCompartment* pTfOpenMode = NULL;
|
||
ITfCompartment* pTfConvMode = NULL;
|
||
|
||
static GUID _GUID_COMPARTMENT_KEYBOARD_INPUTMODE_CONVERSION = { 0xCCF05DD8, 0x4A87, 0x11D7, 0xA6, 0xE2, 0x00, 0x06, 0x5B, 0x84, 0x43, 0x5C };
|
||
|
||
HRESULT hr;
|
||
if (SUCCEEDED(hr = m_tm->QueryInterface( IID_ITfCompartmentMgr, (void**)&pcm )))
|
||
{
|
||
if (SUCCEEDED(hr = pcm->GetCompartment( GUID_COMPARTMENT_KEYBOARD_OPENCLOSE, &pTfOpenMode )))
|
||
{
|
||
if (SUCCEEDED(hr = pcm->GetCompartment( _GUID_COMPARTMENT_KEYBOARD_INPUTMODE_CONVERSION, &pTfConvMode )))
|
||
{
|
||
*ppcm = pcm;
|
||
*ppTfOpenMode = pTfOpenMode;
|
||
*ppTfConvMode = pTfConvMode;
|
||
return TRUE;
|
||
}
|
||
pTfOpenMode->Release();
|
||
}
|
||
pcm->Release();
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
// There are three ways to call this function:
|
||
// SetupCompartmentSinks() : initialization
|
||
// SetupCompartmentSinks(FALSE, openmode, convmode) : Resetting sinks. This is necessary as DaYi and Array IME resets compartment on switching input locale
|
||
// SetupCompartmentSinks(TRUE) : clean up sinks
|
||
BOOL CTsfUiLessMode::SetupCompartmentSinks( BOOL bRemoveOnly, ITfCompartment* pTfOpenMode, ITfCompartment* pTfConvMode )
|
||
{
|
||
bool bLocalCompartments = false;
|
||
ITfCompartmentMgr* pcm = NULL;
|
||
BOOL bRc = FALSE;
|
||
HRESULT hr = E_FAIL;
|
||
|
||
if ( !pTfOpenMode && !pTfConvMode )
|
||
{
|
||
bLocalCompartments = true;
|
||
GetCompartments( &pcm, &pTfOpenMode, &pTfConvMode );
|
||
}
|
||
if ( !( pTfOpenMode && pTfConvMode ) )
|
||
{
|
||
// Invalid parameters or GetCompartments() has failed.
|
||
return FALSE;
|
||
}
|
||
ITfSource *srcOpenMode = NULL;
|
||
if (SUCCEEDED(hr = pTfOpenMode->QueryInterface( IID_ITfSource, (void**)&srcOpenMode )))
|
||
{
|
||
// Remove existing sink for open mode
|
||
if ( m_dwOpenModeSinkCookie != TF_INVALID_COOKIE )
|
||
{
|
||
srcOpenMode->UnadviseSink( m_dwOpenModeSinkCookie );
|
||
m_dwOpenModeSinkCookie = TF_INVALID_COOKIE;
|
||
}
|
||
// Setup sink for open mode (toggle state) change
|
||
if ( bRemoveOnly || SUCCEEDED(hr = srcOpenMode->AdviseSink( IID_ITfCompartmentEventSink, (ITfCompartmentEventSink*)m_TsfSink, &m_dwOpenModeSinkCookie )))
|
||
{
|
||
ITfSource *srcConvMode = NULL;
|
||
if (SUCCEEDED(hr = pTfConvMode->QueryInterface( IID_ITfSource, (void**)&srcConvMode )))
|
||
{
|
||
// Remove existing sink for open mode
|
||
if ( m_dwConvModeSinkCookie != TF_INVALID_COOKIE )
|
||
{
|
||
srcConvMode->UnadviseSink( m_dwConvModeSinkCookie );
|
||
m_dwConvModeSinkCookie = TF_INVALID_COOKIE;
|
||
}
|
||
// Setup sink for open mode (toggle state) change
|
||
if ( bRemoveOnly || SUCCEEDED(hr = srcConvMode->AdviseSink( IID_ITfCompartmentEventSink, (ITfCompartmentEventSink*)m_TsfSink, &m_dwConvModeSinkCookie )))
|
||
{
|
||
bRc = TRUE;
|
||
}
|
||
srcConvMode->Release();
|
||
}
|
||
}
|
||
srcOpenMode->Release();
|
||
}
|
||
if ( bLocalCompartments )
|
||
{
|
||
pTfOpenMode->Release();
|
||
pTfConvMode->Release();
|
||
pcm->Release();
|
||
}
|
||
return bRc;
|
||
}
|
||
|
||
/* IME Message Handler */
|
||
LRESULT CIME::WMInputLanguage(HWND hWnd, UINT /*uiMsg*/, WPARAM /*wParam*/, LPARAM lParam)
|
||
{
|
||
ChangeInputLanguage();
|
||
return 0;
|
||
}
|
||
|
||
LRESULT CIME::WMStartComposition(HWND /*hWnd*/, UINT /*uiMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/)
|
||
{
|
||
return 1L;
|
||
}
|
||
|
||
LRESULT CIME::WMComposition(HWND hWnd, UINT /*uiMsg*/, WPARAM /*wParam*/, LPARAM lParam)
|
||
{
|
||
LRESULT result = 0;
|
||
|
||
if(ms_bCaptureInput == false)
|
||
return 0;
|
||
|
||
HIMC hImc = ImmGetContext(hWnd);
|
||
|
||
if(hImc == NULL)
|
||
return 0;
|
||
|
||
if(lParam&GCS_RESULTSTR)
|
||
ResultProcess(hImc);
|
||
if(lParam&GCS_COMPATTR)
|
||
AttributeProcess(hImc);
|
||
if(lParam&GCS_COMPSTR)
|
||
{
|
||
if (ms_uOutputCodePage == 950) // <20>븸 <20><><EFBFBD><EFBFBD> <20>Է<EFBFBD> ó<><C3B3>
|
||
{
|
||
if (lParam&GCS_COMPATTR)
|
||
CompositionProcessBuilding(hImc);
|
||
else
|
||
CompositionProcess(hImc);
|
||
}
|
||
else
|
||
{
|
||
CompositionProcess(hImc);
|
||
}
|
||
}
|
||
|
||
ImmReleaseContext(hWnd, hImc);
|
||
|
||
if(ms_pEvent)
|
||
ms_pEvent->OnUpdate();
|
||
|
||
return (result);
|
||
}
|
||
|
||
LRESULT CIME::WMEndComposition(HWND /*hWnd*/, UINT /*uiMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/)
|
||
{
|
||
ms_compLen = 0;
|
||
ms_ulbegin = 0;
|
||
ms_ulend = 0;
|
||
|
||
if(ms_pEvent)
|
||
ms_pEvent->OnUpdate();
|
||
|
||
return 0L;
|
||
}
|
||
|
||
LRESULT CIME::WMNotify(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
|
||
{
|
||
LRESULT result = 0;
|
||
|
||
if(ms_bCaptureInput == false)
|
||
return 0;
|
||
switch (wParam) {
|
||
|
||
case IMN_OPENCANDIDATE:
|
||
case IMN_CHANGECANDIDATE: {
|
||
if (ms_bUILessMode && !ms_bUseIMMCandidate)
|
||
break;
|
||
HIMC hImc = ImmGetContext(hWnd);
|
||
if (hImc == NULL)
|
||
break;
|
||
CandidateProcess(hImc);
|
||
if (!m_bUseDefaultIME) {
|
||
if(ms_pEvent)
|
||
ms_pEvent->OnOpenCandidateList();
|
||
} else
|
||
result = ::DefWindowProc(hWnd, uiMsg, wParam, lParam);
|
||
ImmReleaseContext(hWnd, hImc);
|
||
break;
|
||
}
|
||
case IMN_CLOSECANDIDATE:
|
||
if (ms_bUILessMode && !ms_bUseIMMCandidate)
|
||
break;
|
||
if (!m_bUseDefaultIME)
|
||
CloseCandidateList();
|
||
else
|
||
result = DefWindowProc(hWnd, uiMsg, wParam, lParam);
|
||
break;
|
||
|
||
case IMN_SETCONVERSIONMODE:
|
||
case IMN_SETOPENSTATUS:
|
||
if (ms_bUILessMode)
|
||
break;
|
||
CheckToggleState();
|
||
break;
|
||
|
||
case IMN_PRIVATE: {
|
||
if (ms_bUILessMode)
|
||
break;
|
||
HIMC hImc = ImmGetContext(hWnd);
|
||
if (hImc == NULL)
|
||
break;
|
||
ReadingProcess(hImc);
|
||
|
||
// Trap some messages to hide reading window
|
||
switch(ms_adwId[0])
|
||
{
|
||
case IMEID_CHT_VER42:
|
||
case IMEID_CHT_VER43:
|
||
case IMEID_CHT_VER44:
|
||
case IMEID_CHS_VER41:
|
||
case IMEID_CHS_VER42:
|
||
if ((lParam == 1)||(lParam == 2))
|
||
return true;
|
||
break;
|
||
|
||
case IMEID_CHT_VER50:
|
||
case IMEID_CHT_VER51:
|
||
case IMEID_CHT_VER52:
|
||
case IMEID_CHT_VER60:
|
||
case IMEID_CHS_VER53:
|
||
if ((lParam == 16)||(lParam == 17)||(lParam == 26)||(lParam == 27)||(lParam == 28))
|
||
return true;
|
||
break;
|
||
}
|
||
ImmReleaseContext(hWnd, hImc);
|
||
break;
|
||
}
|
||
}
|
||
|
||
if(ms_pEvent)
|
||
ms_pEvent->OnUpdate();
|
||
|
||
return result;
|
||
}
|
||
|
||
LRESULT CIME::WMChar(HWND /*hWnd*/, UINT /*uiMsg*/, WPARAM wParam, LPARAM lParam)
|
||
{
|
||
unsigned char c = unsigned char(wParam & 0xff);
|
||
|
||
switch (c)
|
||
{
|
||
case 8:
|
||
if(ms_bCaptureInput == false)
|
||
return 0;
|
||
if (ms_curpos > 0)
|
||
{
|
||
DecCurPos();
|
||
DelCurPos();
|
||
}
|
||
if(ms_pEvent)
|
||
ms_pEvent->OnUpdate();
|
||
return 0;
|
||
break;
|
||
|
||
default:
|
||
if(ms_pEvent) {
|
||
if (ms_pEvent->OnWM_CHAR(wParam, lParam))
|
||
break;
|
||
}
|
||
if(ms_bCaptureInput == false)
|
||
return 0;
|
||
wchar_t w[10];
|
||
MultiByteToWideChar(ms_uInputCodePage, 0, (char*)&c, 1, w, 1);
|
||
|
||
OnChar(w[0]);
|
||
if (w[0] == L'|')
|
||
OnChar(w[0]);
|
||
if(ms_pEvent)
|
||
ms_pEvent->OnUpdate();
|
||
break;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|