DMDX Help.


Input.

    Newcomers probably want to read the general overview of DMDX's input system before this document.

   The entire input system of Dmastr has changed in DMDX on account of the fact that we are now using DirectInput.   What this means is that any new device that is manufactured that has DirectInput drivers will be usable by DMDX, joysticks and so on.   What this is also means is that DMDX has no way of knowing at compile time what the names for the various buttons are that are on any given device, nor can it even know the name of the device -- meaning the item file must be able to specify what device to get input from (specified to DMDX with the <InputDevice> keyword) and what the names of the various response keys are (specified with the
<MapRequest> and <MapPositiveResponse> and so on once they've had a + or a - prepended to them to make the DMDX signal names).  There are default mappings for certain common devices like the keyboard, the mouse and a generic joystick.   These device and button names are determinable with TimeDX's Input test or by turning Test Mode 10 on before mapping any input devices in DMDX.   RS232 (serial) devices (such as a Cedrus response box) are usable with extra software

    There is a second class of 2D input devices that operate a bit differently, the names of buttons aren't used and instead regions of the screen are given names and operate as buttons when they are hit.

    Additional non-DirectInput devices are available that are built in to DMDX that have pre-determined button names:   

Device Name Device Function Button Names
------------------ ---------------------- -------------------
PIO12 and QPIO12

Polls a MetraByte PIO12 with 8 bits of output.   The Q variant is provided for NT and later (2000 and XP), see below.
Bit0 to Bit15
PIO12output16 and QPIO12output16

Polls a MetraByte PIO12 with 16 bits of output. Bit0 to Bit7
PIO12output24
Only outputs 24 bits to a PIO12 No Buttons
DigitalVOX


Monitors vocal input for energy above a threshold (See Audio Input). DigitalVOX
RecordVocal

Writes vocal input to file (See Audio Input). No Buttons
RawJoystick
Polls joystick switches.   Not available under NT and later (2k, XP, Vista, 7 and later).
Switch1 to Switch4
#Keyboard Uses the first keyboard like device on the machine in the same way as the Keyboard device but without knowing button names.
#1 to #255
#Mouse Uses the first mouse like device on the machine.
#3 to #5
#Joystick Uses the first joystick like device on the machine (works with gamepads).
#0 to #3 (or higher)
tcpip Opens a TCP/IP socket to a specified machine (or the local machine with 127.0.0.1 when none specified) on the port specified (or 4242 if not specified) to control an eye tracker or other piece of equipment.
No buttons yet, it's possible we may assign buttons to certain received strings at a later date.
       
    Note # is not a general purpose switch for any DirectInput device and is in fact part of the name of the built in devices #keyboard, #mouse and #joystick.

    DirectInput devices come in two flavors, those that are interrupt driven and those that are polled, TimeDX displays which any given device is when asked to test it.   The devices that are interrupt driven (usually keyboards and mice) are the best in terms of not chewing up CPU cycles, DMDX's input thread can go to sleep until the device signals that something happened, however these devices can still have latencies that are only really determinable by hooking up a solenoid and measuring how long the device takes to send data -- typical values are 10-15ms for keyboards and 8ms for mice (see below).

    Devices that are polled must be polled by the CPU as often as is practicable, in the case of a PIO12 this is not a particularly big overhead, in the case of a generic DirectInput old analog joystick however a single poll takes over a millisecond (although see below for modified joysticks), an absolutely enormous and very unfortunate overhead, doubly unfortunate because DMDX (currently) does not use the data that takes all that time to acquire (the axes information), triply unfortunate because a joystick is really easy to modify into a custom arrangement of buttons (as opposed to a PIO12 which is (a) more difficult to obtain and (b) requires taking the computer apart to install).   Fortunately the joystick can be read by other than standard means and this the RawJoystick device does (as long as you aren't using NT/2k/XP).   When RawJoystick is used to read a joystick the joystick itself must be an old style joystick or gamepad (new fangled devices will still have to be read with DirectInput), the joystick interface must live at the standard address (port 201H, see TimeDX's PIO Test help) and like the PIO12 you mustn't be using NT (or it's derivatives like Win2000 etc) as reading IO ports directly is a no no under those OSes -- although you can now use inpout32.dll as detailed in the PIO test documentation that will allow reading and writing to one or two ports (one for reading, one for writing) on machines that inpout32.dll works under (everything up to Windows 10 1803 as of 09/22/18).  The RawJoystick device presents the same load (actually less but they are both negligible) as far as polling is concerned as the PIO12.

    In order to make these non-interrupt driven devices usable they are polled infrequently when the clock is not on and at some much higher rate when the clock is on -- both rates can be specified in the item file (see
<InputDevice>).
   
   
    Basic considerations for determining what rates should be for polling devices like joysticks include the following:
        TimeDX provides the time taken to poll the device, usually for a generic DIrectInput joystick this in the order of a millisecond, a 2ms polling rate then means a 50% CPU load, a 3ms polling rate a 33% load and so on.
   
    If the display is not active while gathering responses or the video card is likely to have buffered the entire display (for instance you have 4 megs of video memory, are using 640x480x8bpp and have less than 12 frames to display, the number of video memory buffers displayed by DMDX when an item file is run) then polling the joystick could be 100% of the CPU load (well not actually, but as much as is possible), however setting it's polling to be done every millisecond could well block the rest of DMDX from ever executing, effectively locking the machine up.
   
    If the display is active while gathering responses then adjusting the CPU "clock on" polling rate up until display errors stop occurring will be required.
   
    The thread that does the polling runs at a higher priority than the retrace sync thread, this means that if it chews too much CPU time the retrace thread can loose sync causing "certain display errors".
   
    If <AcousticControl> or <DoubleTapePulse> or <ResquestScheduled> modes are enabled then the non-clockon rate may have to be lowered from it's default 10ms.
   
    There are also some interesting options in some of the joystick configuration files to do with allowing interrupts during the polling of the joystick, the exact effect of these remains to be seen.
   
   
    An additional wrinkle exposed once InstaCal drivers were added to DMDX to allow the use of PIO12 devices under Windows NT and it's successors (2000 and XP so far) necessitated the addition of queued variants of the PIO12 devices, QPIO12 and QPIO12output16.   While the millisecond callback of those OSes is marvelously close to millisecond accuracy (SDs of 0.07ms, you couldn't ask for anything better) the mechanism used to signal code that actually does the polling involves substantial variability under NT, 2k, and XP (SDs of up to 2.5ms, ouch) whereas there was almost no additional variability added under 98SE (certainly I couldn't measure it).   These Q devices actually poll the PIO12 during the call back and then store the time and data in a queue that is then processed by the input thread of the device.   This queue is of a fixed size for the duration of the item file and is specified by the third parameter in the <id> keyword, it's default value being 16 entries (see <id> for a discussion).   Using the QPIO12 device yields SDs of 0.48ms under Test Mode 6.

    Another thing is that the Keithley DriverLINX stuff fails hopelessly with multiple threads and the PIO12 device uses two of them which mandates the use of the queued PIO devices as they happily they only use one thread (the kernal callback) to access the PIO.   The plain PIO12 devices will cause DMDX to fail with the second item file run.
   
   
    Because any number of devices can exist on a machine DMDX must now be told in the item file what devices to use for input with the
<InputDevice> parameter -- this is also where the polling rates for polled devices is specified.   Any number of devices can be installed and if none are installed the keyboard is installed by default (but only if no other device has been specified, if you want another device and the keyboard you will have to specify both).

    Button presses from DirectInput devices are either differentiated by a horrible binary Globally Unique IDentifier (a GUID), or a string, or an arbitrary integer.  Originally I chose the string form but this means DMDX has to know button names and after repeated issues with international users having trouble mapping buttons I built the # input devices that use the arbitrary integer (that hopefully is the same for all space bars and so forth).   In order implement the PIO12 code it had to be made to generate button names too, so it's names are Bit0 to Bit15, likewise the RawJoystick's names are Switch1 to Switch4.   The # devices button names are #nnn.  In addition to the DirectInput name DMDX must know whether a button was pressed or released, so a + for pressed or a - for released is prepended to any name (used more for Zillion responses).  A small problem with # device names is that you can't have more than one of them without running into name conflicts. If you do include more than one # device the first device's buttons are the ones that will be seen when there are the same buttons present on both devices -- so if you're going to map say #joystick and #keyboard map the #joystick first because once the #keyboard is mapped you won't see any of the #joystick keys because the keyboard has more buttons...    DMDX must then be told what button names correspond to what Dmastr input with the
<MapRequest> and <MapPositiveResponse> and so on.

    When a device is installed it's name is checked against a list of known devices and if it is found to be one of them a number of default button mappings are made:
   
   
PIO12 and PIO12output16 (and the Q variants)
+Bit0 REQUEST
+Bit1 NEG_RESP
+Bit2 POS_RESP
+Bit3 TAPE_PULSE
+Bit4 VOX
   
    MOUSE
+Button 2 REQUEST
+Button 1 NEG_RESP
+Button 0 POS_RESP
   
    #MOUSE
+#5     (button 2) REQUEST
+#4     (button 1) NEG_RESP
+#3     (button 0) POS_RESP
   
    KEYBOARD
+Space REQUEST
+Left Shift NEG_RESP
+Right Shift POS_RESP
   
    #KEYBOARD
+#57     (the space bar) REQUEST
+#42     (the left shift key) NEG_RESP
+#54     (the right shift) POS_RESP
   
    JOYSTICK 1 (and any name that begins with JOYSTICK)
+Button 0 REQUEST
+Button 2 NEG_RESP
+Button 1 POS_RESP

    #JOYSTICK
+#0     (button 0) REQUEST
+#2     (button 2) NEG_RESP
+#1     (button 1) POS_RESP
   
    DIGITALVOX
+DigitalVOX VOX
   
    RAWJOYSTICK
+Switch1 REQUEST
+Switch3 NEG_RESP
+Switch3 POS_RESP
+Switch4 VOX
   
   
    If the mappings are not needed (or need to be changed) a given input can always be unmapped with
<UnMapRequest> and so on.   Any number of button names can be mapped to the same DMDX input, however one button name cannot map to multiple inputs.
   
    Because inputs are now string name specific and DMDX looks those inputs up to determine what key does what (see the
<MapReqest> switch) the method of input (MIP) word is somewhat redundant (if you want to ignore a particular keystroke temporarily un-map it momentarily with <UnMapButton +Bit2> for instance and then re-map it afterwards).   Instead, now that the PIO12 reads 16 bits of input and those inputs can float all over the place if they are not all terminated electrically (generating volumes of zillion responses should that input mode be used and generally wasting CPU cycles in any event) the MIP word is very useful for the PIO12 and is now restricted to the PIO12's inputs.   The old MIP names are conserved (as in the <Request>, <NegativeResponse> and so on switches) for existing wiring configurations -- this does not mean however that you could not map "+Bit8" to the request key instead of the default "+Bit0", however <Request 0> is going to disable "+Bit0" (and "-Bit0") regardless of what mapping is made by the <MapReqest> switch.
   
    By default the Zillion input mode stores all button presses and releases on all installed devices, this can be changed with the
<ValidZillionKey> switch and the <InvalidateZillionKey> switch to undo.   Once the <ValidZillionKey> switch is used the Zillion input mode only stores button names specifically nominated with the <ValidZillionKey> switch.  

    The Zillion input mode still searches through the zillion responses made at the end of an item and looks for the last valid response using the regular mappings.

    The number of zillion responses has been left as semi-hard limit (the user can change it with the
<ZillionResponses> parameter) to stop megabytes of output if an input is floating.
   
    I have benched a number of input devices and include the results here FYI.   These were gathered by using a photosensor on the screen (the only way of triggering my solenoid, at the time -- I could have used a PIO line if the hardware was built that way) firing a hefty 12V solenoid.   The Min and Max values are the respective response times, the Min value is as high as it is because it takes some time to get the solenoid moving and then some time for it to push the key it's full travel distance.
   
   
   
PIO12 microswtich 18-20ms This sets the baseline as it has the minimum travel.
PIO12 KB switch 31-33ms Longer values are due to 6mm of extra travel.
Generic Joystick 28-31ms Polled every three ms, this small error range shows the generic joysticks and gamepads are good input devices.
MS Serial Mouse 44-50ms Without the ball.
MS Serial Mouse 46-52ms With the ball.
Old AT Keyboard 40-47ms
OmniKey 102 KB 33-40ms
Cheap Win95 KB 33-69ms A real surprise, shows that all KBs really have to be tested with a solenoid before use as an RT gathering device.


    A much more recent set of tests has been performed with the test hardware having undergone a significant rebuild to provide a steady train of input signals that do not necessarily have to use a solenoid to trigger the DMDX input, instead an opto coupler was used bypassing any mechanical variance possible with a solenoid.   These latter tests were not performed so much to measure the variability of various input devices but to measure the variability of DMDX's measurement of RTs, in response to MYORS in Behavior Research Methods, Instruments and Computers 1999, 31 (2), 322-328.   Using my test hardware then that produces a electronic switch closure every 524.3ms (a 2.000MHz crystal divided by 2 to the 20th power) and Test Mode 8 with a single post target mask the following results were obtained:
   

PIO12 values are:
Version 1 results:
ms n
523 87
524 200
525 239
526 46 Mean 524.4ms
572 sd 0.843ms
   
    Version 2 results:
Mean 524.37ms
sd 0.77ms

PIO12 values with an 11025KHz 16 bit wave file playing:                
ms n
522 2
523 90
524 193
525 227
526 50 Mean 524.4ms
562 sd 0.874ms

PIO12 values with 1 frame displayed every 100ms:        
ms n
522 12
523 81
524 170
525 180
526 59
527 7 Mean 524.4ms
509 sd 1.010ms

PIO12 values with 5Mbps network transfer between two other machines at the same time (which is an extreme amount of traffic):
ms n
523 92
524 196
525 230
526 53 Mean 524.4ms
571 sd 0.868ms

MicroSoft Serial Mouse 2.0A (no ball):    
Version 1 results:                
ms n
523 3
524 334
525 222
526 12 Mean 524.4ms
571 sd 0.545ms

Version 2 results:
Mean 524.37ms
sd 0.35ms

Microsoft USB IntelliMouse (no ball):
Version 2 results:
Mean 524.37ms
sd 3.96ms

Keyboard:            
ms n
508 1
512 35
513 53
523 7
524 1
526 152
527 321
530 1 Mean 524.4ms
571 sd 5.154ms

Instacal QPIO12 values with at twice the closure rate:
Version 3 results:
ms n
261.8 701
262.8 346
261.7 38
261.9 19
262.7 19
262.9 13
261.6 2
263.0 2
261.5 1
262.0 1
262.3 1
263.1 1 Mean 262.13ms
1144 sd 0.47ms


    Test machine for the Version 1 results was an AMD-K6 300 with a Riva 128 4M video card and 64Meg of RAM under Windows 98.   Test machine for the Version 2 results is a Celeron 400 multi-monitor system with a Riva TNT 16M primary display and a S3 Virge GX 4M secondary display, the secondary display being used as the subject's display with 128MB of RAM under Windows 98SE.   Test machine for the Version 3 results was an Athlon 1700+ with NVIDIA GeForce 4MX video card with 512MB of RAM under Windows XP.   As you can see the standard deviations are nothing like Moyors' ~16ms under Windows 95 -- which just goes to show that if you are going to test an operating system then writing code specific to that operating system will yield much better results than writing code for another operating system that the operating system you are testing only provides backwards compatibility for.  

    The standard deviation for the keyboard is as high as it is due to the standard keyboard polling effect that is part of all keyboard hardware and is unavoidable and is also the reason the keyboard should never be used as an input device, Moyors' test uses the keyboard auto-repeat as a signal generator and not as a real response device as we are using it (we cannot use the keyboard auto-repeat as a signal generator as DirectX filters auto-repeat codes, we have to repeatedly generate keystrokes instead and thus incur the keyboard timing error).

    I had high hopes for the Microsoft USB IntelliMouse as a low error input device but as results show, it's lackluster (more on this below).
   
    Interestingly enough using test mode 9 that is designed to be used with a phototransistor triggering off the display (it just stores positive RTs), over one hundred trials with a PIO-12 on the third test setup produces a standard deviation of 0.29ms, almost exactly millisecond accurate timing, substantially better than the test mode 8 results would indicate.   The trouble with test mode 8 is that it measures two variabilities, the beginning and the end of each period, test mode 9 however knows pretty much to the microsecond when the retrace began so it's variability is substantially lower:
   
   
Instacal QPIO12 values, refresh 11.76ms, trigger after 10 frames
Version 3 results:
ms n
118.4 14
119.0 13
118.6 12
118.8 11
119.1 10
118.9 9
118.5 8
118.7 8
118.3 7
119.2 4
118.2 3
119.3 1 Mean 118.72ms
100 sd 0.29ms
   
   

    If you are intending to modify a joystick and use it's buttons for input and you can't use the RawJoystick device to read it you might consider shorting the trim pots that are used for the axes, if a joystick's axis is at it's minimum resistance it is significantly faster to poll -- you can measure the time accurately with TimeDX's Input test.   So, if I push the joystick I have to the left and up it only takes .67 ms to poll as opposed to it's normal 1.1 ms -- if I short them out completely it drops to an eminently usable 0.11 ms! In the last case I would override the default clock on polling rate of 3 ms and make it 1 ms, for instance:
<id "joystick 1" 10,1>
USB Considerations.

    It turns out that the above USB mouse times are bad not necessarily because of the mouse per se but more because XP only polls USB devices at 125 Hz.  There are various hacks around the internet that can change that polling rate for gamers so I decided to revisit the USB issue and see if the USB Mouserate Switcher has any effect.  Times are for testmode 8 on a USB Logitech Trackman:


XP SP2 P4 2.4 GHz, USB mouse, no rate modifications (qPIO12 still active, oops) 8 bit video
Positive Response Latency Mean: 1048.65, Standard Deviation: 6.74

XP SP2 P4 2.4 GHz, USB mouse, no rate modifications (not much difference with qPIO12 removed) 8 bit video
Positive Response Latency Mean: 1048.65, Standard Deviation: 6.40

XP SP2 P4 2.4 GHz, USB mouse, 1000Hz rate modifications 8 bit video
Positive Response Latency Mean: 1048.70, Standard Deviation: 5.65

XP SP2 P4 2.4 GHz, USB mouse, 1000Hz rate modifications 16 bit video
Positive Response Latency Mean: 1048.64, Standard Deviation: 5.72

 

    Fairly lackluster results had me suspecting that the 8 bit video mode was the cause of the high variability but it would appear not to be the case given the last 16 bit test.  The likely explanation is that there is a large amount of software between DMDX and the actual mouse (for instance all mice are aggregated as a single mouse) so I located a  Microsoft SideWinder Plug & Play Game Pad and gave it a run through:


XP SP2 P4 2.4 GHz, USB sidewinder gamepad, no rate modifications 16 bit video
Positive Response Latency Mean: 1048.69, Standard Deviation: 2.61

XP SP2 P4 2.4 GHz, USB sidewinder gamepad, 1000Hz rate modifications 16 bit video
Positive Response Latency Mean: 1048.67, Standard Deviation: 1.33

    Here we can see some significant improvement percentage wise but the raw device was already performing rather well to begin with.

 

    Note that rate tweaking programs aren't going to do anything for USB PIO12 devices as those devices aren't Windows devices so it doesn't matter how often Windows might poll the USB devices for changes as it's not looking at the USB PIO12s.  Worse, the traffic of having windows poll the USB devices every millisecond could interfere with the drivers that do poll USB PIO12s.




DMDX Index.