Equivalent of PreviewKeyDown of C# needed for native C++/MFC - c#

I used a ActiveXControl in a C# Forms application and had the possibility to implement a PreviewKeyDown event handler for that ActiveXControl. That was needed to specify that, e.g. the [ALT] key, is an input key.
For some reasons or other I have to reimplement the application in native C++/MFC and don't know how to specify that this [ALT] key is an input key and to be handled by the ActiveXControl.

You could use SetTimer to generate a WM_TIMER event 20 times a second or so
SetTimer( NULL, kMyTimer, 50, MyTimerCallback );
Then implement a function as follows.
void CALLBACK MyTimerCallback( HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime )
{
static short lastLeftAltPress = 0;
short thisLeftAltPress = GetAsyncKeyState( VK_LMENU );
if ( thisLeftAltPress != 0 && lastLeftAltPress == 0 )
{
CallAltHandlingCode();
}
thisLeftAltPress = lastLestAltPress;
// Handling code for other keys goes here.
}
This will then poll the keyboard every 50ms to find out if the left alt key has just been pressed and then call your handling code. If you want to fire the handler when its released then you would use the following if statement
if ( thisLeftAltPress == 0 && lastLeftAltPress != 0 )
or if you just want to see if it is down then you do
if ( thisLeftAltPress != 0 )
The docs for GetAsyncKeyState do state that you can check whether the lowest bit is set to see if the key has just been pressed but it does also point out that this may fail in unexpected ways in multi-threaded environments. The above scheme should always work.

thanks for all your recommendations.
For my case I finally found some way how to make it work. So far what I have learnt the situation is that a PreviewKeyDown event is triggered before the KeyDown message is sent.
I implemented PreTranslateMessage in the dialog which hosts the ActiveX control and called ::SendMessage(WM_KEYDOWN...) with the handle of the ActiveX control, using pMsg for the arguments.
Cheers,
Ilmari

I think that you can use the GetAsyncKeyState Win32 function (http://msdn.microsoft.com/en-us/library/ms646293%28VS.85%29.aspx) to get the state of all the keys in the system, VK_MENU (http://msdn.microsoft.com/en-us/library/dd375731%28v=vs.85%29.aspx) is the key you should monitor for the [Alt] key.

Haven't tried this, but MSDN doesn't say that you won't get a WM_KEYDOWN for the ALT key -- any other key pressed while ALT is down generates a WM_SYSKEYDOWN, but that doesn't say that you can't handle ALT via WM_KEYDOWN.

Related

SendInput events don't get processed in specific UI area of game

I have a C# application which sends keyboard and mouse events to a game. In the game there's a small UI portion which can change based on what we want to see (like GPS map, different actions to take etc). Sometimes in this portion of the UI we have to press 'Enter' (or another key depending on how the user configured the game's keys) to activate something (for example, press Enter to activate Rescue service).
Now , the problem: all the key events sent from the c# app are processed fine OUTSIDE of this UI, except this 'activate' thing. At first I thought there's a problem with the 'ENTER' (Return) key event, but after chaning it to another key that was working in-game, I noticed that key is also ignored.
I am not sure if it's a problem related to the way I send the messages (maybe it needs to have a specific parameter) and it can be fixed by modifying my app, or is some blockage in-game - and in this case there's nothing I can do.
Here's the code I use to send the key events:
public static void PressKey(short key)
{
INPUT[] inputs = new INPUT[]
{
new INPUT
{
type = INPUT_KEYBOARD,
u = new InputUnion
{
ki = new KEYBDINPUT
{
wVk = (ushort)0,
wScan = (ushort)key,
dwFlags = KEYEVENTF_SCANCODE,
dwExtraInfo = IntPtr.Zero,
}
}
},
new INPUT
{
type = INPUT_KEYBOARD,
u = new InputUnion
{
ki = new KEYBDINPUT
{
wVk = (ushort)0,
wScan = (ushort)key,
dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP,
dwExtraInfo = GetMessageExtraInfo(),
}
}
}
};
SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(typeof(INPUT)));
}
But hoping its the 1st case, I would appreciate any help with this.
Added a screenshot in order to try to better explain the issue
(A) -> That is the UI window that requires "ENTER" to be pressed. Let's suppose that I modify the settings of the game to have "E" instead of "Enter" for the ACTIVATE action. Then the text "Call Assistance Service (ENTER)" will now show "Call Assistance Service (E)". By default, the "E" key is engine start in the game. And it works just fine (in the case (B)) . As soon as I change E to be 'Activate' , it's being completely ignored.
Another point which might (or might not) be relevant , is that the F-keys that can be at the bottom of the UI Window, also WORK just fine.
I hope this clears up the things a little bit more.
I have found what the issue was, and I'm pretty sure it's related to how the game handles the input (but since it's not me who coded the game I cannot guarantee it).
Anyway, to fix my issue, a delay needs to be added between the KEYDOWN and KEYUP events. For the time being I'm using a Timer with a callback for that, but probably there are other ways to do it also (better or not).
Hope this will help someone someday :)

