다음을 통해 공유


RealTimeStylus 플러그 인 샘플

이 애플리케이션은 RealTimeStylus 클래스를 사용하는 방법을 보여 줍니다. RealTimeStylus 클래스를 포함하여 StylusInput API에 대한 자세한 개요는 스타일러스 입력 액세스 및 조작을 참조하세요. 동기 및 비동기 플러그 인에 대한 자세한 내용은 플러그 인 및 RealTimeStylus 클래스를 참조하세요.

샘플 개요

플러그 인, IStylusSyncPlugin 또는 IStylusAsyncPlugin 인터페이스를 구현하는 개체를 RealTimeStylus 개체에 추가할 수 있습니다. 이 샘플 애플리케이션은 다음과 같은 여러 유형의 플러그 인을 사용합니다.

  • 패킷 필터 플러그 인: 패킷을 수정합니다. 이 샘플의 패킷 필터 플러그 인은 사각형 영역 내의 모든(x,y) 패킷 데이터를 제한하여 패킷 정보를 수정합니다.
  • 사용자 지정 동적 렌더러 플러그 인: 동적 렌더링 품질을 수정합니다. 이 샘플의 사용자 지정 동적 렌더링 플러그 인은 스트로크에서 각 (x,y) 지점 주위에 작은 원을 그려 잉크가 렌더링되는 방식을 수정합니다.
  • 동적 렌더러 플러그 인: 동적 렌더링 품질을 수정합니다. 이 샘플에서는 동적 잉크 렌더링을 처리하기 위해 DynamicRenderer 개체를 플러그 인으로 사용하는 방법을 보여 줍니다.
  • 제스처 인식기 플러그 인: 애플리케이션 제스처를 인식합니다. 이 샘플에서는 GestureRecognizer 개체를 플러그 인으로 사용하여 애플리케이션 제스처를 인식하는 방법을 보여 줍니다(Microsoft 제스처 인식기가 있는 시스템에서 실행할 때).

또한 이 샘플에서는 사용자가 컬렉션에서 각 플러그 인의 순서를 추가, 제거 및 변경할 수 있는 사용자 인터페이스를 제공합니다. 샘플 솔루션에는 RealTimeStylusPluginApp 및 RealTimeStylusPlugins의 두 프로젝트가 포함되어 있습니다. RealTimeStylusPluginApp에는 샘플에 대한 사용자 인터페이스가 포함되어 있습니다. RealTimeStylusPlugins는 플러그 인의 구현을 포함합니다. RealTimeStylusPlugins 프로젝트는 패킷 필터 및 사용자 지정 동적 렌더러 플러그 인을 포함하는 RealTimeStylusPlugins 네임스페이스를 정의합니다. 이 네임스페이스는 RealTimeStylusPluginApp 프로젝트에서 참조됩니다. RealTimeStylusPlugins 프로젝트는 Microsoft.Ink, Microsoft.StylusInputMicrosoft.StylusInput.PluginData 네임스페이스를 사용합니다.

Microsoft.StylusInputMicrosoft.StylusInput.PluginData 네임스페이스에 대한 개요는 StylusInput API의 아키텍처를 참조하세요.

패킷 필터 플러그 인

패킷 필터 플러그 인은 패킷 수정을 보여 주는 동기 플러그 인입니다. 특히 폼에 사각형을 정의합니다. 지역 외부에서 그려진 모든 패킷은 지역 내에서 렌더링됩니다. 플러그 인 클래스인 PacketFilterPlugin는 , StylusUpPackets 펜 입력 이벤트에 대한 알림을 StylusDown등록합니다. 클래스는 IStylusSyncPlugin 클래스에 정의된 StylusDown, StylusUpPackets 메서드를 구현합니다.

PacketFilterPlugin 공용 생성자에는 Rectangle 구조가 필요합니다. 이 사각형은 패킷이 포함될 잉크 공간 좌표(.01mm = 1 HIMETRIC 단위)의 사각형 영역을 정의합니다. 사각형은 프라이빗 필드 rectangle에 보관됩니다.

