빠른 시작: 포인터(HTML)

[ 이 문서는 Windows 런타임 앱을 작성하는 Windows에서 8.x 및 Windows Phone 8.x 개발자를 대상으로 합니다. Windows 10용으로 개발하는 경우에는 최신 설명서를 참조하세요.]

터치, 마우스 및 펜/스타일러스 조작은 JavaScript를 사용하는 앱에서 포인터 입력으로 수신, 처리 및 관리됩니다.

Windows 8.1용 업데이트: Windows 8.1에는 다양한 업데이트와 포인터 입력 API의 개선 사항이 포함되어 있습니다. 자세한 내용은 Windows 8.1의 API 변경 사항을 참조하세요.

JavaScript를 사용하여 앱을 처음 개발하는 경우: 다음 항목을 검토하여 여기서 설명하는 기술에 대해 알아보세요.

JavaScript를 사용하여 첫 Windows 스토어 앱 만들기

JavaScript로 작성한 Windows 스토어 앱용 로드맵

이벤트에 대한 자세한 내용은 빠른 시작: HTML 컨트롤 추가 및 이벤트 처리를 참조하세요.

앱 기능 전체 프로세스:

앱 기능 전체 프로세스 시리즈의 일부로 이 기능을 자세히 살펴보세요.

사용자 조작 전체 프로세스(HTML)

사용자 조작 사용자 지정 전체 프로세스(HTML)

사용자 환경 지침:

플랫폼 컨트롤 라이브러리(HTMLXAML)는 표준 조작, 애니메이션 물리적 효과 및 시각적 피드백을 비롯하여 Windows 사용자 조작 환경 전체를 제공합니다. 사용자 지정 조작 지원이 필요 없는 경우에는 이러한 기본 제공 컨트롤을 사용하세요.

플랫폼 컨트롤이 충분하지 않으면 다음 사용자 조작 지침을 통해 입력 모드 전체에서 멋진 몰입형 조작 환경을 일관되게 제공합니다. 이러한 지침은 주로 터치식 입력을 중심으로 다루지만 터치 패드, 마우스, 키보드 및 스타일러스 입력에도 관련이 있습니다.

샘플: 이 기능의 작동 방식을 보려면 앱 샘플을 참조하세요.

사용자 조작 사용자 지정 전체 프로세스 샘플

HTML 스크롤, 이동 및 확대/축소 샘플

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

입력: 인스턴스화 가능한 제스처 샘플

입력: 잉크 샘플

입력: 조작 및 제스처(JavaScript) 샘플

입력: 간단한 잉크 샘플

목표: 포인터 입력을 수신하고 처리하는 방법에 대해 살펴봅니다.

사전 요구 사항

사용자가 JavaScript용 Windows 라이브러리 템플릿을 사용하고 JavaScript로 작성된 기본 앱을 만들 수 있다고 가정합니다.

이 자습서를 완료하려면 다음을 수행해야 합니다.

완료 시간: 30 분.

지침

포인터 입력이란?

마우스, 펜/스타일러스 및 터치 입력을 추상 포인터 입력으로 통합하여 사용 중인 입력 장치 유형과는 별개로 앱의 사용자 조작을 처리할 수 있습니다.

포인터 개체는 입력 장치(예: 마우스, 펜/스타일러스, 한 손가락 또는 여러 손가락)를 통한 고유한 단일 입력 "접촉"(PointerPoint)을 나타냅니다. 시스템에서는 처음 접촉이 감지될 때 포인터를 만들고, 포인터가 감지 범위를 벗어나거나(분리) 취소될 때 포인터를 삭제합니다. 여러 장치 또는 멀티 터치 입력의 경우 각 접점이 하나의 고유한 포인터로 간주됩니다.

다양한 장치에서 직접 입력 데이터를 가로챌 수 있는 포인터 기반 입력 API는 다양합니다. 위치 및 장치 유형과 같은 일반 정보, 압력 및 접촉 기하와 같은 확장된 정보를 가져오기 위해 포인터 이벤트를 처리할 수 있습니다. 앱이 다양한 방법으로 서로 다른 입력 모드에 응답해야 하는 경우가 많기 때문에 사용자가 입력하는 마우스 단추 또는 사용자의 펜 지우개 사용 여부와 같은 특정 장치 속성도 사용할 수 있습니다. 예를 들어 터치 방식에서 이동 및 스크롤과 같은 조작을 지원하도록 할 수 있지만 마우스 및 펜/스타일러스는 잉크 및 그리기와 같은 정밀한 작업에 좀 더 적합합니다. 앱에서 입력 장치와 해당 접근 권한 값을 구분해야 할 경우에는 빠른 시작: 입력 장치 식별을 참조하세요.

