Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
L'esempio Manipulation and Inertia mostra come aggiungere il supporto di Windows Touch alle applicazioni native basate su Windows che usano l'API Windows Touch. Nell'esempio vengono implementate le funzionalità di base dell'API per abilitare la conversione, la rotazione e il ridimensionamento per gli oggetti e l'applicazione di proprietà di inerzia. L'esempio mostra anche come fornire alle applicazioni Windows Touch il supporto di base del mouse. L'immagine seguente mostra l'aspetto dell'esempio quando viene eseguito.
Le caselle con sfumature possono essere manipolate in modo indipendente da un utente quando eseguono l'applicazione da un computer che supporta Windows Touch.
Registrare la finestra touch
Prima di poter ricevere l'input del tocco, devi informare il sistema che la tua applicazione è un'applicazione Windows Touch chiamando la funzione di seguito:
RegisterTouchWindow(g_hWnd, 0);
Implementare l'interfaccia _IManipulationEventSink
Il sink di eventi _IManipulationEvents contiene tre funzioni: ManipulationStarted, ManipulationDelta e ManipulationCompleted. Queste funzioni di callback vengono usate dall'interfaccia IManipulationProcessor e dall'interfaccia IInertiaProcessor per restituire i valori calcolati dai processori dopo aver richiamato le funzioni ProcessTime, ProcessUpWithTime, ProcessDownWithTime e ProcessMoveWithTime. Nell'esempio di codice seguente viene illustrata un'implementazione di esempio di un'interfaccia _IManipulationEvents .
#include "cmanipulationeventsink.h"
#include <math.h>
CManipulationEventSink::CManipulationEventSink(HWND hWnd, CDrawingObject *dObj, int iTimerId, BOOL inertia) {
// Manipulation & Inertia Processors
m_manip = NULL;
m_inert = NULL;
// Connection points for COM.
m_pConPointContainer = NULL;
m_pConnPoint = NULL;
// Reference to an object associated with this event sink.
m_dObj = dObj;
// Handle to the window used for computing boundaries.
m_hWnd = hWnd;
// The unique timer id for this manipulation event sink.
m_iTimerId = iTimerId;
m_bInertia = inertia;
m_cRefCount = 1;
}
CManipulationEventSink::~CManipulationEventSink()
{
}
HRESULT STDMETHODCALLTYPE CManipulationEventSink::ManipulationStarted(
FLOAT x,
FLOAT y)
{
KillTimer(m_hWnd, m_iTimerId);
return S_OK;
}
HRESULT STDMETHODCALLTYPE CManipulationEventSink::ManipulationDelta(
FLOAT x,
FLOAT y,
FLOAT translationDeltaX,
FLOAT translationDeltaY,
FLOAT scaleDelta,
FLOAT expansionDelta,
FLOAT rotationDelta,
FLOAT cumulativeTranslationX,
FLOAT cumulativeTranslationY,
FLOAT cumulativeScale,
FLOAT cumulativeExpansion,
FLOAT cumulativeRotation)
{
FLOAT pivot = 0.0f;
// Apply transformation based on rotationDelta (in radians).
FLOAT rads = 180.0f / 3.14159f;
m_dObj->Rotate(rotationDelta*rads, x, y);
// Apply translation based on scaleDelta.
m_dObj->Scale(scaleDelta);
// Apply translation based on translationDelta.
m_dObj->Translate(translationDeltaX, translationDeltaY);
if(!m_bInertia)
{
// Set values for one-finger rotations.
FLOAT fPivotRadius = (FLOAT)(sqrt(pow(m_dObj->GetWidth()/2, 2)
+ pow(m_dObj->GetHeight()/2, 2)))*0.4f;
FLOAT fPivotPtX = m_dObj->GetCenterX();
FLOAT fPivotPtY = m_dObj->GetCenterY();
m_manip->put_PivotPointX(fPivotPtX);
m_manip->put_PivotPointY(fPivotPtY);
m_manip->put_PivotRadius(fPivotRadius);
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE CManipulationEventSink::ManipulationCompleted(
FLOAT x,
FLOAT y,
FLOAT cumulativeTranslationX,
FLOAT cumulativeTranslationY,
FLOAT cumulativeScale,
FLOAT cumulativeExpansion,
FLOAT cumulativeRotation)
{
if(!m_bInertia)
{
SetupInertia();
// Kick off timer that handles inertia.
SetTimer(m_hWnd, m_iTimerId, DESIRED_MILLISECONDS, NULL);
}
else
{
// Stop timer that handles inertia.
KillTimer(m_hWnd, m_iTimerId);
}
return S_OK;
}
Creare oggetti COM e configurare le interfacce IManipulationProcessor e IInertiaProcessor
L'API fornisce un'implementazione delle interfacce IManipulationProcessor e IInertiaProcessor. È necessario creare un'istanza di e fare riferimento agli oggetti COM dal sink di eventi IManipulationEvents implementato in precedenza.
Gestire i messaggi di WM_TOUCH
I dati di input devono essere estratti dai messaggi di WM_TOUCH e successivamente devono essere elaborati per inserire il processore di manipolazione corretto.
switch (msg)
{
case WM_TOUCH:
iNumContacts = LOWORD(wParam);
hInput = (HTOUCHINPUT)lParam;
pInputs = new TOUCHINPUT[iNumContacts];
// Get each touch input info and feed each
// tagTOUCHINPUT into the process input handler.
if(pInputs != NULL)
{
if(GetTouchInputInfo(hInput, iNumContacts,
pInputs, sizeof(TOUCHINPUT)))
{
for(int i = 0; i < iNumContacts; i++)
{
// Bring touch input info into client coordinates.
ptInputs.x = pInputs[i].x/100;
ptInputs.y = pInputs[i].y/100;
ScreenToClient(g_hWnd, &ptInputs);
pInputs[i].x = ptInputs.x;
pInputs[i].y = ptInputs.y;
g_ctDriver->ProcessInputEvent(pInputs[i]);
}
}
}
delete [] pInputs;
break;
}
Nota
Per usare la funzione ScreenToClient , è necessario disporre del supporto DPI elevato nell'applicazione. Per altre informazioni sul supporto di valori DPI elevati, vedere DPI elevato.
Trasmettere le strutture TOUCHINPUT al processore appropriato
Dopo che i dati sono stati estratti dai messaggi WM_TOUCH utilizzando la funzione GetTouchInputInfo, inserire i dati nel processore di manipolazione invocando le funzioni ProcessUpWithTime, ProcessDownWithTime o ProcessMoveWithTime, a seconda del dwFlag impostato nella struttura TOUCHINPUT.
Nota
Quando si supportano più manipolazioni, è necessario creare un nuovo processore di manipolazione se è necessario usare il dwID definito nella struttura TOUCHINPUT per inviare i dati all'oggetto IManipulationProcessor corretto.
CoreObject* coCurrent = m_coHead;
while(coCurrent!=NULL && !bFoundObj)
{
if(dwEvent & TOUCHEVENTF_DOWN)
{
DownEvent(coCurrent, inData, &bFoundObj);
}
else if(dwEvent & TOUCHEVENTF_MOVE)
{
MoveEvent(coCurrent, inData);
}
else if(dwEvent & TOUCHEVENTF_UP)
{
UpEvent(coCurrent, inData);
}
coCurrent = coCurrent->coNext;
}
VOID CComTouchDriver::DownEvent(CoreObject* coRef, tagTOUCHINPUT inData, BOOL* bFound) {
DWORD dwPCursor = inData.dwID;
DWORD dwPTime = inData.dwTime;
int x = inData.x;
int y = inData.y;
// Check that the user has touched within an object's region and fed to the object's manipulation processor.
if(coRef->doDrawing->InRegion(x, y) &&
!HasCursor(coRef, dwPCursor))
{
...
// Feed values to the Manipulation Processor.
coRef->manipulationProc->ProcessDownWithTime(dwPCursor, (FLOAT)x, (FLOAT)y, dwPTime);
...
}
}
Configurare l'inerzia all'interno di ManipulationCompleted
Dopo aver richiamato il metodo ManipulationCompleted, l'oggetto IManipulationProcessor deve impostare i valori per l'oggetto IInertiaProcessor collegato a IManipulationProcessor per richiamare l'inerzia. Nell'esempio di codice seguente viene illustrato come configurare l'oggetto IInertiaProcessor dal metodo IManipulationProcessor ManipulationCompleted.
int iVWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
int iVHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
RECT rc;
GetClientRect(m_hWnd, &rc);
FLOAT lCWidth = (FLOAT)rc.right;
FLOAT lCHeight = (FLOAT)rc.bottom;
// Set properties for inertia events.
// Deceleration for translations in pixel / msec^2.
m_inert->put_DesiredDeceleration(0.001f);
// Deceleration for rotations in radians / msec^2.
m_inert->put_DesiredAngularDeceleration(0.00001f);
// Calculate borders and elastic margin to be set.
// They are relative to the width and height of the object.
FLOAT fHOffset = m_dObj->GetWidth() * 0.5f;
FLOAT fVOffset = m_dObj->GetHeight() * 0.5f;
// Elastic margin is in pixels - note that it offsets the boundary.
FLOAT fHElasticMargin = 25.0f;
FLOAT fVElasticMargin = 25.0f;
FLOAT fBoundaryLeft = fHOffset + fHElasticMargin;
FLOAT fBoundaryTop = fVOffset + fVElasticMargin;
FLOAT fBoundaryRight = lCWidth - fHOffset - fHElasticMargin;
FLOAT fBoundaryBottom = lCHeight - fVOffset - fVElasticMargin;
// Set borders and elastic margin.
m_inert->put_BoundaryLeft(fBoundaryLeft);
m_inert->put_BoundaryTop(fBoundaryTop);
m_inert->put_BoundaryRight(fBoundaryRight);
m_inert->put_BoundaryBottom(fBoundaryBottom);
m_inert->put_ElasticMarginLeft(fHElasticMargin);
m_inert->put_ElasticMarginTop(fVElasticMargin);
m_inert->put_ElasticMarginRight(fHElasticMargin);
m_inert->put_ElasticMarginBottom(fVElasticMargin);
// Set initial origins.
m_inert->put_InitialOriginX(m_dObj->GetCenterX());
m_inert->put_InitialOriginY(m_dObj->GetCenterY());
FLOAT fVX;
FLOAT fVY;
FLOAT fVR;
m_manip->GetVelocityX(&fVX);
m_manip->GetVelocityY(&fVY);
m_manip->GetAngularVelocity(&fVR);
// Set initial velocities for inertia processor.
m_inert->put_InitialVelocityX(fVX);
m_inert->put_InitialVelocityY(fVY);
m_inert->put_InitialAngularVelocity(fVR);
Pulire gli oggetti COM
Quando l'applicazione si chiude, è necessario pulire gli oggetti COM. Il codice seguente illustra come liberare le risorse allocate nell'esempio.
CComTouchDriver::~CComTouchDriver(VOID) {
CoreObject* coCurrent = m_coHead;
// Clean up COM objects.
while(coCurrent!=NULL)
{
coCurrent->inertiaEventSink->Release();
coCurrent->manipulationEventSink->Release();
coCurrent->inertiaProc->Release();
coCurrent->manipulationProc->Release();
coCurrent = coCurrent->coNext;
}
}
Argomenti correlati
Applicazione di manipolazione multitocco, Manipolazione e esempio di inerzia, Esempi di Windows Touch