public class PacketFilterPlugin:IStylusSyncPlugin  
{
    private System.Drawing.Rectangle rectangle = System.Drawing.Rectangle.Empty;
    public PacketFilterPlugin(Rectangle r)
    {
        rectangle = r;
    }
    // ...

클래스는 PacketFilterPluginDataInterest 속성에 대한 get 접근자를 구현하여 이벤트 알림을 등록합니다. 이 경우 플러그 인은 , , PacketsStylusUpError 알림에 StylusDown응답하는 데 관심이 있습니다. 이 샘플은 DataInterestMask 열거형에 정의된 대로 이러한 값을 반환합니다. 펜 팁이 디지타이저 표면에 연결되면 StylusDown 메서드가 호출됩니다. StylusUp 메서드는 펜 팁이 디지타이저 표면을 떠날 때 호출됩니다. Packets 메서드는 RealTimeStylus 개체가 패킷을 수신할 때 호출됩니다. Error 메서드는 현재 플러그 인 또는 이전 플러그 인에서 예외를 throw할 때 호출됩니다.

public DataInterestMask DataInterest
{
    get
    {
        return DataInterestMask.StylusDown | 
               DataInterestMask.Packets | 
               DataInterestMask.StylusUp | 
               DataInterestMask.Error;
    }
}           
    //...

클래스는 PacketFilterPlugin 도우미 메서드 ModifyPacketData에서 이러한 알림의 대부분을 처리합니다. 메서드는 ModifyPacketDataPacketsData 클래스에서 각 새 패킷에 대한 x 및 y 값을 가져옵니다. 두 값 중 하나가 사각형 외부에 있는 경우 메서드는 값을 사각형 내에 있는 가장 가까운 지점으로 바꿉니다. 이는 플러그 인이 펜 입력 스트림에서 수신되는 패킷 데이터를 대체할 수 있는 방법의 예입니다.

private void ModifyPacketData(StylusDataBase data)
{
    for (int i = 0; i < data.Count ; i += data.PacketPropertyCount)
    {
        // packet data always has x followed by y followed by the rest
        int x = data[i];
        int y = data[i+1];

        // Constrain points to the input rectangle
        x = Math.Max(x, rectangle.Left);
        x = Math.Min(x, rectangle.Right);
        y = Math.Max(y, rectangle.Top);
        y = Math.Min(y, rectangle.Bottom);

        // If necessary, modify the x,y packet data
        if (x != data[i])
        {
            data[i] = x;
        }
        if (y != data[i+1])
        {
            data[i+1] = y;
        } 
    }
}

사용자 지정 동적 렌더러 플러그 인

또한 클래스는 CustomDynamicRenderer 펜 입력 알림을 수신하기 위해 IStylusSyncPlugin 클래스를 구현합니다. 그런 다음 알림을 처리 Packets 하여 각 새 패킷 지점 주위에 작은 원을 그립니다.

클래스에는 클래스 생성자에 전달된 그래픽 개체에 대한 참조를 포함하는 Graphics 변수가 포함되어 있습니다. 동적 렌더링에 사용되는 그래픽 개체입니다.

private Graphics myGraphics;

public CustomDynamicRendererPlugin(Graphics g)
{
    myGraphics = g;
}
        //...
            

사용자 지정 동적 렌더러 플러그 인이 패킷 알림을 받으면 (x,y) 데이터를 추출하고 점 주위에 작은 녹색 원을 그립니다. 펜 입력 스트림을 기반으로 하는 사용자 지정 렌더링의 예입니다.

public void Packets(RealTimeStylus sender,  PacketsData data)
{           
    for (int i = 0; i < data.Count; i += data.PacketPropertyCount)
    {
        // Packet data always has x followed by y followed by the rest
        Point point = new Point(data[i], data[i+1]);

        // Since the packet data is in Ink Space coordinates, we need to convert to Pixels...
        point.X = (int)Math.Round((float)point.X * (float)myGraphics.DpiX/2540.0F);
        point.Y = (int)Math.Round((float)point.Y * (float)myGraphics.DpiY/2540.0F);

        // Draw a circle corresponding to the packet
        myGraphics.DrawEllipse(Pens.Green, point.X - 2, point.Y - 2, 4, 4);
    }
}

RealTimeStylusPluginApp 프로젝트

RealTimeStylusPluginApp 프로젝트는 이전에 설명한 플러그 인과 GestureRecognizerDynamicRenderer 플러그 인을 보여 줍니다. 프로젝트의 사용자 인터페이스는 다음으로 구성됩니다.