조작 지원을 직접 구현할 경우 사용자들은 앱의 UI 요소와의 직접적 조작이 이루어지는 직관적인 환경을 기대한다는 점에 유의하세요. 프레임워크 컨트롤에서 항목들을 일관되고 검색 가능하게 유지할 수 있도록 사용자 지정 조작을 모델링할 것을 권장합니다. 요구 사항이 명확하게 잘 정의되어 있으며 기본 제스처가 시나리오를 지원하지 않는 경우에만 사용자 지정 조작을 만드세요.

UI 만들기

다음 예에서는 직사각형(target)을 포인터 입력을 위한 대상 개체로 사용합니다. 대상의 색상은 포인터 상태가 변경될 때 변경됩니다.

각 포인터에 대한 상세 정보는 포인터에 인접해 있는 부동 텍스트 블록에 표시되며 포인터의 움직임을 따릅니다. 특정 포인터 이벤트는 화면의 오른쪽 끝에 보고됩니다. 다음 스크린샷은 이 예제에 대한 UI를 보여 줍니다.

예제 앱 UI 스크린샷

다음은 HTML 예문입니다.

참고  Windows 스토어 앱

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>PointerInput_Universal.Windows</title>

    <!-- WinJS references -->
    <link href="//Microsoft.WinJS.2.0/css/ui-dark.css" rel="stylesheet" />
    <script src="//Microsoft.WinJS.2.0/js/base.js"></script>
    <script src="//Microsoft.WinJS.2.0/js/ui.js"></script>

    <!-- PointerInput_Universal.Windows references -->
    <link href="/css/default.css" rel="stylesheet" />
    <script src="/js/default.js"></script>
</head>
<body class="windows">
    <div id="grid">
        <div id="targetContainer">
            <div id="target"></div>
        </div>
        <div id="bottom">
        </div>
        <div id="eventLog"></div>
    </div>
</body>
</html>

참고  Windows Phone 스토어 앱

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>PointerInput_Universal.WindowsPhone</title>

    <!-- WinJS references -->
    <!-- At runtime, ui-themed.css resolves to ui-themed.light.css or ui-themed.dark.css 
    based on the user’s theme setting. This is part of the MRT resource loading functionality. -->
    <link href="/css/ui-themed.css" rel="stylesheet" />
    <script src="//Microsoft.Phone.WinJS.2.1/js/base.js"></script>
    <script src="//Microsoft.Phone.WinJS.2.1/js/ui.js"></script>

    <!-- PointerInput_Universal.Phone references -->
    <link href="/css/default.css" rel="stylesheet" />
    <script src="/js/default.js"></script>
</head>
<body class="phone">
    <div id="grid">
        <div id="targetContainer">
            <div id="target"></div>
        </div>
        <div id="bottom">
        </div>
        <div id="eventLog"></div>
    </div>
</body>
</html>

다음은 CSS(CSS 스타일시트) 예문입니다.

참고  이동 또는 확대/축소 조작을 수행하는 동안에는 포인터 이벤트가 종료되지 않습니다. CSS 속성 msTouchAction, overflow-ms-content-zooming을 통해 영역에서 이동 및 확대/축소를 사용하지 않도록 설정할 수 있습니다.

 

body {
    overflow: hidden;
    position: relative;
}

#grid {
    display: -ms-grid;
    height: 100vh; /* 100% of viewport height */
    -ms-grid-columns: 4fr 1fr; /* 2 columns */
    -ms-grid-rows: 1fr 320px 1fr;  /* 3 rows */
    /*touch-action: none;*/ /* Disable panning and zooming */
}
#targetContainer {
    border:solid;
    border-width:thin;
    border-color: red;
    -ms-grid-row: 2;
    -ms-grid-column: 1;
    -ms-grid-row-align: center;
    -ms-grid-column-align: center;
    /*touch-action: none; /* Disable panning and zooming */*/
}
#eventLog {
    -ms-grid-row: 1;
    -ms-grid-column: 2; 
    -ms-grid-row-span: 3;
    padding-right: 10px;
    background-color: black;
    color: white;
}
.phone #target {
    width: 200px;
    height: 300px;
    border: none;
    padding: 0px;
    margin: 0px;
    -ms-transform-origin: 0% 0%;
    /*touch-action: none; /* Disable panning and zooming */*/
}
.windows #target {
    width: 400px;
    height: 200px;
    border: none;
    padding: 0px;
    margin: 0px;
    -ms-transform-origin: 0% 0%;
    touch-action: none; /* Disable panning and zooming */
}

