Listen For CursorDown Event - Happy to pay if someone can figure this out!

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
grimboto
Posts: 53
Joined: 09 Jul 2014, 19:20

Listen For CursorDown Event - Happy to pay if someone can figure this out!

Post by grimboto » 23 Jun 2019, 06:08

I'm using a stylus to draw on the screen using GDIP and there is a small delay between when the stylus touches the screen and the line starts drawing.
After a bit of research i found the below article that describes the timeline of events when a stylus is used.
https://docs.microsoft.com/en-us/windows/desktop/tablet/timeline-of-mouse-messages-and-system-events

A Image from the article below shows where the delay is happening.
Event Timeline.PNG
Event Timeline.PNG (128.98 KiB) Viewed 1265 times
So I was wondering if there is any way to listen for the CursorDown Event. I found a couple of articles on MSDN with examples in other languages but i have no idea how to convert them to AHK or even if they can be converted.

https://docs.microsoft.com/en-us/previous-versions/ms827586%28v%3dmsdn.10%29
https://docs.microsoft.com/en-us/previous-versions/aa510879(v=msdn.10)

If anyone has any ideas it would be greatly appreciated.

thanks GRIMBOTO

Edit: Still trying to figure this out happy to compensate your time if you can find a solution. Currently using AHKHID.ahk but as stated above the small delay is there and it makes writing on the screen quickly difficult.
grimboto
Posts: 53
Joined: 09 Jul 2014, 19:20

Re: Listen For CursorDown Event - Happy to pay if someone can figure this out!

Post by grimboto » 04 Jun 2021, 01:32

bump still looking for a solution for this if anyone has any ideas?
User avatar
mikeyww
Posts: 27366
Joined: 09 Sep 2014, 18:38

Re: Listen For CursorDown Event - Happy to pay if someone can figure this out!

Post by mikeyww » 04 Jun 2021, 05:32

There is always the brute-force method of running a timer and checking the mouse position, though you may be looking for something more direct or more efficient.
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: Listen For CursorDown Event - Happy to pay if someone can figure this out!

Post by swagfag » 05 Jun 2021, 08:52

idk if this can be used the way u intend to(as a blanket hook). seems like these CursorDown events are sent to specific "controls"(eg InkCollector), which need to be associated with a particular hwnd.
which is probably why the docs keep saying
When a given action is performed, the system events (prefixed with ISG_) are sent and received almost instantaneously by the application. The mouse messages (prefixed with WM_) are sent when the action is performed and are received by the application after the time it takes for the event to be processed by the Microsoft Windows messaging service.
...
Applications can listen to system events by using the InkCollector object and listening for the SystemGesture event on it. You can set which events an application listens to.
here's lifting the pen off of the usb tablet vertically and moving it off of the associated window. u can see that no events get captured when interacting with an unrelated window behind the GUI
IInkCollector.gif
IInkCollector.gif (226.54 KiB) Viewed 769 times

Code: Select all

#NoEnv
#SingleInstance Force
#Requires AutoHotkey v1.1.33+

if !InkObjDll := DllCall("LoadLibrary", "Str", "C:\Program Files\Common Files\microsoft shared\ink\InkObj.dll", "Ptr")
{
	MsgBox % "InkObj.dll not found: " A_LastError
	ExitApp
}

CLSID_InkCollector := "{43FB1553-AD74-4ee8-88E4-3E6DAAC915DB}"
IID_IInkCollector := "{F0F060B5-8B1F-4a7c-89EC-880692588A4F}"

pInkCollector := ComObjCreate(CLSID_InkCollector, IID_IInkCollector)
pInkCollectorVtbl := NumGet(pInkCollector+0, "Ptr")

;  8: HRESULT STDMETHODCALLTYPE put_hWnd(/* [in] */ LONG_PTR NewWindow)
pput_hWnd := NumGet(pInkCollectorVtbl + (8 * A_PtrSize), "Ptr")

