Update: here’s a small video of the extension in action
The Surface Dial is a nifty little device, it feels great and can add some nice capabilities to your apps. However, the very best thing about it is that is has an API. I had a go with it and decided to try and turn the dial into a debugging device.
The Dial has a few gestures. It’s a button that you can press, and it rotates clockwise and counter-clockwise. My goal was to start a debugging session by clicking the Dial, Step-Over (F10) by rotating clockwise and Step-Into (F11) by rotating counter-clockwise.
We’ll need some stuff to get going:
Setting up a Visual Studio Extension
To start creating a Visual Studio Extension, launch Visual Studio 2015 and start a new project. If the SDK is installed correctly there should be an Extensibility option with a VSIX Project template.
The project it creates is basically an empty box, just some boilerplate code to have a VSIX installer and have it install your extension in VS. To start adding some functionality to the extension we need to add an extra item, in this case it will be a package, these are added as a new item into the project.
Almost ready, all we need to add next is when our extension should load. We’re going to choose for load on solution load in this sample. This is done by adding an attribute on the package class.
Thrown together, we get:
If you press F5 now, an experimental instance of Visual Studio should launch, with the extension installed.
Connecting to the Dial
This was the hardest part of the project, the Dial API is done in UWP. This is how we can grab the Dial instance in UWP (currently only one dial is supported per system)
var controller = RadialController.CreateForCurrentView();
The problem here is not the fact that it’s a UWP API, we can use those from win32. The problem is that the CreateForCurrentView() method requires a handle to the current window, a UWP window, which we obviously don’t have. I found the solution for this in one of the official Microsoft samples. They have a sample in the windows-classic-samples repository that shows how to access the Dial from a WinForms application.
I took the RadialControllerInterop class from that sample and added it to the extension. however, as it turned out, it was only part of the solution.
The interop interfaces actually reference the RadialController class that lives in Windows.UI.Input, a UWP namespace that we currently have no reference to. That’s where the UwpDesktop NuGet package comes in. This package makes it easy to reference UWP classes from win32 style applications. Once added through NuGet we can add the Windows.UI.Input namespace to the interop class.
We’ve got everything in place to connect to the Dial from Visual Studio.
Glueing it together
Back to the package class, there should be an Initialize method, overridden from the base class. This is where we’ll hook everything up.
First thing we’ll do is grab hold of the current Visual Studio instance, which is a DTE object. We keep a reference to this object in a field because we’ll need it later.
Next up is connecting to the Dial
In this method we’re using interop to get access to the UWP RadialController class via the interface we took from the classic windows samples. As a handle for the windows we pass in the handle for our current Visual Studio instance which we can get to from the DTE object. At this point we got a reference to the Dial that is connected to our system.
The Dial has a radial menu that we can hook into and add or remove items from it. We’ll add a Debug item to it.
I’m doing this through a list just in case I ever want to add more items, but at the moment I’m only adding one. A RadialControllerMenuItem is created via the CreateFromKnownIcon method. First parameter is the text that will be displayed in the menu, the second one is an enum value from an enum that contains some known menu icons. A RadialController has a menu property that has a collection of items, all we need to do is add our items to that collection and it will show up in the radial menu.
Final step is adding the event handlers and calling the debugger methods to let the Dial step through the code.
As you can see, the events coming from the dial are very straightforward, there’s a ButtonClicked and a RotationChanged event.
Here’s what we need to do to start debugging on button click:
The Visual Studio SDK provides an easy to use API surface. We can use the DTE.Application.Debugger class to control the debugger. The Go() method launches a debug session, the Stop() method, well, stops a debugging session.
Next, we’ll handle the rotation events
From the args we get the rotation delta, one step on the rotator is a delta of 10, +10 clockwise and –10 counter-clockwise.
And that’s it, build it in release mode and the bin/release folder will contain a .vsix installer file. Close VS, install the extension, reopen VS, open a solution, select Debug from the radial menu and debug away!
The source code is on GitHub. Here’s a link to the compiled VSIX file.
Disclaimer: the code is provided as-is. I do not plan to publish this on the gallery or maintain the project. Do feel free to pick this up and create an open-source project from it (would be nice to include a reference to this post in the description )