Вы зашли как: Гость
Опрос
Верите ли вы в скорый выход Surface Andromeda?

Начала Metro-программирования: обработка простых жестов

Напечатать страницу
27.09.2012 12:50 | dronov_va

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

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

Чтобы Metro-приложения успешно работали со всеми устройствами ввода, поддерживаемыми Windows 8, включая мыши, стилусы, перья и сенсорные экраны, разработчики платформы Metro изрядно потрудились. Они сильно переработали систему событий мыши, унаследованную от традиционной модели JavaScript-программирования, с целью привести её в соответствие с новыми веяниями. И, что интересно, новая система событий разрешает использовать старые наработки, что должно понравиться JavaScript-программистам со стажем, таким, как автор этой статьи.

Эта статья посвящена обработке самых простых жестов - нажатия и отпускания кнопки мыши, перемещения мыши по экрану, касания экрана пером, стилусом или пальцем и пр.


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

Все эти события перечислены далее:

  • MSPointerDown - возникает при нажатии кнопки мыши или пера или касании экрана стилусом или пальцем.
  • MSPointerUp - возникает при отпускании кнопки мыши или пера или снятии с экрана стилуса или пальца.
  • MSPointerHover - возникает при перемещении пера без нажатия его кнопки.
  • MSPointerOver - возникает, когда мышь, перо, стилус или палец наводится на какой-либо элемент интерфейса.
  • MSPointerMove - возникает, когда мышь, перо, стилус или палец перемещается внутри границ какого-либо элемента интерфейса.
  • MSPointerOut - возникает, когда мышь, перо, стилус или палец выводится за границы какого-либо элемента управления.
  • MSPointerCancel - возникает при прерывании манипуляции мышью, пером, стилусом или пальцем.
  • MSLostPointerCapture - возникает при отмене режима перехвата событий каким-либо элементом интерфейса. Может возникать вместо события MSPointerUp.


Дадим некоторые пояснения.

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

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

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

Прерывание манипулации мышью или аналогичным устройством ввода выполняется системой в следующих случаях:

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


Именно эти события следует использовать вместо старых - mousedown, mouseup, mouseover, mousemove и mouseout соответственно.

divMouseEventHost.addEventListener("MSPointerDown", function() { . . . });


вместо

divMouseEventHost.addEventListener("mousedown", function() { . . . });


Хотя "старые" события всё ещё поддерживаются ради совместимости и могут быть обработаны, следует помнить, что они возникают только в ответ на манипуляции мышью. Манипуляции другими аналогичными устройствами ввода - пером, стилусом или пальцем - обработаны не будут. Не забываем об этом!


2. Получение сведений о возникшем событии
Функция - обработчик события в любом случае принимает единственный параметр - экземпляр объекта, хранящий сведения о возникшем событии. В случае перечисленных ранее событий это будет экземпляр объекта MSPointerEvent.

Все полезные нам свойства этого объекта перечислены далее:

  • hwTimestamp - время возникновения события в миллисекундах в виде целого числа.
  • pointerType - тип устройства ввода. Для его определения можно использовать значения, хранящиеся в следующих свойствах объекта MSPointerEvent: MSPOINTER_TYPE_TOUCH (палец), MSPOINTER_TYPE_PEN (перо или стилус) и MSPOINTER_TYPE_MOUSE (мышь).
  • pressure - сила нажатия пера от 0 до 255 в виде числа с плавающей точкой.
  • rotation - угол поворота пера от 0 до 359 в градусах в виде числа с плавающей точкой.
  • tiltX - угол наклона пера относительно координатной оси Y-Z от -90 до 90 в градусах в виде целого числа. Положительное значение угла обозначает наклон вправо, отрицательное - наклон влево.
  • tiltY - угол наклона пера относительно координатной оси X-Z от -90 до 90 в градусах в виде целого числа. Положительное значение угла обозначает наклон к пользователю, отрицательное - наклон от пользователя.


