Пользовательский интерфейс приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript

Многоточечные жесты

Разбить на страницы
Показывать лекцию целиком

Когда объект MSGesture получает несколько указателей через свое событиет addPointer, он так же запускает события MSGestureStart, MSGestureChange, MSGestureEnd для жестов поворота и масштабирования, вместе с событием MSInertiaStart. В подобных случаях свойства scale, rotation, velocityAngular, expansion, и velocityExpansion в объекте eventArgs приобретают смысл.

Вы можете выборочно просматривать эти свойства для событий MSGestureChange посредством выпадающего списка, который расположен в правом верхнем углу, в упражнении PointerEvents. Вы можете заметить, что, когда вы выполняете многоточечные жесты в имитаторе Visual Studio, вы никогда не видите событие MSGestureTap для отдельных точек касания. Это происходит потому, что распознаватель жестов может видеть подобные множественные события MSPointerDown, которые происходят почти одновременно (здесь играет роль свойство hwTimestamp) и тут же объединяет их в одно событие MSGestureStart (например, начинает жест масштабирования или вращения).

Теперь я уверен, что вы готовы задать несколько важных вопросов. До сих пор я говорил о сенсорных жестах изменения масштаба и вращения, о жестах переноса, как о рахных вещах, но как, на самом деле, различать их, если все они поступют в приложение посредством одного и того же события MSGestureChange? Разве это не запутывает все? Какова стратегия для работы с жестами переноса, вращения и масштабирования?

