InputElement.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. // Copyright (c) The Avalonia Project. All rights reserved.
  2. // Licensed under the MIT license. See licence.md file in the project root for full license information.
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using Avalonia.Interactivity;
  7. using Avalonia.Rendering;
  8. using Avalonia.VisualTree;
  9. namespace Avalonia.Input
  10. {
  11. /// <summary>
  12. /// Implements input-related functionality for a control.
  13. /// </summary>
  14. public class InputElement : Interactive, IInputElement
  15. {
  16. /// <summary>
  17. /// Defines the <see cref="Focusable"/> property.
  18. /// </summary>
  19. public static readonly StyledProperty<bool> FocusableProperty =
  20. AvaloniaProperty.Register<InputElement, bool>(nameof(Focusable));
  21. /// <summary>
  22. /// Defines the <see cref="IsEnabled"/> property.
  23. /// </summary>
  24. public static readonly StyledProperty<bool> IsEnabledProperty =
  25. AvaloniaProperty.Register<InputElement, bool>(nameof(IsEnabled), true);
  26. /// <summary>
  27. /// Defines the <see cref="IsEnabledCore"/> property.
  28. /// </summary>
  29. public static readonly StyledProperty<bool> IsEnabledCoreProperty =
  30. AvaloniaProperty.Register<InputElement, bool>(nameof(IsEnabledCore), true);
  31. /// <summary>
  32. /// Gets or sets associated mouse cursor.
  33. /// </summary>
  34. public static readonly StyledProperty<Cursor> CursorProperty =
  35. AvaloniaProperty.Register<InputElement, Cursor>(nameof(Cursor), null, true);
  36. /// <summary>
  37. /// Defines the <see cref="IsFocused"/> property.
  38. /// </summary>
  39. public static readonly DirectProperty<InputElement, bool> IsFocusedProperty =
  40. AvaloniaProperty.RegisterDirect<InputElement, bool>(nameof(IsFocused), o => o.IsFocused);
  41. /// <summary>
  42. /// Defines the <see cref="IsHitTestVisible"/> property.
  43. /// </summary>
  44. public static readonly StyledProperty<bool> IsHitTestVisibleProperty =
  45. AvaloniaProperty.Register<InputElement, bool>(nameof(IsHitTestVisible), true);
  46. /// <summary>
  47. /// Defines the <see cref="IsPointerOver"/> property.
  48. /// </summary>
  49. public static readonly DirectProperty<InputElement, bool> IsPointerOverProperty =
  50. AvaloniaProperty.RegisterDirect<InputElement, bool>(nameof(IsPointerOver), o => o.IsPointerOver);
  51. /// <summary>
  52. /// Defines the <see cref="GotFocus"/> event.
  53. /// </summary>
  54. public static readonly RoutedEvent<GotFocusEventArgs> GotFocusEvent =
  55. RoutedEvent.Register<InputElement, GotFocusEventArgs>(nameof(GotFocus), RoutingStrategies.Bubble);
  56. /// <summary>
  57. /// Defines the <see cref="LostFocus"/> event.
  58. /// </summary>
  59. public static readonly RoutedEvent<RoutedEventArgs> LostFocusEvent =
  60. RoutedEvent.Register<InputElement, RoutedEventArgs>(nameof(LostFocus), RoutingStrategies.Bubble);
  61. /// <summary>
  62. /// Defines the <see cref="KeyDown"/> event.
  63. /// </summary>
  64. public static readonly RoutedEvent<KeyEventArgs> KeyDownEvent =
  65. RoutedEvent.Register<InputElement, KeyEventArgs>(
  66. "KeyDown",
  67. RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
  68. /// <summary>
  69. /// Defines the <see cref="KeyUp"/> event.
  70. /// </summary>
  71. public static readonly RoutedEvent<KeyEventArgs> KeyUpEvent =
  72. RoutedEvent.Register<InputElement, KeyEventArgs>(
  73. "KeyUp",
  74. RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
  75. /// <summary>
  76. /// Defines the <see cref="TextInput"/> event.
  77. /// </summary>
  78. public static readonly RoutedEvent<TextInputEventArgs> TextInputEvent =
  79. RoutedEvent.Register<InputElement, TextInputEventArgs>(
  80. "TextInput",
  81. RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
  82. /// <summary>
  83. /// Defines the <see cref="PointerEnter"/> event.
  84. /// </summary>
  85. public static readonly RoutedEvent<PointerEventArgs> PointerEnterEvent =
  86. RoutedEvent.Register<InputElement, PointerEventArgs>(nameof(PointerEnter), RoutingStrategies.Direct);
  87. /// <summary>
  88. /// Defines the <see cref="PointerLeave"/> event.
  89. /// </summary>
  90. public static readonly RoutedEvent<PointerEventArgs> PointerLeaveEvent =
  91. RoutedEvent.Register<InputElement, PointerEventArgs>(nameof(PointerLeave), RoutingStrategies.Direct);
  92. /// <summary>
  93. /// Defines the <see cref="PointerMoved"/> event.
  94. /// </summary>
  95. public static readonly RoutedEvent<PointerEventArgs> PointerMovedEvent =
  96. RoutedEvent.Register<InputElement, PointerEventArgs>(
  97. "PointerMove",
  98. RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
  99. /// <summary>
  100. /// Defines the <see cref="PointerPressed"/> event.
  101. /// </summary>
  102. public static readonly RoutedEvent<PointerPressedEventArgs> PointerPressedEvent =
  103. RoutedEvent.Register<InputElement, PointerPressedEventArgs>(
  104. "PointerPressed",
  105. RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
  106. /// <summary>
  107. /// Defines the <see cref="PointerReleased"/> event.
  108. /// </summary>
  109. public static readonly RoutedEvent<PointerReleasedEventArgs> PointerReleasedEvent =
  110. RoutedEvent.Register<InputElement, PointerReleasedEventArgs>(
  111. "PointerReleased",
  112. RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
  113. /// <summary>
  114. /// Defines the <see cref="PointerWheelChanged"/> event.
  115. /// </summary>
  116. public static readonly RoutedEvent<PointerWheelEventArgs> PointerWheelChangedEvent =
  117. RoutedEvent.Register<InputElement, PointerWheelEventArgs>(
  118. "PointerWheelChanged",
  119. RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
  120. /// <summary>
  121. /// Defines the <see cref="Tapped"/> event.
  122. /// </summary>
  123. public static readonly RoutedEvent<RoutedEventArgs> TappedEvent = Gestures.TappedEvent;
  124. /// <summary>
  125. /// Defines the <see cref="DoubleTapped"/> event.
  126. /// </summary>
  127. public static readonly RoutedEvent<RoutedEventArgs> DoubleTappedEvent = Gestures.DoubleTappedEvent;
  128. private bool _isFocused;
  129. private bool _isPointerOver;
  130. /// <summary>
  131. /// Initializes static members of the <see cref="InputElement"/> class.
  132. /// </summary>
  133. static InputElement()
  134. {
  135. IsEnabledProperty.Changed.Subscribe(IsEnabledChanged);
  136. GotFocusEvent.AddClassHandler<InputElement>(x => x.OnGotFocus);
  137. LostFocusEvent.AddClassHandler<InputElement>(x => x.OnLostFocus);
  138. KeyDownEvent.AddClassHandler<InputElement>(x => x.OnKeyDown);
  139. KeyUpEvent.AddClassHandler<InputElement>(x => x.OnKeyUp);
  140. TextInputEvent.AddClassHandler<InputElement>(x => x.OnTextInput);
  141. PointerEnterEvent.AddClassHandler<InputElement>(x => x.OnPointerEnterCore);
  142. PointerLeaveEvent.AddClassHandler<InputElement>(x => x.OnPointerLeaveCore);
  143. PointerMovedEvent.AddClassHandler<InputElement>(x => x.OnPointerMoved);
  144. PointerPressedEvent.AddClassHandler<InputElement>(x => x.OnPointerPressed);
  145. PointerReleasedEvent.AddClassHandler<InputElement>(x => x.OnPointerReleased);
  146. PointerWheelChangedEvent.AddClassHandler<InputElement>(x => x.OnPointerWheelChanged);
  147. PseudoClass(IsEnabledCoreProperty, x => !x, ":disabled");
  148. PseudoClass(IsFocusedProperty, ":focus");
  149. PseudoClass(IsPointerOverProperty, ":pointerover");
  150. }
  151. /// <summary>
  152. /// Occurs when the control receives focus.
  153. /// </summary>
  154. public event EventHandler<RoutedEventArgs> GotFocus
  155. {
  156. add { AddHandler(GotFocusEvent, value); }
  157. remove { RemoveHandler(GotFocusEvent, value); }
  158. }
  159. /// <summary>
  160. /// Occurs when the control loses focus.
  161. /// </summary>
  162. public event EventHandler<RoutedEventArgs> LostFocus
  163. {
  164. add { AddHandler(LostFocusEvent, value); }
  165. remove { RemoveHandler(LostFocusEvent, value); }
  166. }
  167. /// <summary>
  168. /// Occurs when a key is pressed while the control has focus.
  169. /// </summary>
  170. public event EventHandler<KeyEventArgs> KeyDown
  171. {
  172. add { AddHandler(KeyDownEvent, value); }
  173. remove { RemoveHandler(KeyDownEvent, value); }
  174. }
  175. /// <summary>
  176. /// Occurs when a key is released while the control has focus.
  177. /// </summary>
  178. public event EventHandler<KeyEventArgs> KeyUp
  179. {
  180. add { AddHandler(KeyUpEvent, value); }
  181. remove { RemoveHandler(KeyUpEvent, value); }
  182. }
  183. /// <summary>
  184. /// Occurs when a user typed some text while the control has focus.
  185. /// </summary>
  186. public event EventHandler<TextInputEventArgs> TextInput
  187. {
  188. add { AddHandler(TextInputEvent, value); }
  189. remove { RemoveHandler(TextInputEvent, value); }
  190. }
  191. /// <summary>
  192. /// Occurs when the pointer enters the control.
  193. /// </summary>
  194. public event EventHandler<PointerEventArgs> PointerEnter
  195. {
  196. add { AddHandler(PointerEnterEvent, value); }
  197. remove { RemoveHandler(PointerEnterEvent, value); }
  198. }
  199. /// <summary>
  200. /// Occurs when the pointer leaves the control.
  201. /// </summary>
  202. public event EventHandler<PointerEventArgs> PointerLeave
  203. {
  204. add { AddHandler(PointerLeaveEvent, value); }
  205. remove { RemoveHandler(PointerLeaveEvent, value); }
  206. }
  207. /// <summary>
  208. /// Occurs when the pointer moves over the control.
  209. /// </summary>
  210. public event EventHandler<PointerEventArgs> PointerMoved
  211. {
  212. add { AddHandler(PointerMovedEvent, value); }
  213. remove { RemoveHandler(PointerMovedEvent, value); }
  214. }
  215. /// <summary>
  216. /// Occurs when the pointer is pressed over the control.
  217. /// </summary>
  218. public event EventHandler<PointerPressedEventArgs> PointerPressed
  219. {
  220. add { AddHandler(PointerPressedEvent, value); }
  221. remove { RemoveHandler(PointerPressedEvent, value); }
  222. }
  223. /// <summary>
  224. /// Occurs when the pointer is released over the control.
  225. /// </summary>
  226. public event EventHandler<PointerReleasedEventArgs> PointerReleased
  227. {
  228. add { AddHandler(PointerReleasedEvent, value); }
  229. remove { RemoveHandler(PointerReleasedEvent, value); }
  230. }
  231. /// <summary>
  232. /// Occurs when the mouse wheen is scrolled over the control.
  233. /// </summary>
  234. public event EventHandler<PointerWheelEventArgs> PointerWheelChanged
  235. {
  236. add { AddHandler(PointerWheelChangedEvent, value); }
  237. remove { RemoveHandler(PointerWheelChangedEvent, value); }
  238. }
  239. /// <summary>
  240. /// Occurs when a tap gesture occurs on the control.
  241. /// </summary>
  242. public event EventHandler<RoutedEventArgs> Tapped
  243. {
  244. add { AddHandler(TappedEvent, value); }
  245. remove { RemoveHandler(TappedEvent, value); }
  246. }
  247. /// <summary>
  248. /// Occurs when a double-tap gesture occurs on the control.
  249. /// </summary>
  250. public event EventHandler<RoutedEventArgs> DoubleTapped
  251. {
  252. add { AddHandler(DoubleTappedEvent, value); }
  253. remove { RemoveHandler(DoubleTappedEvent, value); }
  254. }
  255. /// <summary>
  256. /// Gets or sets a value indicating whether the control can receive focus.
  257. /// </summary>
  258. public bool Focusable
  259. {
  260. get { return GetValue(FocusableProperty); }
  261. set { SetValue(FocusableProperty, value); }
  262. }
  263. /// <summary>
  264. /// Gets or sets a value indicating whether the control is enabled for user interaction.
  265. /// </summary>
  266. public bool IsEnabled
  267. {
  268. get { return GetValue(IsEnabledProperty); }
  269. set { SetValue(IsEnabledProperty, value); }
  270. }
  271. /// <summary>
  272. /// Gets or sets associated mouse cursor.
  273. /// </summary>
  274. public Cursor Cursor
  275. {
  276. get { return GetValue(CursorProperty); }
  277. set { SetValue(CursorProperty, value); }
  278. }
  279. /// <summary>
  280. /// Gets or sets a value indicating whether the control is focused.
  281. /// </summary>
  282. public bool IsFocused
  283. {
  284. get { return _isFocused; }
  285. private set { SetAndRaise(IsFocusedProperty, ref _isFocused, value); }
  286. }
  287. /// <summary>
  288. /// Gets or sets a value indicating whether the control is considered for hit testing.
  289. /// </summary>
  290. public bool IsHitTestVisible
  291. {
  292. get { return GetValue(IsHitTestVisibleProperty); }
  293. set { SetValue(IsHitTestVisibleProperty, value); }
  294. }
  295. /// <summary>
  296. /// Gets or sets a value indicating whether the pointer is currently over the control.
  297. /// </summary>
  298. public bool IsPointerOver
  299. {
  300. get { return _isPointerOver; }
  301. internal set { SetAndRaise(IsPointerOverProperty, ref _isPointerOver, value); }
  302. }
  303. /// <summary>
  304. /// Gets a value indicating whether the control is effectively enabled for user interaction.
  305. /// </summary>
  306. /// <remarks>
  307. /// The <see cref="IsEnabled"/> property is used to toggle the enabled state for individual
  308. /// controls. The <see cref="IsEnabledCore"/> property takes into account the
  309. /// <see cref="IsEnabled"/> value of this control and its parent controls.
  310. /// </remarks>
  311. bool IInputElement.IsEnabledCore => IsEnabledCore;
  312. /// <summary>
  313. /// Gets a value indicating whether the control is effectively enabled for user interaction.
  314. /// </summary>
  315. /// <remarks>
  316. /// The <see cref="IsEnabled"/> property is used to toggle the enabled state for individual
  317. /// controls. The <see cref="IsEnabledCore"/> property takes into account the
  318. /// <see cref="IsEnabled"/> value of this control and its parent controls.
  319. /// </remarks>
  320. protected bool IsEnabledCore
  321. {
  322. get { return GetValue(IsEnabledCoreProperty); }
  323. set { SetValue(IsEnabledCoreProperty, value); }
  324. }
  325. public List<KeyBinding> KeyBindings { get; } = new List<KeyBinding>();
  326. /// <summary>
  327. /// Focuses the control.
  328. /// </summary>
  329. public void Focus()
  330. {
  331. FocusManager.Instance.Focus(this);
  332. }
  333. /// <inheritdoc/>
  334. protected override void OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e)
  335. {
  336. base.OnDetachedFromVisualTreeCore(e);
  337. if (IsFocused)
  338. {
  339. FocusManager.Instance.Focus(null);
  340. }
  341. }
  342. /// <inheritdoc/>
  343. protected override void OnAttachedToVisualTreeCore(VisualTreeAttachmentEventArgs e)
  344. {
  345. base.OnAttachedToVisualTreeCore(e);
  346. UpdateIsEnabledCore();
  347. }
  348. /// <summary>
  349. /// Called before the <see cref="GotFocus"/> event occurs.
  350. /// </summary>
  351. /// <param name="e">The event args.</param>
  352. protected virtual void OnGotFocus(GotFocusEventArgs e)
  353. {
  354. IsFocused = e.Source == this;
  355. }
  356. /// <summary>
  357. /// Called before the <see cref="LostFocus"/> event occurs.
  358. /// </summary>
  359. /// <param name="e">The event args.</param>
  360. protected virtual void OnLostFocus(RoutedEventArgs e)
  361. {
  362. IsFocused = false;
  363. }
  364. /// <summary>
  365. /// Called before the <see cref="KeyDown"/> event occurs.
  366. /// </summary>
  367. /// <param name="e">The event args.</param>
  368. protected virtual void OnKeyDown(KeyEventArgs e)
  369. {
  370. }
  371. /// <summary>
  372. /// Called before the <see cref="KeyUp"/> event occurs.
  373. /// </summary>
  374. /// <param name="e">The event args.</param>
  375. protected virtual void OnKeyUp(KeyEventArgs e)
  376. {
  377. }
  378. /// <summary>
  379. /// Called before the <see cref="TextInput"/> event occurs.
  380. /// </summary>
  381. /// <param name="e">The event args.</param>
  382. protected virtual void OnTextInput(TextInputEventArgs e)
  383. {
  384. }
  385. /// <summary>
  386. /// Called before the <see cref="PointerEnter"/> event occurs.
  387. /// </summary>
  388. /// <param name="e">The event args.</param>
  389. protected virtual void OnPointerEnter(PointerEventArgs e)
  390. {
  391. }
  392. /// <summary>
  393. /// Called before the <see cref="PointerLeave"/> event occurs.
  394. /// </summary>
  395. /// <param name="e">The event args.</param>
  396. protected virtual void OnPointerLeave(PointerEventArgs e)
  397. {
  398. }
  399. /// <summary>
  400. /// Called before the <see cref="PointerMoved"/> event occurs.
  401. /// </summary>
  402. /// <param name="e">The event args.</param>
  403. protected virtual void OnPointerMoved(PointerEventArgs e)
  404. {
  405. }
  406. /// <summary>
  407. /// Called before the <see cref="PointerPressed"/> event occurs.
  408. /// </summary>
  409. /// <param name="e">The event args.</param>
  410. protected virtual void OnPointerPressed(PointerPressedEventArgs e)
  411. {
  412. }
  413. /// <summary>
  414. /// Called before the <see cref="PointerReleased"/> event occurs.
  415. /// </summary>
  416. /// <param name="e">The event args.</param>
  417. protected virtual void OnPointerReleased(PointerReleasedEventArgs e)
  418. {
  419. }
  420. /// <summary>
  421. /// Called before the <see cref="PointerWheelChanged"/> event occurs.
  422. /// </summary>
  423. /// <param name="e">The event args.</param>
  424. protected virtual void OnPointerWheelChanged(PointerWheelEventArgs e)
  425. {
  426. }
  427. private static void IsEnabledChanged(AvaloniaPropertyChangedEventArgs e)
  428. {
  429. ((InputElement)e.Sender).UpdateIsEnabledCore();
  430. }
  431. /// <summary>
  432. /// Called before the <see cref="PointerEnter"/> event occurs.
  433. /// </summary>
  434. /// <param name="e">The event args.</param>
  435. private void OnPointerEnterCore(PointerEventArgs e)
  436. {
  437. IsPointerOver = true;
  438. OnPointerEnter(e);
  439. }
  440. /// <summary>
  441. /// Called before the <see cref="PointerLeave"/> event occurs.
  442. /// </summary>
  443. /// <param name="e">The event args.</param>
  444. private void OnPointerLeaveCore(PointerEventArgs e)
  445. {
  446. IsPointerOver = false;
  447. OnPointerLeave(e);
  448. }
  449. /// <summary>
  450. /// Updates the <see cref="IsEnabledCore"/> property value.
  451. /// </summary>
  452. private void UpdateIsEnabledCore()
  453. {
  454. UpdateIsEnabledCore(this.GetVisualParent<InputElement>());
  455. }
  456. /// <summary>
  457. /// Updates the <see cref="IsEnabledCore"/> property based on the parent's
  458. /// <see cref="IsEnabledCore"/>.
  459. /// </summary>
  460. /// <param name="parent">The parent control.</param>
  461. private void UpdateIsEnabledCore(InputElement parent)
  462. {
  463. if (parent != null)
  464. {
  465. IsEnabledCore = IsEnabled && parent.IsEnabledCore;
  466. }
  467. else
  468. {
  469. IsEnabledCore = IsEnabled;
  470. }
  471. foreach (var child in this.GetVisualChildren().OfType<InputElement>())
  472. {
  473. child.UpdateIsEnabledCore(this);
  474. }
  475. }
  476. }
  477. }