#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. myeclipse/eclipse添加Spket插件实现ExtJs4.2/ExtJs3智能提示

    前言 感谢luotao,本博客是copy这篇博客的:http://www.cnblogs.com/luotaoyeah/p/3803926.html ,因为太重要了,所以笔者再写一次. 重要说明:ec ...

  2. 给定一颗二叉搜索树,请找出其中的第k小的结点。例如, 5 / \ 3 7 /\ /\ 2 4 6 8 中,按结点数值大小顺序第三个结点的值为4。

    // ConsoleApplication2.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include "stdafx.h ...

  3. [51 nod]1009 数字1的数量

    1009 数字1的数量 基准时间限制:1 秒 空间限制:131072 KB 分值: 5 难度:1级算法题 给定一个十进制正整数N,写下从1开始,到N的所有正数,计算出其中出现所有1的个数.   例如: ...

  4. 将Windows上的文件上传到Linux上

    下载一个SSH Secure Shell Client即可. SSHSecureShellClient-3.2.9下载地址: 免费下载地址在 http://linux.linuxidc.com/ 用户 ...

  5. uva 11825

    刘书上例题  关于集合的动态规划 #include <cstdio> #include <cstdlib> #include <cmath> #include &l ...

  6. Javascript 中判断是谷歌浏览器和IE浏览器的方法

    <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...

  7. mysql 中 isnull 和 ifnull 判断字段是否为null

    对于统计count(type)和avg(type) 都不起作用 SQL中有ISNULL方法,介绍如下: ISNULL使用指定的替换值替换 NULL. 语法ISNULL ( check_expressi ...

  8. eclipse中(装了插件m2eclipse后的)导入maven工程显示"感叹号"

      有时候导入一些开源工程(maven结构的),在eclipse中(装了插件m2eclipse后的)该工程前面会有一个小的红色感叹号,但点开工程后没有发现有打小红叉的内容,这种情况其实大部分是jar包 ...

  9. SQLite操作(C# )

    C#连接SQLite的...方法 http://www.cnblogs.com/virusswb/archive/2010/09/17/SQLite1.html 1 SQLite简介 SQLite,是 ...

  10. iOS开发网络篇--NSURLConnection

    S简介 NSURLConnection: 作用: 1.负责发送请求,建立客户端和服务器的连接发送数据给服务器 2.并收集来自服务器的响应数据 步骤: 1.创建一个NSURL对象,设置请求路径 2.传入 ...