; 10: HRESULT STDMETHODCALLTYPE put_Enabled(/* [in] */ VARIANT_BOOL Collecting)
pput_Enabled := NumGet(pInkCollectorVtbl + (10 * A_PtrSize), "Ptr")

; 46: HRESULT STDMETHODCALLTYPE SetEventInterest(/* [in] */ InkCollectorEventInterest EventId, /* [in] */ VARIANT_BOOL Listen)
pSetEventInterest := NumGet(pInkCollectorVtbl + (46 * A_PtrSize), "Ptr")

ICEI_CursorDown := 0
VARIANT_TRUE := -1
S_OK := 0

; need to say u want to track a certain event
hr := DllCall(pSetEventInterest, "Ptr", pInkCollector, "Int", ICEI_CursorDown, "Short", VARIANT_TRUE, "Ptr")
if (hr != S_OK)
{
	MsgBox % "InkCollector::SetEventInterest failed, HRESULT was " hr ". ErrorLevel was " ErrorLevel
	ExitApp
}

; the hwnd of a window, which will host the InkCollector, is required, so we create our own
Gui New, +HwndhGui +AlwaysOnTop
Gui Show, w400 h200, write inside me

; associate the InkCollector with our GUI
hr := DllCall(pput_hWnd, "Ptr", pInkCollector, "Ptr", hGui, "Ptr")
if (hr != S_OK)
{
	MsgBox % "InkCollector::put_hWnd failed, HRESULT was " hr ". ErrorLevel was " ErrorLevel
	ExitApp
}

; an u also need to switch the InkCollector on, apparently
hr := DllCall(pput_Enabled, "Ptr", pInkCollector, "Short", VARIANT_TRUE, "Ptr")
if (hr != S_OK)
{
	MsgBox % "InkCollector::put_Enabled failed, HRESULT was " hr ". ErrorLevel was " ErrorLevel
	ExitApp
}

VT_UNKNOWN := 0xD
InkCollector := ComObject(VT_UNKNOWN, pInkCollector, 1) ; wrap into a comobject, because ComObjConnect requires one, instead of a raw pointer
ComObjConnect(InkCollector, "_IInkCollectorEvents_")

Escape::
GuiClose:
GuiEscape:
	ExitApp

; void CursorDown([in] IInkCursor *Cursor, [in] IInkStrokeDisp *Stroke);
_IInkCollectorEvents_CursorDown(pIInkCursor, pIInkStrokeDisp, OriginalInkCollectorComObj) {
	ToolTip % A_ThisFunc "`n" A_TickCount
}

; void CursorInRange([in] IInkCursor *Cursor, [in] VARIANT_BOOL NewCursor, [in] VARIANT ButtonsState);
_IInkCollectorEvents_CursorInRange(pIInkCursor, NewCursor, ButtonsState, OriginalInkCollectorComObj) {
	ToolTip % A_ThisFunc "`n" A_TickCount
}

; void CursorOutOfRange([in] IInkCursor *Cursor)
_IInkCollectorEvents_CursorOutOfRange(pIInkCursor, OriginalInkCollectorComObj) {
	ToolTip % A_ThisFunc "`n" A_TickCount
}

v2 is better for working with COM, backporting this to v1 was absolute cancer

Code: Select all

#Requires AutoHotkey v2.0-a136-feda41f4
#SingleInstance Force

#DllLoad 'C:\Program Files\Common Files\microsoft shared\ink\InkObj.dll'

CLSID_InkCollector := '{43FB1553-AD74-4ee8-88E4-3E6DAAC915DB}'
IID_IInkCollector := '{F0F060B5-8B1F-4a7c-89EC-880692588A4F}'

InkCollector := ComObject(CLSID_InkCollector, IID_IInkCollector)

ICEI_CursorDown := 0
VARIANT_TRUE := -1