포인터 이벤트 수신

대부분의 경우 선택한 언어 프레임워크에서 포인터 이벤트 처리기의 이벤트 인수를 통해 포인터 정보를 가져오는 것이 좋습니다.

이벤트 인수가 앱에 필요한 포인터 정보를 표시하지 않으면 getCurrentPointgetIntermediatePoints 메서드 또는 currentPointintermediatePoints 속성을 통해 이벤트 인수의 확장된 포인터 데이터에 액세스할 수 있습니다. 포인터 데이터의 컨텍스트를 지정할 수 있으므로 getCurrentPointgetIntermediatePoints 메서드를 사용하는 것이 좋습니다.

다음 스크린샷은 이 예제의 마우스 포인터 정보가 있는 대상 영역을 보여 줍니다.

포인터 대상 영역의 스크린샷

여기서는 대상 영역에 대한 이벤트 수신기 및 화면 위치를 설정합니다.

먼저 전역 변수를 선언하고, 대상과 포인터 상세 정보 영역을 초기화하고 이벤트 로거를 식별합니다.

// For this example, we track simultaneous contacts in case the 
// number of contacts has reached the maximum supported by the device.
// Depending on the device, additional contacts might be ignored 
// (PointerPressed not fired). 
var numActiveContacts = 0;

// The input target.
var target;

// Target background colors corresponding to various pointer states.
var pointerColor = {
    hover: "rgb(255, 255, 102)",
    down: "rgb(0, 255, 0)",
    up: "rgb(255, 0, 0)",
    cancel: "rgb(0,0,0)",
    out: "rgb(127,127,127)",
    over: "rgb(0,0,255)"
};

// The event log (updated on each event).
var eventLog;

function initialize() {
    /// <summary>Set up the app.</summary>
    eventLog = document.getElementById("eventLog");
    target = document.getElementById("target");
    setTarget();
}

다음으로 대상 개체를 설정하고 대상에 대해 다양한 포인터 이벤트 수신기를 선언합니다.

function setTarget() {
    /// <summary>Set up the target and interaction event handlers.</summary>

    // Initial color of target.
    target.style.backgroundColor = pointerColor.out;

    // Expando dictionary property to track active contacts. 
    // An entry is added during pointer down/hover/over events 
    // and removed during pointer up/cancel/out/lostpointercapture events.
    target.pointers = [];

    // Declare pointer event handlers.
    target.addEventListener("pointerdown", onPointerDown, true);
    target.addEventListener("pointerover", onPointerOver, true);
    target.addEventListener("pointerup", onPointerUp, true);
    target.addEventListener("pointerout", onPointerOut, true);
    target.addEventListener("pointercancel", onPointerCancel, true);
    target.addEventListener("lostpointercapture", onLostPointerCapture, true);
    target.addEventListener("pointermove", onPointerMove, true);
    target.addEventListener("wheel", onMouseWheel, false);
}

마지막으로 포인터 상세 정보 영역을 설정합니다.

function createInfoPop(e) {
    /// <summary>
    /// Create and insert DIV into the DOM for displaying pointer details.
    /// </summary>
    /// <param name="e" type="Event">The event argument.</param>
    var infoPop = document.createElement("div");
    infoPop.setAttribute("id", "infoPop" + e.pointerId);

    // Set screen position of DIV.
    var transform = (new MSCSSMatrix()).translate(e.offsetX + 20, e.offsetY + 20);
    infoPop.style.msTransform = transform;
    target.appendChild(infoPop);

    infoPop.innerText = queryPointer(e);
}

function updateInfoPop(e) {
    /// <summary>
    /// Update pointer details in UI.
    /// </summary>
    /// <param name="e" type="Event">The event argument.</param>
    var infoPop = document.getElementById("infoPop" + e.pointerId);
    if (infoPop === null)
        return;

    // Set screen position of DIV.
    var transform = (new MSCSSMatrix()).translate(e.offsetX + 20, e.offsetY + 20);
    infoPop.style.msTransform = transform;
    infoPop.innerText = queryPointer(e);
}

포인터 이벤트 처리

다음으로 UI 피드백을 사용하여 기본 포인터 이벤트 처리기에 대해 살펴봅니다.

  • 이 처리기는 포인터 접촉 이벤트(아래로, 누름) 이벤트를 관리합니다. 이벤트 로그에 이벤트를 추가하고, 관심있는 포인터를 추적하는 데 사용하는 포인터 배열에 포인터를 추가하고, 포인터 상세 정보를 표시합니다.

    참고  pointerdownpointerup 이벤트는 항상 쌍으로 발생하지는 않습니다. 앱은 포인터 다운 작업(예: pointerup, pointerout, pointercancellostpointercapture)을 완료할 수도 있는 이벤트를 수신하고 처리해야 합니다.

     

    function onPointerDown(e) {
        /// <summary>
        /// Occurs for mouse when at least one mouse button is pressed or 
        /// for touch and pen when there is physical contact with the digitizer.
        /// For input devices that do not support hover, the pointerover event is 
        /// fired immediately before the pointerdown event.  
        /// Here, we  filter pointer input based on the first pointer type detected. 
        /// </summary>
        /// <param name="e" type="Event">The event argument.</param>
    
        // pointerdown and pointerup events do not always occur in pairs. 
        // Listen for and handle any event that might conclude a pointer down action 
        // (such as pointerup, pointerout, pointercancel, and lostpointercapture).
        //
        // For this example, we track the number of contacts in case the 
        // number of contacts has reached the maximum supported by the device.
        // Depending on the device, additional contacts might be ignored 
        // (PointerPressed not fired). 
    
        // Prevent the next handler in the hierarchy from receiving the event.
        e.cancelBubble = true;
    
        // Check if the number of supported contacts is exceeded.
        var touchCapabilities = new Windows.Devices.Input.TouchCapabilities();
        if ((touchCapabilities.touchPresent != 0) & (numActiveContacts > touchCapabilities.contacts)) {
            return;
        }
    
        // Update event details and target UI.
        eventLog.innerText += "\nDown: " + e.pointerId;
        target.style.backgroundColor = pointerColor.down;
    
        // Check if pointer already exists (if hover/over occurred prior to down).
        for (var i in target.pointers) {
            if (target.pointers[i].id = e.pointerId) {
                return;
            }
        }
    
        // Push new pointer Id onto expando target pointers array.
        target.pointers.push({ id: e.pointerId, type: e.pointerType });
    
        // Ensure that the element continues to receive PointerEvents 
        // even if the contact moves off the element. 
        // Capturing the current pointer can improve usability by reducing 
        // the touch precision required when interacting with an element.
        // Note: Only the assigned pointer is affected. 
        target.setPointerCapture(e.pointerId);
    
        // Display pointer details.
        createInfoPop(e);
    }
    
  • 이 처리기는 접촉 지점에 있고 대상의 경계 안으로 이동하는 포인터에 대한 포인터 진입(위로) 이벤트를 관리합니다. 이벤트 로그에 이벤트를 추가하고, 포인터 배열에 포인터를 추가하고, 포인터 상세 정보를 표시합니다.

    접촉 지점에 있지 않지만 대상의 경계 내에 있는 포인터(일반적으로 펜/스타일러스 장치)의 가리킨 상태를 처리하려면 pointermove 이벤트를 참조하세요.

    function onPointerOver(e) {
        /// <summary>
        /// Occurs when a pointer is detected within the hit test boundaries 
        /// of an element.
        /// Also occurs prior to a pointerdown event for devices that do not 
        /// support hover.  
        /// This event type is similar to pointerenter, but bubbles. 
        /// See the pointermove event for handling the hover state of a pointer 
        /// that is not in contact but is within the boundary of the target 
        /// (typically a pen/stylus device). 
        /// </summary>
        /// <param name="e" type="Event">The event argument.</param>
    
        // Prevent the next handler in the hierarchy from receiving the event.
        e.cancelBubble = true;
    
        // Update event details and target UI.
        eventLog.innerText += "\nOver: " + e.pointerId;
    
        if (target.pointers.length === 0) {
            // Change background color of target when pointer contact detected.
            if (e.getCurrentPoint(e.currentTarget).isInContact) {
                // Pointer down occured outside target.
                target.style.backgroundColor = pointerColor.down;
            } else {
                // Pointer down occured inside target.
                target.style.backgroundColor = pointerColor.over;
            }
        }
    
        // Check if pointer already exists.
        for (var i in target.pointers) {
            if (target.pointers[i].id = e.pointerId) {
                return;
            }
        }
    
        // Push new pointer Id onto expando target pointers array.
        target.pointers.push({ id: e.pointerId, type: e.pointerType });
    
        // Ensure that the element continues to receive PointerEvents 
        // even if the contact moves off the element. 
        // Capturing the current pointer can improve usability by reducing 
        // the touch precision required when interacting with an element.
        // Note: Only the assigned pointer is affected. 
        target.setPointerCapture(e.pointerId);
    
        // Display pointer details.
        createInfoPop(e);
    }
    
  • 다음 처리기는 포인터 이동 이벤트를 관리합니다. 이벤트를 이벤트 로그에 추가하고 포인터 세부 정보를 업데이트합니다. 가리키기의 경우 또한 포인터를 포인터 배열에 추가합니다.

    MSPointerHover는 Windows 8.1에서 사용되지 않습니다. 가리킨 상태를 확인하려면 pointermoveIsInContact 포인터 속성을 사용하세요.

    참고   여러 번의 동시 마우스 단추 클릭도 이 처리기에서 처리됩니다. 마우스 입력이 먼저 감지되면 마우스 입력이 할당된 단일 포인터와 연결됩니다. 조작 중에 추가 마우스 단추(왼쪽, 휠 또는 오른쪽)를 클릭하면 포인터 눌림 이벤트를 통해 해당 단추와 포인터 간에 보조 연결이 생성됩니다. 포인터 해제 이벤트는 조작과 연결된 마지막 마우스 단추(초기 단추가 아님)가 해제될 때만 발생됩니다. 이 독점적인 연결 때문에 다른 마우스 단추 클릭은 포인터 이동 이벤트를 통해 라우팅됩니다.

     

     function onPointerMove(e) {
         /// <summary>
         /// Occurs when a pointer moves within the hit test boundaries 
         /// of an element.
         /// </summary>
         /// <param name="e" type="Event">The event argument.</param>
    
         // NOTE: Multiple, simultaneous mouse button inputs are processed here.
         // Mouse input is associated with a single pointer assigned when 
         // mouse input is first detected. 
         // Clicking additional mouse buttons (left, wheel, or right) during 
         // the interaction creates secondary associations between those buttons 
         // and the pointer through the pointer pressed event. 
         // The pointer released event is fired only when the last mouse button 
         // associated with the interaction (not necessarily the initial button) 
         // is released. 
         // Because of this exclusive association, other mouse button clicks are 
         // routed through the pointer move event.  
    
         // Prevent the next handler in the hierarchy from receiving the event.
         e.cancelBubble = true;
    
         if (e.pointerType == "mouse") {
             // Mouse button states are extended PointerPoint properties.
             var pt = e.getCurrentPoint(e.currentTarget);
             var ptProperties = pt.properties;
             if (ptProperties.isLeftButtonPressed) {
                 eventLog.innerText += "\nLeft button: " + e.pointerId;
             }
             if (ptProperties.isMiddleButtonPressed) {
                 eventLog.innerText += "\nWheel button: " + e.pointerId;
             }
             if (ptProperties.isRightButtonPressed) {
                 eventLog.innerText += "\nRight button: " + e.pointerId;
             }
         }
         // Handle hover state of a pointer that is not in contact but is within 
         // the boundary of the target (typically a pen/stylus device). 
         if (e.pointerType == "pen") {
             var pt = e.getCurrentPoint(e.currentTarget);
             if (pt.isInContact == false) {
                 // Update event details and target UI.
                 target.style.backgroundColor = pointerColor.hover;
                 eventLog.innerText = "\nHover: " + e.pointerId;
    
                 // Check if pointer already exists.
                 for (var i in target.pointers) {
                     if (target.pointers[i].id = e.pointerId) {
                         updateInfoPop(e);
                         return;
                     }
                 }
    
                 target.pointers.push({ id: e.pointerId, type: e.pointerType });
    
                 // Ensure that the element continues to receive PointerEvents 
                 // even if the contact moves off the element. 
                 // Capturing the current pointer can improve usability by reducing 
                 // the touch precision required when interacting with an element.
                 // Note: Only the assigned pointer is affected. 
                 target.setPointerCapture(e.pointerId);
             }
         }
    
         // Display pointer details.
         updateInfoPop(e);
     }
    
  • 다음 처리기는 마우스 휠 이벤트(회전)를 관리합니다. 이벤트 로그에 이벤트를 추가하고, 포인터 배열에 포인터를 추가(필요한 경우)하고, 포인터 상세 정보를 표시합니다.

    function onMouseWheel(e) {
        /// <summary>  
        /// Occurs when the mouse wheel is rotated. 
        /// </summary> 
        /// <param name="e" type="Event">The event argument.</param>
        // Check if a mouse pointer already exists.
        for (var i in target.pointers) {
            // Ensure existing pointer type registered with pointerover is mouse. 
            if (target.pointers[i].type === "mouse") {
                e.pointerId = target.pointers[i].id;
                break;
            }
        }
        eventLog.innerText += "\nMouse wheel: " + e.pointerId;
        // For this example, we fire a corresponding pointer down event.
        onPointerDown(e);
    }
    
  • 다음 처리기는 포인터 출발(up) 이벤트를 관리합니다. 이벤트 로그에 이벤트를 추가하고, 포인터 배열에서 포인터를 제거하고, 포인터 상세 정보를 업데이트합니다.

    function onPointerUp(e) {
        /// <summary>
        /// Occurs for mouse at transition from at least one button pressed 
        /// to no buttons pressed.
        /// Occurs for touch and pen when contact is removed from the digitizer. 
        /// For input devices that do not support hover, the pointerout event 
        /// is fired immediately after the pointerup event.  
        /// </summary>
        /// <param name="e" type="Event">The event argument.</param>
    
        // Prevent the next handler in the hierarchy from receiving the event.
        e.cancelBubble = true;
    
        // Update event details.
        eventLog.innerText += "\nUp: " + e.pointerId;
    
        // If event source is mouse pointer and the pointer is still 
        // over the target, retain pointer and pointer details.
        // Return without removing pointer from pointers dictionary.
        // For this example, we assume a maximum of one mouse pointer.
        if ((e.pointerType === "mouse") &
            (document.elementFromPoint(e.x, e.y) === target)) {
            target.style.backgroundColor = pointerColor.up;
            return;
        }
    
        // Ensure capture is released on a pointer up event.
        target.releasePointerCapture(e.pointerId);
    
        // Remove pointer from pointers dictionary.
        var targetPointers = target.pointers;
        for (var i in targetPointers) {
            if (target.pointers[i].id === e.pointerId) {
                target.pointers.splice(i, 1);
                var pointerInfoPop = document.getElementById("infoPop" + e.pointerId);
                if (pointerInfoPop === null)
                    return;
                pointerInfoPop.removeNode(true);
            }
        }
    
        // Update target UI.
        if (target.pointers.length === 0) {
            target.style.backgroundColor = pointerColor.up;
        }
    }
    
  • 다음 처리기는 포인터 출발(out) 이벤트를 관리합니다. 이벤트 로그에 이벤트를 추가하고, 포인터 배열에서 포인터를 제거하고, 포인터 상세 정보를 업데이트합니다.

    function onPointerOut(e) {
        /// <summary>
        /// Occurs when a pointer (in contact or not) moves out of the 
        /// target hit test boundary, after a pointerup event for a device 
        /// that does not support hover, and after a pointercancel event. 
        /// This event type is similar to pointerleave, but bubbles.  
        /// Note: Pointer capture is maintained until pointer up event.
        /// </summary>
        /// <param name="e" type="Event">The event argument.</param>
    
        // Prevent the next handler in the hierarchy from receiving the event.
        e.cancelBubble = true;
    
        // Update event details.
        eventLog.innerText += "\nPointer out: " + e.pointerId;
    
        // Remove pointer from pointers dictionary.
        var targetPointers = target.pointers;
        for (var i in targetPointers) {
            if (target.pointers[i].id === e.pointerId) {
                target.pointers.splice(i, 1);
                var pointerInfoPop = document.getElementById("infoPop" + e.pointerId);
                if (pointerInfoPop === null)
                    return;
                pointerInfoPop.removeNode(true);
    
                // Update target UI.
                if (target.pointers.length === 0) {
                    target.style.backgroundColor = pointerColor.out;
                }
            }
        }
    }
    
  • 다음 처리기는 포인터 취소 이벤트를 관리합니다. 이벤트 로그에 이벤트를 추가하고, 포인터 배열에서 포인터를 제거하고, 포인터 상세 정보를 업데이트합니다.

    function onPointerCancel(e) {
        /// <summary>
        /// Occurs when a pointer is removed.
        /// The app will not receive subsequent events for that pointer, including pointerup.  
        /// </summary>
        /// <param name="e" type="Event">The event argument.</param>
    
        // A pointer can be canceled as a result of one of the following:
        //    - A touch contact is canceled when a pen is detected.
        //    - More than 100ms has passed since the device reported
        //      an active contact.
        //    - The desktop is locked or the user logged off. 
        //    - The number of simultaneous contacts exceeds the number 
        //      supported by the device.
        //    - The system has determined that a pointer is unlikely to 
        //      continue to produce events (for example, due to a hardware event).
        //    - After a pointerdown event, the pointer is subsequently used to 
        //      manipulate the page viewport (for example, panning or zooming).  
    
        // Prevent the next handler in the hierarchy from receiving the event.
        e.cancelBubble = true;
    
        // Update event details.
        eventLog.innerText += "\nPointer canceled: " + e.pointerId;
    
        // Ensure capture is released on a pointer cancel event.
        target.releasePointerCapture(e.pointerId);
    
        // Update target UI.
        if (target.pointers.length === 0) {
            target.style.backgroundColor = pointerColor.cancel;
        }
    
        // Remove pointer from pointers dictionary.
        var targetPointers = target.pointers;
        for (var i in targetPointers) {
            if (target.pointers[i].id === e.pointerId) {
                target.pointers.splice(i, 1);
                var pointerInfoPop = document.getElementById("infoPop" + e.pointerId);
                if (pointerInfoPop === null)
                    return;
                pointerInfoPop.removeNode(true);
    
                // Update target UI.
                if (target.pointers.length === 0) {
                    target.style.backgroundColor = pointerColor.out;
                }
            }
        }
    }
    
  • 다음 처리기는 손실된 포인터 캡처 이벤트를 관리합니다. 이벤트 로그에 이벤트를 추가하고, 포인터 배열에서 포인터를 제거하고, 포인터 상세 정보를 업데이트합니다.

    참고  lostpointercapturepointerup 대신 발생할 수 있습니다. 포인터 캡처는 사용자 조작으로 인해 손실되거나, 다른 포인터를 프로그래밍 방식으로 캡처했거나 현재 포인터 캡처를 고의로 해지했기 때문에 손실될 수 있습니다.

     

    function onLostPointerCapture(e) {
        /// <summary>
        /// Occurs after pointer capture is released for the pointer.  
        /// </summary>
        /// <param name="e" type="Event">The event argument.</param>
    
        // lostpointercapture can fire instead of pointerup. 
    
        // Pointer capture can be lost as a result of one of the following:
        //    - User interactions
        //    - Programmatic caputre of another pointer
        //    - Captured pointer was deliberately released
    
        // Prevent the next handler in the hierarchy from receiving the event.
        e.cancelBubble = true;
    
        // Update event details.
        eventLog.innerText += "\nLost pointer capture: " + e.pointerId;
    
        // We need the device type to handle lost pointer capture from mouse input.
        // Use the getCurrentPoint method over currentPoint property to ensure
        // the coordinate space is in relation to the target element.
        // Note: getCurrentPoint and currentPoint are only available in the 
        // local compartment, they are not available in the web compartment.
        var ptTarget = e.getCurrentPoint(e.currentTarget);
        var ptContainer = e.getCurrentPoint(document.getElementsByTagName("body")[0]);
    
        // If event source is mouse pointer and the pointer is still over 
        // the target, retain pointer and pointer details.
        // For this example, we assume only one mouse pointer.
        if ((ptTarget.pointerDevice.pointerDeviceType === Windows.Devices.Input.PointerDeviceType.mouse) &
            (document.elementFromPoint(ptContainer.position.x, ptContainer.position.y) === target)) {
            target.setPointerCapture(e.pointerId);
            return;
        }
    
        // Remove pointer from pointers dictionary.
        var targetPointers = target.pointers;
        for (var i in targetPointers) {
            if (target.pointers[i].id === e.pointerId) {
                target.pointers.splice(i, 1);
                var pointerInfoPop = document.getElementById("infoPop" + e.pointerId);
                if (pointerInfoPop === null)
                    return;
                pointerInfoPop.removeNode(true);
            }
        }
    
        // Update target UI.
        if (target.pointers.length === 0) {
            target.style.backgroundColor = pointerColor.cancel;
        }
    }
    