Windows store apps c# - capslock on/off

I have managed to determine if capslock is on or off, so that I can display proper error message. But my code works only, if capslock is off when textbox gets focus. But if it is on, then error message appears when it shouldn't.
private Boolean CapsLock = false; //here...how to determine if it is on or off propperly
private void loginCredentials_KeyUp(object sender, KeyRoutedEventArgs e)
{
switch (e.Key.GetHashCode())
{
//...
case 20:
CapsLock = (CapsLock) ? false : true;
errorMessage.Text = (CapsLock) ? ((App)(App.Current)).loader.GetString("capslockError") : String.Empty;
break;
}
}
The WinRT method to find the current key status is GetKeyState, so you can check the key value directly if you need to (similar to the IsKeyLocked mentioned in comments).
I'd note that switching on the hashcode of the key pressed seems wrong, you should check the key value itself against the code from the VirtualKey enum (I guess you've noticed that the hash code is just this value, meaning that it works).
If you do need to know immediately when a key such as the caps lock is pressed in general, not just when your text field has focus, you can register a key handler on the application root visual. Normally key presses will be consumed by controls like a text box that handle them, but you can use AddHandler with true parameter to listen to all key presses including handled ones, something like:
Window.Current.AddHandler(UIElement.KeyUpEvent, new KeyEventHandler(...), true);
Or alternatively use the Window.Current.CoreWindow.KeyUp event.

Capturing a key without focusing the window

