Click here to Skip to main content
15,867,308 members
Articles / Desktop Programming / WPF

Lenovo Horizon Striker

Rate me:
Please Sign up or sign in to vote.
4.27/5 (3 votes)
20 Nov 2013CPOL2 min read 30.2K   123   3   19
Detecting a Lenovo Horizon Striker accessory with a WPF application

Image 1

Introduction

In this article I will provide a simple example of how to get a WPF application to detect a Lenovo striker. The Lenovo striker is an accessory for the Lenovo Horizon All-in-One PC. The striker can be used with some of the pre-loaded Horizon games, like Lonovo Air Hockey, by sliding it around the touchscreen surface. Since, as of the time of writing, there is no documentation on how to use the striker accessory with a WPF application this article will hopefully be a useful and inspirational guide. The following video shows the sample application in action.

Image 2

Striker Accessory

The striker essentially acts as a stylus. At the bottom of the striker there are four circular pads, two of which provide stylus input.

Image 3

The two larger pads act as contact points for stylus input. To make use of the striker in my WPF sample I will find the points of contact, on the screen, of each of the two contact pads; find the 'center' of the striker using the two sets of coordinates; then place an Ellipse directly under the striker.

The XAML markup for the sample project is a simple affair,

XML
<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="LenovoStriker" Height="514" Width="678" WindowState="Maximized">
    <Grid>
        <Canvas x:Name="StylusCanvas" Background="White" StylusDown="StylusCanvas_StylusDown"
                StylusMove="StylusCanvas_StylusMove" StylusUp="StylusCanvas_StylusUp"/>        
    </Grid>
</Window>

Notice that I will be handling some stylus events; specifically the StylusDown,

StylusMove
, and StylusUp events. An Ellipse will be added to the Canvas when the striker is placed on the screen and will follow the striker as it is moved around the screen.

VB.NET
Class MainWindow
    Private strikerPads As New Dictionary(Of Integer, Point)()
    Private diameter As Integer = 160
    Private radius As Integer = 80
    Private strikerEllipse As New Ellipse With {.Height = diameter, .Width = diameter,
                                                .Stroke = Brushes.Black, .StrokeThickness = 2,
                                                .Fill = Brushes.Yellow}

    Private Sub StylusCanvas_StylusDown(sender As Object, e As StylusDownEventArgs)
        Dim padPoint As Point = e.GetPosition(StylusCanvas)
        strikerPads.Add(e.StylusDevice.Id, padPoint)

        If (strikerPads.Count = 2) Then
            PositionEllipse()
            StylusCanvas.Children.Add(strikerEllipse)
        End If
    End Sub

    Private Sub StylusCanvas_StylusMove(sender As Object, e As StylusEventArgs)
        Dim padPoint As Point = e.GetPosition(StylusCanvas)
        strikerPads(e.StylusDevice.Id) = padPoint
        PositionEllipse()
    End Sub

    Private Sub PositionEllipse()
        Dim pad_1 As Point = strikerPads.First.Value
        Dim pad_2 As Point = strikerPads.Last.Value

        Dim y1 As Integer = CInt(pad_1.Y)
        Dim y2 As Integer = CInt(pad_2.Y)
        Dim x1 As Integer = CInt(pad_1.X)
        Dim x2 As Integer = CInt(pad_2.X)

        Dim yDiff As Integer = Math.Abs(y1 - y2)
        Dim xDiff As Integer = Math.Abs(x1 - x2)

        Dim x As Integer
        Dim y As Integer

        If (x1 < x2) Then
            x = x1 + (xDiff / 2) - radius
        Else
            x = x2 + (xDiff / 2) - radius
        End If

        If (y1 < y2) Then
            y = y1 + (yDiff / 2) - radius
        Else
            y = y2 + (yDiff / 2) - radius
        End If

        Canvas.SetLeft(strikerEllipse, x)
        Canvas.SetTop(strikerEllipse, y)
    End Sub
  
    Private Sub StylusCanvas_StylusUp(sender As Object, e As StylusEventArgs)
        If (StylusCanvas.Children.Contains(strikerEllipse)) Then
            StylusCanvas.Children.Remove(strikerEllipse)
        End If
        strikerPads.Remove(e.StylusDevice.Id)
    End Sub
