avalonia-input-interaction
Skill50 starsChanged 7 days agoMITView on GitHub
Use when handling pointer events, keyboard input, gestures, focus, drag-and-drop, or hot keys in Avalonia 11.3/12.x. Covers PointerPressed/Released/Moved, KeyDown/KeyUp, TextInput, HotKeyManager, KeyGesture, focus management and Focus Traversal (12.0+), gesture events and recognizers, drag-and-drop (DragDrop.DoDragDropAsync, DataTransfer, DataFormat; 11.x DataObject), and Cursor types.
In this repository23 other files it gives its agents.
- avalonia-app-developmentSkill
- avalonia-controlsSkill
- avalonia-custom-controlsSkill
- avalonia-data-bindingSkill
- avalonia-data-templatesSkill
- avalonia-deploymentSkill
- avalonia-eventsSkill
- avalonia-graphics-animationSkill
- avalonia-interop-renderingSkill
- avalonia-layoutSkill
- avalonia-mobileSkill
- avalonia-mvvmSkill
- avalonia-performanceSkill
- avalonia-pro-maxSkill
- avalonia-property-systemSkill
- avalonia-servicesSkill
- avalonia-stylingSkill
- avalonia-testingSkill
- avalonia-threadingSkill
- avalonia-versionsSkill
- avalonia-wpf-migrationSkill
- avalonia-xamlSkill
- avaloniaSkill
The file
We split this skill into the rules it gives an agent
1 rule. About 0 are common, 1 is distinctive, and 0 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 10
All input routes as routed events (bubbling by default, tunneling with "Preview" prefix).
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Avalonia Input & Interaction
Version labels: see avalonia-versions. (12.0+) = 12.x only, (11.x) = 11.x only, unlabeled = all.
Overview
All input routes as routed events (bubbling by default, tunneling with "Preview" prefix). Pointer events are unified across mouse, touch, and stylus.
(12.0+) Touch/pen select and focus on pointer release, not press (mouse unchanged). ListBoxItem/TreeViewItem handle selection themselves. Access keys (_Save) match the symbol printed on the key (accents, digits); AccessText.AccessKey is string?.
Pointer Events
| Event | Fires when |
PointerPressed | Button/finger down |
PointerReleased | Button/finger up |
PointerMoved | Pointer moves over control |
PointerEntered | Pointer enters bounds |
PointerExited | Pointer leaves bounds |
PointerCaptureLost | Capture released |
Tapped | Quick tap/click |
DoubleTapped | Double tap/click |
RightTapped | Right-click / long press |
myControl.PointerPressed += (s, e) =>
{
var point = e.GetPosition(myControl);
var props = e.GetCurrentPoint(myControl).Properties;
if (props.IsLeftButtonPressed) { /* left click */ }
if (props.IsRightButtonPressed) { /* right click */ }
if (props.IsMiddleButtonPressed) { /* middle click */ }
};Capture pointer (receive events outside bounds):
myControl.PointerPressed += (s, e) =>
{
e.Pointer.Capture(myControl);
};
myControl.PointerReleased += (s, e) =>
{
e.Pointer.Capture(null); // release
};Check pointer type:
myControl.PointerPressed += (s, e) =>
{
if (e.Pointer.Type == PointerType.Touch) { /* touch */ }
if (e.Pointer.Type == PointerType.Pen) { /* stylus */ }
};Keyboard Events
| Event | Fires when |
KeyDown | Key pressed (repeats while held) |
KeyUp | Key released |
TextInput | Text character produced |
myControl.KeyDown += (s, e) =>
{
if (e.Key == Key.Enter && e.KeyModifiers == KeyModifiers.Control)
{
e.Handled = true; // stop bubbling + prevent default
SubmitForm();
}
};myTextBox.TextInput += (s, e) =>
{
if (!char.IsDigit(e.Text![0]))
e.Handled = true; // block non-digit input
};KeyModifiers flags: None, Alt, Control, Shift, Meta (combinable with |)
// Ctrl+Shift+Z
if (e.Key == Key.Z && e.KeyModifiers == (KeyModifiers.Control | KeyModifiers.Shift))Hot Keys
XAML registration:
<Button HotKey="Ctrl+S" Command="{Binding SaveCommand}" Content="Save"/>
<MenuItem HotKey="Ctrl+Z" Header="Undo" Command="{Binding UndoCommand}"/>Code registration:
HotKeyManager.RegisterHotKey(myControl, new KeyGesture(Key.S, KeyModifiers.Control));
HotKeyManager.SetHotKey(myButton, new KeyGesture(Key.F5));Unregister:
HotKeyManager.SetHotKey(myControl, null);Focus
// Programmatic focus
myControl.Focus(NavigationMethod.Tab);
// Via FocusManager
var fm = TopLevel.GetTopLevel(this)?.FocusManager;
fm?.Focus(myControl, NavigationMethod.Tab);
var focused = fm?.GetFocusedElement();XAML focus control:
<TextBox IsTabStop="False"/> <!-- exclude from tab order -->
<TextBox TabIndex="2"/> <!-- explicit tab order -->There is no AutoFocus property; call Focus() after attach (e.g. in Loaded/OnAttachedToVisualTree) or use FocusManager.
(12.0+) Focus Traversal API — IFocusManager is public and manages all focus:
fm.TryMoveFocus(NavigationDirection.Next); // bool
var next = fm.FindNextElement(NavigationDirection.Next); // IInputElement? (options: FindNextElementOptions)
var first = fm.FindFirstFocusableElement();
var last = fm.FindLastFocusableElement();(11.x) KeyboardNavigationHandler.GetNext — removed in 12.
(12.0+) Cancellable focus — GettingFocus / LosingFocus use FocusChangingEventArgs:
myBox.LosingFocus += (s, e) =>
{
if (!IsValid()) e.TryCancel(); // or e.TrySetNewFocusedElement(otherControl)
};GotFocus / LostFocus use (12.0+) FocusChangedEventArgs (OldFocusedElement, NewFocusedElement, NavigationMethod, KeyModifiers); (11.x) GotFocusEventArgs.
Pseudoclasses for styling:
<Style Selector="TextBox:focus">
<Setter Property="BorderBrush" Value="Blue"/>
</Style>
<Style Selector="Button:focus-visible">
<Setter Property="BorderThickness" Value="2"/>
</Style>Focus scope (contains Tab navigation):
<Panel FocusManager.IsFocusScope="True">
<!-- Tab cycles within this panel -->
</Panel>Gestures
Tapped, RightTapped, DoubleTapped, Holding are events on InputElement. Touch gestures are raised by recognizers added to GestureRecognizers (e.g. PinchGestureRecognizer, ScrollGestureRecognizer, PullGestureRecognizer) and handled as routed events on the element:
<!-- (12.0+) events directly on InputElement -->
<Border Pinch="OnPinch" PinchEnded="OnPinchEnded">
<Border.GestureRecognizers>
<PinchGestureRecognizer/>
</Border.GestureRecognizers>
</Border>
<!-- (11.x) Gestures.Pinch="OnPinch" Gestures.PinchEnded="OnPinchEnded" -->private void OnPinch(object? sender, PinchEventArgs e)
{
_scale *= e.Scale;
myBorder.RenderTransform = new ScaleTransform(_scale, _scale);
}Event (on InputElement) | Args |
Pinch, PinchEnded | PinchEventArgs, PinchEndedEventArgs |
PullGesture, PullGestureEnded | PullGestureEventArgs, PullGestureEndedEventArgs |
ScrollGesture, ScrollGestureInertiaStarting, ScrollGestureEnded | ScrollGesture*EventArgs |
SwipeGesture, SwipeGestureEnded | SwipeGestureEventArgs, SwipeGestureEndedEventArgs |
PointerTouchPadGestureMagnify/Rotate/Swipe | PointerDeltaEventArgs |
Drag and Drop
(12.0+) Source (initiates drag):
private async void OnPointerPressed(object? sender, PointerPressedEventArgs e)
{
var item = DataTransferItem.CreateText("dragged text");
var myFormat = DataFormat.CreateInProcessFormat<MyType>("myapp/mytype");
item.Set(myFormat, myObject); // extra in-process format on same item
var data = new DataTransfer();
data.Add(item);
var result = await DragDrop.DoDragDropAsync(e, data,
DragDropEffects.Copy | DragDropEffects.Move);
}Target (receives drop):
<Border DragDrop.AllowDrop="True"
DragDrop.Drop="OnDrop" DragDrop.DragOver="OnDragOver"
DragDrop.DragEnter="OnDragEnter" DragDrop.DragLeave="OnDragLeave"/>// (12.0+)
private void OnDragOver(object? sender, DragEventArgs e)
{
e.DragEffects = e.DataTransfer.Contains(DataFormat.Text)
? DragDropEffects.Copy
: DragDropEffects.None;
e.Handled = true;
}
private void OnDrop(object? sender, DragEventArgs e)
{
var text = e.DataTransfer.TryGetText(); // string?
var files = e.DataTransfer.TryGetFiles(); // IStorageItem[]?
var mine = e.DataTransfer.TryGetValue(myFormat); // DataFormat<T> where T : class
}Built-in DataFormat: Text, Bitmap, File. Custom: DataFormat.CreateStringApplicationFormat(id), CreateBytesApplicationFormat(id), CreateInProcessFormat<T>(id).
(11.x) equivalent — do not use in 12:
var data = new DataObject();
data.Set(DataFormats.Text, "dragged text");
var result = await DragDrop.DoDragDrop(e, data, DragDropEffects.Copy);
// target: e.Data.Contains(DataFormats.Text), e.Data.GetText(), e.Data.GetFiles()
// DataFormats: Text, Files, FileNamesCursor
<Border Cursor="Hand"/>
<TextBox Cursor="IBeam"/>
<Border Cursor="Wait"/>Available cursors: Default, Arrow, Cross, Hand, Help, IBeam, No, SizeAll, SizeNESW, SizeNS, SizeNWSE, SizeWE, TopSide, BottomSide, LeftSide, RightSide, Wait, None
Custom cursor from bitmap:
var cursor = new Cursor(myBitmap, new PixelPoint(hotspotX, hotspotY));
myControl.Cursor = cursor;Scroll Events
myControl.PointerWheelChanged += (s, e) =>
{
var delta = e.Delta; // Vector: X for horizontal, Y for vertical
ScrollBy(-delta.Y * 30);
};Common Mistakes
- Not setting
e.Handled = trueonKeyDown— event bubbles to parent;TextBoxwill still consume keys DragDrop.DoDragDropAsync(11.x:DoDragDrop) must be called from the pointer event handler — calling afterawaitloses the pointer event contextFocus()before control is attached to visual tree — silently does nothing; call inOnAttachedToVisualTreeor later- Gesture recognizers vs. events —
Tapped/DoubleTappedfire onInputElementdirectly, no recognizer needed; touch gestures (Pinch,ScrollGesture) need the matching recognizer inGestureRecognizers - (12.0+)
Gestures.Pinchprefix — removed; usePinch="..."directly.Gesturesis no longer public - (12.0+) Using
DataObject/DataFormats/e.Data— gone; useDataTransfer/DataFormat/e.DataTransfer - (12.0+) Selection on touch fires on release — don't rely on
PointerPressedto select for touch/pen DragDrop.AllowDropis an attached property — must be set on the drop target, not a parentPointerPressedfires beforeTapped— don't handle both if one is sufficient
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