I have a application that always checks if a key like F12 is pressed. It doesn't need to have in focus of my main window of my app. I tried this code:
public int a = 1;
// DLL libraries used to manage hotkeys
[DllImport("user32.dll")]
public static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc);
[DllImport("user32.dll")]
public static extern bool UnregisterHotKey(IntPtr hWnd, int id);
const int MYACTION_HOTKEY_ID = 1;
public Form1()
{
InitializeComponent();
// Modifier keys codes: Alt = 1, Ctrl = 2, Shift = 4, Win = 8
// Compute the addition of each combination of the keys you want to be pressed
// ALT+CTRL = 1 + 2 = 3 , CTRL+SHIFT = 2 + 4 = 6...
RegisterHotKey(this.Handle, MYACTION_HOTKEY_ID, 0, (int) Keys.F12);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x0312 && m.WParam.ToInt32() == MYACTION_HOTKEY_ID)
{
a++;
MessageBox.Show(a.ToString());
}
base.WndProc(ref m);
}
I put 0 to this line RegisterHotKey(this.Handle, MYACTION_HOTKEY_ID, 0, (int) Keys.F12); so that only if F12 is pressed it will capture.
But it didn't work. How can I solve this?
Here I couldn't understand some lines like:
const int MYACTION_HOTKEY_ID = 1;
m.Msg == 0x0312 && m.WParam.ToInt32() == MYACTION_HOTKEY_ID
base.WndProc(ref m);
Can anyone help me to understand these lines?
But it didn't work. How can I solve this?
What do you mean "it didn't work"? The code in your question looks correct to me.
The only reason it might not be working is because the RegisterHotKey function is returning an error and you're not checking for it. To make this work, you need to add the SetLastError attribute to its declaration, which causes the runtime to cache the Win32 error code that it sets. Once this is done, you can check that error code (if the function returns false) by calling the GetLastWin32Error function. I recommend using the result of this function to generate and throw a Win32Exception.
Modify your declaration of RegisterHotKey as follows:
[DllImport("user32.dll", PreserveSig = false)]
public static extern bool RegisterHotKey(IntPtr hWnd,
int id,
uint fsModifiers,
Keys key);
And your call to the function as follows:
if (!RegisterHotKey(this.Handle, MYACTION_HOTKEY_ID, 0, Keys.F12))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
Once that's done, I suspect you'll see an exception getting thrown with the error message:
Hot key is already registered
Well, that makes debugging the problem much simpler, now doesn't it! Chances are you'll need to select a different hot key, since the RegisterHotKey function documentation tells us explicitly that:
The F12 key is reserved for use by the debugger at all times, so it should not be registered as a hot key. Even when you are not debugging an application, F12 is reserved in case a kernel-mode debugger or a just-in-time debugger is resident.
When I run the code and register F11 as a hotkey, it works just fine for me.
Here I couldn't understand some lines like:
const int MYACTION_HOTKEY_ID = 1;
m.Msg == 0x0312 && m.WParam.ToInt32() == MYACTION_HOTKEY_ID
base.WndProc(ref m);
Can anyone help me to understand these lines?
Sure:
The first line declares a constant value that uniquely identifies the hotkey that you installed using the RegisterHotKey function. More specifically, it corresponds to the id parameter of the function. You passed it in on the initial call.
This checks in the window procedure (WndProc) to see if the message (Msg) that is being processed is the WM_HOTKEY message. The WM_HOTKEY message is posted automatically to your window whenever the hot key you registered with the RegisterHotKey function is pressed.
You shouldn't really be using the magic number 0x0312 directly, though, because you're not the only one who is unsure what it means. Instead, define a constant and use that instead:
const int WM_HOTKEY = 0x0312;
m.Msg == WM_HOTKEY
The second part of that conditional test (the part after the &&) checks the wParam field of the message to see if the hot key that was pressed was the one you registered. Remember that MYACTION_HOTKEY_ID is the unique ID of your hot key. The WM_HOTKEY message documentation tells us that checking the wParam is how we determine which hot key was pressed.
This calls the base class's window procedure. In other words, what you've done is overridden the virtual WndProc method, allowing you to add some additional code (your processing of WM_HOTKEY). When you're done with your additional logic, you want to continue with the logic of the base class, so you forward the message on.
Your code has no wrong . But it doesn't work here because the F12 key is reserved you may try with another key like F10, F11 etc .
I don't know why, but I feel like this is related to this question... so I'm gonna try to explain it once more:
const int MYACTION_HOTKEY_ID = 1;
is where you save the integer that is used to identify the hotkey. If you need to register more than on hotkey, you will have to declare other integer fields identifying the other hotkeys:
const int ANOTHER_ACTION_HOTKEY_ID = 2;
const int AND_ANOTHER_ACTION_HOTKEY_ID = 3;
Then,
m.Msg == 0x0312 && m.WParam.ToInt32() == MYACTION_HOTKEY_ID
is the condition that enables you to know which hotkey has been typed by the user.
0x0312 (also declared as WM_HOTKEY in the documentation you can found here for instance) is to know if a registered hotkey has been pressed:
When a key is pressed, the system looks for a match against all hot keys. Upon finding a match, the system posts the WM_HOTKEY message to the message queue of the window with which the hot key is associated. If the hot key is not associated with a window, then the WM_HOTKEY message is posted to the thread associated with the hot key.
According to the documentation, you cannot use the F12 hotkey:
The F12 key is reserved for use by the debugger at all times, so it should not be registered as a hot key. Even when you are not debugging an application, F12 is reserved in case a kernel-mode debugger or a just-in-time debugger is resident.
To do a similar thing I implemented a low-level keyboard hook using SetWindowsHookEx. That will trap all keyboard messages going through Windows, and allow you to inspect them and if necessary, prevent them going any further.
Take a look at my KeyboardHandling project in my RocketLauncher GitHub hobby project. You can take what you need directly from that. I'm going to make it a nuget package soon, too.

How to detect if any key is pressed