포인터 속성 가져오기

앱에 사용하기 위해 선택하는 언어 프레임워크는 포인터 속성을 가져오는 방법을 지정합니다. 대부분의 속성은 포인터 이벤트 개체를 통해 바로 노출됩니다. 앞에서 설명한 대로 추가 포인터 정보는 이벤트 인수의 getCurrentPointgetIntermediatePoints 메서드 또는 currentPointintermediatePoints 속성을 통해 가져올 수 있습니다. 포인터 데이터의 컨텍스트를 지정할 수 있으므로 getCurrentPointgetIntermediatePoints 메서드를 사용하는 것이 좋습니다.

여기서는 PointerPointPointerPointProperties 개체를 통해서만 사용할 수 있는 이벤트 개체 및 확장 속성에서 직접 다양한 포인터 속성을 쿼리합니다.

function queryPointer(e) {
    /// <summary>
    /// Get extended pointer data.
    /// </summary>
    /// <param name="e" type="Event">The event argument.</param>

    // We get the extended pointer info through the getCurrentPoint method
    // of the event argument. (We recommend using getCurrentPoint 
    // to ensure the coordinate space is in relation to the target.)
    // Note: getCurrentPoint and currentPoint are only available in the 
    // local compartment, they are not available in the web compartment.

    var pt = e.getCurrentPoint(e.currentTarget);
    var ptTargetProperties = pt.properties;

    var details = "Pointer Id: " + e.pointerId;
    switch (e.pointerType) {
        case "mouse":
            details += "\nPointer type: mouse";
            details += "\nLeft button: " + ptTargetProperties.isLeftButtonPressed;
            details += "\nRight button: " + ptTargetProperties.isRightButtonPressed;
            details += "\nWheel button: " + ptTargetProperties.isMiddleButtonPressed;
            details += "\nX1 button: " + ptTargetProperties.isXButton1Pressed;
            details += "\nX2 button: " + ptTargetProperties.isXButton2Pressed;
            break;
        case "pen":
            details += "\nPointer type: pen";
            if (pt.isInContact) {
                details += "\nPressure: " + ptTargetProperties.pressure;
                details += "\nrotation: " + ptTargetProperties.rotation;
                details += "\nTilt X: " + ptTargetProperties.xtilt;
                details += "\nTilt Y: " + ptTargetProperties.ytilt;
                details += "\nBarrel button pressed: " + ptTargetProperties.isBarrelButtonPressed;
            }
            break;
        case "touch":
            details += "\nPointer type: touch";
            details += "\nPressure: " + ptTargetProperties.pressure;
            details += "\nrotation: " + ptTargetProperties.rotation;
            details += "\nTilt X: " + ptTargetProperties.xtilt;
            details += "\nTilt Y: " + ptTargetProperties.ytilt;
            break;
        default:
            details += "\nPointer type: " + "n/a";
            break;
    }
    details += "\nPointer location (target): " + e.offsetX + ", " + e.offsetY;
    details += "\nPointer location (screen): " + e.screenX + ", " + e.screenY;

    return details;
}

좀 더 복잡한 샘플 링크는 이 페이지 하단에 있는 관련 항목을 참조하세요.

전체 예제

포인터 전체 코드를 참조하세요.

요약 및 다음 단계

이 빠른 시작에서는 JavaScript를 사용하는 앱에서 포인터 입력에 대해 알아보았습니다.

포인터 이벤트는 탭, 밀기, 그리고 보조 마우스 단추, 마우스 휠, 펜 단추 및 펜 지우개를 통한 입력 등의 기타 장치별 조작과 같은 단순한 조작을 관리하는 데 유용합니다.

Windows 8 터치 언어에 설명된 제스처 같은 보다 정교한 조작을 처리하려면 빠른 시작: DOM 제스처 및 조작, 빠른 시작: 정적 제스처빠른 시작: 조작 제스처를 참조하세요.

Windows 8 터치 언어에 대한 자세한 내용은 터치 조작 디자인을 참조하세요.

관련 항목

개발자

사용자 조작에 응답

Windows 스토어 앱 개발(JavaScript 및 HTML)

빠른 시작: DOM 제스처 및 조작

빠른 시작: 정적 제스처

빠른 시작: 조작 제스처

디자이너

터치 조작 디자인