Skip to main content

Input events

Avalonia provides a comprehensive set of input events for handling pointer (mouse/touch/pen), keyboard, and gesture interactions. Most input events use a combined Tunnel | Bubble routing strategy, giving parent elements the opportunity to intercept input before it reaches the target.

Pointer events

Pointer events abstract mouse, touch, and pen input into a unified model. They bubble up the visual tree by default.

EventFires When
PointerEnteredThe pointer enters the bounds of the control.
PointerExitedThe pointer leaves the bounds of the control.
PointerMovedThe pointer moves within the control.
PointerPressedA pointer button is pressed over the control.
PointerReleasedA pointer button is released over the control.
PointerCaptureLostThe control loses pointer capture.
PointerWheelChangedThe mouse wheel or trackpad scrolls over the control.

Handling pointer events

protected override void OnPointerPressed(PointerPressedEventArgs e)
{
base.OnPointerPressed(e);

var point = e.GetPosition(this); // Position relative to this control
var properties = e.GetCurrentPoint(this).Properties;

if (properties.IsLeftButtonPressed)
{
// Left button pressed at (point.X, point.Y)
}
}

Key properties on PointerEventArgs

Property / MethodDescription
GetPosition(Visual)Returns the pointer position relative to the specified visual.
GetCurrentPoint(Visual)Returns a PointerPoint with position and button state.
PointerThe Pointer instance, useful for capture operations.
KeyModifiersWhether Shift, Control, Alt, or Meta keys are held.

Pointer capture

When you capture the pointer, all subsequent pointer events are directed to the capturing control until capture is released:

protected override void OnPointerPressed(PointerPressedEventArgs e)
{
base.OnPointerPressed(e);
e.Pointer.Capture(this); // Start capturing
}

protected override void OnPointerReleased(PointerReleasedEventArgs e)
{
base.OnPointerReleased(e);
e.Pointer.Capture(null); // Release capture
}

Only one element can hold pointer capture at a time across the entire application. This matches operating system behavior where a single physical mouse device can only have one captured element. When a different control captures the pointer (for example, in a popup window), the previous capture is released and the original control receives a PointerCaptureLost event.

Keyboard events

Keyboard events fire on the currently focused element and bubble up the tree.

EventFires When
KeyDownA key is pressed.
KeyUpA key is released.
TextInputCharacter input is received (after IME processing).

Handling keyboard events

protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);

if (e.Key == Key.Enter)
{
// Handle Enter key
e.Handled = true;
}

if (e.Key == Key.C && e.KeyModifiers.HasFlag(KeyModifiers.Control))
{
// Handle Ctrl+C
e.Handled = true;
}
}

Key properties on KeyEventArgs

PropertyDescription
KeyThe physical key pressed (from the Key enum).
KeyModifiersModifier keys held (Control, Shift, Alt, Meta).
KeySymbolThe character produced by the key press, if any.

Tunneling (preview) events

For input events that use Tunnel | Bubble routing, the tunneling phase fires first. You can intercept events during the tunnel phase by using the routing strategy parameter:

myControl.AddHandler(InputElement.PointerPressedEvent, OnPreviewPointerPressed,
RoutingStrategies.Tunnel);
private void OnPreviewPointerPressed(object? sender, PointerPressedEventArgs e)
{
// This fires before the bubble phase
// Set e.Handled = true to prevent the event from reaching child elements
}

This is useful for intercepting input at a parent level before child controls process it.

Gesture events

Avalonia provides high-level gesture events built on top of raw pointer events:

EventFires When
TappedA quick tap/click gesture completes.
DoubleTappedA double-tap/double-click gesture completes.
HoldingA long-press gesture is detected (touch).

Gesture events bubble up the tree. For more complex gestures (pinch, pull, scroll), see Gestures.

<Border Tapped="OnBorderTapped" Background="LightGray">
<TextBlock Text="Tap me" />
</Border>
private void OnBorderTapped(object? sender, TappedEventArgs e)
{
// Respond to the tap
}

Common input patterns

Drag detection

private Point _pressPoint;
private bool _isDragging;

protected override void OnPointerPressed(PointerPressedEventArgs e)
{
base.OnPointerPressed(e);
_pressPoint = e.GetPosition(this);
_isDragging = false;
e.Pointer.Capture(this);
}

protected override void OnPointerMoved(PointerEventArgs e)
{
base.OnPointerMoved(e);

if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
{
var currentPoint = e.GetPosition(this);
var delta = currentPoint - _pressPoint;

if (!_isDragging && (Math.Abs(delta.X) > 3 || Math.Abs(delta.Y) > 3))
{
_isDragging = true;
}

if (_isDragging)
{
// Handle drag
}
}
}

protected override void OnPointerReleased(PointerReleasedEventArgs e)
{
base.OnPointerReleased(e);
_isDragging = false;
e.Pointer.Capture(null);
}

Keyboard shortcuts on a window

public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}

protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);

if (e.Key == Key.S && e.KeyModifiers.HasFlag(KeyModifiers.Control))
{
SaveDocument();
e.Handled = true;
}
}
}
tip

For declarative keyboard shortcuts, consider using KeyBindings and HotKeys instead of handling KeyDown manually.

See also