c++實現輸入法窗口自定義的代碼


#pragma once

#include <Windows.h>
#include <imm.h>

#include <string>

#pragma comment ( lib , "imm32.lib" )


//字符串臨時緩存長度
#ifndef _MAX_BUF_
#define _MAX_BUF_ 256
#endif

/*
功能:取輸入法窗口候選字列表,輸入法名稱及狀態
為自己繪制“輸入法窗口”創造必要條件。
標題:實現輸入法窗口自定義
關鍵詞:IME VC 輸入法 輸入法窗口
最后修改日期:2010-09-02
Remark:當前環境VS2008+SP1 WinXPSP3。編譯選項為Unicode。
http://dev.gameres.com/Program/Control/ime.htm
CGetIme為單實例類
測試:在Irrlicht1.7.1中測試通過。
在標准Win32窗口程序中測試通過。
*/
class CGetIme
{
public:
CGetIme(void)
{
m_hWnd = NULL ;
}
~CGetIme();

//功能:初始化當前類的實例,使之可用。
//Remark:你只能在hWnd的屬主(線程)中調用這個函數
//建議在WM_CREATE或WM_IME_SETCONTEXT中調用
void setHWnd(HWND hWnd);

//功能:取候選字列表,和當前輸入的候選key
//Remark:建議在WM_IME_NOTIFY的wParam為以下
//IMN_OPENCANDIDATE和IMN_CHANGECANDIDATE事件
//時調用
//strCS=>已經鍵入的Key,strCL=>候選字列表
void getCandidateList(std::string &strCS,std::string &strCL);

//功能:取輸入法名稱
std::string getDescription();

//功能:取輸入法狀態
std::string getConversion();

//Remark:建議在IMN_CLOSECANDIDATE事件時,關掉對“自定義輸入法窗口”的繪制。

//Remark:WM_IME_CHAR事件中,你會得到,轉換后的字符串,
//不過你是一個wchar_t一個wchar_t的得到,參考下面的代碼段
//char bits [2] = { (char) ((wParam & 0xff00)>> 8), (char) (wParam & 0xff) },wchar_t t = bits;


//禁止輸入法
void disableIME();
//允許輸入法
void enableIME();
protected:
HWND m_hWnd;
HIMC m_hIMC;

std::string m_candidate; //候選字列表
std::string m_description; //輸入法名稱
std::string m_conversion; //輸入法狀態
std::string m_compstr; //已經鍵入的key
};

 

//=======================================================

#include "StdAfx.h"
#include "GetIme.h"

#include <assert.h>

#include "../T3D3_Irrlicht161/Utils.h"

void CGetIme::setHWnd(HWND hWnd)
{
m_hWnd = hWnd;

//ImmGetContext cannot get input context of other process. ImmGetContext internally
//checks whether the process of the target window is the current process.
//If the check fails, the function returns NULL.
m_hIMC = ::ImmGetContext(m_hWnd);
assert(m_hIMC);

//Below,Hide IME window
HWND hWndIME = ::ImmGetDefaultIMEWnd(hWnd);
if (hWndIME)
::ShowWindow(hWndIME,SW_HIDE);
}

CGetIme::~CGetIme()
{
//Show IME window
HWND hWndIME = ::ImmGetDefaultIMEWnd(m_hWnd);
if (hWndIME)
::ShowWindow(hWndIME,SW_SHOW);

ImmReleaseContext(m_hWnd, m_hIMC);
}

