0 out of 1 rated this helpful - Rate this topic

WM_INPUTLANGCHANGE message

Applies to: desktop apps only

Sent to the topmost affected window after an application's input language has been changed. You should make any application-specific settings and pass the message to the DefWindowProc function, which passes the message to all first-level child windows. These child windows can pass the message to DefWindowProc to have it pass the message to their child windows, and so on.

A window receives this message through its WindowProc function.

#define WM_INPUTLANGCHANGE              0x0051

Parameters

wParam

The character set of the new locale.

lParam

The input locale identifier. For more information, see Languages, Locales, and Keyboard Layouts.

Return value

Type: LRESULT

An application should return nonzero if it processes this message.

Requirements

Minimum supported client

Windows 2000 Professional

Minimum supported server

Windows 2000 Server

Header

Winuser.h (include Windows.h)

See also

Reference
DefWindowProc
WM_INPUTLANGCHANGEREQUEST
Conceptual
Windows

 

 

Send comments about this topic to Microsoft

Build date: 2/3/2012

Did you find this helpful?
(1500 characters remaining)
Community Content Add
Annotations FAQ
Use TSF instead of this message
See "What broke the input language messages?" by Michael on his blog "Sorting it all Out" ( http://blogs.msdn.com/b/michkap/archive/2006/05/16/598980.aspx ).

This explain why these messages are no longer reliable (since Windows XP!) and how to fix this.
Sample use
I've been battling with this for a few days and finally figured out why my app (apparently) wasn't always receiving change notifications. But first a little background.

At least for me the phrase "The WM_INPUTLANGCHANGE message is sent to the topmost affected window (my emphasis) after an application's input language has been changed" is quite confusing. I first understood it to mean that the MainFrame window of the app would receive the message, however my MainFrame never does receive it. After digging around the 'net and not finding anything useful I finally remembered to use the free Winspector Spy (http://www.windows-spy.com/), an enhanced version of Spy++, to check which windows were actually receiving the WM_INPUTLANGCHANGE message.

To my surprise (and annoyance :-) it seems that any CWnd derived window within the application can (and will) receive the message if it has the focus (even if the window is not editable, just clicking on it effectively sets the focus.) This explained why, in my application with a tree control, richedit control, combobox and list control, I could only occasionally receive the message.

The "solution" to this problem is therefore to add a handler to all CWnd derived child controls, having them resend the message to the parent which can, if/when the message is received, forward it to the child control which actually wants to handle the message.

Actually handling the message is quite easy, although I'm so used to using the wizards that I never seem to remember how to manually construct the message maps any more. For that reason here are the minimal definitions required to handle the WM_INPUTLANGCHANGE message. The code also shows how easy it is to subclass the Edit control of the combobox, opening up all kinds of other possibilities.

I hope this code proves useful, and if not, at least I will have some place to come back to when I forget (again :-) how to implement the message handlers and subclasses!

Finally, here's the code: in the header file of the class implementing a CWnd derived control e.g.

In MyComboBox.h:
// Subclass used to capture messages from the ComboBox Edit control
// allowing the current charset to be changed when WM_INPUTLANGCHANGE
// is received.
class AFX_EXT_CLASS CMyComboEditBox : public CEdit
{
DECLARE_DYNAMIC(CMyComboEditBox)

public:
CMyComboEditBox();
virtual ~CMyComboEditBox();

protected:
afx_msg LRESULT OnInputLangChange(WPARAM wParam, LPARAM lParam);

DECLARE_MESSAGE_MAP()

protected:
CFont* m_pFont;
};

class AFX_EXT_CLASS CMyComboBox : public CComboBox
{
public:
CMyComboBox();
virtual ~CMyComboBox();

DECLARE_DYNAMIC(CMyComboBox)
// ...
// Override Create so we can subclass the Edit portion of the control
BOOL Create(DWORD dwStyle, const RECT &rect, CWnd* pParentWnd, UINT nID);

protected:
CLBComboEditBox m_edit;
// ...

afx_msg LRESULT OnInputLangChange(WPARAM wParam, LPARAM lParam);

DECLARE_MESSAGE_MAP()
};

In MyComboBox.cpp

///////////////////////////////////////////////////////////////////////
//
// CMyComboBox - implementation

CMyComboBox::CMyComboBox()
{
}

CMyComboBox::~CMyComboBox()
{
// Stop subclassing
if (NULL != m_edit.GetSafeHwnd())
m_edit.UnsubclassWindow();
}

IMPLEMENT_DYNAMIC(CMyComboBox, CComboBox)

BEGIN_MESSAGE_MAP(CMyComboBox, CComboBox)
ON_MESSAGE(WM_INPUTLANGCHANGE, OnInputLangChange)
END_MESSAGE_MAP()

// Override Create so we can subclass the Edit control
BOOL CMyComboBox::Create(DWORD dwStyle, const RECT &rect, CWnd* pParentWnd, UINT nID)
{
BOOL fCreated = __super::Create(dwStyle, rect, pParentWnd, nID);
if (fCreated && m_edit.GetSafeHwnd() == NULL)
{
// Note: to use COMBOBOXINFO the following defines must be set in stdafx.h (ie. XP and higher)
// #define WINVER 0x0500
// #define _WIN32_WINNT 0x0501
// #define _WIN32_WINDOWS 0x0500
// #define _WIN32_IE 0x0501

COMBOBOXINFO info = { sizeof(COMBOBOXINFO) };
if (GetComboBoxInfo(&info))
m_edit.SubclassWindow(info.hwndItem);
}
return fCreated;
}

LRESULT CMyComboBox::OnInputLangChange(WPARAM wParam, LPARAM lParam)
{
// Forward the message to the combo's editbox
return m_edit.SendMessage(WM_INPUTLANGCHANGE, wParam, lParam);

// Alternatively send up to the parent to handle
// return GetParent()->SendMessage(WM_INPUTLANGCHANGE, wParam, lParam);
}


///////////////////////////////////////////////////////////////////////
//
// CMyComboEditBox - implementation

IMPLEMENT_DYNAMIC(CMyComboEditBox, CEdit)

CMyComboEditBox::CMyComboEditBox() : m_pFont(NULL)
{
}

CMyComboEditBox::~CMyComboEditBox()
{
if (m_pFont)
delete m_pFont;
}

BEGIN_MESSAGE_MAP(CMyComboEditBox, CEdit)
ON_MESSAGE(WM_INPUTLANGCHANGE, OnInputLangChange)
END_MESSAGE_MAP()

// CMyComboEditBox message handlers

LRESULT CMyComboEditBox::OnInputLangChange(WPARAM wParam, LPARAM lParam)
{
UNUSED_ALWAYS(lParam);

// Get the current font
CFont* pEditFont = GetFont();

// Obtain the font characteristics
LOGFONT lf;
pEditFont->GetLogFont(&lf);

// Set the new charset (e.g. 161 for Greek)
lf.lfCharSet = (BYTE)LOWORD(wParam);

// Keep track of the old font (if any)
CFont* pOldFont = m_pFont;

// Create a new font based on the updated characteristics
m_pFont = new CFont();
m_pFont->CreateFontIndirect(&lf);
SetFont(m_pFont);

// Clean up the previous font (if any)
if (pOldFont) delete pOldFont;

return 0;
}

Value
 WM_INPUTLANGCHANGE = &H51