Lenovo Horizon Striker






4.27/5 (3投票s)
使用 WPF 应用程序检测 Lenovo Horizon Striker 配件
引言
在本文中,我将提供一个简单的示例,说明如何让 WPF 应用程序检测联想 Striker。联想 Striker 是 联想 Horizon 一体机的配件。通过在触摸屏表面滑动它,Striker 可以用于一些预装的 Horizon 游戏,例如联想空气曲棍球。由于截至撰写本文时,没有关于如何在 WPF 应用程序中使用 Striker 配件的文档,因此希望本文能成为一个有用的和鼓舞人心的指南。以下视频展示了示例应用程序的实际运行情况。
Striker 配件
Striker 本质上充当一个手写笔。在 Striker 的底部有四个圆形垫,其中两个提供手写笔输入。
这两个较大的垫充当手写笔输入的接触点。为了在我的 WPF 示例中使用 Striker,我将找到屏幕上每个接触垫的接触点;使用两组坐标找到 Striker 的“中心”;然后在屏幕上将一个Ellipse
直接放置在 Striker 下方。
示例项目的 XAML 标记非常简单,
<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>
请注意,我将处理一些手写笔事件;特别是StylusDown
、StylusMove
和 StylusUp
事件。当 Striker 放置在屏幕上时,将向 Canvas
添加一个 Ellipse
,并且当 Striker 在屏幕上移动时,它将跟随 Striker 移动。
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
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);
}
}
}
每个接触垫将具有一个手写笔设备 ID,该 ID 用作 Dictionary
集合中的键,其 Value
是垫的屏幕坐标。现在,如果我将 Ellipse
放置在 Canvas
上,在计算出的 Striker 中心坐标处,Ellipse
将会大大偏移。
请记住,在 WPF 中,Ellipse
的坐标点位于左上角。为了正确对齐,我将在 PositionEllipse()
方法中从计算出的值中减去 Ellipse
的半径。
结论
我希望您发现本文中的信息有用,特别是那些在 Intel AIC 2013 竞赛中获得一体机的人。也许第二轮提交的一些应用程序可以使用这个有趣的配件。
历史
- 2013 年 11 月 20 日:初始发布