Alt-Tab issue on Windows Activation in WPF - wpf

In my app, I have a special action mapped to the tab key. The problem is that when you use the short-cut Alt-Tab to switch between different apps, my app gets a tab key (but not the Alt key) when it becomes activated, which I'd like to avoid. This happens sometimes (not all the time), especially when you switch apps very fast.
I could filter it out by checking Keyboard.IsKeyDown(Key.LeftAlt), but my app doesn't get the Alt-key in this case. Any tip?

I've had an issue where KeyUp event handler doesn't register e.Key == Key.LeftAlt. Instead I had to use e.SystemKey == Key.LeftAlt. Perhaps you are facing a similar issue (although I don't know if you use the KeyUp/KeyDown event handler)?
Another thing to try would be Keyboard.Modifiers == ModifierKeys.Alt or maybe even KeyboardDevice.Modifiers == ModifierKeys.Alt inorder to filter out Alt.

Related

Detecting key combinations

I want to detect when a combination like Ctrl-C is pressed in a WPF application. What I've read online says to use something like the following in the KeyDown (or KeyUp) Event:
if ((Keyboard.Modifiers == ModifierKeys.Control) && (e.Key == Key.S))
{
MessageBox.Show("Save!");
}
I'm just trying to understand how this works. As I understand it, e.Key contains the key that was pressed that triggered the event and Keyboard.Modifiers contains the information about the state of the Control key right now. Is it safe to assume that the Control key will still be down by the time the KeyDown event gets handled?
For example, I restart Firefox and it grinds away loading a bunch of tabs, and in the meantime I hit Ctrl-S in my application. There is a delay in getting to KeyDown, and the application thinks just S has been pressed.
Thanks
You could use KeyBindings instead, they define full gestures without such a separation.

How can I pass WM_KEYDOWN messages to the WinForms control inside CWinFormsView?

I have a WinForms control (let's say C) inside the CWinFormsView V of an MDI application. C overrides the OnKeyDown method. I have overriden also OnMouseUp in C and I call the Focus() method there, so when I click inside C the keyboard messages go directly to it and everything works correctly.
However, I'd like to be able to control C using the keyboard when I switch to V without the need to click inside the view. How can I achieve that? Do I need to catch WM_KEYDOWN messages in V and pass them manually to the hosted control (in other words, C)? C is actually a child window of V, shouldn't it somehow work automatically?
If I followed your question, the easiest way is to have V forward the presses to C.
Look at Form.KeyPreview - for V - which will let V see all the key presses when it or one of it's children have focus. You can then forward it to C.
I actually solved the problem with the following code in the V view:
BOOL CMyView::PreTranslateMessage(MSG* pMsg)
{
if( pMsg->message == WM_KEYDOWN || pMsg->message == WM_MOUSEWHEEL )
{
::SendMessage( (HWND) m_myControl->Handle.ToInt32(), pMsg->message, pMsg->wParam, pMsg->lParam );
}
return CWinFormsView::PreTranslateMessage(pMsg);
}
Also I removed the code that sets focus to C on mouse click. This way it is never focused but receives the parent view's messages (I need WM_KEYDOWN and WM_MOUSEWHEEL) from PreTranslateMessage. Not settings the focus is important because otherwise I would lose the ability to switch between MDI views using Ctrl+Tab (if C was focused). So now I can switch between them freely, then when V becomes active I can use the keys to control C but I still can use Ctrl+Tab to switch to another view without having to use the mouse.

Handle KeyDown during a drag drop

I need to respond to keydown events (O, C, G keys etc., not modifier keys) while a Drag+Drop operation is in progress over my control (i.e. between DragEnter and DragLeave). However the KeyDown event is not called at this stage.
I've tried selecting my control and specifically setting focus on DragEnter, but that doesn't work.
EDIT:
Hans' answer is basically correct, except I had to use GetAsynchKeyState to get the behaviour I wanted.
The QueryContinueDrag event is raised on the drag source. Checking for the state of the keys you are interested in is going to require pinvoke, the event is only designed to help recognize the Escape key and modifier key state changes. Which is something to keep in mind, that these keys have any special action is very undiscoverable.
[DllImport("user32.dll")]
private static extern short GetKeyState(Keys key);
It returns a value < 0 when the key is down. I can't say it's guaranteed to work correctly but it looked good when I tried it.
You can also try:
Keyboard.IsKeyDown(); method to check if a specific key is pressed, i.e.:
bool isKeyPressed = Keyboard.IsKeyDown(Key.LeftAlt);
It's similar to the previous answer, but it's a native .NET method, so it doesn't require you to import any functions.
A similar question has been asked here: Handle KeyDown during a drag drop. Or keydown event not workign, but there was a suggestion to make it work like an event.
UPDATE
The first solution seems to work only in WPF. If you want to check states of modifier keys, there is, however, a method utilizing a property Form.ModifierKeys that should work correctly in WinForms. The example shows how to check if alt (left alt) and ctrl keys are both pressed:
if (Form.ModifierKeys == (Keys.Alt | Keys.Control))
{
//TODO: insert your code here
}

Drop outside the control

I'm improving standart WPF TabControl. I want to add undocking functionality to it:
user drags the page just outside the TabControl and this page undocks in the window.
I want two events in this control - PageDragStart (raises when the page dragged outside) and PageDragEnd (raises when the page dropped outside)
I've got no problem with the first event.
But the second... OnDrop doesn't call, because the item dropped outside the tabcontol container. How can I know that it was dropped?
P.S. I want a universal control (so, undocking functionality shouldn't be connected and hardcoded with the window tabcontrol is placed or something like this)
Why use DoDragDrop at all? As I was reading your description, using Mouse.Capture by itself seemed the obvious solution:
Handle OnMouseLeftButtonDown on the tab and start capture
Handle OnMouseMove on the tab and update the cursor based on hit testing
Handle OnMouseLeftButtonUp on the tab, and stop the capture and make the appropriate change
The reasons you might ever consider DoDragDrop over simple mouse capture are:
Integration with Windows' OLE drag and drop so you can drag and drop between applications and technologies
Modal nature of DoDragDrop call (which actually seems to be more of a disadvantage to me)
Automated hit testing of targets
Standardized "drop operation" API to allow unrelated applications to handle copy vs move, etc.
You apparently don't need the OLE integration or multi-application support and you want to customize the hit testing, so it seems that DoDragDrop has no advantages over directly handling the mouse capture.
I solved the problem - in rather brutal and unsafe way. But for it's gonna work as the temporary solution.
Well, when I'm raising PageDragStart event, I call Mouse.Capture(this, CaptureMode.SubTree);
When the page is dropped somewhere - DoDragDrop throws different exceptions (COMException, NullReference (I couldn't find which object is null) and some others I don't remember).
I catch exception and call PageDragEnd event (if the property IsPageDraggingOut set to true).
As far as you can see this solution is really dirty and bad. But it works.
So, any other ideas (or some ideas how to work with Mouse.Capture properly)?

What would be the expected behavior for a window that hides itself upon keystroke

This is a subjective question, but I need opinions.
I have a WinForms C# application whose window hides itself after a specific keystroke (Enter or Escape), with possible modifiers (e.g. Ctrl-Enter). When hiding on KeyDown or KeyPress, the other application that becomes active after my window hides itself receives the KeyUp event for that keystroke. Normally, it shouldn't affect that other application, but some of them out there react on KeyUp. For example, TweetDeck sends the message currently being edited on "Enter" KeyUp, even if it did not receive KeyDown/KeyPress.
So I thought, fine, I'll be a good citizen, I'll hide on KeyUp. But this doesn't feel right. If I only look for keys up, I'm doing what I blame others of doing! If I try to create an history of matching KeyDown/KeyUp, I'm over-complicating my code (modifiers generate their own key up).
What should I do? What should a well-implemented application do?
This is a hack, but you can set the state of your program to "pending hide" when receive the key down. And then when you get the key up for that sequence, reset the "pending state" and then hide.
Alternatively, can you just "eat" the key up off the message queue after you receive the key down?
I would not worry too much about applications handling key up rather than key down - like you point out - the only reason this is an issue is because your app changes active windows in the middle of a key down key up sequence. It is your responsibility (IMO) to also "eat" the key up messages. You can probably just handle the key up instead of key down with no adverse side effects.
EDIT
Thinking about this further - when doing alt-tab to go to a new window - the action does not happen until the key up. In the meantime it shows a window of possible apps to change to. You can do similar action and the behavior has a precedent.
So:
On key down: Display window that indicates app will hide.
on key up: hide window
This is "stateful" - you can only go into hiding if you received the key down and the key up - at least that is what I would do. 99.9999% (guess) not handling key down would be ok.
I can't think of any program that implements keyboard shortcuts on the KeyUp event. That standard was set a long time ago, with the Windows TranslateAccelerator() API function. It translates WM_KEYDOWN. Windows Forms implements the same behavior with ProcessCmdKey().
Sounds like you found a doozy. Does it handle Alt+F4 correctly?
Well, I'd say "Don't worry about it, until it becomes a problem", but I guess it is a problem now....
In that case, I would hide on KeyPress (the expected user experience), but grab the focus until you get a KeyUp (or until a short timeout).

Resources