Freigeben über


Behandeln von Unträgheit in nicht verwaltetem Code

In diesem Abschnitt wird erläutert, wie Sie die IInertiaProcessor-Schnittstelle für die Behandlung von Unzustellbarkeit in nicht verwaltetem Code verwenden.

Übersicht

Um in nicht verwaltetem Code die Inerträgheit zu verwenden, müssen Sie Ereignissenken sowohl für den Bearbeitungsprozessor als auch für den Inertia-Prozessor implementieren. Beginnen Sie mit dem Hinzufügen von Manipulationsunterstützung zu Ihrer Anwendung, wie im Abschnitt Hinzufügen von Manipulationsunterstützung zu nicht verwaltetem Code beschrieben. Beachten Sie, dass die Manipulationsunterstützung erfordert, dass Sie Touchnachrichten anstelle von Gestennachrichten verwenden, um Ereignisdaten an den Bearbeitungsprozessor zu senden. Nachdem Sie die Bearbeitung ausgeführt haben, müssen Sie auch eine zweite Ereignissenke für die Ereignisse implementieren, die von der IInertiaProcessor-Schnittstelle generiert werden, oder Sie müssen Ihre vorhandene Ereignissenke ändern, um sowohl die von der IInertiaProcessor - als auch die IManipulationProcessor-Schnittstelle generierten Ereignisse zu berücksichtigen. Für die Zwecke dieses Beispiels ist es einfacher, von der Ereignissenke zu beginnen, die für den Abschnitt Hinzufügen von Manipulationsunterstützung zu nicht verwaltetem Code erstellt wurde, und einen zweiten Konstruktor hinzuzufügen, der mit dem Inertia-Prozessor anstelle des Bearbeitungsprozessors funktioniert. Auf diese Weise kann die Implementierung der Ereignissenke entweder für den Manipulationsprozessor oder den Inertia-Prozessor funktionieren. Zusätzlich zum Hinzufügen eines zweiten Konstruktors verfügt die Ereignissenke über eine Variable, die angibt, ob sie die Vorgänge basierend auf der Inerträgheitseingabe statt der Manipulationseingabe ausführt.

Hinzufügen von Inertiieunterstützung zu einer Manipulationsprozessor-Ereignissenke

Der folgende Code zeigt den neuen Ereignissenkenkonstruktor, neue Membervariablen für eine IInertiaProcessor-Schnittstelle und ein Flag, das angibt, ob die Senke für DieTrägheit extrapoliert.

    CManipulationEventSink(IManipulationProcessor *pManip, IInertiaProcessor *pInert, HWND hWnd);
    CManipulationEventSink(IInertiaProcessor *pInert, HWND hWnd);
    IInertiaProcessor*      m_pInert;
    BOOL fExtrapolating; 

Nachdem der Klassenheader über die neuen Konstruktoren und ein Flag verfügt, das angibt, ob Sie extrapolieren, können Sie Ihre Ereignissenke implementieren, um separate Behandlungsblöcke für die Ereignisse IManipulationProcessor und IInertiaProcessor zu erhalten. Der Konstruktor, der einen IManipulationProcessor und einen IInertiaProcessor akzeptiert, sollte das fExtrapolating-Flag auf false festlegen, was angibt, dass es sich um einen IManipulationProcessor-Ereignishandler handelt. Der folgende Code zeigt, wie der Konstruktor für eine Ereignissenke implementiert werden kann, die den IManipulationProcessor verwendet.

CManipulationEventSink::CManipulationEventSink(IManipulationProcessor *pManip, IInertiaProcessor *pInert, HWND hWnd)
{
    m_hWnd = hWnd;

    //Set initial ref count to 1.
    m_cRefCount = 1;

    fExtrapolating=FALSE;

    m_pManip = pManip;
    
    m_pInert = pInert;
    
    m_pManip->put_PivotRadius(-1);

    m_cStartedEventCount = 0;
    m_cDeltaEventCount = 0;
    m_cCompletedEventCount = 0;

    HRESULT hr = S_OK;

    //Get the container with the connection points.
    IConnectionPointContainer* spConnectionContainer;
    
    hr = pManip->QueryInterface(
      IID_IConnectionPointContainer, 
          (LPVOID*) &spConnectionContainer
        );
    //hr = manip->QueryInterface(&spConnectionContainer);
    if (spConnectionContainer == NULL){
        // something went wrong, try to gracefully quit
        
    }

    //Get a connection point.
    hr = spConnectionContainer->FindConnectionPoint(__uuidof(_IManipulationEvents), &m_pConnPoint);
    if (m_pConnPoint == NULL){
        // something went wrong, try to gracefully quit
    }

    DWORD dwCookie;

    //Advise.
    hr = m_pConnPoint->Advise(this, &dwCookie);
}

