최신 입력 방식을 지원하는 Windows 8

Windows 8 앱 개발자 블로그

Windows 8 엔지니어링 팀에서 제공하는 Windows 8용 Metro 스타일 앱 개발의 이해

최신 입력 방식을 지원하는 Windows 8

  • Comments 0

Windows 8에서는 입력 플랫폼을 현대화할 방안을 모색했습니다. 입력 플랫폼을 좀 더 쉽게 개발할 수 있게 하는 동시에 Windows와 앱이 발전함에 따라 새로운 입력 형식을 확장하고 지원할 수 있는 기반을 구축하고자 했습니다.

이를 위해 기본으로 돌아가 입력 플랫폼에 대해 다시 생각하고, 설계 지향점이 되는 핵심 원칙을 강화하는 데 집중했습니다. 이 글에서는 이러한 원칙이 중요한 이유를 설명하고, Windows 8 입력 플랫폼의 장점을 활용하여 뛰어난 앱을 개발하는 방법을 소개합니다.

플랫폼 원칙

Windows는 언제나 이 운영 체제를 기반으로 개발되는 앱이 가장 효과적으로 사용될 수 있도록 발전해 왔습니다. 다양한 앱을 통해 Windows를 접하는 사용자가 많고, Windows 8의 경우에는 그 비중이 더욱 늘어날 것으로 예상됩니다. Windows 8에서는 OS 기능 대부분이 앱 경험 기반으로 제공됩니다. 즉, 앱이 예측 가능한 방식으로 사용자의 조작에 반응하기 때문에 사용자가 편안하게 사용할 수 있습니다. 마찬가지로, 개발 프로세스와 플랫폼도 일관되고 예측 가능한 환경을 제공해야 합니다. Windows 7 하드웨어에서 Windows 8 터치 경험터치 하드웨어와 Windows 8 글에서 하드웨어적인 노력에 대해서 이야기하면서 개발자들의 의견도 다각적으로 살펴보았습니다. 성공적인 플랫폼은 개발하기 용이하고 일관성이 있으면서 친숙한 환경을 통해 신뢰감을 주는 동시에 폭넓은 저변을 확보하여 개발자가 창의력을 십분 발휘할 수 있도록 해야 합니다. 그러한 환경을 구현하기 위해 먼저 다음과 같은 원칙에서 접근했습니다.

저변 확대

개발자의 입장에서는 최대한 많은 장치를 지원할 수 있는 환경이 좋습니다. 입력 플랫폼의 관점에 보면 다양한 입력 유형(마우스, 터치, 펜, 터치패드)과 폼 팩터(슬레이트, 올인원, 데스크톱, 랩톱, 컨버터블)를 폭넓게 지원하는 것을 의미합니다. Windows가 이렇게 널리 사용되고 플랫폼으로서 성공을 거둔 데에는 다양한 폼 팩터와 장치를 지원하는 것도 일조했습니다. 바꿔 말하면 플랫폼은 폼 팩터와 장치를 대상으로 앱을 개발하기 용이해야 한다는 것입니다.

일관성과 신뢰성

개발자에게 일관되고 신뢰할 수 있는 환경을 제공하는 것이 우리의 목표였습니다. 앱 개발자가 사용자에게 새로운 조작 방식 또는 입력 패러다임을 가르칠 필요는 없습니다. 모든 Windows 플랫폼의 일관된 환경을 활용하여 사용자가 이미 익숙한 방법으로 앱과 상호 작용할 수 있게 하여 신뢰감을 주어야 합니다. 그렇게 하면 앱과 에코시스템에 대한 사용자의 신뢰도가 높아져 개발자의 부담도 덜 수 있습니다.

개발의 용이성

너무 복잡하거나 일관성이 없다는 등의 다른 어떤 이유로든 앱을 개발하기 어려운 플랫폼은 성공할 수 없습니다. 때문에 개발의 용이성을 기본 원칙 중 하나로 삼았습니다.

입력 플랫폼 소개

입력 플랫폼은 여러 계층으로 이루어져 있습니다. 맨 아래 계층은 Windows 런타임 입력 API로, 성능과 유연성이 대부분 이 계층에서 제공됩니다. 그 상위에 있는 HTML 및 XAML 프레임워크의 제스처 및 포인터 이벤트는 앱에 적용되는 일반적인 제스처 및 원시 데이터 이벤트를 제공합니다. 마지막으로, 앱 템플릿과 컨트롤은 다양한 상황에서 사용할 수 있는 기본 기능을 제공합니다.

