#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.
}

c++实现输入法窗口自定义的代码的更多相关文章

  1. sublime 自定义快捷代码

    选择打开tools ->developer->new snippet <snippet> <content><![CDATA[Hello, ${1:this} ...

  2. Android窗口管理服务WindowManagerService对输入法窗口(Input Method Window)的管理分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/8526644 在Android系统中,输入法窗口 ...

  3. CEGUI 输入法窗口实现

    游戏中经常要输入汉字,但当我们游戏没有自己实现输入法窗口时,windows会使用用户安装的输入法,但这个输入法窗口只会显示在游戏窗口外头,而且当我们游戏全屏时(真全屏,不是那种窗口式的假全屏),屏幕上 ...

  4. 雷林鹏分享:jQuery EasyUI 窗口 - 自定义窗口工具栏

    jQuery EasyUI 窗口 - 自定义窗口工具栏 默认情况下,窗口(window)有四个工具:collapsible.minimizable.maximizable 和 closable.比如我 ...

  5. 雷林鹏分享:jQuery EasyUI 窗口 - 自定义带有工具条和按钮的对话框

    jQuery EasyUI 窗口 - 自定义带有工具条和按钮的对话框 您可以创建一个带有工具栏(toolbar)和按钮(button)的对话框(dialog),可以从 HTML 标记创建.这个教程描述 ...

  6. 自定义sublime代码片段

    sublime text 已经有一些他们内置的一些代码片段,但是有时候,这些并不能满足我们,这就需要我们自定义一些代码片段. 步骤如下: 1.打开sublime text 2.选择 tools -&g ...

  7. sublime自定义snippet代码片段

    相信很多人喜欢sublime编辑工具有两个原因:第一sublime很轻巧方便:第二sublime提供很多自定义拓展功能,包括很简单且和很好用的代码片段功能snippet文件. 今天,在这里就介绍下su ...

  8. 重新想象 Windows 8 Store Apps (27) - 选取器: 联系人选取窗口, 自定义联系人选取窗口

    原文:重新想象 Windows 8 Store Apps (27) - 选取器: 联系人选取窗口, 自定义联系人选取窗口 [源码下载] 重新想象 Windows 8 Store Apps (27) - ...

  9. 重新想象 Windows 8 Store Apps (26) - 选取器: 自定义文件选取窗口, 自定义文件保存窗口

    原文:重新想象 Windows 8 Store Apps (26) - 选取器: 自定义文件选取窗口, 自定义文件保存窗口 [源码下载] 重新想象 Windows 8 Store Apps (26) ...

随机推荐

  1. 3573: [Hnoi2014]米特运输 - BZOJ

    Description米特是D星球上一种非常神秘的物质,蕴含着巨大的能量.在以米特为主要能源的D星上,这种米特能源的运输和储存一直是一个大问题.    D星上有N个城市,我们将其顺序编号为1到N,1号 ...

  2. 一些css效果积累

    悬浮效果: ul li a{text-decoration: none;color: black}  ul li a:hover{color: blue}   鼠标变小手 span:hover{cur ...

  3. Window 2008 R2 + IIS7.5 + VS2013 错误代码 0x80070002

    HTTP 错误 404.0 - Not Found 您要找的资源已被删除.已更名或暂时不可用.详细错误信息模块 IIS Web Core通知 MapRequest Handler处理程序 Static ...

  4. 【锋利的JQuery-学习笔记】切换网页皮肤-且保存于Cookie

    切换网页皮肤: html片段: <head> <link rel="stylesheet" href="styles/skin/skin_0.css&q ...

  5. SVN库实时同步设置

    为了安全起见,SVN服务器除了做定时全量备份和增量备份以外,如条件允许,可做实时备份. 这需要2台机器,一台是master server,另一台做mirror server.master做主服务,mi ...

  6. Open Phone, SMS, Email, Skype and Browser apps of Android in Unity3d

    最近项目需要使用Android的一些基本功能,写插件各种悲剧,google了一下,如获至宝.Nice ! string url = String.Format("tel:{0}", ...

  7. sql over()---转载

    1.使用over子句与rows_number()以及聚合函数进行使用,可以进行编号以及各种操作.而且利用over子句的分组效率比group by子句的效率更高. 2.在订单表(order)中统计中,生 ...

  8. Elasticsearch 学习~

    http://cloud.51cto.com/art/201505/476322.htmEs https://www.gitbook.com/book/asdgh000/mongodb-elastic ...

  9. 在UWSGI和NGINX配合的情况下,配置个别目录上传及超时

    笨办法就是多加一个LOCATION. 然后,自定义以下类似参数 client_max_body_size uwsgi_connect_timeout uwsgi_read_timeout server ...

  10. PHP WAMP关闭notice等提示

    这是xdebug的的错误报告.在开发环境下,可以考虑将其开启,但是在部署到真实应用环境下应该将其关掉. 找到你的php.ini 在最后几行注释掉所有关于xdebug的东西,重启apache即可!