Wednesday, September 30, 2009

Easily Add External I/O to Custom Software – Keyboard Encoder Modules

Arcade Game photo by Robin Norman - Stock Exchange user: otto_taroEver have the need/desire to be able to have your software  interact with a hardware input device other than a mouse or keyboard? Using a Keyboard Encoder Module and a little creativity you can take the input of something like an industrial switch, button, or Programmable Logic Controller (PLC) output and read it in your program as if it were a keystroke from a keyboard. This technique has been in use for a long time by arcade game manufacturers (think joystick and buttons). The devices are relatively reliable, but even if they fail, they are inexpensive and easy to replace.
I used the KE24 Keyboard Encoder Module from Hagstrom Electronics, but due to the declining availability of PS/2 style miniDIN connectors in PC’s, the KE-USB24 would probably be an acceptable choice.
Quick VB.Net code for a Windows Form to check which keystroke was pressed:
   1: ' a constant representing the keystroke value 
   2: ' mapped to a button press. In this example, the F5 key

   3: Dim keyActCounterIncrement as String = "116" 
   4:  
   5: Protected Overrides Function ProcessCmdKey( _
   6:              ByRef msg As System.Windows.Forms.Message, _
   7:              ByVal keyData As System.Windows.Forms.Keys) _
   8:              As Boolean
   9:  
  10:         ' get the key map data
  11:         Dim strKeyData As String = CStr(keyData)
  12:         
  13:         ' The key was pressed to increment a piece part counter.
  14:         If keyData = keyActCounterIncrement Then
  15:             DoSomethingLikeIncrementACounter()
  16:             Return True
  17:         End If
  18: End Function

Here’s a good key translation chart for reference.

[updated 10/19/2009 to add WPF code snippet]
XAML:

   1: <Window x:Class="Window1"
   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:     Title="Pacer" Height="300" Width="300">
   5:     <Grid>
   6:         <TextBox Height="23" Margin="126,74,32,0" Name="txtActCounter" VerticalAlignment="Top" />
   7:         <TextBlock Height="21" Margin="51,77,0,0" Name="lblActCounter" VerticalAlignment="Top" Text="Actual Count" HorizontalAlignment="Left" Width="77" />
   8:     </Grid>
   9: </Window>


   1: Class Window1 
   2:     Private intActCounter As Integer = 0
   3:     Private Sub Window1_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded
   4:         ' register an event handler to intercept the keyboard input
   5:         EventManager.RegisterClassHandler(GetType(Window), _
   6:             Keyboard.KeyUpEvent, New KeyEventHandler(AddressOf KeyUpCapture), True)
   7:         ' set a textbox counter to zero
   8:         txtActCounter.Text = intActCounter.ToString
   9:     End Sub
  10:     Private Sub KeyUpCapture(ByVal sender As Object, ByVal e As KeyEventArgs)
  11:         ' if keypress is F5
  12:         '   do something
  13:         If e.Key = Key.F5 Then
  14:             ' increment counter
  15:             intActCounter += 1
  16:             ' update textbox to counter value
  17:             txtActCounter.Text = intActCounter.ToString
  18:  
  19:         End If
  20:  
  21:     End Sub
  22: End Class
There are a few considerations to using this method:
  • It is a low voltage, low current “dry contact” device, but you still might want to consider soliciting the help of an electrician/controls engineer to wire it up to make sure you don’t fry your new “toy”, your PC, yourself, or another unsuspecting bystander
  • It is a low voltage device so the wiring between the keyboard encoder module and the input device needs to be located in close proximity (i.e. minimal wire length). If you need more distance, I recommend wiring the field device to an industrial dry contact relay bank and locating the relay bank in close proximity to the keyboard encoder module.
  • You probably want to map the inputs to keys, or combinations of keys that are not typically used in normal typing, like the tilde (~), so as not to inadvertently register text actually typed from the keyboard as inputs from the keyboard encoder module.