; 46: HRESULT STDMETHODCALLTYPE SetEventInterest(/* [in] */ InkCollectorEventInterest EventId, /* [in] */ VARIANT_BOOL Listen)
ComCall(46, InkCollector, 'Int', ICEI_CursorDown, 'Short', VARIANT_TRUE)

G := Gui('+AlwaysOnTop', 'write inside me')
G.Show('w400 h200')
G.OnEvent('Close', (*) => ExitApp())
G.OnEvent('Escape', (*) => ExitApp())
Esc::ExitApp()

;  8: HRESULT STDMETHODCALLTYPE put_hWnd(/* [in] */ LONG_PTR NewWindow)
ComCall(8, InkCollector, 'Ptr', G.Hwnd)

; 10: HRESULT STDMETHODCALLTYPE put_Enabled(/* [in] */ VARIANT_BOOL Collecting)
ComCall(10, InkCollector, 'Short', VARIANT_TRUE)

ComObjConnect(InkCollector, '_IInkCollectorEvents_')

; void CursorDown([in] IInkCursor *Cursor, [in] IInkStrokeDisp *Stroke);
_IInkCollectorEvents_CursorDown(pIInkCursor, pIInkStrokeDisp, *) => ToolTip(A_ThisFunc '`n' A_TickCount)

; void CursorInRange([in] IInkCursor *Cursor, [in] VARIANT_BOOL NewCursor, [in] VARIANT ButtonsState);
_IInkCollectorEvents_CursorInRange(pIInkCursor, NewCursor, ButtonsState, *) => ToolTip(A_ThisFunc '`n' A_TickCount)

; void CursorOutOfRange([in] IInkCursor *Cursor)
_IInkCollectorEvents_CursorOutOfRange(pIInkCursor, *) => ToolTip(A_ThisFunc '`n' A_TickCount)
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: Listen For CursorDown Event - Happy to pay if someone can figure this out!

Post by malcev » 05 Jun 2021, 14:38

v2 is better for working with COM, backporting this to v1 was absolute cancer
What are real benefits?
I see only small changing in syntax how to call com methods.
Instead of this:

Code: Select all

DllCall(NumGet(NumGet(InkCollector+0)+46*A_PtrSize), "ptr", InkCollector)
use this

Code: Select all

ComCall(46, InkCollector)
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: Listen For CursorDown Event - Happy to pay if someone can figure this out!

Post by swagfag » 05 Jun 2021, 15:20

u get automatic error reporting, cleanup, parameter/type validation

generally, if ure trying to do something wrong, chances are v2 will complain about it
whereas in v1, ur script either crashes or does nothing. good luck debugging it, unless u specifically know what to look out for. i guess this wouldnt matter as much if u were already a COM god. most ppl arent, though
grimboto
Posts: 53
Joined: 09 Jul 2014, 19:20

Re: Listen For CursorDown Event - Happy to pay if someone can figure this out!

Post by grimboto » 06 Jun 2021, 21:32

Thanks @swagfag that looks very helpful. Do you know if its possible to monitor the events without displaying the gui on the screen? I tried a transparent gui with window style +E0x20 to make it so i can click through but then it stopped receiving the events. If not would you have a link to where i can find the functions to change the color of the pen and clear all current ink?

thanks
lblb
Posts: 190
Joined: 30 Sep 2013, 11:31

Re: Listen For CursorDown Event - Happy to pay if someone can figure this out!

Post by lblb » 07 Jun 2021, 00:48

It would be easier to help you if you shared the code you are using. Can you share what you are working with so far?
grimboto
Posts: 53
Joined: 09 Jul 2014, 19:20

Re: Listen For CursorDown Event - Happy to pay if someone can figure this out!

Post by grimboto » 07 Jun 2021, 04:25

The code I'm currently using is part of a much larger script and hard to separate into just the part I want to uses this for. I'm basically making a touch interface for a old program that doesn't have one.

So the user draws on the screen then it gets converted into a line in the program.

