Home > Enterprise >  WPF determine all keys released in textbox?
WPF determine all keys released in textbox?

Time:09-14

I wanted to make user to customise the shortcut keys, so I'm using a textbox to get the key input. The expected state should be to save the key when pressed, and show KeyGesture string when released.

But some keys will be responded to by other registered hotkeys ( like Ctrl A, win G etc. ) , unable to determine whether if the keys are all released, so that cannot clear ModifierKeys when appropriate.

Here's my code, if input a registered hotkey this keyCount will be wrong:

KeyGestureConverter keyGestureConverter = new KeyGestureConverter();
Key key;
ModifierKeys modifierKeys;
int keyCount = 0;

private void HotKeyTextbox_KeyDown(object sender, KeyEventArgs e)
{
    if (e.Key.Equals(Key.LeftCtrl) || e.Key.Equals(Key.RightCtrl))
        modifierKeys |= ModifierKeys.Control;
    else if (e.Key.Equals(Key.LeftAlt) || e.Key.Equals(Key.RightAlt))
        modifierKeys |= ModifierKeys.Alt;
    else if (e.Key.Equals(Key.LeftShift) || e.Key.Equals(Key.RightShift))
        modifierKeys |= ModifierKeys.Shift;
    else if (e.Key.Equals(Key.LWin) || e.Key.Equals(Key.RWin))
        modifierKeys |= ModifierKeys.Windows;
    else
        key = e.Key;
    keyCount  ;
}

private void HotKeyTextbox_KeyUp(object sender, KeyEventArgs e)
{
    keyCount--;
    try
    {
        KeyGesture keyGesture = new KeyGesture(key, modifierKeys);
        HotKeyTextbox.Text = keyGestureConverter.ConvertToString(keyGesture);
    }
    catch
    {
        HotKeyTextbox.Text = string.Empty;
    }
    if (keyCount <= 0)
    {
        keyCount = 0;
        key = Key.None;
        modifierKeys = ModifierKeys.None;
    }
}

How about achieving the right effect?

CodePudding user response:

EDIT : misunderstood the question, this is for when shortcuts have already been recorded.

private void Key_Down(object sender, System.Windows.Input.KeyEventArgs e)
{
    if (Keyboard.Modifiers == ModifierKeys.Control) // With CTRL
    {
        switch (e.Key)
        {
        case Key.Escape:
            Close();
            break;
        case Key.Y:
            Validate_Data();
            break;
        }
    }
    else // Without CRTL
    {
        switch (e.Key)
        {
            case Key.Escape:
                Close();
                break;
        }
    }
}

CodePudding user response:

You must handle the PreviewKeyDown and PreviewKeyUp events to catch common key gestures before they got handled by the TextBox. TextBox will handle certain gestures like "Ctrl C" and then mark the event as handled.

To print a key combination simply use the KeyGesture.GetDisplayStringForCulture method (see example below).
To register a handler for the recorded gesture, simply define new KeyBinding and add it to the appropriate UIElement.InputBindings collection. But to make sense, you would have to let the user select the key command (action) first. Otherwise you don't know to which action the gesture should map to.
The following example assumes that the selected action is already stored in the SelectedGestureCommand property.

To handle/override globally registered key gestures like your mentioned "Windows G", you would have to use P/Invoke to handle those events on OS level. There is no WPF API for this task.

MainWindow.xaml

<TextBox PreviewKeyDown="RecordGesture_OnKeyDown"
         PreviewKeyUp="PrintRecordedGesture_OnKeyUp" />

MainWindow.xamlcs

public MainWindow()
{
  InitializeComponent();

  // Register the predefined gestures that the user can later modify.
  // TODO::Define the required commands by implementing ICommand for each
  this.InputBindings.Add(new KeyBinding(DoSomethingCommand, Key.A, ModifierKeys.Shift | ModifierKeys.Alt));
}

private void RecordGesture_OnKeyDown(object sender, KeyEventArgs e)
{
  var newGesture = new KeyGesture(e.Key, e.KeyboardDevice.Modifiers);

  // Update the existing action with the new gesture
  KeyBinding selectedKeyBinding = this.InputBindings
    .OfType<KeyBinding>()
    .First(keyBinding => keyBinding.Command == this.SelectedGestureCommand);
  selectedKeyBinding.Gesture = newGesture;
}

private void PrintRecordedGesture_OnKeyUp(object sender, KeyEventArgs e)
{
  var currentGesture = new KeyGesture(e.Key, e.KeyboardDevice.Modifiers);

  // Print the new gesture
  (sender as TextBox).Text = currentGesture.GetDisplayStringForCulture(CultureInfo.CurrentCulture);
}
  • Related