Хорошо, ответ заключается в том, что вам не нужно их разделять! Что, если вы подумаете немного о том, как вы обрабатываете события MSGestureChange и данные, которые каждое из них содержит в зависимости от вида манипуляции, который вы поддерживаете в пользовательском интерфейсе:

  • Если вы поддерживаете лишь перенос элемента (translation), вы просто никогда не обращаете внимание на свойства наподобие scale и rotation и применяете только необходимые, такие, как translationX и translationY. Это было бы ожидаемым поведением при выборе элемента в элементе управления коллекцией, например (или в элементе управления, который позволяет манипулировать элементами по технологии "перетащить и опустить", меняя порядок их расположения).
  • Если вы поддерживаете лишь изменение масштаба (scale), вы игнорируете все свойства, которые имеют отношение к позиционированию и работаете со свойствами scale, expansion, и/или со свойством velocityExpansion. Это будет тем поведением, которое вы хотите реализовать для элемента управления, который поддерживает оптическое или семантическое масштабирование.
  • Если вас интересует лишь вращение (rotation), то ваши друзья – это свойства rotation и velocityAngular.
  • Конечно, если вы хотите поддерживать несколько видов манипуляций, вы можете просто реализовать обработку всех этих свойств, передавая их, например в CSS-трансформацию. Подобное может быть применимо к приложениям, которые реализуют различные манипуляции для экранных объектов, и именно этому посвящен один из примеров Windows SDK, рассматривающий жесты.

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

    В то время, как упражнение PointerEvents, включенное в эту лекцию, давало нам низкоуровневый вид событий указателей и жестов, для приложений по-настоящему важно то, как применять эти события для реальной манипуляции экранными объектами, что является реализацией частей языка касаний, такими, как жесты сжатия/растяжения и вращения. Для того, чтобы увидеть это, мы можем обратиться к примеру "Ввод: жесты, допускающие создание экземпляров" (http://code.msdn.microsoft.com/windowsapps/Input-Instantiable-deda69ca).

    Этот пример, в основном, показывает, как использовать события жестов одновременно с несколькими элементами. В Сценарии 1 и 2, приложение реализует простой пример головоломки, как упоминалось выше. Каждым закрашенным прямоугольником можно управлять по отдельности, используя перетаскивание для перемещения (с инерцией и без), жест сжатия-растяжения для изменения масштаба, и жест вращения для вращения, как показано на рис. 4.1. (рис 4.1) Пример "Ввод: жесты, допускающие создание экземпляров" после того, как с ним немного поработали. Словосочетание "допускающие создание экземпляров" (instantiable) использовано потому, что нам нужно создать экземпляр (instance) объекта MSGesture для приема событий жестов

    В Сценарии 1 (js/instantiableGesture.js) объект MSGesture создается для кажого экранного элемента вместе с еще одним для черного фона, "стола" при инициализации (в функции initialize). Мы уже видели подобное. Похожим бразом, обработчик MSPointerDown (onPointerDown) добавляет указатели к объектам жестов для каждого элемента, уделяя немного больше внимания обработке их положения по оси Z. Это предовращает одновременные касания, указатели мыши и пера работают с тем же самым элементом (что было бы странно!):

    function onPointerDown(e) {
    if (e.target.gesture.pointerType === null) {  
     // Первый контакт e.target.gesture.addPointer(e.pointerId); 
     // Присоединение указателя к элементу
    e.target.gesture.pointerType = e.pointerType;
    }
    else if (e.target.gesture.pointerType === e.pointerType) 
    { // Контакты сходного типа e.target.gesture.addPointer(e.pointerId);         
       // Присоединение указателя к элементу
    }
    
    // ZIndex изменяется при опускании указателя. 
    // Элемент, на который опустился указатель, становится самым верхним 
    var zOrderCurr = e.target.style.zIndex;
    var elts = document.getElementsByClassName("GestureElement");
    for (var i = 0; i < elts.length; i++) {
    if (elts[i].style.zIndex === 3) {
    elts[i].style.zIndex = zOrderCurr;
    }
    e.target.style.zIndex = 3;
    }
    }
     

    Обработчик MSGestureChange выполняется для каждого отдельного фрагмента (onGestureChange), затем собирает все данные по переносу, вращению, масштабированию в объекте eventArgs и применяет их с помощью CSS. Это показывает, как удобно то, что все эти свойства уже описаны в нужной нам системе координат:

    function onGestureChange(e) {
    var elt = e.target;
    var m = new MSCSSMatrix(elt.style.msTransform);
    
     elt.style.msTransform = m.	
    translate(e.offsetX, e.offsetY).	
    translate(e.translationX, e.translationY).
    rotate(e.rotation * 180 / Math.PI).	
    scale(e.scale).	
    translate(-e.offsetX, -e.offsetY);	
    }	
     

    В коде примера выполняется немного больше всего, но то, что мы показали здесь – это самые важные части. Очевидно, если вам не нужна поддержка манипуляций определенного вида, вы можете просто игнорировать определенные свойства в объекте eventArgs.

    Сценарий 2 этого примера формирует такое же изображение, но он реализован несколько иначе. Как вы можете видеть, в его функции initialize (js/gesture.js), изначально регистрируется лишь одно событие, применяющееся к "столу", который имеет черный фон и окружающую его границу.

    Объекты жестов для отдельных фрагментов головоломки создаются и прикрепляются к указателям в событии MSPointerDown (onTableTopPointerDown). Этот подход более эффективен и масштабируем для приложения-головоломки, которое может иметь сотни или даже тысячи фрагментов, так как объекты жестов хранятся лишь до тех пор, пока осуществляется манипуляция конкретным фрагментом. Эти манипуляции так же похожи на те, что были в Сценарии 1, где свойства MSGestureChange применялись посредством CSS-трансформаций. Для того чтобы узнать подробности, обратитесь к комментариям к коду в js/gesture.js, так как они весьма обширны.

    Сценарий 3 этого примера предоставляет еще одну демонстрацию выполнения жестов переноса, сжатия-расширения и вращения с использованием колеса мыши. Как показано в упражнении PointerEvents, единственное, что нужно для того, чтобы сделать это – это обработать событие wheel, установить eventArgs.pointerId в 1 и передать это в обработчик MSPointerDown, который затем добавит указатель к объекту жеста:

     function onMouseWheel(e) {
    e.pointerId = 1; // Фиксированный pointerId для MouseWheel
    onPointerDown(e);	
    }	
     

    Опять же, это все, что нужно. (Мне нравится, когда все так просто!). В качестве упражнения, вы можете попытаться добавить этот код в Сценарии 1 и 2.

    Средство распознавания жестов

    В случае с инерционными жестами, которые продолжают посылать некоторое количество событий MSGestureChange, когда указатель освобожден, вы можете задаться вопросами: "А что, на самом деле, управляет этими событиями? Очевидно, существует особая модель уменьшения скорости, встроенная в эти события, а именно та, на основе которой построены внешний вид и впечатления от взаимодействия с Windows. Но что, если мне нужно другое поведение? И что, если я хочу совсем иначе интерпретировать события указателя?"

    Вспомогательный механизм, который интерпретирует события указателя, превращая их в жесты, называется средством распознавания жестов (gesture recognizer). Его вы можете получить напрямую посредством объекта ). После создания экземпляра этого объекта с помощью команды ) для тех видов манипуляций и жестов, которые вам интересны. Документация по Windows.UI.Input.GestureSettings предоставляет полный набор возможностей, в том числе, такие жесты, как ) (ballineight.js) мы можем видеть, как настраивают средство распознавания жестов для жестов касания (tap), вращения (rotate), переноса (translate) и масштабирования (scale) (с инерцией):

     gr = new Windows.UI.Input.GestureRecognizer();
    
    // Настройка GestureRecognizer для определения манипуляций вращения, переноса, масштабирования,
    // с инерцией для данных трех компонентов манипуляции и обработки касания
    gr.gestureSettings =
    Windows.UI.Input.GestureSettings.manipulationRotate |
    Windows.UI.Input.GestureSettings.manipulationTranslateX | Windows.UI.Input.GestureSettings.manipulationTranslateY | 
    Windows.UI.Input.GestureSettings.manipulationScale | 
    Windows.UI.Input.GestureSettings.manipulationRotateInertia | Windows.UI.Input.GestureSettings.manipulationScaleInertia | 
    Windows.UI.Input.GestureSettings.manipulationTranslateInertia |
    Windows.UI.Input.GestureSettings.tap;
    
    // Выключение обратной связи пользовательского интерфейса для жестов 
    // (обратная связь все еще используется для PointerPoints)
    gr.showGestureFeedback = false;
    

    Объект GestureRecognizer так же имеет множество свойств для настройки его специфических событий. Например, для жестов скольжения по диагонали (cross-slides) вы можете задать свойства crossSlideThresholds, crossSlideExact, и crossSlideHorizontally. Вы можете задать быстроту снижения скорости (в пикселях/мс2) посредством свойств inertiaExpansionDeceleration, inertiaRotationDeceleration, и inertiaTranslationDeceleration.

    После настройки, вы начинаете передавать событий MSPointer* к объекту средсва распознавания жестов, в частности, его методам, которые называются processDownEvent, processMoveEvents, и processUpEvent (так же, если нужно, processMouseWheelEvent, и processInertia). В ответ, в зависимости от конфигурации, средство распознавания жестов запустит некоторое количество собственных событий. Во-первых, это дискретные события, наподобие crossSliding, dragging, holding, rightTapped, и tapped. Для остальных он запустит серию событий manipuationStarted, manipulationUpdated, manipulationInertiaStarting, и manipulationCompleted. Обратите внимание на то, что все эти события исходят из WinRT, поэтому убедитесь, что вызвали, когда нужно, removeEventListener.

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

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

    var recognizer = new Windows.UI.Input.GestureRecognizer();
    recognizer.gestureSettings = Windows.UI.Input.GestureSettings.manipulationTranslateX;
    var DELTA = 10;
    
    myElement.addEventListener('MSPointerDown', function (e) {
    recognizer.processDownEvent(e.getCurrentPoint(e.pointerId));
    });
    myElement.addEventListener('MSPointerUp', function (e) {
    recognizer.processUpEvent(e.getCurrentPoint(e.pointerId));
    });
    myElement.addEventListener('MSPointerMove', function (e) {
    recognizer.processMoveEvents(e.getIntermediatePoints(e.pointerId));
    });
    
    // Помните, что при работе с этими событиями нужен removeEventListener 
    recognizer.addEventListener('manipulationcompleted', function (args) {
    var pt = args.cumulative.translation;
    if (pt.x < -DELTA) {
    // переместить вправо
    }
    else if (pt.x > DELTA) {
    // переместить влево
    }
    });
     

    Помимо использования средства распознавания жестов, помните, что вы всегда можете перейти на более низкий уровень и выполнить собственную обработку событий MSPointer* , если вам это нужно, и, таким образом, полностью обойти средство распознавания жестов. Это может быть нужно, если конфигурации, допустимые в средстве распознавания жестов, не соответствуют вашим особенным нуждам. В то же время, сейчас неплохая возможность для того, чтобы перечитать врезку "Создание совершенно новых жестов?" в конце раздела о языке касаний. Она посвящена некоторым вопросам о том, когда действительно нужны пользовательские жесты.

    Ввод данных с клавиатуры и программная клавиатура

    После всего, что мы узнали о сенсорном вводе данных и о других способах ввода, может показаться, что рассмотрение скромной клавиатуры нас разочарует. Но, все же, клавиатура остается крайне важной для ввода текста, будь это физическая клавиатура или экранная "программная" клавиатура. Она особенно важна для обеспечения специальных возможностей, так как некоторые пользователи физически не могут использовать мышь или другие устройства. На самом деле, раздел 3.5. "Сертификационных требований к приложениям для Windows 8" (http://msdn.microsoft.com/library/windows/apps/hh694083.aspx) говорит об обязательной поддержке приложениями ввода с клавиатуры.

    К счастью, в приложениях для Магазина Windows нет ничего особенного в обработке ввода с клавиатуры, но длинный путь можно пройти короткими шагами. Вот общие положения, взятые из материала "Реализация специальных возможностей клавиатуры" (http://msdn.microsoft.com/library/windows/apps/hh700327.aspx):

  • Обрабатывайте события keydown, keyup и keypress так, как вы уже знаете, особенно для реализации специальных сочетаний клавиш. Смотрите раздел "Стандартные сочетания клавиш" далее в этом разделе для того, чтобы взглянуть на типичные сопоставления команд.
  • Задавайте атрибут tabindex интерактивным элементам, которые должны поддерживать возможность переключения на них с помощью клавиши табуляции. Старайтесь не добавлять tabindex к неинтерактивным элементам, так как это может помешать программам чтения с экрана.
  • Задавайте атрибут accesskey для тех элементов, которым следует иметь клавиатурные сокращения.
  • Вызывайте DOM API для задания фокуса для элементов, которые должны быть элементами по умолчанию
  • Используйте преимущества клавиатурных сокращений, которые уже присутствуют во встроенных элементах управления, в таких, как панель приложения.
  • В приложении "Here My Am!", над которым мы работаем в этом курсе, обновленный вариант которого содержится в дополнительных материалах к этой лекции, добавлена полная поддержка клавиатуры. Это, в основном, коснулось добавления ) для сравнения кодов клавиш:

    var Key = WinJS.Utilities.Key;
    var image = document.getElementById("photo");
    
    image.addEventListener("keydown", function (e) {	
    if (e.keyCode == Key.enter || e.keyCode==Key.space) {
    image.click();	
    }	
    });	
     

    Все это работает и для физической клавиатуры, и для программной. Дело закрыто? Не вполне. Есть две особенности, касающиеся экранной клавиатуры: первая – это как показать ее, вторая – как ее появление подействует на макет приложения. В конце этого раздела мы так же взглянем на стандартные клавиатурные сокращения для команд приложения.

    Показ программной клавиатуры происходит по одной и только одной причине: пользователь касается элемента управления для ввода текста с атрибутом contenteditable="true" (такого, как div или canvas). Нет API, которое отображает клавиатуру, она не появляется и тогда, когда вы щелкаете по подобному элементу управления мышью или пером, или перемещаетесь к нему, нажимая клавишу табуляции на физической клавиатуры.

    Конфигурация клавиатуры зависит от типа элемента управления для ввода текста. Мы можем увидеть это в Сценарии 2 примера "Ввод: сенсорная клавиатура для ввода текста" (http://code.msdn.microsoft.com/windowsapps/Input-Touch-keyboard-text-f86e9bd9), где в файле html/ScopedView.html содержится несколько элементов управления input (окружающая разметка опущена), которые выглядят так, как показано на рис. 4.2.

     <input type="url" name="url" id="url" size="50" />	
    <input type="email" name="email" id="email" size="50" />	
    <input type="password" name="password" id="password" size="50" />
    <input type="text" name="text" id="text" size="50" />	
    <input type="number" name="number" id="number" />	
    <input type="search" name="search" id="search" size="50" />	
    <input type="tel" name="tel" id="tel" size="50" />	
    

    (рис 4.2) Программная клавиатура появляется, когда вы касаетесь поля ввода, как показано в примере

    То, что показано на рис. 4.2. – это клавиатура по умолчанию. Если вы прикоснетесь к полю Search (Поиск), вы получите практически то же самое, за исключением того, что клавиша Enter превратится в клавишу Search (Поиск). Для поля Email клавиатура тоже похожа на стандартную, за исключением того, что появятся кнопки @ и .com у клавиши пробела:

    Клавиатура для ввода URL выглядит так же, но клавиши @ нет, а Enter превращается в Go (Перейти):

    Для поля ввода пароля на клавиатуре появляется клавиша Hide keypresses (Скрыть нажатия клавиш), которая отключает видимую анимацию нажатий клавиш – очень полезная функция, если вы записываете видео!

    И, наконец, поля Number (Число) и Telephone (Телефон) вызывают клавиатуру, ориентированную на ввод чисел:

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

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

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

    Так же клавиатура настроаивает свой внешний вид при работе с элементами управления для ввода текста для предоставления подсказок и выделения появляющейся кнопки Insert (Вставить). Это показано в Сценарии 1 примера:

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

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

    Когда появляется программная клавиатура или панель для ввода рукописного текста, система пытается убедиться в том, что поле ввода видимо, прокручивая содержимое, если это возможно. Это значает просто установку отрицательного вертикального смещения для всей вашей страницы в соответствии с высотой программной клавиатуры. Например, если я добавлю (в качестве радикального решения!) кучу элементов </br> в верхнюю часть страницы html/ScopedView.html в примере, так, чтобы элементы управления для ввода текста оказались внизу страницы, и затем коснусь одного из них, вся страница сдвинется вверх, как показано на рис. 4.3.: (рис 4.3) Когда появляется программная клавиатура, Windows автоматически смещает страницу приложения вверх для того, чтобы поле ввода не оказалось перекрытым

    Хотя такой подход может быть самым простым решением этой задачи, он не всегда идеален. К счастью, вы можете сделать кое-что более интеллектуальное, если хотите, прослушивая события ) и непосредственно подстраивая макет. Код для того, чтобы это сделать, можно найти (вы готовы к этому?) в примере "Реагирование на отображение экранной клавиатуры" (http://code.msdn.microsoft.com/windowsapps/Keyboard-Events-Sample-866ba41c) И пока вы думаете, что это второе самое длинное название JavaScript-примера в Windows SDK, оно, на самом деле, может получить лишь бронзовую медаль. Пример "Невыделяемые области содержимого с CSS-атрибутом –ms-user-select" (http://code.msdn.microsoft.com/windowsapps/Unselectable-content-areas-963eccd9), который мы уже видели, получает золото, а пример "Использование requestAnimationFrame для анимации, эффективно расходующей электроэнергию" (http://code.msdn.microsoft.com/windowsapps/Using-requestAnimationFrame-924b039a) получает серебро. Однако, я не против таких длинных названий – я очень доволен тем, что у нас есть столь обширный набор отличных примеров, из которых мы можем взять много полезного!. К этим событиям очень просто добавить прослушиватели (смотрите в нижней части в js/keyboardPage.js, который, так же, соответствующим образом удаляет прослушиватели):

    var inputPane = Windows.UI.ViewManagement.InputPane.getForCurrentView();
     inputPane.addEventListener("showing", showingHandler, false); 
    inputPane.addEventListener("hiding", hidingHandler, false);
     

    В обработчике события showing объект eventArgs.occludedRect (имеющий тип Windows.Foundation.Rect) дает вам координаты и размеры обрасти, которую перекроет экранная клавиатура. В ответ на это мы можете настроить любые необходимые параметры макета и установить свойство eventArgs.ensuredFocusedElementInView в true. Это сообщит Windows, что автоматический сдвиг выполнять не нужно:

    function showingHandler(e) {
    if (document.activeElement.id === "customHandling") {
    keyboardShowing(e.occludedRect);
    
    // Будьте осторожны с этим свойством. Как только оно установлено, система 
    // не будет делать ничего для того, чтобы элемент, имеющий фокус, был видимым.	
    e.ensuredFocusedElementInView = true;	
    }	
    }	
     

    В примере показаны оба случая. Если вы коснетесь расположенного в нижней левой части приложения элемента defaultHandling, который имеет цвет морской волны, как показано на рис. 4.4, его showingHandler ничего не будет делать, и мы увидим поведение по умолчанию (рис 4.4) Прикосновение к левому элементу defaultHandling в нижней части приведет к стандартному поведению при появлении клавиатуры, при котором содержимое страницы сдвигается вертикально

    Если вы коснетесь элемента customHandling (справа), он вызовет функцию keyboardShowing для настройки макета:

    function keyboardShowing(keyboardRect) {
    // Часть кода опущена...
    var elementToAnimate = document.getElementById("middleContainer");
    var elementToResize = document.getElementById("appView");
    var elementToScroll = document.getElementById("middleList");
    
    // Записываем расстояние перемещения. Это упрощает расчеты 
    displacement = keyboardRect.height;
    var displacementString = -displacement + "px";
    
    // Находим последний видимый элемент в списке
    var bottomOfList = elementToScroll.scrollTop + elementToScroll.clientHeight;
    
    // Анимируем
    showingAnimation = KeyboardEventsSample.Animations.inputPaneShowing(elementToAnimate,
    { top: displacementString, left: "0px" }).then(function () {
    
    // После анимации макет занимает меньшее окно просмотра над клавиатурой
    elementToResize.style.height = keyboardRect.y + "px";
    
    // Прокручиваем список в нужное место, так чтобы прокрутка не была заметна
    elementToScroll.scrollTop = bottomOfList - elementToScroll.clientHeight;	
    showingAnimation = null;	
    });
    }	
     

    Этот код немного сложный, так как он анимирует перемещение различных элементов страницы. В результате макет задействованных элементов, а именно, того, к которому вы прикоснулись – подстраивается для того, чтобы дать место для клавиатуры. Другие элементы на странице, в противном случае, не затрагиваются. Результат показан на рис. 4.5. (рис 4.5) Прикосновение к серому элементу customHandling справа демонстрирует пользовательскую обработку отображения клавиатуры

    Стандартные сочетания клавиш

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

    Действие или команда Сочетание клавиш
    Перемещение фокуса Tab
    Назад (Навигация) Кнопка "Назад" на специальных клавиатурах; клавиша backspace , везде, кроме текстовых полей; Alt+стрелка влево
    Вперед (Навигация) Alt+стрелка вправо
    Вверх Alt+стрелка вверх
    Отмена/Выход из режима ESC
    Перемещение по элементам в списке Клавиши-стрелки (и Tab)
    Быстрое по элементам списка к соедующей группе, если выделение не следует автоматически за фокусом Ctrl+клавиши-стрелки
    Масштабирование (семантическое и оптическое) Ctrl+"+" b Ctrl+ "-"
    Быстрое перемещение к именованному элементу коллекции Начало ввода текста
    Перемещение на большое расстояние Page up/down ( должно работать в пользовательском интерфейсе, поддерживающем сдвиг в горизонтальном и вертикальном направлениях)
    Следующая позиция табуляции или группа Ctrl+Tab
    Предыдущая позиция табуляции или группа Ctrl+Shift+Tab
    N-ная позиция табуляции или группа Ctrl+N (1-9)
    Открыть панель приложения (Windows обрабатывает это автоматически) Win+Z
    Контектстное меню Клавиша контекстного меню
    Открыть дополнительную панель/выбрать элемент меню Enter
    Перейти куда-либо/активировать Enter (в выделении)
    Выбрать Пробел
    Выбрать смежные элементы Shift+клавиши-стрелки
    Закрепить элемент Ctrl+Shift+!
    Сохранить Ctrl+S
    Поиск Ctrl+F
    Печать Ctrl+P (вызывает Windows.Graphics.Printing.PrintManager.showPrintUIAsync)
    Копировать Ctrl+C
    Вырезать Ctrl+X
    Вставить Ctrl+V
    Новый элемент Ctrl+N
    Открыть адрес Ctrl+L или Alt+D
    Вращение Ctrl+"," и Ctrl+"."
    Проигрывание/Пауза Ctrl+P (только медиа-приложения)
    Следующий элемент Ctrl+F (конфликтует с Поиском)
    Предыдущий элемент Ctrl+B
    Перемотка назад Ctrl+Shift+B
    Перемотка вперед Ctrl+Shift+F

    Рукописный ввод

    Помимо встроенной программной клавиатуры и панели для рукописного ввода, приложениям может понадобиться предоставить пользователю поверхность, которая может непосредственно принимать данные указателя в виде рукописного ввода (ink). Под этим я подразумеваю больше, чем использование элемента canvas и обработку событий MSPointer для рисования или создания растровых изображений. Рукописные штрихи – это структура данных, которая поддерживает реально вводимую информацию (в том числе – сведения о нажиме, угле наклона сенсора, скорости, если аппаратное обеспечение это поддерживает), что позволяет выполнять распознавание рукописного ввода и другие виды высокоуровневой обработки информации, которые невозможны при работе с растровыми данными. Работа с рукописным вводом, другими словами, напоминае работу с процессом рисования изображения, а не работу с готовым изображением, и это возможно для всех типов указателей ввода.

    Поддержка рукописного ввода в WinRT располагается в пространстве имен ). Это API не зависит от конкретного презентационного фреймворка, не предоставляет она и средств визуализации: она имеет дело лишь с управлением структурами данных, которые приложение может вывести самостятельно, на поверхности для рисования наподобие canvas. Вот базовые функции этого API:

  • Создание экземпляра управляющего объекта с помощью команды new Windows.UI.Input.Inking.InkManager().
  • Назначение атрибутов рисования путем создания объекта Windows.UI.Input.Inking.InkDrawingAttributes и установки атрибутов штриха, таких, как color, fitToCurve (в противоположность прямым линиям, проводимым по умолчанию), ignorePressure, penTip (Windows.UI.Input.Inking.PenTipShape.circle или rectangle), и size (объект Windows.Foundation.Size со свойствами height и width).
  • Для элементов ввода, прослушивание событий MSPointerDown, MSPointerMove, и MSPointerUp, которые обычно нужны для целей визуализации. eventArgs.currentPoint это объект Windows.UI.Input.PointerPoint, который содержит идентификатор указателя, координаты точки и свойства наподобие pressure, tilt, и twist.
  • Передача объекта PointerPoint методам управляющего объекта processPointerDown, processPointerUpdate, и processPointerUp.
  • После события processPointerUp, управляющий объект рукописного ввода создает объект Windows.UI.Input.Inking.InkStroke для проведенного штриха. Штрихи можно получить посредством метода getStrokes управляющего объекта и вывести так, как нужно.
  • Жесты высокого уровня могут быть непосредственно конвертированы в объекты InkStroke и переданы управляющему объекту посредством метода addStroke. Объекты штрихов можно удалять с использованием метода deleteStroke.
  • Управляющий объект, кроме того, предоставляет методы для распознавания рукописного текста на основе содержащихся в нем штрихов, сохранения и загрузки данных и обработки различных режимов, таких, как рисование и стирание штрихов. Полную демонстрацию этого вы можете найти в примере "Ввод: рукописный ввод" (http://code.msdn.microsoft.com/windowsapps/Ink-App-sample-61abaec3), который показан на рис. 4.6. Этот пример позволит вам увидеть полный набор возможностей платформы рукописного ввода, в том числе – распознавание рукописного текста. (рис 4.6) Пример работы с платформой рукописного ввода содержит множество команд на панели приложения. Зеленый текст "Hello" в верхнем левом углу был создан после выделения рукописного "Hello" и использования команды Recognition (Распознавание)

    SDK так же включает в себя пример "Ввод: упрощенный рукописный ввод" (http://code.msdn.microsoft.com/windowsapps/Input-simplified-ink-sample-11614bbf) для демонстрации сценария, ориентированного на распознавание рукописного текста, как показано на рис. 4.7. Вам следует знать, что это пример, который вовсе не поддерживает касания – он ограничен мышью и пером и использует для активации команд клавиатурные сокращения вместо панели приложения. Взгляните на функцию keydown в файле simpleink.js для того, чтобы увидеть список команд вида "Ctrl + другая клавиша". Клавиша пробел активирует распознавание введенного текста, клавиша backspace очищает рабочую область. Как вы можете видеть на рисунке, я могу думать, что распознавание рукописного текста работает очень хорошо! (Это говорит мне о том, что образцы рукописного текста, которые я передал команде инженеров Microsoft где-то в середине 1990-х, стали значительным вкладом в их дело). (рис 4.7) Пример отлично распознает мой небрежный текст, написанный мышью

    Географическое расположение

    Прежде чем мы рассмотрим датчики в целом, я хочу отдельно рассмотреть возможности определения географического расположения в приложениях для Магазина Windows, так как это API устроено не так, как у других датчиков. Мы уже использовали эту возможность, начиная с Главы 2 курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript", в приложении "Here My Am!", но нам нужен более полной обзор этой крайне полезной возможности.

    В отличие от других датчиков, только определение местоположения имеет выделенную возможность, которую вы должны объявить в манифесте. То, где вы находитесь на Земле, это абсолютные данные, которые являются частью личной информации. Таким образом, пользователи должны дать согласие, прежде чем приложение сможет получить эти сведения, и ваше приложение так же должно предоставлять "Соглашение о конфиденциальности" в Магазине Windows. Другие датчики, в отличие от этого, предоставляют относительную информацию – вы не можете, например, узнать что-либо о человеке из данных о наклоне устройства, о его перемещении или из сведений о том, насколько яркий свет его освещает. Соответственно, вы можете использовать другие датчики без объявления каких-либо особых возможностей.

    Как вы можете знать, данные о географическом местоположении могут быть получены двумя различными путями. Первый, и наиболее точный, конечно, это получение данных с GPS-приемника, который получает информацию от геостационарных спутников, расположенных на орбитах в несколько сотен миль. Другим, достаточно полезным, хотя и не всегда точным средством является попытка узнать местоположение на основе IP-адреса проводного сетевого соединения или триангуляция на основе расположения доступных точек доступа WiFi. В любом случае, WinRT делает все возможное для того, чтобы дать вам достойные показатели.

    Для доступа к данным о географическом местоположении, вы должны сначала создать экземпляр средства определения местоположения WinRT, ). Когда он у вас есть, вы затем можете вызвать его метод getGeopositionAsync, результаты работы которого (помещенные в обработчик завершения), представляют собой объект типа Geoposition (в том же пространстве имен Windows.Devices.Geolocation, если не указано иное). Вот код из "Here My Am!":

    var gl = new Windows.Devices.Geolocation.Geolocator();
    
    gl.getGeopositionAsync().done(function (position) {	
    //Сохранить для целей общего доступа	
    lastPosition = { latitude: position.coordinate.latitude,
    longitude: position.coordinate.longitude };	
    }
     

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

    Объект ) содержит два свойства. Первое, это свойство ), который предоставляет свойства ), который содержит свойство ), в частности – класс MapAddress (http://msdn.microsoft.com/library/jj663670.aspx) для того, чтобы узнать адрес по имеющимся координатам.

    Вы можете задать желаемую точность измерений посредством свойства desiredAccuracy средства определения местоположения, которое может принимать значение PositionAccuracy.default или PositionAccuracy.high. Последнее, учтите, создаст большую нагрузку на аппаратное обеспечение. Это может привести к повышению стоимости использования лимитированного сетевого соединения и ускорить разряд батарей, поэтому устанавливайте этой свойство в значение high только тогда, когда это имеет ключевую важность для работы с приложением.

    Средство определения местоположения так же предоставляет свойство ), содержащим такие члены, как ready, initializing, noData, disabled, notInitialized, и notAvailable. Должно быть очевидным, что вы не сможете получить данные от средства определения местоположения, которое находится в состоянии, отличном от ready (готово). Для того, чтобы отследить это, вы можете прослушивать событие средства определения местоположения statusChanged, свойство eventArgs.status которого в вашем обработчике будет содержать PositionStatus. Это полезно, когда вы обнаруживаете, что GPS-приемнику может понадобиться пара секунд на то, чтобы предоставить необходимые данные. Например, вот как используется данное событие в примере "Определение местопол ожения" (http://code.msdn.microsoft.com/windowsapps/Geolocation-2483de66) из Windows SDK:

    geolocator = new Windows.Devices.Geolocation.Geolocator();
    geolocator.addEventListener("statuschanged", onStatusChanged); //Позже не забудьте удалить
    
    function onStatusChanged(e) {
    switch (e.status) {
    // ...
    }
    }
     

    Обратите внимание на то, что PositionStatus и statusChanged отражают чтение данных с GPS-устройства, и на чтение не влияет разрешение на получение данных о местоположении в панели параметров. Как показано в "Here My Am!", приложению не нужно проверять разрешение, пытаясь получить значения параметров, что является особенностью получения данных от устройства.

    Два других интересных свойства средства определения местоположения – это movementThreshold, расстояние в метрах, на которое может переместиться устройство, прежде чем будет вызвана следующая операция чтения данных (это может быть использовано в сценариях с установкой географических границ), и reportInterval, который задается в миллисекундах между попытками чтения данных. Используйте последний параметр умеренно, устанавливайте его в то значение, которое вам действительно нужно, так как следует стремиться к минимизации сетевой активности и активности GPS-датчика. В любом случае, когда средство определения местоположения получает новые данные и обнаруживает, что устройство переместилось за пределы movementThreshold, оно вызывает событие positionChanged, свойство которого eventArgs.position является новым объектом Geoposition. Это так же показано в Сценарии 1 примера об определении местоположения:

    geolocator.addEventListener("positionchanged", onPositionChanged);
    
    function onPositionChanged(e) {
    var coord = e.position.coordinate;
    
    document.getElementById("latitude").innerHTML = coord.latitude;
    document.getElementById("longitude").innerHTML = coord.longitude;
    document.getElementById("accuracy").innerHTML = coord.accuracy;
    }
     

    В случае с movementThreshold и reportInterval, рассматривайте их с позиций нужд приложения, основанных на точности и/или интервале обновления данных о местоположении, которые вы используете. Например, данные о погоде относятся к регионам и могут обновляться лишь раз в час. Поэтому movementThreshold может быть установлено в милях или километрах, reportInterval – на 15, 30, 60 минут или на более длительное время. Приложения работы с картами или предназначенные для автомобилистов, с другой стороны, работают с данными, весьма чувствительными к местоположению и, таким образом, будут иметь гораздо меньшие пороговые значения и более короткие интервалы обновления.

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

    Так же очень важно отметить, что приложения не получают события positionChanged или statusChanged, когда они приостановлены, если только вы не зарегистрировали для этой цели фоновую задачу, запускаемую по таймеру и пользователь не добавил приложение на экран блокировки. Мы поговорим об этом подробнее в лекции 2 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой", и вы так же сможете увидеть, как это работает в Сценарии 3 примера об определении местоположения. Если, однако, вы не используете фоновые задачи или пользователь не поместил приложение на экран блокировки, и вам все еще нужно отслеживать местоположение пользователя, обрабатывайте соответствующим образом событие resuming и обновляйте там эти данные.

    С другой стороны, некоторые сценарии, исопользующие определение местоположения, такие, как навигация, нуждаются в том, чтобы экран устройства был активен (предотвращая автоматическое выключение экрана), даже если пользователь ничего не делает. Для этой цели вы можете использовать класс в частности, его методы requestActive и requestRelease, которые вы можете вызывать в начале и в конце сеанса навигации. Конечно, поддержание экрана во включенном состоянии приводит к потреблению большей энергии батарей, используйте эту возможность только когда это необходимо – когда приложение используется для целей навигации – и не прибегайте к выполнению подобного запроса при запуске приложения. В противном случае ваше приложение, возможно, прослывет в Магазине Windows как неумеренный потребитель энергии!

    Врезка: Определение местоположения в HTML5

    Опытные разработчики HTML/JavaScript могут удивиться, почему WinRT предоставляет API для определения местоположения в то время, как в HTML5 оно уже есть: window.navigator.geolocation и его метод getCurrentPosition , который возвращает объект с координатами. Причина подобного заключается в том, что другие языки, такие, как C#, VisualBasic и C++ не имеют других API для получения подобных данных, что предоставляет выбор разработчикам на HTML/JavaScript. Если посмотреть глубже, то API HTML5 пользуется теми же данными, что и API WinRT, требует объявления той же возможности Расположение (Location) в манифесте, и нуждается в таком же разрешении пользователя, то есть, в основном, эти два API идентичны. Я дал бы API WinRT небольшое преимущество за счет опции movementThreshold , которая помогает приложению экономить электроэнергию и делает возможной простую постановку географических границ. Выполнение тех же действий в HTML5 потребует более частых запросов и приведет к большему потреблению энергии. Во многих сценариях, однако, вы можете использовать либо то, либо другое, с одинаковыми результатами. Однако, как и другие API WinRT, Windows.Devices.Geolocation доступно лишь страницам локального контекста приложений для Магазина Windows. На страницах веб-контекста вы можете пользоваться API HTML5.

    Датчики

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

    Датчики, опять же, это способ понять взаимоотношения устройства и физического мира, окружающего его, и их использование подразумевает ввод данных, так как вы, будучи человеком, можете влиять на эти взаимоотношения, в основном, перемещая устройство в пространстве или меняя их окружение. Датчики так же могут быть использованы как средства прямого ввода информации, вызывая перемещение объектов на экране, вместо использования какой-то формы абстрактного ввода данных наподобие мыши или клавиатуры. Например, вместо того, чтобы использовать абстрактное сочетание клавиш для того, чтобы наклонить игровое поле, вы можете, используя датчики, просто наклонить устройство. Встряхивание устройства, на самом деле, является хорошо известным физическим жестом, который может быть связан с командой вроде "Повтори, будь ты проклят! Почему ты не делаешь то, что я хочу?". Разве мы долгие годы не трясли наши компьютеры или не стучали по ним, когда они не делали то, что нам нужно? А компьютер с датчиками вполне может отреагировать на такое воздействие!

    Вот, какую информацию могут нам сообщить различные датчики:

  • Местоположение (Location). Позиция устройства на Земле (мы обсудили это в предыдущем разделе).
  • Компас (Compass) и ориентация (Orientation). Ориентация устройства по отношению к магнитным полюсам Земли, или относительно нормального положения устройства (простая и сложная ориентация).
  • Инклинометр, креномер (Inclinometer). Предоставляет данные о поворотах устройства относительно поперечной, продольной и вертикальной осей в трехмерном пространстве.
  • Гирометр (Gyrometer). Данные об угловой скорости/вращательном движении устройства в трехмерном пространстве.
  • Акселерометр (Accelerometer). Ускорение устройства (в G) в трехмерном пространстве (X, Y, Z).
  • Окружающий свет (Ambient light). Яркость света в пространстве, окружающем устройство.
  • Эти датчики предоставляет API WinRTЗдесь присутствует и датчик для бесконтактного взаимодействий (proximity) близко расположенных устройств (NFC), который сообщает о том, что устройства находятся близко друг от друга или соприкасаются, но это больше средство для установления сетевого соединения, нежели датчик, похожий на другие. Мы рассмотрим его в лекции 15., некоторые из них созданы программным путем посредством синтеза датчиков (sensor fusion). Это подразумевает получение исходных данных от одного или большего коичества аппаратных датчиков, комбинирование, интерпретацию и представление их в виде, которым может воспользоваться приложение. Как и с указателями, вы можете пользоваться исходными данными, если нужно, но чаще в этом нет необходимости. Например, простой датчик ориентации (Simple Orientation) предоставляет простую интерпретацию расположения устройства по отношению к его расположению по умолчанию, округляя данные до 90-градусных секторов. Полный датчик ориентации, с другой стороны, комбинирует данные гирометра, акселерометра и компаса для того, чтобы предоставить матрицу трехмерной ориентации, которая гораздо более точна, но ориентирована (если можно использовать каламбур!) на более продвинутые сценарии, нежели обычное определение, расположено ли устройство вниз экраном или на боку.

    Так как работа всех этих датчиков очень похожа друг на друга (это сделано специально, за исключением простого датчика ориентации, который не похож на другие), я хочу показать общий шаблон работы с API датчиков вместо детальных примеров для каждого из них. Подобные примеры можно найти среди SDK-примеров "Акселерометр" (http://code.msdn.microsoft.com/windowsapps/Accelerometer-Sensor-Sample-22982671), "Компас" (http://code.msdn.microsoft.com/windowsapps/Compass-Sensor-Sample-0ed09c55), "Гирометр" (http://code.msdn.microsoft.com/windowsapps/Gyrometer-Sensor-Sample-4fe891d9), "Инклинометр" (http://code.msdn.microsoft.com/windowsapps/Inclinometer-Sensor-Sample-0cd0bf84), "Датчик освещенности" (http://code.msdn.microsoft.com/windowsapps/LightSensor-Sample-4477824c) и "Датчик ориентации" (http://code.msdn.microsoft.com/windowsapps/OrientationSensor-sample-0b1732be).

    Шаблон их использования выглядит следующим образом, некоторые особенности приведены в таблице ниже:

    Получение объекта датчика посредством Windows.Devices.Sensors.<sensor>.getDefault().

    Вызов метода getCurrentReading этого объекта для получения данных.

    Для последующего получения данных, настроить свойства объекта minimumReportInterval и reportInterval (и то и другое – в миллисекундах) и прослушивать событие объекта readingchanged. В ответ обработчик события получит объект подходящего типа с прочитанными данными. В случае с определением местоположения, разумно подойтите к установке этих параметров, что поможет увеличить время работы устройства от батарей, предотвращая излишний расход электроэнергии датчиками.

    Название датчика (Windows.Devices.Sensors.) Дополнительные члены Тип возвращаемых данных (Windows.Devices.Sensors) Свойства возвращаемых данных (timestamp Имеет тип Date; остальные являются числами, если не указано иное)
    Акселерометр (http://msdn.microsoft.com/library/windows/apps/windows.devices.sensors.accelerometer.aspx) Событие: shaken (аррументы события содержат лишь свойство timestamp) ) accelerationX (в G), accelerationY, accelerationZ, timestamp
    Компас (http://msdn.microsoft.com/library/windows/apps/windows.devices.sensors.compass.aspx) n/a ) headingMagneticNorth (градусы), headingTrueNorth, timestamp
    Гирометр (http://msdn.microsoft.com/library/windows/apps/windows.devices.sensors.gyrometer.aspx) n/a ) angularVelocityX (градусы в секунду), angularVelocityY, angularVelocityZ, timestamp
    Инклинометр (http://msdn.microsoft.com/library/windows/apps/windows.devices.sensors.inclinometer.aspx) n/a ) pitchDegrees (градусы), rollDegrees (градусы), yawDegrees (градусы), timestamp
    Датчик освещенности (http://msdn.microsoft.com/library/windows/apps/windows.devices.sensors.lightsensor.aspx) n/a ) illuminenceInLux (люксы), timestamp
    Датчик ориентации (http://msdn.microsoft.com/library/windows/apps/windows.devices.sensors.orientationsensor.aspx) n/a ) quaternion, (SensorQuaternion содержит свойства w, x, y, и z) rotationMatrix (Sensor-RotationMatrix содержит свойства m11, m12, m13, m21, m22, m23, m31, m32, m33), timestamp

    Вот образец кода из примера "Гирометр" (js/scenario1.js):

    gyrometer = Windows.Devices.Sensors.Gyrometer.getDefault();
    
    var minimumReportInterval = gyrometer.minimumReportInterval;
    var reportInterval = minimumReportInterval > 16 ? minimumReportInterval : 16;
    gyrometer.reportInterval = reportInterval;
    
    gyrometer.addEventListener("readingchanged", onDataChanged);   
    // Не забудьте удалить при необходимости
    
    function onDataChanged(e) {
    var reading = e.reading;
    document.getElementById("eventOutputX").innerHTML = reading.angularVelocityX.toFixed(2);
    document.getElementById("eventOutputY").innerHTML = reading.angularVelocityY.toFixed(2);
    document.getElementById("eventOutputZ").innerHTML = reading.angularVelocityZ.toFixed(2);
    }	
     

    В случае с датчиком ориентации, понятие кватернион (quaternion) легче всего понять как вращение точки [x,y,z] вокруг одной произвольной оси. В этом – отличие от матрицы вращения, которая представляет вращение по всем трем осям. Математическая основа кватернионов довольно экзотична, она включает в себя геометрические понятия комплексных чисел, математические понятия мнимых чисел, но работать с ними просто и фреймворки наподобие DirectX поддерживают их. Посмотрите пример "Сенсор ориентации" для того, чтобы больше узнать об этом.

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

    В итоге, использование этого датчика выглядит так:

  • Вызовите Windows.Devices.Sensors.SimpleOrientation.getDefault для того, чтобы получить объект.
  • Вызовите getCurrentOrientation для того, чтобы получить результаты чтения данных.
  • Событие orientationChanged используется для последующего получения данных, где eventArgs содержит свойства orientation (результат чтения данных) и timestamp.
  • Свойство ), который содержит следующие свойства:
  • notRotated ("portrait up", книжная-сверху), rotated90DegreesCounterclockwise ("landscape left" альбомная-слева), rotated180DegreesCounterclockwise ("portrait down" книжная-снизу), rotated270DegreesCounterclockwise ("landscape right" альбомная-справа). Обратите внимание на то, что все это не имеет никакого отношения к состояниям просмотра наподобие полноэкранного альбомного или полноэкранного портретного режимов просмотра.
  • faceup, facedown (лицевой сторонй вверх или вниз, только для планшентых устройств).
  • Демонстрацию использования этого датчика вы можете найти в примере "Простой датчик ориентации" (http://code.msdn.microsoft.com/windowsapps/SimpleOrientationSensor-d948ac62).

    Что мы только что изучили

  • Сообщение: "Дизайн приложений, использующих мышь, касания, перо – без дополнительных усилий" соответствует истине, так как работа с указателями и жестами, поступающими от различных устройств, не требует делать различия между способами ввода.
  • Использование встроенных элементов управления – это самый простой способ обработки ввода, но вы так же можете непосредственно обрабатывать события MSPointer* и MSGesture*, если в этом есть необходимость. Так же вы можете передавать события MSPointer в пользовательское средство распознавания жестов (оно инициирует собственные события).
  • Язык касаний Windows 8 включает в себя касание, нажатие и удержание, прокрутку/сдвиг, скольжение по диагонали (для выделения), жесты сжатия-растяжения, вращение, жесты у краев экрана (от верхней, нижней и от боковых сторон). Касание обычно обрабатывается в событии click, в то время как другие требуют создания объекта MSGesture, связи этого объекта с указателем и обработку последовательностей событий MSGesture*, которая используется для реализации манипуляций и перемещения с инерцией.
  • У языка касаний есть эквиваленты, реализуемые с помощью мыши, пера и клавиатуры. В случае с мышью и пером нужно проделать не так много работы (например, передавать события мыши wheel в объект жеста). Поддержка клавиатуры должна быть реализована отдельно, она использует обычные события HTML/JavaScript.
  • Поддержка клавиатуры так же включает в себя соответствующую настройку для работы с программной (экранной) клавиатурой, которая появляется автоматически для полей ввода текста и других элементов, поддерживающих редактирование содержимого. Она автоматически настраивает свой внешний вид в зависимости от типа вводимых данных и смещает содержимое приложения вверх, если нужно, для того, чтобы не перекрыть клавиатурой элемент управления, в который нужно вводить текст. Приложение так же может обрабатывать события, связанные с экранной клавиатурой для предоставления большего удобства, чем в случае с автоматическим поведением системы.
  • API поддержки рукописного ввода предоставляет приложениям средства для записи, сохранения и вывода последовательностей штрихов, оставленных указателем, штрихи так же можно передать средству распознавания рукописного текста.
  • API определения местоположения в WinRT, так же, как похожее API HTML5, предоставляет приложениям доступ к GPS-данным, а так же – события, показывающие, что устройство пересекло ранее заданное пороговое значение в пространстве.
  • API WinRT предоставляеют множество датчиков, которые можно использовать для ввода данных в приложение. В дополнение к датчику определения местоположения, это компас, датчик ориентации, основанный на квадрантах простой датчик ориентации, инклинометр, гиромет, акселерометр и датчик окружающего освещения.
  • Большая часть сенсоров используется по одному и тому же шаблону: получить объект сенсора, получить текущий результат чтения данных и, возможно, прослушивать событие readingChanged. С ними легко работать, что оставляет большую часть сил на поиск креативных способов их применения!
  • Страницы:

    Когда объект MSGesture получает несколько указателей через свое событиет addPointer, он так же запускает события MSGestureStart, MSGestureChange, MSGestureEnd для жестов поворота и масштабирования, вместе с событием MSInertiaStart. В подобных случаях свойства scale, rotation, velocityAngular, expansion, и velocityExpansion в объекте eventArgs приобретают смысл.

    Вы можете выборочно просматривать эти свойства для событий MSGestureChange посредством выпадающего списка, который расположен в правом верхнем углу, в упражнении PointerEvents. Вы можете заметить, что, когда вы выполняете многоточечные жесты в имитаторе Visual Studio, вы никогда не видите событие MSGestureTap для отдельных точек касания. Это происходит потому, что распознаватель жестов может видеть подобные множественные события MSPointerDown, которые происходят почти одновременно (здесь играет роль свойство hwTimestamp) и тут же объединяет их в одно событие MSGestureStart (например, начинает жест масштабирования или вращения).

    Теперь я уверен, что вы готовы задать несколько важных вопросов. До сих пор я говорил о сенсорных жестах изменения масштаба и вращения, о жестах переноса, как о рахных вещах, но как, на самом деле, различать их, если все они поступют в приложение посредством одного и того же события MSGestureChange? Разве это не запутывает все? Какова стратегия для работы с жестами переноса, вращения и масштабирования?

    Хорошо, ответ заключается в том, что вам не нужно их разделять! Что, если вы подумаете немного о том, как вы обрабатываете события MSGestureChange и данные, которые каждое из них содержит в зависимости от вида манипуляции, который вы поддерживаете в пользовательском интерфейсе:

  • Если вы поддерживаете лишь перенос элемента (translation), вы просто никогда не обращаете внимание на свойства наподобие scale и rotation и применяете только необходимые, такие, как translationX и translationY. Это было бы ожидаемым поведением при выборе элемента в элементе управления коллекцией, например (или в элементе управления, который позволяет манипулировать элементами по технологии "перетащить и опустить", меняя порядок их расположения).
  • Если вы поддерживаете лишь изменение масштаба (scale), вы игнорируете все свойства, которые имеют отношение к позиционированию и работаете со свойствами scale, expansion, и/или со свойством velocityExpansion. Это будет тем поведением, которое вы хотите реализовать для элемента управления, который поддерживает оптическое или семантическое масштабирование.
  • Если вас интересует лишь вращение (rotation), то ваши друзья – это свойства rotation и velocityAngular.
  • Конечно, если вы хотите поддерживать несколько видов манипуляций, вы можете просто реализовать обработку всех этих свойств, передавая их, например в CSS-трансформацию. Подобное может быть применимо к приложениям, которые реализуют различные манипуляции для экранных объектов, и именно этому посвящен один из примеров Windows SDK, рассматривающий жесты.

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

    В то время, как упражнение PointerEvents, включенное в эту лекцию, давало нам низкоуровневый вид событий указателей и жестов, для приложений по-настоящему важно то, как применять эти события для реальной манипуляции экранными объектами, что является реализацией частей языка касаний, такими, как жесты сжатия/растяжения и вращения. Для того, чтобы увидеть это, мы можем обратиться к примеру "Ввод: жесты, допускающие создание экземпляров" (http://code.msdn.microsoft.com/windowsapps/Input-Instantiable-deda69ca).

    Этот пример, в основном, показывает, как использовать события жестов одновременно с несколькими элементами. В Сценарии 1 и 2, приложение реализует простой пример головоломки, как упоминалось выше. Каждым закрашенным прямоугольником можно управлять по отдельности, используя перетаскивание для перемещения (с инерцией и без), жест сжатия-растяжения для изменения масштаба, и жест вращения для вращения, как показано на рис. 4.1. (рис 4.1) Пример "Ввод: жесты, допускающие создание экземпляров" после того, как с ним немного поработали. Словосочетание "допускающие создание экземпляров" (instantiable) использовано потому, что нам нужно создать экземпляр (instance) объекта MSGesture для приема событий жестов

    В Сценарии 1 (js/instantiableGesture.js) объект MSGesture создается для кажого экранного элемента вместе с еще одним для черного фона, "стола" при инициализации (в функции initialize). Мы уже видели подобное. Похожим бразом, обработчик MSPointerDown (onPointerDown) добавляет указатели к объектам жестов для каждого элемента, уделяя немного больше внимания обработке их положения по оси Z. Это предовращает одновременные касания, указатели мыши и пера работают с тем же самым элементом (что было бы странно!):

    function onPointerDown(e) {
    if (e.target.gesture.pointerType === null) {  
     // Первый контакт e.target.gesture.addPointer(e.pointerId); 
     // Присоединение указателя к элементу
    e.target.gesture.pointerType = e.pointerType;
    }
    else if (e.target.gesture.pointerType === e.pointerType) 
    { // Контакты сходного типа e.target.gesture.addPointer(e.pointerId);         
       // Присоединение указателя к элементу
    }
    
    // ZIndex изменяется при опускании указателя. 
    // Элемент, на который опустился указатель, становится самым верхним 
    var zOrderCurr = e.target.style.zIndex;
    var elts = document.getElementsByClassName("GestureElement");
    for (var i = 0; i < elts.length; i++) {
    if (elts[i].style.zIndex === 3) {
    elts[i].style.zIndex = zOrderCurr;
    }
    e.target.style.zIndex = 3;
    }
    }
     

    Обработчик MSGestureChange выполняется для каждого отдельного фрагмента (onGestureChange), затем собирает все данные по переносу, вращению, масштабированию в объекте eventArgs и применяет их с помощью CSS. Это показывает, как удобно то, что все эти свойства уже описаны в нужной нам системе координат:

    function onGestureChange(e) {
    var elt = e.target;
    var m = new MSCSSMatrix(elt.style.msTransform);
    
     elt.style.msTransform = m.	
    translate(e.offsetX, e.offsetY).	
    translate(e.translationX, e.translationY).
    rotate(e.rotation * 180 / Math.PI).	
    scale(e.scale).	
    translate(-e.offsetX, -e.offsetY);	
    }	
     

    В коде примера выполняется немного больше всего, но то, что мы показали здесь – это самые важные части. Очевидно, если вам не нужна поддержка манипуляций определенного вида, вы можете просто игнорировать определенные свойства в объекте eventArgs.

    Сценарий 2 этого примера формирует такое же изображение, но он реализован несколько иначе. Как вы можете видеть, в его функции initialize (js/gesture.js), изначально регистрируется лишь одно событие, применяющееся к "столу", который имеет черный фон и окружающую его границу.

    Объекты жестов для отдельных фрагментов головоломки создаются и прикрепляются к указателям в событии MSPointerDown (onTableTopPointerDown). Этот подход более эффективен и масштабируем для приложения-головоломки, которое может иметь сотни или даже тысячи фрагментов, так как объекты жестов хранятся лишь до тех пор, пока осуществляется манипуляция конкретным фрагментом. Эти манипуляции так же похожи на те, что были в Сценарии 1, где свойства MSGestureChange применялись посредством CSS-трансформаций. Для того чтобы узнать подробности, обратитесь к комментариям к коду в js/gesture.js, так как они весьма обширны.

    Сценарий 3 этого примера предоставляет еще одну демонстрацию выполнения жестов переноса, сжатия-расширения и вращения с использованием колеса мыши. Как показано в упражнении PointerEvents, единственное, что нужно для того, чтобы сделать это – это обработать событие wheel, установить eventArgs.pointerId в 1 и передать это в обработчик MSPointerDown, который затем добавит указатель к объекту жеста:

     function onMouseWheel(e) {
    e.pointerId = 1; // Фиксированный pointerId для MouseWheel
    onPointerDown(e);	
    }	
     

    Опять же, это все, что нужно. (Мне нравится, когда все так просто!). В качестве упражнения, вы можете попытаться добавить этот код в Сценарии 1 и 2.

    Средство распознавания жестов

    В случае с инерционными жестами, которые продолжают посылать некоторое количество событий MSGestureChange, когда указатель освобожден, вы можете задаться вопросами: "А что, на самом деле, управляет этими событиями? Очевидно, существует особая модель уменьшения скорости, встроенная в эти события, а именно та, на основе которой построены внешний вид и впечатления от взаимодействия с Windows. Но что, если мне нужно другое поведение? И что, если я хочу совсем иначе интерпретировать события указателя?"

    Вспомогательный механизм, который интерпретирует события указателя, превращая их в жесты, называется средством распознавания жестов (gesture recognizer). Его вы можете получить напрямую посредством объекта ). После создания экземпляра этого объекта с помощью команды ) для тех видов манипуляций и жестов, которые вам интересны. Документация по Windows.UI.Input.GestureSettings предоставляет полный набор возможностей, в том числе, такие жесты, как ) (ballineight.js) мы можем видеть, как настраивают средство распознавания жестов для жестов касания (tap), вращения (rotate), переноса (translate) и масштабирования (scale) (с инерцией):

     gr = new Windows.UI.Input.GestureRecognizer();
    
    // Настройка GestureRecognizer для определения манипуляций вращения, переноса, масштабирования,
    // с инерцией для данных трех компонентов манипуляции и обработки касания
    gr.gestureSettings =
    Windows.UI.Input.GestureSettings.manipulationRotate |
    Windows.UI.Input.GestureSettings.manipulationTranslateX | Windows.UI.Input.GestureSettings.manipulationTranslateY | 
    Windows.UI.Input.GestureSettings.manipulationScale | 
    Windows.UI.Input.GestureSettings.manipulationRotateInertia | Windows.UI.Input.GestureSettings.manipulationScaleInertia | 
    Windows.UI.Input.GestureSettings.manipulationTranslateInertia |
    Windows.UI.Input.GestureSettings.tap;
    
    // Выключение обратной связи пользовательского интерфейса для жестов 
    // (обратная связь все еще используется для PointerPoints)
    gr.showGestureFeedback = false;
    

    Объект GestureRecognizer так же имеет множество свойств для настройки его специфических событий. Например, для жестов скольжения по диагонали (cross-slides) вы можете задать свойства crossSlideThresholds, crossSlideExact, и crossSlideHorizontally. Вы можете задать быстроту снижения скорости (в пикселях/мс2) посредством свойств inertiaExpansionDeceleration, inertiaRotationDeceleration, и inertiaTranslationDeceleration.

    После настройки, вы начинаете передавать событий MSPointer* к объекту средсва распознавания жестов, в частности, его методам, которые называются processDownEvent, processMoveEvents, и processUpEvent (так же, если нужно, processMouseWheelEvent, и processInertia). В ответ, в зависимости от конфигурации, средство распознавания жестов запустит некоторое количество собственных событий. Во-первых, это дискретные события, наподобие crossSliding, dragging, holding, rightTapped, и tapped. Для остальных он запустит серию событий manipuationStarted, manipulationUpdated, manipulationInertiaStarting, и manipulationCompleted. Обратите внимание на то, что все эти события исходят из WinRT, поэтому убедитесь, что вызвали, когда нужно, removeEventListener.

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

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

    var recognizer = new Windows.UI.Input.GestureRecognizer();
    recognizer.gestureSettings = Windows.UI.Input.GestureSettings.manipulationTranslateX;
    var DELTA = 10;
    
    myElement.addEventListener('MSPointerDown', function (e) {
    recognizer.processDownEvent(e.getCurrentPoint(e.pointerId));
    });
    myElement.addEventListener('MSPointerUp', function (e) {
    recognizer.processUpEvent(e.getCurrentPoint(e.pointerId));
    });
    myElement.addEventListener('MSPointerMove', function (e) {
    recognizer.processMoveEvents(e.getIntermediatePoints(e.pointerId));
    });
    
    // Помните, что при работе с этими событиями нужен removeEventListener 
    recognizer.addEventListener('manipulationcompleted', function (args) {
    var pt = args.cumulative.translation;
    if (pt.x < -DELTA) {
    // переместить вправо
    }
    else if (pt.x > DELTA) {
    // переместить влево
    }
    });
     

    Помимо использования средства распознавания жестов, помните, что вы всегда можете перейти на более низкий уровень и выполнить собственную обработку событий MSPointer* , если вам это нужно, и, таким образом, полностью обойти средство распознавания жестов. Это может быть нужно, если конфигурации, допустимые в средстве распознавания жестов, не соответствуют вашим особенным нуждам. В то же время, сейчас неплохая возможность для того, чтобы перечитать врезку "Создание совершенно новых жестов?" в конце раздела о языке касаний. Она посвящена некоторым вопросам о том, когда действительно нужны пользовательские жесты.

    Ввод данных с клавиатуры и программная клавиатура

    После всего, что мы узнали о сенсорном вводе данных и о других способах ввода, может показаться, что рассмотрение скромной клавиатуры нас разочарует. Но, все же, клавиатура остается крайне важной для ввода текста, будь это физическая клавиатура или экранная "программная" клавиатура. Она особенно важна для обеспечения специальных возможностей, так как некоторые пользователи физически не могут использовать мышь или другие устройства. На самом деле, раздел 3.5. "Сертификационных требований к приложениям для Windows 8" (http://msdn.microsoft.com/library/windows/apps/hh694083.aspx) говорит об обязательной поддержке приложениями ввода с клавиатуры.

    К счастью, в приложениях для Магазина Windows нет ничего особенного в обработке ввода с клавиатуры, но длинный путь можно пройти короткими шагами. Вот общие положения, взятые из материала "Реализация специальных возможностей клавиатуры" (http://msdn.microsoft.com/library/windows/apps/hh700327.aspx):

  • Обрабатывайте события keydown, keyup и keypress так, как вы уже знаете, особенно для реализации специальных сочетаний клавиш. Смотрите раздел "Стандартные сочетания клавиш" далее в этом разделе для того, чтобы взглянуть на типичные сопоставления команд.
  • Задавайте атрибут tabindex интерактивным элементам, которые должны поддерживать возможность переключения на них с помощью клавиши табуляции. Старайтесь не добавлять tabindex к неинтерактивным элементам, так как это может помешать программам чтения с экрана.
  • Задавайте атрибут accesskey для тех элементов, которым следует иметь клавиатурные сокращения.
  • Вызывайте DOM API для задания фокуса для элементов, которые должны быть элементами по умолчанию
  • Используйте преимущества клавиатурных сокращений, которые уже присутствуют во встроенных элементах управления, в таких, как панель приложения.
  • В приложении "Here My Am!", над которым мы работаем в этом курсе, обновленный вариант которого содержится в дополнительных материалах к этой лекции, добавлена полная поддержка клавиатуры. Это, в основном, коснулось добавления ) для сравнения кодов клавиш:

    var Key = WinJS.Utilities.Key;
    var image = document.getElementById("photo");
    
    image.addEventListener("keydown", function (e) {	
    if (e.keyCode == Key.enter || e.keyCode==Key.space) {
    image.click();	
    }	
    });	
     

    Все это работает и для физической клавиатуры, и для программной. Дело закрыто? Не вполне. Есть две особенности, касающиеся экранной клавиатуры: первая – это как показать ее, вторая – как ее появление подействует на макет приложения. В конце этого раздела мы так же взглянем на стандартные клавиатурные сокращения для команд приложения.

    Показ программной клавиатуры происходит по одной и только одной причине: пользователь касается элемента управления для ввода текста с атрибутом contenteditable="true" (такого, как div или canvas). Нет API, которое отображает клавиатуру, она не появляется и тогда, когда вы щелкаете по подобному элементу управления мышью или пером, или перемещаетесь к нему, нажимая клавишу табуляции на физической клавиатуры.

    Конфигурация клавиатуры зависит от типа элемента управления для ввода текста. Мы можем увидеть это в Сценарии 2 примера "Ввод: сенсорная клавиатура для ввода текста" (http://code.msdn.microsoft.com/windowsapps/Input-Touch-keyboard-text-f86e9bd9), где в файле html/ScopedView.html содержится несколько элементов управления input (окружающая разметка опущена), которые выглядят так, как показано на рис. 4.2.

     <input type="url" name="url" id="url" size="50" />	
    <input type="email" name="email" id="email" size="50" />	
    <input type="password" name="password" id="password" size="50" />
    <input type="text" name="text" id="text" size="50" />	
    <input type="number" name="number" id="number" />	
    <input type="search" name="search" id="search" size="50" />	
    <input type="tel" name="tel" id="tel" size="50" />	
    

    (рис 4.2) Программная клавиатура появляется, когда вы касаетесь поля ввода, как показано в примере

    То, что показано на рис. 4.2. – это клавиатура по умолчанию. Если вы прикоснетесь к полю Search (Поиск), вы получите практически то же самое, за исключением того, что клавиша Enter превратится в клавишу Search (Поиск). Для поля Email клавиатура тоже похожа на стандартную, за исключением того, что появятся кнопки @ и .com у клавиши пробела:

    Клавиатура для ввода URL выглядит так же, но клавиши @ нет, а Enter превращается в Go (Перейти):

    Для поля ввода пароля на клавиатуре появляется клавиша Hide keypresses (Скрыть нажатия клавиш), которая отключает видимую анимацию нажатий клавиш – очень полезная функция, если вы записываете видео!

    И, наконец, поля Number (Число) и Telephone (Телефон) вызывают клавиатуру, ориентированную на ввод чисел:

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

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

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

    Так же клавиатура настроаивает свой внешний вид при работе с элементами управления для ввода текста для предоставления подсказок и выделения появляющейся кнопки Insert (Вставить). Это показано в Сценарии 1 примера:

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

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

    Когда появляется программная клавиатура или панель для ввода рукописного текста, система пытается убедиться в том, что поле ввода видимо, прокручивая содержимое, если это возможно. Это значает просто установку отрицательного вертикального смещения для всей вашей страницы в соответствии с высотой программной клавиатуры. Например, если я добавлю (в качестве радикального решения!) кучу элементов </br> в верхнюю часть страницы html/ScopedView.html в примере, так, чтобы элементы управления для ввода текста оказались внизу страницы, и затем коснусь одного из них, вся страница сдвинется вверх, как показано на рис. 4.3.: (рис 4.3) Когда появляется программная клавиатура, Windows автоматически смещает страницу приложения вверх для того, чтобы поле ввода не оказалось перекрытым

    Хотя такой подход может быть самым простым решением этой задачи, он не всегда идеален. К счастью, вы можете сделать кое-что более интеллектуальное, если хотите, прослушивая события ) и непосредственно подстраивая макет. Код для того, чтобы это сделать, можно найти (вы готовы к этому?) в примере "Реагирование на отображение экранной клавиатуры" (http://code.msdn.microsoft.com/windowsapps/Keyboard-Events-Sample-866ba41c) И пока вы думаете, что это второе самое длинное название JavaScript-примера в Windows SDK, оно, на самом деле, может получить лишь бронзовую медаль. Пример "Невыделяемые области содержимого с CSS-атрибутом –ms-user-select" (http://code.msdn.microsoft.com/windowsapps/Unselectable-content-areas-963eccd9), который мы уже видели, получает золото, а пример "Использование requestAnimationFrame для анимации, эффективно расходующей электроэнергию" (http://code.msdn.microsoft.com/windowsapps/Using-requestAnimationFrame-924b039a) получает серебро. Однако, я не против таких длинных названий – я очень доволен тем, что у нас есть столь обширный набор отличных примеров, из которых мы можем взять много полезного!. К этим событиям очень просто добавить прослушиватели (смотрите в нижней части в js/keyboardPage.js, который, так же, соответствующим образом удаляет прослушиватели):

    var inputPane = Windows.UI.ViewManagement.InputPane.getForCurrentView();
     inputPane.addEventListener("showing", showingHandler, false); 
    inputPane.addEventListener("hiding", hidingHandler, false);
     

    В обработчике события showing объект eventArgs.occludedRect (имеющий тип Windows.Foundation.Rect) дает вам координаты и размеры обрасти, которую перекроет экранная клавиатура. В ответ на это мы можете настроить любые необходимые параметры макета и установить свойство eventArgs.ensuredFocusedElementInView в true. Это сообщит Windows, что автоматический сдвиг выполнять не нужно:

    function showingHandler(e) {
    if (document.activeElement.id === "customHandling") {
    keyboardShowing(e.occludedRect);
    
    // Будьте осторожны с этим свойством. Как только оно установлено, система 
    // не будет делать ничего для того, чтобы элемент, имеющий фокус, был видимым.	
    e.ensuredFocusedElementInView = true;	
    }	
    }	
     

    В примере показаны оба случая. Если вы коснетесь расположенного в нижней левой части приложения элемента defaultHandling, который имеет цвет морской волны, как показано на рис. 4.4, его showingHandler ничего не будет делать, и мы увидим поведение по умолчанию (рис 4.4) Прикосновение к левому элементу defaultHandling в нижней части приведет к стандартному поведению при появлении клавиатуры, при котором содержимое страницы сдвигается вертикально

    Если вы коснетесь элемента customHandling (справа), он вызовет функцию keyboardShowing для настройки макета:

    function keyboardShowing(keyboardRect) {
    // Часть кода опущена...
    var elementToAnimate = document.getElementById("middleContainer");
    var elementToResize = document.getElementById("appView");
    var elementToScroll = document.getElementById("middleList");
    
    // Записываем расстояние перемещения. Это упрощает расчеты 
    displacement = keyboardRect.height;
    var displacementString = -displacement + "px";
    
    // Находим последний видимый элемент в списке
    var bottomOfList = elementToScroll.scrollTop + elementToScroll.clientHeight;
    
    // Анимируем
    showingAnimation = KeyboardEventsSample.Animations.inputPaneShowing(elementToAnimate,
    { top: displacementString, left: "0px" }).then(function () {
    
    // После анимации макет занимает меньшее окно просмотра над клавиатурой
    elementToResize.style.height = keyboardRect.y + "px";
    
    // Прокручиваем список в нужное место, так чтобы прокрутка не была заметна
    elementToScroll.scrollTop = bottomOfList - elementToScroll.clientHeight;	
    showingAnimation = null;	
    });
    }	
     

    Этот код немного сложный, так как он анимирует перемещение различных элементов страницы. В результате макет задействованных элементов, а именно, того, к которому вы прикоснулись – подстраивается для того, чтобы дать место для клавиатуры. Другие элементы на странице, в противном случае, не затрагиваются. Результат показан на рис. 4.5. (рис 4.5) Прикосновение к серому элементу customHandling справа демонстрирует пользовательскую обработку отображения клавиатуры

    Стандартные сочетания клавиш

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

    Действие или команда Сочетание клавиш
    Перемещение фокуса Tab
    Назад (Навигация) Кнопка "Назад" на специальных клавиатурах; клавиша backspace , везде, кроме текстовых полей; Alt+стрелка влево
    Вперед (Навигация) Alt+стрелка вправо
    Вверх Alt+стрелка вверх
    Отмена/Выход из режима ESC
    Перемещение по элементам в списке Клавиши-стрелки (и Tab)
    Быстрое по элементам списка к соедующей группе, если выделение не следует автоматически за фокусом Ctrl+клавиши-стрелки
    Масштабирование (семантическое и оптическое) Ctrl+"+" b Ctrl+ "-"
    Быстрое перемещение к именованному элементу коллекции Начало ввода текста
    Перемещение на большое расстояние Page up/down ( должно работать в пользовательском интерфейсе, поддерживающем сдвиг в горизонтальном и вертикальном направлениях)
    Следующая позиция табуляции или группа Ctrl+Tab
    Предыдущая позиция табуляции или группа Ctrl+Shift+Tab
    N-ная позиция табуляции или группа Ctrl+N (1-9)
    Открыть панель приложения (Windows обрабатывает это автоматически) Win+Z
    Контектстное меню Клавиша контекстного меню
    Открыть дополнительную панель/выбрать элемент меню Enter
    Перейти куда-либо/активировать Enter (в выделении)
    Выбрать Пробел
    Выбрать смежные элементы Shift+клавиши-стрелки
    Закрепить элемент Ctrl+Shift+!
    Сохранить Ctrl+S
    Поиск Ctrl+F
    Печать Ctrl+P (вызывает Windows.Graphics.Printing.PrintManager.showPrintUIAsync)
    Копировать Ctrl+C
    Вырезать Ctrl+X
    Вставить Ctrl+V
    Новый элемент Ctrl+N
    Открыть адрес Ctrl+L или Alt+D
    Вращение Ctrl+"," и Ctrl+"."
    Проигрывание/Пауза Ctrl+P (только медиа-приложения)
    Следующий элемент Ctrl+F (конфликтует с Поиском)
    Предыдущий элемент Ctrl+B
    Перемотка назад Ctrl+Shift+B
    Перемотка вперед Ctrl+Shift+F

    Рукописный ввод

    Помимо встроенной программной клавиатуры и панели для рукописного ввода, приложениям может понадобиться предоставить пользователю поверхность, которая может непосредственно принимать данные указателя в виде рукописного ввода (ink). Под этим я подразумеваю больше, чем использование элемента canvas и обработку событий MSPointer для рисования или создания растровых изображений. Рукописные штрихи – это структура данных, которая поддерживает реально вводимую информацию (в том числе – сведения о нажиме, угле наклона сенсора, скорости, если аппаратное обеспечение это поддерживает), что позволяет выполнять распознавание рукописного ввода и другие виды высокоуровневой обработки информации, которые невозможны при работе с растровыми данными. Работа с рукописным вводом, другими словами, напоминае работу с процессом рисования изображения, а не работу с готовым изображением, и это возможно для всех типов указателей ввода.

    Поддержка рукописного ввода в WinRT располагается в пространстве имен ). Это API не зависит от конкретного презентационного фреймворка, не предоставляет она и средств визуализации: она имеет дело лишь с управлением структурами данных, которые приложение может вывести самостятельно, на поверхности для рисования наподобие canvas. Вот базовые функции этого API:

  • Создание экземпляра управляющего объекта с помощью команды new Windows.UI.Input.Inking.InkManager().
  • Назначение атрибутов рисования путем создания объекта Windows.UI.Input.Inking.InkDrawingAttributes и установки атрибутов штриха, таких, как color, fitToCurve (в противоположность прямым линиям, проводимым по умолчанию), ignorePressure, penTip (Windows.UI.Input.Inking.PenTipShape.circle или rectangle), и size (объект Windows.Foundation.Size со свойствами height и width).
  • Для элементов ввода, прослушивание событий MSPointerDown, MSPointerMove, и MSPointerUp, которые обычно нужны для целей визуализации. eventArgs.currentPoint это объект Windows.UI.Input.PointerPoint, который содержит идентификатор указателя, координаты точки и свойства наподобие pressure, tilt, и twist.
  • Передача объекта PointerPoint методам управляющего объекта processPointerDown, processPointerUpdate, и processPointerUp.
  • После события processPointerUp, управляющий объект рукописного ввода создает объект Windows.UI.Input.Inking.InkStroke для проведенного штриха. Штрихи можно получить посредством метода getStrokes управляющего объекта и вывести так, как нужно.
  • Жесты высокого уровня могут быть непосредственно конвертированы в объекты InkStroke и переданы управляющему объекту посредством метода addStroke. Объекты штрихов можно удалять с использованием метода deleteStroke.
  • Управляющий объект, кроме того, предоставляет методы для распознавания рукописного текста на основе содержащихся в нем штрихов, сохранения и загрузки данных и обработки различных режимов, таких, как рисование и стирание штрихов. Полную демонстрацию этого вы можете найти в примере "Ввод: рукописный ввод" (http://code.msdn.microsoft.com/windowsapps/Ink-App-sample-61abaec3), который показан на рис. 4.6. Этот пример позволит вам увидеть полный набор возможностей платформы рукописного ввода, в том числе – распознавание рукописного текста. (рис 4.6) Пример работы с платформой рукописного ввода содержит множество команд на панели приложения. Зеленый текст "Hello" в верхнем левом углу был создан после выделения рукописного "Hello" и использования команды Recognition (Распознавание)

    SDK так же включает в себя пример "Ввод: упрощенный рукописный ввод" (http://code.msdn.microsoft.com/windowsapps/Input-simplified-ink-sample-11614bbf) для демонстрации сценария, ориентированного на распознавание рукописного текста, как показано на рис. 4.7. Вам следует знать, что это пример, который вовсе не поддерживает касания – он ограничен мышью и пером и использует для активации команд клавиатурные сокращения вместо панели приложения. Взгляните на функцию keydown в файле simpleink.js для того, чтобы увидеть список команд вида "Ctrl + другая клавиша". Клавиша пробел активирует распознавание введенного текста, клавиша backspace очищает рабочую область. Как вы можете видеть на рисунке, я могу думать, что распознавание рукописного текста работает очень хорошо! (Это говорит мне о том, что образцы рукописного текста, которые я передал команде инженеров Microsoft где-то в середине 1990-х, стали значительным вкладом в их дело). (рис 4.7) Пример отлично распознает мой небрежный текст, написанный мышью

    Географическое расположение

    Прежде чем мы рассмотрим датчики в целом, я хочу отдельно рассмотреть возможности определения географического расположения в приложениях для Магазина Windows, так как это API устроено не так, как у других датчиков. Мы уже использовали эту возможность, начиная с Главы 2 курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript", в приложении "Here My Am!", но нам нужен более полной обзор этой крайне полезной возможности.

    В отличие от других датчиков, только определение местоположения имеет выделенную возможность, которую вы должны объявить в манифесте. То, где вы находитесь на Земле, это абсолютные данные, которые являются частью личной информации. Таким образом, пользователи должны дать согласие, прежде чем приложение сможет получить эти сведения, и ваше приложение так же должно предоставлять "Соглашение о конфиденциальности" в Магазине Windows. Другие датчики, в отличие от этого, предоставляют относительную информацию – вы не можете, например, узнать что-либо о человеке из данных о наклоне устройства, о его перемещении или из сведений о том, насколько яркий свет его освещает. Соответственно, вы можете использовать другие датчики без объявления каких-либо особых возможностей.

    Как вы можете знать, данные о географическом местоположении могут быть получены двумя различными путями. Первый, и наиболее точный, конечно, это получение данных с GPS-приемника, который получает информацию от геостационарных спутников, расположенных на орбитах в несколько сотен миль. Другим, достаточно полезным, хотя и не всегда точным средством является попытка узнать местоположение на основе IP-адреса проводного сетевого соединения или триангуляция на основе расположения доступных точек доступа WiFi. В любом случае, WinRT делает все возможное для того, чтобы дать вам достойные показатели.

    Для доступа к данным о географическом местоположении, вы должны сначала создать экземпляр средства определения местоположения WinRT, ). Когда он у вас есть, вы затем можете вызвать его метод getGeopositionAsync, результаты работы которого (помещенные в обработчик завершения), представляют собой объект типа Geoposition (в том же пространстве имен Windows.Devices.Geolocation, если не указано иное). Вот код из "Here My Am!":

    var gl = new Windows.Devices.Geolocation.Geolocator();
    
    gl.getGeopositionAsync().done(function (position) {	
    //Сохранить для целей общего доступа	
    lastPosition = { latitude: position.coordinate.latitude,
    longitude: position.coordinate.longitude };	
    }
     

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

    Объект ) содержит два свойства. Первое, это свойство ), который предоставляет свойства ), который содержит свойство ), в частности – класс MapAddress (http://msdn.microsoft.com/library/jj663670.aspx) для того, чтобы узнать адрес по имеющимся координатам.

    Вы можете задать желаемую точность измерений посредством свойства desiredAccuracy средства определения местоположения, которое может принимать значение PositionAccuracy.default или PositionAccuracy.high. Последнее, учтите, создаст большую нагрузку на аппаратное обеспечение. Это может привести к повышению стоимости использования лимитированного сетевого соединения и ускорить разряд батарей, поэтому устанавливайте этой свойство в значение high только тогда, когда это имеет ключевую важность для работы с приложением.

    Средство определения местоположения так же предоставляет свойство ), содержащим такие члены, как ready, initializing, noData, disabled, notInitialized, и notAvailable. Должно быть очевидным, что вы не сможете получить данные от средства определения местоположения, которое находится в состоянии, отличном от ready (готово). Для того, чтобы отследить это, вы можете прослушивать событие средства определения местоположения statusChanged, свойство eventArgs.status которого в вашем обработчике будет содержать PositionStatus. Это полезно, когда вы обнаруживаете, что GPS-приемнику может понадобиться пара секунд на то, чтобы предоставить необходимые данные. Например, вот как используется данное событие в примере "Определение местопол ожения" (http://code.msdn.microsoft.com/windowsapps/Geolocation-2483de66) из Windows SDK:

    geolocator = new Windows.Devices.Geolocation.Geolocator();
    geolocator.addEventListener("statuschanged", onStatusChanged); //Позже не забудьте удалить
    
    function onStatusChanged(e) {
    switch (e.status) {
    // ...
    }
    }
     

    Обратите внимание на то, что PositionStatus и statusChanged отражают чтение данных с GPS-устройства, и на чтение не влияет разрешение на получение данных о местоположении в панели параметров. Как показано в "Here My Am!", приложению не нужно проверять разрешение, пытаясь получить значения параметров, что является особенностью получения данных от устройства.

    Два других интересных свойства средства определения местоположения – это movementThreshold, расстояние в метрах, на которое может переместиться устройство, прежде чем будет вызвана следующая операция чтения данных (это может быть использовано в сценариях с установкой географических границ), и reportInterval, который задается в миллисекундах между попытками чтения данных. Используйте последний параметр умеренно, устанавливайте его в то значение, которое вам действительно нужно, так как следует стремиться к минимизации сетевой активности и активности GPS-датчика. В любом случае, когда средство определения местоположения получает новые данные и обнаруживает, что устройство переместилось за пределы movementThreshold, оно вызывает событие positionChanged, свойство которого eventArgs.position является новым объектом Geoposition. Это так же показано в Сценарии 1 примера об определении местоположения:

    geolocator.addEventListener("positionchanged", onPositionChanged);
    
    function onPositionChanged(e) {
    var coord = e.position.coordinate;
    
    document.getElementById("latitude").innerHTML = coord.latitude;
    document.getElementById("longitude").innerHTML = coord.longitude;
    document.getElementById("accuracy").innerHTML = coord.accuracy;
    }
     

    В случае с movementThreshold и reportInterval, рассматривайте их с позиций нужд приложения, основанных на точности и/или интервале обновления данных о местоположении, которые вы используете. Например, данные о погоде относятся к регионам и могут обновляться лишь раз в час. Поэтому movementThreshold может быть установлено в милях или километрах, reportInterval – на 15, 30, 60 минут или на более длительное время. Приложения работы с картами или предназначенные для автомобилистов, с другой стороны, работают с данными, весьма чувствительными к местоположению и, таким образом, будут иметь гораздо меньшие пороговые значения и более короткие интервалы обновления.

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

    Так же очень важно отметить, что приложения не получают события positionChanged или statusChanged, когда они приостановлены, если только вы не зарегистрировали для этой цели фоновую задачу, запускаемую по таймеру и пользователь не добавил приложение на экран блокировки. Мы поговорим об этом подробнее в лекции 2 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой", и вы так же сможете увидеть, как это работает в Сценарии 3 примера об определении местоположения. Если, однако, вы не используете фоновые задачи или пользователь не поместил приложение на экран блокировки, и вам все еще нужно отслеживать местоположение пользователя, обрабатывайте соответствующим образом событие resuming и обновляйте там эти данные.

    С другой стороны, некоторые сценарии, исопользующие определение местоположения, такие, как навигация, нуждаются в том, чтобы экран устройства был активен (предотвращая автоматическое выключение экрана), даже если пользователь ничего не делает. Для этой цели вы можете использовать класс в частности, его методы requestActive и requestRelease, которые вы можете вызывать в начале и в конце сеанса навигации. Конечно, поддержание экрана во включенном состоянии приводит к потреблению большей энергии батарей, используйте эту возможность только когда это необходимо – когда приложение используется для целей навигации – и не прибегайте к выполнению подобного запроса при запуске приложения. В противном случае ваше приложение, возможно, прослывет в Магазине Windows как неумеренный потребитель энергии!

    Врезка: Определение местоположения в HTML5

    Опытные разработчики HTML/JavaScript могут удивиться, почему WinRT предоставляет API для определения местоположения в то время, как в HTML5 оно уже есть: window.navigator.geolocation и его метод getCurrentPosition , который возвращает объект с координатами. Причина подобного заключается в том, что другие языки, такие, как C#, VisualBasic и C++ не имеют других API для получения подобных данных, что предоставляет выбор разработчикам на HTML/JavaScript. Если посмотреть глубже, то API HTML5 пользуется теми же данными, что и API WinRT, требует объявления той же возможности Расположение (Location) в манифесте, и нуждается в таком же разрешении пользователя, то есть, в основном, эти два API идентичны. Я дал бы API WinRT небольшое преимущество за счет опции movementThreshold , которая помогает приложению экономить электроэнергию и делает возможной простую постановку географических границ. Выполнение тех же действий в HTML5 потребует более частых запросов и приведет к большему потреблению энергии. Во многих сценариях, однако, вы можете использовать либо то, либо другое, с одинаковыми результатами. Однако, как и другие API WinRT, Windows.Devices.Geolocation доступно лишь страницам локального контекста приложений для Магазина Windows. На страницах веб-контекста вы можете пользоваться API HTML5.

    Датчики

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

    Датчики, опять же, это способ понять взаимоотношения устройства и физического мира, окружающего его, и их использование подразумевает ввод данных, так как вы, будучи человеком, можете влиять на эти взаимоотношения, в основном, перемещая устройство в пространстве или меняя их окружение. Датчики так же могут быть использованы как средства прямого ввода информации, вызывая перемещение объектов на экране, вместо использования какой-то формы абстрактного ввода данных наподобие мыши или клавиатуры. Например, вместо того, чтобы использовать абстрактное сочетание клавиш для того, чтобы наклонить игровое поле, вы можете, используя датчики, просто наклонить устройство. Встряхивание устройства, на самом деле, является хорошо известным физическим жестом, который может быть связан с командой вроде "Повтори, будь ты проклят! Почему ты не делаешь то, что я хочу?". Разве мы долгие годы не трясли наши компьютеры или не стучали по ним, когда они не делали то, что нам нужно? А компьютер с датчиками вполне может отреагировать на такое воздействие!

    Вот, какую информацию могут нам сообщить различные датчики:

  • Местоположение (Location). Позиция устройства на Земле (мы обсудили это в предыдущем разделе).
  • Компас (Compass) и ориентация (Orientation). Ориентация устройства по отношению к магнитным полюсам Земли, или относительно нормального положения устройства (простая и сложная ориентация).
  • Инклинометр, креномер (Inclinometer). Предоставляет данные о поворотах устройства относительно поперечной, продольной и вертикальной осей в трехмерном пространстве.
  • Гирометр (Gyrometer). Данные об угловой скорости/вращательном движении устройства в трехмерном пространстве.
  • Акселерометр (Accelerometer). Ускорение устройства (в G) в трехмерном пространстве (X, Y, Z).
  • Окружающий свет (Ambient light). Яркость света в пространстве, окружающем устройство.
  • Эти датчики предоставляет API WinRTЗдесь присутствует и датчик для бесконтактного взаимодействий (proximity) близко расположенных устройств (NFC), который сообщает о том, что устройства находятся близко друг от друга или соприкасаются, но это больше средство для установления сетевого соединения, нежели датчик, похожий на другие. Мы рассмотрим его в лекции 15., некоторые из них созданы программным путем посредством синтеза датчиков (sensor fusion). Это подразумевает получение исходных данных от одного или большего коичества аппаратных датчиков, комбинирование, интерпретацию и представление их в виде, которым может воспользоваться приложение. Как и с указателями, вы можете пользоваться исходными данными, если нужно, но чаще в этом нет необходимости. Например, простой датчик ориентации (Simple Orientation) предоставляет простую интерпретацию расположения устройства по отношению к его расположению по умолчанию, округляя данные до 90-градусных секторов. Полный датчик ориентации, с другой стороны, комбинирует данные гирометра, акселерометра и компаса для того, чтобы предоставить матрицу трехмерной ориентации, которая гораздо более точна, но ориентирована (если можно использовать каламбур!) на более продвинутые сценарии, нежели обычное определение, расположено ли устройство вниз экраном или на боку.

    Так как работа всех этих датчиков очень похожа друг на друга (это сделано специально, за исключением простого датчика ориентации, который не похож на другие), я хочу показать общий шаблон работы с API датчиков вместо детальных примеров для каждого из них. Подобные примеры можно найти среди SDK-примеров "Акселерометр" (http://code.msdn.microsoft.com/windowsapps/Accelerometer-Sensor-Sample-22982671), "Компас" (http://code.msdn.microsoft.com/windowsapps/Compass-Sensor-Sample-0ed09c55), "Гирометр" (http://code.msdn.microsoft.com/windowsapps/Gyrometer-Sensor-Sample-4fe891d9), "Инклинометр" (http://code.msdn.microsoft.com/windowsapps/Inclinometer-Sensor-Sample-0cd0bf84), "Датчик освещенности" (http://code.msdn.microsoft.com/windowsapps/LightSensor-Sample-4477824c) и "Датчик ориентации" (http://code.msdn.microsoft.com/windowsapps/OrientationSensor-sample-0b1732be).

    Шаблон их использования выглядит следующим образом, некоторые особенности приведены в таблице ниже:

    Получение объекта датчика посредством Windows.Devices.Sensors.<sensor>.getDefault().

    Вызов метода getCurrentReading этого объекта для получения данных.

    Для последующего получения данных, настроить свойства объекта minimumReportInterval и reportInterval (и то и другое – в миллисекундах) и прослушивать событие объекта readingchanged. В ответ обработчик события получит объект подходящего типа с прочитанными данными. В случае с определением местоположения, разумно подойтите к установке этих параметров, что поможет увеличить время работы устройства от батарей, предотвращая излишний расход электроэнергии датчиками.

    Название датчика (Windows.Devices.Sensors.) Дополнительные члены Тип возвращаемых данных (Windows.Devices.Sensors) Свойства возвращаемых данных (timestamp Имеет тип Date; остальные являются числами, если не указано иное)
    Акселерометр (http://msdn.microsoft.com/library/windows/apps/windows.devices.sensors.accelerometer.aspx) Событие: shaken (аррументы события содержат лишь свойство timestamp) ) accelerationX (в G), accelerationY, accelerationZ, timestamp
    Компас (http://msdn.microsoft.com/library/windows/apps/windows.devices.sensors.compass.aspx) n/a ) headingMagneticNorth (градусы), headingTrueNorth, timestamp
    Гирометр (http://msdn.microsoft.com/library/windows/apps/windows.devices.sensors.gyrometer.aspx) n/a ) angularVelocityX (градусы в секунду), angularVelocityY, angularVelocityZ, timestamp
    Инклинометр (http://msdn.microsoft.com/library/windows/apps/windows.devices.sensors.inclinometer.aspx) n/a ) pitchDegrees (градусы), rollDegrees (градусы), yawDegrees (градусы), timestamp
    Датчик освещенности (http://msdn.microsoft.com/library/windows/apps/windows.devices.sensors.lightsensor.aspx) n/a ) illuminenceInLux (люксы), timestamp
    Датчик ориентации (http://msdn.microsoft.com/library/windows/apps/windows.devices.sensors.orientationsensor.aspx) n/a ) quaternion, (SensorQuaternion содержит свойства w, x, y, и z) rotationMatrix (Sensor-RotationMatrix содержит свойства m11, m12, m13, m21, m22, m23, m31, m32, m33), timestamp

    Вот образец кода из примера "Гирометр" (js/scenario1.js):

    gyrometer = Windows.Devices.Sensors.Gyrometer.getDefault();
    
    var minimumReportInterval = gyrometer.minimumReportInterval;
    var reportInterval = minimumReportInterval > 16 ? minimumReportInterval : 16;
    gyrometer.reportInterval = reportInterval;
    
    gyrometer.addEventListener("readingchanged", onDataChanged);   
    // Не забудьте удалить при необходимости
    
    function onDataChanged(e) {
    var reading = e.reading;
    document.getElementById("eventOutputX").innerHTML = reading.angularVelocityX.toFixed(2);
    document.getElementById("eventOutputY").innerHTML = reading.angularVelocityY.toFixed(2);
    document.getElementById("eventOutputZ").innerHTML = reading.angularVelocityZ.toFixed(2);
    }	
     

    В случае с датчиком ориентации, понятие кватернион (quaternion) легче всего понять как вращение точки [x,y,z] вокруг одной произвольной оси. В этом – отличие от матрицы вращения, которая представляет вращение по всем трем осям. Математическая основа кватернионов довольно экзотична, она включает в себя геометрические понятия комплексных чисел, математические понятия мнимых чисел, но работать с ними просто и фреймворки наподобие DirectX поддерживают их. Посмотрите пример "Сенсор ориентации" для того, чтобы больше узнать об этом.

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

    В итоге, использование этого датчика выглядит так:

  • Вызовите Windows.Devices.Sensors.SimpleOrientation.getDefault для того, чтобы получить объект.
  • Вызовите getCurrentOrientation для того, чтобы получить результаты чтения данных.
  • Событие orientationChanged используется для последующего получения данных, где eventArgs содержит свойства orientation (результат чтения данных) и timestamp.
  • Свойство ), который содержит следующие свойства:
  • notRotated ("portrait up", книжная-сверху), rotated90DegreesCounterclockwise ("landscape left" альбомная-слева), rotated180DegreesCounterclockwise ("portrait down" книжная-снизу), rotated270DegreesCounterclockwise ("landscape right" альбомная-справа). Обратите внимание на то, что все это не имеет никакого отношения к состояниям просмотра наподобие полноэкранного альбомного или полноэкранного портретного режимов просмотра.
  • faceup, facedown (лицевой сторонй вверх или вниз, только для планшентых устройств).
  • Демонстрацию использования этого датчика вы можете найти в примере "Простой датчик ориентации" (http://code.msdn.microsoft.com/windowsapps/SimpleOrientationSensor-d948ac62).

    Что мы только что изучили

  • Сообщение: "Дизайн приложений, использующих мышь, касания, перо – без дополнительных усилий" соответствует истине, так как работа с указателями и жестами, поступающими от различных устройств, не требует делать различия между способами ввода.
  • Использование встроенных элементов управления – это самый простой способ обработки ввода, но вы так же можете непосредственно обрабатывать события MSPointer* и MSGesture*, если в этом есть необходимость. Так же вы можете передавать события MSPointer в пользовательское средство распознавания жестов (оно инициирует собственные события).
  • Язык касаний Windows 8 включает в себя касание, нажатие и удержание, прокрутку/сдвиг, скольжение по диагонали (для выделения), жесты сжатия-растяжения, вращение, жесты у краев экрана (от верхней, нижней и от боковых сторон). Касание обычно обрабатывается в событии click, в то время как другие требуют создания объекта MSGesture, связи этого объекта с указателем и обработку последовательностей событий MSGesture*, которая используется для реализации манипуляций и перемещения с инерцией.
  • У языка касаний есть эквиваленты, реализуемые с помощью мыши, пера и клавиатуры. В случае с мышью и пером нужно проделать не так много работы (например, передавать события мыши wheel в объект жеста). Поддержка клавиатуры должна быть реализована отдельно, она использует обычные события HTML/JavaScript.
  • Поддержка клавиатуры так же включает в себя соответствующую настройку для работы с программной (экранной) клавиатурой, которая появляется автоматически для полей ввода текста и других элементов, поддерживающих редактирование содержимого. Она автоматически настраивает свой внешний вид в зависимости от типа вводимых данных и смещает содержимое приложения вверх, если нужно, для того, чтобы не перекрыть клавиатурой элемент управления, в который нужно вводить текст. Приложение так же может обрабатывать события, связанные с экранной клавиатурой для предоставления большего удобства, чем в случае с автоматическим поведением системы.
  • API поддержки рукописного ввода предоставляет приложениям средства для записи, сохранения и вывода последовательностей штрихов, оставленных указателем, штрихи так же можно передать средству распознавания рукописного текста.
  • API определения местоположения в WinRT, так же, как похожее API HTML5, предоставляет приложениям доступ к GPS-данным, а так же – события, показывающие, что устройство пересекло ранее заданное пороговое значение в пространстве.
  • API WinRT предоставляеют множество датчиков, которые можно использовать для ввода данных в приложение. В дополнение к датчику определения местоположения, это компас, датчик ориентации, основанный на квадрантах простой датчик ориентации, инклинометр, гиромет, акселерометр и датчик окружающего освещения.
  • Большая часть сенсоров используется по одному и тому же шаблону: получить объект сенсора, получить текущий результат чтения данных и, возможно, прослушивать событие readingChanged. С ними легко работать, что оставляет большую часть сил на поиск креативных способов их применения!
  • Вернуться к учебному плану