My main goal is to replace AHKHID with the cursor down event. currently i'm just recording the mouse position while the mouse button is down drawing a line in the program. Looking at the inkcollector documents i might be able to use the stroke event to get this information aswell.

demo of current script
Animation.gif
Animation.gif (326.31 KiB) Viewed 658 times


thanks GRimboto
grimboto
Posts: 53
Joined: 09 Jul 2014, 19:20

Re: Listen For CursorDown Event - Happy to pay if someone can figure this out!

Post by grimboto » 09 Jun 2021, 00:36

So I've been having a look around and it looks like I should be using the RealTimeStylus object instead of the InkCollector Object as it suits my needs better.

I've managed to create the RealTimeStylus object and it appears to work but i'm having trouble connecting to the events. I need to create a IStylusSyncPlugin object to handle the events but I can't figure out how to get it done.

My Current Code:

Code: Select all

#NoEnv
#SingleInstance Force
#Requires AutoHotkey v1.1.33+


if !RtsCOMDll := DllCall("LoadLibrary", "Str", "C:\Program Files\Common Files\microsoft shared\ink\rtscom.dll", "Ptr")
{
	MsgBox % "rtscom.dll not found: " A_LastError
	ExitApp
}



CLSID_IRealTimeStylus := "{E26B366D-F998-43ce-836F-CB6D904432B0}"
IID_IRealTimeStylus := "{A8BB5D22-3144-4a7b-93CD-F34A16BE513A}"




IID_IStylusSyncPlugin := "{A157B174-482F-4d71-A3F6-3A41DDD11BE9}"



pRealTimeStylus := ComObjCreate(CLSID_IRealTimeStylus, IID_IRealTimeStylus)
pRealTimeStylusVtbl := NumGet(pRealTimeStylus+0, "Ptr")




pput_hWnd := NumGet(pRealTimeStylusVtbl + (6 * A_PtrSize), "Ptr")

pput_Enabled := NumGet(pRealTimeStylusVtbl + (4 * A_PtrSize), "Ptr")

pAddStylusSyncPlugin := NumGet(pRealTimeStylusVtbl + (9 * A_PtrSize), "Ptr")



VARIANT_TRUE := -1
VARIANT_False := 0
S_OK := 0


; the hwnd of a window, which will host the InkCollector, is required, so we create our own
Gui New, +HwndhGui +AlwaysOnTop ;  -Caption
Gui Show, w400 h200, write inside me

WinSet, Transparent , 100, ahk_id %hGui%

; associate the InkCollector with our GUI
hr := DllCall(pput_hWnd, "Ptr", pRealTimeStylus, "Ptr", hGui, "Ptr")
if (hr != S_OK)
{
	MsgBox % "pRealTimeStylus::put_hWnd failed, HRESULT was " hr ". ErrorLevel was " ErrorLevel
	ExitApp
}

; RTS must be disabled to Add a StylusPlugin
hr := DllCall(pput_Enabled, "Ptr", pRealTimeStylus, "Short", VARIANT_False, "Ptr")
if (hr != S_OK)
{
	MsgBox % "pRealTimeStylus::put_Enabled failed, HRESULT was " hr ". ErrorLevel was " ErrorLevel
	ExitApp
}

/*
HRESULT ( STDMETHODCALLTYPE *AddStylusSyncPlugin )( 
            __RPC__in IRealTimeStylus * This,
            /* [in] */ ULONG iIndex,
            /* [in] */ __RPC__in_opt IStylusSyncPlugin *piPlugin);
*/


iIndex := 0
StylusSyncPlugin := new IStylusPlugin


hr := DllCall(pAddStylusSyncPlugin, "Ptr", pRealTimeStylus, "UInt", iIndex, "Ptr", StylusSyncPlugin,  "Ptr")
if (hr != S_OK)
{
	MsgBox % "pRealTimeStylus::AddStylusSyncPlugin, HRESULT was " hr ". ErrorLevel was " ErrorLevel
	ExitApp
}




