private void PreNotifyInput(object sender, NotifyInputEventArgs e)
{
RawKeyboardInputReport keyboardInput = ExtractRawKeyboardInputReport(e, InputManager.PreviewInputReportEvent);
if (keyboardInput != null)
{
CheckForDisconnectedFocus();
// Activation
//
// MITIGATION: KEYBOARD_STATE_OUT_OF_SYNC
//
// It is very important that we allow multiple activate events.
// This is how we deal with the fact that Win32 sometimes sends
// us a WM_SETFOCUS message BEFORE it has updated it's internal
// internal keyboard state information. When we get the
// WM_SETFOCUS message, we activate the keyboard with the
// keyboard state (even though it could be wrong). Then when
// we get the first "real" keyboard input event, we activate
// the keyboard again, since Win32 will have updated the
// keyboard state correctly by then.
//
if ((keyboardInput.Actions & RawKeyboardActions.Activate) == RawKeyboardActions.Activate)
{
//if active source is null, no need to do special-case handling
if (_activeSource == null)
{
// we are now active.
_activeSource = new SecurityCriticalDataClass <PresentationSource>(keyboardInput.InputSource);
}
else if (_activeSource.Value != keyboardInput.InputSource)
{
IKeyboardInputProvider toDeactivate = _activeSource.Value.GetInputProvider(typeof(KeyboardDevice)) as IKeyboardInputProvider;
// we are now active.
_activeSource = new SecurityCriticalDataClass <PresentationSource>(keyboardInput.InputSource);
if (toDeactivate != null)
{
toDeactivate.NotifyDeactivate();
}
}
}
// Generally, we need to check against redundant actions.
// We never prevet the raw event from going through, but we
// will only generate the high-level events for non-redundant
// actions. We store the set of non-redundant actions in
// the dictionary of this event.
// If the input is reporting a key down, the action is never
// considered redundant.
if ((keyboardInput.Actions & RawKeyboardActions.KeyDown) == RawKeyboardActions.KeyDown)
{
RawKeyboardActions actions = GetNonRedundantActions(e);
actions |= RawKeyboardActions.KeyDown;
e.StagingItem.SetData(_tagNonRedundantActions, actions);
// Pass along the key that was pressed, and update our state.
Key key = KeyInterop.KeyFromVirtualKey(keyboardInput.VirtualKey);
e.StagingItem.SetData(_tagKey, key);
e.StagingItem.SetData(_tagScanCode, new ScanCode(keyboardInput.ScanCode, keyboardInput.IsExtendedKey));
// Tell the InputManager that the MostRecentDevice is us.
if (_inputManager != null)
{
_inputManager.Value.MostRecentInputDevice = this;
}
}
// We are missing detection for redundant ups
if ((keyboardInput.Actions & RawKeyboardActions.KeyUp) == RawKeyboardActions.KeyUp)
{
RawKeyboardActions actions = GetNonRedundantActions(e);
actions |= RawKeyboardActions.KeyUp;
e.StagingItem.SetData(_tagNonRedundantActions, actions);
// Pass along the key that was pressed, and update our state.
Key key = KeyInterop.KeyFromVirtualKey(keyboardInput.VirtualKey);
e.StagingItem.SetData(_tagKey, key);
e.StagingItem.SetData(_tagScanCode, new ScanCode(keyboardInput.ScanCode, keyboardInput.IsExtendedKey));
// Tell the InputManager that the MostRecentDevice is us.
if (_inputManager != null)
{
_inputManager.Value.MostRecentInputDevice = this;
}
}
}
// On KeyDown, we might need to set the Repeat flag
if (e.StagingItem.Input.RoutedEvent == Keyboard.PreviewKeyDownEvent)
{
CheckForDisconnectedFocus();
KeyEventArgs args = (KeyEventArgs)e.StagingItem.Input;
// Is this the same as the previous key? (Look at the real key, e.g. TextManager
// might have changed args.Key it to Key.TextInput.)
if (_previousKey == args.RealKey)
{
// Yes, this is a repeat (we got the keydown for it twice, with no KeyUp in between)
args.SetRepeat(true);
}
// Otherwise, keep this key to check against next time.
else
{
_previousKey = args.RealKey;
args.SetRepeat(false);
}
}
// On KeyUp, we clear Repeat flag
else if (e.StagingItem.Input.RoutedEvent == Keyboard.PreviewKeyUpEvent)
{
CheckForDisconnectedFocus();
KeyEventArgs args = (KeyEventArgs)e.StagingItem.Input;
args.SetRepeat(false);
// Clear _previousKey, so that down/up/down/up doesn't look like a repeat
_previousKey = Key.None;
}
}