Взаимодействие с пером и тактильная обратная связь

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

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

Примечание.

При обращении к этой новой функции в API разработчика и связанной документации используется "хаптик", а "tactile" — понятное имя, представленное пользователям для настройки предпочтений отзывов в параметрах Windows.

Интерфейсы обратной связи Haptic, поддерживаемые в Windows 11, включают обратную связь и отзывы о взаимодействии с рукописными вводами:

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

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

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

Обнаружение входных данных пера

Чтобы обнаружить и изолировать входные данные пера, необходимо сначала зарегистрировать событие Pointer Input, а затем проверить, является ли pointerDeviceType пером.

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


private void InputObserver_PointerEntered(object sender, PointerRoutedEventArgs e)
{
    ...
    
    // If the current Pointer device is not a pen, exit.
    if (e.Pointer.PointerDeviceType != PointerDeviceType.Pen) 
    {
       return;
    }
    
    ...    
}

Определение поддержки хаптиковой обратной связи

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

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

Сначала мы пытаемся получить объект PenDevice из текущего PointerId. Если не удается получить PenDevice, мы просто вернемся из обработчика событий.

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

// Attempt to retrieve the PenDevice from the current PointerId.
penDevice = PenDevice.GetFromPointerId(e.Pointer.PointerId);

// If a PenDevice cannot be retrieved based on the PointerId, it does not support 
// advanced pen features, such as haptic feedback. 
if (penDevice == null)
{
    return;
}

// Check to see if the current PenDevice supports haptic feedback by seeing if it 
// has a SimpleHapticsController.
hapticsController = penDevice.SimpleHapticsController;
if (hapticsController == null)
{
    return;
}

Объект SimpleHapticsController , полученный в предыдущем примере, используется в последующих примерах для запроса хаптических возможностей и отправки и остановки хаптических отзывов.

Примечание.

Если вы создаете приложения с помощью предварительной версии 1.0 пакета SDK для Windows, вы можете использовать взаимодействие PenDevice (PenDeviceInterop.FromPoint(PointerPoint)) для доступа к системе PenDevice.

private void InputObserver_PointerEntered(PointerInputObserver sender, PointerEventArgs args)
{
    var penDevice = PenDeviceInterop.PenDeviceFromPointerPoint(args.CurrentPoint);
}

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

Рукописные формы волн

Рукописные волны постоянно играют, пока перо находится в контакте с экраном, и пытается имитировать ощущение различных инструментов написания или рисования.

Возможность Description Обязательный или необязательный
InkContinous waveform Имитирует ощущение рукописного ввода с помощью физического пера точки мяча. Это резервный вариант по умолчанию, когда волны рукописного ввода не поддерживаются храптовым пером. Обязательное поле
КистьContinuous waveform Непрерывный хаптитический сигнал, когда пользователь выбирает кисть в качестве средства рукописного ввода. Необязательно
ChiselMarkerContinuous waveform Непрерывный хаптитический сигнал, когда пользователь выбирает маркер и выделение чисел в качестве средства рукописного ввода. Необязательно
ЛастикContinuous waveform Непрерывный хаптитический сигнал, когда пользователь выбирает ластик в качестве средства рукописного ввода. Необязательно
ГалактикаContinuous waveform
(Документация и руководство по реализации HID относятся к этой волнообразной форме как SparkleContinuous)
Непрерывный хаптиковый сигнал для специальных рукописных инструментов, таких как многоцветная кисть. Необязательно
МеткаContinuous waveform Непрерывный хаптитический сигнал при выборе маркера в качестве средства рукописного ввода. Необязательно
КарандашНо-волновая форма Непрерывный хаптитический сигнал, когда пользователь выбирает карандаш в качестве инструмента рукописного ввода. Необязательно

Формы волн взаимодействия

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

