Interazioni tramite penna e Windows Ink nelle app di Windows
Surface Pen (disponibile per l'acquisto in Microsoft Store).
Panoramica
Ottimizzare l'app di Windows per l'input tramite penna per fornire funzionalità del dispositivo puntatore standard e la migliore esperienza di Windows Ink per gli utenti.
Nota
Questa sezione è incentrata sulla piattaforma Windows Ink. Per la gestione generale dell'input tramite puntatore (simile a mouse, tocco e touchpad), consultare Gestire l'input del puntatore.
Utilizzare l'input penna nell'app di Windows
Usare la penna e l'input penna di Windows per creare app aziendali più coinvolgenti
La piattaforma Windows Ink, insieme a un dispositivo di tipo penna, offre un modo naturale per creare note scritte a mano, disegni e annotazioni in formato digitale. La piattaforma supporta l'acquisizione dell'input del digitalizzatore come dati input penna, la generazione di dati input penna, la gestione dei dati input penna, il rendering dei dati input penna come tratti input penna nel dispositivo di output e la conversione dell'input penna in testo tramite il riconoscimento della grafia.
Oltre ad acquisire la posizione di base e lo spostamento della penna durante la scrittura o il disegno dell'utente, l'app può anche tenere traccia e raccogliere i diversi livelli di pressione usati durante un tratto. Queste informazioni, insieme alle impostazioni sulla forma della punta della penna, le dimensioni e la rotazione, il colore dell'input penna e lo scopo (inchiostro normale, cancellazione, evidenziazione e selezione), consentono di offrire esperienze utente che assomigliano da vicino alla scrittura o al disegno su carta con una penna, una matita o un pennello.
Nota
L'app può anche supportare l'input di tipo penna da altri dispositivi basati su puntatore, inclusi digitalizzatori touch e dispositivi mouse.
La piattaforma input penna è molto flessibile. È progettata per supportare vari livelli di funzionalità, a seconda dei requisiti.
Per le linee guida per l'esperienza utente di Windows Ink, consultare Controlli input penna.
Componenti della piattaforma Windows Ink
Componente | Descrizione |
---|---|
InkCanvas | Un controllo della piattaforma dell'interfaccia utente XAML che, per impostazione predefinita, riceve e visualizza tutto l'input da una penna come tratto input penna o come tratto di cancellazione. Per ulteriori informazioni su come usare InkCanvas, consultare Riconoscere i tratti di Windows Ink come testo e Archiviare e recuperare i dati del tratto di Windows Ink. |
InkPresenter | Oggetto code-behind, di cui è stato creato un'istanza con un controllo InkCanvas (esposto attraverso la proprietà InkCanvas.InkPresenter). Questo oggetto fornisce tutte la funzionalità di input penna predefinita esposta da InkCanvas, insieme a un set completo di API per una personalizzazione aggiuntiva. Per ulteriori informazioni su come usare InkPresenter, consultare Riconoscere i tratti di Windows Ink come testo e Archiviare e recuperare i dati del tratto di Windows Ink. |
InkToolbar | Un controllo della piattaforma dell'interfaccia utente XAML contenente una raccolta personalizzabile ed estendibile di pulsanti che attivano funzionalità correlate all'input penna in un InkCanvas associato. Per ulteriori informazioni su come usare InkToolbar, consultare Aggiungere un controllo InkToolbar a un'app di Windows con input di tipo penna. |
IInkD2DRenderer | Abilita il rendering di tratti input penna sul contesto del dispositivo Direct2D designato di un'app Universal Windows anziché il controllo InkCanvas predefinito. In questo modo è possibile personalizzare completamente l'esperienza di input penna. Per ulteriori informazioni, vedere l'esempio Input penna complesso. |
Input penna di base con InkCanvas
Per aggiungere funzionalità di input penna di base, posizionare semplicemente un controllo InkCanvas della piattaforma UWP nella pagina appropriata nell'app.
Per impostazione predefinita, InkCanvas supporta l'input penna solo da una penna. Il rendering dell'input viene eseguito come tratto input penna usando le impostazioni predefinite per il colore e lo spessore (una penna a sfera nera con uno spessore di 2 pixel) o considerato come gomma del tratto (quando l'input proviene da una punta di tipo gomma o da una punta della penna modificata con un pulsante di cancellazione).
Nota
Se non è presente una punta o un pulsante di tipo gomma, InkCanvas può essere configurato per elaborare l'input dalla punta della penna come tratto di cancellazione.
In questo esempio un controllo InkCanvas sovrappone un'immagine di sfondo.
Nota
InkCanvas ha le proprietà Height e Width impostate a zero come valore predefinito, a meno che l'oggetto non sia figlio di un elemento che ridimensiona automaticamente i relativi elementi figlio, come ad esempio i controlli StackPanel o Grid.
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel x:Name="HeaderPanel" Orientation="Horizontal" Grid.Row="0">
<TextBlock x:Name="Header"
Text="Basic ink sample"
Style="{ThemeResource HeaderTextBlockStyle}"
Margin="10,0,0,0" />
</StackPanel>
<Grid Grid.Row="1">
<Image Source="Assets\StoreLogo.png" />
<InkCanvas x:Name="inkCanvas" />
</Grid>
</Grid>
Questa serie di immagini mostra come viene eseguito il rendering dell'input penna da parte di questo controllo InkCanvas.
InkCanvas vuoto con un'immagine di sfondo. | InkCanvas con tratti di input penna. | InkCanvas con un tratto cancellato (si noti come la cancellazione opera su un intero tratto, non una parte). |
La funzionalità di input penna supportata dal controllo InkCanvas viene fornita da un oggetto code-behind denominato InkPresenter.
Per l'input penna di base, non è necessario preoccuparsi di InkPresenter. Tuttavia, per personalizzare e configurare il comportamento di input penna in InkCanvas, è necessario accedere al corrispondente oggetto InkPresenter.
Personalizzazione di base con InkPresenter
Viene creata un'istanza di un oggetto InkPresenter con ogni controllo InkCanvas.
Nota
Non è possibile creare direttamente un'istanza di InkPresenter. Viene invece eseguito l'accesso tramite la proprietà InkPresenter di InkCanvas.
Oltre a fornire tutti i comportamenti di input penna predefiniti del controllo InkCanvas corrispondente, InkPresenter InkPresenter fornisce un set completo di API per la personalizzazione aggiuntiva del tratto e la gestione più dettagliata dell'input penna (standard e modificato). Sono incluse proprietà del tratto, tipi di dispositivo di input supportati e se l'input viene elaborato dall'oggetto o passato all'app per l'elaborazione.
Nota
L'input penna standard (proveniente dalla punta la penna o punta/pulsante gomma) non viene modificato con un invito hardware secondario, ad esempio un pulsante della penna, un pulsante destro del mouse o un meccanismo simile.
Per impostazione predefinita, l'input penna è supportato solo per l'input penna. In questo caso InkPresenter viene configurato per interpretare i dati di input sia dalla penna che dal mouse come tratti input penna. Sono stati impostati anche alcuni attributi iniziali del tratto input penna usati per il rendering dei tratti in InkCanvas.
Per abilitare l'input penna mouse e tocco, impostare la proprietà InputDeviceTypes di InkPresenter sulla combinazione di valori CoreInputDeviceTypes desiderati.
public MainPage()
{
this.InitializeComponent();
// Set supported inking device types.
inkCanvas.InkPresenter.InputDeviceTypes =
Windows.UI.Core.CoreInputDeviceTypes.Mouse |
Windows.UI.Core.CoreInputDeviceTypes.Pen;
// Set initial ink stroke attributes.
InkDrawingAttributes drawingAttributes = new InkDrawingAttributes();
drawingAttributes.Color = Windows.UI.Colors.Black;
drawingAttributes.IgnorePressure = false;
drawingAttributes.FitToCurve = true;
inkCanvas.InkPresenter.UpdateDefaultDrawingAttributes(drawingAttributes);
}
Gli attributi del tratto input penna possono essere impostati in modo dinamico per soddisfare le preferenze utente o i requisiti dell'app.
In questo caso, si permette a un utente di scegliere da un elenco di colori input penna.
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel x:Name="HeaderPanel" Orientation="Horizontal" Grid.Row="0">
<TextBlock x:Name="Header"
Text="Basic ink customization sample"
VerticalAlignment="Center"
Style="{ThemeResource HeaderTextBlockStyle}"
Margin="10,0,0,0" />
<TextBlock Text="Color:"
Style="{StaticResource SubheaderTextBlockStyle}"
VerticalAlignment="Center"
Margin="50,0,10,0"/>
<ComboBox x:Name="PenColor"
VerticalAlignment="Center"
SelectedIndex="0"
SelectionChanged="OnPenColorChanged">
<ComboBoxItem Content="Black"/>
<ComboBoxItem Content="Red"/>
</ComboBox>
</StackPanel>
<Grid Grid.Row="1">
<Image Source="Assets\StoreLogo.png" />
<InkCanvas x:Name="inkCanvas" />
</Grid>
</Grid>
Si gestiscono quindi le modifiche apportate al colore selezionato e si aggiornano di conseguenza gli attributi del tratto input penna.
// Update ink stroke color for new strokes.
private void OnPenColorChanged(object sender, SelectionChangedEventArgs e)
{
if (inkCanvas != null)
{
InkDrawingAttributes drawingAttributes =
inkCanvas.InkPresenter.CopyDefaultDrawingAttributes();
string value = ((ComboBoxItem)PenColor.SelectedItem).Content.ToString();
switch (value)
{
case "Black":
drawingAttributes.Color = Windows.UI.Colors.Black;
break;
case "Red":
drawingAttributes.Color = Windows.UI.Colors.Red;
break;
default:
drawingAttributes.Color = Windows.UI.Colors.Black;
break;
};
inkCanvas.InkPresenter.UpdateDefaultDrawingAttributes(drawingAttributes);
}
}
Queste immagini illustrano in che modo l'input penna viene elaborato e personalizzato da InkPresenter.
InkCanvas con tratti input penna neri predefiniti.
InkCanvas con tratti input penna di colore rosso selezionati dall'utente.
Per fornire funzionalità oltre all'input penna e alla cancellazione, ad esempio la selezione del tratto, l'app deve identificare un input specifico affinché InkPresenter possa passarlo senza elaborazione e sia gestibile dall'app.
Input pass-through per l'elaborazione avanzata
Per impostazione predefinita, InkPresenter elabora tutti gli input come tratto input penna o tratto di cancellazione, incluso l'input modificato da un invito hardware secondario, ad esempio un pulsante della penna, un pulsante destro del mouse o simile. Tuttavia, gli utenti associano generalmente a questi inviti secondari delle funzionalità aggiuntive o un comportamento modificato.
In alcuni casi, potrebbe anche essere necessario esporre funzionalità aggiuntive per penne senza inviti secondari (funzionalità in genere non associate alla punta della penna), altri tipi di dispositivo di input o un tipo di comportamento modificato in base a una selezione utente nell'interfaccia utente dell'app.
Per supportare questi comportamenti, InkPresenter può essere configurato per lasciare un input specifico non elaborato. Questo input non elaborato viene quindi passato all'app per l'elaborazione.
Esempio: usare l'input non elaborato per implementare la selezione del tratto
La piattaforma Windows Ink non fornisce il supporto predefinito per le azioni che richiedono input modificato, ad esempio la selezione del tratto. Per supportare funzionalità di questo tipo, è necessario fornire una soluzione personalizzata nelle app.
L'esempio di codice seguente (tutto il codice si trova nei file MainPage.xaml e MainPage.xaml.cs) illustra come abilitare la selezione del tratto quando l'input viene modificato con un pulsante della penna (o il pulsante destro del mouse).
Prima di tutto, si imposta l'interfaccia utente in MainPage.xaml.
Qui si aggiunge un'area di disegno (sotto InkCanvas) per disegnare il tratto di selezione. L'uso di un livello separato per disegnare il tratto di selezione lascia InkCanvas e il relativo contenuto invariati.
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <StackPanel x:Name="HeaderPanel" Orientation="Horizontal" Grid.Row="0"> <TextBlock x:Name="Header" Text="Advanced ink customization sample" VerticalAlignment="Center" Style="{ThemeResource HeaderTextBlockStyle}" Margin="10,0,0,0" /> </StackPanel> <Grid Grid.Row="1"> <!-- Canvas for displaying selection UI. --> <Canvas x:Name="selectionCanvas"/> <!-- Inking area --> <InkCanvas x:Name="inkCanvas"/> </Grid> </Grid>
In MainPage.xaml.cs si dichiarano un paio di variabili globali per mantenere i riferimenti agli aspetti dell'interfaccia utente di selezione. In particolare, il tratto di lasso di selezione e il rettangolo di delimitazione che evidenzia i tratti selezionati.
// Stroke selection tool. private Polyline lasso; // Stroke selection area. private Rect boundingRect;
Successivamente, si configura InkPresenter affinché interpreti i dati di input sia dalla penna che dal mouse come tratti input penna e impostiamo alcuni attributi iniziali del tratto input penna usati per il rendering dei tratti su InkCanvas.
Soprattutto, si usa la proprietà InputProcessingConfiguration di InkPresenter per indicare che qualsiasi input modificato deve essere elaborato dall'app. L'input modificato viene specificato assegnando a InputProcessingConfiguration.RightDragAction un valore di InkInputRightDragAction.LeaveUnprocessed. Quando questo valore viene impostato, InkPresenter passa attraverso la classe InkUnprocessedInput, un set di eventi puntatore da gestire.
Vengono assegnati listener per gli eventi PointerPressed, PointerMoved e PointerReleased non elaborati passati da InkPresenter. Tutte le funzionalità di selezione vengono implementate nei gestori di questi eventi.
Infine, si assegnano i listener per gli eventi StrokeStarted e StrokesErased di InkPresenter. Si usano i gestori di questi eventi per ripulire l'interfaccia utente di selezione se viene avviato un nuovo tratto o se viene cancellato un tratto esistente.
public MainPage() { this.InitializeComponent(); // Set supported inking device types. inkCanvas.InkPresenter.InputDeviceTypes = Windows.UI.Core.CoreInputDeviceTypes.Mouse | Windows.UI.Core.CoreInputDeviceTypes.Pen; // Set initial ink stroke attributes. InkDrawingAttributes drawingAttributes = new InkDrawingAttributes(); drawingAttributes.Color = Windows.UI.Colors.Black; drawingAttributes.IgnorePressure = false; drawingAttributes.FitToCurve = true; inkCanvas.InkPresenter.UpdateDefaultDrawingAttributes(drawingAttributes); // By default, the InkPresenter processes input modified by // a secondary affordance (pen barrel button, right mouse // button, or similar) as ink. // To pass through modified input to the app for custom processing // on the app UI thread instead of the background ink thread, set // InputProcessingConfiguration.RightDragAction to LeaveUnprocessed. inkCanvas.InkPresenter.InputProcessingConfiguration.RightDragAction = InkInputRightDragAction.LeaveUnprocessed; // Listen for unprocessed pointer events from modified input. // The input is used to provide selection functionality. inkCanvas.InkPresenter.UnprocessedInput.PointerPressed += UnprocessedInput_PointerPressed; inkCanvas.InkPresenter.UnprocessedInput.PointerMoved += UnprocessedInput_PointerMoved; inkCanvas.InkPresenter.UnprocessedInput.PointerReleased += UnprocessedInput_PointerReleased; // Listen for new ink or erase strokes to clean up selection UI. inkCanvas.InkPresenter.StrokeInput.StrokeStarted += StrokeInput_StrokeStarted; inkCanvas.InkPresenter.StrokesErased += InkPresenter_StrokesErased; }
Di definiscono quindi i gestori per gli eventi PointerPressed, PointerMoved e PointerReleased non elaborati passati da InkPresenter.
Tutte le funzionalità di selezione vengono implementate in questi gestori, inclusi il tratto lasso e il rettangolo di delimitazione.
// Handle unprocessed pointer events from modified input. // The input is used to provide selection functionality. // Selection UI is drawn on a canvas under the InkCanvas. private void UnprocessedInput_PointerPressed( InkUnprocessedInput sender, PointerEventArgs args) { // Initialize a selection lasso. lasso = new Polyline() { Stroke = new SolidColorBrush(Windows.UI.Colors.Blue), StrokeThickness = 1, StrokeDashArray = new DoubleCollection() { 5, 2 }, }; lasso.Points.Add(args.CurrentPoint.RawPosition); selectionCanvas.Children.Add(lasso); } private void UnprocessedInput_PointerMoved( InkUnprocessedInput sender, PointerEventArgs args) { // Add a point to the lasso Polyline object. lasso.Points.Add(args.CurrentPoint.RawPosition); } private void UnprocessedInput_PointerReleased( InkUnprocessedInput sender, PointerEventArgs args) { // Add the final point to the Polyline object and // select strokes within the lasso area. // Draw a bounding box on the selection canvas // around the selected ink strokes. lasso.Points.Add(args.CurrentPoint.RawPosition); boundingRect = inkCanvas.InkPresenter.StrokeContainer.SelectWithPolyLine( lasso.Points); DrawBoundingRect(); }
Per concludere il gestore eventi PointerReleased, si cancella il livello di selezione di tutto il contenuto (tratto lasso) e quindi si disegna un singolo rettangolo di delimitazione intorno ai tratti input penna inclusi nell'area lasso.
// Draw a bounding rectangle, on the selection canvas, encompassing // all ink strokes within the lasso area. private void DrawBoundingRect() { // Clear all existing content from the selection canvas. selectionCanvas.Children.Clear(); // Draw a bounding rectangle only if there are ink strokes // within the lasso area. if (!((boundingRect.Width == 0) || (boundingRect.Height == 0) || boundingRect.IsEmpty)) { var rectangle = new Rectangle() { Stroke = new SolidColorBrush(Windows.UI.Colors.Blue), StrokeThickness = 1, StrokeDashArray = new DoubleCollection() { 5, 2 }, Width = boundingRect.Width, Height = boundingRect.Height }; Canvas.SetLeft(rectangle, boundingRect.X); Canvas.SetTop(rectangle, boundingRect.Y); selectionCanvas.Children.Add(rectangle); } }
Infine, si definiscono i gestori per gli eventi StrokeStarted e StrokesErased di InkPresenter.
Entrambi richiamano la stessa funzione di pulizia per cancellare la selezione corrente ogni volta che viene rilevato un nuovo tratto.
// Handle new ink or erase strokes to clean up selection UI. private void StrokeInput_StrokeStarted( InkStrokeInput sender, Windows.UI.Core.PointerEventArgs args) { ClearSelection(); } private void InkPresenter_StrokesErased( InkPresenter sender, InkStrokesErasedEventArgs args) { ClearSelection(); }
Questa è la funzione per rimuovere tutta l'interfaccia utente di selezione dall'area di disegno di selezione quando viene avviato un nuovo tratto o quando viene cancellato un tratto esistente.
// Clean up selection UI. private void ClearSelection() { var strokes = inkCanvas.InkPresenter.StrokeContainer.GetStrokes(); foreach (var stroke in strokes) { stroke.Selected = false; } ClearDrawnBoundingRect(); } private void ClearDrawnBoundingRect() { if (selectionCanvas.Children.Any()) { selectionCanvas.Children.Clear(); boundingRect = Rect.Empty; } }
Personalizzare il rendering dell'input penna
Per impostazione predefinita, l'input penna viene elaborato in un thread in background a bassa latenza e oggetti di rendering progressivo mentre viene disegnato in modo provvisorio. Quando il tratto viene completato (penna o dito sollevato o pulsante del mouse rilasciato), il tratto viene elaborato sul thread dell'interfaccia utente e sottoposto a rendering in modo definitivo sul livello InkCanvas (sopra il contenuto dell'applicazione e sostituendo l'input penna provvisorio).
È possibile eseguire l'override di questo comportamento predefinito e controllare completamente l'esperienza di input penna "eseguendo il rendering definitivo" dei tratti input penna provvisori. Anche se il comportamento predefinito è in genere sufficiente per la maggior parte delle applicazioni, esistono alcuni casi in cui potrebbe essere necessario il rendering definitivo personalizzato, tra cui:
- Gestione più efficiente di raccolte di tratti input penna di grandi dimensioni o complessi
- Supporto di panoramica e zoom più efficiente su aree di disegno input penna di grandi dimensioni
- Interleaving tra input penna e altri oggetti, ad esempio forme o testo, mantenendo l'ordine z
- Rendere definitivo il rendering e convertire i tratti input penna in modo sincrono in una forma DirectX (ad esempio, una linea retta o una forma rasterizzata e integrata nel contenuto dell'applicazione anziché come livello InkCanvas separato).
Il rendering definitivo personalizzato richiede un oggetto IInkD2DRenderer per gestire l'input penna ed eseguirne il rendering nel contesto di dispositivo Direct2D dell'app di Windows universale, anziché nel controllo InkCanvas predefinito.
Chiamando ActivateCustomDrying (prima del caricamento di InkCanvas), un'app crea un oggetto InkSynchronizer per personalizzare il rendering di un tratto input penna su SurfaceImageSource o VirtualSurfaceImageSource.
Sia SurfaceImageSource che VirtualSurfaceImageSource forniscono una superficie condivisa DirectX per l'app da disegnare e comporre nel contenuto dell'applicazione, anche se VSIS fornisce una superficie virtuale più grande dello schermo per la panoramica e lo zoom efficienti. Poiché gli aggiornamenti visivi di queste superfici vengono sincronizzati con il thread dell'interfaccia utente XAML, quando viene eseguito il rendering dell'input penna, l'input penna provvisorio può essere rimosso contemporaneamente da InkCanvas.
È anche possibile personalizzare l'input penna renderizzato in modo definitivo in un oggetto SwapChainPanel, ma la sincronizzazione con il thread dell'interfaccia utente non è garantita e potrebbe verificarsi un ritardo tra il rendering dell'input penna e il rendering dell'input penna in SwapChainPanel e la rimozione dell'input penna da InkCanvas.
Per un esempio completo di questa funzionalità, vedere l'esempio Input penna complesso.
Nota
Rendering definitivo dell'input penna e InkToolbar
Se l'app esegue l'override del comportamento di rendering dell'input penna predefinito di InkPresenter con un'implementazione del rendering definitivo, i tratti input penna sottoposti a rendering non sono più disponibili per InkToolbar e i comandi di cancellazione predefiniti di InkToolbar non funzionano come previsto. Per fornire funzionalità di cancellazione, è necessario gestire tutti gli eventi del puntatore, eseguire hit test su ogni tratto ed eseguire l'override del comando "Cancella tutto l'input penna" predefinito.
Altri articoli in questa sezione
Argomento | Descrizione |
---|---|
Riconoscere i tratti input penna | Convertire i tratti input penna in testo usando il riconoscimento della grafia o in forme che usano il riconoscimento personalizzato. |
Memorizzare e recuperare i tratti input penna | Archiviare i dati del tratto input penna in un file GIF (Graphics Interchange Format) usando metadati ISF (Ink Serialized Format) incorporati. |
Aggiungere un controllo InkToolbar a un'app per l'input penna di Windows | Aggiungere un controllo InkToolbar predefinito a un'app di input penna di Windows, aggiungere un pulsante penna personalizzato a InkToolbar e associare il pulsante penna personalizzato a una definizione di penna personalizzata. |
Articoli correlati
- Attività iniziali: supportare l'input penna un un'app Windows
- Gestire l'input del puntatore
- Identificare i dispositivi di input
- Specifica ISF (Ink Serialized Format).
API
Esempi
- Esercitazione introduttiva: supportare l'input penna nell'app Windows
- Esempio di input penna semplice (C#/C++)
- Esempio di input penna complesso (C++)
- Esempio di input penna (JavaScript)
- Esempio album da colorare
- Esempio di note di famiglia
- Esempio di input di base
- Esempio di input a bassa latenza
- Esempio di modalità di interazione utente
- Esempio di indicatori visivi di stato attivo