End Class
C#
namespace LenovoStriker
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private Dictionary<int, Point> strikerPads = new Dictionary<int,Point>();
        private static int diameter = 160;
        private static int radius = 80;
        private Ellipse strikerEllipse = new Ellipse()
        {
            Height = diameter,
            Width = diameter,
            Stroke = Brushes.Black,
            StrokeThickness = 2,
            Fill = Brushes.Yellow
        };

        private void StylusCanvas_StylusDown(object sender, StylusDownEventArgs e)
        {
            Point padPoint = e.GetPosition(StylusCanvas);
            strikerPads.Add(e.StylusDevice.Id, padPoint);

            if (strikerPads.Count == 2)
            {
                PositionEllipse();
                StylusCanvas.Children.Add(strikerEllipse);
            }
        }

        private void StylusCanvas_StylusMove(object sender, StylusEventArgs e)
        {
            Point padPoint = e.GetPosition(StylusCanvas);
            strikerPads[e.StylusDevice.Id] = padPoint;            
            PositionEllipse();               
        }

        private void PositionEllipse()
        {
            Point pad_1 = strikerPads.First().Value;
            Point pad_2 = strikerPads.Last().Value;

            int y1 = (int)pad_1.Y;
            int y2 = (int)pad_2.Y;
            int x1 = (int)pad_1.X;
            int x2 = (int)pad_2.X;

            int yDiff = Math.Abs(y1 - y2);
            int xDiff = Math.Abs(x1 - x2);

            int x;
            int y;

            if (x1 < x2)
            {
                x = x1 + (xDiff / 2) - radius;
            }
            else
            {
                x = x2 + (xDiff / 2) - radius;
            }

            if (y1 < y2)
            {
                y = y1 + (yDiff / 2) - radius;
            }
            else
            {
                y = y2 + (yDiff / 2) - radius;
            }

            Canvas.SetLeft(strikerEllipse, x);
            Canvas.SetTop(strikerEllipse, y);
        }

        private void StylusCanvas_StylusUp(object sender, StylusEventArgs e)
        {
            if (StylusCanvas.Children.Contains(strikerEllipse))
            {
                StylusCanvas.Children.Remove(strikerEllipse);
            }
            strikerPads.Remove(e.StylusDevice.Id);
        }
    }
}

Each of the contact pads will have a stylus device ID which is used as a key in a Dictionary collection whose Values are the on-screen coordinates of the pads. Now if I was to place the Ellipse on the Canvas, at the calculated coordinates of the striker center, the Ellipse would be greatly offset.

Image 4

Remember that in WPF the coordinate points of an Ellipse are at the top-left corner. For proper alignment I subtract the radius of the Ellipse from the calculated values in the PositionEllipse() method.

Conclusion

I hope that you found the information in this article useful, especially those who received a AIO in the Intel AIC 2013 competition. Maybe some of the apps that were submitted in Round Two could make use of this interesting accessory.

History

  • 20th Nov 2013: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Kenya Kenya
Experienced C# software developer with a passion for WPF.

Awards,
  • CodeProject MVP 2013
  • CodeProject MVP 2012
  • CodeProject MVP 2021

Comments and Discussions

 
QuestionLenovo Horizon EDice Pin
ThPratik20-Nov-13 6:52
ThPratik20-Nov-13 6:52 
AnswerRe: Lenovo Horizon EDice Pin
Meshack Musundi20-Nov-13 7:00
professionalMeshack Musundi20-Nov-13 7:00 
GeneralRe: Lenovo Horizon EDice Pin
linkedPIXEL20-Nov-13 7:58
linkedPIXEL20-Nov-13 7:58 
GeneralRe: Lenovo Horizon EDice Pin
Meshack Musundi20-Nov-13 8:34
professionalMeshack Musundi20-Nov-13 8:34 
I doubt I'd get a replacement from Intel now. Frown | :(
"As beings of finite lifespan, our contributions to the sum of human knowledge is one of the greatest endeavors we can undertake and one of the defining characteristics of humanity itself"

GeneralRe: Lenovo Horizon EDice Pin
linkedPIXEL20-Nov-13 11:31
linkedPIXEL20-Nov-13 11:31 
GeneralRe: Lenovo Horizon EDice Pin
ThPratik20-Nov-13 17:37
ThPratik20-Nov-13 17:37 
GeneralRe: Lenovo Horizon EDice Pin
linkedPIXEL20-Nov-13 17:48
linkedPIXEL20-Nov-13 17:48 
GeneralRe: Lenovo Horizon EDice Pin
Adam David Hill21-Nov-13 8:39
professionalAdam David Hill21-Nov-13 8:39 
QuestionTouch Count Issue Pin
Adam David Hill19-Nov-13 23:19
professionalAdam David Hill19-Nov-13 23:19 
AnswerRe: Touch Count Issue Pin
Meshack Musundi19-Nov-13 23:51
professionalMeshack Musundi19-Nov-13 23:51 
GeneralRe: Touch Count Issue Pin
Adam David Hill20-Nov-13 0:07
professionalAdam David Hill20-Nov-13 0:07 
GeneralRe: Touch Count Issue Pin
Meshack Musundi20-Nov-13 0:13
professionalMeshack Musundi20-Nov-13 0:13 
QuestionYes, but ... Pin
Florian Rappl19-Nov-13 22:00
professionalFlorian Rappl19-Nov-13 22:00 
AnswerRe: Yes, but ... Pin
Meshack Musundi19-Nov-13 22:39
professionalMeshack Musundi19-Nov-13 22:39 
GeneralRe: Yes, but ... Pin
Florian Rappl19-Nov-13 22:53
professionalFlorian Rappl19-Nov-13 22:53 
GeneralRe: Yes, but ... Pin
Meshack Musundi19-Nov-13 23:10
professionalMeshack Musundi19-Nov-13 23:10 
GeneralRe: Yes, but ... Pin
Meshack Musundi19-Nov-13 23:17
professionalMeshack Musundi19-Nov-13 23:17 
GeneralRe: Yes, but ... Pin
Florian Rappl19-Nov-13 23:25
professionalFlorian Rappl19-Nov-13 23:25 
GeneralRe: Yes, but ... Pin
Meshack Musundi19-Nov-13 23:56
professionalMeshack Musundi19-Nov-13 23:56 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.