;enable RTS anfer Plugin is added
hr := DllCall(pput_Enabled, "Ptr", pRealTimeStylus, "Short", VARIANT_true, "Ptr")
if (hr != S_OK)
{
	MsgBox % "pRealTimeStylus::put_Enabled failed, HRESULT was " hr ". ErrorLevel was " ErrorLevel
	ExitApp
}

return




class IStylusPlugin
{

	QueryInterface(thisInst,riid,ppvObject){
	
		traytip, , testing
	}
	
	AddRef(thisInst){
	
	}
	
	Release(thisInst){
	
	}
	
	RealTimeStylusEnabled(thisInst,piRtsSrc,cTcidCount,pTcids){
	
	}
	
	RealTimeStylusDisabled(thisInst,piRtsSrc,cTcidCount,pTcids){
	
	}
	
	StylusInRange(thisInst,piRtsSrc,tcid,sid){
	
	}
	
	StylusOutOfRange(thisInst,piRtsSrc,tcid,sid){
	
	}
	
	StylusDown(thisInst,piRtsSrc,pStylusInfo,cPropCountPerPkt,pPacket,ppInOutPkt){
	
	}
	
	StylusUp(thisInst,piRtsSrc,pStylusInfo,cPropCountPerPkt,pPacket,ppInOutPkt){
	
	}
	
	StylusButtonDown(thisInst,piRtsSrc,sid,pGuidStylusButton,pStylusPos){
	
	}
	
	StylusButtonUp(thisInst,piRtsSrc,sid,pGuidStylusButton,pStylusPos){
	
	}
	
	InAirPackets(thisInst,piRtsSrc,pStylusInfo,cPktCount,cPktBuffLength,pPackets,pcInOutPkts,ppInOutPkts){
	
	}
	
	Packets(thisInst,piRtsSrc,pStylusInfo,cPktCount,cPktBuffLength,pPackets,pcInOutPkts,ppInOutPkts){
	
	}
	
	CustomStylusDataAdded(thisInst,piRtsSrc,pGuidId,cbData,pbData){
	
	}
	
	SystemEvent(thisInst,piRtsSrc,tcid,sid,event,eventdata){
	
	}
	
	TabletAdded(thisInst,piRtsSrc,piTablet){
	
	}
	
	TabletRemoved(thisInst,piRtsSrc,iTabletIndex){
	
	}
	
	Error(thisInst,piRtsSrc,piPlugin,dataInterest,hrErrorCode,lptrKey){
	
	}
	
	UpdateMapping(thisInst,piRtsSrc){
	
	}
	
	DataInterest(thisInst,pDataInterest){
	
	}
	
}
rtsHeaderFile https://github.com/tpn/winsdk-7/blob/master/v7.1A/Include/RTSCOM.h

Example of the plugin being created - from https://github.com/microsoft/Windows-classic-samples/blob/master/Samples/Win7Samples/Touch/MTScratchpadRTStylus/cpp/MTScratchpadRTStylus.cpp

Code: Select all


///////////////////////////////////////////////////////////////////////////////
// Real Time Stylus sync event handler

// Synchronous plugin, notitification receiver that changes pen color.
class CSyncEventHandlerRTS : public IStylusSyncPlugin
{
    CSyncEventHandlerRTS();
    virtual ~CSyncEventHandlerRTS();

    public:
    // Factory method
    static IStylusSyncPlugin* Create(IRealTimeStylus* pRealTimeStylus);

    // IStylusSyncPlugin methods

