Projectreunion: Question: How should I call WinRT Pointer API in a desktop application?

Created on 8 Oct 2020  路  5Comments  路  Source: microsoft/ProjectReunion

Compared with the old Win32 Pointer API, the limitation of 1024 pressure level is removed and has better support for reading stylus's side buttons in WinRT API. This is critical in content creation, as many OEMs are not offering WinTab support for digitizer on 2-in-1/tablets. The pressure level would be limited to 1024 level no matter how high it should have (2048, 4096, or even 8192), letting alone unexpected side button behaviour if vendor driver does something weird, which was asked by me in Microsoft Community.

Misbehaved S Pen side button on a Samsung machine in application using Win32 Pointer API could be seen here: https://filestore.community.support.microsoft.com/api/images/1a5ff4c5-aeda-4c3c-b2ec-3b5856c5fe1a
Note: the side button behaves correctly in UWP applications using WinRT API.

However, the documentation for making this part of WinRT API working in existing desktop application is quite vague. I could only find demo codes using JavaScript or C#, and they're UWP.

Most helpful comment

You can use PointerPoint in a Win32 application! It's missing the attribute. Here's a little sample:

// Uses C++/WinRT
#include <winrt/Windows.UI.Input.h>
void GetPointerPointInfo(HWND window, UINT pointerId)
{
    auto current = winrt::Windows::UI::Input::PointerPoint::GetCurrentPoint(pointerId);
    auto props = current.Properties();
    std::cout << props.Pressure() << std::endl;
    std::cout << props.Orientation() << std::endl;
    std::cout << props.XTilt() << std::endl;
    std::cout << props.YTilt() << std::endl;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    if (MessageIsForPointer(message)) /* WM_POINTER* */
    {
        GetPointerPointInfo(hWnd, GET_POINTERID_WPARAM(wParam));
        return 0;
    }
    else /* ... */
}

For mouse input be sure to call ::EnableMouseInPointer(TRUE) first - it's the default for UWP apps, but not the default for Win32/HWND.

Sadly I don't have a Samsung device or an S pen to try it out.

Unfortunately, Windows.UI.Input.PointerPoint doesn't have DualApiPartitionAttribute, which means it can't be used in Win32 app.

The attribute is unevenly applied. There's lots of APIs that work fine in desktop apps that are missing the attribute. We're working on more granular attributes for requirements - "must be called on a Dispatcher thread" or "must be called in a process with package identity" or "must be called on a foreground thread" ... something we hope to address in Project Reunion.

All 5 comments

Unfortunately, Windows.UI.Input.PointerPoint doesn't have DualApiPartitionAttribute, which means it can't be used in Win32 app.

You can use PointerPoint in a Win32 application! It's missing the attribute. Here's a little sample:

// Uses C++/WinRT
#include <winrt/Windows.UI.Input.h>
void GetPointerPointInfo(HWND window, UINT pointerId)
{
    auto current = winrt::Windows::UI::Input::PointerPoint::GetCurrentPoint(pointerId);
    auto props = current.Properties();
    std::cout << props.Pressure() << std::endl;
    std::cout << props.Orientation() << std::endl;
    std::cout << props.XTilt() << std::endl;
    std::cout << props.YTilt() << std::endl;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    if (MessageIsForPointer(message)) /* WM_POINTER* */
    {
        GetPointerPointInfo(hWnd, GET_POINTERID_WPARAM(wParam));
        return 0;
    }
    else /* ... */
}

For mouse input be sure to call ::EnableMouseInPointer(TRUE) first - it's the default for UWP apps, but not the default for Win32/HWND.

Sadly I don't have a Samsung device or an S pen to try it out.

Unfortunately, Windows.UI.Input.PointerPoint doesn't have DualApiPartitionAttribute, which means it can't be used in Win32 app.

The attribute is unevenly applied. There's lots of APIs that work fine in desktop apps that are missing the attribute. We're working on more granular attributes for requirements - "must be called on a Dispatcher thread" or "must be called in a process with package identity" or "must be called on a foreground thread" ... something we hope to address in Project Reunion.

Did I mess something up? I only added #include <windows.h> at the beginning but Visual Studio throw an unresolved external symbol error:

