I want to intercept a hot-key (specifically CTRL V) which will interact with my application in a certain way. I am able to globally register the hotkey using the RegisterHotKey method. When I press CTRL V I want the focused window/control to also receive the WM_PASTE message. I've tried sending it trough SendMessage but it didn't seem to work. I eventually ended up Unregistering the HotKey, sending ^v to the current window, then re-Registering the hotkey.
private static void Hook_KeyPressed(object sender, KeyPressedEventArgs e)
{
_hook.KeyPressed -= Hook_KeyPressed;
_hook.Dispose();
SendKeys.Send("^v");
_hook = new KeyboardHook();
_hook.RegisterHotKey(global::ClipMaster.ModifierKeys.Control, Keys.V);
_hook.KeyPressed += Hook_KeyPressed;
}
This does the trick, but it blocks the mouse (and the window) for around half a second. I'm also afraid it won't work in certain applications, although I don't know what example I could give.
I'm not sure what you're trying to achieve with that hook since it's impossible to understand it from the code example.
Assuming you do it for auditing reasons (or monitoring of the sort), I'd suggest to review the return value of the WM_HOTKEY message. It can "say" that the message wasn't processed, hence allowing further processing of the Ctrl-V by other logic (e.g. other hooks).
Also, i'd advise to use alternative way to re-send Ctrl-V than SendKeys class which has know timing issues. Did you consider posting a message instead?
I've also found alternative approach to the hooking itself by using lower level key pressing for hooking.
Let me know if it helped.
Related
I am able to close another application window (calculator) from my application by using the following code:
hwnd = FindWindow(null, "Calculator");SendMessage(hwnd,WM_CLOSE,0,IntPtr.Zero);
But I want to disable the mouse wheel in the same calculator application window. I tried the following way, but it doesn't work:
SendMessage(hwnd, WM_MOUSEWHEEL, 0, IntPtr.Zero);
You need to Hook Into the Event and catch the occurence if you want to disable it for specific hWnds.
Look into this:
https://msdn.microsoft.com/en-us/library/windows/desktop/dd373640(v=vs.85).aspx
If you define your callback function, it does need to take care about the correct distribution of the events to all Windows except the one you are searching for, despite that I'm not sure if this is just a clone of the Eventmessage or if they are only directed to your application if the hook is set.
Important is also that the code provided in the example is not complete,
it is missing a message-loop which actually does the grabbing from the message-queue.
Edit
the link mentioned below
http://null-byte.wonderhowto.com/how-to/create-simple-hidden-console-keylogger-c-sharp-0132757/
I notice that WinForms have many methods that process commands or keys (Process*()) and to (pre)filter system's messages, but their respective purposes remain unclear to me.
The official documentation is somewhat obscure and I haven't found any clear and complete response.
I speak about the following methods:
PreFilterMessage(ref Message m)
ProcessCmdKey(ref Message msg, Keys keyData)
WndProc(ref Message m)
ProcessDialogKey(Keys keyData)
PreProcessMessage(ref Message msg)
ProcessKeyMessage(ref Message m)
ProcessKeyPreview(ref Message m)
Some are for intercept keys (like ProcessCmdKey or ProcessDialogKey) and some for intercept messages (each others). But why as many methods? What are their purposes and their use cases ?
I suppose that the execution order for each method is different.
Here is what I know (or I think know):
PreFilterMessage: first to intercept messages. You can stop the distribution of the message for all following methods here!
ProcessCmdKey: intercepts ALL keys, even combinaisons, special and command keys. Good to detect key shortcuts on the entire form (like Ctrl + D). You can stop the distribution of the keys here.
WndProc: second to intercept messages after filtering? I use it only to detect if user click on the upper right "X", but I suppose that is possible on another method!
ProcessDialogKey: intercepts ONE key only, probably after the ProcessCmdKey and before all key's events of controls.
PreProcessMessage: before WndProc and after PreFilterMessage? I don't know exactly why it is used.
ProcessKeyMessage: intercepts key message. It seems that it is rarely used.
ProcessKeyPreview: intercepts key before preview event? Rarely used too.
In depth, I think that it is the correct execution order:
PreFilter
Filter
PreProcess
Process
Events
Why so many steps?
Any informations or concrete use cases will be appreciated!
A native Windows GUI application normally has one message loop, underlying winapi call is GetMessage(). But has many windows that get messages, underlying winapi call is DispatchMessage(). In your .NET app you have one call to Application.Run() but many WndProc() methods, one for each control. Most of them are hidden in .NET Framework code, exposed only if you override it.
There is in general a need to hook into the message loop, intercepting a message before it is dispatched to the control and arrives in WndProc(). The most obvious reason is keyboard shortcuts, you want to act on them regardless which control has the focus. It would of course be very painful if you had to use KeyDown on every control to detect the shortcut. And less obvious reasons, ActiveX controls are notable for having to negotiate with their host for example.
Winforms gives lots of extension points to intercept messages. Too many, really, but a somewhat inevitable side-effect of not wanting to predict in which cases they might be useful. In order:
IMessageFilter.PreFilterMessage() lets you peek at the message right after it was retrieved by GetMessage(). Keep in mind that you can only see messages that were posted to the message queue, underlying call is PostMessage(), you cannot see sent messages. Which limits its usability to user input, keyboard and mouse messages. Rare to tinker with this, but you could use it to make the mouse act differently and to detect that the user is interacting with your program. Programmers that want to automatically log-out a user after a period of inactivity use it for example.
OnPreviewKeyDown() and PreviewKeyDown event. Specific to the control that has the focus. A way for a control to intercept a keystroke before it is tested for a shortcut. You can detect the cursor keys that way for example, before they are used to move the focus. An alternative to overriding IsInputKey().
PreProcessMessage(). Very similar to PreFilterMessage but specific to the control that has the focus. Important to ActiveX controls, I personally never had a use for it.
ProcessCmdKey(). This is the workhorse method to implement your own shortcut keystrokes.
IsInputKey(), allows a control to vote whether a key that's normally used for navigation should be sent to the control instead. You override this method when you have a use for the cursor keys for example.
ProcessDialogKey(). Just like ProcessCmdKey() but filtered for the keystrokes that should be treated like input keys. The default implementation makes the keyboard message bubble to the parent control, giving you a choice where you override ProcessCmdKey(). I can't think of a good reason why you'd want to override it, and never once did, other than to stop the bubbling.
IsInputChar(), very similar to IsInputKey but for KeyPress events. Never used it myself but a way to filter input early.
ProcessDialogChar(), could be used to give typing keys shortcut keystroke behavior. That's unusual.
WndProc(), the workhorse method for processing messages. You override it to allow a control to respond to messages that are not otherwise covered by existing events. Or to customize the behavior of existing native controls.
ProcessKeyEventArgs(), the general method that generates the keyboard events (OnKeyDown, OnKeyUp, OnKeyPress), called by Control.WndProc(). I can't think of a reason to override it, notable for implementing the quirky Form.KeyPreview property, a VB6 compat property, possibly the reason that it got exposed.
A twisty maze indeed.
Trying to keep it sane, always override ProcessCmdKey() to implement shortcut keys. Override IsInputKey() to let your control see the navigation keys. And only override WndProc() to customize existing controls.
I need an underlying process to gather information about other applications used by Windows. I suspect this would be done using WAPI hooks. What I wish to do is for my program to detect when windows changes focus from one program to another and tell me which one currently has focus.
First I need an event that triggers each time Windows swaps focus between two applications. All events I've found so far only handles changes made from or to the program it's being used by, but I need to find all focus-changes, even if it's between two other programs.
I'll also need a function that gives me the window in focus. Would this work, or is this only internally (windows within the current application and not other programs)?
Cheers
Depending on how accurate you need your focus change detection system to be you might be able to get away with a service that polls for the foreground window using the API function you described GetForegroundWindow (yes this is system-wide, not process specific).
You can then use the handle of that function to determine which process is the current active/focused process. Then retrieve the focused element (child window) of that process..
HWND hwnd = GetForegroundWindow();
DWORD remoteThreadId = GetWindowThreadProcessId(hwnd, NULL);
DWORD currentThreadId = GetCurrentThreadId();
AttachThreadInput(rThreadId, curThreadId, TRUE);
HWND focusElement = GetFocus();
AttachThreadInput(rThreadId, curThreadId, FALSE);
Keep doing this.. and do whatever you need to do with focusElement
UPDATE
Well, apparently, as #Kenneth K. posted in a comment, there is a global EVENT_SYSTEM_FOREGROUND event that you can hook so that you application gets notified when the foreground (focused) window changes. This way you don't need to loop continuously to detect these changes.
EVENT_SYSTEM_FOREGROUND = 3;
WINEVENT_OUTOFCONTEXT = 0;
You can follow the example in this answer to see how to hook this event and get the notifications. Then whenever the foreground (focused) window changes you can hook that window's message loop and look form focus changed events withing that window using the SetWindowsHookEx function.
Another options is to consult the list of system events on MSDN and see if there is one you can use instead of the EVENT_SYSTEM_FOREGROUND, or along with it to detect control-level focus events. Perhaps the EVENT_OBJECT_FOCUS might be useful.
Please let me know if this is still unclear..
The AxAcroPDF swallows all key-related events as soon as it gets focus, including shortcuts, key presses, etc. I added a message filter, and it doesn't get any key-related messages either. It's a COM component, could that be relevant?
Is there any way to catch these before the control starts swallowing them?
Hans is correct, the Acrobat Reader spawns two child AcroRd32 processes which you have no direct access to from within your managed code.
I have experimented with this and you have three viable options:
You can create a global system hook, and then look for and filter out / respond to WM_SETFOCUS messages sent to your child AcroRd32 windows. You can accomplish some of this from within C# by using a wrapper library, such as the one here: http://www.codeproject.com/KB/system/WilsonSystemGlobalHooks.aspx
You also need to identify the correct processes as there may be more than one instance of your application, or other instances of AcroRd32. This is the most deterministic solution, but because your application will now be filtering messages sent to every single window in existence, I generally don't recommend this approach because then your program could negatively affect system stability.
Find an alternate PDF viewing control. See this answer for a few commercial components: .net PDF Viewer control , or roll your own: http://www.codeproject.com/KB/applications/PDFViewerControl.aspx
Find an acceptable hack. Depending on how robust your application needs to be, code such as the following may be suitable (it was suitable for my case):
DateTime _lastRenav = DateTime.MinValue;
public Form1()
{
InitializeComponent();
listBox1.LostFocus += new EventHandler(listBox1_LostFocus);
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
axAcroPDF1.src = "sample.pdf"; //this will cause adobe to take away the focus
_lastRenav = DateTime.Now;
}
void listBox1_LostFocus(object sender, EventArgs e)
{
//restores focus if it were the result of a listbox navigation
if ((DateTime.Now - _lastRenav).TotalSeconds < 1)
listBox1.Focus();
}
I might finally have a ridiculously simple answer. So far in testing this is working.
Having suffered from this problem for quite some time and having built a complex system of each custom control recording which of them last had focus and using a timer to flip focus back (when acropdf grabbed it) I revisited this problem and read a great number of answers (looking for recent solutions). The information gleaned helped me with the idea.
The idea is to disable the (acropdf) control whilst it is loading as in the following example (code reduced for clarity)
AxAcroPDF_this.Enabled = False
AxAcroPDF_this.src = m_src
Then on a timer, after say 1 second.
AxAcroPDF_this.Enabled = True
Basically the idea is to tell Windows not to let users use the acropdf control until allowed, so asking Windows to prevent it from getting focus (because users are not allowed in there).
So far this is holding up, I will edit this if anything changes. If it doesn't work completely for you then maybe the idea points into a useful direction.
It is an out-of-process COM component, that's the problem. Completely in violation of Windows SDK requirements as laid out in SetParent(). Once its window gets the focus, the message loop in the acroread.exe process gets all the messages, your message filter cannot see any messages anymore.
Technically it is fixable by using SetWindowsHookEx() to inject a DLL into the process and monitor messages with WH_GETMESSAGE. But you can't write such a DLL in the C# language.
Major suck, I know. There never seems to be any lack of it with that program.
For some reason Tim's answer, disabling the AxAcroPDF control directly, didn't work in my case. The Leave event on the previously-selected Textbox would never fire, either.
What is working is nesting the AxAcroPDF control inside of a disabled GroupBox. Since the users of my application need to only see the PDF, not interact with it, the GroupBox's Enabled property is set to False in the designer.
I was just wondering if there is a way to disable controls such as ctr Left/Right arrows or Alt+left/right arrows in AxWindowsMediaPlayer. I am using it in WindowsFormsHost in my WPF project. I would like to capture these controls and handle them myself. When I use this block, I don't have any way to prevent it by using e.handeld =true or other ways
void MediaPlayer_KeyDownEvent(object sender, AxWMPLib._WMPOCXEvents_KeyDownEvent e)
{
}
Any suggestion how to disable it and continue with my own controls. The important part is it bubbles up somewhere and freezes the GUI if I use such commands, and I don't have any way to capture it to control. It doesn't have any error though.
thanks
It can be blocked in WindowsFormHost level by controlling keydown.
I have one thought to try, but I haven't tested it. Inherit from WindowsFormsHost and override WndProc() method. In this method capture WM_KEYDOWN message, process it, and if it's a key you want to suppress, return 0.
If it doesn't work, you may want to find other way to hook windows procedure.
Hope this helps.
Cheers, Anvaka