입력 플랫폼의 최상위 계층은 주된 시나리오에 초점을 맞추고 하위 계층은 점진적으로 유연성 및 성능을 더함
그림 1: 입력 플랫폼. 입력 플랫폼의 최상위 계층은 주요 시나리오에 초점을 맞추고 하위 계층은 점진적으로 유연성 및 성능을 더합니다.

대부분의 경우 앱 템플릿과 ListView 또는 SemanticZoom 같은 HTMLXAML 컨트롤만 사용하면 기본 기능은 물론, 일반적인 조작 패턴(예: 터치 언어) 지원, 터치 타기팅, 접근성 지원, 도구 통합 등의 추가 기능까지 구현할 수 있습니다.

특히, 가장 일반적인 터치 사용 시나리오는 이동과 확대/축소이며, 이를 가능하게 하는 것은 Windows 8에서 HTML 및 XAML에 대한 스크롤 보기 컨트롤과 관성, 콘텐츠 경계에서의 바운스, 개발자가 제어할 수 있는 끌기 지점 등의 동작입니다. 이러한 동작은 DirectManipulation이라는 기본 구성 요소를 기반으로 "손가락 동작과 일치"하는 성능을 제공합니다. 대표적인 예로 Windows 8의 시작 메뉴가 이러한 지원 기능을 기반으로 합니다.

게임을 개발하거나, 사용자 지정 컨트롤을 작성하거나, 사용자 지정 시각화를 구현하거나, 3D 조작을 위한 제스처를 만들거나, 원시 데이터가 필요하거나 Windows 8 제스처를 기반으로 하는 작업을 할 때는 먼저 포인터 및 제스처 프레임워크 이벤트(HTMLXAML)를 사용하게 됩니다. 제스처에는 탭하기와 같은 간단한 조작 방식부터 확대/축소, 이동, 회전을 동시에 하는 것과 같은 좀 더 복잡한 것까지 포함됩니다. 잠시 후 자세히 알아볼 포인터 API는 Windows 8에서 마우스, 터치 및 펜 데이터를 간편하게 처리할 수 있도록 합니다. 이러한 이벤트에 액세스함으로써 Windows 8 상호 작용 언어를 앱에 손쉽게 적용할 수 있습니다.

마지막으로, Windows 런타임 입력 API가 스택의 맨 아래 계층을 차지하고 있습니다. 이러한 API(GestureRecognizer, PointerPoint, PointerDevice)는 완벽한 유연성과 제어 기능을 제공하여 원시 입력 데이터 및 관련 속성 전체에 액세스할 수 있게 하고, 완벽한 제스처 및 제스처 구성 세트, 포인터 장치 API 등을 제공합니다. 입력을 위한 WinRT API 표면은 다른 모든 계층에 제공되는 구성 요소 중 하나로, 더욱 풍부하고 뛰어난 성능을 경험할 수 있게 합니다. 이제 마음껏 창의력을 발휘해보십시오!

입력 플랫폼의 기본 개념은 모든 Metro 앱 프레임워크 간에 동일하고 API 표면도 매우 비슷합니다. 때문에 여러 프레임워크에서 공통된 지식을 손쉽게 적용할 수 있습니다. Metro 스타일 HTML 앱을 작성한 후에는 Metro 스타일 XAML 앱에서 손쉽게 입력을 처리하거나 CoreWindow를 기반으로 바로 코드를 작성할 수 있습니다.

다음 섹션에서는 입력 플랫폼의 2개 하위 계층을 중점적으로 살펴보고 플랫폼의 기반이 되는 몇 가지 개념을 소개하며 변화를 주는 것이 왜 중요한 지 살펴봅니다.

포인터 – 입력 통합

마우스는 특히 터치와 비교하면 매우 간단한 입력 장치입니다. 그 이유는 위치와 몇 가지 단추 상태를 기반으로 작동하기 때문입니다. 반면에 터치를 자연스럽게 처리하려면 마우스에서는 볼 수 없었던 복잡성이 더해지게 됩니다. 사용자가 여러 손가락을 동시에 사용할 수 있기 때문에 각각의 입력 흐름을 구분할 방법이 필요합니다. 마우스의 경우 포인터로 특정 대상을 가리킬 수 있지만 시중에 나와 있는 대부분의 터치 장치는 이 기능을 지원하지 않습니다. 또한 터치에는 터치의 접촉 기하(contact geometry)와 같은 앱에 적용되는 흥미로운 속성들이 있습니다. 손가락은 마우스보다 접촉면이 넓고 정확성이 떨어집니다. 마우스, 터치, 펜을 놓고 보면 기존 API와 처리 방식으로는 부족하다는 것이 극명하게 드러납니다.