Объект MSPointerEvent порождён от объекта MouseEvent и, следовательно, поддерживает все его свойства. Сразу рассмотрим самые полезные из них, чтобы не лазить лишний раз в справочник.

  • altKey - возвращает true, если в данный момент удерживается нажатой клавиша <Alt>, и false, если она не нажата.
  • button - значение, указывающее на нажатую в данный момент кнопку мыши: 0 (левая), 1 (средняя или колёсико прокрутки) или 2 (правая).
  • clientX - горизонтальная координата курсора мыши или точки касания, вычисленная относительно верхнего левого угла части экрана, что отводится под вывод интерфейса приложения, в виде целого числа в пикселах.
  • clientY - вертикальная координата курсора мыши или точки касания, вычисленная относительно верхнего левого угла части экрана, что отводится под вывод интерфейса приложения, в виде целого числа в пикселах.
  • ctrlKey - возвращает true, если в данный момент удерживается нажатой клавиша <Ctrl>, и false, если она не нажата.
  • currentTarget - элемент интерфейса, в котором в данный момент выполняется обработка события (может не совпадать с элементом, в котором это событие изначально возникло).
  • fromElement - элемент интерфейса, с которого был уведён курсор мыши или точка касания.
  • offsetX - горизонтальная координата курсора мыши или точки касания, вычисленная относительно верхнего левого угла элемента интерфейса, в котором возникло событие, в виде целого числа в пикселах.
  • offsetY - вертикальная координата курсора мыши или точки касания, вычисленная относительно верхнего левого угла элемента интерфейса, в котором возникло событие, в виде целого числа в пикселах.
  • pageX - горизонтальная координата курсора мыши или точки касания, вычисленная относительно верхнего левого угла интерфейса приложения, в виде целого числа в пикселах.
  • pageY - вертикальная координата курсора мыши или точки касания, вычисленная относительно верхнего левого угла интерфейса приложения, в виде целого числа в пикселах.
  • relatedTarget - в случае события MSPointerOver элемент интерфейса, с которого был уведён курсор мыши или точка касания, а в случае события MSPointerOut элемент, на который был уведён курсор мыши или точка касания.
  • screenX - горизонтальная координата курсора мыши или точки касания, вычисленная относительно верхнего левого угла всего экрана, в виде целого числа в пикселах.
  • screenY - вертикальная координата курсора мыши или точки касания, вычисленная относительно верхнего левого угла всего экрана, в виде целого числа в пикселах.
  • shiftKey - возвращает true, если в данный момент удерживается нажатой клавиша <Shift>, и false, если она не нажата.
  • target - элемент интерфейса, в котором данное событие изначально возникло.
  • timeStamp - время возникновения события в миллисекундах в виде целого числа.
  • toElement - элемент интерфейса, на который был уведён курсор мыши или точка касания.
  • type - имя события в виде строки.
  • x - горизонтальная координата курсора мыши или точки касания, вычисленная относительно верхнего левого угла ближайшего свободно позиционированного элемента-родителя, в виде целого числа в пикселах.
  • y - вертикальная координата курсора мыши или точки касания, вычисленная относительно верхнего левого угла ближайшего свободно позиционированного элемента-родителя, в виде целого числа в пикселах.


divMouseEventHost.addEventListener("MSPointerDown", function(evt) {
  var sX = evt.screenX;
  var sY = evt.screenY;
  var p = 0;
  if (evt.pointerType == evt.MSPOINTER_TYPE_PEN) {
    p = evt.pressure;
  }
});


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

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

Сначала нам потребуется получить экземпляр объекта Windows.UI.Input.PointerPoint, представляющий устройство ввода - мышь, перо, стилус или палец. Для этого нужно всего лишь вызвать метод getCurrentPoint, передав ему в качестве параметра целочисленный идентификатор устройства ввода; этот метод как раз и вернёт то, что нам нужно, - экземпляр объекта Windows.UI.Input.PointerPoint. Отметим, что метод этот следует вызывать у самого данного объекта, а не у его экземпляра.

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

var oPP = Windows.UI.Input.PointerPoint.getCurrentPoint(evt.pointerId);


Объект Windows.UI.Input.PointerPoint поддерживает свойство properties. Оно хранит экземпляр объекта Windows.UI.Input.PointerPointProperties, представляющий дополнительные сведения об устройстве ввода.

