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
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:
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:
Microsoft USB IntelliMouse (no ball):
Version 2 results:
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.