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