Thursday, November 18, 2010

WPF - Simulating Key Press using InputSimulator

In Windows Forms, We are used to using SendKeys to simulate key press on our forms. Most of the times I have seen people simulating key press for Print Screen Key. This is available in WindowsForms assembly. So it is not a WPF thing.

http://msdn.microsoft.com/en-us/library/system.windows.forms.sendkeys.aspx

The question is, do we have anything like that available for WPF built in the framework. If not, does somebody has a solution for this. The answer to the first question is “No” (with all the limitations of my knowledge about WPF). The answer to second question is Yes. Michael Noonan has created this solution for WPF community. This still uses Win32’s SendInput method but provides a simpler interface for developers. It is available with Ms-PL license. You can find it here.

http://inputsimulator.codeplex.com/

Let us see this in practice in a sample WPF application. In this example, we are creating a Window with two buttons. Let’s call them “Capture Screen shot” and “Process Screen Shot”. When user clicks “Capture Screen Shot” then it should take a screen shot. “Process Screen Shot” should not be enabled if there is no image in the clipboard. As soon as the image becomes available, it should automatically be enabled. For “Screen Capture”, we will be simulating “PRINT SCREEN” key press through InputSimulator. For enabling the “Process Screen Shot” button, we will be using a RelayCommand with the button. You can find RelayCommand in this amazing Josh Smith’s article. (This is Copy and Paste type of re-usability :))

http://msdn.microsoft.com/en-us/magazine/dd419663.aspx

First and foremost, let’s add a reference of InputSimulator assembly to our project.


We define our view as follows:
<Window x:Class="WpfApplication4.ScreenShotProcessorView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication4"
Title="ScreenShotProcessorView" Height="300" Width="472">
<Window.DataContext>
<local:ScreenShotProcessViewModel />
</Window.DataContext>
<Grid>
<Button Content="Capture Screen Shot" Height="65"
HorizontalAlignment="Left" Margin="92,66,0,0" x:Name="btnCaptureScreenShot"
VerticalAlignment="Top" Width="257" Command="{Binding ScreenShotCaptureCommand}" />
<Button Content="Process Screen Shot" Height="65" HorizontalAlignment="Left"
Margin="94,163,0,0" VerticalAlignment="Top" Width="259"
x:Name="btnProcessScreenShot" Command="{Binding ScreenShotProcessCommand}"
/>
</Grid>
</Window>

The view needs two commands from the DataContext. They are ScreenShotCaptureCommand and ScreenShotProcessCommand. ScreenShotProcessCommand should check if there is an Image in the Clipboard to process. If yes, then just return true. This would enable “Process Screen Shot” button. Since we always have to keep “Capture Screen Shot” button enabled, CanExecute of ScreenShotCaptureCommand always returns true. We define the View Model for the DataContext of our view as follows:

public class ScreenShotProcessViewModel
{
public ScreenShotProcessViewModel()
{
Clipboard.Clear();
}

RelayCommand _screenShotCaptureCommand;
public ICommand ScreenShotCaptureCommand
{
get
{
if (_screenShotCaptureCommand == null)
{
_screenShotCaptureCommand = new RelayCommand(param => this.CaptureScreen(),
param => { return true; });
}
return _screenShotCaptureCommand;
}
}


private void CaptureScreen()
{
InputSimulator.SimulateKeyPress(VirtualKeyCode.SNAPSHOT);
}

RelayCommand _screenShotProcessCommand;
public ICommand ScreenShotProcessCommand
{
get
{
if (_screenShotProcessCommand == null)
{
_screenShotProcessCommand = new RelayCommand(param => this.ProcessCapturedScreenShot(),
param => CanProcess);
}
return _screenShotProcessCommand;
}
}

bool CanProcess
{
get { return (Clipboard.GetImage() != null); }
}


private void ProcessCapturedScreenShot()
{

}
}

As you have seen above, we have cleared the Clipboard when View Model is instantiated. When we run this the view is displayed as follows:


Just click the “Capture Screen Shot” button. Clicking this would send a Key Press of “Print Screen” Command. Now we have an image in the clipboard. This enables the “Process Screen Shot” button.


For the list of Key Codes, you can refer to the following:

http://msdn.microsoft.com/en-us/library/ms927178.aspx

There are other methods in InputSimulator too which can simulate KeyDown, KeyUp for regular or modified keys (CTRL, ALT etc.). It doesn’t use the exact names but you would figure out what to look for simulation of a particular key. Like for PRINT SCREEN, it defines SNAPSHOT instead of VK_SNAPSHOT as in the above table.

No comments: