mirror of
https://github.com/ZuneDev/MicrosoftIris.git
synced 2026-07-27 13:13:29 -07:00
483 lines
17 KiB
C#
483 lines
17 KiB
C#
// Decompiled with JetBrains decompiler
|
|
// Type: Microsoft.Iris.InputHandlers.ClickHandler
|
|
// Assembly: UIX, Version=4.8.0.0, Culture=neutral, PublicKeyToken=ddd0da4d3e678217
|
|
// MVID: A56C6C9D-B7F6-46A9-8BDE-B3D9B8D60B11
|
|
// Assembly location: C:\Program Files\Zune\UIX.dll
|
|
|
|
using Microsoft.Iris.Input;
|
|
using Microsoft.Iris.Markup;
|
|
using Microsoft.Iris.ModelItems;
|
|
using Microsoft.Iris.OS;
|
|
using Microsoft.Iris.Session;
|
|
using Microsoft.Iris.UI;
|
|
using System;
|
|
|
|
namespace Microsoft.Iris.InputHandlers
|
|
{
|
|
internal class ClickHandler : ModifierInputHandler
|
|
{
|
|
private static int s_defaultRepeatDelay = Win32Api.GetDefaultKeyDelay();
|
|
private static int s_defaultRepeatRate = Win32Api.GetDefaultKeyRepeat();
|
|
private ClickCount _clickCount;
|
|
private ClickType _clickType;
|
|
private int _repeatDelay;
|
|
private int _repeatRate;
|
|
private IUICommand _command;
|
|
private WeakReference _eventContext;
|
|
private ClickType _clickTypeInProgress;
|
|
private DispatcherTimer _repeatTimer;
|
|
private bool _clickValidPosition;
|
|
private bool _handleEscape;
|
|
private bool _handle;
|
|
private bool _repeat;
|
|
|
|
public ClickHandler()
|
|
{
|
|
_clickType = ClickType.Key | ClickType.GamePad | ClickType.LeftMouse;
|
|
_clickCount = ClickCount.Single;
|
|
_repeat = true;
|
|
_repeatDelay = DefaultRepeatDelay;
|
|
_repeatRate = DefaultRepeatRate;
|
|
_handle = true;
|
|
}
|
|
|
|
protected override void OnDispose()
|
|
{
|
|
if (_repeatTimer != null)
|
|
_repeatTimer.Enabled = false;
|
|
base.OnDispose();
|
|
}
|
|
|
|
protected override void ConfigureInteractivity()
|
|
{
|
|
base.ConfigureInteractivity();
|
|
if (!HandleDirect)
|
|
return;
|
|
if (ShouldHandleEvent(ClickType.Mouse))
|
|
UI.MouseInteractive = true;
|
|
if (!ShouldHandleEvent(ClickType.Key | ClickType.GamePad))
|
|
return;
|
|
UI.KeyInteractive = true;
|
|
}
|
|
|
|
public ClickType ClickType
|
|
{
|
|
get => _clickType;
|
|
set
|
|
{
|
|
if (_clickType == value)
|
|
return;
|
|
_clickType = value;
|
|
FireNotification(NotificationID.ClickType);
|
|
}
|
|
}
|
|
|
|
public ClickCount ClickCount
|
|
{
|
|
get => _clickCount;
|
|
set
|
|
{
|
|
if (_clickCount == value)
|
|
return;
|
|
_clickCount = value;
|
|
FireNotification(NotificationID.ClickCount);
|
|
}
|
|
}
|
|
|
|
public bool Repeat
|
|
{
|
|
get => _repeat;
|
|
set
|
|
{
|
|
if (_repeat == value)
|
|
return;
|
|
_repeat = value;
|
|
FireNotification(NotificationID.Repeat);
|
|
}
|
|
}
|
|
|
|
public int RepeatDelay
|
|
{
|
|
get => _repeatDelay;
|
|
set
|
|
{
|
|
if (_repeatDelay == value)
|
|
return;
|
|
_repeatDelay = value;
|
|
FireNotification(NotificationID.RepeatDelay);
|
|
}
|
|
}
|
|
|
|
public int RepeatRate
|
|
{
|
|
get => _repeatRate;
|
|
set
|
|
{
|
|
if (_repeatRate == value)
|
|
return;
|
|
_repeatRate = value;
|
|
FireNotification(NotificationID.RepeatRate);
|
|
}
|
|
}
|
|
|
|
public bool Clicking => _clickTypeInProgress != ClickType.None && _clickValidPosition;
|
|
|
|
public object EventContext => CheckEventContext(ref _eventContext);
|
|
|
|
public IUICommand Command
|
|
{
|
|
get => _command;
|
|
set
|
|
{
|
|
if (_command == value)
|
|
return;
|
|
_command = value;
|
|
FireNotification(NotificationID.Command);
|
|
}
|
|
}
|
|
|
|
public bool Handle
|
|
{
|
|
get => _handle;
|
|
set
|
|
{
|
|
if (_handle == value)
|
|
return;
|
|
_handle = value;
|
|
FireNotification(NotificationID.Handle);
|
|
}
|
|
}
|
|
|
|
private void InvokeCommand()
|
|
{
|
|
FireNotification(NotificationID.Invoked);
|
|
if (_command == null)
|
|
return;
|
|
_command.Invoke();
|
|
}
|
|
|
|
private void BeginClick(ClickType clickType, bool validPosition)
|
|
{
|
|
if (_clickTypeInProgress == ClickType.None)
|
|
{
|
|
_clickTypeInProgress = clickType;
|
|
_clickValidPosition = validPosition;
|
|
if (validPosition)
|
|
FireNotification(NotificationID.Clicking);
|
|
}
|
|
else if (_clickTypeInProgress != clickType)
|
|
CancelClick(ClickType.Any);
|
|
SetEventContext(null, ref _eventContext, NotificationID.EventContext);
|
|
}
|
|
|
|
private void EndClick(ICookedInputSite clickTarget, ClickType clickType)
|
|
{
|
|
if (_clickTypeInProgress == ClickType.None)
|
|
return;
|
|
SetEventContext(clickTarget, ref _eventContext, NotificationID.EventContext);
|
|
if (_clickTypeInProgress == clickType && _clickValidPosition)
|
|
InvokeCommand();
|
|
CancelClick(ClickType.Any);
|
|
}
|
|
|
|
private void UpdateClickValidPosition(bool validPosition)
|
|
{
|
|
bool clicking = Clicking;
|
|
_clickValidPosition = validPosition;
|
|
if (Clicking == clicking)
|
|
return;
|
|
FireNotification(NotificationID.Clicking);
|
|
}
|
|
|
|
private void CancelClick(ClickType clickType)
|
|
{
|
|
if (_clickTypeInProgress != ClickType.None && Library.Bits.TestAllFlags((uint)clickType, (uint)_clickTypeInProgress))
|
|
{
|
|
bool clicking = Clicking;
|
|
_clickTypeInProgress = ClickType.None;
|
|
if (Clicking != clicking)
|
|
FireNotification(NotificationID.Clicking);
|
|
}
|
|
if (_repeatTimer == null)
|
|
return;
|
|
_repeatTimer.Enabled = false;
|
|
}
|
|
|
|
private bool ShouldHandleEvent(
|
|
ClickType type,
|
|
InputHandlerModifiers modifiers,
|
|
ClickCount count)
|
|
{
|
|
return ShouldHandleEvent(type) && _clickCount == count && ShouldHandleEvent(modifiers);
|
|
}
|
|
|
|
private bool ShouldHandleEvent(ClickType type) => Library.Bits.TestAnyFlags((uint)_clickType, (uint)type);
|
|
|
|
private bool OnClickEvent(
|
|
ICookedInputSite clickTarget,
|
|
ClickType type,
|
|
InputHandlerTransition transition,
|
|
InputHandlerModifiers modifiers)
|
|
{
|
|
return OnClickEvent(clickTarget, type, transition, modifiers, ClickCount.Single);
|
|
}
|
|
|
|
private bool OnClickEvent(
|
|
ICookedInputSite clickTarget,
|
|
ClickType type,
|
|
InputHandlerTransition transition,
|
|
InputHandlerModifiers modifiers,
|
|
ClickCount count)
|
|
{
|
|
if (!ShouldHandleEvent(type, modifiers, count))
|
|
return false;
|
|
if (transition == InputHandlerTransition.Up)
|
|
{
|
|
if (HandlerTransition != InputHandlerTransition.Down)
|
|
EndClick(clickTarget, type);
|
|
if (_repeatTimer != null)
|
|
_repeatTimer.Enabled = false;
|
|
}
|
|
else
|
|
{
|
|
BeginClick(type, true);
|
|
if (HandlerTransition == InputHandlerTransition.Down)
|
|
{
|
|
EndClick(clickTarget, type);
|
|
StartRepeat(new ClickHandler.ClickInfo()
|
|
{
|
|
type = type,
|
|
transition = transition,
|
|
modifiers = modifiers,
|
|
count = count,
|
|
target = clickTarget
|
|
});
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private ClickType GetClickType(MouseButtons buttons)
|
|
{
|
|
ClickType clickType = ClickType.None;
|
|
if ((buttons & MouseButtons.Left) != MouseButtons.None)
|
|
clickType |= ClickType.LeftMouse;
|
|
if ((buttons & MouseButtons.Right) != MouseButtons.None)
|
|
clickType |= ClickType.RightMouse;
|
|
if ((buttons & MouseButtons.Middle) != MouseButtons.None)
|
|
clickType |= ClickType.MiddleMouse;
|
|
return clickType;
|
|
}
|
|
|
|
private void StartRepeat(ClickHandler.ClickInfo clickInfo)
|
|
{
|
|
if (!Repeat)
|
|
return;
|
|
if (_repeatTimer == null)
|
|
{
|
|
_repeatTimer = new DispatcherTimer();
|
|
_repeatTimer.Tick += new EventHandler(SimulateClickEvent);
|
|
_repeatTimer.AutoRepeat = true;
|
|
}
|
|
_repeatTimer.Interval = RepeatDelay;
|
|
_repeatTimer.UserData = clickInfo;
|
|
_repeatTimer.Enabled = true;
|
|
}
|
|
|
|
private void SimulateClickEvent(object sender, EventArgs args)
|
|
{
|
|
bool flag = false;
|
|
ClickHandler.ClickInfo userData = (ClickHandler.ClickInfo)_repeatTimer.UserData;
|
|
if (Enabled && Repeat && _clickValidPosition && (userData.target == null || userData.target.IsValid))
|
|
{
|
|
OnClickEvent(userData.target, userData.type, userData.transition, userData.modifiers, userData.count);
|
|
flag = true;
|
|
}
|
|
if (flag)
|
|
{
|
|
_repeatTimer.Enabled = false;
|
|
_repeatTimer = null;
|
|
StartRepeat(userData);
|
|
_repeatTimer.Interval = RepeatRate;
|
|
}
|
|
else
|
|
{
|
|
_repeatTimer.Enabled = false;
|
|
_repeatTimer = null;
|
|
}
|
|
}
|
|
|
|
private static int DefaultRepeatDelay => s_defaultRepeatDelay;
|
|
|
|
private static int DefaultRepeatRate => s_defaultRepeatRate;
|
|
|
|
protected override void OnMousePrimaryDown(UIClass ui, MouseButtonInfo info)
|
|
{
|
|
if (!OnClickEvent(info.Target, GetClickType(info.Button), InputHandlerTransition.Down, GetModifiers(info.Modifiers)) || !_handle)
|
|
return;
|
|
info.MarkHandled();
|
|
}
|
|
|
|
protected override void OnMouseSecondaryDown(UIClass ui, MouseButtonInfo info)
|
|
{
|
|
if (!OnClickEvent(info.Target, GetClickType(info.Button), InputHandlerTransition.Down, GetModifiers(info.Modifiers)) || !_handle)
|
|
return;
|
|
info.MarkHandled();
|
|
}
|
|
|
|
protected override void OnMousePrimaryUp(UIClass ui, MouseButtonInfo info)
|
|
{
|
|
if (!OnClickEvent(info.Target, GetClickType(info.Button), InputHandlerTransition.Up, GetModifiers(info.Modifiers)) || !_handle)
|
|
return;
|
|
info.MarkHandled();
|
|
}
|
|
|
|
protected override void OnMouseSecondaryUp(UIClass ui, MouseButtonInfo info)
|
|
{
|
|
if (!OnClickEvent(info.Target, GetClickType(info.Button), InputHandlerTransition.Up, GetModifiers(info.Modifiers)) || !_handle)
|
|
return;
|
|
info.MarkHandled();
|
|
}
|
|
|
|
protected override void OnMouseDoubleClick(UIClass ui, MouseButtonInfo info)
|
|
{
|
|
ClickType clickType = GetClickType(info.Button);
|
|
if (!OnClickEvent(info.Target, clickType, InputHandlerTransition.Down, GetModifiers(info.Modifiers), ClickCount.Double))
|
|
return;
|
|
OnClickEvent(info.Target, clickType, InputHandlerTransition.Up, GetModifiers(info.Modifiers), ClickCount.Double);
|
|
if (!_handle)
|
|
return;
|
|
info.MarkHandled();
|
|
}
|
|
|
|
protected override void OnMouseMove(UIClass ui, MouseMoveInfo info)
|
|
{
|
|
if (!ShouldHandleEvent(ClickType.Mouse))
|
|
return;
|
|
UpdateClickValidPosition(UI.HasDescendant(info.NaturalTarget as UIClass));
|
|
}
|
|
|
|
protected override void OnLoseMouseFocus(UIClass ui, MouseFocusInfo info)
|
|
{
|
|
if (!ShouldHandleEvent(ClickType.Mouse))
|
|
return;
|
|
CancelClick(ClickType.Mouse);
|
|
}
|
|
|
|
protected override void OnKeyDown(UIClass ui, KeyStateInfo info)
|
|
{
|
|
if (info.RepeatCount > 1U)
|
|
return;
|
|
switch (info.Key)
|
|
{
|
|
case Keys.Enter:
|
|
if (!OnClickEvent(info.Target, ClickType.EnterKey, InputHandlerTransition.Down, GetModifiers(info.Modifiers)) || !_handle)
|
|
break;
|
|
info.MarkHandled();
|
|
break;
|
|
case Keys.Escape:
|
|
if (!Clicking)
|
|
break;
|
|
CancelClick(ClickType.Any);
|
|
if (_handle)
|
|
info.MarkHandled();
|
|
_handleEscape = true;
|
|
break;
|
|
case Keys.Space:
|
|
if (!OnClickEvent(info.Target, ClickType.SpaceKey, InputHandlerTransition.Down, GetModifiers(info.Modifiers)) || !_handle)
|
|
break;
|
|
info.MarkHandled();
|
|
break;
|
|
case Keys.GamePadA:
|
|
if (!OnClickEvent(info.Target, ClickType.GamePadA, InputHandlerTransition.Down, GetModifiers(info.Modifiers)) || !_handle)
|
|
break;
|
|
info.MarkHandled();
|
|
break;
|
|
case Keys.GamePadStart:
|
|
if (!OnClickEvent(info.Target, ClickType.GamePadStart, InputHandlerTransition.Down, GetModifiers(info.Modifiers)) || !_handle)
|
|
break;
|
|
info.MarkHandled();
|
|
break;
|
|
}
|
|
}
|
|
|
|
protected override void OnKeyUp(UIClass ui, KeyStateInfo info)
|
|
{
|
|
switch (info.Key)
|
|
{
|
|
case Keys.Enter:
|
|
if (!OnClickEvent(info.Target, ClickType.EnterKey, InputHandlerTransition.Up, GetModifiers(info.Modifiers)) || !_handle)
|
|
break;
|
|
info.MarkHandled();
|
|
break;
|
|
case Keys.Escape:
|
|
if (!_handleEscape)
|
|
break;
|
|
if (_handle)
|
|
info.MarkHandled();
|
|
_handleEscape = false;
|
|
break;
|
|
case Keys.Space:
|
|
if (!OnClickEvent(info.Target, ClickType.SpaceKey, InputHandlerTransition.Up, GetModifiers(info.Modifiers)) || !_handle)
|
|
break;
|
|
info.MarkHandled();
|
|
break;
|
|
case Keys.GamePadA:
|
|
if (!OnClickEvent(info.Target, ClickType.GamePadA, InputHandlerTransition.Up, GetModifiers(info.Modifiers)) || !_handle)
|
|
break;
|
|
info.MarkHandled();
|
|
break;
|
|
case Keys.GamePadStart:
|
|
if (!OnClickEvent(info.Target, ClickType.GamePadStart, InputHandlerTransition.Up, GetModifiers(info.Modifiers)) || !_handle)
|
|
break;
|
|
info.MarkHandled();
|
|
break;
|
|
}
|
|
}
|
|
|
|
protected override void OnKeyCharacter(UIClass ui, KeyCharacterInfo info)
|
|
{
|
|
switch (info.Character)
|
|
{
|
|
case '\r':
|
|
if (!ShouldHandleEvent(ClickType.EnterKey, GetModifiers(info.Modifiers), ClickCount.Single) || !_handle)
|
|
break;
|
|
info.MarkHandled();
|
|
break;
|
|
case '\x001B':
|
|
if (!_handleEscape || !_handle)
|
|
break;
|
|
info.MarkHandled();
|
|
break;
|
|
case ' ':
|
|
if (!ShouldHandleEvent(ClickType.SpaceKey, GetModifiers(info.Modifiers), ClickCount.Single) || !_handle)
|
|
break;
|
|
info.MarkHandled();
|
|
break;
|
|
}
|
|
}
|
|
|
|
protected override void OnLoseKeyFocus(UIClass ui, KeyFocusInfo info)
|
|
{
|
|
if (ShouldHandleEvent(ClickType.SpaceKey))
|
|
CancelClick(ClickType.SpaceKey);
|
|
if (ShouldHandleEvent(ClickType.EnterKey))
|
|
CancelClick(ClickType.EnterKey);
|
|
if (ShouldHandleEvent(ClickType.GamePadA))
|
|
CancelClick(ClickType.GamePadA);
|
|
if (ShouldHandleEvent(ClickType.GamePadStart))
|
|
CancelClick(ClickType.GamePadStart);
|
|
_handleEscape = false;
|
|
}
|
|
|
|
private struct ClickInfo
|
|
{
|
|
public ClickType type;
|
|
public InputHandlerTransition transition;
|
|
public InputHandlerModifiers modifiers;
|
|
public ClickCount count;
|
|
public ICookedInputSite target;
|
|
}
|
|
}
|
|
}
|