우리는 입력 방식을 분류할 필요가 있다는 사실을 인식하게 되었습니다. 마우스, 터치, 펜 같은 "포인팅 입력"이 있고, 그 외에도 키보드, 필기 또는 음성 인식과 같은 "텍스트 입력" 등 다양한 입력 방식이 존재합니다. Surface나 Kinect 같은 다른 흥미로운 입력 장치도 살펴보면서 이러한 장치 및 입력 방식들 사이의 유사성을 찾기 시작했고 포인팅 입력을 포인터라는 일관된 API 표면으로 통합하는 방법을 택했습니다. 마우스, 터치, 펜을 일관되고 단순한 환경으로 통합하고 플랫폼의 원칙에 맞추는 것은 패러다임의 변화를 의미했습니다.

아주 기본적인 그리기 앱을 예로 들어보겠습니다. 이 앱에서는 다양한 입력의 down, move 및 up 이벤트를 처리하려고 합니다. 유연하지 못한 플랫폼에서 이 앱이 터치, 펜, 마우스에 반응하도록 하려면 9개의 중복된 이벤트 처리기를 별도로 작성해야 합니다. 이러한 플랫폼에서는 코드가 다음과 같이 시작됩니다.

// BAD! Don’t do this in your code.
class NaivePlatform
{
Dictionary<uint, Polyline> strokes = new Dictionary <uint, Polyline>();
Canvas PaintArea = new Canvas();

void OnMouseDown(MouseEventArgs e) { CommonDownHandler(e.Id, e.Position); }
void OnMouseMove(MouseEventArgs e) { CommonMoveHandler(e.Id, e.Position); }
void OnMouseUp(MouseEventArgs e) { CommonUpHandler(e.Id, e.Position); }

void OnPenDown(PenEventArgs e) { CommonDownHandler(e.Id, e.Position); }
void OnPenMove(PenEventArgs e) { CommonMoveHandler(e.Id, e.Position); }
void OnPenUp(PenEventArgs e) { CommonUpHandler(e.Id, e.Position); }

void OnTouchDown(TouchEventArgs e) { CommonDownHandler(e.Id, e.Position); }
void OnTouchMove(TouchEventArgs e) { CommonMoveHandler(e.Id, e.Position); }
void OnTouchUp(TouchEventArgs e) { CommonUpHandler(e.Id, e.Position); }

void CommonDownHandler(uint pointerId, Point position)
{
// Create a new stroke for this pointer and set its basic properties
var stroke = new Polyline();
stroke.Points.Add(position);
stroke.Stroke = new SolidColorBrush(Colors.Red);
stroke.StrokeThickness = 3;

// Add the stroke to dictionary so we can update it in CommonMoveHandler
strokes[pointerId] = stroke;

// Add the stroke to the canvas so that it is rendered
PaintArea.Children.Add(stroke);
}

void CommonMoveHandler(uint pointerId, Point position)
{
try
{
// Update the stroke associated to this pointer with the new point
strokes[pointerId].Points.Add(position);
}
catch (KeyNotFoundException)
{
// this pointer is not painting - ignore it
}
}

void CommonUpHandler(uint pointerId, Point position)
{
// This stroke is completed, so remove it from the dictionary.
// It will still be rendered because we are not removing it from the canvas.
strokes.Remove(pointerId);
}
}

보다시피 코드가 간결하지도 못하고 복사하여 붙여 넣는 과정에서 오류가 발생하기 쉽습니다. 엄청나게 간략하게 작성한 예가 이정도입니다. 실제 그리기 앱이라면 cancel 이벤트를 처리하고 스트로크를 롤백하는 코드가 추가되어야 합니다. 펜 압력 또는 터치 접촉 기하를 사용하여 잉크에 반영할 경우 일반적인 이벤트 처리기를 사용하기가 훨씬 더 어려워집니다. 원시 입력 데이터 위에 일종의 추상화 계층을 만들어야 할 수 있고, 결국은 포인터와 같은 것을 작성하게 됩니다.

그리기 앱의 포인터 버전에서는 간단한 down, move 및 up 처리기 세트를 사용합니다.