Возможность Description Обязательный или необязательный
Щелкните форму волны Короткий отзыв "щелкните". Это резервный вариант по умолчанию, когда волны взаимодействия, выбранные приложением, не поддерживаются хаптильной ручкой. Обязательное поле
Форма волны ошибок Сильный сигнал для оповещения пользователя о том, что действие завершилось сбоем или произошла ошибка. Необязательно
Hover waveform Указывает, что пользователь навел указатель мыши на интерактивный элемент пользовательского интерфейса. Необязательно
Пресс-форма волны Указывает, когда пользователь нажимает интерактивный элемент пользовательского интерфейса в добавочном действии (см. раздел "Выпуск"). Необязательно
Форма волны выпуска Указывает, когда пользователь освобождает интерактивный элемент пользовательского интерфейса в добавочном действии (см. прессу). Необязательно
Форма волны успешного выполнения Сильный сигнал, чтобы предупредить пользователя об успешном выполнении действия. Необязательно
BuzzContinuous waveform Непрерывное жужжание ощущение. Необязательно
RumbleContinuous waveform Непрерывное рычание ощущения. Необязательно

Настройки обратной связи Haptic

Некоторые хаптильные ручки могут поддерживать следующие настройки.

Возможность Description Обязательный или необязательный
Интенсивность Задает интенсивность хаптикового сигнала. Необязательно
Количество воспроизведения Повторяет хаптитический сигнал заданного количества раз. Необязательно
Интервал приостановки воспроизведения Задает время между каждым повторяющимся воспроизведением хаптикового сигнала. Необязательно
Длительность воспроизведения Задает интервал времени воспроизведения хаптитического сигнала. Необязательно

Проверка поддержки пользовательских параметров

Чтобы проверить интенсивность, количество воспроизведения, интервал приостановки воспроизведения и поддержку длительности воспроизведения, используйте следующие свойства SimpleHapticsController:

Отправка и остановка рукописного ввода отзывов

Используйте метод SendHapticFeedback объекта SimpleHapticsController, чтобы передать рукописные волны в перо пользователя. Этот метод поддерживает передачу в виде волны или как волнообразной формы с настраиваемым значением интенсивности (см. раздел "Настройка хаптической обратной связи").

Вызов SendHapticFeedback и передайте в рукописную форму , чтобы настроить перо, чтобы начать воспроизведение этой волнообразной формы, как только кончик пера касается в любом месте экрана. Форма волны будет продолжать играть, пока перо не будет снято или StopFeedback вызывается, в зависимости от того, что происходит сначала. Мы рекомендуем выполнить это в обработчике событий PointerEntered для элемента, в котором требуется воспроизвести хиплиты. Например, приложение с пользовательской реализацией рукописного ввода сделает это в методе Pointer Ввод на холсте рукописного ввода.

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

Если он не поддерживается, вы можете либо не играть ничего вообще, либо вернуться к форме волн InkContinible, так как это гарантированно будет поддерживаться.

В следующем примере мы пытаемся отправить кистьContinuous waveform (но вернуться к InkContinuous, если BrushContinuous не поддерживается).

SimpleHapticsControllerFeedback currentWaveform;

// Attempt to set the currentWaveform to BrushContinuous.
foreach (var waveform in hapticsController.SupportedFeedback)
{
    if (waveform.Waveform == KnownSimpleHapticsControllerWaveforms.BrushContinuous)
    {
        currentWaveform = waveform;
    }
} 

// If currentWaveform is null, it was not in the SupportedFeedback collection, so instead set 
// the waveform to InkContinuous.
if (currentWaveform == null)
{
    foreach (var waveform in hapticsController.SupportedFeedback)
    {
        if (waveform.Waveform == KnownSimpleHapticsControllerWaveforms.InkContinuous)
        {
            currentWaveform = waveform;
        }
    }
}

// Send the currentWaveform 
hapticsController.SendHapticFeedback(currentWaveform);

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

Примечание.

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

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

hapticsController.StopFeedback();

Отправка и остановка обратной связи о взаимодействии

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

Используйте метод SendHapticFeedback объекта SimpleHapticsController для передачи волновых форм взаимодействия перу пользователя. Этот метод поддерживает передачу в виде волны или как волнообразной формы с настраиваемым значением интенсивности (см. раздел "Настройка хаптической обратной связи").

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

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

