How to Piggyback a Keypress?

N

NvrBst

Is there a easy way to resend the KeyPress to the window after
capturing a hotkey?

protected override void WndProc(ref Message m) {
base.WndProc(ref m);
if(m.Msg == WM_HOTKEY) {
if(m.WParam == myHotkeyID) /* Do What I Want to
Do */
Resend the Key Pressed to the application without
triggering the hotkey message again.
}
}
}

it works if I use the C# "SendKeys.Send(...)", and mimics the "ctrl/
shift/alt modifiers" nicely, but the hotkeys are defined by the user,
and converting the "Keys.___" to a string manually is hard at times...
"IE Keys.OemTilda.ToString()" != "`"

Is using PostMessage the easiest? Getting the SYSKEYDOWN, KEYDOWN,
lParam Mimic etc all perfect would take a tiny bit..

Would there be a trick with the DefWndProc/DefWindowProc I could use?
 
N

Nicholas Paldino [.NET/C# MVP]

Well, why do you want to resend the keypress? What are you trying to
do? If all you want to do is do your processing, then let the application
react normally to the keypress, then have done it already (although in a
different order) by calling the WndProc method on the base implementation
(the base.WndProc line).

If you want to do your processing before passing the key along, then
move the call to base.WndProc after your if statement.
 
N

NvrBst

Basically I want to set up a global hotkey for a single (external)
application only. For example, I have my program register a F1
hotkey. Whenever the hotkey is pressed I check to see if the
foreground application is the one I want it to be. If it is I have my
applicaiton react to the F1 key being pressed, if it isn't the
application I want it to be then my program does nothing and I want
the F1 key to be pressed normally like my application wasn't up.

The "base.WndProc(ref m);" doesn't seem to affect anything for the
external programs... Once my program registers the F1 hotkey, no other
application react to the F1 key being pressed (Even with the
"base.WndProc(ref m); line there).

Another options would be unregister all my hotkeys when the
application I want them to affect loses focus, then re-register them
when it gains focus again, but I don't know how to do that other than
setting up a loop that keeps checking forground window which would be
too costly for me.

NB
 
N

Nicholas Paldino [.NET/C# MVP]

So wait a second, why not just code the individual applications to react
to the key that is pressed?
 
N

NvrBst

Only the application that registers the hotkeys is mine... Don't have
the source code of the application that should be active when the
hotkeys are being pressed, or the applications that are active when I
do something else quick (IE Internet Explorer).
 
N

NvrBst

Using the PostMessage Method turned out to be easier than I thought it
was going to be. Heres my code if anyone ever runs into a simular
problem and wants to send a key :)

------------------------------------------------------------------------------------------
[Flags]
public enum mySendKeyFlags : byte {
None = 0x00,
SimReal = 0x01,
SendExtendedKey = 0x02
}
public void SendKey(int key, int[] Modifier, IntPtr
ForGroundWindow, mySendKeyFlags Flags) {
if(Flags & mySendKeyFlags.SimReal !=0) {
byte[] kbState = new byte[255];

AttachThreadInput((uint)AppDomain.GetCurrentThreadId(), (uint)*GET
PROCESS ID OF CURRENT APP*, true);
GetKeyboardState(kbState);
byte[] kbStateMOD = kbState;
for(byte i = 0; i < Modifier.Length; i++)
kbStateMOD[Modifier] = 0x80;
SetKeyboardState(kbStateMOD);

SendKeyHelp(ref key, ref Modifier, ref
ForGroundWindow, ref Flags);

SetKeyboardState(kbState);

AttachThreadInput((uint)AppDomain.GetCurrentThreadId(), (uint)*GET
PROCESS ID OF CURRENT APP*, false);
} else SendDAKeyHelp(ref key, ref Modifier, ref
ForGroundWindow, ref Flags);
}
private void SendKeyHelp(ref int key, ref int[] Modifier, ref
IntPtr ForGroundWindow, ref mySendKeyFlags Flags) {
if(Modifier != null) {
for(byte i = 0; i < Modifier.Length; i++) {
if(Modifier == (int)Keys.Alt)
PostMessage(Params.hWnd, WM_SYSKEYDOWN, Modifier,
(int)MAKELONG(0x1, (ushort)MapVirtualKey((uint)Modifier, 0)));
else PostMessage(Params.hWnd, WM_KEYDOWN,
Modifier, (int)MAKELONG(0x1,
(ushort)MapVirtualKey((uint)Modifier, 0)));
}
}
if(Flags & mySendKeyFlags.SendExtendedKey != 0)
PostMessage(Params.hWnd, WM_KEYDOWN, key, (int)MAKELONG(0x1, (ushort)
(MapVirtualKey((uint)key, 0) | 0x0100)));
else PostMessage(Params.hWnd, WM_KEYDOWN, key,
(int)MAKELONG(0x1, (ushort)MapVirtualKey((uint)key, 0)));

if(Flags & mySendKeyFlags.SimReal != 0) Thread.Sleep(10);

if(Flags & mySendKeyFlags.SendExtendedKey != 0)
PostMessage(Params.hWnd, WM_KEYUP, key, (int)MAKELONG(0x1, (ushort)
(MapVirtualKey((uint)key, 0) | 0xC100)));
else PostMessage(Params.hWnd, WM_KEYUP, key,
(int)MAKELONG(0x1, (ushort)(MapVirtualKey((uint)key, 0) | 0xC000)));
if(Modifier != null) {
for(byte i = 0; i < Modifier.Length; i++) {
if(Modifier == (int)Keys.Alt)
PostMessage(Params.hWnd, WM_SYSKEYUP, Modifier, (int)MAKELONG(0x1,
(ushort)(MapVirtualKey((uint)key, 0) | 0xC000)));
else PostMessage(Params.hWnd, WM_KEYUP,
Modifier, (int)MAKELONG(0x1, (ushort)
(MapVirtualKey((uint)Modifier, 0) | 0xC000)));
}
}
}
------------------------------------------------------------------------------------------

Basically the Key is the Virtual Key code (given in the WM_HOTKEY
message alonge with the Modifiers used). You have to convert the
modifers to an int[] of VKcodes. Have to manual give the extended key
flag if the hotkey is an extended one. Use SimReal if you have
modifiers (ctrl/alt/shift/etc) but you have to get the process id of
the current app (Most my hotkeys don't have modifiers which is why I
have a flag I set only when I have to use it). If anyone knows an
easy way to get the active windows process id (maybe a winapi?) it
would be nice (mine just goes though all processes and checks their
MainWindowHandle against the GetForgroundWindow() that I have).

I was forced to add a 10ms delay in the middle for the SimReal case
(for the application to produce its WM_CHAR message after the
WM_KEYDOWN message is sent... I don't know how to know when the
external message loop produced it.

I'm still in the process of tested/making it the way I want it. If
anyone knows a quick solutions to the processID / WM_CHAR message
problems it would be a help.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top