    // Handled IStylusSyncPlugin methods, they require nontrivial implementation
    STDMETHOD(StylusDown)(IRealTimeStylus* piSrcRtp, const StylusInfo* pStylusInfo, ULONG cPropCountPerPkt, LONG* pPacket, LONG** ppInOutPkt);
    STDMETHOD(StylusUp)(IRealTimeStylus* piSrcRtp, const StylusInfo* pStylusInfo, ULONG cPropCountPerPkt, LONG* pPacket, LONG** ppInOutPkt);
    STDMETHOD(Packets)(IRealTimeStylus* piSrcRtp, const StylusInfo* pStylusInfo, ULONG cPktCount, ULONG cPktBuffLength, LONG* pPackets, ULONG* pcInOutPkts, LONG** ppInOutPkts);
    STDMETHOD(DataInterest)(RealTimeStylusDataInterest* pEventInterest);

    // IStylusSyncPlugin methods with trivial inline implementation, they all return S_OK
    STDMETHOD(RealTimeStylusEnabled)(IRealTimeStylus*, ULONG, const TABLET_CONTEXT_ID*) { return S_OK; }
    STDMETHOD(RealTimeStylusDisabled)(IRealTimeStylus*, ULONG, const TABLET_CONTEXT_ID*) { return S_OK; }
    STDMETHOD(StylusInRange)(IRealTimeStylus*, TABLET_CONTEXT_ID, STYLUS_ID) { return S_OK; }
    STDMETHOD(StylusOutOfRange)(IRealTimeStylus*, TABLET_CONTEXT_ID, STYLUS_ID) { return S_OK; }
    STDMETHOD(InAirPackets)(IRealTimeStylus*, const StylusInfo*, ULONG, ULONG, LONG*, ULONG*, LONG**) { return S_OK; }
    STDMETHOD(StylusButtonUp)(IRealTimeStylus*, STYLUS_ID, const GUID*, POINT*) { return S_OK; }
    STDMETHOD(StylusButtonDown)(IRealTimeStylus*, STYLUS_ID, const GUID*, POINT*) { return S_OK; }
    STDMETHOD(SystemEvent)(IRealTimeStylus*, TABLET_CONTEXT_ID, STYLUS_ID, SYSTEM_EVENT, SYSTEM_EVENT_DATA) { return S_OK; }
    STDMETHOD(TabletAdded)(IRealTimeStylus*, IInkTablet*) { return S_OK; }
    STDMETHOD(TabletRemoved)(IRealTimeStylus*, LONG) { return S_OK; }
    STDMETHOD(CustomStylusDataAdded)(IRealTimeStylus*, const GUID*, ULONG, const BYTE*) { return S_OK; }
    STDMETHOD(Error)(IRealTimeStylus*, IStylusPlugin*, RealTimeStylusDataInterest, HRESULT, LONG_PTR*) { return S_OK; }
    STDMETHOD(UpdateMapping)(IRealTimeStylus*) { return S_OK; }

    // IUnknown methods
    STDMETHOD_(ULONG,AddRef)();
    STDMETHOD_(ULONG,Release)();
    STDMETHOD(QueryInterface)(REFIID riid, LPVOID *ppvObj);

private:
    LONG m_cRefCount;                   // COM object reference count
    IUnknown* m_punkFTMarshaller;       // free-threaded marshaller
    int m_nContacts;                    // number of fingers currently in the contact with the touch digitizer
};

// CSyncEventHandlerRTS constructor.
CSyncEventHandlerRTS::CSyncEventHandlerRTS()
:   m_cRefCount(1),
    m_punkFTMarshaller(NULL),
    m_nContacts(0)
{
}

// CSyncEventHandlerRTS destructor.
CSyncEventHandlerRTS::~CSyncEventHandlerRTS()
{
    if (m_punkFTMarshaller != NULL)
    {
        m_punkFTMarshaller->Release();
    }
}