Объект Windows.UI.Input.PointerPointProperties поддерживает очень много свойств. Давайте их рассмотрим.

  • contactRect - возвращает местоположение и размеры рабочей области сенсорного экрана или дигитайзера. Представляет собой экземпляр объекта Windows.Foundation.Rect, поддерживающего свойства x (горизонтальная координата левого верхнего угла рабочей области), y (вертикальная координата), width (ширина рабочей области) и height (её высота). Все эти значение указываются в виде чисел с плавающей точкой в пикселах.
  • isBarrelButtonPressed - возвращает true, если нажата основная кнопка пера или стилуса, и false в противном случае.
  • isCanceled - возвращает true, если манипуляция устройством ввода была прервана системой, и false в противном случае. Манипуляция устройством ввода прерывается при отключении самого устройства, выполнении пользователем действий, которые система не может распознать, изменении ориентации компьютера и переключении экранов в многомониторной конфигурации.
  • isEraser - возвращает true, если пользователь в данный момент манипулирует цифровым ластиком, и false в противном случае.
  • isHorizontalMouseWheel - возвращает true, если пользователь сместил колёсико прокрутки мыши в горизонтальном направлении, и false в противном случае.
  • isInRange - возвращает true, если перо, стилус или палец находится в рабочей области дигитайзера, и false в противном случае.
  • isInverted - возвращает true, если включен режим инверсии пера или стилуса, и false в противном случае.
  • isLeftButtonPressed - возвращает true, если нажата левая кнопка мыши или пера, и false в противном случае.
  • isMiddleButtonPressed - возвращает true, если нажата средняя кнопка или колёсико прокрутки мыши, и false в противном случае.
  • isRightButtonPressed - возвращает true, если нажата правая кнопка мыши или пера, и false в противном случае.
  • isxButton1Pressed - возвращает true, если нажата первая дополнительная кнопка мыши, и false в противном случае.
  • isxButton2Pressed - возвращает true, если нажата вторая дополнительная кнопка мыши, и false в противном случае.
  • mouseWheelDelta - величина, на которую было повёрнуто колёсико прокрутки мыши относительно предыдущего его положения. Эта величина представляет собой целое число.
  • orientation - возвращает угол, на который перо повёрнуто по оси Z (эта ось расположена перпендикулярно поверхности дигитайзера). Этот угол вычисляется против часовой стрелки в градусах и представляет собой число с плавающей точкой от 0 до 359; значение 0 обозначает, что перо ориентировано по направлению к верхней части экрана или дигитайзера.
  • pointerUpdateKind - значение, указывающее на манипуляцию с кнопками устройства ввода, что была выполнена пользователем. Значение этого свойства представляет собой один из элементов перечисления Windows.UI.Input.PointerUpdateKind: leftButtonPressed (нажата левая кнопка), leftButtonReleased (отпущена левая кнопка), rightButtonPressed (нажата правая кнопка), rightButtonReleased (отпущена правая кнопка), middleButtonPressed (нажата средняя кнопка или колёсико прокрутки), middleButtonReleased (отпущена средняя кнопка или колёсико прокрутки), xButton1Pressed (нажата первая дополнительная кнопка), xButton1Released (отпущена первая дополнительная кнопка), xButton2Pressed (нажата вторая дополнительная кнопка) и xButton2Released (отпущена вторая дополнительная кнопка).
  • pressure - сила нажатия пера в виде числа с плавающей точкой от 0 до 1.
  • touchConfidence - возвращает true, если жест был успешно распознан устройством, и false, если он был признан случайным и отвергнут.
  • twist - возвращает угол, на который перо было повёрнуто по оси Z относительно его предыдущего положения. Этот угол вычисляется по часовой стрелке в градусах и представляет собой число с плавающей точкой от 0 до 359.
  • xTilt - угол наклона пера относительно координатной оси Y-Z от -179 до 179 в градусах в виде числа с плавающей точкой. Положительное значение угла обозначает наклон вправо, отрицательное - наклон влево.
  • yTilt - угол наклона пера относительно координатной оси X-Z от -179 до 179 в градусах в виде числа с плавающей точкой. Положительное значение угла обозначает наклон в сторону пользователя, отрицательное - в сторону от пользователя.


divMouseEventHost.addEventListener("MSPointerDown", function(evt) {
  var oPP = Windows.UI.Input.PointerPoint.getCurrentPoint(evt.pointerId);
  if (oPP.properties.isEraser) {
    //Активизирован цифровой ластик
  }
});

к
}
});[/code]

3. Обработка обычных щелчков и нажатий
Но обрабатывать события, перечисленные в параграфе 1, мы будем не очень часто. Гораздо чаще нам придётся реагировать на обычные щелчки левой кнопкой мыши или обычные кратковременные нажатия пером, стилусом или пальцем.

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