Примечание.

Отправка волны взаимодействия при воспроизведении волны рукописного ввода временно прерывает вилку волнообразной формы. Форма волны рукописного ввода возобновляется при остановке волны взаимодействия.

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

Если он не поддерживается, вы можете либо не играть ничего вообще, либо вернуться к волнообразной форме Click , так как это гарантированно поддерживается.

В следующем примере мы пытаемся отправить волны ошибки (но вернуться к щелчку, если ошибка не поддерживается).

SimpleHapticsControllerFeedback currentWaveform;  

// Attempt to set the currentWaveform to BrushContinuous.
foreach (var waveform in hapticsController.SupportedFeedback)
{
    if (waveform.Waveform == KnownSimpleHapticsControllerWaveforms.Error)
    {
        currentWaveform = waveform;
    }
} 

// If currentWaveform is null, it was not in the SupportedFeedback collection, so instead set 
// the waveform to Click.
if (currentWaveform == null)
{
    foreach (var waveform in hapticsController.SupportedFeedback)
    {
        if (waveform.Waveform == KnownSimpleHapticsControllerWaveforms.Click)
        {
            currentWaveform = waveform;
        }
    }
} 

// Send the currentWaveform.
hapticsController.SendHapticFeedback(currentWaveform); 

Настройка хаптильной обратной связи

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

  1. Настройте интенсивность обратной связи относительно максимального параметра интенсивности системы. Для этого необходимо сначала проверить, поддерживает ли SimpleHapticsController настройку интенсивности, а затем вызвать SendHapticFeedback с требуемым Intensity значением.

    if (hapticsController.IsIntensitySupported) 
    {
        foreach (var waveform in hapticsController.SupportedFeedback)
        {
            if (waveform.Waveform == KnownSimpleHapticsControllerWaveforms.Click)
            {
                double intensity = 0.75;
                hapticsController.SendHapticFeedback(waveform, intensity);
            }
        }
    }
    
  2. Повторите хаптитический сигнал заданное количество раз. Для этого необходимо сначала проверить, поддерживает ли SimpleHapticsController настройку интенсивности, а затем вызвать SendHapticFeedbackForPlayCount с нужным значением счетчика. Можно также задать как интенсивность, так и интервал приостановки воспроизведения.

    Примечание.

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

    if (hapticsController.IsPlayCountSupported && hapticsController.IsIntensitySupported && hapticsController.IsReplayPauseIntervalSupported)
    {
        foreach (var waveform in hapticsController.SupportedFeedback)
        {
            if (waveform.Waveform == KnownSimpleHapticsControllerWaveforms.Click)
            {
                double intensity = 0.75;
                int playCount = 3;
                System.TimeSpan pauseDuration = new System.TimeSpan(1000000);
                hapticsController.SendHapticFeedbackForPlayCount(currentWaveform, intensity, playCount, pauseDuration);
            }
        }
    }
    
  3. Задайте длительность хапетного сигнала. Для этого необходимо сначала проверить, что SimpleHapticsController поддерживает настройку длительности воспроизведения, а затем вызовите SendHapticFeedbackForDuration с требуемым значением интервала времени. Вы также можете задать интенсивность.

    Примечание.

    Если SimpleHapticsController не поддерживает настройку интенсивности, указанное значение будет игнорироваться.

    if (hapticsController.IsPlayDurationSupported && hapticsController.IsIntensitySupported)
    {
        foreach (var waveform in hapticsController.SupportedFeedback)
        {
            if (waveform.Waveform == KnownSimpleHapticsControllerWaveforms.RumbleContinuous)
            {
                double intensity = 0.75;
                System.TimeSpan playDuration = new System.TimeSpan(5000000);
                hapticsController.SendHapticFeedbackForDuration(currentWaveform, intensity, playDuration);
            }
        }
    }
    

Примеры

Ознакомьтесь с примером хаптиков пера для рабочих примеров следующих функций: