Programmatically change keyboard-layout [duplicate] - windows

I found this keyboard hook code, which I'm trying to slightly modify for my purposes: http://blogs.msdn.com/toub/archive/2006/05/03/589423.aspx
As an overview, I want to have the user press a key, say 'E', and have the keyboard return a different character, 'Z', to whatever app is in focus.
The relevant method I changed now looks like:
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
//The truely typed character:
int vkCode = Marshal.ReadInt32(lParam);
Console.WriteLine((Keys)vkCode);
KBDLLHOOKSTRUCT replacementKey = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
replacementKey.vkCode = 90; // char 'Z'
Marshal.StructureToPtr(replacementKey, lParam, false);
//Now changed to my set character
vkCode = Marshal.ReadInt32(lParam);
Console.WriteLine((Keys)vkCode);
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
The console correctly outputs this as:
E
Z
T
Z
G
Z
etc.
HOWEVER, the in focus app still types 'E' instead of 'Z'. Why? I changed the hooked keyboard input to contain 'Z' instead of 'E', and the console lines show that it was changed correctly!
As I understand it, calling the return CallNextHookEx(_hookID, nCode, wParam, lParam); is what sends the "print this now" command to the open app. Is that not how it works? Is there something that's preventing me from typing the character I want? I know apps like AutoHotkey take an input key, check it, and return a different character. How do I do the same here?
Thanks!

I've done this before but a little different.
Instead of trying to change the parameters sent to CallNextHookEx, I 'swallowed' the key press (you can do this by returning a nonzero value from the hook procedure to prevent subsequent procedures from being called).
Then I used SendInput to send the new key that I wanted to 'inject'.
So basically it works like this:
Hook procedure identifies a target key is pressed
Call to SendInput, with the new key
Return 1 from the hook procedure to ignore the original key
Be careful of cyclic redirects, i.e. 'a' redirected to 'b' redirected to 'a', it can easily blow up ;)