How can I detect if any keyboard key is currently being pressed? I'm not interested in what the key is, I just want to know if any key is still pressed down.
if (Keyboard.IsKeyDown(Key.ANYKEY??)
{
}
public static IEnumerable<Key> KeysDown()
{
foreach (Key key in Enum.GetValues(typeof(Key)))
{
if (Keyboard.IsKeyDown(key))
yield return key;
}
}
you could then do:
if(KeysDown().Any()) //...
If you want to detect key pressed only in our application (when your WPF window is activated) add KeyDown like below:
public MainWindow()
{
InitializeComponent();
this.KeyDown += new KeyEventHandler(MainWindow_KeyDown);
}
void MainWindow_KeyDown(object sender, KeyEventArgs e)
{
MessageBox.Show("You pressed a keyboard key.");
}
If you want to detect when a key is pressed even your WPF window is not active is a little harder but posibile. I recomend RegisterHotKey (Defines a system-wide hot key) and UnregisterHotKey from Windows API. Try using these in C# from pinvoke.net or these tutorials:
Global Hotkeys: Register a hotkey that is triggered even when form isn't focused.
Simple steps to enable Hotkey and ShortcutInput user control
Thse is a sample in Microsoft Forums.
You will use Virtual-Key Codes.
I Hope that I was clear and you will understand my answer.
Iterate over the System.Windows.Input.Key enum values.
public static bool IsAnyKeyDown()
{
var values = Enum.GetValues(typeof(Key));
foreach (var v in values)
if (((Key)v) != Key.None && Keyboard.IsKeyDown((Key)v)
return true;
return false;
}
Good answer here...get the set of all the keystates at once using GetKeyboardState():
Detect if any key is pressed in C# (not A, B, but any)
The above is checking the live state of the keyboard.
If you rely on hooking events up to the KeyDown/KeyUp events to track the state of the keyboard...then this may not be so accurate.
That's becuase you are relying on the message pumping to process and dispatch those KeyDown/KeyUp messages....they may be delivered after the real keyboard state has changed again.
Also because when your bit of code that is interested in the keyboard state is running (usually on the UI thread)...the KeyDown or KeyUp can't interrupt you...as they are dispatched on the UI thread too....that's why using GetKeyBoardState() or the Keyboard.IsKeyDown should be used.
(the above is assuming you want and care about the live state)

How to exclude a thread from global hook

We are hooking TextOut(),ExtTextOut() and DrawText() methods GLOBALLY .
i.e.
hhook = SetWindowsHookEx(WH_CBT, function_address, module_handle, 0);
But we want to exclude our application (which we are using to install/uninstall hook) from being hooked. If the last argument to SetWindowsHookEx() is 0(zero) it will hook all the existing threads.How to check here if the current thread is "OurApplication.exe" and then exclude it from hooking or immediately unhook it.
Please provide help.
I don't think it's possible. You either hook to everything or to a specific thread.
Why don't you just filter out your application in whatever code yout have at function_address? Most, if not all, CBT hook callbacks provide window handle at either wParam or lParam argument. You can then get process id from that handle and compare it to your application pid.
Off the top of my head:
Pass the hook dll the PID of the process you want to ignore when you install the hook. Make sure that PID is stored in a shared section so all hook instances see the same value.
In your hook function, check to see if the current process PID matches the one passed in. If it does, don't do your hooky stuff, just pass to CallNextHookEx.
I don't like this because it adds to work done in the hook function, which is always bad. But it seems like it should work in principle.
Thank you experts for replying to our question. We found the way to do that.
Now we added the following block of code in the entry point of the injecting dll.And it is working fine.
BOOL APIENTRY DllMain(HINSTANCE hModule, DWORD dwReason, PVOID lpReserved)
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
IsDebuggerPresent();
// Exclude the "someapplication.exe" from hooking
GetModuleFileName( GetModuleHandle( NULL ),Work,sizeof(Work) );
PathStripPath(Work );
if ( _stricmp( Work, "someapplication.exe" ) != 0 )
{
InstallWindowHooks();
}
break;
case DLL_PROCESS_DETACH:
hWindowReceiver = NULL;
CleanUp();
break;
}
return TRUE;
}

Categories

Resources