[code]btnRun.addEventListener("click", function(evt) { . . . });[/code]
Здесь мы привязываем к событию click кнопки btnRun обработчик, который будет выполнять действие, закрепленное за этой кнопкой.

Так что, как видим, разработчики платформы Metro пошли навстречу "старым" интернет-программистам, собаку съевшим на JavaScript. Теперь они могут без проблем перенести свои уже имеющиеся наработки в среду Metro.


4. Обработка множественных касаний
Подавляющее большинство современных планшетов оснащаются экранами с поддержкой множественных касаний. Самые дешёвые компьютеры подерживают всего два касания; более дорогие могут похвастаться обработкой пяти или даже десяти.

Но как все эти касания распознать и обработать? Очень просто!

Платформа Metro распознаёт каждое касание как отдельное устройство ввода. Это значит, что для каждого касания генерируется отдельный набор событий MSPointerDown, MSPointerMove, MSPointerOver и т. д., и экземпляры объектов, представляющих событие, которые получат функции-обработчики в качестве единственного параметра, будут хранить сведения именно для этого касания.

Осталось выяснить, как отличить одно касание от другого.

Мы уже знаем, что объект MSPointerEvent поддерживает свойство pointerId. Это свойство хранит целочисленный идентификатор устройства ввода. Так вот, эти идентификаторы различны для различных устройств ввода. И, следовательно, для различных касаний!

[code]var arrTouches = [];
divMouseEventHost.addEventListener("MSPointerDown", function(evt) {
var touchExists = false;
for (var i = 0; i < arrTouches.length; i++) {
if (evt.pointerId == arrTouches) {
touchExists = true;
break;
}
}
if (!(touchExists)) {
arrTouches.push(evt.pointerId);
}
});
function removeTouch(evt) {
for (var i = 0; i < arrTouches.length; i++) {
if (evt.pointerId == arrTouches) {
arrTouches.splice(i, 1);
break;
}
}
}
divMouseEventHost.addEventListener("MSPointerUp", removeTouch);
divMouseEventHost.addEventListener("MSPointerCancel", removeTouch);
divMouseEventHost.addEventListener("MSLostPointerCapture", removeTouch);[/code]
Здесь мы привязываем к событию MSPointerDown обработчик, который поместит идентификатор касания, вызвавшего это событие, в массив arrTouches. Но сначала он проверит, присутствует ли уже в массиве такой идентификатор, - это позволит нам избежать засорение массива дублирующимися данными.

Метод push массива (объекта Array) добавляет в массив, у которого был вызван, новый элемент со значением, переданным этому методу в качестве единственного параметра.

Далее мы привязываем к событиям MPPointerUp, MSPointerCancel и MSLostPointerCapture другой обработчик. Он удалит из массива arrTouches идентификатор касания, что вызвало данное событие.

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

Нам может также пригодиться свойство isPrimary объекта MSPointerEvent. Оно возвращает true, если данное касание является самым первым в серии последовательных касаний, и false, если оно уже не первое. (Для мыши, пера и стилуса это свойство всегда возвращает true.)


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

Для обработки жестов, в том числе и "многопальцевых", на высоком уровне платформа Metro предлагает другие инструменты. Используя их, мы можем добавить в приложение поддержку жестов, написав минимум кода. Со временем автор собирается написать статью, рассказывающую об этом.

И ещё. Microsoft официально заявила, что больше не будет применять название "Metro" для обозначения нового класса Windows-приложений, и предостерегла разработчиков от использования этого названия в дальнейшем. Вместо этого рекомендуется использовать наименование "приложения в стиле Windows 8". По мнению автора этой статьи, оно слишком длинное и неуклюжее...

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


Дополнительные материалы



dronov_va, TheVista.Ru Team
Сентябрь 2012

Комментарии

Комментариев нет...
Для возможности комментировать войдите в 1 клик через

По теме

Акции MSFT
105.9 0.00
Акции торгуются с 17:30 до 00:00 по Москве
Мы на Facebook
Мы ВКонтакте
Все права принадлежат © MSInsider.ru (ex TheVista.ru), 2017
Сайт является источником уникальной информации о семействе операционных систем Windows и других продуктах Microsoft. Перепечатка материалов возможна только с разрешения редакции.
Работает на WMS 2.34 (Страница создана за 0.201 секунд (Общее время SQL: 0.013 секунд - SQL запросов: 31 - Среднее время SQL: 0.00041 секунд))