Der folgende Code zeigt, wie der Konstruktor für eine Ereignissenke implementiert werden kann, die den IInertiaProcessor verwendet. Dieser Konstruktor legt das fExtrapolating-Flag auf true fest, was angibt, dass diese instance der Ereignissenkenklasse eine Extrapolation ausführt und alle Bewegungsvorgänge ausführt, die zuvor von den Manipulationsprozessorereignissen ausgeführt wurden.

CManipulationEventSink::CManipulationEventSink(IInertiaProcessor *pInert, HWND hWnd)
{
    m_hWnd = hWnd;

    m_pInert = pInert;
    //Set initial ref count to 1.
    m_cRefCount = 1;

    fExtrapolating=TRUE;

    m_cStartedEventCount = 0;
    m_cDeltaEventCount = 0;
    m_cCompletedEventCount = 0;

    HRESULT hr = S_OK;

    //Get the container with the connection points.
    IConnectionPointContainer* spConnectionContainer;
    
    hr = pInert->QueryInterface(
      IID_IConnectionPointContainer, 
          (LPVOID*) &spConnectionContainer
        );
    //hr = manip->QueryInterface(&spConnectionContainer);
    if (spConnectionContainer == NULL){
        // something went wrong, try to gracefully quit        
    }

    //Get a connection point.
    hr = spConnectionContainer->FindConnectionPoint(__uuidof(_IManipulationEvents), &m_pConnPoint);
    if (m_pConnPoint == NULL){
        // something went wrong, try to gracefully quit
    }
    DWORD dwCookie;

    //Advise.
    hr = m_pConnPoint->Advise(this, &dwCookie);
}   

Hinweis

Die Implementierung der Ereignissenke der Ereignissenke des Manipulationsprozessors wird als Ereignissenke für den Inertia-Prozessor wiederverwendet.

 

Wenn Sie nun diese Klasse , CManipulationEventSink, erstellen, kann sie entweder als Ereignissenke für einen Bearbeitungsprozessor oder als Ereignissenke für einen Inertia-Prozessor erstellt werden. Wenn es als Trägheitsprozessorereignissenke erstellt wird, wird das fExtrapolating-Flag auf true festgelegt, was angibt, dass Manipulationsereignisse extrapoliert werden sollten.

Hinweis

ManipulationStarted wird sowohl von der IManipulationProcessor - als auch von der IInertiaProcessor-Schnittstelle ausgelöst.

 

Wenn die Bearbeitung beginnt, werden die Eigenschaften der IInertiaProcessor-Schnittstelle festgelegt. Der folgende Code zeigt, wie das gestartete Ereignis behandelt wird.

HRESULT STDMETHODCALLTYPE CManipulationEventSink::ManipulationStarted( 
    /* [in] */ FLOAT x,
    /* [in] */ FLOAT y)
{
    m_cStartedEventCount ++;       

    // set origins in manipulation processor
    m_pInert->put_InitialOriginX(x);
    m_pInert->put_InitialOriginY(y);
    
    RECT screenRect;

    HWND desktop = GetDesktopWindow();
    GetClientRect(desktop, &screenRect);

    // physics settings
    // deceleration is units per square millisecond
    m_pInert->put_DesiredDeceleration(.1f);

    // set the boundaries        
    screenRect.left-= 1024;
    m_pInert->put_BoundaryLeft  ( static_cast<float>(screenRect.left   * 100));
    m_pInert->put_BoundaryTop   ( static_cast<float>(screenRect.top    * 100));
    m_pInert->put_BoundaryRight ( static_cast<float>(screenRect.right  * 100));
    m_pInert->put_BoundaryBottom( static_cast<float>(screenRect.bottom * 100));
    
    
    // Elastic boundaries - I set these to 90% of the screen 
    // so... 5% at left, 95% right, 5% top,  95% bottom
    // Values are whole numbers because units are in centipixels
    m_pInert->put_ElasticMarginLeft  (static_cast<float>(screenRect.left   * 5));
    m_pInert->put_ElasticMarginTop   (static_cast<float>(screenRect.top    * 5));
    m_pInert->put_ElasticMarginRight (static_cast<float>(screenRect.right  * 95));
    m_pInert->put_ElasticMarginBottom(static_cast<float>(screenRect.bottom * 95));
    
    
    return S_OK;
}

In diesem Beispiel werden Bearbeitungsdelta verwendet, um das Fenster zu verschieben. Der folgende Code zeigt, wie das Deltaereignis behandelt wird.

HRESULT STDMETHODCALLTYPE CManipulationEventSink::ManipulationDelta( 
    /* [in] */ FLOAT x,
    /* [in] */ FLOAT y,
    /* [in] */ FLOAT translationDeltaX,
    /* [in] */ FLOAT translationDeltaY,
    /* [in] */ FLOAT scaleDelta,
    /* [in] */ FLOAT expansionDelta,
    /* [in] */ FLOAT rotationDelta,
    /* [in] */ FLOAT cumulativeTranslationX,
    /* [in] */ FLOAT cumulativeTranslationY,
    /* [in] */ FLOAT cumulativeScale,
    /* [in] */ FLOAT cumulativeExpansion,
    /* [in] */ FLOAT cumulativeRotation)
{
    m_cDeltaEventCount ++;
        
    RECT rect;
            
    GetWindowRect(m_hWnd, &rect);
        
    int oldWidth =  rect.right-rect.left;
    int oldHeight = rect.bottom-rect.top;            

    // scale and translate the window size / position    
    MoveWindow(m_hWnd,                                              // the window to move
        static_cast<int>(rect.left + (translationDeltaX / 100.0f)), // the x position
        static_cast<int>(rect.top + (translationDeltaY/100.0f)),    // the y position
        static_cast<int>(oldWidth * scaleDelta),                    // width
        static_cast<int>(oldHeight * scaleDelta),                   // height
        TRUE);                                                      // redraw
                     
    return S_OK;
}

In diesem Beispiel starten oder beenden Manipulationsereignisse einen Timer, der Process auf der IInertiaProcessor-Schnittstelle aufruft. Der folgende Code zeigt, wie das abgeschlossene Manipulationsereignis behandelt wird.

HRESULT STDMETHODCALLTYPE CManipulationEventSink::ManipulationCompleted( 
    /* [in] */ FLOAT x,
    /* [in] */ FLOAT y,
    /* [in] */ FLOAT cumulativeTranslationX,
    /* [in] */ FLOAT cumulativeTranslationY,
    /* [in] */ FLOAT cumulativeScale,
    /* [in] */ FLOAT cumulativeExpansion,
    /* [in] */ FLOAT cumulativeRotation)
{
    m_cCompletedEventCount ++;

    m_fX = x;
    m_fY = y;

    // place your code handler here to do any operations based on the manipulation   
    
    if (fExtrapolating){
        //Inertia Complete, stop the timer used for processing      
        KillTimer(m_hWnd,0);        
    }else{ 
        // setup velocities for inertia processor
        float vX = 0.0f;
        float vY = 0.0f;
        float vA = 0.0f;
        m_pManip->GetVelocityX(&vX);
        m_pManip->GetVelocityY(&vY);
        m_pManip->GetAngularVelocity(&vA);

        // complete any previous processing
        m_pInert->Complete();
        
        // Reset sets the  initial timestamp
        m_pInert->Reset();
                
        // 
        m_pInert->put_InitialVelocityX(vX);
        m_pInert->put_InitialVelocityY(vY);        
        
        m_pInert->put_InitialOriginX(x);
        m_pInert->put_InitialOriginY(y);
        
           
        // Start a timer
        SetTimer(m_hWnd,0, 50, 0);        
    }

    return S_OK;
}

Der folgende Code zeigt, wie Sie WM_TIMER Nachrichten in WndProc interpretieren können, um Aufrufe von Process auf der IInertiaProcessor-Schnittstelle auszuführen.

case WM_TIMER:       
  if (g_pIInertProc){
    BOOL b;       
    g_pIInertProc->Process(&b);        
  }
  break;

Koinitialisieren des Trägheitsprozessors und des Manipulationsprozessors und Initialisieren der Ereignissenken

Nachdem Sie Ihre Ereignissenke so geändert haben, dass sie sowohl den IManipulationProcessor als auch den IInertiaProcessor unterstützt, können Sie die Ereignissenken initialisieren und so einrichten, dass sie von Ihrer Anwendung ausgeführt werden. Der folgende Code zeigt, wie die Schnittstellenzeiger zugeordnet werden.

//Include windows.h for touch events
#include "windows.h"  

// Manipulation implementation file
#include <manipulations_i.c>
    
// Smart Pointer to a global reference of a manipulation processor, event sink
IManipulationProcessor* g_pIManipProc;
IInertiaProcessor*      g_pIInertProc;

Das folgende Codebeispiel zeigt, wie Sie Ihre Schnittstellen instanziieren.

   HRESULT hr = CoInitialize(0);
        
   hr = CoCreateInstance(CLSID_ManipulationProcessor,
       NULL,
       CLSCTX_INPROC_SERVER,
       IID_IUnknown,
       (VOID**)(&g_pIManipProc)
   );
   
   hr = CoCreateInstance(CLSID_InertiaProcessor,
       NULL,
       CLSCTX_INPROC_SERVER,
       IID_IUnknown,
       (VOID**)(&g_pIInertProc)
   );

Das folgende Codebeispiel zeigt, wie Sie Ihre Ereignissenken mit den Schnittstellenzeigern erstellen und das Fenster für toucheingaben registrieren.

   g_pManipulationEventSink = new CManipulationEventSink(g_pIManipProc, g_pIInertProc, hWnd);
   g_pManipulationEventSink = new CManipulationEventSink(g_pIInertProc, hWnd);


   RegisterTouchWindow(hWnd, 0);  

Trägheit