Kinect For Windows Interactions Gallery – Kinectify my own control

Now that we’ve looked at the existing controls in the Interaction Gallery. What happens now we want some other control “Kinectified”. Generally speaking I think you can get most of what you want without going direct to the interaction stream and getting the events and properties that are exposed in the KinectRegion.  So for our example we’re going to make a “Kinectified” CheckBox.

If you look at Microsoft.Kinect.Toolkit.Controls.KinectButtonBase it will give you pretty much everything you need for this.

public class MyCheckBox : CheckBox
{
    private static readonly bool IsInDesignMode = DesignerProperties.GetIsInDesignMode(new DependencyObject());
    private HandPointer _capturedHandPointer;

    public MyCheckBox()
    {
        if (!IsInDesignMode)
        {
            Initialise();
        }

    }

    private void Initialise()
    {
        KinectRegion.AddHandPointerPressHandler(this, this.OnHandPointerPress);
        KinectRegion.AddHandPointerGotCaptureHandler(this, this.OnHandPointerCaptured);
        KinectRegion.AddHandPointerPressReleaseHandler(this, this.OnHandPointerPressRelease);
        KinectRegion.AddHandPointerLostCaptureHandler(this, this.OnHandPointerLostCapture);
        KinectRegion.AddHandPointerEnterHandler(this, this.OnHandPointerEnter);
        KinectRegion.AddHandPointerLeaveHandler(this, this.OnHandPointerLeave);

        KinectRegion.SetIsPressTarget(this, true);
    }
}

Here we create our own checkbox based on the normal checkbox.

We intialise our control and grab the events we care about from the KinectRegion we will sit our control inside of so they are passed through and we can handle them.

We want the checkbox to act like the buttons, so we make sure we set the SetIsPressTarget to true.

private void OnHandPointerLeave(object sender, HandPointerEventArgs e)
{
    if (!KinectRegion.GetIsPrimaryHandPointerOver(this))
    {
        VisualStateManager.GoToState(this, "Normal", true);
    }
}

private void OnHandPointerEnter(object sender, HandPointerEventArgs e)
{
    if (KinectRegion.GetIsPrimaryHandPointerOver(this))
    {
        VisualStateManager.GoToState(this, "MouseOver", true);
    }
}

The HandPointerLeave and Enter are similar to a mouse leave/enter. As we have two hands, we first ensure the hand over the object is the “Primary Hand” before we change the look and feel of the control.

private void OnHandPointerLostCapture(object sender, HandPointerEventArgs e)
{
    if (_capturedHandPointer == e.HandPointer)
    {
        _capturedHandPointer = null;
        IsPressed = false;
        e.Handled = true;
    }
}

private void OnHandPointerCaptured(object sender, HandPointerEventArgs e)
{
    if (_capturedHandPointer == null)
    {
        _capturedHandPointer = e.HandPointer;
        IsPressed = true;
        e.Handled = true;
    }
}

private void OnHandPointerPress(object sender, HandPointerEventArgs e)
{
    if (_capturedHandPointer == null && e.HandPointer.IsPrimaryUser && e.HandPointer.IsPrimaryHandOfUser)
    {
        e.HandPointer.Capture(this);
        e.Handled = true;
    }
}

For the Capture and Lost capture we want to grab a reference to the hand pointer to ensure we’re checking the state of the same hand and setting whether we’re in a pressed state correctly.

When we detect a press, we want to ensure it’s the primary hand of the primary user before handle the event.

private void OnHandPointerPressRelease(object sender, HandPointerEventArgs e)
{
    if (_capturedHandPointer == e.HandPointer)
    {
        if (e.HandPointer.GetIsOver(this))
        {
            OnClick();
            VisualStateManager.GoToState(this, "MouseOver", true);
        }
        else
        {
            VisualStateManager.GoToState(this, "Normal", true);
        }

        e.Handled = true;
    }
}

For the pressrelease – this would be similar to a left mouse up – we only want to fire the onclick when they let the mouse go – here it’s when they let go of the control.

In this case – we need to see where their hand is. If it’s over the control we fire a click, but if they’ve moved off they’ve effectively cancelled the click so we go back to a normal state.

Now we can put our control into KinectRegion and see it in action. Note – I haven’t changed the style of the checkbox here. You’d most likely want to make the actual check box much bigger or more like a toggle switch look etc to make it easier to press.

<k:KinectRegion Name="KinectRegion" Height="350" VerticalAlignment="Top">
    <interactionStream:MyCheckBox VerticalAlignment="Center" HorizontalAlignment="Center" Margin="0,300,0,0"/>
</k:KinectRegion>

When we run we now get the hand pointer with indicators for hover, press, release and importantly the checkbox state changes.

check_hover

Hovering over the checkbox

check_press

Pressing / Checking the checkbox

check_checked  

Checked Box.

 

Using these principals, you should be able to make all the one handed/single person controls you need.  When you need two hands or two people you’ll need a bit more thought and more custom code of how to deal with and visually indicate what’s going on.  In that case you should look more into the Controls Projet like KinectRegion, KinectCursor and KinectAdapter.

 

Technorati Tags: