In my previous posts about Kinect, I've showed how to get started, how to change Angles and more cool stuff, but now it's time to start working on the real things, how to enable Kinect to your environment, I'm talking about PC.
You may say Kinect is not yet perfect and the precision of the Skeleton Tracking system isn't 100% accurate, and if you have to stand at least 1 meter from the screen how you will be able to see something from that distance? Even more how to perform a Click? (Raising the other hand isn't a good solution, but checking the distance of the hand can help us to do that – I'll show more later.)
Several posts ago, I've talked about Masking in WPF and showed how to create WP7 The Mask Way– Rating Control and More. In this post, I'll use the same concept to Create Kinect Buttons that can fit for PC.
How?
There are several ways to accomplish that, the one I'm going to show is by Timer
– same as the XBox Kinect concept you will move the Kinect Cursor over the Button
then based on the Time you want the user has to hold the cursor in the same position and if he completes the time period, then a Click
event will be fired.
Step 1: Create a New Control
Create XAML: I've used the same concept as the Rating Control Mask and define the Border Path, Mask and the Fill and also added a Text Block to display the Text on the button.
<Grid x:Name="LayoutRoot">
<Path x:Name="FillPath" Stretch="Fill" Data="F1 M 113.302,91.7188C 113.302,103.641
103.642,113.299 91.7213,113.299L 21.582,113.299C 9.66146,113.299 7.62939e-006,103.641
7.62939e-006,91.7188L 7.62939e-006,21.5821C 7.62939e-006,9.66148
9.66146,2.47955e-005 21.582,2.47955e-005L 91.7213,2.47955e-005C 103.642,
2.47955e-005 113.302,9.66148
113.302,21.5821L 113.302,91.7188 Z " Margin="8,8,0,0" Height="113"
HorizontalAlignment="Left" Width="113" VerticalAlignment="Top"
Fill="{Binding PathFill}">
</Path>
<Rectangle x:Name="Mask" Fill="White" Height="121" VerticalAlignment="Top"
HorizontalAlignment="Left" Width="129" RenderTransformOrigin="0.5,0.5" >
</Rectangle>
<Path x:Name="BorderPath" Stretch="Fill" StrokeThickness="0.591467"
StrokeLineJoin="Round" Stroke="#FF777677"
Data="F1 M 121.384,99.8022C 121.384,111.724 111.724,121.383
99.8035,121.383L 29.6642,121.383C 17.7436,121.383 8.08218,111.724
8.08218,99.8022L 8.08218,29.6655C 8.08218,17.745 17.7436,8.0835
29.6642,8.0835L 99.8035,8.0835C
111.724,8.0835 121.384,17.745 121.384,29.6655L 121.384,
99.8022 Z M 104.624,0.295738L 24.8439,0.295738C 11.2853,
0.295738 0.295734,11.2866 0.295734,24.8439L
0.295734,104.624C 0.295734,118.181 11.2853,129.172 24.8439,
129.172L 104.624,129.172C 118.181,129.172 129.172,118.181 129.172,
104.624L 129.172,24.8439C
129.172,11.2866 118.181,0.295738 104.624,0.295738 Z "
HorizontalAlignment="Left" Width="129" Height="129" VerticalAlignment="Top">
<Path.Fill>
<LinearGradientBrush StartPoint="0.5,6.51193e-007" EndPoint="0.5,1">
<LinearGradientBrush.GradientStops>
<GradientStop Color="#FFDED9D2" Offset="0" />
<GradientStop Color="#FF858681" Offset="0.154192" />
<GradientStop Color="#FF2D3330" Offset="0.26404" />
<GradientStop Color="#FF969997" Offset="0.383313" />
<GradientStop Color="#FFFFFFFF" Offset="0.57303" />
<GradientStop Color="#FF7F7F7F" Offset="0.735806" />
<GradientStop Color="#FF000000" Offset="1" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Path.Fill>
</Path>
<TextBlock Name="txtHeader" Text="{Binding DisplayText}"
Foreground="{Binding DisplayTextColor}" TextAlignment="Center"
TextWrapping="WrapWithOverflow" FontSize="38"
VerticalAlignment="Center" HorizontalAlignment="Center" />
</Grid>
Define the basic properties for your button control, for example I've defined some DependencyProperty
for Time Interval, Fill Path Color and Display Text, etc…
public int Time
{
get { return (int)this.GetValue(TimeProperty); }
set { this.SetValue(TimeProperty, value); }
}
public static readonly DependencyProperty TimeProperty = DependencyProperty.Register(
"Time", typeof(int), typeof(KinectButton), new PropertyMetadata((int)3));
public Brush PathFill
{
get { return (Brush)this.GetValue(PathFillProperty); }
set { this.SetValue(PathFillProperty, value); }
}
public static readonly DependencyProperty PathFillProperty = DependencyProperty.Register(
"PathFill", typeof(Brush), typeof(KinectButton), new PropertyMetadata(Brushes.Yellow));
public Brush DisplayTextColor
{
get { return (Brush)this.GetValue(DisplayTextColorProperty); }
set { this.SetValue(DisplayTextColorProperty, value); }
}
public static readonly DependencyProperty DisplayTextColorProperty =
DependencyProperty.Register(
"DisplayTextColor", typeof(Brush), typeof(KinectButton),
new PropertyMetadata(Brushes.Black));
public string DisplayText
{
get { return (string)this.GetValue(TextProperty); }
set { this.SetValue(TextProperty, value); }
}
public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
"DisplayText", typeof(string), typeof(KinectButton),
new PropertyMetadata("Display Text"));
Step 2: Enter, Leave and Simulate Click Event
Register for MouseEnter
and MouseLeave
event and define new event for you KinectButton
called – ClickHandler
.
public delegate void ClickHandler(object sender, EventArgs eventArgs);
public event ClickHandler Click;
Now, when the mouse enters to the KinectButton
, we going to start Fill the button with Color and when the button leaves the KinectButton
, we will remove the fill.
private void SrKinectButtonMouseEnter(object sender, MouseEventArgs e)
{
StartFill();
}
private void SrKinectButtonMouseLeave(object sender, MouseEventArgs e)
{
RemoveFill();
}
You can put counter and several other techniques to show the count down for the user. I did an Animation to fill the KinectButton
, like that:
void StartFill()
{
da = new DoubleAnimation(Mask.ActualHeight, MinFillHeight, _duration);
da.Completed += new EventHandler(da_Completed);
Mask.BeginAnimation(Canvas.HeightProperty, da);
}
void da_Completed(object sender, EventArgs e)
{
if (Click != null)
Click(sender, e);
Mask.BeginAnimation(Canvas.HeightProperty, null);
}
void RemoveFill()
{
da.Completed -= da_Completed;
da = new DoubleAnimation(Mask.ActualHeight, MaxFillHeight, ReverseDuration);
Mask.BeginAnimation(Canvas.HeightProperty, da);
}
Step 3: Use It
<Kit:KinectButton Canvas.Left="565" Canvas.Top="158"
DisplayTextColor="Black" PathFill="Red"
DisplayText="C" Time="2" Name="btnPlus" Click="btnPlus_Click" />
<object type="application/x-shockwave-flash" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=3,0,0,0" width="512" height="370" data="http://www.youtube.com/v/fTLIxtE06c0"><param name="movie" value="http://www.youtube.com/v/fTLIxtE06c0" /><param name="quality" value="high" /><param name="wmode" value="transparent" />
Download Control Kit