// GOOD! Do this instead of the previous code.
void OnPointerPressed(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
{
// Retrieve current point, in the coordinate system of the painting area
var currentPoint = e.GetCurrentPoint(PaintArea);

// Create new stroke for this pointer and set its basic properties
var stroke = new Windows.UI.Xaml.Shapes.Polyline();
stroke.Points.Add(currentPoint.Position);
stroke.Stroke = new Windows.UI.Xaml.Media.SolidColorBrush(Windows.UI.Colors.Red);
stroke.StrokeThickness = 3;

// Add the stroke to dictionary so we can update it in PointerMoved event handler
strokes[currentPoint.PointerId] = stroke;

// Add the stroke to the painting area so that it is rendered
PaintArea.Children.Add(stroke);
}

void OnPointerMoved(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
{
// Retrieve current point, in the coordinate system of the painting area
var currentPoint = e.GetCurrentPoint(PaintArea);

try
{
// Update the stroke associated to this pointer with the new point
strokes[currentPoint.PointerId].Points.Add(currentPoint.Position);
}
catch (System.Collections.Generic.KeyNotFoundException)
{
// this pointer is not painting - ignore it
}
}

void OnPointerReleased(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
{
// Retrieve current point, in the coordinate system of the painting area
var currentPoint = e.GetCurrentPoint(PaintArea);

// This stroke is completed, remove it from the dictionary.
// It will still be rendered because we are not removing it from PaintArea.
strokes.Remove(currentPoint.PointerId);
}

터치, 펜 및 마우스 입력을 나타내는 포인터 이벤트는 입력 위치, 형식 및 관련 ID와 같은 기본 속성이 모두 동일합니다. 각 방식별로 포인터 이벤트에 연결해야 할 고유한 데이터가 있을 수 있습니다. 예를 들어 펜은 압력 정보나 기울기 정보를 전달할 수 있고, 일반적으로 마우스는 단추 상태 정보를 전달하며, Surface와 같은 장치는 태그 또는 비전 데이터를 포함할 수 있습니다. 우리는 이러한 고유 데이터가 포인터와 함께 노출되도록 하는 기능을 추가했습니다. 터치 입력을 통해 받은 포인터 데이터에는 위치나 포인터 ID와 같은 기본 속성 외에, 터치의 접촉 직사각형 등 터치 방식에만 사용되는 데이터도 포함되어 있습니다.

이러한 데이터의 조합은 대부분의 포인팅 입력 코드를 일반화되고 간결한 형태로 유지하면서도 입력 방식의 차별성이 드러나는 환경으로 만들어 주는 보다 일관된 API 세트라는 가능성을 열었습니다. 가장 대표적인 예가 바로 노트 기록용 앱입니다. 펜으로 잉크를 적용할 수 있고, 터치로 이동과 확대/축소가 가능하며, 기존의 선택 모델을 마우스에 그대로 적용할 수 있습니다. 각 방식은 고유한 특성을 보이면서도 코드는 매우 간결하고 단순하게 유지되는 것입니다.

웹의 경우를 잠깐 살펴보면 포인터가 Metro 스타일 HTML 앱과 브라우저 모두에 노출됩니다(Metro 스타일 및 데스크톱). 물론 이러한 환경은 마우스 이벤트와 같은 W3C 표준을 계속 지원하지만 포인터에 비해 기능이 제한적입니다. 포인터는 앞으로 개발될 새로운 입력 형식을 지원하도록 무리 없이 확장할 수 있고 새로운 입력 방식이 나올 때마다 많은 수의 새로운 개체를 추가하면서 발생하는 군더더기가 없습니다(예: TouchEvent, TouchList 및 Touch). 포인터의 기능에 열광하는 이유도 바로 이 때문입니다.

Win8을 개발하면서 중요하게 고려했던 원칙 중 하나가 빠르고 유연해야 한다는 것이었습니다. 입력 스택이 빠르고 유연하지 않으면 다른 부분도 그럴 수밖에 없습니다. 때문에 우리는 터치 입력 처리에서 발생하는 버퍼링과 지연을 없애기 위해 노력했고 전반적인 터치 관련 스택의 성능을 높이기 위해 많은 노력을 기울였습니다. 이러한 노력 덕분에 Windows 8에서는 빠르고 지연이 없는 입력이 가능해졌습니다. Windows 8 하드웨어의 종단 간 지연 시간, 즉 손가락이 디지타이저와 접촉하는 순간부터 그에 따른 반응으로 디스플레이가 변경되는 시점까지 걸리는 시간은 60 ~ 70ms입니다. 그 중에서 입력 스택이 차지하는 시간은 1 ~ 2ms에 불과합니다.

Windows 8에서의 터치 성능 투자를 분야별로 보여 주는 그래프
그림 2: Windows 8의 터치 성능에 대한 투자 분야

포인터, 그리고 포인터와 제스처 시스템 간의 상호 작용은 성능을 개선하는 데 있어서 중요한 역할을 합니다. 포인터는 Microsoft의 플랫폼 원칙에 본질적으로 부합하고 개발자들이 다양한 입력을 쉽게 처리할 수 있도록 함으로써 자동 연결을 만들고 작성할 코드를 줄이며 개발의 용이성을 높일 수 있습니다.

제스처 – 터치 언어를 앱의 일부로 통합

제스처는 우리에게 이미 익숙합니다. 대부분의 사용자는 웹 브라우저에서 이동하거나 앱을 탭하여 실행하는 데 별다른 어려움을 느끼지 않고 있습니다. 제스처는 Windows 8 상호 작용 언어의 표현 방식입니다. 즉, 사용자의 입력에 반응하여 앱과 시스템의 작업을 자연스럽게 매핑해 주는 역할을 합니다.

제스처 입력은 당연히 포인터를 기반으로 합니다. 대부분의 앱이 제스처를 사용하여 탭, 이동 및 확대/축소를 처리하며, 제스처 감지를 위해 전달하는 경우 외에는 원시 포인터 데이터가 거의 사용되지 않습니다.

입력 플랫폼의 계층의 모든 수준에서는 일관된 제스처 세트를 지원하며, 그러한 세트는 Windows 8 상호 작용 언어를 미러링합니다. 따라서 대개의 경우 앱 사용과 관련한 개념을 사용자에게 가르칠 필요가 없습니다.

지원되는 제스처 세트에 매핑되는 Windows 8 상호 작용 언어를 보여 주는 이미지
그림 3: Windows 8 상호 작용 언어. 상호 작용 언어가 지원되는 제스처 세트에 어떻게 매핑되는지를 알 수 있습니다.

Windows 8에는 기본적으로 모든 앱 포인터 입력을 제공하고 개발자가 제스처 감지에 사용할 데이터 세트, 제스처 감지의 구성 방법 및 출력 처리 방법을 선택하도록 하는 모델을 적용했습니다. 이러한 유연성은 개발자가 원하는 경험을 정확하게 구현할 수 있게 해 줍니다.

Windows 8의 상호 작용 언어에서는 콘텐츠가 "손가락 동작과 일치"하여 동작하는 직접 조작 원칙을 고수했습니다. 조작 방식이 이를 가능하게 했습니다. 플랫폼의 관점에서 보면 제스처는 우리가 인식하고 알림을 제공하는 모든 상호 작용이라고 할 수 있습니다. 조작이란 누르기, 길게 누르기, 탭 등의 다른 제스처와 마찬가지로 제스처의 한 유형입니다. 조작은 변환, 배율 조정 및 회전과 같은 변경의 조합입니다(선형 대수에 익숙한 개발자를 위한 2D 기하학 변환). 예를 들어 새로운 시작 환경에서는 이동할 경우 내부적으로는 조작이 이루어집니다. 두 번째 손가락을 대고 확대/축소를 시작하는 것도 조작에 해당합니다. 뿐만 아니라 손가락 하나를 사용하는 상호 작용을 두 개를 사용하는 상호 작용으로 변환하거나 이동과 확대/축소 간에 변환(또는 두 가지의 조합)하는 것도 쉽게 표현할 수 있습니다.

HTML 프레임워크와 XAML 프레임워크는 개발자를 대신해 제스처 이벤트를 제공하며, 대부분의 경우에는 이러한 이벤트만으로 충분합니다. 추가 구성 옵션과 같은 컨트롤이 추가로 필요한 경우에는 Windows 런타임 GestureRecognizer를 사용합니다. 먼저 다음과 같이 이 런타임을 구성합니다.

C#
// C#
public GestureManager(Windows.UI.Xaml.Shapes.Rectangle target, Windows.UI.Xaml.UIElement parent)
{
// Configure gesture recognizer
gestureRecognizer = new Windows.UI.Input.GestureRecognizer();
gestureRecognizer.GestureSettings =
Windows.UI.Input.GestureSettings.Hold |
Windows.UI.Input.GestureSettings.ManipulationRotate |
Windows.UI.Input.GestureSettings.ManipulationRotateInertia |
Windows.UI.Input.GestureSettings.ManipulationScale |
Windows.UI.Input.GestureSettings.ManipulationScaleInertia |
Windows.UI.Input.GestureSettings.ManipulationTranslateInertia |
Windows.UI.Input.GestureSettings.ManipulationTranslateX |
Windows.UI.Input.GestureSettings.ManipulationTranslateY |
Windows.UI.Input.GestureSettings.RightTap |
Windows.UI.Input.GestureSettings.Tap;

// Register event handlers for gestures
gestureRecognizer.ManipulationStarted += OnManipulationStarted;
gestureRecognizer.ManipulationUpdated += OnManipulationUpdated;
gestureRecognizer.ManipulationInertiaStarting += OnManipulationInertiaStarting;
gestureRecognizer.ManipulationCompleted += OnManipulationCompleted;
gestureRecognizer.Holding += OnHolding;
gestureRecognizer.RightTapped += OnRightTapped;
gestureRecognizer.Tapped += OnTapped;
}

JavaScript
// JS
function GestureManager(target, parent) {
var gestureRecognizer = new Windows.UI.Input.GestureRecognizer;

// Configure GestureRecognizer
gestureRecognizer.gestureSettings =
Windows.UI.Input.GestureSettings.hold |
Windows.UI.Input.GestureSettings.manipulationRotate |
Windows.UI.Input.GestureSettings.manipulationRotateInertia |
Windows.UI.Input.GestureSettings.manipulationScale |
Windows.UI.Input.GestureSettings.manipulationScaleInertia |
Windows.UI.Input.GestureSettings.manipulationTranslateInertia |
Windows.UI.Input.GestureSettings.manipulationTranslateX |
Windows.UI.Input.GestureSettings.manipulationTranslateY |
Windows.UI.Input.GestureSettings.rightTap |
Windows.UI.Input.GestureSettings.tap;

// Register event handlers for gestures
gestureRecognizer.addEventListener('manipulationstarted', onManipulationStarted);
gestureRecognizer.addEventListener('manipulationupdated', onManipulationUpdated);
gestureRecognizer.addEventListener('manipulationcompleted', onManipulationCompleted);
gestureRecognizer.addEventListener('manipulationinertiastarting',
onManipulationInertiaStarting);
gestureRecognizer.addEventListener('manipulationinertiacompleted',
onManipulationInertiaCompleted);
gestureRecognizer.addEventListener('holding', onHolding);
gestureRecognizer.addEventListener('tapped', onTapped);
gestureRecognizer.addEventListener('righttapped', onRightTapped);
}

상호 작용 앱에서 핵심이 되는 것은 제스처입니다. 대부분의 앱에서는 앱에서 요구하는 제스처를 선언하고, 앱에서 인식한 포인터 데이터를 받고, 제스처 감지를 실행하고, 해당 제스처를 처리하는 식으로 흐름이 진행됩니다.

이 코드 조각에서는 입력 형식을 확인하거나 입력 형식별 처리를 실행하지 않고 모든 포인터 데이터가 제스처 감지를 위해 전달되는 것을 알 수 있습니다.

C#

// C#
void OnPointerPressed(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
{
var currentPoint = e.GetCurrentPoint(parent);

// Make target capture the pointer associated to this event
target.CapturePointer(e.Pointer);

// Route the event to the gesture recognizer
gestureRecognizer.ProcessDownEvent(currentPoint);
}

void OnPointerMoved(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
{
// Route the event to the gesture recognizer
// We pass all intermediate points that might have been coalesced
// in a single PointerMove event.
gestureRecognizer.ProcessMoveEvents(e.GetIntermediatePoints(parent));
}

void OnPointerReleased(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
{
var currentPoint = e.GetCurrentPoint(parent);

// Route the event to the gesture recognizer
gestureRecognizer.ProcessUpEvent(currentPoint);

// Release pointer capture on the pointer associated to this event
target.ReleasePointerCapture(e.Pointer);
}

void OnPointerWheelChanged(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
{
var currentPoint = e.GetCurrentPoint(parent);
bool shift = (e.KeyModifiers & Windows.System.VirtualKeyModifiers.Shift) ==
Windows.System.VirtualKeyModifiers.Shift;
bool ctrl = (e.KeyModifiers & Windows.System.VirtualKeyModifiers.Control) ==
Windows.System.VirtualKeyModifiers.Control;

// Route the event to the gesture recognizer
gestureRecognizer.ProcessMouseWheelEvent(currentPoint, shift, ctrl);
}

JavaScript

// JS
function onPointerDown(evt) {
// Make target capture the pointer associated to this event
target.msSetPointerCapture(evt.pointerId);

// Route the event to the gesture recognizer
gestureRecognizer.processDownEvent(evt.getCurrentPoint(parent));
}

function onPointerMove(evt) {
// Route the event to the gesture recognizer
// We pass all intermediate points that might have been coalesced
// in a single PointerMove event.
gestureRecognizer.processMoveEvents(evt.getIntermediatePoints(parent));
}

function onPointerUp(evt) {
// Route the event to the gesture recognizer
gestureRecognizer.processUpEvent(evt.getCurrentPoint(parent));
}

function onWheel(evt) {
// Route the event to the gesture recognizer
gestureRecognizer.processMouseWheelEvent(evt.getCurrentPoint(parent), evt.shiftKey,
evt.ctrlKey);
}

Word와 같은 문서 보기 앱의 경우 이동과 확대/축소가 주로 사용됩니다. 따라서 이 두 가지 조작 구성 요소에 대해 제스처 인식을 구성하고 회전은 무시할 수 있습니다. 포인터 데이터가 주 보기로 전달되면 앱이 제스처 감지 코드로 데이터를 보내고, 제스처 인식 코드에서 조작이 시작되거나 계속되거나(관성 상태로의 전환) 끝났음을 알리는 이벤트를 반환합니다.

다양한 방식과 폼 팩터의 폭넓은 지원을 위한 코딩

포인터라는 개념은 입력 프로그래밍에 대한 우리의 생각을 바꾸어놓았습니다. 포인터는 작성할 코드를 줄여 개발을 용이하게 하고 스토어에 앱을 게시하는 기간을 단축해 주며 여러 입력 장치를 손쉽게 지원할 수 있도록 지원 폭을 넓혀 줍니다. 또한 입력을 처리하는 방식도 간결하게 제시합니다. "터치를 위한 코드만 작성하면 나머지는 시스템에서 자동으로 이루어진다"는 개념을 새로 도입한 것입니다.

터치를 위한 코드, 즉 CFT란 입력 방식에 대한 기존의 개념을 바꾸어 플랫폼의 주요 기본 원칙으로 삼은 결과물입니다. 보다 정확하게 말한다면 "포인터를 위한 코드를 작성하면 터치 및 기본 마우스/펜 동작은 자동으로 따라온다"는 것이 맞을 것입니다. 이러한 CFT 덕분에 정의되지 않은 포인터 이벤트를 처리하는 간단한 코드만 작성하면 세 가지 주요 포인팅 입력 방식에 대한 처리기를 반복적으로 작성하지 않아도 됩니다. 특정 입력 방식에만 적용되는 동작을 만들거나 OS에서 기본적으로 제공되는 동작 외에 다른 동작을 지원하는 것도 가능합니다.

여기서 소개한 각각의 포인터 이벤트 처리기는 실제 환경에서의 CFT를 보여 줍니다. 모든 제스처 샘플의 포인터 처리기는 입력 형식과는 무관하며, 일반적으로 포인터 데이터를 받아 캡처를 설정하고 적중 테스트 또는 기타 상태 관리 작업을 실행한 후 포인터 데이터를 제스처 인식 코드로 전달합니다.

C#

// C#
void OnPointerPressed(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
{
var currentPoint = e.GetCurrentPoint(parent);

// Make target capture the pointer associated to this event
target.CapturePointer(e.Pointer);

// Route the event to the gesture recognizer
gestureRecognizer.ProcessDownEvent(currentPoint);
}

JavaScript

// JS
function onPointerDown(evt) {
// Make target capture the pointer associated to this event
target.msSetPointerCapture(evt.pointerId);

// Route the event to the gesture recognizer
gestureRecognizer.processDownEvent(evt.getCurrentPoint(parent));
}

CFT는 단순히 지원 범위를 확대하고 개발의 용이성을 높이기 위한 것만은 아닙니다. 일관성과 신뢰성에도 직접적인 영향을 미칩니다. 예를 들어 탭 제스처에 대한 제스처 감지를 구성할 경우 세 가지 입력 방식 모두에서 탭을 사용할 수 있습니다. SecondaryTap에 대한 구성에서는 마우스(오른쪽 클릭), 터치(길게 누르기), 펜(길게 누르기 또는 펜 단추를 누른 상태에서 탭)을 통해 입력되는 "오른쪽 클릭 유형의 제스처"를 정의되지 않은 이벤트에 매핑합니다.

다음은 제스처 샘플에서 발췌한 코드로, TapRightTap 제스처 처리기를 보여 줍니다.

C#

// C#
void OnTapped(Windows.UI.Input.GestureRecognizer sender, Windows.UI.Input.TappedEventArgs
args)
{
byte[] rgb = new byte[3];

// Randomly change the color of target
randomGenerator.NextBytes(rgb);
target.Fill = new
Windows.UI.Xaml.Media.SolidColorBrush(Windows.UI.ColorHelper.FromArgb(255,
rgb[0], rgb[1], rgb[2]));
}

void OnRightTapped(Windows.UI.Input.GestureRecognizer sender,
Windows.UI.Input.RightTappedEventArgs args)
{
// Restore original values
target.Fill = initialBrush;
InitManipulationTransforms();
}

JavaScript

// JS
function onTapped(evt) {
target.style.backgroundColor = getNextColorFromColor(target.style.backgroundColor);
}

function onRightTapped(evt) {
// Reset target to its initial state (transform, color)
target.style.backgroundColor = target.initialColor;
target.style.msTransform = target.initialTransform;
}

이러한 이벤트 처리기 어디에서도 포인터 유형은 확인하지 않으며, 개발자의 추가 작업 없이도 바로 다양한 포인터 유형에서 해당 입력을 감지합니다.

결론

우리는 개발자가 플랫폼에서 필요로 하는 기능을 쉽게 찾을 수 있도록 하고자 했습니다. 그런데 입력은 이미 설계되었기 때문에 가장 쉬운 방법은 일관된 Windows 환경을 앱에 활용하는 것이었습니다.

입력 플랫폼은 원칙으로 세운 방법론을 고려하여 개발의 용이성, 일관성 및 신뢰성을 보장하고 폭넓은 지원을 제공하는 것을 목표로 설계되었습니다. 포인터나 CFT 같은 개념을 도입하여 개발 시간을 단축하고 작성할 코드의 양을 줄였습니다. 제스처 감지 덕분에 손쉽게 Windows 8 상호 작용 언어를 앱에 사용하고, 일관되며 익숙한 환경을 사용자에게 제공할 수 있게 되었습니다. 여러 플랫폼과 프레임워크 간에 유사한 개념이 적용되어 개발자에게도 일관성을 제공합니다. 마지막으로 포인터 및 제스처 API에 적용된 CFT 개념은 여러 장치를 손쉽게 지원할 수 있도록 해 줍니다.

우리는 지금까지 Windows 8에 새롭게 적용된 기능에 상당히 고무되어 있습니다. 여러분도 유용하게 사용하기를 바랍니다.

입력 플랫폼에 대한 자세한 내용을 알아보려면 설명서를 참조하거나 샘플을 다운로드하거나 포럼에 질문을 게시하시기 바랍니다.

감사합니다.

- 수석 Windows 프로그램 관리자, Reed Townsend

추가 리소스

링크

유형

주요 내용

빠른 시작: 터치식 입력

빠른 시작

앱에서 터치와 제스처를 처리하는 방법에 대한 개요

입력: DOM 포인터 및 제스처 이벤트 처리 샘플

샘플

포인터에 대한 HTML 지원, HTML5 Canvas 요소 사용, 그리기 기능 구현, 포인터 이벤트 처리

XAML 사용자 입력 이벤트 샘플

샘플

포인터 및 제스처에 대한 XAML 지원, 그리기 기능 구현, 포인터 이벤트 및 캡처, 제스처 이벤트, 조작

입력: C++ 기반의 조작 및 제스처

샘플

Windows 런타임 GestureRecognizer, PointerPointer 및 PointerDevice 클래스 사용, CoreWindow를 기반으로 한 코드 작성

입력: JavaScript 기반의 조작 및 제스처

샘플

간단한 HTML 게임에서의 Winndows 런타임 GestureRecognizer 및 PointerPoint 사용

HTML 프레임워크 포인터 및 제스처 이벤트

문서

onmspointerdown, onmsgesturetap, onmsgesturestart, onmsgestureend 등의 이벤트

XAML 프레임워크 포인터 및 제스처 이벤트

문서

PointerPressed, Tapped, ManipulationStarted 등의 이벤트

GestureRecognizer, PointerPoint, PointerDevice 클래스

문서

포인터 및 제스처에 사용되는 Windows 런타임 클래스에 대한 자세한 설명서

  • Loading...
Leave a Comment
  • Please add 5 and 5 and type the answer here:
  • Post