1>------ Rebuild All started: Project: WinRT C++ Ink Demo, Configuration: Debug x64 ------
1>WinRT C++ Ink Demo.cpp
1>MSVCRTD.lib(exe_main.obj) : error LNK2019: unresolved external symbol main referenced in function "int __cdecl invoke_main(void)" (?invoke_main@@YAHXZ)
1>C:\Users\Aster\Source\Repos\WinRT C++ Ink Demo\x64\Debug\WinRT C++ Ink Demo.exe : fatal error LNK1120: 1 unresolved externals
1>Done building project "WinRT C++ Ink Demo.vcxproj" -- FAILED.
========== Rebuild All: 0 succeeded, 1 failed, 0 skipped ==========

I'm using latest Insider dev Windows SDK (10.0.20231.0). Using an older Windows SDK (Below is using 10.0.18362.0 SDK) would throw more unresolved symbol error:

1>------ Build started: Project: WinRT C++ Ink Demo, Configuration: Debug x64 ------
1>WinRT C++ Ink Demo.obj : error LNK2019: unresolved external symbol WINRT_GetRestrictedErrorInfo referenced in function "public: __cdecl winrt::hresult_error::hresult_error(struct winrt::hresult,struct winrt::hresult_error::from_abi_t)" (??0hresult_error@winrt@@QEAA@Uhresult@1@Ufrom_abi_t@01@@Z)
1>WinRT C++ Ink Demo.obj : error LNK2019: unresolved external symbol WINRT_RoGetActivationFactory referenced in function "__cdecl winrt::get_activation_factory<struct winrt::Windows::UI::Input::IPointerPointStatics>(struct winrt::param::hstring const &)" (??$get_activation_factory@UIPointerPointStatics@Input@UI@Windows@winrt@@@winrt@@YA@AEBUhstring@param@0@@Z)
1>WinRT C++ Ink Demo.obj : error LNK2019: unresolved external symbol WINRT_RoOriginateLanguageException referenced in function "private: void __cdecl winrt::hresult_error::originate(struct winrt::hresult,void *)" (?originate@hresult_error@winrt@@AEAAXUhresult@2@PEAX@Z)
1>WinRT C++ Ink Demo.obj : error LNK2019: unresolved external symbol WINRT_WindowsCreateStringReference referenced in function "public: __cdecl winrt::param::hstring::hstring(class std::basic_string_view<wchar_t,struct std::char_traits<wchar_t> > const &)" (??0hstring@param@winrt@@QEAA@AEBV?$basic_string_view@_WU?$char_traits@_W@std@@@std@@@Z)
1>MSVCRTD.lib(exe_main.obj) : error LNK2019: unresolved external symbol main referenced in function "int __cdecl invoke_main(void)" (?invoke_main@@YAHXZ)
1>C:\Users\Aster\Source\Repos\WinRT C++ Ink Demo\x64\Debug\WinRT C++ Ink Demo.exe : fatal error LNK1120: 5 unresolved externals
1>Done building project "WinRT C++ Ink Demo.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

@Aster-the-Med-Stu

For the issue on the top, the linker thinks you're writing a CLI app when you're not; you can fix that in Project Properties > Linker. For the bottom issue, try adding windowsapp.lib to your application's linkline.

The current scenario is quite awkward. I'm trying to bring WinRT Ink API to Krita (C++ and Qt). The problem is that it won't build using msvc/Clang, thus I couldn't call WinRT API directly. (mainly because it uses many Linux libraries which isn't quite fit for MSVC/clang and C++ subversion support isn't that new. Documented way to build Krita under Windows is using MinGW-w64).

Personally, I think I could write and build a custom DLL that reads from WinRT Ink API and "exposes" it for Krita to use. But this is making things more complicated. Googling doesn't offer valuable results for calling WinRT API in a normal win32 DLL.

(If anyone came across here, the guide for using WinRT component in win32 C++ desktop app is at https://blogs.windows.com/windowsdeveloper/2019/04/30/enhancing-non-packaged-desktop-apps-using-windows-runtime-components/)

Another question I am curious is that why I couldn't read mouse event through Python/WinRT (https://github.com/microsoft/xlang/issues/711). There is no demo and I am not sure how WinRT API projection works.

Was this page helpful?
0 / 5 - 0 ratings