You have, most likely, installed the hook "thread wide" and not "system wide", which means that the key translation will occur only for the thread installing the hook.
In order to install it "system wide" you will need two pieces: one dll having the "hook provider" and an exe managing it.
Here is a good tutorial
http://www.codeproject.com/KB/system/hooksys.aspx
and here an example:
http://www.codeguru.com/cpp/com-tech/shell/article.php/c4509/
But:
1. Installing system wide hooks can seriously screw up you system (make sure that you forward the keys that you don't translate).
2. Please... don't create another keylogger

Related

Are there any Win32 functions I can use to get the count / itemdata from a CComboBoxEx control?

My parent dialog has a CComboBoxEx control (which is mapped to a derived class called CDatesComboBoxEx).
In one part of the application this dialog displays a popup modal dialog. And, inside the modal dialog, it needs access to information from the dates combo.
What I decided to do (which works fine) is pass the address of my combo in the constructor of the popup dialog. So I can now do things like:
m_pComboDates->GetCount()
m_pComboDates->GetItemDataPtr(i)
I was wondering if there was any way to use native Win32 code here instead?
We can get access to the parents handle (GetParent()->GetSafeHWnd()).
We know the ID of the control on the parent dialog (IDC_COMBOBOXEX_OCLM_WEEK_OF_MEETING).
So is it possible to somehow directly get the count and item data?
I know that there are these macros:
ComboBox_GetCount
ComboBox_GetItemData
But:
Can these be macros be used with CComboBoxEx control? And ...
How do we get the HWND on the combo given the context I previously described?
Actually, I think I missunderstood the purpose of those "macros". I can get the combo handle like this:
HWND hDatesCombo = ::GetDlgItem(
GetParent()->GetSafeHwnd(), IDC_COMBOBOXEX_OCLM_WEEK_OF_MEETING);
But, ComboBox_GetCount does not return a value. Nor the others. So I am somewhat confused.
Based on the answer, this bit is now fine:
HWND hDatesCombo = ::GetDlgItem(GetParent()->GetSafeHwnd(), IDC_COMBOBOXEX_OCLM_WEEK_OF_MEETING);
int iNumDates = static_cast<int>(::SendMessage(hDatesCombo, CB_GETCOUNT, 0, 0));
And inside my for loop I am doing this:
LRESULT itemData = ::SendMessage(hDatesCombo, CB_GETITEMDATA, static_cast<WPARAM>(i), 0);
auto* pEntry = static_cast<CChristianLifeMinistryEntry*>((LPVOID)itemData);
That is the only way I can find to cast it. If I try static_cast<LPVOID> it won't work either.
I was wondering if there was any way to use native Win32 code here instead?
Yes, there is. The SendMessage function (and its returned value) is what you need …
Once you have the HWND of your combo-box, you can send it the CB_GETCOUNT message to ask it how many items it contains:
HWND hDatesCombo = ::GetDlgItem(GetParent()->GetSafeHwnd(), IDC_COMBOBOXEX_OCLM_WEEK_OF_MEETING);
LRESULT nItems = ::SendMessage(hDatesCombo, CB_GETCOUNT, 0, 0);
And, to get the item data associated with a particular entry, send the CB_GETITEMDATA message, with the (zero-based) index of the item in question as the wParam argument:
//...
LRESULT *ItemData = new LRESULT[static_cast<size_t>(nItems)];
for (int i = 0; i < nItems; ++i) {
ItemData[i] = ::SendMessage(hDatesCombo, CB_GETITEMDATA, static_cast<WPARAM>(i), 0);
}
//...
delete[] ItemData; // When you're done with the data list
Of course, if your item data are pointers (such as if you have an owner-drawn combo with1 the CBS_HASSTRINGS style), you would need to modify the second code snippet accordingly, adding relevant the reinterpret_cast operations where necessary. (Note that both the LRESULT and WPARAM types are defined as being suitable for storing pointers.)
1 The linked M/S documentation page is a bit fuzzy on whether this applies to owner-drawn combos with or without the CBS_HASSTRINGS style.

How to extract the character from WM_KEYDOWN in PreTranslateMessage(MSG*pMsg)

In a MFC application within PreTranslateMessage(MSG *pMsg) inherited from a CView, I have this:
if (pMsg->message == WM_KEYDOWN) ...
The fields in a WM_KEYDOWN are documented here. The virtual key VK_ value is in pMsg->wParam and pMsg->lParam contains several field, of which bits 16-23 is the keyboard scan code.
So in my code I use:
const int virtualKey = pMsg->wParam;
const int hardwareScanCode = (pMsg->lParam >> 16) & 0x00ff; // bits 16-23
On my non-US keyboard for example, when I press the "#" character, I get the following:
virtualKey == 0xde --> VK_OEM_7 "Used for miscellaneous characters; it can vary by keyboard."
hardwareScanCode == 0x29 (41 decimal)
The character I'd like to "capture" or process differently is ASCII "#", 0x23 (35 decimal).
MY QUESTION
How do I translate the WM_KEYDOWN information to get something I can compare against, regardless of language or keyboard layout? I need to identify the # key whether the user has a standard US keyboard, or something different.
For example, I've been looking at the following functions such as:
MapVirtualKey(virtualkey, MAPVK_VSC_TO_VK);
// previous line is useless, the key VK_OEM_7 doesn't map to anything without the scan code
ToAscii(virtualKey, hardwareScanCode, nullptr, &word, 0);
// previous line returns zero, and zero is written to `word`
Edit:
Long story short: On a U.S. keyboard, SHIFT+3 = #, while on a French keyboard SHIFT+3 = /. So I don't want to look at individual keys, instead I want to know about the character.
When handling WM_KEYDOWN, how do I translate lParam and wParam (the "keys") to find out the character which the keyboard and Windows is about to generate?
I believe this is a better solution. This one was tested with both the standard U.S. keyboard layout and the Canadian-French keyboard layout.
const int wParam = pMsg->wParam;
const int lParam = pMsg->lParam;
const int keyboardScanCode = (lParam >> 16) & 0x00ff;
const int virtualKey = wParam;
BYTE keyboardState[256];
GetKeyboardState(keyboardState);
WORD ascii = 0;
const int len = ToAscii(virtualKey, keyboardScanCode, keyboardState, &ascii, 0);
if (len == 1 && ascii == '#')
{
// ...etc...
}
Even though the help page seems to hint that keyboardState is optional for the call to ToAscii(), I found that it was required with the character I was trying to detect.
Found the magic API call that gets me what I need: GetKeyNameText()
if (pMsg->message == WM_KEYDOWN)
{
char buffer[20];
const int len = GetKeyNameTextA(pMsg->lParam, buffer, sizeof(buffer));
if (len == 1 && buffer[0] == '#')
{
// ...etc...
}
}
Nope, that code only works on keyboard layouts that have an explicit '#' key. Doesn't work on layouts like the standard U.S. layout where '#' is a combination of other keys like SHIFT + 3.
I'm not an MFC expert, but here's roughly what I believe its message loop looks like:
while (::GetMessage(&msg, NULL, 0, 0) > 0) {
if (!app->PreTranslateMessage(&msg)) { // the hook you want to use
TranslateMessage(&msg); // where WM_CHAR messages are generated
DispatchMessage(&msg); // where the original message is dispatched
}
}
Suppose a U.S. user (for whom 3 and # are on the same key) presses that key.
The PreTranslateMessage hook will see the WM_KEYDOWN message.
If it allows the message to pass through, then TranslateMessage will generate a WM_CHAR message (or something from that family of messages) and dispatch it directly. PreTranslateMessage will never see the WM_CHAR.
Whether that WM_CHAR is a '3' or a '#' depends on the keyboard state, specifically whether a Shift key is currently pressed. But the WM_KEYDOWN message doesn't contain all the keyboard state. TranslateMessage keeps track of the state by taking notes on the keyboard messages that pass through it, so it knows whether the Shift (or Ctrl or Alt) is already down.
Then DispatchMessage will dispatch the original WM_KEYDOWN message.
If you want to catch only the '#' and not the '3's, then you have two options:
Make your PreTranslateMessage hook keep track of all the keyboard state (like TranslateMessage would normally do). It would have to watch for all of the keyboard messages to track the keyboard state and use that in conjunction with the keyboard layout to figure whether the current message would normally generate a '#'. You'd then have to manually dispatch the WM_KEYDOWN message and return TRUE (so that the normal translate/dispatch doesn't happen). You'd also have to be careful to also filter the corresponding WM_KEYUP messages so that you don't confuse TranslateMessage's internal state. That's a lot of work and lots to test.
Find a place to intercept the WM_CHAR messages that TranslateMessage generates.
For that second option, you could subclass the destination window, have it intercept WM_CHAR messages when the character is '#' and pass everything else through. That seems a lot simpler and well targeted.

Double click in empty area of CListBox does not call my double click function

I am using Visual Studio MFC for GUI programming.
I currently have a CListBox, and I want it to call a function when I double click on an empty part of it. (when no item is selected) Currently, I am only able to add items to it by pressing a separate button.
I made the following test code to test whether the CListBox is responding to a double click at an empty spot.
BEGIN_MESSAGE_MAP(CScnBuildDlg, CDialog)
ON_LBN_DBLCLK(IDC_EVENT_LIST, OnDblclkEventList)
END_MESSAGE_MAP()
void CScnBuildDlg::OnDblclkEventList()
{
exit(-1); //Currently, it only exits when double clicking on a specific item, not on an empty space
}
Any ideas on how to fix this?
Thanks.
An additional way of trapping this event is possible by using CWnd::Oncommand. If you add this event handler to your dialog code as follows, you will be able to trap the double-click.
BOOL CScnBuildDlg::OnCommand(
WPARAM wParam,
LPARAM lParam
)
{
if (LOWORD(wParam) == IDC_EVENT_LIST && HIWORD(wParam) == LBN_DBLCLK)
DoSomething ();
return CDialog::OnCommand(wParam, lParam);
}
However, you'll need to be careful because this event will trap the double-click on an existing list box item as well. You'll also need to make sure that you allow the base class a chance to handle the WM_COMMAND message. If not, you may experience some strange bugs.

EN_UPDATE does not send to the subclassed edit box procedure

I have subclassed Edit control window procedure and then found out it no longer
sent the EN_UPDATE.
Am I missing something , and could somebody suggest me a workaround on this one?
LRESULT CALLBACK EditBoxProc_textbox3( HWND hwnd, UINT message , WPARAM wParam, LPARAM lParam )
{
int previous_position = 0 ;
WCHAR previous_text [1024];
WCHAR current_text [1024];
switch (message)
{
case WM_CREATE:
previous_text[0] = L'\0';
current_text[0] = L'\0';
break;
case EN_SETFOCUS:
// :TODO: read the current text of the textbox3 and update textbox2
// text according to it. //
Edit_Enable(hwndTextBox2,FALSE);
break;
case EN_UPDATE:
MessageBox(NULL,L"EN_UPDATE", lpszAppName,MB_OK);
GetWindowText( hwndTextBox3, current_text ,1024);
if( is_valid_textbox3(current_text))
{
wcscpy(previous_text,current_text);
previous_position = LOWORD(Edit_GetSel(hwndTextBox3));
update_textbox2(NULL);
}else
{
SetWindowText(hwndTextBox3, previous_text );
Edit_SetSel(hwndTextBox3,previous_position, previous_position);
}
break;
case EN_KILLFOCUS:
Edit_Enable(hwndTextBox2,TRUE);
break;
default:
break;
}
return CallWindowProc(edit_old_wndproc_textbox3,hwnd,message,\
wParam,lParam);
}
and then found out it no longer sent the EN_UPDATE
It never sent EN_UPDATE in the first place. It is a notification message that's actually sent as a WM_COMMAND message. And it is sent to the parent of the Edit control, not the control itself. Same goes for EN_SET/KILLFOCUS.
The design philosophy here is that an Edit control can simply be put on, say, a dialog. And the custom code that makes the dialog behave in a certain way is written in the parent window's procedure with no requirement to subclass the control. Which is fine but it makes it difficult to create a customized edit control that can have its own behavior. Or in other words, it makes it hard to componentize an edit control. The EN_SET/KILLFOCUS notifications are not a problem, you can simple detect their corresponding WM_SET/KILLFOCUS messages. But you'll hit the wall on EN_UPDATE, the control doesn't send any message like that to itself. Only the parent window can detect it.
Componentizing an edit control is pretty desirable and actively pursued by object-oriented class libraries like Winforms and Qt. They have a class wrapper for the control (TextBox, QLineEdit) that has a virtual method that can be overridden (OnTextChanged, changeEvent) so that the control can be customized into a derived class with its own behavior. And generate an event (aka signal) that anybody can subscribe to, not just the parent (TextChanged, textChanged). To make that work, the parent window needs to participate. When it gets the WM_COMMAND message, it must echo the notification back to the child control. Either by sending a special message back or by calling a virtual method on the child class.
You can of course implement this yourself as well, albeit that you are liable of reinventing such a class library. Consider using an existing one instead.

Intercept CDialog creation

I have a rather large app that displays many different MFC CDialog-derived dialog windows. All of the dialogs are displayed from a central function that is similar to this:
void ShowDialog(CDialog& dlg)
{
dlg.DoModal();
}
Now I need to essentially call a function in every dialog's OnInitDialog method. It doesn't technically need to be within OnInitDialog, but preferably before the dialog is visible.
The brute force method would be to go through the code and find every last dialog and add the function call to the OnInitDialog method (if it has one, and if it doesn't, add one). But it seems like there must be a more elegant way...
Note that dlg is not actually a CDialog, but something that derives from it.
Any thoughts, tricks or hacks? I'm not above patching the message map, but hope to find something cleaner/safer.
If you've got a common ancestor for all your dialogs, which you seem to imply you have, then you can simply put the code in that common ancestor in a suitable location of your choice. For example OnInitDialog() is virtual.
Turns out it is quite easy to do:
HHOOK gPrevHook = SetWindowsHookEx(WH_CALLWNDPROCRET, HookProc, NULL, myGUIThreadID);
LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if(NULL != wParam)
{
CWPRETSTRUCT* pS = (CWPRETSTRUCT*)lParam;
if(WM_INITDIALOG == pS->message)
CallFuncOnWindow(pS->hwnd);
}
return CallNextHookEx(gPrevHook, nCode, wParam, lParam);
}
Probably not the thing to do for a high performance app, but for something that is a simple GUI it works perfectly. No other code changes required.

Resources