Wednesday 17 June 2020

A cure for Win10 in Tablet mode

- or how to detect tablet mode in Windows 10 from Delphi.



Sorry about the cure-tablet pun, but Windows 10 is not able yet to enter Pill mode.

This small post is actually also about wrapping Win10 SDK apis, that might not have been fully implemented as Delphi classes/interfaces or are missing because of their little use - which incidentally is that ones I often miss.

I was getting a bit frustrated refactoring some old code, and thought that it would be fun to add a Windows 10 feature to the project instead - and since I was sitting on an old Surface - I could switch that into "Tablet" mode.


But my internet search was a bit disappointing - one SO entry that suggested to use an external DLL - and then the reference guide from Raymond Chen, which is always great, but his examples are still not in Delphi or ObjectPascal.

I was pretty sure the unit Winapi.UI.ViewManagement had everything I needed, so in my head the test code would look something like this - which was a lot nicer than the SO and the C++ samples:

uses
  Winapi.UI.ViewManagement;

procedure TForm1.Button1Click(Sender: TObject);
var
  UI: TUIViewSettings;
  UIView: IUIViewSettings;
begin
    UI := TUIViewSettings.Create;
    try
      UIView := UI.GetForWindow(Self.Handle);
      case UIView.UserInteractionMode of
        0: Memo1.Lines.Add('Normal mouse mode.');
        1: Memo1.Lines.Add('Tablet mode.');
      end;
    finally
      UI.Free;
    end;
  end;
end;

..but no GetForWindow was implemented, so no interoperability between the UWP/WinRT view and my window handle. The implementation of IUIViewSettingsInterop was missing. The cause is probably that the interop header is located somewhere completely different compared to some of the other interop headers - and just looking at Raymonds post with reference to WRL, which I guess you now should move to WinRT and then to ??

Keeping track of the ever changing landscape of Windows SDKs and UI frameworks is not what I spend most of my time on - but in these days one might hope for a "reunion" - we just had a 100th year anniversary on one, from the part in Denmark where I was born. See Genforeningen2020

It had been years since I had converted .h headers or created .tlb from .idl files, which was the route I was sure I had to ascend down.

After not having much success, I swallowed my pride, and asked some grown-ups for help - but it seemed that no-one had had the stupid idea before me.

But that actually made me step back - and think the answer is in the source - Embarcadero had implemented other WinRT interfaces - just not the one I needed, so given the "Windows 10 SharingContract" sample I found an example on how the WinAPI.ApplicationModel.DataTransferInterop interface was implemented, using the TWinRTImportHelper class and others. So the unit System.Win.WinRT is you little helper.

I did, for now, end up messing up a local copy of Winapi.UI.ViewManagement.pas - so these are the additions - that I will put in a separate unit - until Embarcadero hopefully gets them included - vote for RSP-29682 :)

I added these lines:

// Interop Intf: "IUIViewSettingsInterop"
  IUIViewSettingsInterop = interface(IInspectable)
    ['{3694DBF9-8F68-44BE-8FF5-195C98EDE8A6}']
    function GetForWindow(appWindow: THandle; const riid: TGUID): IUIViewSettings; safecall;
  end;

and changed this:

TUIViewSettings = class(TWinRTGenericImportS<IUIViewSettingsStatics>)
to
TUIViewSettings = class(TWinRTGenericImportSO<IUIViewSettingsStatics, IUIViewSettingsInterop>)

All done - and now the actual working test code example looks like this:

uses
  Winapi.CommonTypes,
  System.Win.WinRT,
  Winapi.UI.ViewManagement;
...
procedure TForm1.Button1Click(Sender: TObject);
var
  UI: TUIViewSettings;
  UIView: Winapi.UI.ViewManagement.IUIViewSettings;
begin
  if TOSVersion.Check(10) then
  begin
    UI := TUIViewSettings.Create;
    try
      UIView := UI.Interop.GetForWindow(Self.Handle, TWinRTImportHelper.GetUIID<IUIViewSettings>);
      case UIView.UserInteractionMode of
        UserInteractionMode.Mouse: Memo1.Lines.Add('Normal mouse mode.');
        UserInteractionMode.Touch: Memo1.Lines.Add('Tablet mode.');
      end;
    finally
      UI.Free;
    end;
  end;
end;

Thanks to Embarcadero for bringing me out of my comfort zone - looking at .h and .idl files again, just to let me discover the WinRT helpers they DID provide - the answers are in the source.

Enjoy.

5 comments:

  1. Honestly I cant tell by the blog 9f your still working on siege of Avalon I'm genuinely curious about that project of yours

    ReplyDelete
    Replies
    1. Hi, I am - see answer to your comment in the cure for pox post. I have a build where SoAOS "works" in tablet mode, but I need to redefine some keys. Not sure if I will commit this. Getting the non-dfx stuff done is the most important (and refactoring) - before change of graphic backend. And some recent changes to POXStudio is also overdue. Thanks for showing interest and let me know if there is something specific you want to see in SoAOS.
      Have a nice day and take care out there. This is an edit of previous answer - which had "fat fingers on phone"-typos :)

      Delete
    2. I'm not a programmer by any extent but I would like to contribute in some way if possible this game hold a special place in my heart and if I can be involved I'd like to be.

      As far as features go there was a lot of the keep we didn't get to see if possible could those be added since I'm not a programmer I do t know what level of work that would require so sorry in Advance if that's a tall order

      Delete
    3. Sorry missed you reply - things currently get lost in my reorg. inbox - anyway as I remember some of the rooms are available in the later chapters - have you played all 6? How is your German - there is a lot of info on http://soamigos.de/wbb5/forum/ - and there are several mod projects that tells the story what happens after SoA - but they are mostly in German :) The old Chap(ter)Editor is available and some of the other tools but they are in a sad state - if you ask me. And I would love to solve that eventually - like I started to do with the POXStudio project. Progress is slow - and even worse here in summer. One thing that could be helpful is testing the changes that is done to the engine - so I will put releases up, if you are not able to compile the game yourself.

      Delete
  2. This comment has been removed by the author.

    ReplyDelete