none
Keyboard Accelerators and the Alt Key

    Question

  • I note that controls in WPF can have accelerators, assigned using the "_" character, as in,   "myButton.Content = "_DoSomething".  Typically, when the above accelerator is assigned, pressing the "Alt" key first displays the accelerator.  Then pressing "D" does the action, pressing the button, in this case. 

    I want to programmatically fire the "Alt" key event, so that the user does not have to first press Alt.  I recognize that there is a display properties option for this, but each user will have their unique setting and I do not want to alter their display properties. 

    I've tried code of this form:

     

     KeyEventArgs e1 = new KeyEventArgs(Keyboard.PrimaryDevice, Keyboard.PrimaryDevice.ActiveSource, 0, Key.LeftAlt);

    e1.RoutedEvent = Keyboard.KeyDownEvent;

    myButton.RaiseEvent(e1);

    But it doesn't quite do the trick.   Can anyone help me with this? 

    Thanks. 

    David

     

     

     

    Monday, March 22, 2010 5:38 PM

Answers

  • Excellent assistance Matt and Linda.   Thank you. 

    I was faced with a challenge to emulate an older Windows application, and I see the risks of my goal.  The old application, written using C and direct Windows API calls, would assign accelerator keys to each menu item (where the menu items were essentially buttons).  But the user needed only to press a single keystroke to activate the menu item.  They never needed to somehow "activate" the accelerators.  In WPF I observed that I could assign accelerators, but they would not even appear until I pressed the Alt key.   Display Properties/Appearance/Effects has an option that changes this behavior, but I wanted to avoid that option.

    I do see that I could simply trap key presses (as with the KeyDown event handler), in fact I already have a similar event handler in place.  Then yes, I could fire an appropriate event to process the keystroke.  But I still wanted the accelerators themselves to display.  I want the user to see which key is the accelerator for each keystroke. 

    I have devised a solution based on this code sample:

    http://inputsimulator.codeplex.com/

    Ultimately, I used Platform Invoke calls to SendInput to fire first an "Alt" keystroke, and then an "Escape" keystroke each time an new Window displays.  The simulated Alt key activates the accelerators.  The Escape appeared necessary because the Alt tended to leave the focus on the control menu of each window, and I wanted focus to remain on the last thing I focused on. 

    But boy was this challenging to debug.  In fact, since the keystroke would be essentially picked up by whatever window was currently active, it appeared that my very attempt to use Visual Studio Debugging would usually thwart my attempt, because the wrong window would process my simulated keystroke. 

    It's a delicate balance, but it is working now.  Please don't chastise me for emulating the old application behavior.  We have a large installed user base and they do not want to change their keystroke behaviors. 

    Thank you for your thoughtful assistance. 

    David

     

     

     

     

     

     

    • Marked as answer by Linda Liu Monday, March 29, 2010 2:10 AM
    Friday, March 26, 2010 1:23 PM

All replies

  • Hi DRoss11450,

    Based on my understanding, you have some button with access key, so the button will be invoked  by pressing the Alt key and an access key. And now you want the button be invoked without the Alt key pressed, if I’m off based, please feel free to let me know.

    We can add a KeyDown event to the window, and in the key down event, we invoke the button if it is the access key.
    Some thing likes the follows:

    private void Window_KeyDown(object sender, KeyEventArgs e)

    {

        if (Keyboard.IsKeyDown(Key.D))

        {

            btn1.RaiseEvent(new RoutedEventArgs(Button.ClickEvent,this));

        }

    }

    Hope this  helps.

    Best regards,
    Linda Liu


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Wednesday, March 24, 2010 2:18 PM
  • Linda,

    If the window has a textbox control in it and if the user tries to input the alphabet 'D' in the textbox instead of trying to focus the control with access key 'D' wouldn't your proposed method lead to random effects ? Handling key down events for input controls like textbox and marking them as handled may solve the problem - I think.

    DRoss11450 - it is not a good principle to simulate key press events in general unless your solution needs it specifically. Make sure you do have enough test cases to test your solution.

    AT

    Wednesday, March 24, 2010 5:03 PM
  • I like Linda's approach but the scope at which you handle the KeyDown even is important to prevent issues like Console is suggesting.  Two points:

    - Instead of Keyboard.IsKeyDown, should juset check e.Key from the KeyEventArgs

    - I'd suggest handling PreviewKeyDown even, not KeyDown event, to prevent other controls in the visual tree from swallowing the keydown.

    - If you actually end up raising the button click event, odds are you want to set e.Handled to true.

    Matt


    SDET : Deployment/Hosting
    Wednesday, March 24, 2010 8:08 PM
  • Excellent assistance Matt and Linda.   Thank you. 

    I was faced with a challenge to emulate an older Windows application, and I see the risks of my goal.  The old application, written using C and direct Windows API calls, would assign accelerator keys to each menu item (where the menu items were essentially buttons).  But the user needed only to press a single keystroke to activate the menu item.  They never needed to somehow "activate" the accelerators.  In WPF I observed that I could assign accelerators, but they would not even appear until I pressed the Alt key.   Display Properties/Appearance/Effects has an option that changes this behavior, but I wanted to avoid that option.

    I do see that I could simply trap key presses (as with the KeyDown event handler), in fact I already have a similar event handler in place.  Then yes, I could fire an appropriate event to process the keystroke.  But I still wanted the accelerators themselves to display.  I want the user to see which key is the accelerator for each keystroke. 

    I have devised a solution based on this code sample:

    http://inputsimulator.codeplex.com/

    Ultimately, I used Platform Invoke calls to SendInput to fire first an "Alt" keystroke, and then an "Escape" keystroke each time an new Window displays.  The simulated Alt key activates the accelerators.  The Escape appeared necessary because the Alt tended to leave the focus on the control menu of each window, and I wanted focus to remain on the last thing I focused on. 

    But boy was this challenging to debug.  In fact, since the keystroke would be essentially picked up by whatever window was currently active, it appeared that my very attempt to use Visual Studio Debugging would usually thwart my attempt, because the wrong window would process my simulated keystroke. 

    It's a delicate balance, but it is working now.  Please don't chastise me for emulating the old application behavior.  We have a large installed user base and they do not want to change their keystroke behaviors. 

    Thank you for your thoughtful assistance. 

    David

     

     

     

     

     

     

    • Marked as answer by Linda Liu Monday, March 29, 2010 2:10 AM
    Friday, March 26, 2010 1:23 PM