// CSyncEventHandlerRTS factory method: creates new CSyncEventHandlerRTS and adds it to the synchronous
// plugin list of the RTS object.
// in:
//      pRealTimeStylus         RTS object
// returns:
//      CSyncEventHandlerRTS object through IStylusSyncPlugin interface, or NULL on failure
IStylusSyncPlugin* CSyncEventHandlerRTS::Create(IRealTimeStylus* pRealTimeStylus)
{
    // Check input argument
    if (pRealTimeStylus == NULL)
    {
        ASSERT(pRealTimeStylus != NULL && L"CSyncEventHandlerRTS::Create: invalid argument RealTimeStylus");
        return NULL;
    }

    // Instantiate CSyncEventHandlerRTS object
    CSyncEventHandlerRTS* pSyncEventHandlerRTS = new CSyncEventHandlerRTS();
    if (pSyncEventHandlerRTS == NULL)
    {
        ASSERT(pSyncEventHandlerRTS != NULL && L"CSyncEventHandlerRTS::Create: cannot create instance of CSyncEventHandlerRTS");
        return NULL;
    }

    // Create free-threaded marshaller for this object and aggregate it.
    HRESULT hr = CoCreateFreeThreadedMarshaler(pSyncEventHandlerRTS, &pSyncEventHandlerRTS->m_punkFTMarshaller);
    if (FAILED(hr))
    {
        ASSERT(SUCCEEDED(hr) && L"CSyncEventHandlerRTS::Create: cannot create free-threaded marshaller");
        pSyncEventHandlerRTS->Release();
        return NULL;
    }

    // Add CSyncEventHandlerRTS object to the list of synchronous plugins in the RTS object.
    hr = pRealTimeStylus->AddStylusSyncPlugin(
        0,                      // insert plugin at position 0 in the sync plugin list
        pSyncEventHandlerRTS);  // plugin to be inserted - event handler CSyncEventHandlerRTS
    if (FAILED(hr))
    {
        ASSERT(SUCCEEDED(hr) && L"CEventHandlerRTS::Create: failed to add CSyncEventHandlerRTS to the RealTimeStylus plugins");
        pSyncEventHandlerRTS->Release();
        return NULL;
    }

    return pSyncEventHandlerRTS;
}

// Pen-down notification.
// Sets the color for the newly started stroke and increments finger-down counter.
// in:
//      piRtsSrc            RTS object that has sent this event
//      pStylusInfo         StylusInfo struct (context ID, cursor ID, etc)
//      cPropCountPerPkt    number of properties per packet
//      pPacket             packet data (layout depends on packet description set)
// in/out:
//      ppInOutPkt          modified packet data (same layout as pPackets)
// returns:
//      HRESULT error code
HRESULT CSyncEventHandlerRTS::StylusDown(
    IRealTimeStylus* /* piRtsSrc */,
    const StylusInfo* /* pStylusInfo */,
    ULONG /* cPropCountPerPkt */,
    LONG* /* pPacket */,
    LONG** /* ppInOutPkt */)
{
    // Get DrawingAttributes of DynamicRenderer
    IInkDrawingAttributes* pDrawingAttributesDynamicRenderer;
    HRESULT hr = g_pDynamicRenderer->get_DrawingAttributes(&pDrawingAttributesDynamicRenderer);
    if (FAILED(hr))
    {
        ASSERT(SUCCEEDED(hr) && L"CSyncEventHandlerRTS::StylusDown: failed to get RTS's drawing attributes");        
        return hr;
    }

    // Set new stroke color to the DrawingAttributes of the DynamicRenderer
    // If there are no fingers down, this is a primary contact
    hr = pDrawingAttributesDynamicRenderer->put_Color(GetTouchColor(m_nContacts == 0));
    if (FAILED(hr))
    {
        ASSERT(SUCCEEDED(hr) && L"CSyncEventHandlerRTS::StylusDown: failed to set color");
        pDrawingAttributesDynamicRenderer->Release();
        return hr;
    }

    pDrawingAttributesDynamicRenderer->Release();

    ++m_nContacts;  // Increment finger-down counter

    return S_OK;
}

