HomeQuestions and AnswersArticlesSamplesLibrariesForumsNewsLinks

How enable IME in my own and common controls?

By Ilya Manin, August 12, 2004.

Question

By default IME (input method editor) is enabled for edit box and list box controls. All other controls get numeric key codes from hardware keys directly. What can I do, if I need to get alphabetic characters in other controls? For example, List View control can perform simple item search by first characters of items. But the control doesn't get any alphabetic characters without IME.

Answer

First of all, include windowsm.h and tpcshell.h headers in your code. Note that you don't need to link to any special libraries since all functions related to IME are located in coredll.lib. To enable IME in a window you have to handle WM_SETFOCUS and WM_KILLFOCUS messages and enable or disable IME using ImmSetOpenStatus function. Also, you can activate any specific input mode using ImmEscape function. The following example shows how to enable IME for a List View control using WTL library:

#include <windowsm.h>
#include <tpcshell.h>
. . .
class CListViewIME: public CWindowImpl<CListViewIME, CListViewCtrl>
{
public:
	DECLARE_WND_SUPERCLASS(NULL, CListViewCtrl::GetWndClassName());
	BEGIN_MSG_MAP(CListViewIME)
		MESSAGE_HANDLER(WM_KILLFOCUS, OnKillFocus)
		MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
	END_MSG_MAP()

	BOOL OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		bHandled = FALSE;
		// Get current input context
		HIMC hC = ImmGetContext(m_hWnd);		
		// Open the IME 
		ImmSetOpenStatus(hC, TRUE);
		// Set "multi-press" input mode
		ImmEscape(NULL, hC, IME_ESC_SET_MODE, (LPVOID)IM_SPELL);
		return 0;
	}

	BOOL OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		bHandled = FALSE;
		// Get current input context
		HIMC hC = ImmGetContext(m_hWnd);
		// Close the IME 
		ImmSetOpenStatus(hC, FALSE);
		return 0;
	}
};
		

This is all you need to do to enable IME. However, to work gracefully with other controls you additionally need to do the following:

  • Check if IME is needed by the next control getting focus from you (by sending WM_IME_REQUEST message). If this control needs IME, do not deactivate it.
  • Report to other controls that your control needs IME (by responding to WM_IME_REQUEST message).
The following example shows how to do this in WTL:

#include <windowsm.h>
#include <tpcshell.h>
. . .
class CListViewIME: public CWindowImpl<CListViewIME, CListViewCtrl>
{
public:
	DECLARE_WND_SUPERCLASS(NULL, CListViewCtrl::GetWndClassName());
	BEGIN_MSG_MAP(CListViewIME)
		MESSAGE_HANDLER(WM_IME_REQUEST, OnRequest)
		MESSAGE_HANDLER(WM_KILLFOCUS, OnKillFocus)
		MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
	END_MSG_MAP()

	BOOL OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		bHandled = FALSE;
		HIMC hC = ImmGetContext(m_hWnd);
		ImmSetOpenStatus(hC, TRUE);
		ImmEscape(NULL, hC, IME_ESC_SET_MODE, (LPVOID)IM_SPELL);
		return 0;
	}
	BOOL OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		bHandled = FALSE;
		HIMC hC = ImmGetContext(m_hWnd);		
		//Check if IME is needed by window that got focus
		if (!IsImeNeeded((HWND) wParam))
			ImmEscape(NULL, hC, IME_ESC_RETAIN_MODE_ICON, (LPVOID)TRUE);
		ImmSetOpenStatus(hC, FALSE);
		return 0;
	}
	BOOL OnRequest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		if (wParam == IMR_ISIMEAWARE)
		{
			return IMEAF_AWARE;
		}
		bHandled = FALSE;
		return 0;
	}
private:
	// Private method for checks if IME aware 
	BOOL IsImeNeeded(HWND hWnd)
	{
		DWORD dwRes = SendMessage(hWnd, WM_IME_REQUEST, IMR_ISIMEAWARE, 0);
		return (dwRes & IMEAF_AWARE) == IMEAF_AWARE;
	}
};
		

If you want to use this code in "pure" API application, you can add follow code to window procedure of your window:

#include <windowsm.h>
#include <tpcshell.h>
. . .
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	HIMC hC;
	switch (message) 
	{
		case WM_SETFOCUS:
		{
			hC = ImmGetContext(m_hWnd);
			ImmSetOpenStatus(hC, TRUE);
			ImmEscape(NULL, hC, IME_ESC_SET_MODE, (LPVOID)IM_SPELL);
			return 0;
		}
		break;
		case WM_KILLFOCUS:
		{
			DWORD dwRes = SendMessage((HWND)wParam, WM_IME_REQUEST, IMR_ISIMEAWARE, 0);
			hC = ImmGetContext(m_hWnd);
			if (dwRes & IMEAF_AWARE) == IMEAF_AWARE)
				ImmEscape(NULL, hC, IME_ESC_RETAIN_MODE_ICON, (LPVOID)TRUE);
			ImmSetOpenStatus(hC, FALSE);
			return 0;
		}
		break;
		case WM_IME_REQUEST:
		{
			if (wParam == IMR_ISIMEAWARE)
			{
				return IMEAF_AWARE;
			}
		}
		break;
	}
	return DefWindowProc(hWnd, message, wParam, lParam);
}
		

Discuss

Discuss this QA. Here you can write your comments and read comments of other developers.

  © 2002 Smartphone Developer Network | Want to be an author? | Contact Us