void CGetIme::getCandidateList(std::string &strCS,std::string &strCL)
{
std::string sR("");
wchar_t buf[32];
char *p;
int nR;
DWORD dwSize;
LPCANDIDATELIST lp;

m_candidate = "";
m_compstr = "";

HKL hKL = ::GetKeyboardLayout(0);//獲得鍵盤布局
if (hKL==0)
{
OutputDebugString(L"hKL==0/n");
return ;
}

if( m_hIMC == NULL)
{
OutputDebugString(L"hIMC ==0/n");
return ;
}

ZeroMemory(buf,sizeof(buf));

ImmGetCompositionString(m_hIMC, GCS_COMPSTR, buf, 20);
std::wstring wsB=buf;
strCS = ws2s(wsB);
m_compstr = strCS;

dwSize = ImmGetCandidateList(m_hIMC, 0, NULL, 0);

if (dwSize>0)
{
p=new char[dwSize];
lp = (LPCANDIDATELIST)p;

nR = ImmGetCandidateList(m_hIMC, 0, lp, dwSize);
//若是取其它窗口的IMM狀態,則lp->dwStyle的值為零(Unknown)。
//否則返回一,表示可以讀取lp指向的數據結構!

if (nR && lp->dwCount>1)
{
int i=1;
strCL = "";
char temp[_MAX_BUF_];
ZeroMemory(temp,sizeof(temp));

int nOffset;

while ( (i<lp->dwCount-lp->dwSelection+1) &&
(i<lp->dwPageSize+1) )
{
std::wstring sT= (wchar_t *)(p + lp->dwOffset[lp->dwPageStart+(i-1)]);
sprintf( temp , " %d." , i);

strCL = strCL + temp;
strCL = strCL + "" + ws2s(sT);
i++;
}
if (strCL.find_first_not_of(' ') != -1)
{
strCL =strCL.substr(strCL.find_first_not_of(' '),strCL.length());
//例如“萬能五筆輸入法中”狀態中輸入字符"k",strCL變為下值
//1.中 2.口 3.員工maa 4.哎呀aka 5.只w 6.員m
}
}

delete p;
}
else
{
OutputDebugString(L"Error: dwSize = ImmGetCandidateList(hIMC, 0, NULL, 0);<= 0 /n");
}
m_candidate = strCL;
}

//取輸入法名稱
std::string CGetIme::getDescription()
{
std::string sR("");

m_description = "";

HKL hKL = ::GetKeyboardLayout(0);//獲得鍵盤布局
if (hKL==0)
return sR;

int iSize = ::ImmGetDescription(hKL, NULL, 0);//獲得輸入法名稱大小

if (iSize>=_MAX_BUF_)
{
OutputDebugString(L"CShowIMEUI::getDescription iSize>=MAX_BUF_SIZE CallError/n");
return sR;
}

if (iSize==0)
{
//如果名稱大小為0則不顯示輸入法狀態
OutputDebugString(L"CShowIMEUI::getDescription iSize==0 CallError/n");
return sR;
}

wchar_t name[_MAX_BUF_];
::ImmGetDescription(hKL,name, _MAX_BUF_ );//獲得輸入法名稱
std::wstring wsName = name;
sR = ws2s(wsName);

m_description = sR;

return sR;
}

//取輸入法狀態
std::string CGetIme::getConversion()
{
DWORD dwConversion;
DWORD dwSentence;
LPDWORD lpfdwConversion = &dwConversion;
LPDWORD lpfdwSentence = &dwSentence;
std::string conversion;

m_conversion = "";
if (m_hIMC==NULL)
{
return "";
}

BOOL ret = ::ImmGetConversionStatus(m_hIMC, lpfdwConversion, lpfdwSentence);
::ImmReleaseContext(m_hWnd,m_hIMC);
char pOutputBuf[_MAX_BUF_];
memset(pOutputBuf,0,_MAX_BUF_);

if (*lpfdwConversion & 0x01) strcat(pOutputBuf, " 中文");
else strcat(pOutputBuf, " 英文");
if (*lpfdwConversion & 0x08) strcat(pOutputBuf, " 全角");
else strcat(pOutputBuf, " 半角");
if (*lpfdwConversion & 0x400) strcat(pOutputBuf, " 中文標點");
else strcat(pOutputBuf, " 英文標點");
if (*lpfdwConversion & 0x80) strcat(pOutputBuf, " 軟鍵盤");
else
conversion = "";

conversion = pOutputBuf;

m_conversion = conversion;

return conversion;
}


void CGetIme::disableIME()
{
m_hIMC = ImmAssociateContext(m_hWnd, NULL);

// It makes IME disable for hWnd window.
// Then you can do whatever you want without IME.

//如果是MFC程序~~~~ 最好在 InitInstance() 下加一句~~
//ImmDisableIME(GetCurrentThreadId());
}

void CGetIme::enableIME()
{
ImmAssociateContext(m_hWnd, m_hIMC);

// If you want to enable IME again,
// then you can use the previous stored IME
// context(hIMC) to restore IME.
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM