Взаимодействие с пером и Windows Ink в приложениях для Windows

Изображение героя пера Surface.
Ручка Surface (доступна для покупки в Microsoft Store).

Обзор

Оптимизируйте приложение Windows для ввода пера, чтобы обеспечить как стандартные функциональные возможности устройств указателя, так и лучшие возможности Windows Ink для пользователей.

Примечание.

В этом разделе рассматривается платформа Windows Ink. Общие сведения об обработке входных данных указателя (аналогично мыши, касания и сенсорной панели), см. в разделе "Обработка ввода указателя".

Использование рукописного ввода в приложении Для Windows

Использование Пера Windows и Рукописного ввода для создания более привлекательных корпоративных приложений

Платформа Windows Ink вместе с устройством пера предоставляет естественный способ создания цифровых рукописных заметок, рисунков и заметок. Платформа поддерживает запись входных данных дигитайзера в виде рукописных данных, создания рукописных данных, управления данными рукописного ввода, отрисовки рукописных данных в виде росчерков рукописного ввода на выходном устройстве и преобразования рукописного ввода в текст с помощью распознавания рукописного ввода.

Помимо записи основной позиции и перемещения пера по мере записи или рисования, приложение также может отслеживать и собирать различные объемы давления, используемого на протяжении штриха. Эти сведения, а также параметры для фигуры пера, размера и поворота, цвета рукописного ввода и назначения (обычный рукописный ввод, стирания, выделения и выбора), позволяют предоставлять пользователям возможности, которые очень похожи на написание или рисование на бумаге с пером, карандашом или кистью.

Примечание.

Ваше приложение также может поддерживать ввод рукописного ввода с других устройств на основе указателя, включая сенсорные дигитайзеры и устройства мыши. 

Платформа рукописного ввода очень гибкая. Он предназначен для поддержки различных уровней функциональности в зависимости от ваших требований.

Рекомендации по пользовательскому интерфейсу Windows Ink см. в разделе "Элементы управления рукописным вводом".

Компоненты платформы Windows Ink

Компонент Description
InkCanvas Элемент управления платформой пользовательского интерфейса XAML, который по умолчанию получает и отображает все входные данные из пера в виде росчерка рукописного ввода или штриха удаления.
Дополнительные сведения о том, как использовать InkCanvas, см. в разделе Распознавание росчерков Windows Ink в виде текста и хранилища и получения данных росчерка Windows Ink.
InkPresenter. Объект code-behind, созданный вместе с элементом управления InkCanvas (предоставляется через свойство InkCanvas.InkPresenter). Этот объект предоставляет все функции рукописного ввода по умолчанию, предоставляемые InkCanvas, а также комплексный набор API для дополнительной настройки и персонализации.
Дополнительные сведения о том, как использовать InkPresenter, см. в разделе "Распознавание росчерков Windows Ink в виде текста и магазина" и получения данных росчерка Windows Ink.
InkToolbar Элемент управления платформы пользовательского интерфейса XAML, содержащий настраиваемую и расширяемую коллекцию кнопок, которые активируют функции, связанные с рукописным вводом, в связанном InkCanvas.
Дополнительные сведения об использовании inkToolbar см. в разделе "Добавление панели inkToolbar" в приложение рукописного ввода windows.
IInkD2DRenderer Включает отрисовку росчерков рукописного ввода в назначенный контекст устройства Direct2D универсального приложения Для Windows вместо элемента управления InkCanvas по умолчанию. Это обеспечивает полную настройку интерфейса рукописного ввода.
Дополнительные сведения см. в примере сложного рукописного ввода.

Базовая рукописная вводка с помощью InkCanvas

Чтобы добавить основные функции рукописного ввода, просто поместите элемент управления платформы UWP InkCanvas на соответствующую страницу в приложении.

По умолчанию InkCanvas поддерживает входные данные рукописного ввода только из пера. Входные данные отображаются в виде росчерка рукописного ввода с использованием параметров по умолчанию для цвета и толщины (черно-шарового пера с толщиной 2 пикселя), или обрабатываются как ластик (если входные данные из подсказки ластика или кончик пера изменены кнопкой удаления).

Примечание.

Если подсказка или кнопка ластика отсутствует, можно настроить InkCanvas для обработки входных данных из кончика пера в виде штриха удаления.

В этом примере inkCanvas накладывает фоновое изображение.

Примечание.

InkCanvas имеет свойства Height и Width по умолчанию нулю, если он не является дочерним элементом элемента, который автоматически размерирует дочерние элементы, такие как элементы управления StackPanel или 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>

В этой серии изображений показано, как отрисовывается ввод пера этим элементом управления InkCanvas.

Снимок экрана: пустой объект InkCanvas с фоновым изображением. Снимок экрана: InkCanvas с росчерками рукописного ввода. Снимок экрана: InkCanvas с одним штрихом стирается.
Пустой inkCanvas с фоновым изображением. InkCanvas с рукописными росчерками. InkCanvas с одним штрихом стирается (обратите внимание, как стереть работает на весь штрих, а не на часть).

Функции рукописного ввода, поддерживаемые элементом управления InkCanvas, предоставляются объектом программной части под названием InkPresenter.

Для простого рукописного ввода вам не нужно беспокоиться о себе с InkPresenter. Однако для настройки и настройки поведения рукописного ввода в InkCanvas необходимо получить доступ к соответствующему объекту InkPresenter.

Базовая настройка с помощью InkPresenter

Объект InkPresenter создается с каждым элементом управления InkCanvas.

Примечание.

Не удается создать экземпляр inkPresenter напрямую. Вместо этого он осуществляется через свойство InkPresenter inkCanvas. 

Помимо предоставления всех действий рукописного ввода по умолчанию соответствующего элемента управления InkCanvas, InkPresenter предоставляет полный набор API для дополнительной настройки штриха и более точного управления входными данными пера (стандартным и измененным). Сюда входят свойства штриха, поддерживаемые типы устройств ввода и обработка входных данных объектом или передаче в приложение для обработки.

Примечание.

Стандартные входные данные рукописного ввода (из кончика пера или кнопки ластика) не изменяются с дополнительным аппаратным обеспечением, например кнопкой пера, правой кнопкой мыши или аналогичным механизмом.

По умолчанию рукописный ввод поддерживается только для ввода пера. Здесь мы настраиваем InkPresenter для интерпретации входных данных из пера и мыши в виде росчерков рукописного ввода. Мы также устанавливаем некоторые начальные атрибуты росчерка рукописного ввода, используемые для отрисовки штрихов в InkCanvas.

Чтобы включить ввод мыши и сенсорного ввода, задайте для свойства InputDeviceTypes inkPresenter сочетание значений CoreInputDeviceTypes, которые требуется.

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);
}

Атрибуты росчерка рукописного ввода можно задать динамически для удовлетворения требований пользователей или приложений.

Здесь мы позволим пользователю выбрать из списка цветов рукописного ввода.

<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>

Затем мы обрабатываем изменения выбранного цвета и обновляем атрибуты росчерка рукописного ввода соответствующим образом.

// 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);
    }
}

На этих изображениях показано, как обрабатывается и настраивается ввод пера inkPresenter.

Снимок экрана: inkCanvas с росчерками чернил по умолчанию.

InkCanvas с черными рукописными росчерками по умолчанию.

Снимок экрана: InkCanvas с выбранными пользователем красными росчерками рукописного ввода.

InkCanvas с выбранными пользователем красными росчерками рукописного ввода.

Чтобы обеспечить функциональные возможности за пределами рукописного ввода и стирания, таких как выбор штриха, приложение должно определить определенные входные данные для InkPresenter для передачи необработанных данных для обработки приложения.

Сквозные входные данные для расширенной обработки

По умолчанию InkPresenter обрабатывает все входные данные как росчерк рукописного ввода или штрих удаления, включая входные данные, измененные дополнительным аппаратным обеспечением, например кнопку пера, правую кнопку мыши или аналогичную. Однако обычно пользователи ожидают некоторые дополнительные функциональные возможности или измененное поведение с этими дополнительными разрешениями.

В некоторых случаях также может потребоваться предоставить дополнительные функции для перьев без дополнительных разрешений (функциональные возможности, которые обычно не связаны с подсказкой пера), другие типы входных устройств или некоторый тип измененного поведения на основе выбора пользователя в пользовательском интерфейсе приложения.

Для поддержки этого можно настроить InkPresenter , чтобы оставить определенные входные данные без обработки. Затем эти необработанные входные данные передаются в приложение для обработки.

Пример. Использование необработанных входных данных для реализации выделения штрихов

Платформа Windows Ink не предоставляет встроенную поддержку действий, требующих измененных входных данных, таких как выбор штриха. Для поддержки таких функций необходимо предоставить пользовательское решение в приложениях.

В следующем примере кода (весь код находится в файле MainPage.xaml и MainPage.xaml.cs файлах), как включить выделение штрихов при изменении входных данных с помощью кнопки "Баррель пера" (или правой кнопки мыши).

  1. Сначала мы настраиваем пользовательский интерфейс в MainPage.xaml.

    Здесь мы добавим холст (под InkCanvas), чтобы нарисовать штрих выделения. Использование отдельного слоя для рисования штриха выделения оставляет InkCanvas и его содержимое нетронуто.

    Снимок экрана: пустой объект InkCanvas с базовым холстом выбора.

      <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>
    
  2. В MainPage.xaml.cs мы объявляем несколько глобальных переменных для хранения ссылок на аспекты пользовательского интерфейса выбора. В частности, фрагмент выделения лассо и ограничивающий прямоугольник, который выделяет выбранные штрихи.

      // Stroke selection tool.
      private Polyline lasso;
      // Stroke selection area.
      private Rect boundingRect;
    
  3. Затем мы настроим InkPresenter для интерпретации входных данных из пера и мыши в виде росчерков рукописного ввода и задайте некоторые начальные атрибуты рукописного штриха, используемые для отрисовки штрихов в InkCanvas.

    Самое главное, мы используем свойство InputProcessingConfiguration inkPresenter, чтобы указать, что любые измененные входные данные должны обрабатываться приложением. Измененные входные данные задаются путем назначения InputProcessingConfiguration.RightDragAction значения InkInputRightDragAction.LeaveUnprocessed. Если это значение задано, inkPresenter передается в класс InkUnprocessedInput, набор событий указателя для обработки.

    Мы назначаем прослушиватели для необработанных событий PointerPressed, PointerMoved и PointerReleased, передаваемых InkPresenter. Все функции выбора реализованы в обработчиках этих событий.

    Наконец, мы назначаем прослушиватели для событий StrokeStarted и StrokesErased inkPresenter. Обработчики этих событий используются для очистки пользовательского интерфейса выбора при запуске нового штриха или удалении существующего штриха.

    Снимок экрана: пример настройки рукописного ввода с изображением рукописных фрагментов по умолчанию с рукописными росчерками по умолчанию.

      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;
      }
    
  4. Затем мы определяем обработчики для необработанных событий PointerPressed, PointerMoved и PointerReleased, передаваемых InkPresenter.

    Все функции выбора реализованы в этих обработчиках, включая штрих лассо и ограничивающий прямоугольник.

    Снимок экрана: выделенный фрагмент.

      // 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();
        }
    
  5. Чтобы завершить обработчик событий PointerReleased, мы очищаем слой выбора всего содержимого (штрих лассо), а затем рисуем один ограничивающий прямоугольник вокруг росчерков рукописного ввода, охватываемых областью лассо.

    Снимок экрана: ограничивающий прямоугольник выделения.

      // 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);
          }
        }
    
  6. Наконец, мы определим обработчики для событий StrokeStarted и StrokesErased InkPresenter.

    Эти оба просто вызывают одну и ту же функцию очистки, чтобы очистить текущий выбор всякий раз при обнаружении нового штриха.

      // 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();
      }
    
  7. Вот функция, чтобы удалить весь пользовательский интерфейс выбора из холста выбора при запуске нового росчерка или существующего штриха удаляется.

      // 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;
        }
      }
    

Настраиваемая отрисовка рукописного ввода

По умолчанию входные данные рукописного ввода обрабатываются в фоновом потоке с низкой задержкой и отображаются во время выполнения или "мокрые", как оно нарисовано. После завершения росчерка (перо или палец снят, или кнопка мыши выпущена), штрих обрабатывается в потоке пользовательского интерфейса и отображается "сухой" на слое InkCanvas (над содержимым приложения и заменой мокрого рукописного ввода).

Это поведение по умолчанию можно переопределить и полностью контролировать процесс рукописного ввода путем "настраиваемой сушки" мокрых росчерков рукописного ввода. Хотя поведение по умолчанию обычно достаточно для большинства приложений, существует несколько случаев, когда может потребоваться настраиваемая сушка, к ним относятся:

  • Более эффективное управление большими или сложными коллекциями рукописных росчерков
  • Более эффективная поддержка сдвига и масштабирования на больших холстах рукописного ввода
  • Переключение рукописного ввода и других объектов, таких как фигуры или текст, при сохранении порядка z
  • Высушивание и преобразование рукописного ввода в фигуру DirectX (например, прямая линия или фигура растеризованы и интегрированы в содержимое приложения вместо отдельного слоя InkCanvas ).

Для пользовательской сушки требуется объект IInkD2DRenderer для управления вводом рукописного ввода и отрисовки его в контексте устройства Direct2D универсального приложения Для Windows вместо элемента управления InkCanvas по умолчанию.

При вызове ActivateCustomDrying (до загрузки InkCanvas) приложение создает объект InkSynchronizer для настройки отрисовки росчерка рукописного ввода в SurfaceImageSource или VirtualSurfaceImageSource.

SurfaceImageSource и VirtualSurfaceImageSource предоставляют общую поверхность DirectX для приложения для рисования и создания в содержимое приложения, хотя VSIS предоставляет виртуальную поверхность, которая больше экрана для выполнения сдвига и масштабирования. Так как визуальные обновления этих поверхностей синхронизированы с потоком пользовательского интерфейса XAML, при отрисовке рукописного ввода в любой из них можно удалить из InkCanvas одновременно.

Вы также можете пользовательский сухой рукописный ввод в swapChainPanel, но синхронизация с потоком пользовательского интерфейса не гарантируется, и может возникнуть задержка между отображением рукописного ввода в БуферChainPanel и удаление рукописного ввода из InkCanvas.

Полный пример этой функции см. в примере сложного рукописного ввода.

Примечание.

Настраиваемая сушка и панель InkToolbar
Если приложение переопределяет поведение отрисовки рукописного ввода по умолчанию для InkPresenter с помощью пользовательской реализации сушки, отрисованные росчерки рукописного ввода больше не доступны для панели InkToolbar, а встроенные команды удаления inkToolbar не работают должным образом. Чтобы обеспечить функциональность удаления, необходимо обрабатывать все события указателя, выполнять тестирование попаданий на каждом штрихе и переопределять встроенную команду "Удалить все рукописные вводы".

Раздел Описание
Распознавание росчерков рукописного ввода Преобразование рукописных росчерков в текст с помощью распознавания рукописного ввода или фигур с помощью пользовательского распознавания.
Хранение и получение росчерков рукописного ввода Храните данные росчерка рукописного ввода в gif-файле с помощью внедренных метаданных сериализованного формата рукописного ввода (ISF).
Добавление inkToolbar в приложение рукописного ввода Windows Добавьте в приложение рукописного ввода по умолчанию inkToolbar по умолчанию, добавьте настраиваемую кнопку пера в панель InkToolbar и привязите настраиваемую кнопку пера к пользовательскому определению пера.

Программные интерфейсы

Примеры

Архивные примеры