[KOSD Series] When Surface Dial meets UWP

Starting from end of last year, I have been working on several UWP projects at work. Few days ago, I’m glad to have the opportunity to borrow a Surface Dial from Riza.

Surface Dial is a revolutionary input device. It was introduced by Microsoft in the 2016 together with Surface Studio. Most of the time, it works awesome on Surface devices. However, that doesn’t mean we can’t use it with our Windows desktop or laptop. As a secondary input device, it can be used together with our mouse or touch. Developers are also welcomed to customize the abilities of the Surface Dial on their UWP apps.

In this article, I will be sharing on how we can use Surface Dial to support a quick menu of commands in an UWP app.

Installing Surface Dial

First of all, we need to make sure our Windows device is on (Yes, UWP currently can only work on Windows machines). Then we need to turn on the Bluetooth on the machine. If our PC doesn’t come with the Bluetooth hardware installed, we can easily add it by purchasing a Bluetooth USB dongle.

After that, we need to turn our Surface Dial on by removing the cover of its bottom and then pressing the button next to the batteries, as shown in the photo below.

🎨 Added Surface Dial to my PC. 🎨

Now we can find the Surface Dial on the “Bluetooth & other devices” window. We can proceed to add it to our PC.

Adding Menu on Surface Dial

For those who attended my sharing in Microsoft Insider Dev Tour 2019 in Kuala Lumpur and Johor Bahru last year, the following UWP app should be familiar to you.

🎨 The UWP demo app done by Justin Liu for Microsoft Insider Dev Tour. 🎨

Now we will proceed to add Surface Dial menu to this page.

In the code-behind of the page, we will have the following global objects.

private RadialController radialController;
private RadialControllerConfiguration radialControllerConfig;

Then, we can initialize the RadialController.

// Create a reference to the RadialController.
radialController = RadialController.CreateForCurrentView();
// Set rotation resolution to 1 degree of sensitivity.
radialController.RotationResolutionInDegrees = 1;

What does setting RotationResolutionInDegrees mean here? The value actually is the minimum rotation value required for the RotationChanged event to be fired. So, by setting it to 1, every one degree of rotate on the Surface Dial, the RotationChanged event will be triggered. Also, by default, when the RotationChanged happens, the Surface Dial will vibrate. So it is like massaging your hand when you’re rotating the Surface Dial that has its RotationResolutionInDegrees set to 1.

Then we can proceed to add our menu items to the Surface Dial. Here, we use a font glyph for the custom tool.

var imageGallery = RadialControllerMenuItem.CreateFromFontGlyph("Image Gallery", "\xE15A", "Segoe MDL2 Assets");
...
radialController.Menu.Items.Add(imageGallery);

However, please take note that, by default, there are built-in menu items for the Surface Dial. So we need to remove them to prevent squeezing in too much menu items to the Surface Dial UI and thus making it harder to control.

To remove the built-in menu items, we just need to reset in the configuration of the Surface Dial. Another thing to take note is that the Surface Dial menu must have at least one menu item, else the default menu items will be restored.

radialControllerConfig = RadialControllerConfiguration.GetForCurrentView();

radialControllerConfig.SetDefaultMenuItems(new RadialControllerSystemMenuItemKind[] { });

Now there is a funny thing is that if we remove all the built-in menu items before we add our customized menu items, i.e swapping the position of the two blocks of codes above, then we will realize that the default menu items will be restored and our customized menu items will be appended to the default ones, as shown in the screenshot below.

🎨 Oh my tian, the buttons on the Surface Dial menu are so crowded! 🎨

Finally, if we want to handle the events fired from the Surface Dial, for example when users click on it or rotate it, we can use the following handlers.

radialController.ButtonClicked += RadialController_ButtonClicked;
radialController.RotationChanged += RadialController_RotationChanged;

Please take note that the ButtonClicked event is not triggered when a menu item is selected. Instead we need to do as follows to handle the menu item chosen event.

imageGallery.Invoked += ImageGallery_Invoked;

Result

So, now, with all these few lines of codes, we can have a beautiful Surface Dial control on our UWP app, as shown in the following photo. Yay!

🎨 Control the universe with our hand. 🎨

References

  1. Support the Surface Dial (and other wheel devices) in your UWP app;
  2. Creating Custom Dial Menu.

KOSD, or Kopi-O Siew Dai, is a type of Singapore coffee that I enjoy. It is basically a cup of coffee with a little bit of sugar. This series is meant to blog about technical knowledge that I gained while having a small cup of Kopi-O Siew Dai.

#net-core, #c, #surface, #surface-dial, #uwp