// Pen-up notification.
// Decrements finger-down counter.
// in:
//      piRtsSrc            RTS object that has sent this event
//      pStylusInfo         StylusInfo struct (context ID, cursor ID, etc)
//      cPropCountPerPkt    number of properties per packet
//      pPacket             packet data (layout depends on packet description set)
// in/out:
//      ppInOutPkt          modified packet data (same layout as pPackets)
// returns:
//      HRESULT error code
HRESULT CSyncEventHandlerRTS::StylusUp(
    IRealTimeStylus* /* piRtsSrc */,
    const StylusInfo* /* pStylusInfo */,
    ULONG /* cPropCountPerPkt */,
    LONG* /* pPacket */,
    LONG** /* ppInOutPkt */)
{
    --m_nContacts;  // Decrement finger-down counter

    return S_OK;
}

// Pen-move notification.
// In this case, does nothing, but likely to be used in a more complex application.
// RTS framework does stroke collection and rendering for us.
// in:
//      piRtsRtp            RTS object that has sent this event
//      pStylusInfo         StylusInfo struct (context ID, cursor ID, etc)
//      cPktCount           number of packets
//      cPktBuffLength      pPacket buffer size, in elements, equal to number of packets times number of properties per packet
//      pPackets            packet data (layout depends on packet description set)
// in/out:
//      pcInOutPkts         modified number of packets
//      ppInOutPkts         modified packet data (same layout as pPackets)
// returns:
//      HRESULT error code
HRESULT CSyncEventHandlerRTS::Packets(
    IRealTimeStylus* /* piSrcRtp */,
    const StylusInfo* /* pStylusInfo */,
    ULONG /* cPktCount */,
    ULONG /* cPktBuffLength */,
    LONG* /* pPackets */,
    ULONG* /* pcInOutPkts */,
    LONG** /* ppInOutPkts */)
{
    return S_OK;    
}

// Defines which handlers are called by the framework. We set the flags for pen-down, pen-up and pen-move.
// in/out:
//      pDataInterest       flags that enable/disable notification handlers
// returns:
//      HRESULT error code
HRESULT CSyncEventHandlerRTS::DataInterest(RealTimeStylusDataInterest *pDataInterest)
{
    *pDataInterest = (RealTimeStylusDataInterest)(RTSDI_StylusDown | RTSDI_Packets | RTSDI_StylusUp);

    return S_OK;
}

// Increments reference count of the COM object.
// returns:
//      reference count
ULONG CSyncEventHandlerRTS::AddRef()
{
    return InterlockedIncrement(&m_cRefCount);
}

// Decrements reference count of the COM object, and deletes it
// if there are no more references left.
// returns:
//      reference count
ULONG CSyncEventHandlerRTS::Release()
{
    ULONG cNewRefCount = InterlockedDecrement(&m_cRefCount);
    if (cNewRefCount == 0)
    {
        delete this;
    }
    return cNewRefCount;
}

// Returns a pointer to any interface supported by this object.
// If IID_IMarshal interface is requested, delegate the call to the aggregated
// free-threaded marshaller.
// If a valid pointer is returned, COM object reference count is increased.
// returns:
//      pointer to the interface requested, or NULL if the interface is not supported by this object
HRESULT CSyncEventHandlerRTS::QueryInterface(REFIID riid, LPVOID *ppvObj)
{
    if ((riid == IID_IStylusSyncPlugin) || (riid == IID_IUnknown))
    {
        *ppvObj = this;
        AddRef();
        return S_OK;
    }
    else if ((riid == IID_IMarshal) && (m_punkFTMarshaller != NULL))
    {
        return m_punkFTMarshaller->QueryInterface(riid, ppvObj);
    }

    *ppvObj = NULL;
    return E_NOINTERFACE;
}
sample from MSDN -- https://docs.microsoft.com/en-us/windows/win32/tablet/realtimestylus-plug-in-sample

If anyone has any Ideas on how i can get this working that would be great.

Thanks Grimbot
Post Reply

Return to “Ask for Help (v1)”