  • 잉크 입력 영역을 정의하는 데 사용되는 GroupBox 컨트롤을 포함하는 양식입니다.
  • 사용 가능한 플러그 인을 나열하고 선택할 수 있는 CheckedListBox 컨트롤입니다.
  • 플러그 인의 순서를 다시 정렬할 수 있도록 하는 Button 개체 쌍입니다.

프로젝트는 프로젝트에서 사용되는 플러그 인을 더 쉽게 관리할 수 있도록 구조 PlugInListItem체 를 정의합니다. 구조체에는 PlugInListItem 플러그 인 및 설명이 포함됩니다.

RealTimeStylusPluginApp 클래스 자체는 IStylusAsyncPlugin 클래스를 구현합니다. 이는 GestureRecognizer 플러그 인이 출력 큐에 RealTimeStylusPluginApp 제스처 데이터를 추가할 때 클래스에 알릴 수 있도록 필요합니다. 애플리케이션은 CustomStylusDataAdded 알림을 등록합니다. 제스처 데이터가 수신되면 RealTimeStylusPluginApp 양식의 맨 아래에 있는 상태 표시줄에 설명을 배치합니다.

public void CustomStylusDataAdded(RealTimeStylus sender, CustomStylusData data)
{
    if (data.CustomDataId == GestureRecognizer.GestureRecognitionDataGuid)
    {
        GestureRecognitionData grd = data.Data as GestureRecognitionData;
        if (grd != null)
        {
            if (grd.Count > 0)
            {
                GestureAlternate ga = grd[0];
                sbGesture.Text = "Gesture=" + ga.Id + ", Confidence=" + ga.Confidence;
            }
        }
    }
}

참고

CustomStylusDataAdded 구현에서는 GUID(GestureRecognitionDataGuid 필드 사용) 또는 형식(as 문의 결과를 사용하여)을 통해 출력 큐에서 사용자 지정 제스처 데이터를 식별할 수 있다는 점이 흥미롭습니다. 샘플은 데모를 위해 두 가지 식별 기술을 모두 사용합니다. 두 방법만으로도 유효합니다.

 

폼의 Load 이벤트 처리기에서 애플리케이션은 및 CustomDynamicRenderer 클래스의 인스턴스를 PacketFilter 만들고 목록 상자에 추가합니다. 그런 다음, 애플리케이션은 GestureRecognizer 클래스의 instance 만들고 성공하면 목록 상자에 추가합니다. 제스처 인식기가 시스템에 없으면 실패합니다. 다음으로, 애플리케이션은 DynamicRenderer 개체를 인스턴스화하고 목록 상자에 추가합니다. 마지막으로 애플리케이션은 각 플러그 인과 RealTimeStylus 개체 자체를 사용하도록 설정합니다.

샘플에 대해 유의해야 할 또 다른 중요한 점은 도우미 메서드에서 플러그 인이 추가 또는 제거되기 전에 RealTimeStylus 개체를 먼저 사용하지 않도록 설정한 다음 추가 또는 제거가 완료된 후 다시 사용하도록 설정된다는 것입니다.

private void RemoveFromPluginCollection(int index)
{
    IStylusSyncPlugin plugin = ((PluginListItem)chklbPlugins.Items[index]).Plugin;

    bool rtsEnabled = myRealTimeStylus.Enabled;
    myRealTimeStylus.Enabled = false;
    myRealTimeStylus.SyncPluginCollection.Remove(plugin);
    myRealTimeStylus.Enabled = rtsEnabled;
}

Microsoft.StylusInput.DynamicRenderer

Microsoft.StylusInput.GestureRecognizer

Microsoft.StylusInput.RealTimeStylus

Microsoft.StylusInput.DataInterestMask

Microsoft.StylusInput.IStylusSyncPlugin

Microsoft.StylusInput.IStylusAsyncPlugin

Microsoft.StylusInput.PluginData.PacketsData

스타일러스 입력 액세스 및 조작

플러그 인 및 RealTimeStylus 클래스

RealTimeStylus 잉크 컬렉션 샘플