<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://www.bci2000.org/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Jhill</id>
	<title>BCI2000 Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://www.bci2000.org/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Jhill"/>
	<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php/Special:Contributions/Jhill"/>
	<updated>2026-06-09T04:46:41Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.6</generator>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Contributions:SerialInterface&amp;diff=12439</id>
		<title>Contributions:SerialInterface</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Contributions:SerialInterface&amp;diff=12439"/>
		<updated>2026-05-12T17:44:53Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* SkipUnrecognizedBytes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Synopsis==&lt;br /&gt;
An extension that allows flexible communication to and from serial-port devices such as programmable microcontrollers (e.g. Arduino, Teensy, Pico, etc.)&lt;br /&gt;
&lt;br /&gt;
==Location==&lt;br /&gt;
http://{{SERVERNAME}}/svn/trunk/src/contrib/Extensions/SerialInterface&lt;br /&gt;
&lt;br /&gt;
==Versioning==&lt;br /&gt;
&lt;br /&gt;
===Authors===&lt;br /&gt;
Jeremy Hill (hill@neurotechcenter.org)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Version History===&lt;br /&gt;
* 2023-08-10: Initial public release&lt;br /&gt;
* 2025-06-13: SerialInput parameter added, expanding the options for two-way communication.&lt;br /&gt;
&lt;br /&gt;
===Source Code Revisions===&lt;br /&gt;
*Initial development: r7523&lt;br /&gt;
*Known to compile under: r8888&lt;br /&gt;
*Broken since: --&lt;br /&gt;
&lt;br /&gt;
==Functional Description==&lt;br /&gt;
Among the biosignal acquisition devices supported by BCI2000, a few allow &amp;quot;digital output&amp;quot;, i.e. the generation of TTL pulses that might be used to trigger or otherwise synchronize with other devices; most, however, do not offer this functionality. Furthermore, many devices support &#039;&#039;acquisition&#039;&#039; of TTL pulses and other auxiliary information alongside biosignal data; however, some devices lack even this capability.&lt;br /&gt;
&lt;br /&gt;
Where such functionality is lacking, one flexible option for adding it to your system is to build and program a custom solution based on a microcontroller such as an Arduino, Teensy or Pico (hereafter referred to as a &amp;quot;widget&amp;quot;).  The SerialInterface extension allows BCI2000 to interface with such widgets.&lt;br /&gt;
&lt;br /&gt;
The primary intended purpose of the SerialInterface is to send arbitrary byte strings to a widget over a serial port whenever specified BCI2000 [[User Reference:Expression Syntax|Expressions]] become true—this is a simple way in which digital-output functionality may be supplied for hardware that lacks it. This mechanism could also allow your BCI system to control almost anything you can imagine attaching to a custom microcontroller.  Since the outgoing byte strings can be configured arbitrarily, you might possibly be able to make this work even if you cannot (re-)program the widget yourself.&lt;br /&gt;
&lt;br /&gt;
A secondary function of the SerialInterface is to receive and log [[Programming Reference:Events|Event]] information. This can be done in two ways: either by supplying a fixed set of byte strings that BCI2000 should respond to when it receives them from the widget, or by having the widget send actual BCI2000 event descriptors. For the latter, the widget must be programmed to output strings in the format that BCI2000 will understand. If you have the ability to re-program your widget, then you may also optionally make the widget define its own BCI2000 Parameters and Events. Together, these mechanisms allow information from arbitrary sensors to be sent to BCI2000, mediated by a programmable widget.&lt;br /&gt;
&lt;br /&gt;
An example BCI2000-compatible microcontroller sketch, for the Arduino IDE, is provided in [https://bci2000.org/svn/trunk/src/contrib/Extensions/SerialInterface/TTLExampleSketch/ the TTLExampleSketch subdirectory]. It makes use of [https://www.arduino.cc/reference/en/libraries/keyhole the Keyhole library], which can be installed via the IDE&#039;s library manager and which makes it easy for sketches to respond to serial-port commands and to allow their variables to be read and written.&lt;br /&gt;
&lt;br /&gt;
Note that the SerialInterface Extension is intended to provide &#039;&#039;auxiliary&#039;&#039; input/output functionality to source modules that acquire their primary signal elsewhere.  If you also want to acquire the &#039;&#039;primary&#039;&#039; signal from the same widget, you should use the closely-related [[Contributions:SerialWidgetADC|SerialWidgetADC]], which is part of the SerialWidget signal-source module and which requires a more-sophisticated sketch.&lt;br /&gt;
&lt;br /&gt;
==Enabling SerialInterface==&lt;br /&gt;
&lt;br /&gt;
[[User_Reference:Logging_Input|Like all Extensions]], SerialInterface is only available if your signal source module was compiled with the appropriate CMake flag enabled: in this case, &amp;lt;code&amp;gt;EXTENSIONS_SERIALINTERFACE=ON&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Then, when you launch BCI2000, SerialInterface must be enabled by supplying a value for the &amp;lt;code&amp;gt;--SerialPort&amp;lt;/code&amp;gt; parameter [[User_Reference:Module_Command_Line_Options#Specifying_Options|on the command-line]]. For example, in a [[User_Reference:Operator_Module_Scripting|BCI2000 script]], you might use the line:&lt;br /&gt;
 start executable SignalGenerator --local --SerialPort=COM4:baud=9600,dtr=on&lt;br /&gt;
&lt;br /&gt;
In the example above, note that a suffix has been appended to the usual serial-port address &amp;lt;code&amp;gt;COM4&amp;lt;/code&amp;gt;, attached by a colon. In this optional suffix, you can specify a comma-separated list of options as understood by the Windows &amp;lt;code&amp;gt;MODE&amp;lt;/code&amp;gt; command (see [https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-buildcommdcba#parameters Microsoft&#039;s documentation for the configuration string passed to the BuildCommDCBA() function]).  These options may or may not be necessary for your widget—for example, we have found that the Teensy microcontroller does not seem to care whether the &amp;lt;code&amp;gt;dtr&amp;lt;/code&amp;gt; option is on or off; however, the Pico will not work properly unless this option is explicitly turned on, whereas the ItsyBitsy M4 will fail to communicate if it &#039;&#039;is&#039;&#039; turned on.&lt;br /&gt;
&lt;br /&gt;
==Defining BCI2000 Parameters and Events from the Widget==&lt;br /&gt;
If you want your widget to define its own BCI2000 Parameters and Events, the widget must be programmed to send this information to BCI2000 on command, and you can specify exactly what sequence of bytes the command comprises. To ensure that the chosen command is sent to the widget during the [[Programming_Reference:GenericFilter_Class#Publish|&amp;quot;Publish&amp;quot; phase]] of BCI2000 startup, you should specify it as the &amp;lt;code&amp;gt;--PublishCommand&amp;lt;/code&amp;gt; parameter, again on the command line:&lt;br /&gt;
 start executable SignalGenerator --local --SerialPort=COM4:baud=9600,dtr=on --PublishCommand=publish\n&lt;br /&gt;
&lt;br /&gt;
The particular byte sequence &amp;lt;code&amp;gt;publish\n&amp;lt;/code&amp;gt; works with &amp;lt;code&amp;gt;TTLExampleSketch.ino&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
When the widget receives the publish command, it must reply with one or more lines of text.  BCI2000 will attempt to interpret any line containing the &amp;lt;code&amp;gt;=&amp;lt;/code&amp;gt; character as a [[Technical_Reference:Parameter_Definition|Parameter definition]], and any other non-empty line as an [[Programming_Reference:Events#Implementation|Event definition]].   The widget must send a blank line (terminated with &amp;lt;code&amp;gt;\n&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;\r\n&amp;lt;/code&amp;gt;) to signify the end of the definitions (if your sketch omits this, BCI2000 will hang indefinitely, waiting for more definitions).&lt;br /&gt;
&lt;br /&gt;
A widget Parameter definition may be specified as &amp;lt;code&amp;gt;(readonly)&amp;lt;/code&amp;gt;, in which case the Parameter may be of any type and will not be editable by the user. Such read-only parameters are a means by which the widget can make annotations that will be stored in data files&#039; parameter headers (e.g. information about microcontroller model or sketch version).  On the other hand, if the &amp;lt;code&amp;gt;(readonly)&amp;lt;/code&amp;gt; flag is &#039;&#039;not&#039;&#039; found in the Parameter definition comment, the Parameter will actually be configurable by the user: in this case, only &amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;float&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt; Parameters are allowed.  If the widget defines configurable Parameters, Parameter values will be sent to the widget when the user presses &amp;quot;Set Config&amp;quot;, using strings of the following format:&lt;br /&gt;
 Foo=1\n&lt;br /&gt;
 Bar=3.0\n&lt;br /&gt;
 Boo=&amp;quot;this is a string parameter value&amp;quot;\n&lt;br /&gt;
 &lt;br /&gt;
In that case, your widget sketch must be able to interpret such commands (the [https://www.arduino.cc/reference/en/libraries/keyhole Keyhole] library makes this easy, as shown in the example sketch).&lt;br /&gt;
&lt;br /&gt;
You may also chose to specify a &#039;&#039;&#039;ParameterUpdateCommand&#039;&#039;&#039;: if so, the specified bytes will be sent to the widget in the [[Programming_Reference:GenericFilter_Class#StopRun|&amp;quot;StopRun&amp;quot; phase]], to request updates to the values of widget-defined parameters. When the widget receives the specified parameter-update command, just as with the publish command, it must reply with a sequence of lines terminated by a blank line.  As before, if you choose to use this option, BCI2000 will hang until it receives that final blank line.  This time, however, the non-blank lines are expected to have the same syntax as the lines that were sent &#039;&#039;to&#039;&#039; the widget on Set Config, e.g. &amp;lt;code&amp;gt;Foo=123&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Boo=&amp;quot;some string&amp;quot;&amp;lt;/code&amp;gt;.  Note that you can only update parameters that the widget itself has previously declared, and you cannot update a parameter that was declared as &amp;lt;code&amp;gt;(readonly)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Parameters==&lt;br /&gt;
If enabled using the &amp;lt;code&amp;gt;--SerialPort&amp;lt;/code&amp;gt; command-line parameter, the full set of SerialInterface&#039;s parameters (described below) will appear in the Source tab of BCI2000&#039;s Config window. In addition, any Parameters defined by the widget itself, in response to a &amp;lt;code&amp;gt;--PublishCommand&amp;lt;/code&amp;gt;, will appear in whichever tabs and sections their definitions dictate.&lt;br /&gt;
&lt;br /&gt;
Note that, wherever a SerialInterface Parameter specifies a byte string to be sent to the widget, the byte string may be expressed using backslash escapes familiar to the C/C++ or Python programmer: &amp;lt;code&amp;gt;\n&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;\r&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;\t&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;\0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;\\&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;\xNN&amp;lt;/code&amp;gt;  are all recognized, where &amp;lt;code&amp;gt;NN&amp;lt;/code&amp;gt; stands for a pair of hex digits (these are interpreted like Python, not like C—in other words, the maximum expected number of digits is 2). Other backslash escapes are not supported (so, use &amp;lt;code&amp;gt;\x07&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;\a&amp;lt;/code&amp;gt;, use&amp;lt;code&amp;gt;\x0B&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;\v&amp;lt;/code&amp;gt;, etc.).  If your widget sketch uses the Keyhole library, commands are expected to end with either a newline &amp;lt;code&amp;gt;\n&amp;lt;/code&amp;gt; or a semicolon &amp;lt;code&amp;gt;;&amp;lt;/code&amp;gt; (but in a BCI2000 script, semicolons mean something to the script interpreter, so you would have to ensure they&#039;re used in quotes).&lt;br /&gt;
&lt;br /&gt;
===SerialPort===&lt;br /&gt;
This string specifies the port address, optionally followed by a colon and a comma-delimited sequence of serial port options as described above. This must be [[User_Reference:Module_Command_Line_Options#Specifying_Options|specified on the command-line when the signal source module is launched]] and its value cannot be changed without quitting and relaunching BCI2000. If this parameter is absent or its value is empty, the SerialInterface extension is entirely disabled.&lt;br /&gt;
&lt;br /&gt;
===PublishCommand===&lt;br /&gt;
This optional string specifies the sequence of bytes that should be sent by BCI2000 to request Parameter and Event definitions from the widget. If used, this must be [[User_Reference:Module_Command_Line_Options#Specifying_Options|specified on the command-line when the signal source module is launched]]. Its value cannot be changed without quitting and relaunching BCI2000.&lt;br /&gt;
&lt;br /&gt;
===StartCommand===&lt;br /&gt;
If specified, this sequence of bytes is sent to the widget whenever a run is started (e.g. when Start or Resume is pressed).&lt;br /&gt;
With &amp;lt;code&amp;gt;TTLExampleSketch.ino&amp;lt;/code&amp;gt;, the string &amp;lt;code&amp;gt;mute=0\n&amp;lt;/code&amp;gt; can be used, although the sketch will work on most microcontrollers even without a StartCommand and StopCommand.&lt;br /&gt;
&lt;br /&gt;
===StopCommand===&lt;br /&gt;
If specified, this sequence of bytes is sent to the widget whenever a run stops (e.g. when Suspend is pressed) and also when Set Config is pressed.&lt;br /&gt;
With &amp;lt;code&amp;gt;TTLExampleSketch.ino&amp;lt;/code&amp;gt;, the string &amp;lt;code&amp;gt;mute=1\n&amp;lt;/code&amp;gt; can be used, although the sketch will work on most microcontrollers even without a StartCommand and StopCommand.&lt;br /&gt;
&lt;br /&gt;
===ParameterUpdateCommand===&lt;br /&gt;
If specified, this sequence of bytes is sent to the widget whenever a run stops (e.g. when Suspend is pressed).&lt;br /&gt;
As with the &#039;&#039;&#039;PublishCommand&#039;&#039;&#039;, BCI2000 will then expect the widget to reply with a sequence of lines, terminated by a blank line. Each line is expected to be of the format &amp;lt;code&amp;gt;ParameterName = VALUE&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;ParameterName&amp;lt;/code&amp;gt; must denote a writeable parameter previously declared by the widget, and &amp;lt;code&amp;gt;VALUE&amp;lt;/code&amp;gt; can be a simple numeric value or string (quoted and backslash-escaped if necessary).&lt;br /&gt;
This allows new parameter values to be carried over from one run to the next.&lt;br /&gt;
&lt;br /&gt;
===SerialInputs===&lt;br /&gt;
This matrix parameter gives BCI2000 the limited ability to respond to serial-port messages sent by the widget, even if you cannot re-program your widget.&lt;br /&gt;
&lt;br /&gt;
If not empty, the matrix must have four columns.  The first column contains (backslash-escaped) byte strings that the widget might send to BCI2000. The second column contains names of State Variables that have been declared as [[Programming_Reference:Events|Events]] (perhaps using [[User_Reference:Operator_Module_Scripting#ADD_EVENT_&amp;lt;name&amp;gt;_&amp;lt;bit_width&amp;gt;_&amp;lt;initial_value&amp;gt;|&amp;lt;code&amp;gt;ADD EVENT&amp;lt;/code&amp;gt;]] in your launcher script).  The third column contains the integer value that should be assigned to the Event when the byte string is received.   In the fourth column, the entry should either be left blank (in which case, the Event will remain at the assigned value until it is changed again) or set to 0 (in which case the Event is transient, remaining at the assigned value only for one sample before automatically returning to 0).  Thus, the second, third and fourth columns can be read from left to right as a [[Programming_Reference:Events#Descriptor_Syntax|BCI2000 Event descriptor]], like &amp;lt;code&amp;gt;MyEvent 123&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;MyEvent 123 0&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A given byte string is allowed to appear more than once in the table, to trigger multiple Events simultaneously.  The Event name (second column) is allowed to be blank, to enable a particular byte string to be recognized but ignored.&lt;br /&gt;
&lt;br /&gt;
Note that the &#039;&#039;&#039;SerialInputs&#039;&#039;&#039; mechanism is designed to be very generic, and as such it is not necessarily possible to tailor it to the particular protocol your widget uses. For example, BCI2000 will not know how the widget likes to terminate messages unless you explicitly include the terminator bytes (so, if &amp;lt;code&amp;gt;shutdown&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;shutdown-gracefully&amp;lt;/code&amp;gt; are both configured, the longer command will never be recognized: BCI2000 will greedily recognize and obey &amp;lt;code&amp;gt;shutdown&amp;lt;/code&amp;gt; before attempting to move on to &amp;lt;code&amp;gt;-gracefully&amp;lt;/code&amp;gt;). The limitations of the &#039;&#039;&#039;SerialInputs&#039;&#039;&#039; table also make themselves felt if the widget sends a byte string that you have omitted from the table. Then, one of two compromises must be accepted (see the description of the &#039;&#039;&#039;SkipUnrecognizedBytes&#039;&#039;&#039; parameter, below). In general, it is not possible to support a serial protocol that includes variable values (unless you create a separate &#039;&#039;&#039;SerialInputs&#039;&#039;&#039; row for every possible combination of values).&lt;br /&gt;
&lt;br /&gt;
===SkipUnrecognizedBytes===&lt;br /&gt;
This boolean parameter determines what happens if you are using the &#039;&#039;&#039;SerialInputs&#039;&#039;&#039; table to recognize messages from the widget, and the widget sends you a string that is not recognized. Either choice can have unfortunate consequences, depending on your widget&#039;s protocol.&lt;br /&gt;
&lt;br /&gt;
If the &#039;&#039;&#039;SkipUnrecognizedBytes&#039;&#039;&#039; parameter is set to false (unchecked), then the data coming from the widget will continue to build into an ever-lengthening unrecognized command: BCI2000 will not recognize another &#039;&#039;&#039;SerialInputs&#039;&#039;&#039; byte string at all until the SerialInterface is reset (which happens at the start of a run if SerialInterface is running as an Extension, or when Set Config is pressed if you are running SerialWidgetADC).&lt;br /&gt;
&lt;br /&gt;
If &#039;&#039;&#039;SkipUnrecognizedBytes&#039;&#039;&#039; is set to true (checked), then it will be possible to discard unrecognized bytes and match a known string, but with the danger that substrings of &#039;&#039;un&#039;&#039;recognized commands could be falsely recognized as commands. For example, if you have enabled &#039;&#039;&#039;SkipUnrecognizedBytes&#039;&#039;&#039;, and you have listed the command &amp;lt;code&amp;gt;arm_stimulator&amp;lt;/code&amp;gt; in &#039;&#039;&#039;SerialInputs&#039;&#039;&#039; but &#039;&#039;not&#039;&#039; &amp;lt;code&amp;gt;disarm_stimulator&amp;lt;/code&amp;gt;, and the widget then happens to send &amp;lt;code&amp;gt;disarm_stimulator&amp;lt;/code&amp;gt;,  then BCI2000 will discard the bytes &amp;lt;code&amp;gt;dis&amp;lt;/code&amp;gt; and recognize &amp;lt;code&amp;gt;arm_stimulator&amp;lt;/code&amp;gt;, leading to the opposite of the intended effect. Clearly, this is a function of how the widget&#039;s protocol is designed.  To avoid such situations, you must either (a) ensure that the entries in the &#039;&#039;&#039;SerialInputs&#039;&#039;&#039; table exhaustively cover the repertoire of possible widget outputs (don&#039;t worry, if a known longer string gets matched, its embedded substrings will not get matched), or (b) accept the consequences of disabling &#039;&#039;&#039;SkipUnrecognizedBytes&#039;&#039;&#039;. An even more robust option, if possible, is (c) to leave the &#039;&#039;&#039;SerialInputs&#039;&#039;&#039; table empty and re-program your widget to send BCI2000 event descriptors directly as text (see the [[#State Variables|State Variables]] section, below).&lt;br /&gt;
&lt;br /&gt;
===SerialOutputs===&lt;br /&gt;
This matrix parameter gives BCI2000 the ability to send messages to the widget whenever specified contingencies are met.&lt;br /&gt;
&lt;br /&gt;
If not empty, the matrix must have two columns.  The first column contains [[User Reference:Expression Syntax|Expressions]]. The second column contains (backslash-escaped) byte strings.  Expressions are evaluated at the beginning of each sample-block. If an Expression was previously zero and now evaluates to non-zero, the corresponding byte string is immediately sent to the widget.  In this way, you can link a BCI2000 State Variable to a widget command that, for example, causes a TTL pulse to be generated.&lt;br /&gt;
&lt;br /&gt;
If you are using &amp;lt;code&amp;gt;TTLExampleSketch.ino&amp;lt;/code&amp;gt;, you would associate Expressions with the commands &amp;lt;code&amp;gt;output=1\n&amp;lt;/code&amp;gt; and  &amp;lt;code&amp;gt;output=0\n&amp;lt;/code&amp;gt;. For example, let&#039;s assume you have defined your own State Variable called  &amp;lt;code&amp;gt;StimTrigger&amp;lt;/code&amp;gt;. Then your &#039;&#039;&#039;SerialOutputs&#039;&#039;&#039; parameter might look as shown in the screenshot:&lt;br /&gt;
&lt;br /&gt;
[[File:SerialOutputs.PNG]]&lt;br /&gt;
&lt;br /&gt;
===ElseIf===&lt;br /&gt;
This parameter dictates the logic by which the rows of the &#039;&#039;&#039;SerialOutputs&#039;&#039;&#039; Parameter are processed.&lt;br /&gt;
You may choose to process all rows on every sample-block (and potentially send all byte strings, one after the other);&lt;br /&gt;
alternatively, you may choose to stop after the first matching row (so, on any given sample-block, at most one of the byte strings will be sent).&lt;br /&gt;
Possible values are 0 (&amp;quot;process all rows&amp;quot;) or 1 (&amp;quot;stop at the first match&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
==State Variables==&lt;br /&gt;
&lt;br /&gt;
The SerialInterface does not define any State Variables or Events of its own, but will define any [[#Defining BCI2000 Parameters and Events from the Widget|Events the widget tells it to define]] in response to a &amp;lt;code&amp;gt;--PublishCommand&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
During a run, a widget may change an Event value at any time by sending an [[Programming_Reference:Events#Descriptor_Syntax|Event descriptor line]]: usually, this is the name of the event, followed by a space, followed by the value expressed as decimal text, followed by a line-ending. Optionally, an Event descriptor may contain an additional space and a zero, to indicate an instantaneous transient event.  For example, &amp;lt;code&amp;gt;TTLExampleSketch.ino&amp;lt;/code&amp;gt; will send &lt;br /&gt;
 TTLInput 1\r\n&lt;br /&gt;
whenever the voltage on its input pin changes from low to high, and&lt;br /&gt;
 TTLInput 0\r\n&lt;br /&gt;
 PulseDurationMsec 123 0\r\n&lt;br /&gt;
whenever the voltage changes from high to low (where 123 is a place-holder for however long the input pulse in fact lasted, according to the widget&#039;s millisecond timer).&lt;br /&gt;
&lt;br /&gt;
Note that it is not necessary for the Event in question to have been defined by the widget itself—it could have been added by one of the other filters and loggers, or in your [[User_Reference:Operator_Module_Scripting|BCI2000 script]] using [[User_Reference:Operator_Module_Scripting#ADD_EVENT_&amp;lt;name&amp;gt;_&amp;lt;bit_width&amp;gt;_&amp;lt;initial_value&amp;gt;|an &amp;lt;code&amp;gt;ADD EVENT&amp;lt;/code&amp;gt; command]] before the &amp;lt;code&amp;gt;STARTUP SYSTEM&amp;lt;/code&amp;gt; line. This means you do not necessarily have to implement the widget&#039;s response to a &amp;lt;code&amp;gt;--PublishCommand&amp;lt;/code&amp;gt;, even if you are planning to use the widget to log Events.&lt;br /&gt;
&lt;br /&gt;
If you cannot re-program the widget at all, you may still have some (limited) options for triggering Events in response to messages from the widget, via the &#039;&#039;&#039;SerialInputs&#039;&#039;&#039; parameter.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
[[Contributions:SerialWidgetADC]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Contributions]][[Category:Extension]]&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Contributions:SerialInterface&amp;diff=12438</id>
		<title>Contributions:SerialInterface</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Contributions:SerialInterface&amp;diff=12438"/>
		<updated>2026-05-12T17:40:41Z</updated>

		<summary type="html">&lt;p&gt;Jhill: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Synopsis==&lt;br /&gt;
An extension that allows flexible communication to and from serial-port devices such as programmable microcontrollers (e.g. Arduino, Teensy, Pico, etc.)&lt;br /&gt;
&lt;br /&gt;
==Location==&lt;br /&gt;
http://{{SERVERNAME}}/svn/trunk/src/contrib/Extensions/SerialInterface&lt;br /&gt;
&lt;br /&gt;
==Versioning==&lt;br /&gt;
&lt;br /&gt;
===Authors===&lt;br /&gt;
Jeremy Hill (hill@neurotechcenter.org)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Version History===&lt;br /&gt;
* 2023-08-10: Initial public release&lt;br /&gt;
* 2025-06-13: SerialInput parameter added, expanding the options for two-way communication.&lt;br /&gt;
&lt;br /&gt;
===Source Code Revisions===&lt;br /&gt;
*Initial development: r7523&lt;br /&gt;
*Known to compile under: r8888&lt;br /&gt;
*Broken since: --&lt;br /&gt;
&lt;br /&gt;
==Functional Description==&lt;br /&gt;
Among the biosignal acquisition devices supported by BCI2000, a few allow &amp;quot;digital output&amp;quot;, i.e. the generation of TTL pulses that might be used to trigger or otherwise synchronize with other devices; most, however, do not offer this functionality. Furthermore, many devices support &#039;&#039;acquisition&#039;&#039; of TTL pulses and other auxiliary information alongside biosignal data; however, some devices lack even this capability.&lt;br /&gt;
&lt;br /&gt;
Where such functionality is lacking, one flexible option for adding it to your system is to build and program a custom solution based on a microcontroller such as an Arduino, Teensy or Pico (hereafter referred to as a &amp;quot;widget&amp;quot;).  The SerialInterface extension allows BCI2000 to interface with such widgets.&lt;br /&gt;
&lt;br /&gt;
The primary intended purpose of the SerialInterface is to send arbitrary byte strings to a widget over a serial port whenever specified BCI2000 [[User Reference:Expression Syntax|Expressions]] become true—this is a simple way in which digital-output functionality may be supplied for hardware that lacks it. This mechanism could also allow your BCI system to control almost anything you can imagine attaching to a custom microcontroller.  Since the outgoing byte strings can be configured arbitrarily, you might possibly be able to make this work even if you cannot (re-)program the widget yourself.&lt;br /&gt;
&lt;br /&gt;
A secondary function of the SerialInterface is to receive and log [[Programming Reference:Events|Event]] information. This can be done in two ways: either by supplying a fixed set of byte strings that BCI2000 should respond to when it receives them from the widget, or by having the widget send actual BCI2000 event descriptors. For the latter, the widget must be programmed to output strings in the format that BCI2000 will understand. If you have the ability to re-program your widget, then you may also optionally make the widget define its own BCI2000 Parameters and Events. Together, these mechanisms allow information from arbitrary sensors to be sent to BCI2000, mediated by a programmable widget.&lt;br /&gt;
&lt;br /&gt;
An example BCI2000-compatible microcontroller sketch, for the Arduino IDE, is provided in [https://bci2000.org/svn/trunk/src/contrib/Extensions/SerialInterface/TTLExampleSketch/ the TTLExampleSketch subdirectory]. It makes use of [https://www.arduino.cc/reference/en/libraries/keyhole the Keyhole library], which can be installed via the IDE&#039;s library manager and which makes it easy for sketches to respond to serial-port commands and to allow their variables to be read and written.&lt;br /&gt;
&lt;br /&gt;
Note that the SerialInterface Extension is intended to provide &#039;&#039;auxiliary&#039;&#039; input/output functionality to source modules that acquire their primary signal elsewhere.  If you also want to acquire the &#039;&#039;primary&#039;&#039; signal from the same widget, you should use the closely-related [[Contributions:SerialWidgetADC|SerialWidgetADC]], which is part of the SerialWidget signal-source module and which requires a more-sophisticated sketch.&lt;br /&gt;
&lt;br /&gt;
==Enabling SerialInterface==&lt;br /&gt;
&lt;br /&gt;
[[User_Reference:Logging_Input|Like all Extensions]], SerialInterface is only available if your signal source module was compiled with the appropriate CMake flag enabled: in this case, &amp;lt;code&amp;gt;EXTENSIONS_SERIALINTERFACE=ON&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Then, when you launch BCI2000, SerialInterface must be enabled by supplying a value for the &amp;lt;code&amp;gt;--SerialPort&amp;lt;/code&amp;gt; parameter [[User_Reference:Module_Command_Line_Options#Specifying_Options|on the command-line]]. For example, in a [[User_Reference:Operator_Module_Scripting|BCI2000 script]], you might use the line:&lt;br /&gt;
 start executable SignalGenerator --local --SerialPort=COM4:baud=9600,dtr=on&lt;br /&gt;
&lt;br /&gt;
In the example above, note that a suffix has been appended to the usual serial-port address &amp;lt;code&amp;gt;COM4&amp;lt;/code&amp;gt;, attached by a colon. In this optional suffix, you can specify a comma-separated list of options as understood by the Windows &amp;lt;code&amp;gt;MODE&amp;lt;/code&amp;gt; command (see [https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-buildcommdcba#parameters Microsoft&#039;s documentation for the configuration string passed to the BuildCommDCBA() function]).  These options may or may not be necessary for your widget—for example, we have found that the Teensy microcontroller does not seem to care whether the &amp;lt;code&amp;gt;dtr&amp;lt;/code&amp;gt; option is on or off; however, the Pico will not work properly unless this option is explicitly turned on, whereas the ItsyBitsy M4 will fail to communicate if it &#039;&#039;is&#039;&#039; turned on.&lt;br /&gt;
&lt;br /&gt;
==Defining BCI2000 Parameters and Events from the Widget==&lt;br /&gt;
If you want your widget to define its own BCI2000 Parameters and Events, the widget must be programmed to send this information to BCI2000 on command, and you can specify exactly what sequence of bytes the command comprises. To ensure that the chosen command is sent to the widget during the [[Programming_Reference:GenericFilter_Class#Publish|&amp;quot;Publish&amp;quot; phase]] of BCI2000 startup, you should specify it as the &amp;lt;code&amp;gt;--PublishCommand&amp;lt;/code&amp;gt; parameter, again on the command line:&lt;br /&gt;
 start executable SignalGenerator --local --SerialPort=COM4:baud=9600,dtr=on --PublishCommand=publish\n&lt;br /&gt;
&lt;br /&gt;
The particular byte sequence &amp;lt;code&amp;gt;publish\n&amp;lt;/code&amp;gt; works with &amp;lt;code&amp;gt;TTLExampleSketch.ino&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
When the widget receives the publish command, it must reply with one or more lines of text.  BCI2000 will attempt to interpret any line containing the &amp;lt;code&amp;gt;=&amp;lt;/code&amp;gt; character as a [[Technical_Reference:Parameter_Definition|Parameter definition]], and any other non-empty line as an [[Programming_Reference:Events#Implementation|Event definition]].   The widget must send a blank line (terminated with &amp;lt;code&amp;gt;\n&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;\r\n&amp;lt;/code&amp;gt;) to signify the end of the definitions (if your sketch omits this, BCI2000 will hang indefinitely, waiting for more definitions).&lt;br /&gt;
&lt;br /&gt;
A widget Parameter definition may be specified as &amp;lt;code&amp;gt;(readonly)&amp;lt;/code&amp;gt;, in which case the Parameter may be of any type and will not be editable by the user. Such read-only parameters are a means by which the widget can make annotations that will be stored in data files&#039; parameter headers (e.g. information about microcontroller model or sketch version).  On the other hand, if the &amp;lt;code&amp;gt;(readonly)&amp;lt;/code&amp;gt; flag is &#039;&#039;not&#039;&#039; found in the Parameter definition comment, the Parameter will actually be configurable by the user: in this case, only &amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;float&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt; Parameters are allowed.  If the widget defines configurable Parameters, Parameter values will be sent to the widget when the user presses &amp;quot;Set Config&amp;quot;, using strings of the following format:&lt;br /&gt;
 Foo=1\n&lt;br /&gt;
 Bar=3.0\n&lt;br /&gt;
 Boo=&amp;quot;this is a string parameter value&amp;quot;\n&lt;br /&gt;
 &lt;br /&gt;
In that case, your widget sketch must be able to interpret such commands (the [https://www.arduino.cc/reference/en/libraries/keyhole Keyhole] library makes this easy, as shown in the example sketch).&lt;br /&gt;
&lt;br /&gt;
You may also chose to specify a &#039;&#039;&#039;ParameterUpdateCommand&#039;&#039;&#039;: if so, the specified bytes will be sent to the widget in the [[Programming_Reference:GenericFilter_Class#StopRun|&amp;quot;StopRun&amp;quot; phase]], to request updates to the values of widget-defined parameters. When the widget receives the specified parameter-update command, just as with the publish command, it must reply with a sequence of lines terminated by a blank line.  As before, if you choose to use this option, BCI2000 will hang until it receives that final blank line.  This time, however, the non-blank lines are expected to have the same syntax as the lines that were sent &#039;&#039;to&#039;&#039; the widget on Set Config, e.g. &amp;lt;code&amp;gt;Foo=123&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Boo=&amp;quot;some string&amp;quot;&amp;lt;/code&amp;gt;.  Note that you can only update parameters that the widget itself has previously declared, and you cannot update a parameter that was declared as &amp;lt;code&amp;gt;(readonly)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Parameters==&lt;br /&gt;
If enabled using the &amp;lt;code&amp;gt;--SerialPort&amp;lt;/code&amp;gt; command-line parameter, the full set of SerialInterface&#039;s parameters (described below) will appear in the Source tab of BCI2000&#039;s Config window. In addition, any Parameters defined by the widget itself, in response to a &amp;lt;code&amp;gt;--PublishCommand&amp;lt;/code&amp;gt;, will appear in whichever tabs and sections their definitions dictate.&lt;br /&gt;
&lt;br /&gt;
Note that, wherever a SerialInterface Parameter specifies a byte string to be sent to the widget, the byte string may be expressed using backslash escapes familiar to the C/C++ or Python programmer: &amp;lt;code&amp;gt;\n&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;\r&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;\t&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;\0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;\\&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;\xNN&amp;lt;/code&amp;gt;  are all recognized, where &amp;lt;code&amp;gt;NN&amp;lt;/code&amp;gt; stands for a pair of hex digits (these are interpreted like Python, not like C—in other words, the maximum expected number of digits is 2). Other backslash escapes are not supported (so, use &amp;lt;code&amp;gt;\x07&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;\a&amp;lt;/code&amp;gt;, use&amp;lt;code&amp;gt;\x0B&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;\v&amp;lt;/code&amp;gt;, etc.).  If your widget sketch uses the Keyhole library, commands are expected to end with either a newline &amp;lt;code&amp;gt;\n&amp;lt;/code&amp;gt; or a semicolon &amp;lt;code&amp;gt;;&amp;lt;/code&amp;gt; (but in a BCI2000 script, semicolons mean something to the script interpreter, so you would have to ensure they&#039;re used in quotes).&lt;br /&gt;
&lt;br /&gt;
===SerialPort===&lt;br /&gt;
This string specifies the port address, optionally followed by a colon and a comma-delimited sequence of serial port options as described above. This must be [[User_Reference:Module_Command_Line_Options#Specifying_Options|specified on the command-line when the signal source module is launched]] and its value cannot be changed without quitting and relaunching BCI2000. If this parameter is absent or its value is empty, the SerialInterface extension is entirely disabled.&lt;br /&gt;
&lt;br /&gt;
===PublishCommand===&lt;br /&gt;
This optional string specifies the sequence of bytes that should be sent by BCI2000 to request Parameter and Event definitions from the widget. If used, this must be [[User_Reference:Module_Command_Line_Options#Specifying_Options|specified on the command-line when the signal source module is launched]]. Its value cannot be changed without quitting and relaunching BCI2000.&lt;br /&gt;
&lt;br /&gt;
===StartCommand===&lt;br /&gt;
If specified, this sequence of bytes is sent to the widget whenever a run is started (e.g. when Start or Resume is pressed).&lt;br /&gt;
With &amp;lt;code&amp;gt;TTLExampleSketch.ino&amp;lt;/code&amp;gt;, the string &amp;lt;code&amp;gt;mute=0\n&amp;lt;/code&amp;gt; can be used, although the sketch will work on most microcontrollers even without a StartCommand and StopCommand.&lt;br /&gt;
&lt;br /&gt;
===StopCommand===&lt;br /&gt;
If specified, this sequence of bytes is sent to the widget whenever a run stops (e.g. when Suspend is pressed) and also when Set Config is pressed.&lt;br /&gt;
With &amp;lt;code&amp;gt;TTLExampleSketch.ino&amp;lt;/code&amp;gt;, the string &amp;lt;code&amp;gt;mute=1\n&amp;lt;/code&amp;gt; can be used, although the sketch will work on most microcontrollers even without a StartCommand and StopCommand.&lt;br /&gt;
&lt;br /&gt;
===ParameterUpdateCommand===&lt;br /&gt;
If specified, this sequence of bytes is sent to the widget whenever a run stops (e.g. when Suspend is pressed).&lt;br /&gt;
As with the &#039;&#039;&#039;PublishCommand&#039;&#039;&#039;, BCI2000 will then expect the widget to reply with a sequence of lines, terminated by a blank line. Each line is expected to be of the format &amp;lt;code&amp;gt;ParameterName = VALUE&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;ParameterName&amp;lt;/code&amp;gt; must denote a writeable parameter previously declared by the widget, and &amp;lt;code&amp;gt;VALUE&amp;lt;/code&amp;gt; can be a simple numeric value or string (quoted and backslash-escaped if necessary).&lt;br /&gt;
This allows new parameter values to be carried over from one run to the next.&lt;br /&gt;
&lt;br /&gt;
===SerialInputs===&lt;br /&gt;
This matrix parameter gives BCI2000 the limited ability to respond to serial-port messages sent by the widget, even if you cannot re-program your widget.&lt;br /&gt;
&lt;br /&gt;
If not empty, the matrix must have four columns.  The first column contains (backslash-escaped) byte strings that the widget might send to BCI2000. The second column contains names of State Variables that have been declared as [[Programming_Reference:Events|Events]] (perhaps using [[User_Reference:Operator_Module_Scripting#ADD_EVENT_&amp;lt;name&amp;gt;_&amp;lt;bit_width&amp;gt;_&amp;lt;initial_value&amp;gt;|&amp;lt;code&amp;gt;ADD EVENT&amp;lt;/code&amp;gt;]] in your launcher script).  The third column contains the integer value that should be assigned to the Event when the byte string is received.   In the fourth column, the entry should either be left blank (in which case, the Event will remain at the assigned value until it is changed again) or set to 0 (in which case the Event is transient, remaining at the assigned value only for one sample before automatically returning to 0).  Thus, the second, third and fourth columns can be read from left to right as a [[Programming_Reference:Events#Descriptor_Syntax|BCI2000 Event descriptor]], like &amp;lt;code&amp;gt;MyEvent 123&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;MyEvent 123 0&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A given byte string is allowed to appear more than once in the table, to trigger multiple Events simultaneously.  The Event name (second column) is allowed to be blank, to enable a particular byte string to be recognized but ignored.&lt;br /&gt;
&lt;br /&gt;
Note that the &#039;&#039;&#039;SerialInputs&#039;&#039;&#039; mechanism is designed to be very generic, and as such it is not necessarily possible to tailor it to the particular protocol your widget uses. For example, BCI2000 will not know how the widget likes to terminate messages unless you explicitly include the terminator bytes (so, if &amp;lt;code&amp;gt;shutdown&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;shutdown-gracefully&amp;lt;/code&amp;gt; are both configured, the longer command will never be recognized: BCI2000 will greedily recognize and obey &amp;lt;code&amp;gt;shutdown&amp;lt;/code&amp;gt; before attempting to move on to &amp;lt;code&amp;gt;-gracefully&amp;lt;/code&amp;gt;). The limitations of the &#039;&#039;&#039;SerialInputs&#039;&#039;&#039; table also make themselves felt if the widget sends a byte string that you have omitted from the table. Then, one of two compromises must be accepted (see the description of the &#039;&#039;&#039;SkipUnrecognizedBytes&#039;&#039;&#039; parameter, below). In general, it is not possible to support a serial protocol that includes variable values (unless you create a separate &#039;&#039;&#039;SerialInputs&#039;&#039;&#039; row for every possible combination of values).&lt;br /&gt;
&lt;br /&gt;
===SkipUnrecognizedBytes===&lt;br /&gt;
This boolean parameter determines what happens if you are using the &#039;&#039;&#039;SerialInputs&#039;&#039;&#039; table to recognize messages from the widget, and the widget sends you a string that is not recognized. Either choice can have unfortunate consequences, depending on your widget&#039;s protocol.&lt;br /&gt;
&lt;br /&gt;
If the &#039;&#039;&#039;SkipUnrecognizedBytes&#039;&#039;&#039; parameter is set to false (unchecked), then the data coming from the widget will continue to build into an ever-lengthening unrecognized command: BCI2000 will not recognize another &#039;&#039;&#039;SerialInputs&#039;&#039;&#039; byte string at all until the SerialInterface is reset (which happens at the start of a run if SerialInterface is running as an Extension, or when Set Config is pressed if you are running SerialWidgetADC).&lt;br /&gt;
&lt;br /&gt;
If &#039;&#039;&#039;SkipUnrecognizedBytes&#039;&#039;&#039; is set to true (checked), then it will be possible to discard unrecognized bytes and match a known string, but with the danger that substrings of &#039;&#039;un&#039;&#039;recognized commands could be falsely recognized as commands. For example, if you have enabled &#039;&#039;&#039;SkipUnrecognizedBytes&#039;&#039;&#039;, and you have listed the command &amp;lt;code&amp;gt;arm_stimulator&amp;lt;/code&amp;gt; in &#039;&#039;&#039;SerialInputs&#039;&#039;&#039; but &#039;&#039;not&#039;&#039; &amp;lt;code&amp;gt;disarm_stimulator&amp;lt;/code&amp;gt;, and the widget then happens to send &amp;lt;code&amp;gt;disarm_stimulator&amp;lt;/code&amp;gt;,  then BCI2000 will discard the bytes &amp;lt;code&amp;gt;dis&amp;lt;/code&amp;gt; and recognize &amp;lt;code&amp;gt;arm_stimulator&amp;lt;/code&amp;gt;, leading to the opposite of the intended effect. Clearly, this is a function of how the widget&#039;s protocol is designed.  To avoid such situations, you must either (a) ensure that the entries in the &#039;&#039;&#039;SerialInputs&#039;&#039;&#039; table exhaustively cover the repertoire of possible widget outputs (don&#039;t worry, if a known longer string gets matched, its substrings will not get matched), or (b) accept the consequences of disabling &#039;&#039;&#039;SkipUnrecognizedBytes&#039;&#039;&#039;. An even more robust option, if possible, is (c) to leave the &#039;&#039;&#039;SerialInputs&#039;&#039;&#039; table empty and re-program your widget to send BCI2000 event descriptors directly as text (see the [[#State Variables|State Variables]] section, below).&lt;br /&gt;
&lt;br /&gt;
===SerialOutputs===&lt;br /&gt;
This matrix parameter gives BCI2000 the ability to send messages to the widget whenever specified contingencies are met.&lt;br /&gt;
&lt;br /&gt;
If not empty, the matrix must have two columns.  The first column contains [[User Reference:Expression Syntax|Expressions]]. The second column contains (backslash-escaped) byte strings.  Expressions are evaluated at the beginning of each sample-block. If an Expression was previously zero and now evaluates to non-zero, the corresponding byte string is immediately sent to the widget.  In this way, you can link a BCI2000 State Variable to a widget command that, for example, causes a TTL pulse to be generated.&lt;br /&gt;
&lt;br /&gt;
If you are using &amp;lt;code&amp;gt;TTLExampleSketch.ino&amp;lt;/code&amp;gt;, you would associate Expressions with the commands &amp;lt;code&amp;gt;output=1\n&amp;lt;/code&amp;gt; and  &amp;lt;code&amp;gt;output=0\n&amp;lt;/code&amp;gt;. For example, let&#039;s assume you have defined your own State Variable called  &amp;lt;code&amp;gt;StimTrigger&amp;lt;/code&amp;gt;. Then your &#039;&#039;&#039;SerialOutputs&#039;&#039;&#039; parameter might look as shown in the screenshot:&lt;br /&gt;
&lt;br /&gt;
[[File:SerialOutputs.PNG]]&lt;br /&gt;
&lt;br /&gt;
===ElseIf===&lt;br /&gt;
This parameter dictates the logic by which the rows of the &#039;&#039;&#039;SerialOutputs&#039;&#039;&#039; Parameter are processed.&lt;br /&gt;
You may choose to process all rows on every sample-block (and potentially send all byte strings, one after the other);&lt;br /&gt;
alternatively, you may choose to stop after the first matching row (so, on any given sample-block, at most one of the byte strings will be sent).&lt;br /&gt;
Possible values are 0 (&amp;quot;process all rows&amp;quot;) or 1 (&amp;quot;stop at the first match&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
==State Variables==&lt;br /&gt;
&lt;br /&gt;
The SerialInterface does not define any State Variables or Events of its own, but will define any [[#Defining BCI2000 Parameters and Events from the Widget|Events the widget tells it to define]] in response to a &amp;lt;code&amp;gt;--PublishCommand&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
During a run, a widget may change an Event value at any time by sending an [[Programming_Reference:Events#Descriptor_Syntax|Event descriptor line]]: usually, this is the name of the event, followed by a space, followed by the value expressed as decimal text, followed by a line-ending. Optionally, an Event descriptor may contain an additional space and a zero, to indicate an instantaneous transient event.  For example, &amp;lt;code&amp;gt;TTLExampleSketch.ino&amp;lt;/code&amp;gt; will send &lt;br /&gt;
 TTLInput 1\r\n&lt;br /&gt;
whenever the voltage on its input pin changes from low to high, and&lt;br /&gt;
 TTLInput 0\r\n&lt;br /&gt;
 PulseDurationMsec 123 0\r\n&lt;br /&gt;
whenever the voltage changes from high to low (where 123 is a place-holder for however long the input pulse in fact lasted, according to the widget&#039;s millisecond timer).&lt;br /&gt;
&lt;br /&gt;
Note that it is not necessary for the Event in question to have been defined by the widget itself—it could have been added by one of the other filters and loggers, or in your [[User_Reference:Operator_Module_Scripting|BCI2000 script]] using [[User_Reference:Operator_Module_Scripting#ADD_EVENT_&amp;lt;name&amp;gt;_&amp;lt;bit_width&amp;gt;_&amp;lt;initial_value&amp;gt;|an &amp;lt;code&amp;gt;ADD EVENT&amp;lt;/code&amp;gt; command]] before the &amp;lt;code&amp;gt;STARTUP SYSTEM&amp;lt;/code&amp;gt; line. This means you do not necessarily have to implement the widget&#039;s response to a &amp;lt;code&amp;gt;--PublishCommand&amp;lt;/code&amp;gt;, even if you are planning to use the widget to log Events.&lt;br /&gt;
&lt;br /&gt;
If you cannot re-program the widget at all, you may still have some (limited) options for triggering Events in response to messages from the widget, via the &#039;&#039;&#039;SerialInputs&#039;&#039;&#039; parameter.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
[[Contributions:SerialWidgetADC]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Contributions]][[Category:Extension]]&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Contributions:SerialInterface&amp;diff=12437</id>
		<title>Contributions:SerialInterface</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Contributions:SerialInterface&amp;diff=12437"/>
		<updated>2026-05-12T17:37:26Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* ElseIf */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Synopsis==&lt;br /&gt;
An extension that allows flexible communication to and from serial-port devices such as programmable microcontrollers (e.g. Arduino, Teensy, Pico, etc.)&lt;br /&gt;
&lt;br /&gt;
==Location==&lt;br /&gt;
http://{{SERVERNAME}}/svn/trunk/src/contrib/Extensions/SerialInterface&lt;br /&gt;
&lt;br /&gt;
==Versioning==&lt;br /&gt;
&lt;br /&gt;
===Authors===&lt;br /&gt;
Jeremy Hill (hill@neurotechcenter.org)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Version History===&lt;br /&gt;
* 2023-08-10: Initial public release&lt;br /&gt;
* 2025-06-13: SerialInput parameter added, expanding the options for two-way communication.&lt;br /&gt;
&lt;br /&gt;
===Source Code Revisions===&lt;br /&gt;
*Initial development: r7523&lt;br /&gt;
*Known to compile under: r8888&lt;br /&gt;
*Broken since: --&lt;br /&gt;
&lt;br /&gt;
==Functional Description==&lt;br /&gt;
Among the biosignal acquisition devices supported by BCI2000, a few allow &amp;quot;digital output&amp;quot;, i.e. the generation of TTL pulses that might be used to trigger or otherwise synchronize with other devices; most, however, do not offer this functionality. Furthermore, many devices support &#039;&#039;acquisition&#039;&#039; of TTL pulses and other auxiliary information alongside biosignal data; however, some devices lack even this capability.&lt;br /&gt;
&lt;br /&gt;
Where such functionality is lacking, one flexible option for adding it to your system is to build and program a custom solution based on a microcontroller such as an Arduino, Teensy or Pico (hereafter referred to as a &amp;quot;widget&amp;quot;).  The SerialInterface extension allows BCI2000 to interface with such widgets.&lt;br /&gt;
&lt;br /&gt;
The primary intended purpose of the SerialInterface is to send arbitrary byte strings to a widget over a serial port whenever specified BCI2000 [[User Reference:Expression Syntax|Expressions]] become true—this is a simple way in which digital-output functionality may be supplied for hardware that lacks it. This mechanism could also allow your BCI system to control almost anything you can imagine attaching to a custom microcontroller.  Since the outgoing byte strings can be configured arbitrarily, you might possibly be able to make this work even if you cannot (re-)program the widget yourself.&lt;br /&gt;
&lt;br /&gt;
A secondary function of the SerialInterface is to receive and log [[Programming Reference:Events|Event]] information. This can be done in two ways: either by supplying a fixed set of byte strings that BCI2000 should respond to when it receives them from the widget, or by having the widget send actual BCI2000 event descriptors. For the latter, the widget must be programmed to output strings in the format that BCI2000 will understand. If you have the ability to re-program your widget, then you may also optionally make the widget define its own BCI2000 Parameters and Events. Together, these mechanisms allow information from arbitrary sensors to be sent to BCI2000, mediated by a programmable widget.&lt;br /&gt;
&lt;br /&gt;
An example BCI2000-compatible microcontroller sketch, for the Arduino IDE, is provided in [https://bci2000.org/svn/trunk/src/contrib/Extensions/SerialInterface/TTLExampleSketch/ the TTLExampleSketch subdirectory]. It makes use of [https://www.arduino.cc/reference/en/libraries/keyhole the Keyhole library], which can be installed via the IDE&#039;s library manager and which makes it easy for sketches to respond to serial-port commands and to allow their variables to be read and written.&lt;br /&gt;
&lt;br /&gt;
Note that the SerialInterface Extension is intended to provide &#039;&#039;auxiliary&#039;&#039; input/output functionality to source modules that acquire their primary signal elsewhere.  If you also want to acquire the &#039;&#039;primary&#039;&#039; signal from the same widget, you should use the closely-related [[Contributions:SerialWidgetADC|SerialWidgetADC]], which is part of the SerialWidget signal-source module and which requires a more-sophisticated sketch.&lt;br /&gt;
&lt;br /&gt;
==Enabling SerialInterface==&lt;br /&gt;
&lt;br /&gt;
[[User_Reference:Logging_Input|Like all Extensions]], SerialInterface is only available if your signal source module was compiled with the appropriate CMake flag enabled: in this case, &amp;lt;code&amp;gt;EXTENSIONS_SERIALINTERFACE=ON&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Then, when you launch BCI2000, SerialInterface must be enabled by supplying a value for the &amp;lt;code&amp;gt;--SerialPort&amp;lt;/code&amp;gt; parameter [[User_Reference:Module_Command_Line_Options#Specifying_Options|on the command-line]]. For example, in a [[User_Reference:Operator_Module_Scripting|BCI2000 script]], you might use the line:&lt;br /&gt;
 start executable SignalGenerator --local --SerialPort=COM4:baud=9600,dtr=on&lt;br /&gt;
&lt;br /&gt;
In the example above, note that a suffix has been appended to the usual serial-port address &amp;lt;code&amp;gt;COM4&amp;lt;/code&amp;gt;, attached by a colon. In this optional suffix, you can specify a comma-separated list of options as understood by the Windows &amp;lt;code&amp;gt;MODE&amp;lt;/code&amp;gt; command (see [https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-buildcommdcba#parameters Microsoft&#039;s documentation for the configuration string passed to the BuildCommDCBA() function]).  These options may or may not be necessary for your widget—for example, we have found that the Teensy microcontroller does not seem to care whether the &amp;lt;code&amp;gt;dtr&amp;lt;/code&amp;gt; option is on or off; however, the Pico will not work properly unless this option is explicitly turned on, whereas the ItsyBitsy M4 will fail to communicate if it &#039;&#039;is&#039;&#039; turned on.&lt;br /&gt;
&lt;br /&gt;
==Defining BCI2000 Parameters and Events from the Widget==&lt;br /&gt;
If you want your widget to define its own BCI2000 Parameters and Events, the widget must be programmed to send this information to BCI2000 on command, and you can specify exactly what sequence of bytes the command comprises. To ensure that the chosen command is sent to the widget during the [[Programming_Reference:GenericFilter_Class#Publish|&amp;quot;Publish&amp;quot; phase]] of BCI2000 startup, you should specify it as the &amp;lt;code&amp;gt;--PublishCommand&amp;lt;/code&amp;gt; parameter, again on the command line:&lt;br /&gt;
 start executable SignalGenerator --local --SerialPort=COM4:baud=9600,dtr=on --PublishCommand=publish\n&lt;br /&gt;
&lt;br /&gt;
The particular byte sequence &amp;lt;code&amp;gt;publish\n&amp;lt;/code&amp;gt; works with &amp;lt;code&amp;gt;TTLExampleSketch.ino&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
When the widget receives the publish command, it must reply with one or more lines of text.  BCI2000 will attempt to interpret any line containing the &amp;lt;code&amp;gt;=&amp;lt;/code&amp;gt; character as a [[Technical_Reference:Parameter_Definition|Parameter definition]], and any other non-empty line as an [[Programming_Reference:Events#Implementation|Event definition]].   The widget must send a blank line (terminated with &amp;lt;code&amp;gt;\n&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;\r\n&amp;lt;/code&amp;gt;) to signify the end of the definitions (if your sketch omits this, BCI2000 will hang indefinitely, waiting for more definitions).&lt;br /&gt;
&lt;br /&gt;
A widget Parameter definition may be specified as &amp;lt;code&amp;gt;(readonly)&amp;lt;/code&amp;gt;, in which case the Parameter may be of any type and will not be editable by the user. Such read-only parameters are a means by which the widget can make annotations that will be stored in data files&#039; parameter headers (e.g. information about microcontroller model or sketch version).  On the other hand, if the &amp;lt;code&amp;gt;(readonly)&amp;lt;/code&amp;gt; flag is &#039;&#039;not&#039;&#039; found in the Parameter definition comment, the Parameter will actually be configurable by the user: in this case, only &amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;float&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt; Parameters are allowed.  If the widget defines configurable Parameters, Parameter values will be sent to the widget when the user presses &amp;quot;Set Config&amp;quot;, using strings of the following format:&lt;br /&gt;
 Foo=1\n&lt;br /&gt;
 Bar=3.0\n&lt;br /&gt;
 Boo=&amp;quot;this is a string parameter value&amp;quot;\n&lt;br /&gt;
 &lt;br /&gt;
In that case, your widget sketch must be able to interpret such commands (the [https://www.arduino.cc/reference/en/libraries/keyhole Keyhole] library makes this easy, as shown in the example sketch).&lt;br /&gt;
&lt;br /&gt;
You may also chose to specify a &#039;&#039;&#039;ParameterUpdateCommand&#039;&#039;&#039;: if so, the specified bytes will be sent to the widget in the [[Programming_Reference:GenericFilter_Class#StopRun|&amp;quot;StopRun&amp;quot; phase]], to request updates to the values of widget-defined parameters. When the widget receives the specified parameter-update command, just as with the publish command, it must reply with a sequence of lines terminated by a blank line.  As before, if you choose to use this option, BCI2000 will hang until it receives that final blank line.  This time, however, the non-blank lines are expected to have the same syntax as the lines that were sent &#039;&#039;to&#039;&#039; the widget on Set Config, e.g. &amp;lt;code&amp;gt;Foo=123&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Boo=&amp;quot;some string&amp;quot;&amp;lt;/code&amp;gt;.  Note that you can only update parameters that the widget itself has previously declared, and you cannot update a parameter that was declared as &amp;lt;code&amp;gt;(readonly)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Parameters==&lt;br /&gt;
If enabled using the &amp;lt;code&amp;gt;--SerialPort&amp;lt;/code&amp;gt; command-line parameter, the full set of SerialInterface&#039;s parameters (described below) will appear in the Source tab of BCI2000&#039;s Config window. In addition, any Parameters defined by the widget itself, in response to a &amp;lt;code&amp;gt;--PublishCommand&amp;lt;/code&amp;gt;, will appear in whichever tabs and sections their definitions dictate.&lt;br /&gt;
&lt;br /&gt;
Note that, wherever a SerialInterface Parameter specifies a byte string to be sent to the widget, the byte string may be expressed using backslash escapes familiar to the C/C++ or Python programmer: &amp;lt;code&amp;gt;\n&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;\r&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;\t&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;\0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;\\&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;\xNN&amp;lt;/code&amp;gt;  are all recognized, where &amp;lt;code&amp;gt;NN&amp;lt;/code&amp;gt; stands for a pair of hex digits (these are interpreted like Python, not like C—in other words, the maximum expected number of digits is 2). Other backslash escapes are not supported (so, use &amp;lt;code&amp;gt;\x07&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;\a&amp;lt;/code&amp;gt;, use&amp;lt;code&amp;gt;\x0B&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;\v&amp;lt;/code&amp;gt;, etc.).  If your widget sketch uses the Keyhole library, commands are expected to end with either a newline &amp;lt;code&amp;gt;\n&amp;lt;/code&amp;gt; or a semicolon &amp;lt;code&amp;gt;;&amp;lt;/code&amp;gt; (but in a BCI2000 script, semicolons mean something to the script interpreter, so you would have to ensure they&#039;re used in quotes).&lt;br /&gt;
&lt;br /&gt;
===SerialPort===&lt;br /&gt;
This string specifies the port address, optionally followed by a colon and a comma-delimited sequence of serial port options as described above. This must be [[User_Reference:Module_Command_Line_Options#Specifying_Options|specified on the command-line when the signal source module is launched]] and its value cannot be changed without quitting and relaunching BCI2000. If this parameter is absent or its value is empty, the SerialInterface extension is entirely disabled.&lt;br /&gt;
&lt;br /&gt;
===PublishCommand===&lt;br /&gt;
This optional string specifies the sequence of bytes that should be sent by BCI2000 to request Parameter and Event definitions from the widget. If used, this must be [[User_Reference:Module_Command_Line_Options#Specifying_Options|specified on the command-line when the signal source module is launched]]. Its value cannot be changed without quitting and relaunching BCI2000.&lt;br /&gt;
&lt;br /&gt;
===StartCommand===&lt;br /&gt;
If specified, this sequence of bytes is sent to the widget whenever a run is started (e.g. when Start or Resume is pressed).&lt;br /&gt;
With &amp;lt;code&amp;gt;TTLExampleSketch.ino&amp;lt;/code&amp;gt;, the string &amp;lt;code&amp;gt;mute=0\n&amp;lt;/code&amp;gt; can be used, although the sketch will work on most microcontrollers even without a StartCommand and StopCommand.&lt;br /&gt;
&lt;br /&gt;
===StopCommand===&lt;br /&gt;
If specified, this sequence of bytes is sent to the widget whenever a run stops (e.g. when Suspend is pressed) and also when Set Config is pressed.&lt;br /&gt;
With &amp;lt;code&amp;gt;TTLExampleSketch.ino&amp;lt;/code&amp;gt;, the string &amp;lt;code&amp;gt;mute=1\n&amp;lt;/code&amp;gt; can be used, although the sketch will work on most microcontrollers even without a StartCommand and StopCommand.&lt;br /&gt;
&lt;br /&gt;
===ParameterUpdateCommand===&lt;br /&gt;
If specified, this sequence of bytes is sent to the widget whenever a run stops (e.g. when Suspend is pressed).&lt;br /&gt;
As with the &#039;&#039;&#039;PublishCommand&#039;&#039;&#039;, BCI2000 will then expect the widget to reply with a sequence of lines, terminated by a blank line. Each line is expected to be of the format &amp;lt;code&amp;gt;ParameterName = VALUE&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;ParameterName&amp;lt;/code&amp;gt; must denote a writeable parameter previously declared by the widget, and &amp;lt;code&amp;gt;VALUE&amp;lt;/code&amp;gt; can be a simple numeric value or string (quoted and backslash-escaped if necessary).&lt;br /&gt;
This allows new parameter values to be carried over from one run to the next.&lt;br /&gt;
&lt;br /&gt;
===SerialInputs===&lt;br /&gt;
This matrix parameter gives BCI2000 the limited ability to respond to serial-port messages sent by the widget, even if you cannot re-program your widget.&lt;br /&gt;
&lt;br /&gt;
If not empty, the matrix must have four columns.  The first column contains (backslash-escaped) byte strings that the widget might send to BCI2000. The second column contains names of State Variables that have been declared as [[Programming_Reference:Events|Events]] (perhaps using [[User_Reference:Operator_Module_Scripting#ADD_EVENT_&amp;lt;name&amp;gt;_&amp;lt;bit_width&amp;gt;_&amp;lt;initial_value&amp;gt;|&amp;lt;code&amp;gt;ADD EVENT&amp;lt;/code&amp;gt;]] in your launcher script).  The third column contains the integer value that should be assigned to the Event when the byte string is received.   In the fourth column, the entry should either be left blank (in which case, the Event will remain at the assigned value until it is changed again) or set to 0 (in which case the Event is transient, remaining at the assigned value only for one sample before automatically returning to 0).  Thus, the second, third and fourth columns can be read from left to right as a [[Programming_Reference:Events#Descriptor_Syntax|BCI2000 Event descriptor]], like &amp;lt;code&amp;gt;MyEvent 123&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;MyEvent 123 0&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A given byte string is allowed to appear more than once in the table, to trigger multiple Events simultaneously.  The Event name (second column) is allowed to be blank, to enable a particular byte string to be recognized but ignored.&lt;br /&gt;
&lt;br /&gt;
Note that the &#039;&#039;&#039;SerialInputs&#039;&#039;&#039; mechanism is designed to be very generic, and as such it is not necessarily possible to tailor it to the particular protocol your widget uses. For example, BCI2000 will not know how the widget likes to terminate messages unless you explicitly include the terminator bytes (so, if &amp;lt;code&amp;gt;shutdown&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;shutdown-gracefully&amp;lt;/code&amp;gt; are both configured, the longer command will never be recognized: BCI2000 will greedily recognize and obey &amp;lt;code&amp;gt;shutdown&amp;lt;/code&amp;gt; before attempting to move on to &amp;lt;code&amp;gt;-gracefully&amp;lt;/code&amp;gt;). The limitations of the &#039;&#039;&#039;SerialInputs&#039;&#039;&#039; table also make themselves felt if the widget sends a byte string that you have omitted from the table. Then, one of two compromises must be accepted (see the description of the &#039;&#039;&#039;SkipUnrecognizedBytes&#039;&#039;&#039; parameter, below). In general, it is not possible to support a serial protocol that includes variable values (unless you create a separate &#039;&#039;&#039;SerialInputs&#039;&#039;&#039; row for every possible combination of values).&lt;br /&gt;
&lt;br /&gt;
===SkipUnrecognizedBytes===&lt;br /&gt;
This boolean parameter determines what happens if you are using the &#039;&#039;&#039;SerialInputs&#039;&#039;&#039; table to recognize messages from the widget, and the widget sends you a string that is not recognized. Either choice can have unfortunate consequences, depending on your widget&#039;s protocol.&lt;br /&gt;
&lt;br /&gt;
If the &#039;&#039;&#039;SkipUnrecognizedBytes&#039;&#039;&#039; parameter is set to false (unchecked), then the data coming from the widget will continue to build into an ever-lengthening unrecognized command: BCI2000 will not recognize another &#039;&#039;&#039;SerialInputs&#039;&#039;&#039; byte string at all until the SerialInterface is reset (which happens at the start of a run if SerialInterface is running as an Extension, or when Set Config is pressed if you are running SerialWidgetADC).&lt;br /&gt;
&lt;br /&gt;
If &#039;&#039;&#039;SkipUnrecognizedBytes&#039;&#039;&#039; is set to true (checked), then it will be possible to discard unrecognized bytes and match a known string, but with the danger that substrings of &#039;&#039;un&#039;&#039;recognized commands could be falsely recognized as commands. For example, if you have enabled &#039;&#039;&#039;SkipUnrecognizedBytes&#039;&#039;&#039;, and you have listed the command &amp;lt;code&amp;gt;arm_stimulator&amp;lt;/code&amp;gt; in &#039;&#039;&#039;SerialInputs&#039;&#039;&#039; but &#039;&#039;not&#039;&#039; &amp;lt;code&amp;gt;disarm_stimulator&amp;lt;/code&amp;gt;, and the widget then happens to send &amp;lt;code&amp;gt;disarm_stimulator&amp;lt;/code&amp;gt;,  then BCI2000 will discard the bytes &amp;lt;code&amp;gt;dis&amp;lt;/code&amp;gt; and recognize &amp;lt;code&amp;gt;arm_stimulator&amp;lt;/code&amp;gt;, leading to the opposite of the intended effect. Clearly, this is a function of how the widget&#039;s protocol is designed.  To avoid such situations, you must either (a) ensure that the entries in the &#039;&#039;&#039;SerialInputs&#039;&#039;&#039; table exhaustively cover the repertoire of possible widget outputs (don&#039;t worry, if a known longer string gets matched, its substrings will not get matched), or (b) accept the consequences of disabling &#039;&#039;&#039;SkipUnrecognizedBytes&#039;&#039;&#039;. An even more robust option, if possible, is (c) to leave the &#039;&#039;&#039;SerialInputs&#039;&#039;&#039; table empty and re-program your widget to send BCI2000 event descriptors directly as text (see the [[#State Variables|State Variables]] section, below).&lt;br /&gt;
&lt;br /&gt;
===SerialOutputs===&lt;br /&gt;
This matrix parameter gives BCI2000 the ability to send messages to the widget whenever specified contingencies are met.&lt;br /&gt;
&lt;br /&gt;
If not empty, the matrix must have two columns.  The first column contains [[User Reference:Expression Syntax|Expressions]]. The second column contains (backslash-escaped) byte strings.  Expressions are evaluated at the beginning of each sample-block. If an Expression was previously zero and now evaluates to non-zero, the corresponding byte string is immediately sent to the widget.  In this way, you can link a BCI2000 State Variable to a widget command that, for example, causes a TTL pulse to be generated.&lt;br /&gt;
&lt;br /&gt;
If you are using &amp;lt;code&amp;gt;TTLExampleSketch.ino&amp;lt;/code&amp;gt;, you would associate Expressions with the commands &amp;lt;code&amp;gt;output=1\n&amp;lt;/code&amp;gt; and  &amp;lt;code&amp;gt;output=0\n&amp;lt;/code&amp;gt;. For example, let&#039;s assume you have defined your own State Variable called  &amp;lt;code&amp;gt;StimTrigger&amp;lt;/code&amp;gt;. Then your &#039;&#039;&#039;SerialOutputs&#039;&#039;&#039; parameter might look as shown in the screenshot:&lt;br /&gt;
&lt;br /&gt;
[[File:SerialOutputs.PNG]]&lt;br /&gt;
&lt;br /&gt;
===ElseIf===&lt;br /&gt;
This parameter dictates the logic by which the rows of the &#039;&#039;&#039;SerialOutputs&#039;&#039;&#039; Parameter are processed.&lt;br /&gt;
You may choose to process all rows on every sample-block (and potentially send all byte strings, one after the other);&lt;br /&gt;
alternatively, you may choose to stop after the first matching row (so, on any given sample-block, at most one of the byte strings will be sent).&lt;br /&gt;
Possible values are 0 (&amp;quot;process all rows&amp;quot;) or 1 (&amp;quot;stop at the first match&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
==State Variables==&lt;br /&gt;
&lt;br /&gt;
The SerialInterface does not define any State Variables or Events of its own, but will define any Events the widget tells it to define in response to a &amp;lt;code&amp;gt;--PublishCommand&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
During a run, a widget may change an Event value at any time by sending an [[Programming_Reference:Events#Descriptor_Syntax|Event descriptor line]]: usually, this is the name of the event, followed by a space, followed by the value expressed as decimal text, followed by a line-ending. Optionally, an Event descriptor may contain an additional space and a zero, to indicate an instantaneous transient event.  For example, &amp;lt;code&amp;gt;TTLExampleSketch.ino&amp;lt;/code&amp;gt; will send &lt;br /&gt;
 TTLInput 1\r\n&lt;br /&gt;
whenever the voltage on its input pin changes from low to high, and&lt;br /&gt;
 TTLInput 0\r\n&lt;br /&gt;
 PulseDurationMsec 123 0\r\n&lt;br /&gt;
whenever the voltage changes from high to low (where 123 is a place-holder for however long the input pulse in fact lasted, according to the widget&#039;s millisecond timer).&lt;br /&gt;
&lt;br /&gt;
Note that it is not necessary for the Event in question to have been defined by the widget itself—it could have been added by one of the other filters and loggers, or in your [[User_Reference:Operator_Module_Scripting|BCI2000 script]] using [[User_Reference:Operator_Module_Scripting#ADD_EVENT_&amp;lt;name&amp;gt;_&amp;lt;bit_width&amp;gt;_&amp;lt;initial_value&amp;gt;|an &amp;lt;code&amp;gt;ADD EVENT&amp;lt;/code&amp;gt; command]] before the &amp;lt;code&amp;gt;STARTUP SYSTEM&amp;lt;/code&amp;gt; line. This means you do not necessarily have to implement the widget&#039;s response to a &amp;lt;code&amp;gt;--PublishCommand&amp;lt;/code&amp;gt;, even if you are planning to use the widget to log Events.&lt;br /&gt;
&lt;br /&gt;
If you cannot re-program the widget at all, you may still have some (limited) options for triggering Events in response to messages from the widget, via the &#039;&#039;&#039;SerialInputs&#039;&#039;&#039; parameter.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
[[Contributions:SerialWidgetADC]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Contributions]][[Category:Extension]]&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Main_Page&amp;diff=12412</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Main_Page&amp;diff=12412"/>
		<updated>2026-05-04T15:49:00Z</updated>

		<summary type="html">&lt;p&gt;Jhill: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__ __NOEDITSECTION__&lt;br /&gt;
&amp;lt;table cellspacing=&amp;quot;10&amp;quot; class=&amp;quot;noprint&amp;quot; style=&amp;quot;float:left; margin-top:0;margin-bottom:0; text-align:right&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;border-radius: 10px; background-color:#efefef;padding: 1em 1em 1em 1em;word-spacing:1em;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;htmltag tagname=&amp;quot;form&amp;quot; name=&amp;quot;sitesearch&amp;quot; action=&amp;quot;https://www.google.com/search&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;htmltag tagname=&amp;quot;input&amp;quot; name=&amp;quot;q&amp;quot; type=&amp;quot;text&amp;quot; size=&amp;quot;40&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;htmltag tagname=&amp;quot;input&amp;quot; type=&amp;quot;submit&amp;quot; value=&amp;quot;Google site search of bci2000.org&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;htmltag tagname=&amp;quot;input&amp;quot; type=&amp;quot;hidden&amp;quot; name=&amp;quot;sitesearch&amp;quot; value=&amp;quot;bci2000.org&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;htmltag tagname=&amp;quot;input&amp;quot; type=&amp;quot;hidden&amp;quot; name=&amp;quot;ie&amp;quot; value=&amp;quot;utf-8&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;htmltag tagname=&amp;quot;input&amp;quot; type=&amp;quot;hidden&amp;quot; name=&amp;quot;oe&amp;quot; value=&amp;quot;utf-8&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/htmltag&amp;gt;&lt;br /&gt;
&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table cellspacing=&amp;quot;10&amp;quot; style=&amp;quot;width:100%;margin-top:-10px&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;margin:0; margin-top:-10px; margin-right:10px; background-color:#ededed; padding:0 1em 1em 1em; align:right; border-radius: 10px; vertical-align:top;&amp;quot;&amp;gt;&lt;br /&gt;
=&amp;lt;b&amp;gt;Download BCI2000&amp;lt;/b&amp;gt;=&lt;br /&gt;
&amp;lt;span style=&amp;quot;font-size:130%&amp;quot;&amp;gt;1. [https://www.bci2000.org/useradmin/ Create a free user account!] (Required to download BCI2000)&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;font-size:130%&amp;quot;&amp;gt;2. Download the [https://bci2000.org/downloads/bin/BCI2000Setup.exe latest release], [[BCI2000 Binaries|previous versions]], or the source code ([[Programming Howto:Building and Customizing BCI2000 |Windows]], [[Programming Howto:Non:Building and Customizing BCI2000 on Non-Windows Platforms |Non-windows]])&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/td&amp;gt; &lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table cellspacing=&amp;quot;10&amp;quot; style=&amp;quot;width:100%;margin-top:-10px&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt; &amp;lt;td style=&amp;quot;margin:0; margin-right:10px; border-radius: 10px; border:0.5px solid #a2a2a2; padding:0 1em 1em 1em; align:right;vertical-align:top;&amp;quot;&amp;gt;&lt;br /&gt;
=&amp;lt;b&amp;gt;What is BCI2000?&amp;lt;/b&amp;gt;=&lt;br /&gt;
BCI2000 is a free, open-source, general-purpose software system for brain-computer interface (BCI) research.&lt;br /&gt;
BCI2000 includes software tools that can acquire and process data, present stimuli and feedback, and manage interaction with outside devices such as robotic arms. BCI2000 is a real-time system that can synchronize EEG and other signals with a wide variety of biosignals and input devices such as mice or eye-trackers. It has several modules to manage data importing and exporting in common file formats. BCI2000 operates on most Windows systems, and the source code can be compiled on most Windows machines. &lt;br /&gt;
&lt;br /&gt;
[[File:BCI2000 New Schematic Extra Large.gif|center|800px|BCI2000 Schematic]]&lt;br /&gt;
&lt;br /&gt;
Above shows the main framework of BCI2000, with examples for each section. Navigate to the [[User Reference:Filters|Filters page]] to learn more about the framework, or view links below for tutorials and more reference pages.&lt;br /&gt;
&amp;lt;/td&amp;gt; &amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table cellspacing=&amp;quot;10&amp;quot; style=&amp;quot;width:100%;margin-top:-10px&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;margin:0; margin-top:10px; margin-right:10px; border-radius: 10px; padding:0 1em 1em 1em; background-color:#fff8dc; align:right;vertical-align:top;&amp;quot;&amp;gt;&lt;br /&gt;
==BCI2000 for Users==&lt;br /&gt;
&lt;br /&gt;
* [//{{SERVERNAME}}/useradmin Create or modify a User Account]&lt;br /&gt;
* [[DownloadBCI2000|Download BCI2000]]&lt;br /&gt;
* [https://bci2000.org/externals/mex/mexfiles.zip Download BCI2000 Matlab MEX files]&lt;br /&gt;
&lt;br /&gt;
* Take the introductory [[User Tutorial:BCI2000 Tour|BCI2000 Tour]]&lt;br /&gt;
* Learn more through an &amp;lt;br /&amp;gt; [[Introduction_to_Adaptive_Neurotechnologies|Introduction to Adaptive Neurotechnologies]]&lt;br /&gt;
* Review the terminology in the [[BCI2000 Glossary]]&lt;br /&gt;
&amp;lt;/td&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;td style=&amp;quot;margin:0; margin-top:10px; margin-right:10px; border-radius: 10px; padding:0 1em 1em 1em; background-color:#e3f5fc; align:right;vertical-align:top;&amp;quot;&amp;gt;&lt;br /&gt;
==BCI2000 for Developers==&lt;br /&gt;
* [//{{SERVERNAME}}/useradmin Create or modify a User Account]&lt;br /&gt;
*  Download source code ([[Programming Howto:Building and Customizing BCI2000 |Windows]], [[Programming Howto:Non:Building and Customizing BCI2000 on Non-Windows Platforms |Non-windows]])&lt;br /&gt;
* [[Programming Reference:Patches|Create a patch]] to add your code to the BCI2000 svn!&lt;br /&gt;
* [[APIs|BCI2000 API Documentation]]&lt;br /&gt;
* [[Rebuild BCI2000]] - instructions for rapid prototyping!&lt;br /&gt;
&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;margin:0; margin-top:10px; margin-right:10px; border-radius: 10px;  background-color:#e3f5fc; padding:0 1em 1em 1em; align:right;vertical-align:top;&amp;quot;&amp;gt;&lt;br /&gt;
==BCI2000 References==&lt;br /&gt;
===BCI2000 Overview and Tools===&lt;br /&gt;
* The [[User Reference:Contents|User Reference Manual]] describes all details&amp;lt;br /&amp;gt;of system configuration and usage&lt;br /&gt;
===Technical References===&lt;br /&gt;
* The [[Technical Reference:Contents|Technical Reference Manual]] contains a discussion of its &amp;lt;br /&amp;gt;basic concepts, and a detailed specification of the BCI2000 standard.&lt;br /&gt;
===Programming References===&lt;br /&gt;
* The [[Programming Reference:Contents|Programming Reference]] provides background information &amp;lt;br /&amp;gt;which you need in order to understand, modify, or create code that &amp;lt;br /&amp;gt;depends on the BCI2000 framework.&lt;br /&gt;
===Contributions===&lt;br /&gt;
* [[Contributions:Contents|User-Contributed BCI2000 Components and Patches]]&lt;br /&gt;
===Categories===&lt;br /&gt;
*[[:Category:Data Acquisition | Data Acquisition]]&lt;br /&gt;
*[[:Category:Signal Processing | Signal Processing]]&lt;br /&gt;
*[[Contributions:Extensions | Extensions]]&lt;br /&gt;
*[[:Category:User Application | User Application]]&lt;br /&gt;
*[[:Category:External Interfaces | External Interfaces]]&lt;br /&gt;
*[[:Category:User Interface | User Interface]]&lt;br /&gt;
*[[:Category:Video | Video Tutorials]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/td&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;td style=&amp;quot;margin:0; margin-top:10px; margin-right:10px; border-radius: 10px; background-color:#fff8dc; padding:0 1em 1em 1em; align:right;vertical-align:top;&amp;quot;&amp;gt;&lt;br /&gt;
==BCI2000 Tutorials==&lt;br /&gt;
===Setup Tutorials===&lt;br /&gt;
*[[Programming Howto:Install Prerequisites|Install Prerequisites]]&lt;br /&gt;
*[[Programming Howto:Register with BCI2000 Project|Register with the BCI2000 Project]]&lt;br /&gt;
*[[Programming Howto:Download the BCI2000 Sourcecode|Download the BCI2000 Sourcecode]]&lt;br /&gt;
*[[Programming Howto:Configure BCI2000 for Compilation|Configure BCI2000 for Compilation]]&lt;br /&gt;
*[[Programming Howto:Compile BCI2000|Compile BCI2000]]&lt;br /&gt;
===Experimental Tutorials===&lt;br /&gt;
*[[User Tutorial:Mu Rhythm BCI Tutorial|Mu Rhythm BCI Tutorial]]&lt;br /&gt;
*[[User Tutorial:P300 BCI Tutorial|P300 BCI Tutorial]]&lt;br /&gt;
*[[User Tutorial:Testing AV Playback Tutorial|Testing AV Playback Tutorial]]&lt;br /&gt;
===Programming Tutorials===&lt;br /&gt;
*[[Programming Tutorial:Implementing a Source Module|Implementing a Source Module]]&lt;br /&gt;
*[[Programming Howto:Create a custom Signal Processing Module|Implementing a Signal Processing Module]]&lt;br /&gt;
*[[Programming Tutorial:Implementing a Matlab-based Filter|Implementing a Matlab-based Filter]]&lt;br /&gt;
*[[Programming Tutorial:Implementing an Input Logger|Implementing an Input Logger]]&lt;br /&gt;
===Data Analysis Tutorials===&lt;br /&gt;
*[[User Tutorial:Data Analysis|Data Analysis with BCI2000]]&lt;br /&gt;
* Converting and Analyzing BCI2000 Data with  [[User Reference:Matlab MEX Files|Matlab MEX Files]]&lt;br /&gt;
* Analyze BCI2000 Data in Python with [https://github.com/neurotechcenter/BCI2kReader BCI2k Reader]&lt;br /&gt;
===All Tutorials: See a complete list of [[User Tutorial|BCI2000 tutorials]] here===&lt;br /&gt;
* &lt;br /&gt;
&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;margin:0; margin-right:10px; border-radius: 10px; padding:0 1em 1em 1em; background-color:#fff8dc; align:right;vertical-align:top;&amp;quot;&amp;gt;&lt;br /&gt;
==Supported Frameworks==&lt;br /&gt;
===BCI2000 Core Frameworks===&lt;br /&gt;
* [[User Reference:P3SpellerTask|P3 Speller]]&lt;br /&gt;
* [[User Reference:StimulusPresentationTask|Stimulus Presentation]] &lt;br /&gt;
* [[User Reference:CursorTask|Cursor Task]]&lt;br /&gt;
===[[Supported Frameworks|External Frameworks]]===&lt;br /&gt;
* [[User Tutorial:BCI2000Remote|BCI2000 Remote]] - includes Matlab, C++, and Python &lt;br /&gt;
* [[PsychoPy]]&lt;br /&gt;
* [[BCPy2000]]&lt;br /&gt;
&amp;lt;/td&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;td style=&amp;quot;margin:0; margin-top:10px; margin-right:10px; border-radius: 10px; padding:0 1em 1em 1em; background-color:#e3f5fc; align:right;vertical-align:top;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Additional Information==&lt;br /&gt;
* [[System Features|Features supported by BCI2000]]&lt;br /&gt;
* [https://github.com/neurotechcenter NCAN Github]&lt;br /&gt;
* [//{{SERVERNAME}}/phpbb BCI2000 Community Forum]&lt;br /&gt;
* [//{{SERVERNAME}}/tracproj/newticket Submit a Bug Report]  (make sure you log in)&lt;br /&gt;
* [[User FAQ|BCI2000 Frequently Asked Questions]]&lt;br /&gt;
* [[BCI2000 Glossary]]&amp;lt;br /&amp;gt;of terms specific to BCI2000&lt;br /&gt;
* [[BCI2000 Licensing|Licensing Information]]&lt;br /&gt;
&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table cellspacing=&amp;quot;10&amp;quot; style=&amp;quot;width:100%;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;margin:0; margin-top:10px; margin-right:10px; border-radius: 10px; border:0.5px solid #a2a2a2; padding:0 1em 1em 1em; background-color:white; align:right;vertical-align:top;&amp;quot;&amp;gt;&lt;br /&gt;
==BCI2000 Publications==&lt;br /&gt;
* [https://{{SERVERNAME}}/downloads/doc/paper.pdf G. Schalk, D.J. McFarland, T. Hinterberger, N. Birbaumer, and J.R. Wolpaw: &#039;&#039;BCI2000: A General-Purpose Brain-Computer Interface (BCI) System&#039;&#039;, IEEE Trans Biomed Eng, 51(6), June 2004.]&lt;br /&gt;
* J. Mellinger, G. Schalk: &#039;&#039;BCI2000: A General-Purpose Software Platform for BCI Research,&#039;&#039; In: G. Dornhege, J. del R. Millán, T. Hinterberger, D.J. McFarland, K.-R. Müller (eds.), &#039;&#039;Toward Brain-Computer Interfacing,&#039;&#039; MIT Press, 2007.&lt;br /&gt;
* [http://www.amazon.com/Practical-Guide-BrainComputer-Interfacing-BCI2000/dp/1849960917/ G. Schalk, J. Mellinger: &amp;quot;A Practical Guide to Brain-Computer Interfacing with BCI2000&amp;quot;, Springer, 2010.]&lt;br /&gt;
* J. Mellinger, G. Schalk: &amp;quot;Using BCI2000 in BCI Research,&amp;quot; In: B. Graimann, B. Allison, G. Pfurtscheller (eds.), &amp;quot;Brain-Computer Interfaces: Revolutionizing Human-Computer Interaction&amp;quot;, Springer, 2010.&lt;br /&gt;
&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Main_Page&amp;diff=12411</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Main_Page&amp;diff=12411"/>
		<updated>2026-05-04T15:47:54Z</updated>

		<summary type="html">&lt;p&gt;Jhill: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__ __NOEDITSECTION__&lt;br /&gt;
&amp;lt;table cellspacing=&amp;quot;10&amp;quot; class=&amp;quot;noprint&amp;quot; style=&amp;quot;float:left; margin-top:0;margin-bottom:0; text-align:right&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;border-radius: 10px; background-color:#efefef;padding: 1em 1em 1em 1em;word-spacing:1em;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;htmltag tagname=&amp;quot;form&amp;quot; name=&amp;quot;sitesearch&amp;quot; action=&amp;quot;https://www.google.com/search&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;htmltag tagname=&amp;quot;input&amp;quot; name=&amp;quot;q&amp;quot; type=&amp;quot;text&amp;quot; size=&amp;quot;40&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;htmltag tagname=&amp;quot;input&amp;quot; type=&amp;quot;submit&amp;quot; value=&amp;quot;Google site search of bci2000.org&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;htmltag tagname=&amp;quot;input&amp;quot; type=&amp;quot;hidden&amp;quot; name=&amp;quot;sitesearch&amp;quot; value=&amp;quot;bci2000.org&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;htmltag tagname=&amp;quot;input&amp;quot; type=&amp;quot;hidden&amp;quot; name=&amp;quot;ie&amp;quot; value=&amp;quot;utf-8&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;htmltag tagname=&amp;quot;input&amp;quot; type=&amp;quot;hidden&amp;quot; name=&amp;quot;oe&amp;quot; value=&amp;quot;utf-8&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/htmltag&amp;gt;&lt;br /&gt;
&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table cellspacing=&amp;quot;10&amp;quot; style=&amp;quot;width:100%;margin-top:-10px&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;margin:0; margin-top:-10px; margin-right:10px; background-color:#ededed; padding:0 1em 1em 1em; align:right; border-radius: 10px; vertical-align:top;&amp;quot;&amp;gt;&lt;br /&gt;
=&amp;lt;b&amp;gt;Download BCI2000&amp;lt;/b&amp;gt;=&lt;br /&gt;
&amp;lt;span style=&amp;quot;font-size:130%&amp;quot;&amp;gt;1. [https://www.bci2000.org/useradmin/ Create a free user account!] (Required to download BCI2000)&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;font-size:130%&amp;quot;&amp;gt;2. Download the [https://bci2000.org/downloads/bin/BCI2000Setup.exe latest release], [[BCI2000 Binaries|previous versions]], or the source code ([[Programming Howto:Building and Customizing BCI2000 |Windows]], [[Programming Howto:Non:Building and Customizing BCI2000 on Non-Windows Platforms |Non-windows]])&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/td&amp;gt; &lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table cellspacing=&amp;quot;10&amp;quot; style=&amp;quot;width:100%;margin-top:-10px&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt; &amp;lt;td style=&amp;quot;margin:0; margin-right:10px; border-radius: 10px; border:0.5px solid #a2a2a2; padding:0 1em 1em 1em; align:right;vertical-align:top;&amp;quot;&amp;gt;&lt;br /&gt;
=&amp;lt;b&amp;gt;What is BCI2000?&amp;lt;/b&amp;gt;=&lt;br /&gt;
BCI2000 is a free, open-source, general-purpose software system for brain-computer interface (BCI) research that.&lt;br /&gt;
BCI2000 includes software tools that can acquire and process data, present stimuli and feedback, and manage interaction with outside devices such as robotic arms. BCI2000 is a real-time system that can synchronize EEG and other signals with a wide variety of biosignals and input devices such as mice or eye-trackers. It has several modules to manage data importing and exporting in common file formats. BCI2000 operates on most Windows systems, and the source code can be compiled on most Windows machines. &lt;br /&gt;
&lt;br /&gt;
[[File:BCI2000 New Schematic Extra Large.gif|center|800px|BCI2000 Schematic]]&lt;br /&gt;
&lt;br /&gt;
Above shows the main framework of BCI2000, with examples for each section. Navigate to the [[User Reference:Filters|Filters page]] to learn more about the framework, or view links below for tutorials and more reference pages.&lt;br /&gt;
&amp;lt;/td&amp;gt; &amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table cellspacing=&amp;quot;10&amp;quot; style=&amp;quot;width:100%;margin-top:-10px&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;margin:0; margin-top:10px; margin-right:10px; border-radius: 10px; padding:0 1em 1em 1em; background-color:#fff8dc; align:right;vertical-align:top;&amp;quot;&amp;gt;&lt;br /&gt;
==BCI2000 for Users==&lt;br /&gt;
&lt;br /&gt;
* [//{{SERVERNAME}}/useradmin Create or modify a User Account]&lt;br /&gt;
* [[DownloadBCI2000|Download BCI2000]]&lt;br /&gt;
* [https://bci2000.org/externals/mex/mexfiles.zip Download BCI2000 Matlab MEX files]&lt;br /&gt;
&lt;br /&gt;
* Take the introductory [[User Tutorial:BCI2000 Tour|BCI2000 Tour]]&lt;br /&gt;
* Learn more through an &amp;lt;br /&amp;gt; [[Introduction_to_Adaptive_Neurotechnologies|Introduction to Adaptive Neurotechnologies]]&lt;br /&gt;
* Review the terminology in the [[BCI2000 Glossary]]&lt;br /&gt;
&amp;lt;/td&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;td style=&amp;quot;margin:0; margin-top:10px; margin-right:10px; border-radius: 10px; padding:0 1em 1em 1em; background-color:#e3f5fc; align:right;vertical-align:top;&amp;quot;&amp;gt;&lt;br /&gt;
==BCI2000 for Developers==&lt;br /&gt;
* [//{{SERVERNAME}}/useradmin Create or modify a User Account]&lt;br /&gt;
*  Download source code ([[Programming Howto:Building and Customizing BCI2000 |Windows]], [[Programming Howto:Non:Building and Customizing BCI2000 on Non-Windows Platforms |Non-windows]])&lt;br /&gt;
* [[Programming Reference:Patches|Create a patch]] to add your code to the BCI2000 svn!&lt;br /&gt;
* [[APIs|BCI2000 API Documentation]]&lt;br /&gt;
* [[Rebuild BCI2000]] - instructions for rapid prototyping!&lt;br /&gt;
&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;margin:0; margin-top:10px; margin-right:10px; border-radius: 10px;  background-color:#e3f5fc; padding:0 1em 1em 1em; align:right;vertical-align:top;&amp;quot;&amp;gt;&lt;br /&gt;
==BCI2000 References==&lt;br /&gt;
===BCI2000 Overview and Tools===&lt;br /&gt;
* The [[User Reference:Contents|User Reference Manual]] describes all details&amp;lt;br /&amp;gt;of system configuration and usage&lt;br /&gt;
===Technical References===&lt;br /&gt;
* The [[Technical Reference:Contents|Technical Reference Manual]] contains a discussion of its &amp;lt;br /&amp;gt;basic concepts, and a detailed specification of the BCI2000 standard.&lt;br /&gt;
===Programming References===&lt;br /&gt;
* The [[Programming Reference:Contents|Programming Reference]] provides background information &amp;lt;br /&amp;gt;which you need in order to understand, modify, or create code that &amp;lt;br /&amp;gt;depends on the BCI2000 framework.&lt;br /&gt;
===Contributions===&lt;br /&gt;
* [[Contributions:Contents|User-Contributed BCI2000 Components and Patches]]&lt;br /&gt;
===Categories===&lt;br /&gt;
*[[:Category:Data Acquisition | Data Acquisition]]&lt;br /&gt;
*[[:Category:Signal Processing | Signal Processing]]&lt;br /&gt;
*[[Contributions:Extensions | Extensions]]&lt;br /&gt;
*[[:Category:User Application | User Application]]&lt;br /&gt;
*[[:Category:External Interfaces | External Interfaces]]&lt;br /&gt;
*[[:Category:User Interface | User Interface]]&lt;br /&gt;
*[[:Category:Video | Video Tutorials]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/td&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;td style=&amp;quot;margin:0; margin-top:10px; margin-right:10px; border-radius: 10px; background-color:#fff8dc; padding:0 1em 1em 1em; align:right;vertical-align:top;&amp;quot;&amp;gt;&lt;br /&gt;
==BCI2000 Tutorials==&lt;br /&gt;
===Setup Tutorials===&lt;br /&gt;
*[[Programming Howto:Install Prerequisites|Install Prerequisites]]&lt;br /&gt;
*[[Programming Howto:Register with BCI2000 Project|Register with the BCI2000 Project]]&lt;br /&gt;
*[[Programming Howto:Download the BCI2000 Sourcecode|Download the BCI2000 Sourcecode]]&lt;br /&gt;
*[[Programming Howto:Configure BCI2000 for Compilation|Configure BCI2000 for Compilation]]&lt;br /&gt;
*[[Programming Howto:Compile BCI2000|Compile BCI2000]]&lt;br /&gt;
===Experimental Tutorials===&lt;br /&gt;
*[[User Tutorial:Mu Rhythm BCI Tutorial|Mu Rhythm BCI Tutorial]]&lt;br /&gt;
*[[User Tutorial:P300 BCI Tutorial|P300 BCI Tutorial]]&lt;br /&gt;
*[[User Tutorial:Testing AV Playback Tutorial|Testing AV Playback Tutorial]]&lt;br /&gt;
===Programming Tutorials===&lt;br /&gt;
*[[Programming Tutorial:Implementing a Source Module|Implementing a Source Module]]&lt;br /&gt;
*[[Programming Howto:Create a custom Signal Processing Module|Implementing a Signal Processing Module]]&lt;br /&gt;
*[[Programming Tutorial:Implementing a Matlab-based Filter|Implementing a Matlab-based Filter]]&lt;br /&gt;
*[[Programming Tutorial:Implementing an Input Logger|Implementing an Input Logger]]&lt;br /&gt;
===Data Analysis Tutorials===&lt;br /&gt;
*[[User Tutorial:Data Analysis|Data Analysis with BCI2000]]&lt;br /&gt;
* Converting and Analyzing BCI2000 Data with  [[User Reference:Matlab MEX Files|Matlab MEX Files]]&lt;br /&gt;
* Analyze BCI2000 Data in Python with [https://github.com/neurotechcenter/BCI2kReader BCI2k Reader]&lt;br /&gt;
===All Tutorials: See a complete list of [[User Tutorial|BCI2000 tutorials]] here===&lt;br /&gt;
* &lt;br /&gt;
&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;margin:0; margin-right:10px; border-radius: 10px; padding:0 1em 1em 1em; background-color:#fff8dc; align:right;vertical-align:top;&amp;quot;&amp;gt;&lt;br /&gt;
==Supported Frameworks==&lt;br /&gt;
===BCI2000 Core Frameworks===&lt;br /&gt;
* [[User Reference:P3SpellerTask|P3 Speller]]&lt;br /&gt;
* [[User Reference:StimulusPresentationTask|Stimulus Presentation]] &lt;br /&gt;
* [[User Reference:CursorTask|Cursor Task]]&lt;br /&gt;
===[[Supported Frameworks|External Frameworks]]===&lt;br /&gt;
* [[User Tutorial:BCI2000Remote|BCI2000 Remote]] - includes Matlab, C++, and Python &lt;br /&gt;
* [[PsychoPy]]&lt;br /&gt;
* [[BCPy2000]]&lt;br /&gt;
&amp;lt;/td&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;td style=&amp;quot;margin:0; margin-top:10px; margin-right:10px; border-radius: 10px; padding:0 1em 1em 1em; background-color:#e3f5fc; align:right;vertical-align:top;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Additional Information==&lt;br /&gt;
* [[System Features|Features supported by BCI2000]]&lt;br /&gt;
* [https://github.com/neurotechcenter NCAN Github]&lt;br /&gt;
* [//{{SERVERNAME}}/phpbb BCI2000 Community Forum]&lt;br /&gt;
* [//{{SERVERNAME}}/tracproj/newticket Submit a Bug Report]  (make sure you log in)&lt;br /&gt;
* [[User FAQ|BCI2000 Frequently Asked Questions]]&lt;br /&gt;
* [[BCI2000 Glossary]]&amp;lt;br /&amp;gt;of terms specific to BCI2000&lt;br /&gt;
* [[BCI2000 Licensing|Licensing Information]]&lt;br /&gt;
&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table cellspacing=&amp;quot;10&amp;quot; style=&amp;quot;width:100%;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;margin:0; margin-top:10px; margin-right:10px; border-radius: 10px; border:0.5px solid #a2a2a2; padding:0 1em 1em 1em; background-color:white; align:right;vertical-align:top;&amp;quot;&amp;gt;&lt;br /&gt;
==BCI2000 Publications==&lt;br /&gt;
* [https://{{SERVERNAME}}/downloads/doc/paper.pdf G. Schalk, D.J. McFarland, T. Hinterberger, N. Birbaumer, and J.R. Wolpaw: &#039;&#039;BCI2000: A General-Purpose Brain-Computer Interface (BCI) System&#039;&#039;, IEEE Trans Biomed Eng, 51(6), June 2004.]&lt;br /&gt;
* J. Mellinger, G. Schalk: &#039;&#039;BCI2000: A General-Purpose Software Platform for BCI Research,&#039;&#039; In: G. Dornhege, J. del R. Millán, T. Hinterberger, D.J. McFarland, K.-R. Müller (eds.), &#039;&#039;Toward Brain-Computer Interfacing,&#039;&#039; MIT Press, 2007.&lt;br /&gt;
* [http://www.amazon.com/Practical-Guide-BrainComputer-Interfacing-BCI2000/dp/1849960917/ G. Schalk, J. Mellinger: &amp;quot;A Practical Guide to Brain-Computer Interfacing with BCI2000&amp;quot;, Springer, 2010.]&lt;br /&gt;
* J. Mellinger, G. Schalk: &amp;quot;Using BCI2000 in BCI Research,&amp;quot; In: B. Graimann, B. Allison, G. Pfurtscheller (eds.), &amp;quot;Brain-Computer Interfaces: Revolutionizing Human-Computer Interaction&amp;quot;, Springer, 2010.&lt;br /&gt;
&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Contributions:SerialWidgetADC&amp;diff=12303</id>
		<title>Contributions:SerialWidgetADC</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Contributions:SerialWidgetADC&amp;diff=12303"/>
		<updated>2026-01-26T00:48:17Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* Widget Timing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Synopsis==&lt;br /&gt;
An ADC that allows signals to be acquired from programmable serial-port devices such as the Arduino, Teensy, Pico, etc.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Location==&lt;br /&gt;
http://{{SERVERNAME}}/svn/trunk/src/contrib/SignalSource/SerialWidget&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Versioning==&lt;br /&gt;
&lt;br /&gt;
===Authors===&lt;br /&gt;
Jeremy Hill (hill@neurotechcenter.org)&lt;br /&gt;
&lt;br /&gt;
===Version History===&lt;br /&gt;
* 2023-09-22: Initial public release&lt;br /&gt;
&lt;br /&gt;
===Source Code Revisions===&lt;br /&gt;
*Initial development: r7613&lt;br /&gt;
*Known to compile under: r8888&lt;br /&gt;
*Broken since: --&lt;br /&gt;
&lt;br /&gt;
==Functional Description==&lt;br /&gt;
The &#039;&#039;SerialWidgetADC&#039;&#039; filter is the key component of the &#039;&#039;SerialWidget&#039;&#039; source module, and can acquire signals from a serial-port-equipped embedded system such as an Arduino, Teensy or Pico microcontroller (hereafter referred to as a &amp;quot;widget&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
This ADC includes all the functionality of the [[Contributions:SerialInterface|SerialInterface Extension]]&lt;br /&gt;
(which allows widgets to be used alongside other source acquisition hardware, providing auxiliary input and output).&lt;br /&gt;
The difference is that the ADC allows the primary signal to be acquired from the widget as well. This provides cheap platform possibilities for realtime testing during development of BCI2000 setups (as an alternative to the SignalGenerator, SoundcardSource or FilePlayback modules) and also allows BCI2000 to be used as a development tool in microcontroller programming (when you need higher data rates, better timing stability or greater flexibility than the Arduino IDE&#039;s Serial Plotter can provide).&lt;br /&gt;
&lt;br /&gt;
Developer note: the &#039;&#039;SerialInterface&#039;&#039; Extension and the &#039;&#039;SerialWidgetADC&#039;&#039; are aware of each other, and the Extension will automatically disable itself in the presence of the ADC, so there is no conflict if the Extension is turned on in CMake during the build.&lt;br /&gt;
&lt;br /&gt;
==Parameters==&lt;br /&gt;
&lt;br /&gt;
Parameters for handling widgets are described under [[Contributions:SerialInterface]].&lt;br /&gt;
&lt;br /&gt;
As in the &#039;&#039;SerialInterface&#039;&#039; Extension,  the &amp;lt;code&amp;gt;--SerialPort&amp;lt;/code&amp;gt; parameter must be supplied on the command-line and cannot be changed without relaunching BCI2000.&lt;br /&gt;
For example, your [[User_Reference:Operator_Module_Scripting|BCI2000 script]] might contain the line:&lt;br /&gt;
  start executable SerialWidget --local --SerialPort=COM4:baud=9600,dtr=on&lt;br /&gt;
The same is true of the &amp;lt;code&amp;gt;--PublishCommand&amp;lt;/code&amp;gt; parameter, if used. &lt;br /&gt;
&lt;br /&gt;
The one departure from &#039;&#039;SerialInterface&#039;&#039; behavior is the handling of custom &#039;&#039;&#039;StartCommand&#039;&#039;&#039; and &#039;&#039;&#039;StopCommand&#039;&#039;&#039; messages. ADCs expect the signal to be delivered between runs as well as during runs.  Therefore, if a &#039;&#039;&#039;StartCommand&#039;&#039;&#039; message is specified, the ADC sends it to the widget as soon as the user presses Set Config (whereas the &#039;&#039;SerialInterface&#039;&#039; Extension would wait until the user presses Start or Resume). Similarly, if a &#039;&#039;&#039;StopCommand&#039;&#039;&#039; message is specified, the ADC only sends it immediately prior to disconnecting and reconnecting on subsequent Set Config operations, and/or when BCI2000 quits (whereas the &#039;&#039;SerialInterface&#039;&#039; Extension would send it when the user presses Suspend).&lt;br /&gt;
&lt;br /&gt;
Additional Parameters may be defined by the widget itself, if you specify a &amp;lt;code&amp;gt;--PublishCommand&amp;lt;/code&amp;gt; on the command-line and the widget is programmed to support the specified command, [[Contributions:SerialInterface#Defining_BCI2000_Parameters_and_Events_from_the_Widget|as described in the SerialInterface documentation]]. As also described there, the values of widget-defined parameters may optionally be updated by the widget when a run ends, if you specify a &#039;&#039;&#039;ParameterUpdateCommand&#039;&#039;&#039; that the widget supports.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Parameters common to all source modules (&#039;&#039;&#039;SamplingRate&#039;&#039;&#039;, &#039;&#039;&#039;SampleBlockSize&#039;&#039;&#039;, &#039;&#039;&#039;SourceCh&#039;&#039;&#039;, etc.) are described under [[User Reference:DataIOFilter]].&lt;br /&gt;
&#039;&#039;SerialWidgetADC&#039;&#039; adds only one parameter of its own:&lt;br /&gt;
&lt;br /&gt;
===SourceChPins===&lt;br /&gt;
&lt;br /&gt;
This is a list of integer values, one per channel. The widget interprets these numbers when deciding how to acquire signals. The interpretation depends entirely on the way the widget is programmed: the simplest way would be to interpret the numbers as indices of the pins from which signals should be read (for example, as arguments to &amp;lt;code&amp;gt;analogRead()&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;digitalRead()&amp;lt;/code&amp;gt; in the Arduino language). The parameter takes its name from this idea. However, a more-sophisticated widget might be programmed to do its own digital signal processing, and/or to generate artificial signals in response to external sensor inputs, and the relationship between these signals and the &#039;&#039;&#039;SourceChPins&#039;&#039;&#039; values may be arbitrary, as long as the number of channels matches the number of &#039;&#039;&#039;SourceChPins&#039;&#039;&#039; values.&lt;br /&gt;
&lt;br /&gt;
==States==&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;SerialWidgetADC&#039;&#039; does not define any State Variables or Events of its own, but can create Events as directed by the widget, [[Contributions:SerialInterface#Defining_BCI2000_Parameters_and_Events_from_the_Widget|as described in the SerialInterface documentation]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Widget Programming==&lt;br /&gt;
&lt;br /&gt;
The requirements for widget programming are somewhat more stringent than they were for compatibility with the SerialInterface Extension.&lt;br /&gt;
An example SerialWidgetADC-compatible sketch is provided in [https://bci2000.org/svn/trunk/src/contrib/SignalSource/SerialWidget/ExampleSourceSketch/ the ExampleSourceSketch subdirectory] (programs in the Arduino IDE are called &amp;quot;sketches&amp;quot; for some reason). &#039;&#039;ExampleSourceSketch.ino&#039;&#039; makes use of the [https://www.arduino.cc/reference/en/libraries/signalacquisition SignalAcquisition] and [https://www.arduino.cc/reference/en/libraries/keyhole Keyhole] libraries, which can be installed via the IDE&#039;s library manager and which makes it easy for sketches to respond to serial-port commands and to allow their variables to be read and written. This sketch is an expanded version of the &#039;&#039;TTLExampleSketch.ino&#039;&#039; provided with the SerialInterface Extension, and it handles TTL input and output in the same way; however, courtesy of the &#039;&#039;SignalAcquisition&#039;&#039; library, the sketch also fulfills the following additional requirements for SerialWidgetADC compatibility:&lt;br /&gt;
&lt;br /&gt;
* To enable signal acquisition, the sketch must support the following commands, sent over the serial port (the specific numbers are just examples, but the variable names and syntax must be supported as shown):&lt;br /&gt;
   samplesPerSecond=1000\n&lt;br /&gt;
   samplesPerBlock=40\n&lt;br /&gt;
   sourcePins=&amp;quot;26 27&amp;quot;\n&lt;br /&gt;
   &lt;br /&gt;
   // NB: in the SignalAcquisition library, the .exposeVariables() method ensures&lt;br /&gt;
   //     that your sketch supports these, if called inside a Keyhole::begin() block&lt;br /&gt;
&lt;br /&gt;
* The widget is responsible for sample timing. When the widget has acquired a complete sample-block (the specified number of signal samples from all the specified pins) it must send a sample-block header, which is either &amp;lt;code&amp;gt;\x01\x00&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;\x00\x01&amp;lt;/code&amp;gt; followed by a line-ending (&amp;lt;code&amp;gt;\n&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;\r\n&amp;lt;/code&amp;gt;). Disregarding the line-ending, the header is actually the 16-bit binary representation of the number 1 (the former version is little-endian, the latter big-endian). Based on the header, the ADC will automatically determine whether the subsequent sample data need to be endian-swapped. The header can be sent easily using the following Arduino code:&lt;br /&gt;
   const uint16_t endianMarker = 1;&lt;br /&gt;
   Serial.write( (uint8_t*)&amp;amp;endianMarker, sizeof(endianMarker) );&lt;br /&gt;
   Serial.println(); // don&#039;t forget the line-ending&lt;br /&gt;
   &lt;br /&gt;
   // NB: in the SignalAcquisition library, the .acquire() method does this for you&lt;br /&gt;
  &lt;br /&gt;
* Immediately after the sample-block header, the widget must send the raw sample data as packed 32-bit floats. The size of this payload is exactly (number of pins)*&amp;lt;code&amp;gt;samplesPerBlock&amp;lt;/code&amp;gt;*&amp;lt;code&amp;gt;sizeof(float)&amp;lt;/code&amp;gt; bytes.  All the different channels&#039; values for the first sample should be sent in the order specified by &amp;lt;code&amp;gt;sourcePins&amp;lt;/code&amp;gt;, then all the channels&#039; values for the second sample, and so on.&lt;br /&gt;
   Serial.write( (uint8_t *)data, numberOfBytes );&lt;br /&gt;
   Serial.println(); // a line-ending at this point is optional, but makes debugging easier in the Arduino IDE&#039;s Serial Monitor&lt;br /&gt;
   Serial.flush();   // important for good timing&lt;br /&gt;
   &lt;br /&gt;
   // NB: in the SignalAcquisition library, the .acquire() method does this for you&lt;br /&gt;
&lt;br /&gt;
* Between sample-blocks, the widget may send other messages provided they end with a line-ending (&amp;lt;code&amp;gt;\n&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;\r\n&amp;lt;/code&amp;gt;) and do &#039;&#039;&#039;not&#039;&#039;&#039; begin with &amp;lt;code&amp;gt;\x01\x00&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;\x00\x01&amp;lt;/code&amp;gt;.  This allows it to send the same message types that the SerialInterface Extension allows, which are:&lt;br /&gt;
** BCI2000 [[Programming_Reference:Events#Descriptor_Syntax|Event descriptor]] lines, to mark the timing of arbitrary events: BCI2000 will attempt to interpret any line that does not begin with &amp;lt;code&amp;gt;{&amp;lt;/code&amp;gt; as an Event descriptor;&lt;br /&gt;
** error messages: BCI2000 will issue a fatal error containing the text of any line it receives from the widget if that line begins with &amp;lt;code&amp;gt;{&amp;lt;/code&amp;gt; and contains the substring &amp;lt;code&amp;gt;_ERROR_&amp;lt;/code&amp;gt; (which is true of any error message sent by the Keyhole library);&lt;br /&gt;
** any other JSON output: BCI2000 will simply ignore any other line beginning with the &amp;lt;code&amp;gt;{&amp;lt;/code&amp;gt; character.&lt;br /&gt;
** (You can also use the &#039;&#039;&#039;SerialInputs&#039;&#039;&#039; parameter to recognize strings that do not necessarily have to end with &amp;lt;code&amp;gt;\r\n&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;\n&amp;lt;/code&amp;gt;,  as long as you do not include entries beginning with &amp;lt;code&amp;gt;\x01\x00&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;\x00\x01&amp;lt;/code&amp;gt; in the table.  However, there&#039;s no real advantage to this; since you have control over the widget&#039;s firmware, it is better to program it to send event descriptors as text lines.)&lt;br /&gt;
&lt;br /&gt;
==Widget Timing==&lt;br /&gt;
&lt;br /&gt;
The particular implementation in the &#039;&#039;SignalAcquisition&#039;&#039; library contains features that will help you verify and debug your widget&#039;s timing.&lt;br /&gt;
&lt;br /&gt;
#. In the Serial Monitor of the Arduino IDE, first send the commands to set the acquisition parameters the way you want them. (NB: where you see &amp;lt;code&amp;gt;\n&amp;lt;/code&amp;gt; above, do not literally type a backslash followed by an &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;: the &amp;lt;code&amp;gt;\n&amp;lt;/code&amp;gt; stands for the newline character, which the Serial Monitor will append for you when you press return.)&lt;br /&gt;
#. Then, additionally send &amp;lt;code&amp;gt;debugCommOverhead=1&amp;lt;/code&amp;gt; to enable measurement of the serial-port overhead.&lt;br /&gt;
#. Then send &amp;lt;code&amp;gt;mute=0&amp;lt;/code&amp;gt; to begin sending sample-blocks.&lt;br /&gt;
#. Send &amp;lt;code&amp;gt;mute=1;?&amp;lt;/code&amp;gt;  to stop the flow and examine variables.&lt;br /&gt;
#. Repeatedly alternate &amp;lt;code&amp;gt;mute=0&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;mute=1;?&amp;lt;/code&amp;gt; to take multiple readings.&lt;br /&gt;
&lt;br /&gt;
Verify the following:&lt;br /&gt;
&lt;br /&gt;
#. The &amp;lt;code&amp;gt;idleLoops&amp;lt;/code&amp;gt; variable should be reliably greater than 0 when queried with &amp;lt;code&amp;gt;mute=1;?&amp;lt;/code&amp;gt; . If it is 0, this indicates that your sketch may be unable to keep up with the desired sample rate. You need to reduce &amp;lt;code&amp;gt;samplesPerSecond&amp;lt;/code&amp;gt;.&lt;br /&gt;
#. The &amp;lt;code&amp;gt;debugCommOverhead&amp;lt;/code&amp;gt; variable will now contain a timing measurement indicating the number of microseconds it took to send data over the serial port for the last sample-block. This will be roughly proportional to the number of channels and the number of samples per block. It should not exceed the sample period in microseconds (&amp;lt;code&amp;gt;1e6/samplesPerSecond&amp;lt;/code&amp;gt;): if it does, your data will contain readings that were unevenly sampled in time. In that case, you should reduce &amp;lt;code&amp;gt;samplesPerSecond&amp;lt;/code&amp;gt;, reduce &amp;lt;code&amp;gt;samplesPerBlock&amp;lt;/code&amp;gt;, or reduce the number of channels in &amp;lt;code&amp;gt;sourcePins&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
You can also probe the capabilities of your system by setting &amp;lt;code&amp;gt;debugSampleInterval=1&amp;lt;/code&amp;gt;, then setting &amp;lt;code&amp;gt;samplesPerSecond&amp;lt;/code&amp;gt; too high and repeatedly querying the &amp;lt;code&amp;gt;debugSampleInterval&amp;lt;/code&amp;gt; variable. This gives you an empirical measurement of the interval between the sample before last and the last one in microseconds. (With &amp;lt;code&amp;gt;debugSampleInterval&amp;lt;/code&amp;gt; set to non-zero you can also use BCI2000 to do something similar: set the &amp;lt;code&amp;gt;SamplingRate&amp;lt;/code&amp;gt; parameter too high, and use the timing window to look at the difference between nominal and measured sample-block durations.) Remember to set &amp;lt;code&amp;gt;debugSampleInterval=0&amp;lt;/code&amp;gt; when you have finished debugging - this makes the system more responsive to, and allows more robust recovery from, transient timing hiccups (whereas prolonged tolerance of overly-long sample intervals will lead to data loss).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;NB: the use of &amp;lt;code&amp;gt;debugCommOverhead&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;debugSampleInterval&amp;lt;/code&amp;gt; assume you are working with version 1.4.0 or later of the &#039;&#039;SignalAcquisition&#039;&#039; Arduino-IDE library.&#039;&#039;&lt;br /&gt;
&#039;&#039;In earlier versions, similar functionality was available under the names &amp;lt;code&amp;gt;commOverheadMicros&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;measuredMicrosPerSample&amp;lt;/code&amp;gt; but we strongly recommend that you update your library to the latest version.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
[[User Reference:DataIOFilter]], [[Programming Reference:GenericADC Class]], [[Contributions:SerialInterface]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Filters]][[Category:Data Acquisition]]&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Contributions:SerialWidgetADC&amp;diff=12302</id>
		<title>Contributions:SerialWidgetADC</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Contributions:SerialWidgetADC&amp;diff=12302"/>
		<updated>2026-01-26T00:47:05Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* Widget Timing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Synopsis==&lt;br /&gt;
An ADC that allows signals to be acquired from programmable serial-port devices such as the Arduino, Teensy, Pico, etc.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Location==&lt;br /&gt;
http://{{SERVERNAME}}/svn/trunk/src/contrib/SignalSource/SerialWidget&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Versioning==&lt;br /&gt;
&lt;br /&gt;
===Authors===&lt;br /&gt;
Jeremy Hill (hill@neurotechcenter.org)&lt;br /&gt;
&lt;br /&gt;
===Version History===&lt;br /&gt;
* 2023-09-22: Initial public release&lt;br /&gt;
&lt;br /&gt;
===Source Code Revisions===&lt;br /&gt;
*Initial development: r7613&lt;br /&gt;
*Known to compile under: r8888&lt;br /&gt;
*Broken since: --&lt;br /&gt;
&lt;br /&gt;
==Functional Description==&lt;br /&gt;
The &#039;&#039;SerialWidgetADC&#039;&#039; filter is the key component of the &#039;&#039;SerialWidget&#039;&#039; source module, and can acquire signals from a serial-port-equipped embedded system such as an Arduino, Teensy or Pico microcontroller (hereafter referred to as a &amp;quot;widget&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
This ADC includes all the functionality of the [[Contributions:SerialInterface|SerialInterface Extension]]&lt;br /&gt;
(which allows widgets to be used alongside other source acquisition hardware, providing auxiliary input and output).&lt;br /&gt;
The difference is that the ADC allows the primary signal to be acquired from the widget as well. This provides cheap platform possibilities for realtime testing during development of BCI2000 setups (as an alternative to the SignalGenerator, SoundcardSource or FilePlayback modules) and also allows BCI2000 to be used as a development tool in microcontroller programming (when you need higher data rates, better timing stability or greater flexibility than the Arduino IDE&#039;s Serial Plotter can provide).&lt;br /&gt;
&lt;br /&gt;
Developer note: the &#039;&#039;SerialInterface&#039;&#039; Extension and the &#039;&#039;SerialWidgetADC&#039;&#039; are aware of each other, and the Extension will automatically disable itself in the presence of the ADC, so there is no conflict if the Extension is turned on in CMake during the build.&lt;br /&gt;
&lt;br /&gt;
==Parameters==&lt;br /&gt;
&lt;br /&gt;
Parameters for handling widgets are described under [[Contributions:SerialInterface]].&lt;br /&gt;
&lt;br /&gt;
As in the &#039;&#039;SerialInterface&#039;&#039; Extension,  the &amp;lt;code&amp;gt;--SerialPort&amp;lt;/code&amp;gt; parameter must be supplied on the command-line and cannot be changed without relaunching BCI2000.&lt;br /&gt;
For example, your [[User_Reference:Operator_Module_Scripting|BCI2000 script]] might contain the line:&lt;br /&gt;
  start executable SerialWidget --local --SerialPort=COM4:baud=9600,dtr=on&lt;br /&gt;
The same is true of the &amp;lt;code&amp;gt;--PublishCommand&amp;lt;/code&amp;gt; parameter, if used. &lt;br /&gt;
&lt;br /&gt;
The one departure from &#039;&#039;SerialInterface&#039;&#039; behavior is the handling of custom &#039;&#039;&#039;StartCommand&#039;&#039;&#039; and &#039;&#039;&#039;StopCommand&#039;&#039;&#039; messages. ADCs expect the signal to be delivered between runs as well as during runs.  Therefore, if a &#039;&#039;&#039;StartCommand&#039;&#039;&#039; message is specified, the ADC sends it to the widget as soon as the user presses Set Config (whereas the &#039;&#039;SerialInterface&#039;&#039; Extension would wait until the user presses Start or Resume). Similarly, if a &#039;&#039;&#039;StopCommand&#039;&#039;&#039; message is specified, the ADC only sends it immediately prior to disconnecting and reconnecting on subsequent Set Config operations, and/or when BCI2000 quits (whereas the &#039;&#039;SerialInterface&#039;&#039; Extension would send it when the user presses Suspend).&lt;br /&gt;
&lt;br /&gt;
Additional Parameters may be defined by the widget itself, if you specify a &amp;lt;code&amp;gt;--PublishCommand&amp;lt;/code&amp;gt; on the command-line and the widget is programmed to support the specified command, [[Contributions:SerialInterface#Defining_BCI2000_Parameters_and_Events_from_the_Widget|as described in the SerialInterface documentation]]. As also described there, the values of widget-defined parameters may optionally be updated by the widget when a run ends, if you specify a &#039;&#039;&#039;ParameterUpdateCommand&#039;&#039;&#039; that the widget supports.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Parameters common to all source modules (&#039;&#039;&#039;SamplingRate&#039;&#039;&#039;, &#039;&#039;&#039;SampleBlockSize&#039;&#039;&#039;, &#039;&#039;&#039;SourceCh&#039;&#039;&#039;, etc.) are described under [[User Reference:DataIOFilter]].&lt;br /&gt;
&#039;&#039;SerialWidgetADC&#039;&#039; adds only one parameter of its own:&lt;br /&gt;
&lt;br /&gt;
===SourceChPins===&lt;br /&gt;
&lt;br /&gt;
This is a list of integer values, one per channel. The widget interprets these numbers when deciding how to acquire signals. The interpretation depends entirely on the way the widget is programmed: the simplest way would be to interpret the numbers as indices of the pins from which signals should be read (for example, as arguments to &amp;lt;code&amp;gt;analogRead()&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;digitalRead()&amp;lt;/code&amp;gt; in the Arduino language). The parameter takes its name from this idea. However, a more-sophisticated widget might be programmed to do its own digital signal processing, and/or to generate artificial signals in response to external sensor inputs, and the relationship between these signals and the &#039;&#039;&#039;SourceChPins&#039;&#039;&#039; values may be arbitrary, as long as the number of channels matches the number of &#039;&#039;&#039;SourceChPins&#039;&#039;&#039; values.&lt;br /&gt;
&lt;br /&gt;
==States==&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;SerialWidgetADC&#039;&#039; does not define any State Variables or Events of its own, but can create Events as directed by the widget, [[Contributions:SerialInterface#Defining_BCI2000_Parameters_and_Events_from_the_Widget|as described in the SerialInterface documentation]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Widget Programming==&lt;br /&gt;
&lt;br /&gt;
The requirements for widget programming are somewhat more stringent than they were for compatibility with the SerialInterface Extension.&lt;br /&gt;
An example SerialWidgetADC-compatible sketch is provided in [https://bci2000.org/svn/trunk/src/contrib/SignalSource/SerialWidget/ExampleSourceSketch/ the ExampleSourceSketch subdirectory] (programs in the Arduino IDE are called &amp;quot;sketches&amp;quot; for some reason). &#039;&#039;ExampleSourceSketch.ino&#039;&#039; makes use of the [https://www.arduino.cc/reference/en/libraries/signalacquisition SignalAcquisition] and [https://www.arduino.cc/reference/en/libraries/keyhole Keyhole] libraries, which can be installed via the IDE&#039;s library manager and which makes it easy for sketches to respond to serial-port commands and to allow their variables to be read and written. This sketch is an expanded version of the &#039;&#039;TTLExampleSketch.ino&#039;&#039; provided with the SerialInterface Extension, and it handles TTL input and output in the same way; however, courtesy of the &#039;&#039;SignalAcquisition&#039;&#039; library, the sketch also fulfills the following additional requirements for SerialWidgetADC compatibility:&lt;br /&gt;
&lt;br /&gt;
* To enable signal acquisition, the sketch must support the following commands, sent over the serial port (the specific numbers are just examples, but the variable names and syntax must be supported as shown):&lt;br /&gt;
   samplesPerSecond=1000\n&lt;br /&gt;
   samplesPerBlock=40\n&lt;br /&gt;
   sourcePins=&amp;quot;26 27&amp;quot;\n&lt;br /&gt;
   &lt;br /&gt;
   // NB: in the SignalAcquisition library, the .exposeVariables() method ensures&lt;br /&gt;
   //     that your sketch supports these, if called inside a Keyhole::begin() block&lt;br /&gt;
&lt;br /&gt;
* The widget is responsible for sample timing. When the widget has acquired a complete sample-block (the specified number of signal samples from all the specified pins) it must send a sample-block header, which is either &amp;lt;code&amp;gt;\x01\x00&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;\x00\x01&amp;lt;/code&amp;gt; followed by a line-ending (&amp;lt;code&amp;gt;\n&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;\r\n&amp;lt;/code&amp;gt;). Disregarding the line-ending, the header is actually the 16-bit binary representation of the number 1 (the former version is little-endian, the latter big-endian). Based on the header, the ADC will automatically determine whether the subsequent sample data need to be endian-swapped. The header can be sent easily using the following Arduino code:&lt;br /&gt;
   const uint16_t endianMarker = 1;&lt;br /&gt;
   Serial.write( (uint8_t*)&amp;amp;endianMarker, sizeof(endianMarker) );&lt;br /&gt;
   Serial.println(); // don&#039;t forget the line-ending&lt;br /&gt;
   &lt;br /&gt;
   // NB: in the SignalAcquisition library, the .acquire() method does this for you&lt;br /&gt;
  &lt;br /&gt;
* Immediately after the sample-block header, the widget must send the raw sample data as packed 32-bit floats. The size of this payload is exactly (number of pins)*&amp;lt;code&amp;gt;samplesPerBlock&amp;lt;/code&amp;gt;*&amp;lt;code&amp;gt;sizeof(float)&amp;lt;/code&amp;gt; bytes.  All the different channels&#039; values for the first sample should be sent in the order specified by &amp;lt;code&amp;gt;sourcePins&amp;lt;/code&amp;gt;, then all the channels&#039; values for the second sample, and so on.&lt;br /&gt;
   Serial.write( (uint8_t *)data, numberOfBytes );&lt;br /&gt;
   Serial.println(); // a line-ending at this point is optional, but makes debugging easier in the Arduino IDE&#039;s Serial Monitor&lt;br /&gt;
   Serial.flush();   // important for good timing&lt;br /&gt;
   &lt;br /&gt;
   // NB: in the SignalAcquisition library, the .acquire() method does this for you&lt;br /&gt;
&lt;br /&gt;
* Between sample-blocks, the widget may send other messages provided they end with a line-ending (&amp;lt;code&amp;gt;\n&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;\r\n&amp;lt;/code&amp;gt;) and do &#039;&#039;&#039;not&#039;&#039;&#039; begin with &amp;lt;code&amp;gt;\x01\x00&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;\x00\x01&amp;lt;/code&amp;gt;.  This allows it to send the same message types that the SerialInterface Extension allows, which are:&lt;br /&gt;
** BCI2000 [[Programming_Reference:Events#Descriptor_Syntax|Event descriptor]] lines, to mark the timing of arbitrary events: BCI2000 will attempt to interpret any line that does not begin with &amp;lt;code&amp;gt;{&amp;lt;/code&amp;gt; as an Event descriptor;&lt;br /&gt;
** error messages: BCI2000 will issue a fatal error containing the text of any line it receives from the widget if that line begins with &amp;lt;code&amp;gt;{&amp;lt;/code&amp;gt; and contains the substring &amp;lt;code&amp;gt;_ERROR_&amp;lt;/code&amp;gt; (which is true of any error message sent by the Keyhole library);&lt;br /&gt;
** any other JSON output: BCI2000 will simply ignore any other line beginning with the &amp;lt;code&amp;gt;{&amp;lt;/code&amp;gt; character.&lt;br /&gt;
** (You can also use the &#039;&#039;&#039;SerialInputs&#039;&#039;&#039; parameter to recognize strings that do not necessarily have to end with &amp;lt;code&amp;gt;\r\n&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;\n&amp;lt;/code&amp;gt;,  as long as you do not include entries beginning with &amp;lt;code&amp;gt;\x01\x00&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;\x00\x01&amp;lt;/code&amp;gt; in the table.  However, there&#039;s no real advantage to this; since you have control over the widget&#039;s firmware, it is better to program it to send event descriptors as text lines.)&lt;br /&gt;
&lt;br /&gt;
==Widget Timing==&lt;br /&gt;
&lt;br /&gt;
The particular implementation in the &#039;&#039;SignalAcquisition&#039;&#039; library contains features that will help you verify and debug your widget&#039;s timing.&lt;br /&gt;
&lt;br /&gt;
#. In the Serial Monitor of the Arduino IDE, first send the commands to set the acquisition parameters the way you want them. (NB: where you see &amp;lt;code&amp;gt;\n&amp;lt;/code&amp;gt; above, do not literally type a backslash followed by an &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;: the &amp;lt;code&amp;gt;\n&amp;lt;/code&amp;gt; stands for the newline character, which the Serial Monitor will append for you when you press return.)&lt;br /&gt;
#. Then, additionally send &amp;lt;code&amp;gt;debugCommOverhead=1&amp;lt;/code&amp;gt; to enable measurement of the serial-port overhead.&lt;br /&gt;
#. Then send &amp;lt;code&amp;gt;mute=0&amp;lt;/code&amp;gt; to begin sending sample-blocks.&lt;br /&gt;
#. Send &amp;lt;code&amp;gt;mute=1;?&amp;lt;/code&amp;gt;  to stop the flow and examine variables.&lt;br /&gt;
#. Repeatedly alternate &amp;lt;code&amp;gt;mute=0&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;mute=1;?&amp;lt;/code&amp;gt; to take multiple readings.&lt;br /&gt;
&lt;br /&gt;
Verify the following:&lt;br /&gt;
&lt;br /&gt;
#. The &amp;lt;code&amp;gt;idleLoops&amp;lt;/code&amp;gt; variable should be reliably greater than 0 when queried with &amp;lt;code&amp;gt;mute=1;?&amp;lt;/code&amp;gt; . If it is 0, this indicates that your sketch may be unable to keep up with the desired sample rate. You need to reduce &amp;lt;code&amp;gt;samplesPerSecond&amp;lt;/code&amp;gt;.&lt;br /&gt;
#. The &amp;lt;code&amp;gt;debugCommOverhead&amp;lt;/code&amp;gt; variable will now contain a timing measurement indicating the number of microseconds it took to send data over the serial port for the last sample-block. This will be roughly proportional to the number of channels and the number of samples per block. It should not exceed the sample period in microseconds (&amp;lt;code&amp;gt;1e6/samplesPerSecond&amp;lt;/code&amp;gt;): if it does, your data will contain readings that were unevenly sampled in time. In that case, you should reduce &amp;lt;code&amp;gt;samplesPerSecond&amp;lt;/code&amp;gt;, reduce &amp;lt;code&amp;gt;samplesPerBlock&amp;lt;/code&amp;gt;, or reduce the number of channels in &amp;lt;code&amp;gt;sourcePins&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
You can also probe the capabilities of your system by setting &amp;lt;code&amp;gt;debugSampleInterval=1&amp;lt;/code&amp;gt;, then setting &amp;lt;code&amp;gt;samplesPerSecond&amp;lt;/code&amp;gt; too high and repeatedly querying the &amp;lt;code&amp;gt;debugSampleInterval&amp;lt;/code&amp;gt; variable. This gives you an empirical measurement of the interval between the sample before last and the last one in microseconds. (With &amp;lt;code&amp;gt;debugSampleInterval&amp;lt;/code&amp;gt; set to non-zero you can also use BCI2000 to do something similar: set the &amp;lt;code&amp;gt;SamplingRate&amp;lt;/code&amp;gt; parameter too high, and use the timing window to look at the difference between nominal and measured sample-block durations.) Remember to set &amp;lt;code&amp;gt;debugSampleInterval=0&amp;lt;/code&amp;gt; when you have finished debugging - this will the system more responsive to, and allow more robust recovery from, transient timing hiccups (continued tolerance of overly long sample intervals will lead to data loss).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;NB: the use of &amp;lt;code&amp;gt;debugCommOverhead&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;debugSampleInterval&amp;lt;/code&amp;gt; assume you are working with version 1.4.0 or later of the &#039;&#039;SignalAcquisition&#039;&#039; Arduino-IDE library.&#039;&#039;&lt;br /&gt;
&#039;&#039;In earlier versions, similar functionality was available under the names &amp;lt;code&amp;gt;commOverheadMicros&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;measuredMicrosPerSample&amp;lt;/code&amp;gt; but we strongly recommend that you update your library to the latest version.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
[[User Reference:DataIOFilter]], [[Programming Reference:GenericADC Class]], [[Contributions:SerialInterface]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Filters]][[Category:Data Acquisition]]&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Contributions:SerialWidgetADC&amp;diff=12301</id>
		<title>Contributions:SerialWidgetADC</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Contributions:SerialWidgetADC&amp;diff=12301"/>
		<updated>2026-01-26T00:35:00Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* Widget Timing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Synopsis==&lt;br /&gt;
An ADC that allows signals to be acquired from programmable serial-port devices such as the Arduino, Teensy, Pico, etc.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Location==&lt;br /&gt;
http://{{SERVERNAME}}/svn/trunk/src/contrib/SignalSource/SerialWidget&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Versioning==&lt;br /&gt;
&lt;br /&gt;
===Authors===&lt;br /&gt;
Jeremy Hill (hill@neurotechcenter.org)&lt;br /&gt;
&lt;br /&gt;
===Version History===&lt;br /&gt;
* 2023-09-22: Initial public release&lt;br /&gt;
&lt;br /&gt;
===Source Code Revisions===&lt;br /&gt;
*Initial development: r7613&lt;br /&gt;
*Known to compile under: r8888&lt;br /&gt;
*Broken since: --&lt;br /&gt;
&lt;br /&gt;
==Functional Description==&lt;br /&gt;
The &#039;&#039;SerialWidgetADC&#039;&#039; filter is the key component of the &#039;&#039;SerialWidget&#039;&#039; source module, and can acquire signals from a serial-port-equipped embedded system such as an Arduino, Teensy or Pico microcontroller (hereafter referred to as a &amp;quot;widget&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
This ADC includes all the functionality of the [[Contributions:SerialInterface|SerialInterface Extension]]&lt;br /&gt;
(which allows widgets to be used alongside other source acquisition hardware, providing auxiliary input and output).&lt;br /&gt;
The difference is that the ADC allows the primary signal to be acquired from the widget as well. This provides cheap platform possibilities for realtime testing during development of BCI2000 setups (as an alternative to the SignalGenerator, SoundcardSource or FilePlayback modules) and also allows BCI2000 to be used as a development tool in microcontroller programming (when you need higher data rates, better timing stability or greater flexibility than the Arduino IDE&#039;s Serial Plotter can provide).&lt;br /&gt;
&lt;br /&gt;
Developer note: the &#039;&#039;SerialInterface&#039;&#039; Extension and the &#039;&#039;SerialWidgetADC&#039;&#039; are aware of each other, and the Extension will automatically disable itself in the presence of the ADC, so there is no conflict if the Extension is turned on in CMake during the build.&lt;br /&gt;
&lt;br /&gt;
==Parameters==&lt;br /&gt;
&lt;br /&gt;
Parameters for handling widgets are described under [[Contributions:SerialInterface]].&lt;br /&gt;
&lt;br /&gt;
As in the &#039;&#039;SerialInterface&#039;&#039; Extension,  the &amp;lt;code&amp;gt;--SerialPort&amp;lt;/code&amp;gt; parameter must be supplied on the command-line and cannot be changed without relaunching BCI2000.&lt;br /&gt;
For example, your [[User_Reference:Operator_Module_Scripting|BCI2000 script]] might contain the line:&lt;br /&gt;
  start executable SerialWidget --local --SerialPort=COM4:baud=9600,dtr=on&lt;br /&gt;
The same is true of the &amp;lt;code&amp;gt;--PublishCommand&amp;lt;/code&amp;gt; parameter, if used. &lt;br /&gt;
&lt;br /&gt;
The one departure from &#039;&#039;SerialInterface&#039;&#039; behavior is the handling of custom &#039;&#039;&#039;StartCommand&#039;&#039;&#039; and &#039;&#039;&#039;StopCommand&#039;&#039;&#039; messages. ADCs expect the signal to be delivered between runs as well as during runs.  Therefore, if a &#039;&#039;&#039;StartCommand&#039;&#039;&#039; message is specified, the ADC sends it to the widget as soon as the user presses Set Config (whereas the &#039;&#039;SerialInterface&#039;&#039; Extension would wait until the user presses Start or Resume). Similarly, if a &#039;&#039;&#039;StopCommand&#039;&#039;&#039; message is specified, the ADC only sends it immediately prior to disconnecting and reconnecting on subsequent Set Config operations, and/or when BCI2000 quits (whereas the &#039;&#039;SerialInterface&#039;&#039; Extension would send it when the user presses Suspend).&lt;br /&gt;
&lt;br /&gt;
Additional Parameters may be defined by the widget itself, if you specify a &amp;lt;code&amp;gt;--PublishCommand&amp;lt;/code&amp;gt; on the command-line and the widget is programmed to support the specified command, [[Contributions:SerialInterface#Defining_BCI2000_Parameters_and_Events_from_the_Widget|as described in the SerialInterface documentation]]. As also described there, the values of widget-defined parameters may optionally be updated by the widget when a run ends, if you specify a &#039;&#039;&#039;ParameterUpdateCommand&#039;&#039;&#039; that the widget supports.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Parameters common to all source modules (&#039;&#039;&#039;SamplingRate&#039;&#039;&#039;, &#039;&#039;&#039;SampleBlockSize&#039;&#039;&#039;, &#039;&#039;&#039;SourceCh&#039;&#039;&#039;, etc.) are described under [[User Reference:DataIOFilter]].&lt;br /&gt;
&#039;&#039;SerialWidgetADC&#039;&#039; adds only one parameter of its own:&lt;br /&gt;
&lt;br /&gt;
===SourceChPins===&lt;br /&gt;
&lt;br /&gt;
This is a list of integer values, one per channel. The widget interprets these numbers when deciding how to acquire signals. The interpretation depends entirely on the way the widget is programmed: the simplest way would be to interpret the numbers as indices of the pins from which signals should be read (for example, as arguments to &amp;lt;code&amp;gt;analogRead()&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;digitalRead()&amp;lt;/code&amp;gt; in the Arduino language). The parameter takes its name from this idea. However, a more-sophisticated widget might be programmed to do its own digital signal processing, and/or to generate artificial signals in response to external sensor inputs, and the relationship between these signals and the &#039;&#039;&#039;SourceChPins&#039;&#039;&#039; values may be arbitrary, as long as the number of channels matches the number of &#039;&#039;&#039;SourceChPins&#039;&#039;&#039; values.&lt;br /&gt;
&lt;br /&gt;
==States==&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;SerialWidgetADC&#039;&#039; does not define any State Variables or Events of its own, but can create Events as directed by the widget, [[Contributions:SerialInterface#Defining_BCI2000_Parameters_and_Events_from_the_Widget|as described in the SerialInterface documentation]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Widget Programming==&lt;br /&gt;
&lt;br /&gt;
The requirements for widget programming are somewhat more stringent than they were for compatibility with the SerialInterface Extension.&lt;br /&gt;
An example SerialWidgetADC-compatible sketch is provided in [https://bci2000.org/svn/trunk/src/contrib/SignalSource/SerialWidget/ExampleSourceSketch/ the ExampleSourceSketch subdirectory] (programs in the Arduino IDE are called &amp;quot;sketches&amp;quot; for some reason). &#039;&#039;ExampleSourceSketch.ino&#039;&#039; makes use of the [https://www.arduino.cc/reference/en/libraries/signalacquisition SignalAcquisition] and [https://www.arduino.cc/reference/en/libraries/keyhole Keyhole] libraries, which can be installed via the IDE&#039;s library manager and which makes it easy for sketches to respond to serial-port commands and to allow their variables to be read and written. This sketch is an expanded version of the &#039;&#039;TTLExampleSketch.ino&#039;&#039; provided with the SerialInterface Extension, and it handles TTL input and output in the same way; however, courtesy of the &#039;&#039;SignalAcquisition&#039;&#039; library, the sketch also fulfills the following additional requirements for SerialWidgetADC compatibility:&lt;br /&gt;
&lt;br /&gt;
* To enable signal acquisition, the sketch must support the following commands, sent over the serial port (the specific numbers are just examples, but the variable names and syntax must be supported as shown):&lt;br /&gt;
   samplesPerSecond=1000\n&lt;br /&gt;
   samplesPerBlock=40\n&lt;br /&gt;
   sourcePins=&amp;quot;26 27&amp;quot;\n&lt;br /&gt;
   &lt;br /&gt;
   // NB: in the SignalAcquisition library, the .exposeVariables() method ensures&lt;br /&gt;
   //     that your sketch supports these, if called inside a Keyhole::begin() block&lt;br /&gt;
&lt;br /&gt;
* The widget is responsible for sample timing. When the widget has acquired a complete sample-block (the specified number of signal samples from all the specified pins) it must send a sample-block header, which is either &amp;lt;code&amp;gt;\x01\x00&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;\x00\x01&amp;lt;/code&amp;gt; followed by a line-ending (&amp;lt;code&amp;gt;\n&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;\r\n&amp;lt;/code&amp;gt;). Disregarding the line-ending, the header is actually the 16-bit binary representation of the number 1 (the former version is little-endian, the latter big-endian). Based on the header, the ADC will automatically determine whether the subsequent sample data need to be endian-swapped. The header can be sent easily using the following Arduino code:&lt;br /&gt;
   const uint16_t endianMarker = 1;&lt;br /&gt;
   Serial.write( (uint8_t*)&amp;amp;endianMarker, sizeof(endianMarker) );&lt;br /&gt;
   Serial.println(); // don&#039;t forget the line-ending&lt;br /&gt;
   &lt;br /&gt;
   // NB: in the SignalAcquisition library, the .acquire() method does this for you&lt;br /&gt;
  &lt;br /&gt;
* Immediately after the sample-block header, the widget must send the raw sample data as packed 32-bit floats. The size of this payload is exactly (number of pins)*&amp;lt;code&amp;gt;samplesPerBlock&amp;lt;/code&amp;gt;*&amp;lt;code&amp;gt;sizeof(float)&amp;lt;/code&amp;gt; bytes.  All the different channels&#039; values for the first sample should be sent in the order specified by &amp;lt;code&amp;gt;sourcePins&amp;lt;/code&amp;gt;, then all the channels&#039; values for the second sample, and so on.&lt;br /&gt;
   Serial.write( (uint8_t *)data, numberOfBytes );&lt;br /&gt;
   Serial.println(); // a line-ending at this point is optional, but makes debugging easier in the Arduino IDE&#039;s Serial Monitor&lt;br /&gt;
   Serial.flush();   // important for good timing&lt;br /&gt;
   &lt;br /&gt;
   // NB: in the SignalAcquisition library, the .acquire() method does this for you&lt;br /&gt;
&lt;br /&gt;
* Between sample-blocks, the widget may send other messages provided they end with a line-ending (&amp;lt;code&amp;gt;\n&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;\r\n&amp;lt;/code&amp;gt;) and do &#039;&#039;&#039;not&#039;&#039;&#039; begin with &amp;lt;code&amp;gt;\x01\x00&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;\x00\x01&amp;lt;/code&amp;gt;.  This allows it to send the same message types that the SerialInterface Extension allows, which are:&lt;br /&gt;
** BCI2000 [[Programming_Reference:Events#Descriptor_Syntax|Event descriptor]] lines, to mark the timing of arbitrary events: BCI2000 will attempt to interpret any line that does not begin with &amp;lt;code&amp;gt;{&amp;lt;/code&amp;gt; as an Event descriptor;&lt;br /&gt;
** error messages: BCI2000 will issue a fatal error containing the text of any line it receives from the widget if that line begins with &amp;lt;code&amp;gt;{&amp;lt;/code&amp;gt; and contains the substring &amp;lt;code&amp;gt;_ERROR_&amp;lt;/code&amp;gt; (which is true of any error message sent by the Keyhole library);&lt;br /&gt;
** any other JSON output: BCI2000 will simply ignore any other line beginning with the &amp;lt;code&amp;gt;{&amp;lt;/code&amp;gt; character.&lt;br /&gt;
** (You can also use the &#039;&#039;&#039;SerialInputs&#039;&#039;&#039; parameter to recognize strings that do not necessarily have to end with &amp;lt;code&amp;gt;\r\n&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;\n&amp;lt;/code&amp;gt;,  as long as you do not include entries beginning with &amp;lt;code&amp;gt;\x01\x00&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;\x00\x01&amp;lt;/code&amp;gt; in the table.  However, there&#039;s no real advantage to this; since you have control over the widget&#039;s firmware, it is better to program it to send event descriptors as text lines.)&lt;br /&gt;
&lt;br /&gt;
==Widget Timing==&lt;br /&gt;
&lt;br /&gt;
The particular implementation in the &#039;&#039;SignalAcquisition&#039;&#039; library contains features that will help you verify and debug your widget&#039;s timing.&lt;br /&gt;
&lt;br /&gt;
#. In the Serial Monitor of the Arduino IDE, first send the commands to set the acquisition parameters the way you want them. (NB: where you see &amp;lt;code&amp;gt;\n&amp;lt;/code&amp;gt; above, do not literally type a backslash followed by an &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;: the &amp;lt;code&amp;gt;\n&amp;lt;/code&amp;gt; stands for the newline character, which the Serial Monitor will append for you when you press return.)&lt;br /&gt;
#. Then, additionally send &amp;lt;code&amp;gt;debugCommOverhead=1&amp;lt;/code&amp;gt; to enable measurement of the serial-port overhead.&lt;br /&gt;
#. Then send &amp;lt;code&amp;gt;mute=0&amp;lt;/code&amp;gt; to begin sending sample-blocks.&lt;br /&gt;
#. Send &amp;lt;code&amp;gt;mute=1;?&amp;lt;/code&amp;gt;  to stop the flow and examine variables.&lt;br /&gt;
#. Repeatedly alternate &amp;lt;code&amp;gt;mute=0&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;mute=1;?&amp;lt;/code&amp;gt; to take multiple readings.&lt;br /&gt;
&lt;br /&gt;
Verify the following:&lt;br /&gt;
&lt;br /&gt;
#. The &amp;lt;code&amp;gt;idleLoops&amp;lt;/code&amp;gt; variable should be reliably greater than 0 when queried with &amp;lt;code&amp;gt;mute=1;?&amp;lt;/code&amp;gt; . If it is 0, this indicates that your sketch may be unable to keep up with the desired sample rate. You need to reduce &amp;lt;code&amp;gt;samplesPerSecond&amp;lt;/code&amp;gt;.&lt;br /&gt;
#. The &amp;lt;code&amp;gt;debugCommOverhead&amp;lt;/code&amp;gt; variable will now contain a timing measurement indicating the number of microseconds it took to send data over the serial port for the last sample-block. This will be roughly proportional to the number of channels and the number of samples per block. It should not exceed the sample period in microseconds (&amp;lt;code&amp;gt;1e6/samplesPerSecond&amp;lt;/code&amp;gt;): if it does, your data will contain readings that were unevenly sampled in time. In that case, you should reduce &amp;lt;code&amp;gt;samplesPerSecond&amp;lt;/code&amp;gt;, reduce &amp;lt;code&amp;gt;samplesPerBlock&amp;lt;/code&amp;gt;, or reduce the number of channels in &amp;lt;code&amp;gt;sourcePins&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
You can also probe the capabilities of your system by setting &amp;lt;code&amp;gt;debugSampleInterval=1&amp;lt;/code&amp;gt;, then setting &amp;lt;code&amp;gt;samplesPerSecond&amp;lt;/code&amp;gt; too high and repeatedly querying the &amp;lt;code&amp;gt;debugSampleInterval&amp;lt;/code&amp;gt; variable. This gives you an empirical measurement of the interval between the sample before last and the last one in microseconds. (With &amp;lt;code&amp;gt;debugSampleInterval&amp;lt;/code&amp;gt; set to non-zero you can also use BCI2000 to do something similar: set the &amp;lt;code&amp;gt;SamplingRate&amp;lt;/code&amp;gt; parameter too high, and use the timing window to look at the difference between nominal and measured sample-block durations.) Remember to set &amp;lt;code&amp;gt;debugSampleInterval=0&amp;lt;/code&amp;gt; when you have finished debugging - this will the system more responsive to, and allow more robust recovery from, transient timing hiccups (continued tolerance of overly long sample intervals will lead to data loss).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;NB: the use of &amp;lt;code&amp;gt;debugCommOverhead&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;debugSampleInterval&amp;lt;/code&amp;gt; assume you are working with version 1.4.0 or later of the &#039;&#039;SignalAcquisition&#039;&#039; Arduino-IDE library.&lt;br /&gt;
In earlier versions, similar functionality was available under the names &amp;lt;code&amp;gt;commOverheadMicros&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;measuredMicrosPerSample&amp;lt;/code&amp;gt; but we strongly recommend that you update your library to the latest version.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
[[User Reference:DataIOFilter]], [[Programming Reference:GenericADC Class]], [[Contributions:SerialInterface]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Filters]][[Category:Data Acquisition]]&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Contributions:SerialWidgetADC&amp;diff=12300</id>
		<title>Contributions:SerialWidgetADC</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Contributions:SerialWidgetADC&amp;diff=12300"/>
		<updated>2026-01-26T00:22:07Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* Widget Timing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Synopsis==&lt;br /&gt;
An ADC that allows signals to be acquired from programmable serial-port devices such as the Arduino, Teensy, Pico, etc.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Location==&lt;br /&gt;
http://{{SERVERNAME}}/svn/trunk/src/contrib/SignalSource/SerialWidget&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Versioning==&lt;br /&gt;
&lt;br /&gt;
===Authors===&lt;br /&gt;
Jeremy Hill (hill@neurotechcenter.org)&lt;br /&gt;
&lt;br /&gt;
===Version History===&lt;br /&gt;
* 2023-09-22: Initial public release&lt;br /&gt;
&lt;br /&gt;
===Source Code Revisions===&lt;br /&gt;
*Initial development: r7613&lt;br /&gt;
*Known to compile under: r8888&lt;br /&gt;
*Broken since: --&lt;br /&gt;
&lt;br /&gt;
==Functional Description==&lt;br /&gt;
The &#039;&#039;SerialWidgetADC&#039;&#039; filter is the key component of the &#039;&#039;SerialWidget&#039;&#039; source module, and can acquire signals from a serial-port-equipped embedded system such as an Arduino, Teensy or Pico microcontroller (hereafter referred to as a &amp;quot;widget&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
This ADC includes all the functionality of the [[Contributions:SerialInterface|SerialInterface Extension]]&lt;br /&gt;
(which allows widgets to be used alongside other source acquisition hardware, providing auxiliary input and output).&lt;br /&gt;
The difference is that the ADC allows the primary signal to be acquired from the widget as well. This provides cheap platform possibilities for realtime testing during development of BCI2000 setups (as an alternative to the SignalGenerator, SoundcardSource or FilePlayback modules) and also allows BCI2000 to be used as a development tool in microcontroller programming (when you need higher data rates, better timing stability or greater flexibility than the Arduino IDE&#039;s Serial Plotter can provide).&lt;br /&gt;
&lt;br /&gt;
Developer note: the &#039;&#039;SerialInterface&#039;&#039; Extension and the &#039;&#039;SerialWidgetADC&#039;&#039; are aware of each other, and the Extension will automatically disable itself in the presence of the ADC, so there is no conflict if the Extension is turned on in CMake during the build.&lt;br /&gt;
&lt;br /&gt;
==Parameters==&lt;br /&gt;
&lt;br /&gt;
Parameters for handling widgets are described under [[Contributions:SerialInterface]].&lt;br /&gt;
&lt;br /&gt;
As in the &#039;&#039;SerialInterface&#039;&#039; Extension,  the &amp;lt;code&amp;gt;--SerialPort&amp;lt;/code&amp;gt; parameter must be supplied on the command-line and cannot be changed without relaunching BCI2000.&lt;br /&gt;
For example, your [[User_Reference:Operator_Module_Scripting|BCI2000 script]] might contain the line:&lt;br /&gt;
  start executable SerialWidget --local --SerialPort=COM4:baud=9600,dtr=on&lt;br /&gt;
The same is true of the &amp;lt;code&amp;gt;--PublishCommand&amp;lt;/code&amp;gt; parameter, if used. &lt;br /&gt;
&lt;br /&gt;
The one departure from &#039;&#039;SerialInterface&#039;&#039; behavior is the handling of custom &#039;&#039;&#039;StartCommand&#039;&#039;&#039; and &#039;&#039;&#039;StopCommand&#039;&#039;&#039; messages. ADCs expect the signal to be delivered between runs as well as during runs.  Therefore, if a &#039;&#039;&#039;StartCommand&#039;&#039;&#039; message is specified, the ADC sends it to the widget as soon as the user presses Set Config (whereas the &#039;&#039;SerialInterface&#039;&#039; Extension would wait until the user presses Start or Resume). Similarly, if a &#039;&#039;&#039;StopCommand&#039;&#039;&#039; message is specified, the ADC only sends it immediately prior to disconnecting and reconnecting on subsequent Set Config operations, and/or when BCI2000 quits (whereas the &#039;&#039;SerialInterface&#039;&#039; Extension would send it when the user presses Suspend).&lt;br /&gt;
&lt;br /&gt;
Additional Parameters may be defined by the widget itself, if you specify a &amp;lt;code&amp;gt;--PublishCommand&amp;lt;/code&amp;gt; on the command-line and the widget is programmed to support the specified command, [[Contributions:SerialInterface#Defining_BCI2000_Parameters_and_Events_from_the_Widget|as described in the SerialInterface documentation]]. As also described there, the values of widget-defined parameters may optionally be updated by the widget when a run ends, if you specify a &#039;&#039;&#039;ParameterUpdateCommand&#039;&#039;&#039; that the widget supports.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Parameters common to all source modules (&#039;&#039;&#039;SamplingRate&#039;&#039;&#039;, &#039;&#039;&#039;SampleBlockSize&#039;&#039;&#039;, &#039;&#039;&#039;SourceCh&#039;&#039;&#039;, etc.) are described under [[User Reference:DataIOFilter]].&lt;br /&gt;
&#039;&#039;SerialWidgetADC&#039;&#039; adds only one parameter of its own:&lt;br /&gt;
&lt;br /&gt;
===SourceChPins===&lt;br /&gt;
&lt;br /&gt;
This is a list of integer values, one per channel. The widget interprets these numbers when deciding how to acquire signals. The interpretation depends entirely on the way the widget is programmed: the simplest way would be to interpret the numbers as indices of the pins from which signals should be read (for example, as arguments to &amp;lt;code&amp;gt;analogRead()&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;digitalRead()&amp;lt;/code&amp;gt; in the Arduino language). The parameter takes its name from this idea. However, a more-sophisticated widget might be programmed to do its own digital signal processing, and/or to generate artificial signals in response to external sensor inputs, and the relationship between these signals and the &#039;&#039;&#039;SourceChPins&#039;&#039;&#039; values may be arbitrary, as long as the number of channels matches the number of &#039;&#039;&#039;SourceChPins&#039;&#039;&#039; values.&lt;br /&gt;
&lt;br /&gt;
==States==&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;SerialWidgetADC&#039;&#039; does not define any State Variables or Events of its own, but can create Events as directed by the widget, [[Contributions:SerialInterface#Defining_BCI2000_Parameters_and_Events_from_the_Widget|as described in the SerialInterface documentation]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Widget Programming==&lt;br /&gt;
&lt;br /&gt;
The requirements for widget programming are somewhat more stringent than they were for compatibility with the SerialInterface Extension.&lt;br /&gt;
An example SerialWidgetADC-compatible sketch is provided in [https://bci2000.org/svn/trunk/src/contrib/SignalSource/SerialWidget/ExampleSourceSketch/ the ExampleSourceSketch subdirectory] (programs in the Arduino IDE are called &amp;quot;sketches&amp;quot; for some reason). &#039;&#039;ExampleSourceSketch.ino&#039;&#039; makes use of the [https://www.arduino.cc/reference/en/libraries/signalacquisition SignalAcquisition] and [https://www.arduino.cc/reference/en/libraries/keyhole Keyhole] libraries, which can be installed via the IDE&#039;s library manager and which makes it easy for sketches to respond to serial-port commands and to allow their variables to be read and written. This sketch is an expanded version of the &#039;&#039;TTLExampleSketch.ino&#039;&#039; provided with the SerialInterface Extension, and it handles TTL input and output in the same way; however, courtesy of the &#039;&#039;SignalAcquisition&#039;&#039; library, the sketch also fulfills the following additional requirements for SerialWidgetADC compatibility:&lt;br /&gt;
&lt;br /&gt;
* To enable signal acquisition, the sketch must support the following commands, sent over the serial port (the specific numbers are just examples, but the variable names and syntax must be supported as shown):&lt;br /&gt;
   samplesPerSecond=1000\n&lt;br /&gt;
   samplesPerBlock=40\n&lt;br /&gt;
   sourcePins=&amp;quot;26 27&amp;quot;\n&lt;br /&gt;
   &lt;br /&gt;
   // NB: in the SignalAcquisition library, the .exposeVariables() method ensures&lt;br /&gt;
   //     that your sketch supports these, if called inside a Keyhole::begin() block&lt;br /&gt;
&lt;br /&gt;
* The widget is responsible for sample timing. When the widget has acquired a complete sample-block (the specified number of signal samples from all the specified pins) it must send a sample-block header, which is either &amp;lt;code&amp;gt;\x01\x00&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;\x00\x01&amp;lt;/code&amp;gt; followed by a line-ending (&amp;lt;code&amp;gt;\n&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;\r\n&amp;lt;/code&amp;gt;). Disregarding the line-ending, the header is actually the 16-bit binary representation of the number 1 (the former version is little-endian, the latter big-endian). Based on the header, the ADC will automatically determine whether the subsequent sample data need to be endian-swapped. The header can be sent easily using the following Arduino code:&lt;br /&gt;
   const uint16_t endianMarker = 1;&lt;br /&gt;
   Serial.write( (uint8_t*)&amp;amp;endianMarker, sizeof(endianMarker) );&lt;br /&gt;
   Serial.println(); // don&#039;t forget the line-ending&lt;br /&gt;
   &lt;br /&gt;
   // NB: in the SignalAcquisition library, the .acquire() method does this for you&lt;br /&gt;
  &lt;br /&gt;
* Immediately after the sample-block header, the widget must send the raw sample data as packed 32-bit floats. The size of this payload is exactly (number of pins)*&amp;lt;code&amp;gt;samplesPerBlock&amp;lt;/code&amp;gt;*&amp;lt;code&amp;gt;sizeof(float)&amp;lt;/code&amp;gt; bytes.  All the different channels&#039; values for the first sample should be sent in the order specified by &amp;lt;code&amp;gt;sourcePins&amp;lt;/code&amp;gt;, then all the channels&#039; values for the second sample, and so on.&lt;br /&gt;
   Serial.write( (uint8_t *)data, numberOfBytes );&lt;br /&gt;
   Serial.println(); // a line-ending at this point is optional, but makes debugging easier in the Arduino IDE&#039;s Serial Monitor&lt;br /&gt;
   Serial.flush();   // important for good timing&lt;br /&gt;
   &lt;br /&gt;
   // NB: in the SignalAcquisition library, the .acquire() method does this for you&lt;br /&gt;
&lt;br /&gt;
* Between sample-blocks, the widget may send other messages provided they end with a line-ending (&amp;lt;code&amp;gt;\n&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;\r\n&amp;lt;/code&amp;gt;) and do &#039;&#039;&#039;not&#039;&#039;&#039; begin with &amp;lt;code&amp;gt;\x01\x00&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;\x00\x01&amp;lt;/code&amp;gt;.  This allows it to send the same message types that the SerialInterface Extension allows, which are:&lt;br /&gt;
** BCI2000 [[Programming_Reference:Events#Descriptor_Syntax|Event descriptor]] lines, to mark the timing of arbitrary events: BCI2000 will attempt to interpret any line that does not begin with &amp;lt;code&amp;gt;{&amp;lt;/code&amp;gt; as an Event descriptor;&lt;br /&gt;
** error messages: BCI2000 will issue a fatal error containing the text of any line it receives from the widget if that line begins with &amp;lt;code&amp;gt;{&amp;lt;/code&amp;gt; and contains the substring &amp;lt;code&amp;gt;_ERROR_&amp;lt;/code&amp;gt; (which is true of any error message sent by the Keyhole library);&lt;br /&gt;
** any other JSON output: BCI2000 will simply ignore any other line beginning with the &amp;lt;code&amp;gt;{&amp;lt;/code&amp;gt; character.&lt;br /&gt;
** (You can also use the &#039;&#039;&#039;SerialInputs&#039;&#039;&#039; parameter to recognize strings that do not necessarily have to end with &amp;lt;code&amp;gt;\r\n&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;\n&amp;lt;/code&amp;gt;,  as long as you do not include entries beginning with &amp;lt;code&amp;gt;\x01\x00&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;\x00\x01&amp;lt;/code&amp;gt; in the table.  However, there&#039;s no real advantage to this; since you have control over the widget&#039;s firmware, it is better to program it to send event descriptors as text lines.)&lt;br /&gt;
&lt;br /&gt;
==Widget Timing==&lt;br /&gt;
&lt;br /&gt;
The particular implementation in the &#039;&#039;SignalAcquisition&#039;&#039; library contains features that will help you verify and debug your widget&#039;s timing.&lt;br /&gt;
&lt;br /&gt;
#. In the Serial Monitor of the Arduino IDE, first send the commands to set the acquisition parameters the way you want them. (NB: where you see &amp;lt;code&amp;gt;\n&amp;lt;/code&amp;gt; above, do not literally type a backslash followed by an &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;: the &amp;lt;code&amp;gt;\n&amp;lt;/code&amp;gt; stands for the newline character, which the Serial Monitor will append for you when you press return.)&lt;br /&gt;
#. Then, additionally send &amp;lt;code&amp;gt;debugCommOverhead=1&amp;lt;/code&amp;gt; to enable measurement of the serial-port overhead.&lt;br /&gt;
#. Then send &amp;lt;code&amp;gt;mute=0&amp;lt;/code&amp;gt; to begin sending sample-blocks.&lt;br /&gt;
#. Send &amp;lt;code&amp;gt;mute=1;?&amp;lt;/code&amp;gt;  to stop the flow and examine variables.&lt;br /&gt;
#. Repeatedly alternate &amp;lt;code&amp;gt;mute=0&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;mute=1;?&amp;lt;/code&amp;gt; to take multiple readings.&lt;br /&gt;
&lt;br /&gt;
Verify the following:&lt;br /&gt;
&lt;br /&gt;
#. The &amp;lt;code&amp;gt;idleLoops&amp;lt;/code&amp;gt; variable should be reliably greater than 0 when queried with &amp;lt;code&amp;gt;mute=1;?&amp;lt;/code&amp;gt; . If it is 0, this indicates that your sketch may be unable to keep up with the desired sample rate. You need to reduce &amp;lt;code&amp;gt;samplesPerSecond&amp;lt;/code&amp;gt;.&lt;br /&gt;
#. The &amp;lt;code&amp;gt;debugCommOverhead&amp;lt;/code&amp;gt; variable will now contain a timing measurement indicating the number of microseconds it took to send data over the serial port for the last sample-block. This will be roughly proportional to the number of channels and the number of samples per block. It should not exceed the sample period in microseconds (&amp;lt;code&amp;gt;1e6/samplesPerSecond&amp;lt;/code&amp;gt;): if it does, your data will contain readings that were unevenly sampled in time. In that case, you should reduce &amp;lt;code&amp;gt;samplesPerSecond&amp;lt;/code&amp;gt;, reduce &amp;lt;code&amp;gt;samplesPerBlock&amp;lt;/code&amp;gt;, or reduce the number of channels in &amp;lt;code&amp;gt;sourcePins&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
As of version 1.4.0 of the &#039;&#039;SignalAcquisition&#039;&#039; library, you can also probe the capabilities of your system by setting &amp;lt;code&amp;gt;debugSampleInterval=1&amp;lt;/code&amp;gt;, then setting &amp;lt;code&amp;gt;samplesPerSecond&amp;lt;/code&amp;gt; too high and repeatedly querying the &amp;lt;code&amp;gt;debugSampleInterval&amp;lt;/code&amp;gt; variable. This gives you an empirical measurement of the interval between the sample before last and the last one in microseconds. (With &amp;lt;code&amp;gt;debugSampleInterval&amp;lt;/code&amp;gt; set to non-zero you can also use BCI2000 to do something similar: set the &amp;lt;code&amp;gt;SamplingRate&amp;lt;/code&amp;gt; parameter too high, and use the timing window to look at the difference between nominal and measured sample-block durations.) Remember to set &amp;lt;code&amp;gt;debugSampleInterval=0&amp;lt;/code&amp;gt; when you have finished debugging - this will the system more responsive to, and allow more robust recovery from, transient timing hiccups (continued tolerance of overly long sample intervals will lead to data loss).&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
[[User Reference:DataIOFilter]], [[Programming Reference:GenericADC Class]], [[Contributions:SerialInterface]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Filters]][[Category:Data Acquisition]]&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12299</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12299"/>
		<updated>2026-01-26T00:12:54Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* CUSTOM DIALOG ... */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
__FORCETOC__&lt;br /&gt;
&lt;br /&gt;
===CHOOSE ...===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CHOOSE&amp;lt;/code&amp;gt; family of commands prompt the user to specify file or directory paths, via the Qt graphical user interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILE&amp;lt;/code&amp;gt;  (or equivalently &amp;lt;code&amp;gt;CHOOSE FILE&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CHOOSE INPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select a single existing file, and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILES&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE FILES&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select one or more existing files, and prints the resulting file paths one per line (&amp;lt;code&amp;gt;FOR ... IN ...&amp;lt;/code&amp;gt; can iterate over these).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE OUTPUT FILE&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE OUTPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists) and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;&lt;br /&gt;
: Prompts the user to specify a directory, and prints the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
If the user cancels the dialog, the commands print nothing.&lt;br /&gt;
&lt;br /&gt;
The commands may be followed by one or more of the following optional clauses (they must appear in this order):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[OF] TYPE[S] &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This limits the view (via a drop-down file-type selector) to files that have the specified extension(s). This clause cannot be used with &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;.  Instead of a file extension (starting with a dot) you can alternatively specify a glob pattern (containing a star). You can include &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt; (or equivalently &amp;lt;code&amp;gt;*.*&amp;lt;/code&amp;gt;) in the list if you want to give the user the option of overriding the limitation.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[STARTING] AT &amp;lt;dir&amp;gt;&amp;lt;/code&amp;gt; (equivalently you can say &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;FROM&amp;lt;/code&amp;gt; if it reads better)&lt;br /&gt;
: This specifies where the dialog&#039;s file-system navigation should start (by default, it will start in the current working directory).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[WITH] PROMPT &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This specifies the text prompt at the top of the dialog.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
choose file of type .dat from ../data/samplefiles with prompt &amp;quot;Choose a data file for playback:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose output file of type .prm in ../parms with prompt &amp;quot;Save parameters as...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose directory starting at ../data with prompt &amp;quot;Select a subject directory:&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===CUSTOM DIALOG ...===&lt;br /&gt;
&lt;br /&gt;
This command assembles a flexibly customizable modal dialog for communicating with the user. The command returns (prints) a string denoting which button the user pressed to complete the dialog, and as a side effect it may set any environment variables that the command specifies.  If the user cancels the dialog, the command does nothing (prints nothing, does not change any environment variables).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command can be followed by as many clauses as you like. The main types of clause are &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog, in the order you provide. Possible clauses are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Each message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule. Simplest example: &amp;lt;pre&amp;gt;custom dialog message &amp;quot;Hello world!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;] [CATALOG &amp;lt;listVariableName&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. If you supply a &amp;lt;code&amp;gt;CATALOG&amp;lt;/code&amp;gt; subclause, the variable name will be added to a newline-delimited sequence of names stored in another environment variable, designated by &amp;lt;code&amp;gt;&amp;lt;listVariableName&amp;gt;&amp;lt;/code&amp;gt; - this can be useful for later iteration (see below).   A simple &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;] [CATALOG &amp;lt;listVariableName&amp;gt;]&amp;lt;/code&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used, in conjunction with an empty first/default option, to force the user to make an explicit selection, as in the following example (note the leading &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt; character inside the braces): &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, will be the one that gets highlighted by default and bound to the enter/return keystroke. If you do not specify a default, then &amp;quot;Ok&amp;quot; will be assumed to be the default button. If the designated default does not appear in the list of buttons, the buttons will all have equal status with no return-keystroke binding. The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke, and pressing this button is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).  For most purposes, you will probably not need to override the button configuration explicitly. In dialogs without &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are simply displaying messages to the user), the &amp;lt;code&amp;gt;BUTTONS {Ok} DEFAULT Ok&amp;lt;/code&amp;gt; configuration is assumed. In dialogs with one or more &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are asking the user for information), the &amp;lt;code&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel&amp;lt;/code&amp;gt; configuration is assumed.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TITLE &amp;lt;text&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This overrides the default dialog title &amp;quot;BCI2000&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;SPACING &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical spacing between successive &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; elements.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;WIDTH &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;HEIGHT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum height of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;LEFT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the horizontal coordinate of the dialog&#039;s left edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TOP &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical coordinate of the dialog&#039;s top edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CACHEFILE &amp;lt;FILENAME&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Specifying a cache file allows dialog contents to be made persistent across sessions. If the specified file already exists when the dialog is invoked, it will get run via &amp;lt;code&amp;gt;EXECUTE SCRIPT&amp;lt;/code&amp;gt;; if this sets any of the dialog&#039;s environment variables, then these new values override the &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; values for the corresponding text fields and drop-down menus. But you do not need to initialize the specified file manually—if it does not exist, nothing is loaded. When the dialog is successfully completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button), &amp;lt;code&amp;gt;WRITE ENVIRONMENT&amp;lt;/code&amp;gt; is automatically called to write the corresponding &amp;lt;code&amp;gt;SET ENVIRONMENT&amp;lt;/code&amp;gt; statements to the specified file. So, when the same dialog is invoked next time around, these settings will be loaded: the user will see whatever settings they entered/chose this time.  Example: &amp;lt;pre&amp;gt;custom dialog  cachefile vars.bci  var subjectName &amp;quot;Subject ID:&amp;quot; {} default Nobody minimum 1 &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Integrated &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; example====&lt;br /&gt;
&lt;br /&gt;
The following partial listing illustrates one way &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; might be used to implement a simplified launcher GUI, for a hypothetical auditory BCI experiment.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# [initialize system]&lt;br /&gt;
# [start up modules]&lt;br /&gt;
# [load baseline parameters for this BCI]&lt;br /&gt;
&lt;br /&gt;
set environment launcherAction ${&lt;br /&gt;
    custom dialog &lt;br /&gt;
        title &amp;quot;Auditory BCI Launcher&amp;quot; &lt;br /&gt;
        cachefile &amp;quot;${parent directory $0}/launcherDialogVars.bci&amp;quot;&lt;br /&gt;
        var subjectName &amp;quot;Subject ID:&amp;quot;         {}    default &amp;quot;$subjectName&amp;quot; minimum 1&lt;br /&gt;
        var runType     &amp;quot;Run Type:&amp;quot;           {Calibration|Free Selection}&lt;br /&gt;
        var condition   &amp;quot;Stimulus Condition:&amp;quot; {SlowStimuli.prm|FastStimuli.prm}&lt;br /&gt;
        message &amp;quot;NB: each condition should be calibrated separately.&amp;quot; &lt;br /&gt;
        buttons {Quit|Launch} default Launch escape Quit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if [ $launcherAction == &amp;quot;&amp;quot; ]&lt;br /&gt;
    quit&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if [ $runType == Calibration ]&lt;br /&gt;
    load parameterfile ../parms/calib.prm       # let&#039;s assume you have created this&lt;br /&gt;
else&lt;br /&gt;
    load parameterfile ../parms/free.prm        # and this&lt;br /&gt;
end&lt;br /&gt;
load parameterfile ../parms/$stimulusCondition  # and these&lt;br /&gt;
set parameter SubjectName $subjectName&lt;br /&gt;
setconfig&lt;br /&gt;
show window   # unless you have some other remote-control mechanism for suspending/resuming runs&lt;br /&gt;
set state Running 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The resulting dialog looks like this:&lt;br /&gt;
&lt;br /&gt;
[[File:CustomDialogExample.png]]&lt;br /&gt;
&lt;br /&gt;
====Example of &amp;lt;code&amp;gt;CATALOG&amp;lt;/code&amp;gt; usage====&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CATALOG&amp;lt;/code&amp;gt; option allows you to keep track of one or more lists of variable names. It helps to cut down on boilerplate repetition in certain common patterns. Here is an example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Create some new parameters&lt;br /&gt;
add parameter Application:Custom%20Stimuli float MinStimulusGap= 100ms 100ms 0 % // minimum gap to use in custom stimulus generation&lt;br /&gt;
add parameter Application:Custom%20Stimuli float MaxStimulusGap= 400ms 400ms 0 % // maximum gap to use in custom stimulus generation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# In the dialog, some entries will be environment variables with exactly&lt;br /&gt;
# the same names as parameters - let&#039;s catalog these&lt;br /&gt;
if [ ${&lt;br /&gt;
        custom dialog&lt;br /&gt;
            var SubjectName     &amp;quot;Subject:&amp;quot;     {}  minimum 1                default &amp;quot;Nobody&amp;quot; catalog DialogParams&lt;br /&gt;
            var MaxStimulusGap  &amp;quot;Minimum Gap:&amp;quot; {0ms|50ms|100ms|200ms|400ms} default &amp;quot;100ms&amp;quot;  catalog DialogParams &lt;br /&gt;
            var MinStimulusGap  &amp;quot;Maximum Gap:&amp;quot; {0ms|50ms|100ms|200ms|400ms} default &amp;quot;400ms&amp;quot;  catalog DialogParams &lt;br /&gt;
            var RunType         &amp;quot;Run Type:&amp;quot;    {Calibration.prm|FreeSpelling.prm}&lt;br /&gt;
            &lt;br /&gt;
            cachefile &amp;quot;${parent directory $0}/launcherDialogVars.bci&amp;quot;&lt;br /&gt;
            &lt;br /&gt;
    } == &amp;quot;&amp;quot; ]; quit; end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ...&lt;br /&gt;
&lt;br /&gt;
# The catalog saves us from having to hard-code a list of the new parameter names a third time:&lt;br /&gt;
for var in $DialogParams        &lt;br /&gt;
    set parameter $var ${$var}&lt;br /&gt;
    # We chose the environment variable names to be the same as the corresponding parameter names.&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# This dialog variable is handled differently, so we did not catalog it with the others:&lt;br /&gt;
load parameterfile $RunType&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notes:  In the example above, we have used just one catalog variable, &amp;lt;code&amp;gt;DialogParams&amp;lt;/code&amp;gt;, but you are free to use more than one if you want to assemble separate lists of variables for different purposes.  The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command clears each catalog variable the first time it uses it (so, you can run the example above multiple times, and &amp;lt;code&amp;gt;DialogParams&amp;lt;/code&amp;gt; will still only contain one copy of each name).  Catalog variables get cleared and (re-)filled regardless of whether the dialog is accepted or cancelled.&lt;br /&gt;
&lt;br /&gt;
====Using &amp;lt;code&amp;gt;HIDDEN&amp;lt;/code&amp;gt; (a.k.a. &amp;lt;code&amp;gt;visible=false&amp;lt;/code&amp;gt;) and &amp;lt;code&amp;gt;FIXED&amp;lt;/code&amp;gt; (a.k.a. &amp;lt;code&amp;gt;fixed=true&amp;lt;/code&amp;gt;) to make a &amp;quot;wizard&amp;quot;====&lt;br /&gt;
&lt;br /&gt;
Each &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; entry may also have a modifier that overrides its visibility and whether the user can actually change it.&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;code&amp;gt;HIDDEN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;INVISIBLE&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;visible=false&amp;lt;/code&amp;gt; to hide a particular &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; from the user&#039;s view (but it will still set its environment variable if the user accepts the dialog).   The opposite, &amp;lt;code&amp;gt;VISIBLE&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;visible=true&amp;lt;/code&amp;gt;, makes the &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; visible in the GUI (which is the default behavior anyway).&lt;br /&gt;
* Use &amp;lt;code&amp;gt;FIXED&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;fixed=true&amp;lt;/code&amp;gt; to display the &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt;&#039;s label and value but without giving the user the chance to change it (and it will still set its environment variable if the user accepts the dialog).  The opposite, &amp;lt;code&amp;gt;fixed=false&amp;lt;/code&amp;gt;, makes the &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; adjustable (which is the default behavior anyway).&lt;br /&gt;
&lt;br /&gt;
The ability to make certain variables fixed or hidden, while still including them in the GUI, allows the de-facto construction of multi-stage &amp;quot;wizards&amp;quot; using repeated calls to &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt;. The following example allows the operator to configure the task as &amp;quot;active&amp;quot; (which then makes a certain subset of parameters visible for configuration in the second stage) or &amp;quot;passive&amp;quot; (associated with a different subset of parameters).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# &amp;quot;wizard&amp;quot; example leveraging `visible=false` and `fixed=true` modifiers&lt;br /&gt;
&lt;br /&gt;
add parameter Application:Robot string TaskVariant=             Active     %   %      % // None or Passive or Active&lt;br /&gt;
add parameter Application:Robot float  ActivePulseDuration=     100ms      %  50ms    % // &lt;br /&gt;
add parameter Application:Robot float  ActivePulseISI=          100ms      %  10ms    % // &lt;br /&gt;
add parameter Application:Robot float  PassiveStandardDuration= 100ms      %  50ms    % // &lt;br /&gt;
add parameter Application:Robot float  PassiveDurationDelta=    100ms      %  10ms    % // &lt;br /&gt;
&lt;br /&gt;
wizardStage := 1&lt;br /&gt;
set variable response &amp;quot;-&amp;quot;&lt;br /&gt;
while [ $response != Launch ] &amp;amp;&amp;amp; [ $response != &amp;quot;&amp;quot; ] # NB: QUIT will not succeed if placed inside the WHILE loop, and there is no BREAK&lt;br /&gt;
	if [ $wizardStage == 1 ]&lt;br /&gt;
		set environment TaskVariant &amp;quot;&amp;quot;&lt;br /&gt;
		set variable buttons {cancel|Next}&lt;br /&gt;
		set variable defaultButton Next&lt;br /&gt;
	elseif [ $wizardStage == 2 ]&lt;br /&gt;
		set variable buttons {cancel|Previous|Launch}&lt;br /&gt;
		set variable defaultButton Launch&lt;br /&gt;
	end&lt;br /&gt;
	set variable response ${&lt;br /&gt;
		custom dialog&lt;br /&gt;
			var SUBJECTNAME              &amp;quot;Subject:&amp;quot;                    {}                                                       &lt;br /&gt;
				default &amp;quot;Nobody&amp;quot;  minimum 1                        &lt;br /&gt;
			var TaskVariant              &amp;quot;Task Variant:&amp;quot;               {None|Passive|Active}                                    &lt;br /&gt;
				default &amp;quot;Active&amp;quot;  minimum 1   catalog DialogParams fixed=${[ $wizardStage != 1 ]}&lt;br /&gt;
			var PassiveStandardDuration  &amp;quot;Passive Standard Duration:&amp;quot;  {50ms|100ms|150ms|200ms|250ms}                           &lt;br /&gt;
				default &amp;quot;100ms&amp;quot;   minimum 1   catalog DialogParams visible=${[ $TaskVariant == &amp;quot;Passive&amp;quot; ]}&lt;br /&gt;
			var PassiveDurationDelta     &amp;quot;Passive Duration Delta:&amp;quot;     {0ms|10ms|20ms|30ms|40ms|50ms|60ms|70ms|80ms|90ms|100ms} &lt;br /&gt;
				default &amp;quot;100ms&amp;quot;   minimum 1   catalog DialogParams visible=${[ $TaskVariant == &amp;quot;Passive&amp;quot; ]}&lt;br /&gt;
			var ActivePulseDuration      &amp;quot;Active Pulse Duration:&amp;quot;      {50ms|100ms|150ms|200ms|250ms}                           &lt;br /&gt;
				default &amp;quot;100ms&amp;quot;   minimum 1   catalog DialogParams visible=${[ $TaskVariant == &amp;quot;Active&amp;quot;  ]}&lt;br /&gt;
			var ActivePulseISI           &amp;quot;Active Pulse ISI:&amp;quot;           {0ms|10ms|20ms|30ms|40ms|50ms|60ms|70ms|80ms|90ms|100ms} &lt;br /&gt;
				default &amp;quot;100ms&amp;quot;   minimum 1   catalog DialogParams visible=${[ $TaskVariant == &amp;quot;Active&amp;quot;  ]}&lt;br /&gt;
			message &amp;quot;(no task-specific parameters)&amp;quot; visible=${[ $task == None ]}&lt;br /&gt;
			top 200&lt;br /&gt;
			width 400&lt;br /&gt;
		cachefile &amp;quot;${parent directory $0}/launcherDialogVars.bci&amp;quot;&lt;br /&gt;
		buttons $buttons default $defaultButton escape cancel&lt;br /&gt;
	}&lt;br /&gt;
	if [ $response == &amp;quot;Previous&amp;quot; ]; wizardStage := wizardStage - 1; end&lt;br /&gt;
	if [ $response == &amp;quot;Next&amp;quot;     ]; wizardStage := wizardStage + 1; end&lt;br /&gt;
end&lt;br /&gt;
if [ $response == &amp;quot;&amp;quot; ]; quit; end&lt;br /&gt;
&lt;br /&gt;
for x in $DialogParams&lt;br /&gt;
	set parameter $x ${$x}&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12283</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12283"/>
		<updated>2026-01-08T00:31:03Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* CUSTOM DIALOG ... */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
__FORCETOC__&lt;br /&gt;
&lt;br /&gt;
===CHOOSE ...===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CHOOSE&amp;lt;/code&amp;gt; family of commands prompt the user to specify file or directory paths, via the Qt graphical user interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILE&amp;lt;/code&amp;gt;  (or equivalently &amp;lt;code&amp;gt;CHOOSE FILE&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CHOOSE INPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select a single existing file, and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILES&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE FILES&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select one or more existing files, and prints the resulting file paths one per line (&amp;lt;code&amp;gt;FOR ... IN ...&amp;lt;/code&amp;gt; can iterate over these).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE OUTPUT FILE&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE OUTPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists) and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;&lt;br /&gt;
: Prompts the user to specify a directory, and prints the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
If the user cancels the dialog, the commands print nothing.&lt;br /&gt;
&lt;br /&gt;
The commands may be followed by one or more of the following optional clauses (they must appear in this order):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[OF] TYPE[S] &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This limits the view (via a drop-down file-type selector) to files that have the specified extension(s). This clause cannot be used with &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;.  Instead of a file extension (starting with a dot) you can alternatively specify a glob pattern (containing a star). You can include &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt; (or equivalently &amp;lt;code&amp;gt;*.*&amp;lt;/code&amp;gt;) in the list if you want to give the user the option of overriding the limitation.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[STARTING] AT &amp;lt;dir&amp;gt;&amp;lt;/code&amp;gt; (equivalently you can say &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;FROM&amp;lt;/code&amp;gt; if it reads better)&lt;br /&gt;
: This specifies where the dialog&#039;s file-system navigation should start (by default, it will start in the current working directory).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[WITH] PROMPT &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This specifies the text prompt at the top of the dialog.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
choose file of type .dat from ../data/samplefiles with prompt &amp;quot;Choose a data file for playback:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose output file of type .prm in ../parms with prompt &amp;quot;Save parameters as...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose directory starting at ../data with prompt &amp;quot;Select a subject directory:&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===CUSTOM DIALOG ...===&lt;br /&gt;
&lt;br /&gt;
This command assembles a flexibly customizable modal dialog for communicating with the user. The command returns (prints) a string denoting which button the user pressed to complete the dialog, and as a side effect it may set any environment variables that the command specifies.  If the user cancels the dialog, the command does nothing (prints nothing, does not change any environment variables).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command can be followed by as many clauses as you like. The main types of clause are &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog, in the order you provide. Possible clauses are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Each message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule. Simplest example: &amp;lt;pre&amp;gt;custom dialog message &amp;quot;Hello world!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;] [CATALOG &amp;lt;listVariableName&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. If you supply a &amp;lt;code&amp;gt;CATALOG&amp;lt;/code&amp;gt; subclause, the variable name will be added to a newline-delimited sequence of names stored in another environment variable, designated by &amp;lt;code&amp;gt;&amp;lt;listVariableName&amp;gt;&amp;lt;/code&amp;gt; - this can be useful for later iteration (see below).   A simple &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;] [CATALOG &amp;lt;listVariableName&amp;gt;]&amp;lt;/code&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used, in conjunction with an empty first/default option, to force the user to make an explicit selection, as in the following example (note the leading &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt; character inside the braces): &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, will be the one that gets highlighted by default and bound to the enter/return keystroke. If you do not specify a default, then &amp;quot;Ok&amp;quot; will be assumed to be the default button. If the designated default does not appear in the list of buttons, the buttons will all have equal status with no return-keystroke binding. The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke, and pressing this button is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).  For most purposes, you will probably not need to override the button configuration explicitly. In dialogs without &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are simply displaying messages to the user), the &amp;lt;code&amp;gt;BUTTONS {Ok} DEFAULT Ok&amp;lt;/code&amp;gt; configuration is assumed. In dialogs with one or more &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are asking the user for information), the &amp;lt;code&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel&amp;lt;/code&amp;gt; configuration is assumed.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TITLE &amp;lt;text&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This overrides the default dialog title &amp;quot;BCI2000&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;SPACING &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical spacing between successive &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; elements.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;WIDTH &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;HEIGHT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum height of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;LEFT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the horizontal coordinate of the dialog&#039;s left edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TOP &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical coordinate of the dialog&#039;s top edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CACHEFILE &amp;lt;FILENAME&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Specifying a cache file allows dialog contents to be made persistent across sessions. If the specified file already exists when the dialog is invoked, it will get run via &amp;lt;code&amp;gt;EXECUTE SCRIPT&amp;lt;/code&amp;gt;; if this sets any of the dialog&#039;s environment variables, then these new values override the &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; values for the corresponding text fields and drop-down menus. But you do not need to initialize the specified file manually—if it does not exist, nothing is loaded. When the dialog is successfully completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button), &amp;lt;code&amp;gt;WRITE ENVIRONMENT&amp;lt;/code&amp;gt; is automatically called to write the corresponding &amp;lt;code&amp;gt;SET ENVIRONMENT&amp;lt;/code&amp;gt; statements to the specified file. So, when the same dialog is invoked next time around, these settings will be loaded: the user will see whatever settings they entered/chose this time.  Example: &amp;lt;pre&amp;gt;custom dialog  cachefile vars.bci  var subjectName &amp;quot;Subject ID:&amp;quot; {} default Nobody minimum 1 &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Integrated &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; example====&lt;br /&gt;
&lt;br /&gt;
The following partial listing illustrates one way &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; might be used to implement a simplified launcher GUI, for a hypothetical auditory BCI experiment.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# [initialize system]&lt;br /&gt;
# [start up modules]&lt;br /&gt;
# [load baseline parameters for this BCI]&lt;br /&gt;
&lt;br /&gt;
set environment launcherAction ${&lt;br /&gt;
    custom dialog &lt;br /&gt;
        title &amp;quot;Auditory BCI Launcher&amp;quot; &lt;br /&gt;
        cachefile &amp;quot;${parent directory $0}/launcherDialogVars.bci&amp;quot;&lt;br /&gt;
        var subjectName &amp;quot;Subject ID:&amp;quot;         {}    default &amp;quot;$subjectName&amp;quot; minimum 1&lt;br /&gt;
        var runType     &amp;quot;Run Type:&amp;quot;           {Calibration|Free Selection}&lt;br /&gt;
        var condition   &amp;quot;Stimulus Condition:&amp;quot; {SlowStimuli.prm|FastStimuli.prm}&lt;br /&gt;
        message &amp;quot;NB: each condition should be calibrated separately.&amp;quot; &lt;br /&gt;
        buttons {Quit|Launch} default Launch escape Quit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if [ $launcherAction == &amp;quot;&amp;quot; ]&lt;br /&gt;
    quit&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if [ $runType == Calibration ]&lt;br /&gt;
    load parameterfile ../parms/calib.prm       # let&#039;s assume you have created this&lt;br /&gt;
else&lt;br /&gt;
    load parameterfile ../parms/free.prm        # and this&lt;br /&gt;
end&lt;br /&gt;
load parameterfile ../parms/$stimulusCondition  # and these&lt;br /&gt;
set parameter SubjectName $subjectName&lt;br /&gt;
setconfig&lt;br /&gt;
show window   # unless you have some other remote-control mechanism for suspending/resuming runs&lt;br /&gt;
set state Running 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The resulting dialog looks like this:&lt;br /&gt;
&lt;br /&gt;
[[File:CustomDialogExample.png]]&lt;br /&gt;
&lt;br /&gt;
====Example of &amp;lt;code&amp;gt;CATALOG&amp;lt;/code&amp;gt; usage====&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CATALOG&amp;lt;/code&amp;gt; option allows you to keep track of one or more lists of variable names. It helps to cut down on boilerplate repetition in certain common patterns. Here is an example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Create some new parameters&lt;br /&gt;
add parameter Application:Custom%20Stimuli float MinStimulusGap= 100ms 100ms 0 % // minimum gap to use in custom stimulus generation&lt;br /&gt;
add parameter Application:Custom%20Stimuli float MaxStimulusGap= 400ms 400ms 0 % // maximum gap to use in custom stimulus generation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# In the dialog, some entries will be environment variables with exactly&lt;br /&gt;
# the same names as parameters - let&#039;s catalog these&lt;br /&gt;
if [ ${&lt;br /&gt;
        custom dialog&lt;br /&gt;
            var SubjectName     &amp;quot;Subject:&amp;quot;     {}  minimum 1                default &amp;quot;Nobody&amp;quot; catalog DialogParams&lt;br /&gt;
            var MaxStimulusGap  &amp;quot;Minimum Gap:&amp;quot; {0ms|50ms|100ms|200ms|400ms} default &amp;quot;100ms&amp;quot;  catalog DialogParams &lt;br /&gt;
            var MinStimulusGap  &amp;quot;Maximum Gap:&amp;quot; {0ms|50ms|100ms|200ms|400ms} default &amp;quot;400ms&amp;quot;  catalog DialogParams &lt;br /&gt;
            var RunType         &amp;quot;Run Type:&amp;quot;    {Calibration.prm|FreeSpelling.prm}&lt;br /&gt;
            &lt;br /&gt;
            cachefile &amp;quot;${parent directory $0}/launcherDialogVars.bci&amp;quot;&lt;br /&gt;
            &lt;br /&gt;
    } == &amp;quot;&amp;quot; ]; quit; end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ...&lt;br /&gt;
&lt;br /&gt;
# The catalog saves us from having to hard-code a list of the new parameter names a third time:&lt;br /&gt;
for var in $DialogParams        &lt;br /&gt;
    set parameter $var ${$var}&lt;br /&gt;
    # We chose the environment variable names to be the same as the corresponding parameter names.&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# This dialog variable is handled differently, so we did not catalog it with the others:&lt;br /&gt;
load parameterfile $RunType&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notes:  In the example above, we have used just one catalog variable, &amp;lt;code&amp;gt;DialogParams&amp;lt;/code&amp;gt;, but you are free to use more than one if you want to assemble separate lists of variables for different purposes.  The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command clears each catalog variable the first time it uses it (so, you can run the example above multiple times, and &amp;lt;code&amp;gt;DialogParams&amp;lt;/code&amp;gt; will still only contain one copy of each name).  Catalog variables get cleared and (re-)filled regardless of whether the dialog is accepted or cancelled.&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12282</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12282"/>
		<updated>2026-01-07T16:03:07Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* CUSTOM DIALOG ... */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
__FORCETOC__&lt;br /&gt;
&lt;br /&gt;
===CHOOSE ...===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CHOOSE&amp;lt;/code&amp;gt; family of commands prompt the user to specify file or directory paths, via the Qt graphical user interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILE&amp;lt;/code&amp;gt;  (or equivalently &amp;lt;code&amp;gt;CHOOSE FILE&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CHOOSE INPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select a single existing file, and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILES&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE FILES&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select one or more existing files, and prints the resulting file paths one per line (&amp;lt;code&amp;gt;FOR ... IN ...&amp;lt;/code&amp;gt; can iterate over these).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE OUTPUT FILE&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE OUTPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists) and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;&lt;br /&gt;
: Prompts the user to specify a directory, and prints the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
If the user cancels the dialog, the commands print nothing.&lt;br /&gt;
&lt;br /&gt;
The commands may be followed by one or more of the following optional clauses (they must appear in this order):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[OF] TYPE[S] &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This limits the view (via a drop-down file-type selector) to files that have the specified extension(s). This clause cannot be used with &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;.  Instead of a file extension (starting with a dot) you can alternatively specify a glob pattern (containing a star). You can include &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt; (or equivalently &amp;lt;code&amp;gt;*.*&amp;lt;/code&amp;gt;) in the list if you want to give the user the option of overriding the limitation.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[STARTING] AT &amp;lt;dir&amp;gt;&amp;lt;/code&amp;gt; (equivalently you can say &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;FROM&amp;lt;/code&amp;gt; if it reads better)&lt;br /&gt;
: This specifies where the dialog&#039;s file-system navigation should start (by default, it will start in the current working directory).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[WITH] PROMPT &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This specifies the text prompt at the top of the dialog.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
choose file of type .dat from ../data/samplefiles with prompt &amp;quot;Choose a data file for playback:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose output file of type .prm in ../parms with prompt &amp;quot;Save parameters as...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose directory starting at ../data with prompt &amp;quot;Select a subject directory:&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===CUSTOM DIALOG ...===&lt;br /&gt;
&lt;br /&gt;
This command assembles a flexibly customizable modal dialog for communicating with the user. The command returns (prints) a string denoting which button the user pressed to complete the dialog, and as a side effect it may set any environment variables that the command specifies.  If the user cancels the dialog, the command does nothing (prints nothing, does not change any environment variables).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command can be followed by as many clauses as you like. The main types of clause are &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog, in the order you provide. Possible clauses are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Each message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule. Simplest example: &amp;lt;pre&amp;gt;custom dialog message &amp;quot;Hello world!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;] [CATALOG &amp;lt;listVariableName&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. If you supply a &amp;lt;code&amp;gt;CATALOG&amp;lt;/code&amp;gt; subclause, the variable name will be added to a newline-delimited sequence of names stored in another environment variable, designated by &amp;lt;code&amp;gt;&amp;lt;listVariableName&amp;gt;&amp;lt;/code&amp;gt;.  This can be useful for later iteration (see below).   A simple &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;] [CATALOG &amp;lt;listVariableName&amp;gt;]&amp;lt;/code&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used, in conjunction with an empty first/default option, to force the user to make an explicit selection, as in the following example (note the leading &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt; character inside the braces): &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, will be the one that gets highlighted by default and bound to the enter/return keystroke. If you do not specify a default, then &amp;quot;Ok&amp;quot; will be assumed to be the default button. If the designated default does not appear in the list of buttons, the buttons will all have equal status with no return-keystroke binding. The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke, and pressing this button is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).  For most purposes, you will probably not need to override the button configuration explicitly. In dialogs without &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are simply displaying messages to the user), the &amp;lt;code&amp;gt;BUTTONS {Ok} DEFAULT Ok&amp;lt;/code&amp;gt; configuration is assumed. In dialogs with one or more &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are asking the user for information), the &amp;lt;code&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel&amp;lt;/code&amp;gt; configuration is assumed.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TITLE &amp;lt;text&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This overrides the default dialog title &amp;quot;BCI2000&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;SPACING &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical spacing between successive &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; elements.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;WIDTH &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;HEIGHT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum height of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;LEFT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the horizontal coordinate of the dialog&#039;s left edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TOP &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical coordinate of the dialog&#039;s top edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CACHEFILE &amp;lt;FILENAME&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Specifying a cache file allows dialog contents to be made persistent across sessions. If the specified file already exists when the dialog is invoked, it will get run via &amp;lt;code&amp;gt;EXECUTE SCRIPT&amp;lt;/code&amp;gt;; if this sets any of the dialog&#039;s environment variables, then these new values override the &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; values for the corresponding text fields and drop-down menus. But you do not need to initialize the specified file manually—if it does not exist, nothing is loaded. When the dialog is successfully completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button), &amp;lt;code&amp;gt;WRITE ENVIRONMENT&amp;lt;/code&amp;gt; is automatically called to write the corresponding &amp;lt;code&amp;gt;SET ENVIRONMENT&amp;lt;/code&amp;gt; statements to the specified file. So, when the same dialog is invoked next time around, these settings will be loaded: the user will see whatever settings they entered/chose this time.  Example: &amp;lt;pre&amp;gt;custom dialog  cachefile vars.bci  var subjectName &amp;quot;Subject ID:&amp;quot; {} default Nobody minimum 1 &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Integrated &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; example====&lt;br /&gt;
&lt;br /&gt;
The following partial listing illustrates one way &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; might be used to implement a simplified launcher GUI, for a hypothetical auditory BCI experiment.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# [initialize system]&lt;br /&gt;
# [start up modules]&lt;br /&gt;
# [load baseline parameters for this BCI]&lt;br /&gt;
&lt;br /&gt;
set environment launcherAction ${&lt;br /&gt;
    custom dialog &lt;br /&gt;
        title &amp;quot;Auditory BCI Launcher&amp;quot; &lt;br /&gt;
        cachefile &amp;quot;${parent directory $0}/launcherDialogVars.bci&amp;quot;&lt;br /&gt;
        var subjectName &amp;quot;Subject ID:&amp;quot;         {}    default &amp;quot;$subjectName&amp;quot; minimum 1&lt;br /&gt;
        var runType     &amp;quot;Run Type:&amp;quot;           {Calibration|Free Selection}&lt;br /&gt;
        var condition   &amp;quot;Stimulus Condition:&amp;quot; {SlowStimuli.prm|FastStimuli.prm}&lt;br /&gt;
        message &amp;quot;NB: each condition should be calibrated separately.&amp;quot; &lt;br /&gt;
        buttons {Quit|Launch} default Launch escape Quit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if [ $launcherAction == &amp;quot;&amp;quot; ]&lt;br /&gt;
    quit&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if [ $runType == Calibration ]&lt;br /&gt;
    load parameterfile ../parms/calib.prm       # let&#039;s assume you have created this&lt;br /&gt;
else&lt;br /&gt;
    load parameterfile ../parms/free.prm        # and this&lt;br /&gt;
end&lt;br /&gt;
load parameterfile ../parms/$stimulusCondition  # and these&lt;br /&gt;
set parameter SubjectName $subjectName&lt;br /&gt;
setconfig&lt;br /&gt;
show window   # unless you have some other remote-control mechanism for suspending/resuming runs&lt;br /&gt;
set state Running 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The resulting dialog looks like this:&lt;br /&gt;
&lt;br /&gt;
[[File:CustomDialogExample.png]]&lt;br /&gt;
&lt;br /&gt;
====Example of &amp;lt;code&amp;gt;CATALOG&amp;lt;/code&amp;gt; usage====&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CATALOG&amp;lt;/code&amp;gt; option allows you to keep track of one or more lists of variable names. It helps to cut down on boilerplate repetition in certain common patterns. Here is an example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Create some new parameters&lt;br /&gt;
add parameter Application:Custom%20Stimuli float MinStimulusGap= 100ms   100ms 0 %   // minimum gap to use in custom stimulus generation&lt;br /&gt;
add parameter Application:Custom%20Stimuli float MaxStimulusGap= 400ms   400ms 0 %   // maximum gap to use in custom stimulus generation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# In the dialog, some entries will be environment variables with exactly the&lt;br /&gt;
# same names as parameters - let&#039;s catalog these&lt;br /&gt;
if [ ${&lt;br /&gt;
        custom dialog&lt;br /&gt;
            var SubjectName     &amp;quot;Subject:&amp;quot;     {}  minimum 1                default &amp;quot;Nobody&amp;quot; catalog DialogParams&lt;br /&gt;
            var MaxStimulusGap  &amp;quot;Minimum Gap:&amp;quot; {0ms|50ms|100ms|200ms|400ms} default &amp;quot;100ms&amp;quot;  catalog DialogParams &lt;br /&gt;
            var MinStimulusGap  &amp;quot;Maximum Gap:&amp;quot; {0ms|50ms|100ms|200ms|400ms} default &amp;quot;400ms&amp;quot;  catalog DialogParams &lt;br /&gt;
            var RunType         &amp;quot;Run Type:&amp;quot;    {Calibration.prm|FreeSpelling.prm}&lt;br /&gt;
            &lt;br /&gt;
            cachefile &amp;quot;${parent directory $0}/launcherDialogVars.bci&amp;quot;&lt;br /&gt;
            &lt;br /&gt;
    } == &amp;quot;&amp;quot; ]; quit; end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ...&lt;br /&gt;
&lt;br /&gt;
for var in $DialogParams        # The catalog saves you from having to hard-code a list of the new parameter names a third time.&lt;br /&gt;
    set parameter $var ${$var}  # We chose the environment variable names to be the same as the corresponding parameter names.&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
load parameterfile $RunType     # This dialog variable is handled differently, so we did not catalog it with the others.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notes:  In the example above, we have used just one catalog variable, &amp;lt;code&amp;gt;DialogParams&amp;lt;/code&amp;gt;, but you are free to use more than one if you want to assemble separate lists of variables for different purposes.  The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command clears each catalog variable the first time it uses it (so, you can run the example above multiple times, and &amp;lt;code&amp;gt;DialogParams&amp;lt;/code&amp;gt; will still only contain one copy of each name).  Catalog variables get cleared and filled regardless of whether the dialog is accepted or cancelled.&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12131</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12131"/>
		<updated>2025-10-10T15:59:26Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* CUSTOM DIALOG ... */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
__FORCETOC__&lt;br /&gt;
&lt;br /&gt;
===CHOOSE ...===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CHOOSE&amp;lt;/code&amp;gt; family of commands prompt the user to specify file or directory paths, via the Qt graphical user interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILE&amp;lt;/code&amp;gt;  (or equivalently &amp;lt;code&amp;gt;CHOOSE FILE&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CHOOSE INPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select a single existing file, and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILES&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE FILES&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select one or more existing files, and prints the resulting file paths one per line (&amp;lt;code&amp;gt;FOR ... IN ...&amp;lt;/code&amp;gt; can iterate over these).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE OUTPUT FILE&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE OUTPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists) and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;&lt;br /&gt;
: Prompts the user to specify a directory, and prints the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
If the user cancels the dialog, the commands print nothing.&lt;br /&gt;
&lt;br /&gt;
The commands may be followed by one or more of the following optional clauses (they must appear in this order):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[OF] TYPE[S] &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This limits the view (via a drop-down file-type selector) to files that have the specified extension(s). This clause cannot be used with &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;.  Instead of a file extension (starting with a dot) you can alternatively specify a glob pattern (containing a star). You can include &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt; (or equivalently &amp;lt;code&amp;gt;*.*&amp;lt;/code&amp;gt;) in the list if you want to give the user the option of overriding the limitation.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[STARTING] AT &amp;lt;dir&amp;gt;&amp;lt;/code&amp;gt; (equivalently you can say &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;FROM&amp;lt;/code&amp;gt; if it reads better)&lt;br /&gt;
: This specifies where the dialog&#039;s file-system navigation should start (by default, it will start in the current working directory).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[WITH] PROMPT &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This specifies the text prompt at the top of the dialog.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
choose file of type .dat from ../data/samplefiles with prompt &amp;quot;Choose a data file for playback:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose output file of type .prm in ../parms with prompt &amp;quot;Save parameters as...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose directory starting at ../data with prompt &amp;quot;Select a subject directory:&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===CUSTOM DIALOG ...===&lt;br /&gt;
&lt;br /&gt;
This command assembles a flexibly customizable modal dialog for communicating with the user. The command returns (prints) a string denoting which button the user pressed to complete the dialog, and as a side effect it may set any environment variables that the command specifies.  If the user cancels the dialog, the command does nothing (prints nothing, does not change any environment variables).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command can be followed by as many clauses as you like. The main types of clause are &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog, in the order you provide. Possible clauses are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Each message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule. Simplest example: &amp;lt;pre&amp;gt;custom dialog message &amp;quot;Hello world!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. For example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used, in conjunction with an empty first/default option, to force the user to make an explicit selection, as in the following example (note the leading &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt; character inside the braces): &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, will be the one that gets highlighted by default and bound to the enter/return keystroke. If you do not specify a default, then &amp;quot;Ok&amp;quot; will be assumed to be the default button. If the designated default does not appear in the list of buttons, the buttons will all have equal status with no return-keystroke binding. The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke, and pressing this button is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).  For most purposes, you will probably not need to override the button configuration explicitly. In dialogs without &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are simply displaying messages to the user), the &amp;lt;code&amp;gt;BUTTONS {Ok} DEFAULT Ok&amp;lt;/code&amp;gt; configuration is assumed. In dialogs with one or more &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are asking the user for information), the &amp;lt;code&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel&amp;lt;/code&amp;gt; configuration is assumed.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TITLE &amp;lt;text&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This overrides the default dialog title &amp;quot;BCI2000&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;SPACING &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical spacing between successive &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; elements.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;WIDTH &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;HEIGHT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum height of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;LEFT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the horizontal coordinate of the dialog&#039;s left edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TOP &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical coordinate of the dialog&#039;s top edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CACHEFILE &amp;lt;FILENAME&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Specifying a cache file allows dialog contents to be made persistent across sessions. If the specified file already exists when the dialog is invoked, it will get run via &amp;lt;code&amp;gt;EXECUTE SCRIPT&amp;lt;/code&amp;gt;; if this sets any of the dialog&#039;s environment variables, then these new values override the &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; values for the corresponding text fields and drop-down menus. But you do not need to initialize the specified file manually—if it does not exist, nothing is loaded. When the dialog is successfully completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button), &amp;lt;code&amp;gt;WRITE ENVIRONMENT&amp;lt;/code&amp;gt; is automatically called to write the corresponding &amp;lt;code&amp;gt;SET ENVIRONMENT&amp;lt;/code&amp;gt; statements to the specified file. So, when the same dialog is invoked next time around, these settings will be loaded: the user will see whatever settings they entered/chose this time.  Example: &amp;lt;pre&amp;gt;custom dialog  cachefile vars.bci  var subjectName &amp;quot;Subject ID:&amp;quot; {} default Nobody minimum 1 &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Integrated &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; example====&lt;br /&gt;
&lt;br /&gt;
The following partial listing illustrates one way &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; might be used to implement a simplified launcher GUI, for a hypothetical auditory BCI experiment.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# [initialize system]&lt;br /&gt;
# [start up modules]&lt;br /&gt;
# [load baseline parameters for this BCI]&lt;br /&gt;
&lt;br /&gt;
set environment launcherAction ${&lt;br /&gt;
    custom dialog &lt;br /&gt;
        title &amp;quot;Auditory BCI Launcher&amp;quot; &lt;br /&gt;
        cachefile &amp;quot;${parent directory $0}/launcherDialogVars.bci&amp;quot;&lt;br /&gt;
        var subjectName &amp;quot;Subject ID:&amp;quot;         {}    default &amp;quot;$subjectName&amp;quot; minimum 1&lt;br /&gt;
        var runType     &amp;quot;Run Type:&amp;quot;           {Calibration|Free Selection}&lt;br /&gt;
        var condition   &amp;quot;Stimulus Condition:&amp;quot; {SlowStimuli.prm|FastStimuli.prm}&lt;br /&gt;
        message &amp;quot;NB: each condition should be calibrated separately.&amp;quot; &lt;br /&gt;
        buttons {Quit|Launch} default Launch escape Quit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if [ $launcherAction == &amp;quot;&amp;quot; ]&lt;br /&gt;
    quit&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if [ $runType == Calibration ]&lt;br /&gt;
    load parameterfile ../parms/calib.prm       # let&#039;s assume you have created this&lt;br /&gt;
else&lt;br /&gt;
    load parameterfile ../parms/free.prm        # and this&lt;br /&gt;
end&lt;br /&gt;
load parameterfile ../parms/$stimulusCondition  # and these&lt;br /&gt;
set parameter SubjectName $subjectName&lt;br /&gt;
setconfig&lt;br /&gt;
show window   # unless you have some other remote-control mechanism for suspending/resuming runs&lt;br /&gt;
set state Running 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The resulting dialog looks like this:&lt;br /&gt;
&lt;br /&gt;
[[File:CustomDialogExample.png]]&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12130</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12130"/>
		<updated>2025-10-10T15:58:33Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* CUSTOM DIALOG ... */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
__FORCETOC__&lt;br /&gt;
&lt;br /&gt;
===CHOOSE ...===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CHOOSE&amp;lt;/code&amp;gt; family of commands prompt the user to specify file or directory paths, via the Qt graphical user interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILE&amp;lt;/code&amp;gt;  (or equivalently &amp;lt;code&amp;gt;CHOOSE FILE&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CHOOSE INPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select a single existing file, and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILES&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE FILES&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select one or more existing files, and prints the resulting file paths one per line (&amp;lt;code&amp;gt;FOR ... IN ...&amp;lt;/code&amp;gt; can iterate over these).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE OUTPUT FILE&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE OUTPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists) and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;&lt;br /&gt;
: Prompts the user to specify a directory, and prints the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
If the user cancels the dialog, the commands print nothing.&lt;br /&gt;
&lt;br /&gt;
The commands may be followed by one or more of the following optional clauses (they must appear in this order):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[OF] TYPE[S] &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This limits the view (via a drop-down file-type selector) to files that have the specified extension(s). This clause cannot be used with &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;.  Instead of a file extension (starting with a dot) you can alternatively specify a glob pattern (containing a star). You can include &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt; (or equivalently &amp;lt;code&amp;gt;*.*&amp;lt;/code&amp;gt;) in the list if you want to give the user the option of overriding the limitation.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[STARTING] AT &amp;lt;dir&amp;gt;&amp;lt;/code&amp;gt; (equivalently you can say &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;FROM&amp;lt;/code&amp;gt; if it reads better)&lt;br /&gt;
: This specifies where the dialog&#039;s file-system navigation should start (by default, it will start in the current working directory).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[WITH] PROMPT &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This specifies the text prompt at the top of the dialog.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
choose file of type .dat from ../data/samplefiles with prompt &amp;quot;Choose a data file for playback:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose output file of type .prm in ../parms with prompt &amp;quot;Save parameters as...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose directory starting at ../data with prompt &amp;quot;Select a subject directory:&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===CUSTOM DIALOG ...===&lt;br /&gt;
&lt;br /&gt;
This command assembles a flexibly customizable modal dialog for communicating with the user. The command returns (prints) a string denoting which button the user pressed to complete the dialog, and as a side effect it may set any environment variables that the command specifies.  If the user cancels the dialog, the command does nothing (prints nothing, does not change any environment variables).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command can be followed by as many clauses as you like. The main types of clause are &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog, in the order you provide. Possible clauses are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Each message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule. Simplest example: &amp;lt;pre&amp;gt;custom dialog message &amp;quot;Hello world!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. For example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used, in conjunction with an empty first/default option, to force the user to make an explicit selection, as in the following example (note the leading &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt; character inside the braces): &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, will be the one that gets highlighted by default and bound to the enter/return keystroke. If you do not specify a default, then &amp;quot;Ok&amp;quot; will be assumed to be the default button. If the designated default does not appear in the list of buttons, the buttons will all have equal status with no return-keystroke binding. The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke, and pressing this button is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).  For most purposes, you will probably not need to override the button configuration explicitly. In dialogs without &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are simply displaying messages to the user), the &amp;lt;code&amp;gt;BUTTONS {Ok} DEFAULT Ok&amp;lt;/code&amp;gt; configuration is assumed. In dialogs with one or more &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are asking the user for information), the &amp;lt;code&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel&amp;lt;/code&amp;gt; configuration is assumed.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TITLE &amp;lt;text&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This overrides the default dialog title &amp;quot;BCI2000&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;SPACING &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical spacing between successive &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; elements.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;WIDTH &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;HEIGHT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum height of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;LEFT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the horizontal coordinate of the dialog&#039;s left edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TOP &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical coordinate of the dialog&#039;s top edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CACHEFILE &amp;lt;FILENAME&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Specifying a cache file allows dialog contents to be made persistent across sessions. If the specified file already exists when the dialog is invoked, it will get run via &amp;lt;code&amp;gt;EXECUTE SCRIPT&amp;lt;/code&amp;gt;; if this sets any of the dialog&#039;s environment variables, then these new values override the &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; values for the corresponding text fields and drop-down menus. But you do not need to initialize the specified file manually—if it does not exist, nothing is loaded. When the dialog is successfully completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button), &amp;lt;code&amp;gt;WRITE ENVIRONMENT&amp;lt;/code&amp;gt; is automatically called to write the corresponding &amp;lt;code&amp;gt;SET ENVIRONMENT&amp;lt;/code&amp;gt; statements to the specified file. So, when the same dialog is invoked again, these settings will be loaded: the user will see whatever settings they entered/chose the previous time.  Example: &amp;lt;pre&amp;gt;custom dialog  cachefile vars.bci  var subjectName &amp;quot;Subject ID:&amp;quot; {} default Nobody minimum 1 &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Integrated &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; example====&lt;br /&gt;
&lt;br /&gt;
The following partial listing illustrates one way &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; might be used to implement a simplified launcher GUI, for a hypothetical auditory BCI experiment.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# [initialize system]&lt;br /&gt;
# [start up modules]&lt;br /&gt;
# [load baseline parameters for this BCI]&lt;br /&gt;
&lt;br /&gt;
set environment launcherAction ${&lt;br /&gt;
    custom dialog &lt;br /&gt;
        title &amp;quot;Auditory BCI Launcher&amp;quot; &lt;br /&gt;
        cachefile &amp;quot;${parent directory $0}/launcherDialogVars.bci&amp;quot;&lt;br /&gt;
        var subjectName &amp;quot;Subject ID:&amp;quot;         {}    default &amp;quot;$subjectName&amp;quot; minimum 1&lt;br /&gt;
        var runType     &amp;quot;Run Type:&amp;quot;           {Calibration|Free Selection}&lt;br /&gt;
        var condition   &amp;quot;Stimulus Condition:&amp;quot; {SlowStimuli.prm|FastStimuli.prm}&lt;br /&gt;
        message &amp;quot;NB: each condition should be calibrated separately.&amp;quot; &lt;br /&gt;
        buttons {Quit|Launch} default Launch escape Quit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if [ $launcherAction == &amp;quot;&amp;quot; ]&lt;br /&gt;
    quit&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if [ $runType == Calibration ]&lt;br /&gt;
    load parameterfile ../parms/calib.prm       # let&#039;s assume you have created this&lt;br /&gt;
else&lt;br /&gt;
    load parameterfile ../parms/free.prm        # and this&lt;br /&gt;
end&lt;br /&gt;
load parameterfile ../parms/$stimulusCondition  # and these&lt;br /&gt;
set parameter SubjectName $subjectName&lt;br /&gt;
setconfig&lt;br /&gt;
show window   # unless you have some other remote-control mechanism for suspending/resuming runs&lt;br /&gt;
set state Running 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The resulting dialog looks like this:&lt;br /&gt;
&lt;br /&gt;
[[File:CustomDialogExample.png]]&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12128</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12128"/>
		<updated>2025-10-09T02:08:59Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* Integrated CUSTOM DIALOG example */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
__FORCETOC__&lt;br /&gt;
&lt;br /&gt;
===CHOOSE ...===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CHOOSE&amp;lt;/code&amp;gt; family of commands prompt the user to specify file or directory paths, via the Qt graphical user interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILE&amp;lt;/code&amp;gt;  (or equivalently &amp;lt;code&amp;gt;CHOOSE FILE&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CHOOSE INPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select a single existing file, and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILES&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE FILES&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select one or more existing files, and prints the resulting file paths one per line (&amp;lt;code&amp;gt;FOR ... IN ...&amp;lt;/code&amp;gt; can iterate over these).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE OUTPUT FILE&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE OUTPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists) and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;&lt;br /&gt;
: Prompts the user to specify a directory, and prints the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
If the user cancels the dialog, the commands print nothing.&lt;br /&gt;
&lt;br /&gt;
The commands may be followed by one or more of the following optional clauses (they must appear in this order):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[OF] TYPE[S] &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This limits the view (via a drop-down file-type selector) to files that have the specified extension(s). This clause cannot be used with &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;.  Instead of a file extension (starting with a dot) you can alternatively specify a glob pattern (containing a star). You can include &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt; (or equivalently &amp;lt;code&amp;gt;*.*&amp;lt;/code&amp;gt;) in the list if you want to give the user the option of overriding the limitation.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[STARTING] AT &amp;lt;dir&amp;gt;&amp;lt;/code&amp;gt; (equivalently you can say &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;FROM&amp;lt;/code&amp;gt; if it reads better)&lt;br /&gt;
: This specifies where the dialog&#039;s file-system navigation should start (by default, it will start in the current working directory).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[WITH] PROMPT &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This specifies the text prompt at the top of the dialog.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
choose file of type .dat from ../data/samplefiles with prompt &amp;quot;Choose a data file for playback:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose output file of type .prm in ../parms with prompt &amp;quot;Save parameters as...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose directory starting at ../data with prompt &amp;quot;Select a subject directory:&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===CUSTOM DIALOG ...===&lt;br /&gt;
&lt;br /&gt;
This command assembles a flexibly customizable modal dialog for communicating with the user. The command returns (prints) a string denoting which button the user pressed to complete the dialog, and as a side effect it may set any environment variables that the command specifies.  If the user cancels the dialog, the command does nothing (prints nothing, does not change any environment variables).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command can be followed by as many clauses as you like. The main types of clause are &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog, in the order you provide. Possible clauses are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Each message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule. Simplest example: &amp;lt;pre&amp;gt;custom dialog message &amp;quot;Hello world!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. For example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used, in conjunction with an empty first/default option, to force the user to make an explicit selection, as in the following example (note the leading &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt; character inside the braces): &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, will be the one that gets highlighted by default and bound to the enter/return keystroke. If you do not specify a default, then &amp;quot;Ok&amp;quot; will be assumed to be the default button. If the designated default does not appear in the list of buttons, the buttons will all have equal status with no return-keystroke binding. The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke, and pressing this button is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).  For most purposes, you will probably not need to override the button configuration explicitly. In dialogs without &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are simply displaying messages to the user), the &amp;lt;code&amp;gt;BUTTONS {Ok} DEFAULT Ok&amp;lt;/code&amp;gt; configuration is assumed. In dialogs with one or more &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are asking the user for information), the &amp;lt;code&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel&amp;lt;/code&amp;gt; configuration is assumed.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TITLE &amp;lt;text&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This overrides the default dialog title &amp;quot;BCI2000&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;SPACING &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical spacing between successive &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; elements.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;WIDTH &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;HEIGHT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum height of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;LEFT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the horizontal coordinate of the dialog&#039;s left edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TOP &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical coordinate of the dialog&#039;s top edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CACHEFILE &amp;lt;FILENAME&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Specifying a cache file allows dialog contents to be made persistent across sessions. If the specified file already exists when the dialog is invoked, the file gets run with &amp;lt;code&amp;gt;EXECUTE SCRIPT&amp;lt;/code&amp;gt;; if this sets any of the dialog&#039;s environment variables, then these new values override the &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; values for the corresponding text fields and drop-down menus. When the dialog is successfully completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button), &amp;lt;code&amp;gt;WRITE ENVIRONMENT&amp;lt;/code&amp;gt; is automatically called to write the corresponding &amp;lt;code&amp;gt;SET ENVIRONMENT&amp;lt;/code&amp;gt; statements to the specified file. So, when the same dialog is invoked again, these settings will be loaded: the user will see whatever settings they entered/chose the previous time.  Example: &amp;lt;pre&amp;gt;custom dialog  cachefile vars.bci  var subjectName &amp;quot;Subject ID:&amp;quot; {} default Nobody minimum 1 &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Integrated &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; example====&lt;br /&gt;
&lt;br /&gt;
The following partial listing illustrates one way &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; might be used to implement a simplified launcher GUI, for a hypothetical auditory BCI experiment.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# [initialize system]&lt;br /&gt;
# [start up modules]&lt;br /&gt;
# [load baseline parameters for this BCI]&lt;br /&gt;
&lt;br /&gt;
set environment launcherAction ${&lt;br /&gt;
    custom dialog &lt;br /&gt;
        title &amp;quot;Auditory BCI Launcher&amp;quot; &lt;br /&gt;
        cachefile &amp;quot;${parent directory $0}/launcherDialogVars.bci&amp;quot;&lt;br /&gt;
        var subjectName &amp;quot;Subject ID:&amp;quot;         {}    default &amp;quot;$subjectName&amp;quot; minimum 1&lt;br /&gt;
        var runType     &amp;quot;Run Type:&amp;quot;           {Calibration|Free Selection}&lt;br /&gt;
        var condition   &amp;quot;Stimulus Condition:&amp;quot; {SlowStimuli.prm|FastStimuli.prm}&lt;br /&gt;
        message &amp;quot;NB: each condition should be calibrated separately.&amp;quot; &lt;br /&gt;
        buttons {Quit|Launch} default Launch escape Quit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if [ $launcherAction == &amp;quot;&amp;quot; ]&lt;br /&gt;
    quit&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if [ $runType == Calibration ]&lt;br /&gt;
    load parameterfile ../parms/calib.prm       # let&#039;s assume you have created this&lt;br /&gt;
else&lt;br /&gt;
    load parameterfile ../parms/free.prm        # and this&lt;br /&gt;
end&lt;br /&gt;
load parameterfile ../parms/$stimulusCondition  # and these&lt;br /&gt;
set parameter SubjectName $subjectName&lt;br /&gt;
setconfig&lt;br /&gt;
show window   # unless you have some other remote-control mechanism for suspending/resuming runs&lt;br /&gt;
set state Running 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The resulting dialog looks like this:&lt;br /&gt;
&lt;br /&gt;
[[File:CustomDialogExample.png]]&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12127</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12127"/>
		<updated>2025-10-08T23:33:23Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* Integrated CUSTOM DIALOG example */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
__FORCETOC__&lt;br /&gt;
&lt;br /&gt;
===CHOOSE ...===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CHOOSE&amp;lt;/code&amp;gt; family of commands prompt the user to specify file or directory paths, via the Qt graphical user interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILE&amp;lt;/code&amp;gt;  (or equivalently &amp;lt;code&amp;gt;CHOOSE FILE&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CHOOSE INPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select a single existing file, and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILES&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE FILES&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select one or more existing files, and prints the resulting file paths one per line (&amp;lt;code&amp;gt;FOR ... IN ...&amp;lt;/code&amp;gt; can iterate over these).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE OUTPUT FILE&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE OUTPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists) and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;&lt;br /&gt;
: Prompts the user to specify a directory, and prints the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
If the user cancels the dialog, the commands print nothing.&lt;br /&gt;
&lt;br /&gt;
The commands may be followed by one or more of the following optional clauses (they must appear in this order):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[OF] TYPE[S] &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This limits the view (via a drop-down file-type selector) to files that have the specified extension(s). This clause cannot be used with &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;.  Instead of a file extension (starting with a dot) you can alternatively specify a glob pattern (containing a star). You can include &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt; (or equivalently &amp;lt;code&amp;gt;*.*&amp;lt;/code&amp;gt;) in the list if you want to give the user the option of overriding the limitation.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[STARTING] AT &amp;lt;dir&amp;gt;&amp;lt;/code&amp;gt; (equivalently you can say &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;FROM&amp;lt;/code&amp;gt; if it reads better)&lt;br /&gt;
: This specifies where the dialog&#039;s file-system navigation should start (by default, it will start in the current working directory).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[WITH] PROMPT &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This specifies the text prompt at the top of the dialog.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
choose file of type .dat from ../data/samplefiles with prompt &amp;quot;Choose a data file for playback:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose output file of type .prm in ../parms with prompt &amp;quot;Save parameters as...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose directory starting at ../data with prompt &amp;quot;Select a subject directory:&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===CUSTOM DIALOG ...===&lt;br /&gt;
&lt;br /&gt;
This command assembles a flexibly customizable modal dialog for communicating with the user. The command returns (prints) a string denoting which button the user pressed to complete the dialog, and as a side effect it may set any environment variables that the command specifies.  If the user cancels the dialog, the command does nothing (prints nothing, does not change any environment variables).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command can be followed by as many clauses as you like. The main types of clause are &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog, in the order you provide. Possible clauses are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Each message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule. Simplest example: &amp;lt;pre&amp;gt;custom dialog message &amp;quot;Hello world!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. For example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used, in conjunction with an empty first/default option, to force the user to make an explicit selection, as in the following example (note the leading &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt; character inside the braces): &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, will be the one that gets highlighted by default and bound to the enter/return keystroke. If you do not specify a default, then &amp;quot;Ok&amp;quot; will be assumed to be the default button. If the designated default does not appear in the list of buttons, the buttons will all have equal status with no return-keystroke binding. The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke, and pressing this button is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).  For most purposes, you will probably not need to override the button configuration explicitly. In dialogs without &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are simply displaying messages to the user), the &amp;lt;code&amp;gt;BUTTONS {Ok} DEFAULT Ok&amp;lt;/code&amp;gt; configuration is assumed. In dialogs with one or more &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are asking the user for information), the &amp;lt;code&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel&amp;lt;/code&amp;gt; configuration is assumed.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TITLE &amp;lt;text&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This overrides the default dialog title &amp;quot;BCI2000&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;SPACING &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical spacing between successive &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; elements.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;WIDTH &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;HEIGHT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum height of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;LEFT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the horizontal coordinate of the dialog&#039;s left edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TOP &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical coordinate of the dialog&#039;s top edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CACHEFILE &amp;lt;FILENAME&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Specifying a cache file allows dialog contents to be made persistent across sessions. If the specified file already exists when the dialog is invoked, the file gets run with &amp;lt;code&amp;gt;EXECUTE SCRIPT&amp;lt;/code&amp;gt;; if this sets any of the dialog&#039;s environment variables, then these new values override the &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; values for the corresponding text fields and drop-down menus. When the dialog is successfully completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button), &amp;lt;code&amp;gt;WRITE ENVIRONMENT&amp;lt;/code&amp;gt; is automatically called to write the corresponding &amp;lt;code&amp;gt;SET ENVIRONMENT&amp;lt;/code&amp;gt; statements to the specified file. So, when the same dialog is invoked again, these settings will be loaded: the user will see whatever settings they entered/chose the previous time.  Example: &amp;lt;pre&amp;gt;custom dialog  cachefile vars.bci  var subjectName &amp;quot;Subject ID:&amp;quot; {} default Nobody minimum 1 &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Integrated &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; example====&lt;br /&gt;
&lt;br /&gt;
The following partial listing illustrates one way &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; might be used to implement a simplified launcher GUI, for a hypothetical auditory BCI experiment.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# [initialize system]&lt;br /&gt;
# [start up modules]&lt;br /&gt;
# [load baseline parameters for this BCI]&lt;br /&gt;
&lt;br /&gt;
set environment launcherAction ${&lt;br /&gt;
    custom dialog &lt;br /&gt;
        title &amp;quot;Auditory BCI Launcher&amp;quot; &lt;br /&gt;
        cachefile &amp;quot;${parent directory $0}/launcherDialogVars.bci&amp;quot;&lt;br /&gt;
        var subjectName &amp;quot;Subject ID:&amp;quot;         {}                                 default &amp;quot;$subjectName&amp;quot; &lt;br /&gt;
        var runType     &amp;quot;Run Type:&amp;quot;           {Calibration|Free Selection}&lt;br /&gt;
        var condition   &amp;quot;Stimulus Condition:&amp;quot; {SlowStimuli.prm|FastStimuli.prm}&lt;br /&gt;
        message &amp;quot;NB: each condition should be calibrated separately.&amp;quot; &lt;br /&gt;
        buttons {Quit|Launch} default Launch escape Quit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if [ $launcherAction == &amp;quot;&amp;quot; ]&lt;br /&gt;
    quit&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if [ $runType == Calibration ]&lt;br /&gt;
    load parameterfile ../parms/calib.prm       # let&#039;s assume you have created this&lt;br /&gt;
else&lt;br /&gt;
    load parameterfile ../parms/free.prm        # and this&lt;br /&gt;
end&lt;br /&gt;
load parameterfile ../parms/$stimulusCondition  # and these&lt;br /&gt;
set parameter SubjectName $subjectName&lt;br /&gt;
setconfig&lt;br /&gt;
show window   # unless you have some other remote-control mechanism for suspending/resuming runs&lt;br /&gt;
set state Running 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The resulting dialog looks like this:&lt;br /&gt;
&lt;br /&gt;
[[File:CustomDialogExample.png]]&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12126</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12126"/>
		<updated>2025-10-08T23:32:29Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* CUSTOM DIALOG ... */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
__FORCETOC__&lt;br /&gt;
&lt;br /&gt;
===CHOOSE ...===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CHOOSE&amp;lt;/code&amp;gt; family of commands prompt the user to specify file or directory paths, via the Qt graphical user interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILE&amp;lt;/code&amp;gt;  (or equivalently &amp;lt;code&amp;gt;CHOOSE FILE&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CHOOSE INPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select a single existing file, and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILES&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE FILES&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select one or more existing files, and prints the resulting file paths one per line (&amp;lt;code&amp;gt;FOR ... IN ...&amp;lt;/code&amp;gt; can iterate over these).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE OUTPUT FILE&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE OUTPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists) and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;&lt;br /&gt;
: Prompts the user to specify a directory, and prints the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
If the user cancels the dialog, the commands print nothing.&lt;br /&gt;
&lt;br /&gt;
The commands may be followed by one or more of the following optional clauses (they must appear in this order):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[OF] TYPE[S] &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This limits the view (via a drop-down file-type selector) to files that have the specified extension(s). This clause cannot be used with &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;.  Instead of a file extension (starting with a dot) you can alternatively specify a glob pattern (containing a star). You can include &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt; (or equivalently &amp;lt;code&amp;gt;*.*&amp;lt;/code&amp;gt;) in the list if you want to give the user the option of overriding the limitation.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[STARTING] AT &amp;lt;dir&amp;gt;&amp;lt;/code&amp;gt; (equivalently you can say &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;FROM&amp;lt;/code&amp;gt; if it reads better)&lt;br /&gt;
: This specifies where the dialog&#039;s file-system navigation should start (by default, it will start in the current working directory).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[WITH] PROMPT &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This specifies the text prompt at the top of the dialog.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
choose file of type .dat from ../data/samplefiles with prompt &amp;quot;Choose a data file for playback:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose output file of type .prm in ../parms with prompt &amp;quot;Save parameters as...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose directory starting at ../data with prompt &amp;quot;Select a subject directory:&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===CUSTOM DIALOG ...===&lt;br /&gt;
&lt;br /&gt;
This command assembles a flexibly customizable modal dialog for communicating with the user. The command returns (prints) a string denoting which button the user pressed to complete the dialog, and as a side effect it may set any environment variables that the command specifies.  If the user cancels the dialog, the command does nothing (prints nothing, does not change any environment variables).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command can be followed by as many clauses as you like. The main types of clause are &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog, in the order you provide. Possible clauses are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Each message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule. Simplest example: &amp;lt;pre&amp;gt;custom dialog message &amp;quot;Hello world!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. For example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used, in conjunction with an empty first/default option, to force the user to make an explicit selection, as in the following example (note the leading &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt; character inside the braces): &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, will be the one that gets highlighted by default and bound to the enter/return keystroke. If you do not specify a default, then &amp;quot;Ok&amp;quot; will be assumed to be the default button. If the designated default does not appear in the list of buttons, the buttons will all have equal status with no return-keystroke binding. The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke, and pressing this button is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).  For most purposes, you will probably not need to override the button configuration explicitly. In dialogs without &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are simply displaying messages to the user), the &amp;lt;code&amp;gt;BUTTONS {Ok} DEFAULT Ok&amp;lt;/code&amp;gt; configuration is assumed. In dialogs with one or more &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are asking the user for information), the &amp;lt;code&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel&amp;lt;/code&amp;gt; configuration is assumed.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TITLE &amp;lt;text&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This overrides the default dialog title &amp;quot;BCI2000&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;SPACING &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical spacing between successive &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; elements.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;WIDTH &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;HEIGHT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum height of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;LEFT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the horizontal coordinate of the dialog&#039;s left edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TOP &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical coordinate of the dialog&#039;s top edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CACHEFILE &amp;lt;FILENAME&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Specifying a cache file allows dialog contents to be made persistent across sessions. If the specified file already exists when the dialog is invoked, the file gets run with &amp;lt;code&amp;gt;EXECUTE SCRIPT&amp;lt;/code&amp;gt;; if this sets any of the dialog&#039;s environment variables, then these new values override the &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; values for the corresponding text fields and drop-down menus. When the dialog is successfully completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button), &amp;lt;code&amp;gt;WRITE ENVIRONMENT&amp;lt;/code&amp;gt; is automatically called to write the corresponding &amp;lt;code&amp;gt;SET ENVIRONMENT&amp;lt;/code&amp;gt; statements to the specified file. So, when the same dialog is invoked again, these settings will be loaded: the user will see whatever settings they entered/chose the previous time.  Example: &amp;lt;pre&amp;gt;custom dialog  cachefile vars.bci  var subjectName &amp;quot;Subject ID:&amp;quot; {} default Nobody minimum 1 &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Integrated &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; example====&lt;br /&gt;
&lt;br /&gt;
The following partial listing illustrates one way &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; might be used to implement a simplified launcher GUI, for a hypothetical auditory BCI experiment.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# [initialize system]&lt;br /&gt;
# [start up modules]&lt;br /&gt;
# [load baseline parameters for this BCI]&lt;br /&gt;
&lt;br /&gt;
set environment launcherAction ${&lt;br /&gt;
    custom dialog &lt;br /&gt;
        title &amp;quot;Auditory BCI Launcher&amp;quot; &lt;br /&gt;
        cachefile &amp;quot;${parent directory $0}/launcherDialogVars.bci&amp;quot;&lt;br /&gt;
        var subjectName       &amp;quot;Subject ID:&amp;quot; {}  default &amp;quot;$subjectName&amp;quot; &lt;br /&gt;
        var runType           &amp;quot;Run Type:&amp;quot;   {Calibration|Free Selection}&lt;br /&gt;
        var stimulusCondition &amp;quot;Stimulus Condition:&amp;quot; {SlowStimuli.prm|FastStimuli.prm}&lt;br /&gt;
        message &amp;quot;NB: each condition should be calibrated separately.&amp;quot; &lt;br /&gt;
        buttons {Quit|Launch} default Launch escape Quit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if [ $launcherAction == &amp;quot;&amp;quot; ]&lt;br /&gt;
    quit&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if [ $runType == Calibration ]&lt;br /&gt;
    load parameterfile ../parms/calib.prm       # let&#039;s assume you have created this&lt;br /&gt;
else&lt;br /&gt;
    load parameterfile ../parms/free.prm        # and this&lt;br /&gt;
end&lt;br /&gt;
load parameterfile ../parms/$stimulusCondition  # and these&lt;br /&gt;
set parameter SubjectName $subjectName&lt;br /&gt;
setconfig&lt;br /&gt;
show window   # unless you have some other remote-control mechanism for suspending/resuming runs&lt;br /&gt;
set state Running 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The resulting dialog looks like this:&lt;br /&gt;
&lt;br /&gt;
[[File:CustomDialogExample.png]]&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12125</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12125"/>
		<updated>2025-10-08T03:31:16Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* CUSTOM DIALOG ... */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
__FORCETOC__&lt;br /&gt;
&lt;br /&gt;
===CHOOSE ...===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CHOOSE&amp;lt;/code&amp;gt; family of commands prompt the user to specify file or directory paths, via the Qt graphical user interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILE&amp;lt;/code&amp;gt;  (or equivalently &amp;lt;code&amp;gt;CHOOSE FILE&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CHOOSE INPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select a single existing file, and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILES&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE FILES&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select one or more existing files, and prints the resulting file paths one per line (&amp;lt;code&amp;gt;FOR ... IN ...&amp;lt;/code&amp;gt; can iterate over these).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE OUTPUT FILE&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE OUTPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists) and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;&lt;br /&gt;
: Prompts the user to specify a directory, and prints the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
If the user cancels the dialog, the commands print nothing.&lt;br /&gt;
&lt;br /&gt;
The commands may be followed by one or more of the following optional clauses (they must appear in this order):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[OF] TYPE[S] &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This limits the view (via a drop-down file-type selector) to files that have the specified extension(s). This clause cannot be used with &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;.  Instead of a file extension (starting with a dot) you can alternatively specify a glob pattern (containing a star). You can include &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt; (or equivalently &amp;lt;code&amp;gt;*.*&amp;lt;/code&amp;gt;) in the list if you want to give the user the option of overriding the limitation.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[STARTING] AT &amp;lt;dir&amp;gt;&amp;lt;/code&amp;gt; (equivalently you can say &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;FROM&amp;lt;/code&amp;gt; if it reads better)&lt;br /&gt;
: This specifies where the dialog&#039;s file-system navigation should start (by default, it will start in the current working directory).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[WITH] PROMPT &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This specifies the text prompt at the top of the dialog.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
choose file of type .dat from ../data/samplefiles with prompt &amp;quot;Choose a data file for playback:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose output file of type .prm in ../parms with prompt &amp;quot;Save parameters as...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose directory starting at ../data with prompt &amp;quot;Select a subject directory:&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===CUSTOM DIALOG ...===&lt;br /&gt;
&lt;br /&gt;
This command assembles a flexibly customizable modal dialog for communicating with the user. The command returns (prints) a string denoting which button the user pressed to complete the dialog, and as a side effect it may set any environment variables that the command specifies.  If the user cancels the dialog, the command does nothing (prints nothing, does not change any environment variables).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command can be followed by as many clauses as you like. The main types of clause are &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog, in the order you provide. Possible clauses are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Each message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule. Simplest example: &amp;lt;pre&amp;gt;custom dialog message &amp;quot;Hello world!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. For example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used, in conjunction with an empty first/default option, to force the user to make an explicit selection, as in the following example (note the leading &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt; character inside the braces): &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, will be the one that gets highlighted by default and bound to the enter/return keystroke. If you do not specify a default, then &amp;quot;Ok&amp;quot; will be assumed to be the default button. If the designated default does not appear in the list of buttons, the buttons will all have equal status with no return-keystroke binding. The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke, and pressing this button is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).  For most purposes, you will probably not need to override the button configuration explicitly. In dialogs without &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are simply displaying messages to the user), the &amp;lt;code&amp;gt;BUTTONS {Ok} DEFAULT Ok&amp;lt;/code&amp;gt; configuration is assumed. In dialogs with one or more &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are asking the user for information), the &amp;lt;code&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel&amp;lt;/code&amp;gt; configuration is assumed.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TITLE &amp;lt;text&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This overrides the default dialog title &amp;quot;BCI2000&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;SPACING &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical spacing between successive &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; elements.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;WIDTH &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;HEIGHT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum height of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;LEFT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the horizontal coordinate of the dialog&#039;s left edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TOP &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical coordinate of the dialog&#039;s top edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CACHEFILE &amp;lt;FILENAME&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Specifying a cache file allows dialog contents to be made persistent across sessions. If the specified file already exists when the dialog is invoked, the file gets run with &amp;lt;code&amp;gt;EXECUTE SCRIPT&amp;lt;/code&amp;gt;; if this sets any of the dialog&#039;s environment variables, then these new values override the &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; values for the corresponding text fields and drop-down menus. When the dialog is successfully completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button), &amp;lt;code&amp;gt;WRITE ENVIRONMENT&amp;lt;/code&amp;gt; is automatically called to write the corresponding &amp;lt;code&amp;gt;SET ENVIRONMENT&amp;lt;/code&amp;gt; statements to the specified file. So, when the same dialog is invoked again, these settings will be loaded: the user will see whatever settings they entered/chose the previous time.&lt;br /&gt;
&lt;br /&gt;
====Integrated &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; example====&lt;br /&gt;
&lt;br /&gt;
The following partial listing illustrates one way &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; might be used to implement a simplified launcher GUI, for a hypothetical auditory BCI experiment.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# [initialize system]&lt;br /&gt;
# [start up modules]&lt;br /&gt;
# [load baseline parameters for this BCI]&lt;br /&gt;
# [optionally, you could pre-initialize environment variables subjectName, runType and stimulusCondition]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
set environment launcherAction ${&lt;br /&gt;
    custom dialog &lt;br /&gt;
        title &amp;quot;Auditory BCI Launcher&amp;quot; &lt;br /&gt;
        var subjectName &amp;quot;Subject ID:&amp;quot; {} default $subjectName minimum 1 &lt;br /&gt;
        var runType &amp;quot;Run Type:&amp;quot; {Calibration|Free Selection} default $runType &lt;br /&gt;
        var stimulusCondition &amp;quot;Stimulus Condition:&amp;quot; {SlowStimuli.prm|FastStimuli.prm} default $stimulusCondition &lt;br /&gt;
        message &amp;quot;NB: each condition should be calibrated separately.&amp;quot; &lt;br /&gt;
        buttons {Quit|Launch} default Launch escape Quit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if [ $launcherAction == &amp;quot;&amp;quot; ]&lt;br /&gt;
    quit&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if [ $runType == Calibration ]&lt;br /&gt;
    load parameterfile ../parms/calib.prm       # let&#039;s assume you have created this&lt;br /&gt;
else&lt;br /&gt;
    load parameterfile ../parms/free.prm        # and this&lt;br /&gt;
end&lt;br /&gt;
load parameterfile ../parms/$stimulusCondition  # and these&lt;br /&gt;
set parameter SubjectName $subjectName&lt;br /&gt;
setconfig&lt;br /&gt;
show window   # unless you have some other remote-control mechanism for suspending/resuming runs&lt;br /&gt;
set state Running 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The resulting dialog looks like this:&lt;br /&gt;
&lt;br /&gt;
[[File:CustomDialogExample.png]]&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12124</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12124"/>
		<updated>2025-10-08T03:30:30Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* CUSTOM DIALOG ... */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
__FORCETOC__&lt;br /&gt;
&lt;br /&gt;
===CHOOSE ...===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CHOOSE&amp;lt;/code&amp;gt; family of commands prompt the user to specify file or directory paths, via the Qt graphical user interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILE&amp;lt;/code&amp;gt;  (or equivalently &amp;lt;code&amp;gt;CHOOSE FILE&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CHOOSE INPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select a single existing file, and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILES&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE FILES&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select one or more existing files, and prints the resulting file paths one per line (&amp;lt;code&amp;gt;FOR ... IN ...&amp;lt;/code&amp;gt; can iterate over these).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE OUTPUT FILE&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE OUTPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists) and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;&lt;br /&gt;
: Prompts the user to specify a directory, and prints the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
If the user cancels the dialog, the commands print nothing.&lt;br /&gt;
&lt;br /&gt;
The commands may be followed by one or more of the following optional clauses (they must appear in this order):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[OF] TYPE[S] &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This limits the view (via a drop-down file-type selector) to files that have the specified extension(s). This clause cannot be used with &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;.  Instead of a file extension (starting with a dot) you can alternatively specify a glob pattern (containing a star). You can include &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt; (or equivalently &amp;lt;code&amp;gt;*.*&amp;lt;/code&amp;gt;) in the list if you want to give the user the option of overriding the limitation.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[STARTING] AT &amp;lt;dir&amp;gt;&amp;lt;/code&amp;gt; (equivalently you can say &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;FROM&amp;lt;/code&amp;gt; if it reads better)&lt;br /&gt;
: This specifies where the dialog&#039;s file-system navigation should start (by default, it will start in the current working directory).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[WITH] PROMPT &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This specifies the text prompt at the top of the dialog.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
choose file of type .dat from ../data/samplefiles with prompt &amp;quot;Choose a data file for playback:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose output file of type .prm in ../parms with prompt &amp;quot;Save parameters as...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose directory starting at ../data with prompt &amp;quot;Select a subject directory:&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===CUSTOM DIALOG ...===&lt;br /&gt;
&lt;br /&gt;
This command assembles a flexibly customizable modal dialog for communicating with the user. The command returns (prints) a string denoting which button the user pressed to complete the dialog, and as a side effect it may set any environment variables that the command specifies.  If the user cancels the dialog, the command does nothing (prints nothing, does not change any environment variables).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command can be followed by as many clauses as you like. The main types of clause are &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog, in the order you provide. Possible clauses are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Each message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule. Simplest example: &amp;lt;pre&amp;gt;custom dialog message &amp;quot;Hello world!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. For example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used, in conjunction with an empty first/default option, to force the user to make an explicit selection, as in the following example (note the leading &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt; character inside the braces): &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, will be the one that gets highlighted by default and bound to the enter/return keystroke. If you do not specify a default, then &amp;quot;Ok&amp;quot; will be assumed to be the default button. If the designated default does not appear in the list of buttons, the buttons will all have equal status with no return-keystroke binding. The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke, and pressing this button is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).  For most purposes, you will probably not need to override the button configuration explicitly. In dialogs without &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are simply displaying messages to the user), the &amp;lt;code&amp;gt;BUTTONS {Ok} DEFAULT Ok&amp;lt;/code&amp;gt; configuration is assumed. In dialogs with one or more &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are asking the user for information), the &amp;lt;code&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel&amp;lt;/code&amp;gt; configuration is assumed.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TITLE &amp;lt;text&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This overrides the default dialog title &amp;quot;BCI2000&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;SPACING &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical spacing between successive &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; elements.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;WIDTH &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;HEIGHT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum height of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;LEFT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the horizontal coordinate of the dialog&#039;s left edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TOP &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical coordinate of the dialog&#039;s top edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CACHEFILE &amp;lt;FILENAME&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Specifying a cache file allows dialog contents to be made persistent across sessions. If the specified file already exists when the dialog is invoked, the file gets run with &amp;lt;code&amp;gt;EXECUTE SCRIPT&amp;lt;/code&amp;gt;; if this sets any of the dialog&#039;s environment variables, then these new values override the &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; values for the corresponding text fields and drop-down menus. When the dialog is successfully completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button), &amp;lt;code&amp;gt;WRITE ENVIRONMENT&amp;lt;/code&amp;gt; is automatically called to write the corresponding &amp;lt;code&amp;gt;SET ENVIRONMENT&amp;lt;/code&amp;gt; statements to the specified file. So, when the same dialog is invoked again, these settings will be loaded: the user will see whatever settings they entered/chose the previous time.&lt;br /&gt;
&lt;br /&gt;
====Integrated &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; example====&lt;br /&gt;
&lt;br /&gt;
The following partial listing illustrates one way &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; might be used to implement a simplified launcher GUI, for a hypothetical auditory BCI experiment.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# [initialize system]&lt;br /&gt;
# [start up modules]&lt;br /&gt;
# [load baseline parameters for this BCI]&lt;br /&gt;
# [optionally, you could pre-initialize environment variables subjectName, runType and stimulusCondition]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
set environment launcherAction ${&lt;br /&gt;
    custom dialog &lt;br /&gt;
        title &amp;quot;Auditory BCI Launcher&amp;quot; &lt;br /&gt;
        var subjectName &amp;quot;Subject ID:&amp;quot; {} default $subjectName minimum 1 &lt;br /&gt;
        var runType &amp;quot;Run Type:&amp;quot; {Calibration|Free Selection} default $runType &lt;br /&gt;
        var stimulusCondition &amp;quot;Stimulus Condition:&amp;quot; {SlowStimuli.prm|FastStimuli.prm} default $stimulusCondition &lt;br /&gt;
        message &amp;quot;NB: each condition should be calibrated separately.&amp;quot; &lt;br /&gt;
        buttons {Quit|Launch} default Launch escape Quit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if [ $launcherAction == &amp;quot;&amp;quot; ]&lt;br /&gt;
    quit&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if [ $runType == Calibration ]&lt;br /&gt;
    load parameterfile ../parms/calib.prm       # let&#039;s assume you have created this&lt;br /&gt;
else&lt;br /&gt;
    load parameterfile ../parms/free.prm        # and this&lt;br /&gt;
end&lt;br /&gt;
load parameterfile ../parms/$stimulusCondition  # and these&lt;br /&gt;
set parameter SubjectName $subjectName&lt;br /&gt;
setconfig&lt;br /&gt;
show window   # unless you have some other remote-control mechanism for suspending/resuming runs&lt;br /&gt;
set state Running 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The resulting dialog looks like this:&lt;br /&gt;
&lt;br /&gt;
[[File:CustomDialogExample.png]]&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Operator_Module_Scripting&amp;diff=12120</id>
		<title>User Reference:Operator Module Scripting</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Operator_Module_Scripting&amp;diff=12120"/>
		<updated>2025-10-04T00:35:06Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* Commands operating on Environment Variables */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Operator scripts automate actions that the otherwise would be performed by the user, e.g. starting or suspending system operation.&lt;br /&gt;
Scripts may be contained in script files, or given immediately in the operator module&#039;s preferences dialog.&lt;br /&gt;
There is also an option to specify scripts from the [[User Reference:Module Command Line Options#Operator Module|command line]] when starting the operator module. When using the [[User_Reference:BCI2000Shell|BCI2000Shell]], or the [[Technical_Reference:Operator_Library|Operator Library]] from your own application, you may execute scripts at any time.&lt;br /&gt;
&lt;br /&gt;
In addition, the operator scripting language may be used to control an operator module over a [[User_Reference:Module_Command_Line_Options#--Telnet|Telnet]] or [[User_Reference:Module_Command_Line_Options#--WebSocket|WebSocket]] connection.&lt;br /&gt;
===Syntax===&lt;br /&gt;
&#039;&#039;&#039;Command separation.&#039;&#039;&#039; Scripts consist of sequences of the commands listed below. A command must be terminated with either a newline, or a semicolon (;).&lt;br /&gt;
This allows to put multiple commands into one line, separated by semicolon characters.&lt;br /&gt;
Commands are case-insensitive, variables and values may be case-sensitive, depending on context.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Comments.&#039;&#039;&#039; Lines starting with a &#039;#&#039; character are ignored. Such lines may be used to hold comments. In addition, when any of the first two lines of a script contains &amp;quot;#!&amp;quot; (the Unix shell invocation sequence), it will be ignored. In conjunction with [[User Reference:BCI2000Shell|BCI2000Shell]], this may be used to write Operator scripts that may be treated as executables.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Escaping.&#039;&#039;&#039; In order to resolve ambiguity about command arguments that contain white space, they must be included in double quotes, or the white space must be encoded in URL-fashion, e.g. &#039;&#039;%20&#039;&#039; instead of a space character. Similarly, when an argument contains a semicolon (;), it must be included in double quotes, or the semicolon must be encoded in URL-fashion, i.e. as &#039;&#039;%3B&#039;&#039;. Also, &amp;quot;$&amp;quot; characters indicate command substitution, so they should be encoded as &#039;&#039;%24&#039;&#039; if substitution is not desired.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Variable Substitution.&#039;&#039;&#039; When a command contains a dollar sign, alphanumeric characters following the dollar sign will be interpreted as the name of a variable: $NAME. The name will be matched against Expression variable names first, followed with Local variable names, and finally Environment variable names. When a match is found, $NAME will be replaced with the content of the matching variable. When no match is found, $NAME will be resolved to an empty string, without triggering an error.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Command Substitution.&#039;&#039;&#039; When part of a command is enclosed with ${...}, this subexpression will be substituted with the result of its execution as a command. E.g.,&lt;br /&gt;
 LOG &amp;quot;Current system state is: ${GET SYSTEM STATE}&amp;quot;&lt;br /&gt;
 LOG &amp;quot;The path environment variable is: ${PATH}&amp;quot;&lt;br /&gt;
Note that the last example uses the short form of the GET command, which will return the value of a PATH parameter or a PATH state if such exists. To make sure that only environment variables are matched, use the long form of the GET command:&lt;br /&gt;
 LOG MESSAGE &amp;quot;The path environment variable is: ${GET VARIABLE PATH}&amp;quot;&lt;br /&gt;
Substitutions may be nested, i.e. the following will work as expected:&lt;br /&gt;
 SET MyVar &amp;quot;LIST STATES&amp;quot;; LOG &amp;quot;States are: ${$MyVar}&amp;quot;&lt;br /&gt;
 SET MyVar &amp;quot;LIST STATES&amp;quot;; LOG &amp;quot;States are: ${${GET VARIABLE MyVar}}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Mathematical Expressions.&#039;&#039;&#039; A command may consist of a single [[User Reference:Expression Syntax|mathematical expression]]. This expression is then evaluated, and its result is returned as the command&#039;s result. As a special case, this allows the use of expression variables in ${...} substitutions. Consider for example&lt;br /&gt;
 x:=0; WHILE x&amp;lt;10; LOG ${x:=x+1}; END&lt;br /&gt;
There, the first command creates and initializes the expression variable x. In the WHILE condition, an expression is allowed as well as any command. In the LOG command, an expression appears in ${...}, which executes the expression in braces, and substitutes the result of the expression as an argument into the LOG command, which adds an entry to the Operator log. This results in a sequence of 10 log entries, containing the numbers from 1 to 10.&lt;br /&gt;
&lt;br /&gt;
===Commands===&lt;br /&gt;
====Control commands====&lt;br /&gt;
These commands allow conditional execution of parts of a script. When a condition is expected, any other scripting command may be given. Its result will be considered to represent a boolean value of &amp;quot;true&amp;quot; if it is empty, a nonzero number, or the string &amp;quot;true&amp;quot;. It will be taken to represent a boolean value of &amp;quot;false&amp;quot; if it contains a numeric value of zero, or any string that does not evaluate to a nonzero number. Note that identification of an empty value with &amp;quot;true&amp;quot; differs from string handling in the EVALUATE CONDITION command. This is because most scripting commands return nothing on success, but an error message on failure.&lt;br /&gt;
&lt;br /&gt;
The output of the SYSTEM and START EXECUTABLE commands is handled specially. There, the result code of the created child process is translated into a boolean value in the ordinary manner, treating a result code of zero as &amp;quot;true&amp;quot;, and any other result code as &amp;quot;false&amp;quot;. This allows to use external commands in the same way as in a native shell.&lt;br /&gt;
&lt;br /&gt;
=====IF &amp;lt;condition&amp;gt;; &amp;lt;if commands&amp;gt;; [ ELSEIF &amp;lt;condition&amp;gt;; &amp;lt;elseif commands&amp;gt;;] ... [ ELSE; &amp;lt;else commands&amp;gt;;] END=====&lt;br /&gt;
Executes &#039;&#039;if commands&#039;&#039; if &#039;&#039;condition&#039;&#039; evaluates to &amp;quot;true&amp;quot;. Otherwise, the &#039;&#039;elseif commands&#039;&#039; of the first matching &#039;&#039;elseif condition&#039;&#039; are executed. When none of the &#039;&#039;elseif conditions&#039;&#039; evaluates to &amp;quot;true&amp;quot;,  &#039;&#039;else commands&#039;&#039; are executed. ELSEIF and ELSE blocks may be omitted.&lt;br /&gt;
&lt;br /&gt;
=====WHILE &amp;lt;condition&amp;gt;; &amp;lt;loop commands&amp;gt;; END=====&lt;br /&gt;
Executes &#039;&#039;loop commands&#039;&#039; while &#039;&#039;condition&#039;&#039; evaluates to &#039;&#039;true&#039;&#039;.&lt;br /&gt;
=====DO; &amp;lt;loop commands&amp;gt;; UNTIL &amp;lt;condition&amp;gt;=====&lt;br /&gt;
Executes &#039;&#039;loop commands&#039;&#039; until &amp;quot;condition&amp;quot; evaluates to &#039;&#039;true&#039;&#039;.&lt;br /&gt;
=====FOR &amp;lt;name&amp;gt; IN &amp;lt;item1&amp;gt; &amp;lt;item2&amp;gt; ... ; &amp;lt;loop commands&amp;gt;; END=====&lt;br /&gt;
Creates a local variable with the specified name. Then, sequentially assigns each &#039;&#039;item&#039;&#039; to that variable, and executes &#039;&#039;loop commands&#039;&#039;. If an &#039;&#039;item&#039;&#039; contains newline characters, it is split up into multiple items, corresponding to the lines contained in the &#039;&#039;item&#039;&#039;. E.g.,&lt;br /&gt;
 FOR i IN top ${LIST FILES} bottom; LOG ${i}; END&lt;br /&gt;
will first write a log entry &amp;quot;top&amp;quot;. Then, it will create a log entry for each file in the current directory, and finally, it will create a log entry &amp;quot;bottom&amp;quot;.&lt;br /&gt;
=====RETURN [&amp;lt;value&amp;gt;]=====&lt;br /&gt;
Finishes execution of the current script, and optionally returns a value to the caller.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on Conditions====&lt;br /&gt;
=====EVALUATE CONDITION &amp;lt;left&amp;gt; [&amp;lt;op&amp;gt; [&amp;lt;right&amp;gt;]]=====&lt;br /&gt;
Evaluates a comparison between the &#039;&#039;left&#039;&#039; and &#039;&#039;right&#039;&#039; operands. As a comparison operator, the following may be specified: ==, !=, ~=, &amp;lt;, &amp;gt;, &amp;lt;=, &amp;gt;=. There, the != operator behaves identically to the ~= operator. When a test for equality is performed, the two operands are treated as strings, and compared in a case-insensitive manner. When any of the inequality tests is performed, the two operands are converted into floating-point numbers before comparison.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;right&#039;&#039; operand may be omitted, in which case it is treated as if an empty string were specified. Also, the &#039;&#039;op&#039;&#039; operator may be omitted, in which case the following rules apply regarding the remaining operand: If it is an empty string, or equal to the string &amp;quot;false&amp;quot; in case-insensitive comparison, the result is &amp;quot;false&amp;quot;. If entirely consists of the text representation of a floating-point number, the result is &amp;quot;false&amp;quot; if the number is 0, and &amp;quot;true&amp;quot; if the number is not 0.&lt;br /&gt;
&lt;br /&gt;
Inspired by the unix sh shells&#039; &amp;lt;tt&amp;gt;test&amp;lt;/tt&amp;gt; command, there exists a short form of the EVALUATE CONDITION command, where the arguments of EVALUATE CONDITION may appear within square brackets. This allows constructs such as&lt;br /&gt;
 IF [ ${MyVar} == MyValue ]; LOG Is equal; ELSE; LOG Is different; END&lt;br /&gt;
Note that the arguments to EVALUATE CONDITION must always be separated by white space, no matter whether its long or short form is used.&lt;br /&gt;
&lt;br /&gt;
Conditions may be combined logically using the operators &amp;amp;&amp;amp; and ||.   These go &#039;&#039;outside&#039;&#039; the square brackets.  Note also that whitespace around the comparison operators is critical, otherwise the conditional will be treated as a single string (which will always evaluate to &amp;quot;true&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
 IF [ ${foo} == foo ] || [ ${bar} == bar ]; LOG got a match; END&lt;br /&gt;
&lt;br /&gt;
====Commands operating on Local Variables====&lt;br /&gt;
Besides environment variables, there exist local variables in scripts. Local variables are inherited by sub-scripts executed with the EXECUTE SCRIPT command, but changes to the variable&#039;s values will not be propagated to the calling script.&lt;br /&gt;
=====SET VARIABLE &amp;lt;name&amp;gt; &amp;lt;value&amp;gt;=====&lt;br /&gt;
Sets the named variable to the specified value.&lt;br /&gt;
=====CLEAR VARIABLE &amp;lt;name&amp;gt;=====&lt;br /&gt;
Removes the named variable from memory.&lt;br /&gt;
=====GET VARIABLE &amp;lt;name&amp;gt;=====&lt;br /&gt;
Returns the variable&#039;s current value. When the variable does not exist, an empty value is returned rather than an error message generated.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on Environment Variables====&lt;br /&gt;
These scripting commands allow to read and modify environment variables. Changes to environment variables will be visible to child processes started with SYSTEM or START EXECUTABLE. Variable values are stored as strings. Variable names may not contain the equals sign.&lt;br /&gt;
=====SET ENVIRONMENT &amp;lt;name&amp;gt; &amp;lt;value&amp;gt;=====&lt;br /&gt;
Sets the named variable to the specified value.&lt;br /&gt;
=====CLEAR ENVIRONMENT &amp;lt;name&amp;gt;=====&lt;br /&gt;
Removes the named variable from memory.&lt;br /&gt;
=====GET ENVIRONMENT &amp;lt;name&amp;gt;=====&lt;br /&gt;
Returns the variable&#039;s current value. When the variable does not exist, an empty value is returned rather than an error message.&lt;br /&gt;
=====WRITE ENVIRONMENT &amp;lt;fileName&amp;gt; &amp;lt;variableName1&amp;gt; &amp;lt;variableName2&amp;gt; ...=====&lt;br /&gt;
Writes a series of SET ENVIRONMENT statements to the specified file, overwriting any previous file contents.  This saves the values of the named variables in such a way that you can later load them back by calling EXECUTE SCRIPT &amp;lt;filename&amp;gt;. The variable names may refer to either local or environment variables at the time of writing, but when you execute the script they will all be loaded as environment variables.&lt;br /&gt;
=====APPEND ENVIRONMENT &amp;lt;fileName&amp;gt; &amp;lt;variableName1&amp;gt; &amp;lt;variableName2&amp;gt; ...=====&lt;br /&gt;
This is the same as WRITE ENVIRONMENT, except that the SET ENVIRONMENT statements are appended to the named file without overwriting its previous contents.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on Scripts====&lt;br /&gt;
=====SET SCRIPT &amp;lt;handler names&amp;gt; &amp;lt;scripting commands&amp;gt;=====&lt;br /&gt;
Associates a sequence of scripting commands with the named handler. Handlers are specified by names as given [[#Handlers|below]]. Multiple handlers may be specified by concatenating their names with a pipe character, e.g. &amp;quot;OnStart|OnResume&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Scripting commands must be included in double quotes, unless they consist of a single word.&lt;br /&gt;
When specifying a sequence of scripting commands, they must be separated with a semicolon character: &amp;quot;SetConfig; Start&amp;quot;. In order to use double quotes or semicolons within the commands themselves, encode these as you would in a URL, i.e. replace a double quote character with &#039;&#039;%22&#039;&#039;, and a semicolon with &#039;&#039;%3B&#039;&#039;: &amp;quot;Load Parameters %22my file%22&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
To use a script file rather than a literal script, use the EXECUTE SCRIPT command:&lt;br /&gt;
 SET SCRIPT OnConnect &amp;quot;EXECUTE SCRIPT myscript.txt&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=====GET SCRIPT &amp;lt;handler name&amp;gt;=====&lt;br /&gt;
Returns the script associated with the specified handler.&lt;br /&gt;
&lt;br /&gt;
=====CLEAR SCRIPT &amp;lt;handler names&amp;gt;=====&lt;br /&gt;
Clears scripts for the given handlers. Equivalent to calling SET SCRIPT with an empty script.&lt;br /&gt;
&lt;br /&gt;
=====EXECUTE SCRIPT &amp;lt;file or handler name&amp;gt; [&amp;lt;Arg1&amp;gt; &amp;lt;Arg2&amp;gt; ... &amp;lt;Arg9&amp;gt;]=====&lt;br /&gt;
Executes a script contained in a file, and optionally sets the script&#039;s local variables &#039;&#039;1&#039;&#039; to &#039;&#039;9&#039;&#039; to the specified values. To execute script commands already associated with a handler, provide a handler name rather than a file. When the script is executed successfully, the result of the last executed script command becomes the result of the EXECUTE SCRIPT command itself. Use &amp;quot;RETURN &amp;lt;value&amp;gt;&amp;quot; anywhere in a script in order to finish execution, and return a certain value.&lt;br /&gt;
&lt;br /&gt;
When you run a script through EXECUTE SCRIPT, it will inherit copies of variables from its calling script/command line. Modifications of variables will be local to the script, and will be lost when script execution is complete.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;AbortOnError&#039;&#039; variable determines whether a script is aborted when any of its commands result in an error message. &#039;&#039;AbortOnError&#039;&#039; is not inherited but defaults to 1 in any script.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on Parameters====&lt;br /&gt;
=====LOAD PARAMETERFILE &amp;lt;file&amp;gt;, LOAD PARAMETERS &amp;lt;file&amp;gt;=====&lt;br /&gt;
Loads a parameter file specified by its path and name. Relative paths are interpreted relative to the operator module&#039;s working directory at startup. Usually, this matches the executable&#039;s location in the &amp;lt;tt&amp;gt;prog&amp;lt;/tt&amp;gt; directory.&lt;br /&gt;
As the parameter file name must not contain white space, please use HTML-type encoding for white space characters, such as &amp;lt;tt&amp;gt;Documents%20and%20Settings&amp;lt;/tt&amp;gt; when referring to a user&#039;s &amp;quot;Documents and Settings&amp;quot; folder.&lt;br /&gt;
&lt;br /&gt;
NOTE: Only those parameters will be loaded that do exist at the time when this command is called. In idle state, no parameters exist other than created by ADD PARAMETER. After modules are connected and have published their parameters to the Operator module, a full set of parameters exists.&lt;br /&gt;
&lt;br /&gt;
=====ADD PARAMETER &amp;lt;parameter definition&amp;gt;=====&lt;br /&gt;
Adds a parameter to the system. The parameter is specified as a [[Technical_Reference:Parameter_Definition#Parameter_Lines|parameter line]]. This command may not be used after system initialization has completed, i.e. its use is restricted to the &amp;quot;Idle&amp;quot; and &amp;quot;Publishing&amp;quot; [[Technical_Reference:States_of_Operation#Publishing_Phase|phases of system operation]]. In terms of handlers, its use is restricted to the &#039;&#039;OnConnect&#039;&#039; handler.&lt;br /&gt;
=====EXISTS PARAMETER &amp;lt;name&amp;gt;=====&lt;br /&gt;
Returns &amp;quot;true&amp;quot; when the specified parameter exists in the system, and &amp;quot;false&amp;quot; otherwise.&lt;br /&gt;
&lt;br /&gt;
=====ISEMPTY PARAMETER &amp;lt;name&amp;gt;=====&lt;br /&gt;
Returns &amp;quot;true&amp;quot; when the specified parameter exists and has no values, &amp;quot;false&amp;quot; if it exists and has values.&lt;br /&gt;
&lt;br /&gt;
=====SET PARAMETER &amp;lt;name&amp;gt;[( idx1, idx2 )] &amp;lt;value&amp;gt;=====&lt;br /&gt;
Sets the named parameter to the specified value. Values that contain special characters, or whitespace must use the [[Technical_Reference:Parameter_Definition#Special_Characters|parameter value encoding]]. Use parentheses to specify indices or labels. Omitted indices default to 1.&lt;br /&gt;
&lt;br /&gt;
=====SET PARAMETER &amp;lt;parameter line&amp;gt;=====&lt;br /&gt;
Replace a parameter&#039;s value and definition with the information given in the [[Technical_Reference:Parameter_Definition#Parameter_Lines|parameter line]]. The parameter must exist in the system when this command is executed.&lt;br /&gt;
&lt;br /&gt;
=====GET PARAMETER &amp;lt;name&amp;gt;[( idx1, idx2 )]=====&lt;br /&gt;
Prints the value of the named parameter. Use parentheses to specify indices or labels.&lt;br /&gt;
&lt;br /&gt;
=====SET PARAMETERROWS &amp;lt;parameter name&amp;gt; &amp;lt;rows&amp;gt;=====&lt;br /&gt;
Sets the number of rows in the named parameter.&lt;br /&gt;
&lt;br /&gt;
=====GET PARAMETERROWS &amp;lt;parameter name&amp;gt;=====&lt;br /&gt;
Prints the number of rows in the named parameter.&lt;br /&gt;
&lt;br /&gt;
=====SET PARAMETERCOLS &amp;lt;parameter name&amp;gt;=====&lt;br /&gt;
Sets the number of columns in the named parameter.&lt;br /&gt;
&lt;br /&gt;
=====GET PARAMETERCOLS &amp;lt;parameter name&amp;gt;=====&lt;br /&gt;
Prints the number of columns in the named parameter.&lt;br /&gt;
&lt;br /&gt;
=====LIST PARAMETER &amp;lt;wildcard expression&amp;gt;, LIST PARAMETERS=====&lt;br /&gt;
Prints all parameters with names matching the wildcard expression, in form of parameter lines.&lt;br /&gt;
=====CLEAR PARAMETERS=====&lt;br /&gt;
Clears the list of parameters in the system. May only be executed in &#039;&#039;Idle&#039;&#039; and &#039;&#039;Publishing&#039;&#039; system states.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on States====&lt;br /&gt;
In BCI2000, there are three types of States that differ in their alignment to brain signal data (see [[Technical_Reference:State_Definition#Kinds_of_States|Kinds of States]]). This section applies to both Stream States, and normal States.&lt;br /&gt;
For Event States, see the next section.&lt;br /&gt;
&lt;br /&gt;
=====ADD STATE &amp;lt;name&amp;gt; &amp;lt;bit width&amp;gt; &amp;lt;initial value&amp;gt;=====&lt;br /&gt;
Adds a state variable to the system. State variables are defined by name, bit width, and initial value (see [[Technical Reference:State Definition]]). This command may not be used after system initialization has completed, i.e. its use is restricted to the &amp;quot;Idle&amp;quot; and &amp;quot;Publishing&amp;quot; [[Technical_Reference:States_of_Operation#Publishing_Phase|phases of system operation]]. In terms of handlers, its use is restricted to the &#039;&#039;OnConnect&#039;&#039; handler.&lt;br /&gt;
=====EXISTS STATE &amp;lt;name&amp;gt;=====&lt;br /&gt;
Returns &amp;quot;true&amp;quot; when the specified state exists in the system, and &amp;quot;false&amp;quot; otherwise.&lt;br /&gt;
&lt;br /&gt;
=====SET STATE &amp;lt;name&amp;gt; &amp;lt;value&amp;gt;, SET STATES &amp;lt;name1&amp;gt; &amp;lt;value1&amp;gt; &amp;lt;name2&amp;gt; &amp;lt;value2&amp;gt; ...=====&lt;br /&gt;
Sets the named state variable to the specified integer value by sending a state message to the source module.&lt;br /&gt;
Setting the &#039;&#039;Running&#039;&#039; state to 1 will start system operation, setting it to 0 will suspend the system.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;SET STATES&amp;lt;/tt&amp;gt; will atomically set the values of multiple states.&lt;br /&gt;
&lt;br /&gt;
=====GET STATE[(&amp;lt;sample&amp;gt;)] &amp;lt;name&amp;gt;=====&lt;br /&gt;
Gets the value of the named state. Note that state values are not updated from the application module when the &#039;&#039;OperatorBackLink&#039;&#039; parameter is 0. In that case, GET STATE will return the state&#039;s initial value.&lt;br /&gt;
&lt;br /&gt;
An optional one-based sample index may be given to indicate that the state value should be retrieved at the given sample position. Sample positions range from 1 to the number of samples per block present in the state vector. The number of samples per block may be retrieved using GET STATEVECTOR SAMPLES.&lt;br /&gt;
&lt;br /&gt;
By default, the state&#039;s value is retrieved for sample index 1.&lt;br /&gt;
&lt;br /&gt;
=====LIST STATE &amp;lt;wildcard expression&amp;gt;, LIST STATES=====&lt;br /&gt;
Lists all states, or states with names matching the given wildcard expression, in form of state lines.&lt;br /&gt;
=====CLEAR STATES=====&lt;br /&gt;
Clears the list of states in the system. May only be executed in &#039;&#039;Idle&#039;&#039; and &#039;&#039;Publishing&#039;&#039; system states.&lt;br /&gt;
&lt;br /&gt;
=====FREEZE STATES, THAW STATES=====&lt;br /&gt;
Freezes/thaws the values of all states in the state vector, without interfering with system operation.  &amp;quot;Freezing&amp;quot; creates, and &amp;quot;thawing&amp;quot; discards, a frozen snapshot of the state vector. For the duration of its existence, GET STATE calls will be diverted to the snapshot.  This is useful for ensuring that multiple GET STATE commands actually retrieve mutually-consistent values from different state variables (i.e. values from the same sample-block).&lt;br /&gt;
&lt;br /&gt;
=====GET STATEVECTOR SAMPLES=====&lt;br /&gt;
Returns the number of samples in the state vector per block of data. In the system&#039;s &amp;quot;Running&amp;quot; state, this matches the number of samples per block in the source data. Prior to the &amp;quot;Running&amp;quot; state, this command returns 1 because the state vector has not yet been updated from the application module.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on Events====&lt;br /&gt;
Events are a special type of state, which are recorded asynchronously, at single-sample resolution. Events may only be added while the system is in &amp;quot;idle&amp;quot; state. This kind of events is not related to [[#Handlers|Operator Events]] as defined below.&lt;br /&gt;
=====ADD EVENT &amp;lt;name&amp;gt; &amp;lt;bit width&amp;gt; &amp;lt;initial value&amp;gt;=====&lt;br /&gt;
Adds an event to the system. Like state variables, events are defined by name, bit width, and initial value (see [[Technical Reference:State Definition]]). This command may not be used after the system has started up, so it is typically executed in a batch file before &#039;&#039;STARTUP&#039;&#039; has been called.&lt;br /&gt;
&lt;br /&gt;
=====EXISTS EVENT &amp;lt;name&amp;gt;=====&lt;br /&gt;
Returns &amp;quot;true&amp;quot; when the specified event exists in the system, and &amp;quot;false&amp;quot; otherwise.&lt;br /&gt;
&lt;br /&gt;
=====SET EVENT &amp;lt;name&amp;gt; &amp;lt;value&amp;gt;=====&lt;br /&gt;
Asynchronously sets an event to the given value. Recording events requires the EventLink logger component to be present in the source module.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In versions prior to BCI2000 3.06, this command behaved as described for PULSE EVENT below, rather than as advertised. If you used SET EVENT in your scripts, it is recommended to replace it with PULSE EVENT in order to retain original behavior.&lt;br /&gt;
&lt;br /&gt;
=====PULSE EVENT &amp;lt;name&amp;gt; &amp;lt;value&amp;gt;=====&lt;br /&gt;
Asynchronously sets an event to the given value for a single sample duration. Recording events requires the EventLink logger component to be present in the source module.&lt;br /&gt;
&lt;br /&gt;
=====SET EVENTS [&amp;lt;name&amp;gt; &amp;lt;value&amp;gt;] [&amp;lt;name2&amp;gt; &amp;lt;value2&amp;gt;] ... =====&lt;br /&gt;
Asynchronously sets given events to their specified values. Using this command, rather than multiple SET EVENT commands in a row, ensures that all event changes are recorded at exactly the same point in time. Recording events requires the EventLink logger component to be present in the source module.&lt;br /&gt;
&lt;br /&gt;
=====PULSE EVENTS [&amp;lt;name&amp;gt; &amp;lt;value&amp;gt;] [&amp;lt;name2&amp;gt; &amp;lt;value2&amp;gt;] ... =====&lt;br /&gt;
Asynchronously sets given events to their specified values for a single sample duration. Using this command, rather than multiple PULSE EVENT commands in a row, ensures that all event changes are recorded at exactly the same point in time. Recording events requires the EventLink logger component to be present in the source module.&lt;br /&gt;
&lt;br /&gt;
=====GET EVENT[(&amp;lt;sample&amp;gt;)] &amp;lt;name&amp;gt;=====&lt;br /&gt;
Gets the value of the named event. Note that evemt values are not updated from the application module when the &#039;&#039;OperatorBackLink&#039;&#039; parameter is 0.&lt;br /&gt;
&lt;br /&gt;
An optional one-based sample index may be given to indicate that the event&#039;s value should be retrieved at the given sample position. Sample positions range from 1 to the number of samples per block present in the state vector. The number of samples per block may be retrieved using GET STATEVECTOR SAMPLES.&lt;br /&gt;
&lt;br /&gt;
By default, the event&#039;s value is retrieved for sample index 1.&lt;br /&gt;
&lt;br /&gt;
=====LIST EVENT &amp;lt;wildcard expression&amp;gt;, LIST EVENTS=====&lt;br /&gt;
Lists all events, or events with names matching the given wildcard expression, in form of state lines.&lt;br /&gt;
=====CLEAR EVENTS=====&lt;br /&gt;
Clears the list of events in the system. May only be executed in &#039;&#039;Idle&#039;&#039; state.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on VisProperties====&lt;br /&gt;
=====SET VISPROPERTY &amp;lt;visID&amp;gt;.&amp;lt;name&amp;gt; &amp;lt;value&amp;gt;=====&lt;br /&gt;
Sets the named [[Technical Reference:Visualization Properties|visualization property]] for the specified visualization ID to the given value. If the visualization ID contains a dot character, it must be encoded in [[Technical_Reference:Parameter_Definition#Special_Characters|parameter value encoding]]. E.g., setting the window width for the visualization ID &amp;quot;2.D1&amp;quot; would be written &amp;lt;code&amp;gt;SET VISPROPERTY 2%2ED1.Width 200&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=====RESET VISPROPERTY &amp;lt;visID&amp;gt;.&amp;lt;name&amp;gt;=====&lt;br /&gt;
Removes the named visualization property with the specified visualization ID from the property store, effectively resetting its value to its default.&lt;br /&gt;
&lt;br /&gt;
=====GET VISPROPERTY &amp;lt;visID&amp;gt;.&amp;lt;name&amp;gt;=====&lt;br /&gt;
Prints the value of the named [[Technical Reference:Visualization Properties|visualization property]] for the specified visualization ID.&lt;br /&gt;
&lt;br /&gt;
=====SET VISPROPERTIES &amp;lt;property set ID&amp;gt;=====&lt;br /&gt;
Applies a set of visualization property values as given in the [[#VisPropertySets|VisPropertySets]] parameter. In that matrix-valued parameter, row labels specify visualization properties such as &amp;quot;SRCD.Left&amp;quot;, and columns represent sets of property values. Column labels are IDs of the corresponding property sets.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on the Control Signal====&lt;br /&gt;
=====GET SIGNAL( &amp;lt;channel index&amp;gt;, &amp;lt;element index&amp;gt; )=====&lt;br /&gt;
Prints the value of the control signal at the given indices. Indices are 1-based.&lt;br /&gt;
=====GET SIGNAL CHANNELS=====&lt;br /&gt;
Prints the number of channels in the control signal.&lt;br /&gt;
=====GET SIGNAL ELEMENTS=====&lt;br /&gt;
Prints the number of elements (samples) in the control signal.&lt;br /&gt;
=====FREEZE SIGNAL, THAW SIGNAL=====&lt;br /&gt;
Freezes/thaws the contents of the control signal, without interfering with system operation. &amp;quot;Freezing&amp;quot; creates, and &amp;quot;thawing&amp;quot; discards, a frozen snapshot of the control signal. For the duration of its existence, GET SIGNAL calls will be diverted to the snapshot. This is useful for ensuring that multiple GET SIGNAL commands actually retrieve mutually-consistent values from different elements in the control signal (i.e. values from the same sample-block).&lt;br /&gt;
&lt;br /&gt;
====Commands operating on Expressions====&lt;br /&gt;
=====EVALUATE EXPRESSION &amp;lt;expression&amp;gt;=====&lt;br /&gt;
This command treats the remainder of the command as a literal mathematical expression (for a description, see [[User Reference:Expression Syntax]]). An expression may contain assignments to variables; such variables may then be used in later expressions. Note that expression variables are different from local and environment variables that may be accessed by GET/SET VARIABLE/ENVIRONMENT. Expression variables hold numerical values, while local and environment variables hold string values. Also, environment variables are accessible to child processes started with SYSTEM or START EXECUTABLE, while expression variables are accessible only to scripts. When a script is executed using the EXECUTE SCRIPT command, it will inherit a copy of all expression variables present. Changes to these variables from the executed script will not be visible in the parent script.&lt;br /&gt;
&lt;br /&gt;
=====CLEAR EXPRESSION VARIABLE &amp;lt;name&amp;gt;=====&lt;br /&gt;
Clears the named expression variable from storage.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on Watches====&lt;br /&gt;
A &amp;quot;Watch&amp;quot; is an object that consists of a set of expressions, and an action. Whenever the value of any of the expressions changes, the watch is &amp;quot;triggered&amp;quot;, and the action is executed. Watches allow client applications to respond to BCI2000 state changes in a reliable manner. Rather than polling information from BCI2000, a client may create a watch to be notified about changes of interest. This avoids the problem of missing short-lived changes, which is inherent in the polling approach.&lt;br /&gt;
&lt;br /&gt;
For watches created through operator scripting, the action consists of dumping values of all the expressions to a UDP port.&lt;br /&gt;
&lt;br /&gt;
The intended use of a watch from a client application is to create a separate thread that reads from the watch&#039;s UDP port in a blocking mode, and calls an appropriate handler function whenever it receives data.&lt;br /&gt;
The data sent will consist of a single UDP packet with a single line in ASCII format, terminated with a CRLF sequence. The line consists of tab-separated data fields, which contain the current values of the expressions specified when creating the watch. In addition, the first field contains a time stamp in milliseconds. This time stamp represents the point in time where the expression value changed, with an accuracy of a single sample.&lt;br /&gt;
&lt;br /&gt;
=====ADD WATCH [decimate &amp;lt;n&amp;gt;] &amp;lt;expression1&amp;gt; &amp;lt;expression2&amp;gt; ... [AT &amp;lt;ip:port&amp;gt;]=====&lt;br /&gt;
Adds a watch for the listed expressions. Each expression&#039;s value will be reported in a separate field. When an address is specified in &amp;lt;tt&amp;gt;ip:port&amp;lt;/tt&amp;gt; format, the watch tries to open that port for output, and creation fails if that port is taken. When no address is specified, a free port is chosen automatically. In both cases, successful creation of the watch is indicated by returning the output address in ASCII format. The address is also used to uniquely identify a watch in the context of a connection.&lt;br /&gt;
&lt;br /&gt;
When a &#039;&#039;decimate &amp;lt;n&amp;gt;&#039;&#039; clause is present, the watch will be created with decimation, i.e. it will only be evaluated for every &#039;&#039;n&#039;&#039;th&lt;br /&gt;
sample of the state vector.&lt;br /&gt;
&lt;br /&gt;
If a watch is created through a remote connection, it will use the remote host&#039;s external IP address for automatically chosen addresses. Otherwise, the output port will be associated with the machine&#039;s &amp;lt;tt&amp;gt;localhost&amp;lt;/tt&amp;gt; address.&lt;br /&gt;
&lt;br /&gt;
Watches may be created even if the system is currently running. In this case, the watch is triggered immediately at creation, and sends its current expression values to its output port.&lt;br /&gt;
&lt;br /&gt;
=====ADD WATCH SYSTEM STATE [AT &amp;lt;address&amp;gt;]=====&lt;br /&gt;
Similar to the first variant of ADD WATCH, but will watch the system&#039;s state as reported by GET SYSTEM STATE.&lt;br /&gt;
&lt;br /&gt;
=====CLEAR WATCH &amp;lt;address&amp;gt;, CLEAR WATCHES [&amp;lt;wildcard-expression&amp;gt;]=====&lt;br /&gt;
Removes the watches specified by address, or those with their addresses matching a wildcard expression. If CLEAR WATCHES is called without argument, all watches will be deleted.&lt;br /&gt;
&lt;br /&gt;
=====TRIGGER WATCH &amp;lt;address&amp;gt;, TRIGGER WATCHES  [&amp;lt;wildcard-expression&amp;gt;]=====&lt;br /&gt;
Forces dumping of the watches&#039; current expression values to their output ports. Mostly useful for testing purposes.&lt;br /&gt;
&lt;br /&gt;
=====LIST WATCHES  [&amp;lt;wildcard-expression&amp;gt;]=====&lt;br /&gt;
Displays a list of existing watches, and their addresses.&lt;br /&gt;
&lt;br /&gt;
=====COUNT WATCHES  [&amp;lt;wildcard-expression&amp;gt;]=====&lt;br /&gt;
Returns the number of existing watches, or the number of watches whose addresses match the optional wildcard expression.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on Files, Directories, and Paths====&lt;br /&gt;
=====EXTRACT DIRECTORY &amp;lt;path&amp;gt;, EXTRACT FILE &amp;lt;path&amp;gt;, EXTRACT FILE BASE &amp;lt;path&amp;gt;=====&lt;br /&gt;
Extracts the directory or file portion of a given path. When the path specifies a non-existing directory, the directory name must be followed with a separator (&amp;quot;/&amp;quot;) in order to be recognized as a directory. The EXTRACT DIRECTORY command always returns its result with a trailing separator. The EXTRACT FILE BASE command returns the file portion without extension.&lt;br /&gt;
&lt;br /&gt;
=====IS DIRECTORY &amp;lt;path&amp;gt;, IS FILE &amp;lt;path&amp;gt;, IS PATH &amp;lt;path&amp;gt;=====&lt;br /&gt;
Determines whether the specified path points to an existing directory, file, or any of the two. The result is returned as one of the strings &amp;quot;true&amp;quot; or &amp;quot;false&amp;quot;.&lt;br /&gt;
=====PARENT DIRECTORY &amp;lt;path&amp;gt;=====&lt;br /&gt;
Returns the parent directory of the specified path, independently of whether the path points to a directory, or to a file.&lt;br /&gt;
=====CURRENT DIRECTORY=====&lt;br /&gt;
Returns the current working directory. Note that working directories are per-script, i.e. multiple scripts running in parallel may have different working directories.&lt;br /&gt;
&lt;br /&gt;
=====CHANGE DIRECTORY &amp;lt;path&amp;gt;=====&lt;br /&gt;
Changes the script&#039;s working directory. Note that working directories are per-script, i.e. multiple scripts running in parallel may have different working directories. Also, this command will only affect the default directory of scripting commands, not the application-global working directory as seen by the OS.&lt;br /&gt;
&lt;br /&gt;
=====MAKE DIRECTORY &amp;lt;path&amp;gt;=====&lt;br /&gt;
Creates a new directory with the given path. The directory&#039;s parent must exist for the command to succeed.&lt;br /&gt;
=====LIST DIRECTORY [&amp;lt;path&amp;gt; or &amp;lt;wildcard expression&amp;gt;]=====&lt;br /&gt;
Returns a listing of the specified directory, or the current working directory if no path is specified. The listing is in long form. You may use wildcard expressions in order to restrict the output.&lt;br /&gt;
=====LIST FILE &amp;lt;wildcard expression&amp;gt;=====&lt;br /&gt;
Returns a list of file names matching &#039;&#039;wildcard expression&#039;&#039; in the current directory.&lt;br /&gt;
=====LIST FILES [&amp;lt;directory&amp;gt; [&amp;lt;wildcard expression&amp;gt;]]=====&lt;br /&gt;
Returns a list of file names from the specified directory, matching &#039;&#039;wildcard expression&#039;&#039;. When &#039;&#039;wildcard expression&#039;&#039; is missing, all files are listed. When &#039;&#039;directory&#039;&#039; is missing, files in the current directory are listed.&lt;br /&gt;
=====LIST DIRECTORIES [&amp;lt;directory&amp;gt; [&amp;lt;wildcard expression&amp;gt;]]=====&lt;br /&gt;
Returns a list of directory names from the specified directory, matching &#039;&#039;wildcard expression&#039;&#039;. When &#039;&#039;wildcard expression&#039;&#039; is missing, all directories are listed. When &#039;&#039;directory&#039;&#039; is missing, directories in the current directory are listed.&lt;br /&gt;
&lt;br /&gt;
=====RENAME FILE &amp;lt;current path&amp;gt; &amp;lt;new path&amp;gt;, RENAME DIRECTORY &amp;lt;current path&amp;gt; &amp;lt;new name&amp;gt;=====&lt;br /&gt;
Renames a file resp. a directory. For files, a different path may be given in the second argument, resulting in that the file is moved to the location specified by the new path. For directories, the path up to the directory&#039;s name must stay the same.&lt;br /&gt;
=====REMOVE FILE &amp;lt;path&amp;gt;, REMOVE DIRECTORY &amp;lt;path&amp;gt;=====&lt;br /&gt;
Removes the specified file or directory. This command cannot be undone. The directory must be empty for the command to succeed.&lt;br /&gt;
=====FORCEREMOVE DIRECTORY &amp;lt;path&amp;gt;=====&lt;br /&gt;
Removes the specified directory and its contents. Symbolic links are treated as ordinary files, i.e. they are not followed. This command cannot be undone.&lt;br /&gt;
=====NORMALIZED PATH &amp;lt;path&amp;gt;=====&lt;br /&gt;
Returns &amp;lt;path&amp;gt;, with the following transformations applied:&lt;br /&gt;
*Removes relative elements (&amp;lt;tt&amp;gt;..&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;.&amp;lt;/tt&amp;gt;) as far as possible. For absolute paths, the result will not contain any relative elements; for relative paths, double-dots may appear at the beginning of the result if necessary.&lt;br /&gt;
If a relative path simplifies to the empty string, &amp;lt;tt&amp;gt;./&amp;lt;/tt&amp;gt; is returned. Thus, the result of NORMALIZED PATH is never empty, unless its input was empty.&lt;br /&gt;
*Replaces backward slashes with forward slashes to achieve uniformity across platforms.&lt;br /&gt;
*On case-insensitive file systems, replaces the spelling of names with the one stored in the file system.&lt;br /&gt;
*On Win32, replaces short (8.3) names with long ones.&lt;br /&gt;
&lt;br /&gt;
=====CANONICAL PATH &amp;lt;path&amp;gt;=====&lt;br /&gt;
If &amp;lt;path&amp;gt; points to an existing file or directory, CANONICAL PATH returns a valid absolute file path, suitable as an unambiguous representation for the object pointed to. Especially, two non-empty canonical path strings will compare equal if and only if they refer to the same file system object.&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;path&amp;gt; does not point to an existing file system object, construction of a canonical path is not possible due to lack of information about the named object, and CANONICAL PATH will return an empty string.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTES:&#039;&#039;&#039; The need for an unambiguous, or canonical, representation arises due to ambiguities in the string representation of paths, and in file systems themselves.&lt;br /&gt;
*Paths may contain relative elements: &amp;lt;tt&amp;gt;/mydir/../myfile&amp;lt;/tt&amp;gt; points to the same object as &amp;lt;tt&amp;gt;/myfile&amp;lt;/tt&amp;gt;.&lt;br /&gt;
*A path that involves symbolic links will point to the same object as a path containing one or more of those links in resolved form.&lt;br /&gt;
*File systems may be case-insensitive, or may even provide multiple distinct names for individual directory entries (Win32 short vs. long names).&lt;br /&gt;
&lt;br /&gt;
On &#039;&#039;&#039;Win32,&#039;&#039;&#039; CANONICAL PATH returns the short (8.3) representation of a path, using uppercase spelling, and backslashes as directory separators. Apart from efficiency considerations, this aesthetically unpleasing representation has been chosen to discourage its use for anything except comparing file system objects.&lt;br /&gt;
&lt;br /&gt;
On &#039;&#039;&#039;other systems,&#039;&#039;&#039; CANONICAL PATH will return the result of the POSIX &amp;lt;tt&amp;gt;realpath()&amp;lt;/tt&amp;gt; function.&lt;br /&gt;
&lt;br /&gt;
In both cases, a CANONICAL PATH will end with a native directory separator if, and only if, the object pointed to is a directory.&lt;br /&gt;
&lt;br /&gt;
=====REAL PATH &amp;lt;path&amp;gt;=====&lt;br /&gt;
On this command provides a work-alike for the POSIX &amp;lt;tt&amp;gt;realpath()&amp;lt;/tt&amp;gt; function.&lt;br /&gt;
If &amp;lt;path&amp;gt; is empty, or if &amp;lt;path&amp;gt; points to a non-existing object, the result will be empty. Otherwise, an absolute path will be returned, with symbolic links resolved, using forward slashes as directory separators, and with spelling normalized as described for NORMALIZED PATH. A forward slash will be appended if the path points to a directory.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In principle, the path returned by REAL PATH should be just as unambiguous as the result of CANONICAL PATH. However, there are a few caveats:&lt;br /&gt;
* On case-insensitive file systems, two independently obtained results of REAL PATH might differ in case spelling even if referring to the same file system object. This should not be the case for CANONICAL PATH.&lt;br /&gt;
* Determining the result of CANONICAL PATH is a fast operation. In contrast, REAL PATH may be expensive to determine, as for each directory on the path a listing needs to be obtained, and a canonical path needs to be formed, and compared, for half of the listed directory entries on average.&lt;br /&gt;
* On Win32, quite some amount of complexity arises from backward compatibility layers, forbidden file names, multiple filesystem roots, etc. Internally calling &amp;lt;tt&amp;gt;GetShortPathName()&amp;lt;/tt&amp;gt;, CANONICAL PATH does not need to handle that complexity, and may be considered more reliable for identifying file system objects than REAL PATH.&lt;br /&gt;
&lt;br /&gt;
=====READ FILE &amp;lt;filename&amp;gt;=====&lt;br /&gt;
Returns the text content of the file indicated by &amp;lt;filename&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=====WRITE FILE &amp;lt;filename&amp;gt; &amp;lt;line&amp;gt;,  OVERWRITE FILE &amp;lt;filename&amp;gt; &amp;lt;line&amp;gt;, APPEND TO FILE &amp;lt;filename&amp;gt; &amp;lt;line&amp;gt;=====&lt;br /&gt;
These commands write the specified &amp;lt;line&amp;gt; of text to the file indicated by &amp;lt;filename&amp;gt;.   They behave like the &amp;lt;tt&amp;gt;echo&amp;lt;/tt&amp;gt; command of a typical shell, in the sense that a line-ending will be automatically added to the &amp;lt;line&amp;gt; if it does not already end with one. To suppress the automatic line-ending, you can say WRITE FILE &amp;lt;filename&amp;gt; &amp;lt;content&amp;gt; WITHOUT LINE ENDING (or equivalently, for short, you can say WITHOUT LF or WITHOUT CRLF). Any previous content in &amp;lt;file&amp;gt; will be lost if you use WRITE or OVERWRITE (they are the same, just synonyms for each other) whereas APPEND preserves previous content and adds the new &amp;lt;line&amp;gt; to the end.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on executables====&lt;br /&gt;
=====START EXECUTABLE &amp;lt;command line&amp;gt;=====&lt;br /&gt;
Behaves identically to CREATE PROCESS, except that it does not report a process id for the new process. For details, see CREATE PROCESS.&lt;br /&gt;
&lt;br /&gt;
=====CATEGORIZE EXECUTABLE &amp;lt;name or path&amp;gt;=====&lt;br /&gt;
BCI2000 keeps a list of executables/modules that have been built, and sorts them into categories. The CATEGORIZE EXECUTABLE command provides a way to retrieve that information. Given the name or path of an executable, it outputs one of the following categories:&lt;br /&gt;
* SignalSource,&lt;br /&gt;
* SignalProcessing,&lt;br /&gt;
* Application,&lt;br /&gt;
* Operator,&lt;br /&gt;
* Tool,&lt;br /&gt;
* Helper,&lt;br /&gt;
* Unknown.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on Lines of input/output====&lt;br /&gt;
=====WRITE LINE &amp;lt;line&amp;gt;=====&lt;br /&gt;
Writes a line of output. Destination depends on the context in which a script is executed. If the context is an Operator Handler, output is written as a log entry. If the context is a telnet session, output is written to the telnet connection. If the context is a [[User Reference:BCI2000Shell|BCI2000Shell]], output is written to the shell&#039;s stdout.&lt;br /&gt;
&lt;br /&gt;
=====READ LINE=====&lt;br /&gt;
Reads a line of input from the current execution context&#039;s input. If the command is executed within an Operator Handler, it will fail. If executed within a telnet session, the other side of the connection is prompted for input. If executed from within a [[User Reference:BCI2000Shell|BCI2000Shell]], input is read from the shell&#039;s stdin.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on Processes in the Operating System====&lt;br /&gt;
=====CREATE PROCESS &amp;lt;command line&amp;gt;=====&lt;br /&gt;
Starts the specified executable with options. This command returns after the started program has finished initialization, i.e. it will detect load time failures such as missing DLLs on Windows. If the process is still running when CREATE PROCESS returns, its result will be an operating system process id (pid). If the process has terminated, CREATE PROCESS will report its exit code marked with an &amp;lt;tt&amp;gt;ExitCode&amp;lt;/tt&amp;gt; tag to allow distinction between a pid and an exit code.&lt;br /&gt;
Please note that CREATE PROCESS requires quoting of arguments differently from other scripting commands. For details, see the SYSTEM command.&lt;br /&gt;
&lt;br /&gt;
=====TERMINATE PROCESS &amp;lt;pid&amp;gt;=====&lt;br /&gt;
Tries to terminate the process with the given operating system pid, waiting for the process to terminate before returning. Will return &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt; to indicate that a suitable process existed but could not be terminated.&lt;br /&gt;
&lt;br /&gt;
=====WAIT FOR PROCESS &amp;lt;pid&amp;gt; [&amp;lt;timeout seconds&amp;gt; = infinite]=====&lt;br /&gt;
Waits for the process with the given operating system pid to terminate, or the timeout to expire. Returns &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt; to indicate that the process is still executing.&lt;br /&gt;
&lt;br /&gt;
=====SHOW PROCESS &amp;lt;pid&amp;gt;=====&lt;br /&gt;
Makes all windows visible which are associated with the process referred to by pid.&lt;br /&gt;
In addition, brings one of the process&#039; top level (desktop level) windows to the front for user interaction.&lt;br /&gt;
&lt;br /&gt;
=====HIDE PROCESS &amp;lt;pid&amp;gt;=====&lt;br /&gt;
Makes all windows invisible which are associated with the process referred to by pid.&lt;br /&gt;
&lt;br /&gt;
====Global commands====&lt;br /&gt;
=====HELP [&amp;lt;type&amp;gt;]=====&lt;br /&gt;
When called with a type argument, lists commands that exist for the specified type (e.g., SYSTEM, or FILE). When called without argument, lists all commands in their main form. HELP ALL will list all commands, including synonyms.&lt;br /&gt;
&lt;br /&gt;
=====SET &amp;lt;name&amp;gt; &amp;lt;value&amp;gt;, GET &amp;lt;name&amp;gt;, &amp;lt;name&amp;gt;=====&lt;br /&gt;
Allows to set or retrieve the value of local and environment variables. The name is matched against local and environment variables. When no variable with the given name is found, SET will create a local variable, while GET will result in an error. GET may be further abbreviated to only consist of a name.&lt;br /&gt;
&lt;br /&gt;
GET further allows evaluation of [[User_Reference:Expression_Syntax|mathematical expressions]]. When the expression is invalid, or contains an unknown variable, an error is triggered.&lt;br /&gt;
&lt;br /&gt;
=====GET SYSTEM STATE=====&lt;br /&gt;
Prints the current system state. This will be one of Unavailable, Idle, Startup, Initialization, Resting, Suspended, ParamsModified, Running, Termination, Busy (for details, see the WAIT FOR command below).&lt;br /&gt;
&lt;br /&gt;
=====GET CURRENT RUN FILE=====&lt;br /&gt;
Prints the full path to the current run file, or an empty string, if called outside Running state.&lt;br /&gt;
&lt;br /&gt;
=====WAIT FOR &amp;lt;system state&amp;gt; [&amp;lt;timeout seconds&amp;gt;]=====&lt;br /&gt;
Waits until the system is in the specified state. This may be one of Idle, Startup, Connected, Resting, Suspended, ParamsModified, Running, Busy, or a combination of these, separated with a pipe character: &amp;quot;Resting|Suspended&amp;quot;. When no timeout is given, this command waits indefinitely. If the wait is successful, i.e. system state matches one of the specified states, WAIT FOR will return a value of &amp;quot;true&amp;quot;. If timeout occurred, WAIT FOR will return &amp;quot;false&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
If the BCI2000 system is shut down while a script is executing a WAIT FOR command, the script will be terminated with a &amp;quot;wait aborted&amp;quot; error message.&lt;br /&gt;
&lt;br /&gt;
In more detail, user visible states are:&lt;br /&gt;
* Idle: System is shut down and does not do other processing than executing scripts.&lt;br /&gt;
* Startup: System has started up and is listening for incoming connections.&lt;br /&gt;
* Connected: All core modules have connected to the system.&lt;br /&gt;
* Resting: The system has been initialized but is not running.&lt;br /&gt;
* Suspended: The system has ended running and is behaving like in Resting.&lt;br /&gt;
* ParamsModified: In Suspended mode, parameter changes have been published and will be applied at Resume.&lt;br /&gt;
* Running: The system is running, processing brain signals, and displaying stimuli.&lt;br /&gt;
* Busy: The system is performing a transition from one state to another.&lt;br /&gt;
&lt;br /&gt;
As a synonym for &amp;quot;Connected,&amp;quot; &amp;quot;Initialization&amp;quot; is valid as well since it is compatible with the nomenclature in StateMachine.h. Still, it should be avoided because it is easily confused with, but very distinct from, the actions performed in the Initialize() phase.&lt;br /&gt;
&lt;br /&gt;
=====SLEEP &amp;amp;lt;time in seconds&amp;amp;gt;=====&lt;br /&gt;
Waits (sleeps) for the given amount of time. Timing resolution is 50ms. Tends to sleep a little longer than specified, with the error growing with duration.&lt;br /&gt;
&lt;br /&gt;
=====GET SYSTEM VERSION=====&lt;br /&gt;
Prints BCI2000 version information.&lt;br /&gt;
=====SETCONFIG, SET CONFIG=====&lt;br /&gt;
Applies current parameters to the system. Corresponds to the &#039;&#039;SetConfig&#039;&#039; button in the GUI version of the Operator module.&lt;br /&gt;
&lt;br /&gt;
=====START=====&lt;br /&gt;
Starts or resumes system operation, corresponding to the &#039;&#039;Start/Resume&#039;&#039; button in the GUI version of the Operator module.&lt;br /&gt;
=====STOP=====&lt;br /&gt;
Stops system operation. Corresponds to the &#039;&#039;Stop&#039;&#039; button in the GUI version of the Operator.&lt;br /&gt;
=====STARTUP SYSTEM=====&lt;br /&gt;
When in idle state, starts up the system to wait for incoming connections from core modules. Additionally, the following arguments may be given: 1) an IP address on which to listen (default is to listen on all addresses), and 2) a list of generic core module names with ports. The default configuration corresponds to these arguments:&lt;br /&gt;
 STARTUP SYSTEM * SignalSource:4000 SignalProcessing:4001 Application:4002&lt;br /&gt;
&lt;br /&gt;
A system log file may optionally be specified on this line, by inserting the &amp;lt;code&amp;gt;--SystemLogFile&amp;lt;/code&amp;gt; flag between the IP address and the module specifiers. For example:&lt;br /&gt;
&lt;br /&gt;
 STARTUP SYSTEM * --SystemLogFile=SOME_FILE.TXT SignalSource:4000 SignalProcessing:4001 Application:4002&lt;br /&gt;
&lt;br /&gt;
The system log file will record all operator log window messages for the current launch, until the system shuts down.  It may be helpful to use the variables &amp;lt;code&amp;gt;$YYYYMMDD&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;$HHMMSS&amp;lt;/code&amp;gt; to specify the filename.  Note that file name and path cannot contain spaces.&lt;br /&gt;
&lt;br /&gt;
=====SHUTDOWN SYSTEM=====&lt;br /&gt;
Shuts down core modules, and enters idle system state.&lt;br /&gt;
=====RESET SYSTEM=====&lt;br /&gt;
Shuts down the system, and clears all parameter, state, and event information.&lt;br /&gt;
&lt;br /&gt;
=====QUIT, EXIT [&amp;lt;result&amp;gt;]=====&lt;br /&gt;
Quits the operator module after terminating all BCI2000 modules. The optional &#039;&#039;result&#039;&#039; argument determines the result of the executed script.&lt;br /&gt;
&lt;br /&gt;
=====CLOSE CONNECTION, TERMINATE CONNECTION=====&lt;br /&gt;
In the context of a telnet or websocket connection, this command will terminate the connection.&lt;br /&gt;
In other contexts, such as event handlers, it will be ignored.&lt;br /&gt;
&lt;br /&gt;
=====SYSTEM &amp;lt;command line&amp;gt;=====&lt;br /&gt;
Executes a shell command, redirecting any console output into the command&#039;s script result. E.g., to obtain a directory listing, under Windows, you would enter&lt;br /&gt;
 SYSTEM DIR&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Arguments to the SYSTEM command are executed by the operating system&#039;s shell, and thus may require quoting different from the other scripting commands. E.g., writing&lt;br /&gt;
 SET mydir ${PARENT DIRECTORY $BCI2000LAUNCHDIR}; ECHO ${LIST FILES $mydir}&lt;br /&gt;
will list files in the BCI2000 main directory, independently of whether the path to that directory contains space characters or not. However, to obtain a directory listing through the SYSTEM command, you would need to write&lt;br /&gt;
 ECHO ${SYSTEM DIR &amp;quot;$mydir&amp;quot;}&lt;br /&gt;
to make sure the content of the variable &#039;&#039;mydir&#039;&#039; is interpreted as a single argument, independently of whether it contains space characters.&lt;br /&gt;
&lt;br /&gt;
=====LOG &amp;lt;message&amp;gt;=====&lt;br /&gt;
Append the specified message to the system log.&lt;br /&gt;
=====WARN &amp;lt;message&amp;gt;=====&lt;br /&gt;
Append the specified message to the system log, formatted as a warning.&lt;br /&gt;
=====ERROR &amp;lt;message&amp;gt;=====&lt;br /&gt;
Append the specified message to the system log, formatted as an error message.&lt;br /&gt;
&lt;br /&gt;
=====CAPTURE MESSAGES &amp;lt;message types&amp;gt;=====&lt;br /&gt;
Captures system log messages into a background buffer. When no message type is given, all messages are captured. When &amp;quot;None&amp;quot; is given as a message type, message capturing is disabled. Otherwise, the message type must be one of &amp;quot;Errors&amp;quot;, &amp;quot;Warnings&amp;quot;, &amp;quot;Debug&amp;quot;, &amp;quot;Log&amp;quot;. Multiple message types may be specified in a single command. When &amp;quot;None&amp;quot; appears within a single command, all preceding message types are ignored. Multiple CAPTURE MESSAGES commands are cumulative, except when &amp;quot;None&amp;quot; is specified as a message type.&lt;br /&gt;
&lt;br /&gt;
=====FLUSH MESSAGES=====&lt;br /&gt;
Clears the background message buffer, and returns its previous content. Use CAPTURE MESSAGES to capture messages into the background message buffer.&lt;br /&gt;
&lt;br /&gt;
====Operator-module defined Commands====&lt;br /&gt;
=====HIDE WINDOW [&amp;lt;name&amp;gt;], SHOW WINDOW [&amp;lt;name&amp;gt;]=====&lt;br /&gt;
Hides or shows the specified window. When called without a window name, the Operator module&#039;s main window is hidden or shown. The window name may be one of Main, Configuration, Log, Watches, and Visualizations. When &amp;quot;Watches&amp;quot; is given, the window state refers to visibility of the Watches area in the Visualizations window.&lt;br /&gt;
&lt;br /&gt;
=====MOVE WINDOW &amp;lt;name&amp;gt; &amp;lt;x&amp;gt; &amp;lt;y&amp;gt;, RESIZE WINDOW &amp;lt;name&amp;gt; &amp;lt;width&amp;gt; &amp;lt;height&amp;gt;=====&lt;br /&gt;
Moves resp. resizes the specified window with one of the above names.&lt;br /&gt;
Window decorations (title bar, frame) are taken into consideration such that the total size of the window matches the given width and height.&lt;br /&gt;
&lt;br /&gt;
=====ARRANGE WINDOW &amp;lt;name&amp;gt; &amp;lt;rows&amp;gt; &amp;lt;cols&amp;gt; &amp;lt;row&amp;gt; &amp;lt;col&amp;gt; [&amp;lt;rowspan&amp;gt; &amp;lt;colspan&amp;gt;]=====&lt;br /&gt;
Arranges the named window in a virtual &#039;&#039;rows&#039;&#039; x &#039;&#039;cols&#039;&#039; grid at grid position &#039;&#039;row, col&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Optional &#039;&#039;rowspan&#039;&#039; and &#039;&#039;colspan&#039;&#039; arguments may be given to specify the extension of the window across more than one row or column. &lt;br /&gt;
Using a &#039;&#039;rowspan&#039;&#039; of 0 will result in the window assuming its minimum height.&lt;br /&gt;
Likewise, a &#039;&#039;colspan&#039;&#039; of 0 will result in the window&#039;s minimum width.&lt;br /&gt;
&lt;br /&gt;
If multiple screens are present, windows are arranged on the screen that contains the Operator window.&lt;br /&gt;
&lt;br /&gt;
=====SET TITLE &amp;lt;title&amp;gt;=====&lt;br /&gt;
Sets the title of the main Operator window.&lt;br /&gt;
=====SET BUTTON &amp;lt;idx&amp;gt; &amp;lt;label&amp;gt; &amp;lt;commands&amp;gt;=====&lt;br /&gt;
Configures the function button with 1-based index &#039;&#039;idx&#039;&#039; such that it is labelled &#039;&#039;label&#039;&#039; and executes &#039;&#039;commands&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=====VISUALIZE WATCH [decimate &amp;lt;n&amp;gt;] [range &amp;lt;min&amp;gt; &amp;lt;max&amp;gt;] &amp;lt;expression1&amp;gt; ...=====&lt;br /&gt;
Adds a watch for the given expressions to the operator module&#039;s Watches window, and makes the Watches window visible if it is hidden. If the &#039;&#039;decimate&#039;&#039; clause is present, the command will create a watch which will be evaluated only for every &#039;&#039;n&#039;&#039;th sample in the state vector. If the &#039;&#039;range&#039;&#039; clause is present, display minimum and maximum will not be adjusted automatically but will be fixed to the values given.&lt;br /&gt;
&lt;br /&gt;
By default, &#039;&#039;decimate&#039;&#039; has a value of &amp;quot;auto&amp;quot;; this means that there is no decimation of evaluation (i.e., all samples are evaluated) but changes that occur within 1ms will be shortened into their maximum and minimum, and thus reported as only two values.&lt;br /&gt;
This has proven to be efficient for avoiding sluggishness from flooding the application with events.&lt;br /&gt;
&lt;br /&gt;
=====MOVE VISUALIZATON &amp;lt;visID&amp;gt; &amp;lt;x&amp;gt; &amp;lt;y&amp;gt;, RESIZE VISUALIZATION &amp;lt;visID&amp;gt; &amp;lt;width&amp;gt; &amp;lt;height&amp;gt;=====&lt;br /&gt;
Moves resp. resizes the specified visualization window.&lt;br /&gt;
Window decorations (title bar, frame) are taken into consideration such that the total size of the window matches the given width and height. If unknown, visualization IDs may be obtained from the Operator&#039;s &#039;&#039;Window-&amp;gt;Visualizations&#039;&#039; menu.&lt;br /&gt;
&lt;br /&gt;
=====ARRANGE VISUALIZATION &amp;lt;visID&amp;gt; &amp;lt;rows&amp;gt; &amp;lt;cols&amp;gt; &amp;lt;row&amp;gt; &amp;lt;col&amp;gt; [&amp;lt;rowspan&amp;gt; &amp;lt;colspan&amp;gt;]=====&lt;br /&gt;
Arranges the named visualization window in a virtual &#039;&#039;rows&#039;&#039; x &#039;&#039;cols&#039;&#039; grid at grid position &#039;&#039;row, col&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Optional &#039;&#039;rowspan&#039;&#039; and &#039;&#039;colspan&#039;&#039; arguments may be given to specify the extension of the window across more than one row or column. &lt;br /&gt;
Using a &#039;&#039;rowspan&#039;&#039; of 0 will result in the window assuming its minimum height.&lt;br /&gt;
Likewise, a &#039;&#039;colspan&#039;&#039; of 0 will result in the window&#039;s minimum width.&lt;br /&gt;
&lt;br /&gt;
If multiple screens are present, windows are arranged on the screen that contains the Operator window.&lt;br /&gt;
&lt;br /&gt;
=====RECORD VISUALIZATION &amp;lt;visID&amp;gt; [on|off]=====&lt;br /&gt;
Registers the named visualization for recording. The visualization name must be the short name as displayed in the &#039;&#039;View-&amp;gt;Visualizations&#039;&#039; menu. Switching a visualization recording to &amp;quot;on&amp;quot; is only possible in idle state (because an event for recording frame numbers must be registered in the system). When a visualization is registered for recording, its frames are stored immediately as they arrive at the operator module. Currently, only bitmap visualizations may be recorded.&lt;br /&gt;
&lt;br /&gt;
Example: Recording the application window&lt;br /&gt;
 RECORD VISUALIZATION ApplicationWindow on&lt;br /&gt;
 ...&lt;br /&gt;
 # after parameters have been loaded&lt;br /&gt;
 Set parameter VisualizeApplicationWindow 1&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
=====PUT NOTE &amp;lt;note&amp;gt;=====&lt;br /&gt;
Adds the given text to the [[User_Reference:Operator_Notes#Taking_Notes_during_recording_in_Operator|notes window]].&lt;br /&gt;
If the system is in &#039;&#039;Running&#039;&#039; state, the text will also be added to the current notes file as described under&lt;br /&gt;
[[User_Reference:Operator_Notes#Note_storage_and_file_format|&amp;quot;notes file&amp;quot;]].&lt;br /&gt;
&lt;br /&gt;
=====START TELNET &amp;lt;address&amp;gt;, STOP TELNET &amp;lt;address&amp;gt;=====&lt;br /&gt;
Starts or stops a telnet server listening at the given address. The address is in &amp;lt;IP&amp;gt;:&amp;lt;port&amp;gt; format.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IMPORTANT:&#039;&#039;&#039; You should not use this command on global internet addresses, as there is no authentication performed. Only use addresses in the local network, such as 10.x.x.x, 172.x.x.x, or 192.168.x.x.&lt;br /&gt;
&lt;br /&gt;
=====START WEBSOCKET &amp;lt;address&amp;gt;, STOP WEBSOCKET &amp;lt;address&amp;gt;=====&lt;br /&gt;
Starts or stops a websocket server listening at the given address. The address is in &amp;lt;IP&amp;gt;:&amp;lt;port&amp;gt; format.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IMPORTANT:&#039;&#039;&#039; You should not use this command on global internet addresses, as there is no authentication performed. Only use addresses in the local network, such as 10.x.x.x, 172.x.x.x, or 192.168.x.x.&lt;br /&gt;
&lt;br /&gt;
====Operator-module Commands for Soliciting Input from the User====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=====CHOOSE [INPUT] FILE[S] [OF TYPE &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]] [STARTING AT &amp;lt;dir&amp;gt;] [WITH PROMPT &amp;lt;message&amp;gt;]=====&lt;br /&gt;
Via the Qt graphical user interface, prompt the user to select an existing file (or multiple files, if the keyword FILES is used). Print the resulting file path(s).&lt;br /&gt;
(See the [[User_Reference:Custom_GUI_Commands|Custom GUI Commands]] page for details and examples.)&lt;br /&gt;
&lt;br /&gt;
=====CHOOSE [OUTPUT] FILE [OF TYPE &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]] [STARTING AT &amp;lt;dir&amp;gt;] [WITH PROMPT &amp;lt;message&amp;gt;]=====&lt;br /&gt;
Via the Qt graphical user interface, prompt the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists). Print the resulting file path.&lt;br /&gt;
(See the [[User_Reference:Custom_GUI_Commands|Custom GUI Commands]] page for details and examples.)&lt;br /&gt;
&lt;br /&gt;
=====CHOOSE DIRECTORY [STARTING AT &amp;lt;dir&amp;gt;] [WITH PROMPT &amp;lt;message&amp;gt;]=====&lt;br /&gt;
Via the Qt graphical user interface, prompt the user to specify a directory. Print the resulting directory path.&lt;br /&gt;
(See the [[User_Reference:Custom_GUI_Commands|Custom GUI Commands]] page for details and examples.)&lt;br /&gt;
&lt;br /&gt;
=====CUSTOM DIALOG [MESSAGE &amp;lt;msg&amp;gt;] [VAR &amp;lt;varname&amp;gt; &amp;lt;label&amp;gt; {[&amp;lt;options&amp;gt;]} ] [BUTTONS {&amp;lt;buttons&amp;gt;}] ... =====&lt;br /&gt;
Via the Qt graphical user interface, prompt the user with a modal dialog that can be flexibly customized.&lt;br /&gt;
(See the [[User_Reference:Custom_GUI_Commands|Custom GUI Commands]] page for details and examples.)&lt;br /&gt;
&lt;br /&gt;
===Predefined Variables===&lt;br /&gt;
The following variables exist when an Operator script is executed.&lt;br /&gt;
Some of these variables are marked with &#039;&#039;local&#039;&#039;. This means that they are not environment variables, i.e. they are invisible to child processes that are launched using the SYSTEM or START EXECUTABLE commands, and their values may be different between script invocations. In script code, they are accessed like ordinary variables.&lt;br /&gt;
====BCI2000LAUNCHDIR====&lt;br /&gt;
The full absolute path to the directory where the Operator module resides. This is also prepended to the PATH environment variable, such that executables from the current BCI2000 installation will have precedence over any other executable with the same name.&lt;br /&gt;
&lt;br /&gt;
On macOS, this is the path where the Operator module&#039;s application bundle resides. In the default configuration, this is the BCI2000 prog directory, both on macOS and on other platforms.&lt;br /&gt;
&lt;br /&gt;
====BCI2000BINARY====&lt;br /&gt;
The full absolute path to the Operator module.&lt;br /&gt;
====LogLevel (local)====&lt;br /&gt;
Determines the amount of log information written to the Operator log. This variable only affects log messages originating from the current script. May be 2 (display all log messages), 1 (display fewer log messages), or 0 (suppress all log messages). Set to 1 by default. Changes to this local variable are not propagated to any sub-scripts called. &#039;&#039;NOTE:&#039;&#039; Only log messages are controlled by this variable. Error messages originating from a script with &#039;LogLevel 0&#039; will still be displayed in the Operator log. When &#039;AbortOnError&#039; is set to 0, you may set &#039;LogLevel&#039; to -1 in order to display error messages. When &#039;AbortOnError&#039; is 1 (the default), error messages will always be displayed to indicate the reason for failure.&lt;br /&gt;
&lt;br /&gt;
====AbortOnError (local)====&lt;br /&gt;
Determines if a script is aborted when an error happens, or whether the error is silently ignored. Set to 1 by default (script is aborted on error). Changes to this local variable are not propagated to any sub-scripts called.&lt;br /&gt;
&lt;br /&gt;
====Result (local)====&lt;br /&gt;
The result of the last executed scripting command. When a script is executed by calling EXECUTE SCRIPT, the script&#039;s last executed command determines the result of the EXECUTE SCRIPT command itself.&lt;br /&gt;
&lt;br /&gt;
====0, 1, ... 9 (local)====&lt;br /&gt;
When a script file is being executed, these variables contain the arguments of the EXECUTE SCRIPT command.&lt;br /&gt;
&#039;&#039;$0&#039;&#039; resolves to the full absolute path to the current script file. Within scripts, all of the &#039;&#039;0-9&#039;&#039; variables are defined, and those that do not have a matching argument are empty.&lt;br /&gt;
&lt;br /&gt;
====YYYYMMDD (local)====&lt;br /&gt;
Local time at execution of the current script, in YYYYMMDD format. In interactive sessions, reflects the time when the session was initiated.&lt;br /&gt;
&lt;br /&gt;
====HHMMSS (local)====&lt;br /&gt;
Local time at execution of the current script, in HHMMSS format. In interactive sessions, reflects the time when the session was initiated.&lt;br /&gt;
&lt;br /&gt;
===Abbreviated commands and synonyms===&lt;br /&gt;
To minimize the need of consulting documentation, as well as for backward compatibility, a number of &#039;&#039;&#039;synonymous commands&#039;&#039;&#039; are provided. E.g., states may be added by INSERT STATE as well as ADD STATE, and the existence of a file may be queried by IS FILE as well as EXISTS FILE. For an overview over all allowed forms of commands, use the HELP ALL command.&lt;br /&gt;
&lt;br /&gt;
To simplify operation in interactive sessions, &#039;&#039;&#039;abbreviated commands&#039;&#039;&#039; exist. Currently, these are:&lt;br /&gt;
:&#039;&#039;&#039;cd&#039;&#039;&#039; for CHANGE DIRECTORY,&lt;br /&gt;
:&#039;&#039;&#039;pwd&#039;&#039;&#039; and &#039;&#039;&#039;cd&#039;&#039;&#039; without argument for CURRENT DIRECTORY,&lt;br /&gt;
:&#039;&#039;&#039;ls&#039;&#039;&#039; and &#039;&#039;&#039;dir&#039;&#039;&#039; for LIST DIRECTORY,&lt;br /&gt;
:&#039;&#039;&#039;mkdir&#039;&#039;&#039; for MAKE DIRECTORY,&lt;br /&gt;
:&#039;&#039;&#039;echo&#039;&#039;&#039; for WRITE LINE,&lt;br /&gt;
:&#039;&#039;&#039;realpath&#039;&#039;&#039; for REAL PATH,&lt;br /&gt;
:&#039;&#039;&#039;dirname&#039;&#039;&#039; for EXTRACT DIRECTORY,&lt;br /&gt;
:&#039;&#039;&#039;basename&#039;&#039;&#039; for EXTRACT FILE BASE.&lt;br /&gt;
&lt;br /&gt;
===Handlers===&lt;br /&gt;
In the Operator GUI, script execution is bound to a number of Operator Events (not to be confused with Event states, above) that occur during various [[Technical Reference:States of Operation|stages of BCI2000 system operation]]:&lt;br /&gt;
====OnConnect====&lt;br /&gt;
This handler runs at startup, as soon as all modules are connected to the operator module.&lt;br /&gt;
====OnSetConfig====&lt;br /&gt;
This handler runs each time a set of parameters is applied to the system. This happens when the user clicks the &#039;&#039;SetConfig&#039;&#039; button. Execution of the &#039;&#039;SETCONFIG&#039;&#039; command also runs this handler.&lt;br /&gt;
&lt;br /&gt;
====OnStart, OnResume====&lt;br /&gt;
These handlers are triggered by the &#039;&#039;Start&#039;&#039;/&#039;&#039;Resume&#039;&#039; button. One of these handlers is also triggered when the &#039;&#039;Running&#039;&#039; state variable is set to 1 from a script. Whether &#039;&#039;OnStart&#039;&#039; or &#039;&#039;OnResume&#039;&#039; is triggered depends on whether the system has been running before with the current set of parameters.&lt;br /&gt;
&lt;br /&gt;
====OnStartRun====&lt;br /&gt;
Similarly to OnStart and OnResume, this handler is triggered by the &#039;&#039;Start&#039;&#039;/&#039;&#039;Resume&#039;&#039; button. Unlike other event handlers, OnStartRun has an argument, which is the current run file.&lt;br /&gt;
&lt;br /&gt;
OnStart or OnResume are triggered immediately after &#039;&#039;Start&#039;&#039;/&#039;&#039;Resume&#039;&#039; has been pressed, whereas OnStartRun is deferred until modules have confirmed to be in Running state. This makes sure that the OnStartRun event handler receives a valid run file name.&lt;br /&gt;
&lt;br /&gt;
====OnNextFilePart====&lt;br /&gt;
This handler is triggered during a run, whenever the &#039;&#039;FilePart&#039;&#039; event state is incremented. It allows scripts to know when a new&lt;br /&gt;
partial file has begun. For further information, see the [[User_Reference:BCI2000FileWriter#FileSplittingCondition|FileSplittingCondition]] parameter.&lt;br /&gt;
&lt;br /&gt;
====OnSuspend/OnStopRun====&lt;br /&gt;
Triggered when the system goes from running into suspended mode. This happens whenever the &#039;&#039;Running&#039;&#039; state variable changes from 1 to 0. This may happen when the user clicks &#039;&#039;Suspend&#039;&#039;, when the application module switches the system into suspended mode, or when a script sets the &#039;&#039;Running&#039;&#039; state variable to 0.&lt;br /&gt;
&lt;br /&gt;
====OnShutdown====&lt;br /&gt;
Triggered when the operator module shuts down connections, and switches into idle state.&lt;br /&gt;
&lt;br /&gt;
====OnExit====&lt;br /&gt;
Triggered when the operator module exits. Execution of the QUIT command also triggers this handler. This handler is not available to the SET SCRIPT and CLEAR SCRIPT commands. Also, when both an OnShutdown and an OnExit script are defined, the OnExit script may be executed before the OnShutdown script.&lt;br /&gt;
&lt;br /&gt;
====Associating Scripts with Operator Events====&lt;br /&gt;
In the operator module&#039;s preferences dialog, script commands may be entered for each of the handlers listed above.&lt;br /&gt;
Scripts may be specified as paths to script files, or as immediate one-line scripts.&lt;br /&gt;
Entries that start with a minus sign (-) are treated as one-line scripts, which may contain multiple commands separated with semicolons.&lt;br /&gt;
&lt;br /&gt;
Scripts may also be specified from the command line used to start up the operator module. There, handler names are followed with the content of the respective preference entry, enclosed in double quotes (&amp;quot;...&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Finally, scripts may be specified using the SET SCRIPT command of the scripting language itself.&lt;br /&gt;
&lt;br /&gt;
===Examples===&lt;br /&gt;
====Making use of the Operator module&#039;s Function Buttons====&lt;br /&gt;
To add a state variable called &amp;quot;Artifact&amp;quot;, and to set it using the operator&#039;s function buttons, do this:&lt;br /&gt;
*Enter the following line under &amp;quot;After All Modules Connected&amp;quot; in the operator&#039;s preferences dialog (note the minus sign):&lt;br /&gt;
 -ADD STATE Artifact 1 0&lt;br /&gt;
*Under &amp;quot;Function Buttons&amp;quot;, enter &amp;quot;Set Artifact&amp;quot; as the name of button 1, and as its command, enter (note there is no minus sign):&lt;br /&gt;
 SET STATE Artifact 1&lt;br /&gt;
*Enter &amp;quot;Clear Artifact&amp;quot; as the name of button 2, and as its command, enter&lt;br /&gt;
 SET STATE Artifact 0&lt;br /&gt;
&lt;br /&gt;
====A fully automated BCI2000 session====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Echo Please enter a subject ID:&lt;br /&gt;
Set SubjectID ${Read line}&lt;br /&gt;
&lt;br /&gt;
Startup system&lt;br /&gt;
Start executable SignalGenerator&lt;br /&gt;
Start executable SpectralSignalProcessing&lt;br /&gt;
Start executable CursorTask&lt;br /&gt;
Wait for Connected&lt;br /&gt;
Load parameterfile &amp;quot;../parms/examples/CursorTask_SignalGenerator.prm&amp;quot;&lt;br /&gt;
For i in 1 2 3&lt;br /&gt;
  Load parameterfile &amp;quot;../parms/MyExperiment/Session$i.prm&amp;quot;&lt;br /&gt;
  Set parameter SubjectName $SubjectID&lt;br /&gt;
  Set parameter SubjectSession $i&lt;br /&gt;
  Set config&lt;br /&gt;
  Wait for Resting&lt;br /&gt;
  Start&lt;br /&gt;
  Wait for Suspended 1000&lt;br /&gt;
End&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Automating BCI2000 by Operator command line arguments====&lt;br /&gt;
The following example shows how to specify script commands from the command line.&lt;br /&gt;
It fully automates BCI2000 operation by loading a parameter file, applying parameters, starting the system once the parameters are applied, and quitting the system once the run is over. For better readability, the example is broken across lines, using the ^ DOS line continuation character.&lt;br /&gt;
&lt;br /&gt;
 operator.exe --OnConnect &amp;quot;-LOAD PARAMETERFILE ../parms/examples/CursorTask_SignalGenerator.prm; SETCONFIG&amp;quot; ^&lt;br /&gt;
              --OnSetConfig &amp;quot;-SET STATE Running 1&amp;quot;  ^&lt;br /&gt;
              --OnSuspend &amp;quot;-QUIT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
====Automatically arranging windows in a 4x2 grid====&lt;br /&gt;
The following example arranges Source and Roundtrip visualizations on the left side of the screen.&lt;br /&gt;
On the right side, a large area is dedicated to the Operator&#039;s log window, and the Operator&#039;s main window sits at the bottom right.&lt;br /&gt;
&lt;br /&gt;
 Arrange Visualization SRCD 4 2 1 1 2 1&lt;br /&gt;
 Arrange Visualization RNDT 4 2 3 1&lt;br /&gt;
 Arrange Window Main 4 2 4 2&lt;br /&gt;
 Arrange Window Log  4 2 1 2 3 1&lt;br /&gt;
&lt;br /&gt;
[[File:Operator_Arrangement.PNG|center|640px|border]]&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
[[User Reference:Module Command Line Options]], [[User Reference:Operator Module]], [[User Reference:BCI2000Shell]], [[Technical Reference:States of Operation]]&lt;br /&gt;
&lt;br /&gt;
[[Category:User Interface]]&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Operator_Module_Scripting&amp;diff=12100</id>
		<title>User Reference:Operator Module Scripting</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Operator_Module_Scripting&amp;diff=12100"/>
		<updated>2025-10-01T21:06:24Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* Commands operating on Files, Directories, and Paths */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Operator scripts automate actions that the otherwise would be performed by the user, e.g. starting or suspending system operation.&lt;br /&gt;
Scripts may be contained in script files, or given immediately in the operator module&#039;s preferences dialog.&lt;br /&gt;
There is also an option to specify scripts from the [[User Reference:Module Command Line Options#Operator Module|command line]] when starting the operator module. When using the [[User_Reference:BCI2000Shell|BCI2000Shell]], or the [[Technical_Reference:Operator_Library|Operator Library]] from your own application, you may execute scripts at any time.&lt;br /&gt;
&lt;br /&gt;
In addition, the operator scripting language may be used to control an operator module over a [[User_Reference:Module_Command_Line_Options#--Telnet|Telnet]] or [[User_Reference:Module_Command_Line_Options#--WebSocket|WebSocket]] connection.&lt;br /&gt;
===Syntax===&lt;br /&gt;
&#039;&#039;&#039;Command separation.&#039;&#039;&#039; Scripts consist of sequences of the commands listed below. A command must be terminated with either a newline, or a semicolon (;).&lt;br /&gt;
This allows to put multiple commands into one line, separated by semicolon characters.&lt;br /&gt;
Commands are case-insensitive, variables and values may be case-sensitive, depending on context.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Comments.&#039;&#039;&#039; Lines starting with a &#039;#&#039; character are ignored. Such lines may be used to hold comments. In addition, when any of the first two lines of a script contains &amp;quot;#!&amp;quot; (the Unix shell invocation sequence), it will be ignored. In conjunction with [[User Reference:BCI2000Shell|BCI2000Shell]], this may be used to write Operator scripts that may be treated as executables.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Escaping.&#039;&#039;&#039; In order to resolve ambiguity about command arguments that contain white space, they must be included in double quotes, or the white space must be encoded in URL-fashion, e.g. &#039;&#039;%20&#039;&#039; instead of a space character. Similarly, when an argument contains a semicolon (;), it must be included in double quotes, or the semicolon must be encoded in URL-fashion, i.e. as &#039;&#039;%3B&#039;&#039;. Also, &amp;quot;$&amp;quot; characters indicate command substitution, so they should be encoded as &#039;&#039;%24&#039;&#039; if substitution is not desired.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Variable Substitution.&#039;&#039;&#039; When a command contains a dollar sign, alphanumeric characters following the dollar sign will be interpreted as the name of a variable: $NAME. The name will be matched against Expression variable names first, followed with Local variable names, and finally Environment variable names. When a match is found, $NAME will be replaced with the content of the matching variable. When no match is found, $NAME will be resolved to an empty string, without triggering an error.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Command Substitution.&#039;&#039;&#039; When part of a command is enclosed with ${...}, this subexpression will be substituted with the result of its execution as a command. E.g.,&lt;br /&gt;
 LOG &amp;quot;Current system state is: ${GET SYSTEM STATE}&amp;quot;&lt;br /&gt;
 LOG &amp;quot;The path environment variable is: ${PATH}&amp;quot;&lt;br /&gt;
Note that the last example uses the short form of the GET command, which will return the value of a PATH parameter or a PATH state if such exists. To make sure that only environment variables are matched, use the long form of the GET command:&lt;br /&gt;
 LOG MESSAGE &amp;quot;The path environment variable is: ${GET VARIABLE PATH}&amp;quot;&lt;br /&gt;
Substitutions may be nested, i.e. the following will work as expected:&lt;br /&gt;
 SET MyVar &amp;quot;LIST STATES&amp;quot;; LOG &amp;quot;States are: ${$MyVar}&amp;quot;&lt;br /&gt;
 SET MyVar &amp;quot;LIST STATES&amp;quot;; LOG &amp;quot;States are: ${${GET VARIABLE MyVar}}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Mathematical Expressions.&#039;&#039;&#039; A command may consist of a single [[User Reference:Expression Syntax|mathematical expression]]. This expression is then evaluated, and its result is returned as the command&#039;s result. As a special case, this allows the use of expression variables in ${...} substitutions. Consider for example&lt;br /&gt;
 x:=0; WHILE x&amp;lt;10; LOG ${x:=x+1}; END&lt;br /&gt;
There, the first command creates and initializes the expression variable x. In the WHILE condition, an expression is allowed as well as any command. In the LOG command, an expression appears in ${...}, which executes the expression in braces, and substitutes the result of the expression as an argument into the LOG command, which adds an entry to the Operator log. This results in a sequence of 10 log entries, containing the numbers from 1 to 10.&lt;br /&gt;
&lt;br /&gt;
===Commands===&lt;br /&gt;
====Control commands====&lt;br /&gt;
These commands allow conditional execution of parts of a script. When a condition is expected, any other scripting command may be given. Its result will be considered to represent a boolean value of &amp;quot;true&amp;quot; if it is empty, a nonzero number, or the string &amp;quot;true&amp;quot;. It will be taken to represent a boolean value of &amp;quot;false&amp;quot; if it contains a numeric value of zero, or any string that does not evaluate to a nonzero number. Note that identification of an empty value with &amp;quot;true&amp;quot; differs from string handling in the EVALUATE CONDITION command. This is because most scripting commands return nothing on success, but an error message on failure.&lt;br /&gt;
&lt;br /&gt;
The output of the SYSTEM and START EXECUTABLE commands is handled specially. There, the result code of the created child process is translated into a boolean value in the ordinary manner, treating a result code of zero as &amp;quot;true&amp;quot;, and any other result code as &amp;quot;false&amp;quot;. This allows to use external commands in the same way as in a native shell.&lt;br /&gt;
&lt;br /&gt;
=====IF &amp;lt;condition&amp;gt;; &amp;lt;if commands&amp;gt;; [ ELSEIF &amp;lt;condition&amp;gt;; &amp;lt;elseif commands&amp;gt;;] ... [ ELSE; &amp;lt;else commands&amp;gt;;] END=====&lt;br /&gt;
Executes &#039;&#039;if commands&#039;&#039; if &#039;&#039;condition&#039;&#039; evaluates to &amp;quot;true&amp;quot;. Otherwise, the &#039;&#039;elseif commands&#039;&#039; of the first matching &#039;&#039;elseif condition&#039;&#039; are executed. When none of the &#039;&#039;elseif conditions&#039;&#039; evaluates to &amp;quot;true&amp;quot;,  &#039;&#039;else commands&#039;&#039; are executed. ELSEIF and ELSE blocks may be omitted.&lt;br /&gt;
&lt;br /&gt;
=====WHILE &amp;lt;condition&amp;gt;; &amp;lt;loop commands&amp;gt;; END=====&lt;br /&gt;
Executes &#039;&#039;loop commands&#039;&#039; while &#039;&#039;condition&#039;&#039; evaluates to &#039;&#039;true&#039;&#039;.&lt;br /&gt;
=====DO; &amp;lt;loop commands&amp;gt;; UNTIL &amp;lt;condition&amp;gt;=====&lt;br /&gt;
Executes &#039;&#039;loop commands&#039;&#039; until &amp;quot;condition&amp;quot; evaluates to &#039;&#039;true&#039;&#039;.&lt;br /&gt;
=====FOR &amp;lt;name&amp;gt; IN &amp;lt;item1&amp;gt; &amp;lt;item2&amp;gt; ... ; &amp;lt;loop commands&amp;gt;; END=====&lt;br /&gt;
Creates a local variable with the specified name. Then, sequentially assigns each &#039;&#039;item&#039;&#039; to that variable, and executes &#039;&#039;loop commands&#039;&#039;. If an &#039;&#039;item&#039;&#039; contains newline characters, it is split up into multiple items, corresponding to the lines contained in the &#039;&#039;item&#039;&#039;. E.g.,&lt;br /&gt;
 FOR i IN top ${LIST FILES} bottom; LOG ${i}; END&lt;br /&gt;
will first write a log entry &amp;quot;top&amp;quot;. Then, it will create a log entry for each file in the current directory, and finally, it will create a log entry &amp;quot;bottom&amp;quot;.&lt;br /&gt;
=====RETURN [&amp;lt;value&amp;gt;]=====&lt;br /&gt;
Finishes execution of the current script, and optionally returns a value to the caller.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on Conditions====&lt;br /&gt;
=====EVALUATE CONDITION &amp;lt;left&amp;gt; [&amp;lt;op&amp;gt; [&amp;lt;right&amp;gt;]]=====&lt;br /&gt;
Evaluates a comparison between the &#039;&#039;left&#039;&#039; and &#039;&#039;right&#039;&#039; operands. As a comparison operator, the following may be specified: ==, !=, ~=, &amp;lt;, &amp;gt;, &amp;lt;=, &amp;gt;=. There, the != operator behaves identically to the ~= operator. When a test for equality is performed, the two operands are treated as strings, and compared in a case-insensitive manner. When any of the inequality tests is performed, the two operands are converted into floating-point numbers before comparison.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;right&#039;&#039; operand may be omitted, in which case it is treated as if an empty string were specified. Also, the &#039;&#039;op&#039;&#039; operator may be omitted, in which case the following rules apply regarding the remaining operand: If it is an empty string, or equal to the string &amp;quot;false&amp;quot; in case-insensitive comparison, the result is &amp;quot;false&amp;quot;. If entirely consists of the text representation of a floating-point number, the result is &amp;quot;false&amp;quot; if the number is 0, and &amp;quot;true&amp;quot; if the number is not 0.&lt;br /&gt;
&lt;br /&gt;
Inspired by the unix sh shells&#039; &amp;lt;tt&amp;gt;test&amp;lt;/tt&amp;gt; command, there exists a short form of the EVALUATE CONDITION command, where the arguments of EVALUATE CONDITION may appear within square brackets. This allows constructs such as&lt;br /&gt;
 IF [ ${MyVar} == MyValue ]; LOG Is equal; ELSE; LOG Is different; END&lt;br /&gt;
Note that the arguments to EVALUATE CONDITION must always be separated by white space, no matter whether its long or short form is used.&lt;br /&gt;
&lt;br /&gt;
Conditions may be combined logically using the operators &amp;amp;&amp;amp; and ||.   These go &#039;&#039;outside&#039;&#039; the square brackets.  Note also that whitespace around the comparison operators is critical, otherwise the conditional will be treated as a single string (which will always evaluate to &amp;quot;true&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
 IF [ ${foo} == foo ] || [ ${bar} == bar ]; LOG got a match; END&lt;br /&gt;
&lt;br /&gt;
====Commands operating on Local Variables====&lt;br /&gt;
Besides environment variables, there exist local variables in scripts. Local variables are inherited by sub-scripts executed with the EXECUTE SCRIPT command, but changes to the variable&#039;s values will not be propagated to the calling script.&lt;br /&gt;
=====SET VARIABLE &amp;lt;name&amp;gt; &amp;lt;value&amp;gt;=====&lt;br /&gt;
Sets the named variable to the specified value.&lt;br /&gt;
=====CLEAR VARIABLE &amp;lt;name&amp;gt;=====&lt;br /&gt;
Removes the named variable from memory.&lt;br /&gt;
=====GET VARIABLE &amp;lt;name&amp;gt;=====&lt;br /&gt;
Returns the variable&#039;s current value. When the variable does not exist, an empty value is returned rather than an error message.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on Environment Variables====&lt;br /&gt;
These scripting commands allow to read and modify environment variables. Changes to environment variables will be visible to child processes started with SYSTEM or START EXECUTABLE. Variable values are stored as strings. Variable names may not contain the equals sign.&lt;br /&gt;
=====SET ENVIRONMENT &amp;lt;name&amp;gt; &amp;lt;value&amp;gt;=====&lt;br /&gt;
Sets the named variable to the specified value.&lt;br /&gt;
=====CLEAR ENVIRONMENT &amp;lt;name&amp;gt;=====&lt;br /&gt;
Removes the named variable from memory.&lt;br /&gt;
=====GET ENVIRONMENT &amp;lt;name&amp;gt;=====&lt;br /&gt;
Returns the variable&#039;s current value. When the variable does not exist, an empty value is returned rather than an error message.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on Scripts====&lt;br /&gt;
=====SET SCRIPT &amp;lt;handler names&amp;gt; &amp;lt;scripting commands&amp;gt;=====&lt;br /&gt;
Associates a sequence of scripting commands with the named handler. Handlers are specified by names as given [[#Handlers|below]]. Multiple handlers may be specified by concatenating their names with a pipe character, e.g. &amp;quot;OnStart|OnResume&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Scripting commands must be included in double quotes, unless they consist of a single word.&lt;br /&gt;
When specifying a sequence of scripting commands, they must be separated with a semicolon character: &amp;quot;SetConfig; Start&amp;quot;. In order to use double quotes or semicolons within the commands themselves, encode these as you would in a URL, i.e. replace a double quote character with &#039;&#039;%22&#039;&#039;, and a semicolon with &#039;&#039;%3B&#039;&#039;: &amp;quot;Load Parameters %22my file%22&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
To use a script file rather than a literal script, use the EXECUTE SCRIPT command:&lt;br /&gt;
 SET SCRIPT OnConnect &amp;quot;EXECUTE SCRIPT myscript.txt&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=====GET SCRIPT &amp;lt;handler name&amp;gt;=====&lt;br /&gt;
Returns the script associated with the specified handler.&lt;br /&gt;
&lt;br /&gt;
=====CLEAR SCRIPT &amp;lt;handler names&amp;gt;=====&lt;br /&gt;
Clears scripts for the given handlers. Equivalent to calling SET SCRIPT with an empty script.&lt;br /&gt;
&lt;br /&gt;
=====EXECUTE SCRIPT &amp;lt;file or handler name&amp;gt; [&amp;lt;Arg1&amp;gt; &amp;lt;Arg2&amp;gt; ... &amp;lt;Arg9&amp;gt;]=====&lt;br /&gt;
Executes a script contained in a file, and optionally sets the script&#039;s local variables &#039;&#039;1&#039;&#039; to &#039;&#039;9&#039;&#039; to the specified values. To execute script commands already associated with a handler, provide a handler name rather than a file. When the script is executed successfully, the result of the last executed script command becomes the result of the EXECUTE SCRIPT command itself. Use &amp;quot;SET Result &amp;lt;value&amp;gt;&amp;quot; as the last command in a script in order to return a certain value.&lt;br /&gt;
&lt;br /&gt;
When you run a script through EXECUTE SCRIPT, it will inherit copies of variables from its calling script/command line. Variable changes will be local to the script, and will be lost when script execution is complete.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;AbortOnError&#039;&#039; variable determines whether a script is aborted when any of its commands result in an error message. &#039;&#039;AbortOnError&#039;&#039; is not inherited but defaults to 1 in any script.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on Parameters====&lt;br /&gt;
=====LOAD PARAMETERFILE &amp;lt;file&amp;gt;, LOAD PARAMETERS &amp;lt;file&amp;gt;=====&lt;br /&gt;
Loads a parameter file specified by its path and name. Relative paths are interpreted relative to the operator module&#039;s working directory at startup. Usually, this matches the executable&#039;s location in the &amp;lt;tt&amp;gt;prog&amp;lt;/tt&amp;gt; directory.&lt;br /&gt;
As the parameter file name must not contain white space, please use HTML-type encoding for white space characters, such as &amp;lt;tt&amp;gt;Documents%20and%20Settings&amp;lt;/tt&amp;gt; when referring to a user&#039;s &amp;quot;Documents and Settings&amp;quot; folder.&lt;br /&gt;
&lt;br /&gt;
NOTE: Only those parameters will be loaded that do exist at the time when this command is called. In idle state, no parameters exist other than created by ADD PARAMETER. After modules are connected and have published their parameters to the Operator module, a full set of parameters exist.&lt;br /&gt;
&lt;br /&gt;
=====ADD PARAMETER &amp;lt;parameter definition&amp;gt;=====&lt;br /&gt;
Adds a parameter to the system. The parameter is specified as a [[Technical_Reference:Parameter_Definition#Parameter_Lines|parameter line]]. This command may not be used after system initialization has completed, i.e. its use is restricted to the &amp;quot;Idle&amp;quot; and &amp;quot;Publishing&amp;quot; [[Technical_Reference:States_of_Operation#Publishing_Phase|phases of system operation]]. In terms of handlers, its use is restricted to the &#039;&#039;OnConnect&#039;&#039; handler.&lt;br /&gt;
=====EXISTS PARAMETER &amp;lt;name&amp;gt;=====&lt;br /&gt;
Returns &amp;quot;true&amp;quot; when the specified parameter exists in the system, and &amp;quot;false&amp;quot; otherwise.&lt;br /&gt;
&lt;br /&gt;
=====ISEMPTY PARAMETER &amp;lt;name&amp;gt;=====&lt;br /&gt;
Returns &amp;quot;true&amp;quot; when the specified parameter exists and has no values, &amp;quot;false&amp;quot; if it exists and has values.&lt;br /&gt;
&lt;br /&gt;
=====SET PARAMETER &amp;lt;name&amp;gt;[( idx1, idx2 )] &amp;lt;value&amp;gt;=====&lt;br /&gt;
Sets the named parameter to the specified value. Values that contain special characters, or whitespace must use the [[Technical_Reference:Parameter_Definition#Special_Characters|parameter value encoding]]. Use parentheses to specify indices or labels. Omitted indices default to 1.&lt;br /&gt;
&lt;br /&gt;
=====SET PARAMETER &amp;lt;parameter line&amp;gt;=====&lt;br /&gt;
Replace a parameter&#039;s value and definition with the information given in the [[Technical_Reference:Parameter_Definition#Parameter_Lines|parameter line]]. The parameter must exist in the system when this command is executed.&lt;br /&gt;
&lt;br /&gt;
=====GET PARAMETER &amp;lt;name&amp;gt;[( idx1, idx2 )]=====&lt;br /&gt;
Prints the value of the named parameter. Use parentheses to specify indices or labels.&lt;br /&gt;
&lt;br /&gt;
=====SET PARAMETERROWS &amp;lt;parameter name&amp;gt; &amp;lt;rows&amp;gt;=====&lt;br /&gt;
Sets the number of rows in the named parameter.&lt;br /&gt;
&lt;br /&gt;
=====GET PARAMETERROWS &amp;lt;parameter name&amp;gt;=====&lt;br /&gt;
Prints the number of rows in the named parameter.&lt;br /&gt;
&lt;br /&gt;
=====SET PARAMETERCOLS &amp;lt;parameter name&amp;gt;=====&lt;br /&gt;
Sets the number of columns in the named parameter.&lt;br /&gt;
&lt;br /&gt;
=====GET PARAMETERCOLS &amp;lt;parameter name&amp;gt;=====&lt;br /&gt;
Prints the number of columns in the named parameter.&lt;br /&gt;
&lt;br /&gt;
=====LIST PARAMETER &amp;lt;wildcard expression&amp;gt;, LIST PARAMETERS=====&lt;br /&gt;
Prints all parameters with names matching the wildcard expression, in form of parameter lines.&lt;br /&gt;
=====CLEAR PARAMETERS=====&lt;br /&gt;
Clears the list of parameters in the system. May only be executed in &#039;&#039;Idle&#039;&#039; and &#039;&#039;Publishing&#039;&#039; system states.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on States====&lt;br /&gt;
In BCI2000, there are three types of States that differ in their alignment to brain signal data (see [[Technical_Reference:State_Definition#Kinds_of_States|Kinds of States]]). This section applies to both Stream States, and normal States.&lt;br /&gt;
For Event States, see the next section.&lt;br /&gt;
&lt;br /&gt;
=====ADD STATE &amp;lt;name&amp;gt; &amp;lt;bit width&amp;gt; &amp;lt;initial value&amp;gt;=====&lt;br /&gt;
Adds a state variable to the system. State variables are defined by name, bit width, and initial value (see [[Technical Reference:State Definition]]). This command may not be used after system initialization has completed, i.e. its use is restricted to the &amp;quot;Idle&amp;quot; and &amp;quot;Publishing&amp;quot; [[Technical_Reference:States_of_Operation#Publishing_Phase|phases of system operation]]. In terms of handlers, its use is restricted to the &#039;&#039;OnConnect&#039;&#039; handler.&lt;br /&gt;
=====EXISTS STATE &amp;lt;name&amp;gt;=====&lt;br /&gt;
Returns &amp;quot;true&amp;quot; when the specified state exists in the system, and &amp;quot;false&amp;quot; otherwise.&lt;br /&gt;
&lt;br /&gt;
=====SET STATE &amp;lt;name&amp;gt; &amp;lt;value&amp;gt;, SET STATES &amp;lt;name1&amp;gt; &amp;lt;value1&amp;gt; &amp;lt;name2&amp;gt; &amp;lt;value2&amp;gt; ...=====&lt;br /&gt;
Sets the named state variable to the specified integer value by sending a state message to the source module.&lt;br /&gt;
Setting the &#039;&#039;Running&#039;&#039; state to 1 will start system operation, setting it to 0 will suspend the system.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;SET STATES&amp;lt;/tt&amp;gt; will atomically set the values of multiple states.&lt;br /&gt;
&lt;br /&gt;
=====GET STATE[(&amp;lt;sample&amp;gt;)] &amp;lt;name&amp;gt;=====&lt;br /&gt;
Gets the value of the named state. Note that state values are not updated from the application module when the &#039;&#039;OperatorBackLink&#039;&#039; parameter is 0. In that case, GET STATE will return the state&#039;s initial value.&lt;br /&gt;
&lt;br /&gt;
An optional one-based sample index may be given to indicate that the state value should be retrieved at the given sample position. Sample positions range from 1 to the number of samples per block present in the state vector. The number of samples per block may be retrieved using GET STATEVECTOR SAMPLES.&lt;br /&gt;
&lt;br /&gt;
By default, the state&#039;s value is retrieved for sample index 1.&lt;br /&gt;
&lt;br /&gt;
=====LIST STATE &amp;lt;wildcard expression&amp;gt;, LIST STATES=====&lt;br /&gt;
Lists all states, or states with names matching the given wildcard expression, in form of state lines.&lt;br /&gt;
=====CLEAR STATES=====&lt;br /&gt;
Clears the list of states in the system. May only be executed in &#039;&#039;Idle&#039;&#039; and &#039;&#039;Publishing&#039;&#039; system states.&lt;br /&gt;
&lt;br /&gt;
=====FREEZE STATES, THAW STATES=====&lt;br /&gt;
Freezes/thaws the values of all states in the state vector, without interfering with system operation.  &amp;quot;Freezing&amp;quot; creates, and &amp;quot;thawing&amp;quot; discards, a frozen snapshot of the state vector. For the duration of its existence, GET STATE calls will be diverted to the snapshot.  This is useful for ensuring that multiple GET STATE commands actually retrieve mutually-consistent values from different state variables (i.e. values from the same sample-block).&lt;br /&gt;
&lt;br /&gt;
=====GET STATEVECTOR SAMPLES=====&lt;br /&gt;
Returns the number of samples in the state vector per block of data. In the system&#039;s &amp;quot;Running&amp;quot; state, this matches the number of samples per block in the source data. Prior to the &amp;quot;Running&amp;quot; state, this is 1 because the state vector has not yet been updated from the application module.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on Events====&lt;br /&gt;
Events are a special type of state, which are recorded asynchronously, at single-sample resolution. Events may only be added while the system is in &amp;quot;idle&amp;quot; state. This kind of events is not related to [[#Handlers|Operator Events]] as defined below.&lt;br /&gt;
=====ADD EVENT &amp;lt;name&amp;gt; &amp;lt;bit width&amp;gt; &amp;lt;initial value&amp;gt;=====&lt;br /&gt;
Adds an event to the system. Like state variables, events are defined by name, bit width, and initial value (see [[Technical Reference:State Definition]]). This command may not be used after the system has started up, so it is typically executed within a telnet session before &#039;&#039;STARTUP&#039;&#039; has been called.&lt;br /&gt;
=====EXISTS EVENT &amp;lt;name&amp;gt;=====&lt;br /&gt;
Returns &amp;quot;true&amp;quot; when the specified event exists in the system, and &amp;quot;false&amp;quot; otherwise.&lt;br /&gt;
&lt;br /&gt;
=====SET EVENT &amp;lt;name&amp;gt; &amp;lt;value&amp;gt;=====&lt;br /&gt;
Asynchronously sets an event to the given value. Recording events requires the EventLink logger component to be present in the source module.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In versions prior to BCI2000 3.06, this command behaved as described for PULSE EVENT below, rather than as advertised. If you used SET EVENT in your scripts, it is recommended to replace it with PULSE EVENT in order to retain original behavior.&lt;br /&gt;
&lt;br /&gt;
=====PULSE EVENT &amp;lt;name&amp;gt; &amp;lt;value&amp;gt;=====&lt;br /&gt;
Asynchronously sets an event to the given value for a single sample duration. Recording events requires the EventLink logger component to be present in the source module.&lt;br /&gt;
&lt;br /&gt;
=====SET EVENTS [&amp;lt;name&amp;gt; &amp;lt;value&amp;gt;] [&amp;lt;name2&amp;gt; &amp;lt;value2&amp;gt;] ... =====&lt;br /&gt;
Asynchronously sets given events to their specified values. Using this command, rather than multiple SET EVENT commands in a row, ensures that all event changes are recorded at exactly the same point in time. Recording events requires the EventLink logger component to be present in the source module.&lt;br /&gt;
&lt;br /&gt;
=====PULSE EVENTS [&amp;lt;name&amp;gt; &amp;lt;value&amp;gt;] [&amp;lt;name2&amp;gt; &amp;lt;value2&amp;gt;] ... =====&lt;br /&gt;
Asynchronously sets given events to their specified values for a single sample duration. Using this command, rather than multiple PULSE EVENT commands in a row, ensures that all event changes are recorded at exactly the same point in time. Recording events requires the EventLink logger component to be present in the source module.&lt;br /&gt;
&lt;br /&gt;
=====GET EVENT[(&amp;lt;sample&amp;gt;)] &amp;lt;name&amp;gt;=====&lt;br /&gt;
Gets the value of the named event. Note that evemt values are not updated from the application module when the &#039;&#039;OperatorBackLink&#039;&#039; parameter is 0.&lt;br /&gt;
&lt;br /&gt;
An optional one-based sample index may be given to indicate that the event&#039;s value should be retrieved at the given sample position. Sample positions range from 1 to the number of samples per block present in the state vector. The number of samples per block may be retrieved using GET STATEVECTOR SAMPLES.&lt;br /&gt;
&lt;br /&gt;
By default, the event&#039;s value is retrieved for sample index 1.&lt;br /&gt;
&lt;br /&gt;
=====LIST EVENT &amp;lt;wildcard expression&amp;gt;, LIST EVENTS=====&lt;br /&gt;
Lists all events, or events with names matching the given wildcard expression, in form of state lines.&lt;br /&gt;
=====CLEAR EVENTS=====&lt;br /&gt;
Clears the list of events in the system. May only be executed in &#039;&#039;Idle&#039;&#039; state.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on VisProperties====&lt;br /&gt;
=====SET VISPROPERTY &amp;lt;visID&amp;gt;.&amp;lt;name&amp;gt; &amp;lt;value&amp;gt;=====&lt;br /&gt;
Sets the named [[Technical Reference:Visualization Properties|visualization property]] for the specified visualization ID to the given value. If the visualization ID contains a dot character, it must be encoded in [[Technical_Reference:Parameter_Definition#Special_Characters|parameter value encoding]]. E.g., setting the window width for the visualization ID &amp;quot;2.D1&amp;quot; would be written &amp;lt;code&amp;gt;SET VISPROPERTY 2%2ED1.Width 200&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=====RESET VISPROPERTY &amp;lt;visID&amp;gt;.&amp;lt;name&amp;gt;=====&lt;br /&gt;
Removes the named visualization property fro the specified visualization ID from the property store, effectively resetting its value to its default.&lt;br /&gt;
&lt;br /&gt;
=====GET VISPROPERTY &amp;lt;visID&amp;gt;.&amp;lt;name&amp;gt;=====&lt;br /&gt;
Prints the value of the named [[Technical Reference:Visualization Properties|visualization property]] for the specified visualization ID.&lt;br /&gt;
&lt;br /&gt;
=====SET VISPROPERTIES &amp;lt;property set ID&amp;gt;=====&lt;br /&gt;
Applies a set of visualization property values as given in the [[#VisPropertySets|VisPropertySets]] parameter. In that matrix-valued parameter, row labels specify visualization properties such as &amp;quot;SRCD.Left&amp;quot;, and columns represent sets of property values. Column labels are IDs of the corresponding property sets.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on the Control Signal====&lt;br /&gt;
=====GET SIGNAL( &amp;lt;channel index&amp;gt;, &amp;lt;element index&amp;gt; )=====&lt;br /&gt;
Prints the value of the control signal at the given indices. Indices are 1-based.&lt;br /&gt;
=====GET SIGNAL CHANNELS=====&lt;br /&gt;
Prints the number of channels in the control signal.&lt;br /&gt;
=====GET SIGNAL ELEMENTS=====&lt;br /&gt;
Prints the number of elements (samples) in the control signal.&lt;br /&gt;
=====FREEZE SIGNAL, THAW SIGNAL=====&lt;br /&gt;
Freezes/thaws the contents of the control signal, without interfering with system operation. &amp;quot;Freezing&amp;quot; creates, and &amp;quot;thawing&amp;quot; discards, a frozen snapshot of the control signal. For the duration of its existence, GET SIGNAL calls will be diverted to the snapshot. This is useful for ensuring that multiple GET SIGNAL commands actually retrieve mutually-consistent values from different elements in the control signal (i.e. values from the same sample-block).&lt;br /&gt;
&lt;br /&gt;
====Commands operating on Expressions====&lt;br /&gt;
=====EVALUATE EXPRESSION &amp;lt;expression&amp;gt;=====&lt;br /&gt;
This command treats the remainder of the command as a literal mathematical expression (for a description, see [[User Reference:Expression Syntax]]. An expression may contain variable assignments; such variables may then be used in later expressions. Note that expression variables are different from local and environment variables that may be accessed by GET/SET VARIABLE/ENVIRONMENT. Expression variables hold numerical values, while local and environment variables hold string values. Also, environment variables are accessible to child processes started with SYSTEM or START EXECUTABLE, while expression variables are accessible only to scripts. When a script is executed using the EXECUTE SCRIPT command, it will inherit a copy of all expression variables present. Changes to these variables from the executed script will not be visible in the parent script.&lt;br /&gt;
&lt;br /&gt;
=====CLEAR EXPRESSION VARIABLE &amp;lt;name&amp;gt;=====&lt;br /&gt;
Clears the named expression variable from storage.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on Watches====&lt;br /&gt;
A &amp;quot;Watch&amp;quot; is an object that consists of a set of expressions, and an action. Whenever the value of any of the expressions changes, the watch is &amp;quot;triggered&amp;quot;, and the action is executed. Watches allow client applications to respond to BCI2000 state changes in a reliable manner. Rather than polling information from BCI2000, a client may create a watch to be notified about changes of interest. This avoids the problem of missing short-lived changes, which is inherent in the polling approach.&lt;br /&gt;
&lt;br /&gt;
For watches created through operator scripting, the action consists of dumping values of all the expressions to a UDP port.&lt;br /&gt;
&lt;br /&gt;
The intended use of a watch from a client application is to create a separate thread that reads from the watch&#039;s UDP port in a blocking mode, and calls an appropriate handler function whenever it receives data.&lt;br /&gt;
The data sent will consist of a single UDP packet with a single line in ASCII format, terminated with a CRLF sequence. The line consists of tab-separated data fields, which contain the current values of the expressions specified when creating the watch. In addition, the first field contains a time stamp in the same time base as the &amp;lt;tt&amp;gt;SourceTime&amp;lt;/tt&amp;gt; state, wrapping around every 65536 ms. This time stamp represents the point in time where the expression value changed, with an accuracy of a single sample.&lt;br /&gt;
&lt;br /&gt;
=====ADD WATCH [decimate &amp;lt;n&amp;gt;] &amp;lt;expression1&amp;gt; &amp;lt;expression2&amp;gt; ... [AT &amp;lt;ip:port&amp;gt;]=====&lt;br /&gt;
Adds a watch for the listed expressions. Each expression&#039;s value will be reported in a separate field. When an address is specified in &amp;lt;tt&amp;gt;ip:port&amp;lt;/tt&amp;gt; format, the watch tries to open that port for output, and creation fails if that port is taken. Otherwise, a free port is chosen automatically. In both cases, successful creation of the watch is indicated by returning the output address in ASCII format. The address is also used to uniquely identify a watch in the context of a connection.&lt;br /&gt;
&lt;br /&gt;
When a &#039;&#039;decimate &amp;lt;n&amp;gt;&#039;&#039; clause is present, the watch will be created with decimation, i.e. it will only be evaluated for every &#039;&#039;n&#039;&#039;th&lt;br /&gt;
sample of the state vector.&lt;br /&gt;
&lt;br /&gt;
If a watch is created through a remote connection, it will use the remote host&#039;s external IP address for automatically chosen addresses. Otherwise, the output port will be associated with the machine&#039;s &amp;lt;tt&amp;gt;localhost&amp;lt;/tt&amp;gt; address.&lt;br /&gt;
&lt;br /&gt;
Watches may be created even if the system is currently running. In this case, the watch is triggered immediately, and sends its current expression values to its output port.&lt;br /&gt;
&lt;br /&gt;
=====ADD WATCH SYSTEM STATE [AT &amp;lt;address&amp;gt;]=====&lt;br /&gt;
Similar to the first variant of ADD WATCH, but will watch the system&#039;s state as reported by GET SYSTEM STATE.&lt;br /&gt;
&lt;br /&gt;
=====CLEAR WATCH &amp;lt;address&amp;gt;, CLEAR WATCHES [&amp;lt;wildcard-expression&amp;gt;]=====&lt;br /&gt;
Removes the watches specified by address, or those with their addresses matching a wildcard expression. If CLEAR WATCHES is called without argument, all watches will be deleted.&lt;br /&gt;
&lt;br /&gt;
=====TRIGGER WATCH &amp;lt;address&amp;gt;, TRIGGER WATCHES  [&amp;lt;wildcard-expression&amp;gt;]=====&lt;br /&gt;
Forces dumping of the watches&#039; current expression values to their output ports. Mostly useful for testing purposes.&lt;br /&gt;
&lt;br /&gt;
=====LIST WATCHES  [&amp;lt;wildcard-expression&amp;gt;]=====&lt;br /&gt;
Displays a list of existing watches, and their addresses.&lt;br /&gt;
&lt;br /&gt;
=====COUNT WATCHES  [&amp;lt;wildcard-expression&amp;gt;]=====&lt;br /&gt;
Returns the number of existing watches, or the number of watches whose addresses match the optional wildcard expression.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on Files, Directories, and Paths====&lt;br /&gt;
=====EXTRACT DIRECTORY &amp;lt;path&amp;gt;, EXTRACT FILE &amp;lt;path&amp;gt;, EXTRACT FILE BASE &amp;lt;path&amp;gt;=====&lt;br /&gt;
Extracts the directory or file portion of a given path. When the path specifies a non-existing directory, the directory name must be followed with a separator (&amp;quot;/&amp;quot;) in order to be recognized as a directory. The EXTRACT DIRECTORY command always returns its result with a trailing separator. The EXTRACT FILE BASE command returns the file portion without extension.&lt;br /&gt;
&lt;br /&gt;
=====IS DIRECTORY &amp;lt;path&amp;gt;, IS FILE &amp;lt;path&amp;gt;, IS PATH &amp;lt;path&amp;gt;=====&lt;br /&gt;
Determines whether the specified path points to an existing directory, file, or any of the two. The result is returned as one of the strings &amp;quot;true&amp;quot; or &amp;quot;false&amp;quot;.&lt;br /&gt;
=====PARENT DIRECTORY &amp;lt;path&amp;gt;=====&lt;br /&gt;
Returns the parent directory of the specified path, independently of whether the path points to a directory, or to a file.&lt;br /&gt;
=====CURRENT DIRECTORY=====&lt;br /&gt;
Returns the current working directory.&lt;br /&gt;
=====CHANGE DIRECTORY &amp;lt;path&amp;gt;=====&lt;br /&gt;
Changes the working directory.&lt;br /&gt;
=====MAKE DIRECTORY &amp;lt;path&amp;gt;=====&lt;br /&gt;
Creates a new directory with the given path. The directory&#039;s parent must exist for the command to succeed.&lt;br /&gt;
=====LIST DIRECTORY [&amp;lt;path&amp;gt; or &amp;lt;wildcard expression&amp;gt;]=====&lt;br /&gt;
Returns a listing of the specified directory, or the current working directory if no path is specified. The listing is in long form. You may use wildcard expressions in order to restrict the output.&lt;br /&gt;
=====LIST FILE &amp;lt;wildcard expression&amp;gt;=====&lt;br /&gt;
Returns a list of file names matching &#039;&#039;wildcard expression&#039;&#039; in the current directory.&lt;br /&gt;
=====LIST FILES [&amp;lt;directory&amp;gt; [&amp;lt;wildcard expression&amp;gt;]]=====&lt;br /&gt;
Returns a list of file names from the specified directory, matching &#039;&#039;wildcard expression&#039;&#039;. When &#039;&#039;wildcard expression&#039;&#039; is missing, all files are listed. When &#039;&#039;directory&#039;&#039; is missing, files in the current directory are listed.&lt;br /&gt;
=====LIST DIRECTORIES [&amp;lt;directory&amp;gt; [&amp;lt;wildcard expression&amp;gt;]]=====&lt;br /&gt;
Returns a list of directory names from the specified directory, matching &#039;&#039;wildcard expression&#039;&#039;. When &#039;&#039;wildcard expression&#039;&#039; is missing, all directories are listed. When &#039;&#039;directory&#039;&#039; is missing, directories in the current directory are listed.&lt;br /&gt;
&lt;br /&gt;
=====RENAME FILE &amp;lt;current path&amp;gt; &amp;lt;new path&amp;gt;, RENAME DIRECTORY &amp;lt;current path&amp;gt; &amp;lt;new name&amp;gt;=====&lt;br /&gt;
Renames a file resp. a directory. For files, a different path may be given in the second argument, resulting in that the file is moved to the location specified by the new path. For directories, the path up to the directory&#039;s name must stay the same.&lt;br /&gt;
=====REMOVE FILE &amp;lt;path&amp;gt;, REMOVE DIRECTORY &amp;lt;path&amp;gt;=====&lt;br /&gt;
Removes the specified file or directory. This command cannot be undone. The directory must be empty for the command to succeed.&lt;br /&gt;
=====FORCEREMOVE DIRECTORY &amp;lt;path&amp;gt;=====&lt;br /&gt;
Removes the specified directory and its contents. Symbolic links are treated as ordinary files, i.e. they are not followed. This command cannot be undone.&lt;br /&gt;
=====NORMALIZED PATH &amp;lt;path&amp;gt;=====&lt;br /&gt;
Returns &amp;lt;path&amp;gt;, with the following transformations applied:&lt;br /&gt;
*Removes relative elements (&amp;lt;tt&amp;gt;..&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;.&amp;lt;/tt&amp;gt;) as far as possible. For absolute paths, the result will not contain any relative elements; for relative paths, double-dots may appear at the beginning of the result if necessary.&lt;br /&gt;
If a relative path simplifies to the empty string, &amp;lt;tt&amp;gt;./&amp;lt;/tt&amp;gt; is returned. Thus, the result of NORMALIZED PATH is never empty, unless its input was empty.&lt;br /&gt;
*Replaces backward slashes with forward slashes to achieve uniformity across platforms.&lt;br /&gt;
*On case-insensitive file systems, replaces the spelling of names with the one stored in the file system.&lt;br /&gt;
*On Win32, replaces short (8.3) names with long ones.&lt;br /&gt;
&lt;br /&gt;
=====CANONICAL PATH &amp;lt;path&amp;gt;=====&lt;br /&gt;
If &amp;lt;path&amp;gt; points to an existing file or directory, CANONICAL PATH returns a valid absolute file path, suitable as an unambiguous representation for the object pointed to. Especially, two non-empty canonical path strings will compare equal if and only if they refer to the same file system object.&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;path&amp;gt; does not point to an existing file system object, construction of a canonical path is not possible due to lack of information about the named object, and CANONICAL PATH will return an empty string.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTES:&#039;&#039;&#039; The need for an unambiguous, or canonical, representation arises due to ambiguities in the string representation of paths, and in file systems themselves.&lt;br /&gt;
*Paths may contain relative elements: &amp;lt;tt&amp;gt;/mydir/../myfile&amp;lt;/tt&amp;gt; points to the same object as &amp;lt;tt&amp;gt;/myfile&amp;lt;/tt&amp;gt;.&lt;br /&gt;
*A path that involves symbolic links will point to the same object as a path containing one or more of those links in resolved form.&lt;br /&gt;
*File systems may be case-insensitive, or may even provide multiple distinct names for individual directory entries (Win32 short vs. long names).&lt;br /&gt;
&lt;br /&gt;
On &#039;&#039;&#039;Win32,&#039;&#039;&#039; CANONICAL PATH returns the short (8.3) representation of a path, using uppercase spelling, and backslashes as directory separators. Apart from efficiency considerations, this aesthetically unpleasing representation has been chosen to discourage its use for anything except comparing file system objects.&lt;br /&gt;
&lt;br /&gt;
On &#039;&#039;&#039;other systems,&#039;&#039;&#039; CANONICAL PATH will return the result of the POSIX &amp;lt;tt&amp;gt;realpath()&amp;lt;/tt&amp;gt; function.&lt;br /&gt;
&lt;br /&gt;
In both cases, a CANONICAL PATH will end with a native directory separator if, and only if, the object pointed to is a directory.&lt;br /&gt;
&lt;br /&gt;
=====REAL PATH &amp;lt;path&amp;gt;=====&lt;br /&gt;
On this command provides a work-alike for the POSIX &amp;lt;tt&amp;gt;realpath()&amp;lt;/tt&amp;gt; function.&lt;br /&gt;
If &amp;lt;path&amp;gt; is empty, or if &amp;lt;path&amp;gt; points to a non-existing object, the result will be empty. Otherwise, an absolute path will be returned, with symbolic links resolved, using forward slashes as directory separators, and with spelling normalized as described for NORMALIZED PATH. A forward slash will be appended if the path points to a directory.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In principle, the path returned by REAL PATH should be just as unambiguous as the result of CANONICAL PATH. However, there are a few caveats:&lt;br /&gt;
* On case-insensitive file systems, two independently obtained results of REAL PATH might differ in case spelling even if referring to the same file system object. This should not be the case for CANONICAL PATH.&lt;br /&gt;
* Determining the result of CANONICAL PATH is a fast operation. In contrast, REAL PATH may be expensive to determine, as for each directory on the path a listing needs to be obtained, and a canonical path needs to be formed, and compared, for half of the listed directory entries on average.&lt;br /&gt;
* On Win32, quite some amount of complexity arises from backward compatibility layers, forbidden file names, multiple filesystem roots, etc. Internally calling &amp;lt;tt&amp;gt;GetShortPathName()&amp;lt;/tt&amp;gt;, CANONICAL PATH does not need to handle that complexity, and may be considered more reliable for identifying file system objects than REAL PATH.&lt;br /&gt;
&lt;br /&gt;
=====READ FILE &amp;lt;filename&amp;gt;=====&lt;br /&gt;
Returns the text content of the file indicated by &amp;lt;filename&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=====WRITE FILE &amp;lt;filename&amp;gt; &amp;lt;line&amp;gt;,  OVERWRITE FILE &amp;lt;filename&amp;gt; &amp;lt;line&amp;gt;, APPEND TO FILE &amp;lt;filename&amp;gt; &amp;lt;line&amp;gt;=====&lt;br /&gt;
These commands write the specified &amp;lt;line&amp;gt; of text to the file indicated by &amp;lt;filename&amp;gt;.   They behave like the &amp;lt;tt&amp;gt;echo&amp;lt;/tt&amp;gt; command of a typical shell, in the sense that a line-ending will be automatically added to the &amp;lt;line&amp;gt; if it does not already end with one. To suppress the automatic line-ending, you can say WRITE FILE &amp;lt;filename&amp;gt; &amp;lt;content&amp;gt; WITHOUT LINE ENDING (or equivalently, for short, you can say WITHOUT LF or WITHOUT CRLF). Any previous content in &amp;lt;file&amp;gt; will be lost if you use WRITE or OVERWRITE (they are the same, just synonyms for each other) whereas APPEND preserves previous content and adds the new &amp;lt;line&amp;gt; to the end.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on executables====&lt;br /&gt;
=====START EXECUTABLE &amp;lt;command line&amp;gt;=====&lt;br /&gt;
Behaves identically to CREATE PROCESS, except that it does not report a process id for the new process. For details, see CREATE PROCESS.&lt;br /&gt;
&lt;br /&gt;
=====CATEGORIZE EXECUTABLE &amp;lt;name or path&amp;gt;=====&lt;br /&gt;
BCI2000 keeps a list of executables/modules that have been built, and sorts them into categories. The CATEGORIZE EXECUTABLE command provides a way to retrieve that information. Given the name or path of an executable, it outputs one of the following categories:&lt;br /&gt;
* SignalSource,&lt;br /&gt;
* SignalProcessing,&lt;br /&gt;
* Application,&lt;br /&gt;
* Operator,&lt;br /&gt;
* Tool,&lt;br /&gt;
* Helper,&lt;br /&gt;
* Unknown.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on Lines of input/output====&lt;br /&gt;
=====WRITE LINE &amp;lt;line&amp;gt;=====&lt;br /&gt;
Writes a line of output. Destination depends on the context in which a script is executed. If the context is an Operator Handler, output is written as a log entry. If the context is a telnet session, output is written to the telnet connection. If the context is a [[User Reference:BCI2000Shell|BCI2000Shell]], output is written to the shell&#039;s stdout.&lt;br /&gt;
&lt;br /&gt;
=====READ LINE=====&lt;br /&gt;
Reads a line of input from the current execution context&#039;s input. If the command is executed within an Operator Handler, it will fail. If executed within a telnet session, the other side of the connection is prompted for input. If executed from within a [[User Reference:BCI2000Shell|BCI2000Shell]], input is read from the shell&#039;s stdin.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on Processes in the Operating System====&lt;br /&gt;
=====CREATE PROCESS &amp;lt;command line&amp;gt;=====&lt;br /&gt;
Starts the specified executable with options. This command returns after the started program has finished initialization, i.e. it will detect load time failures such as missing DLLs on Windows. If the process is still running when CREATE PROCESS returns, its result will be an operating system process id (pid). If the process has terminated, CREATE PROCESS will report its exit code marked with an &amp;lt;tt&amp;gt;ExitCode&amp;lt;/tt&amp;gt; tag to allow distinction between a pid and an exit code.&lt;br /&gt;
Please note that CREATE PROCESS requires quoting of arguments differently from other scripting commands. For details, see the SYSTEM command.&lt;br /&gt;
&lt;br /&gt;
=====TERMINATE PROCESS &amp;lt;pid&amp;gt;=====&lt;br /&gt;
Tries to terminate the process with the given operating system pid, waiting for the process to terminate before returning. Will return &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt; to indicate that a suitable process existed but could not be terminated.&lt;br /&gt;
&lt;br /&gt;
=====WAIT FOR PROCESS &amp;lt;pid&amp;gt; [&amp;lt;timeout seconds&amp;gt; = infinite]=====&lt;br /&gt;
Waits for the process with the given operating system pid to terminate, or the timeout to expire. Returns &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt; to indicate that the process is still executing.&lt;br /&gt;
&lt;br /&gt;
=====SHOW PROCESS &amp;lt;pid&amp;gt;=====&lt;br /&gt;
Makes all windows visible which are associated with the process referred to by pid.&lt;br /&gt;
In addition, brings one of the process&#039; top level (desktop level) windows to the front for user interaction.&lt;br /&gt;
&lt;br /&gt;
=====HIDE PROCESS &amp;lt;pid&amp;gt;=====&lt;br /&gt;
Makes all windows invisible which are associated with the process referred to by pid.&lt;br /&gt;
&lt;br /&gt;
====Global commands====&lt;br /&gt;
=====HELP [&amp;lt;type&amp;gt;]=====&lt;br /&gt;
When called with a type argument, lists commands that exist for the specified type (e.g., SYSTEM, or FILE). When called without argument, lists all commands in their main form. HELP ALL will list all commands, including synonyms.&lt;br /&gt;
&lt;br /&gt;
=====SET &amp;lt;name&amp;gt; &amp;lt;value&amp;gt;, GET &amp;lt;name&amp;gt;, &amp;lt;name&amp;gt;=====&lt;br /&gt;
Allows to set or retrieve the value of local and environment variables. The name is matched against local and environment variables. When no variable with the given name is found, SET will create a local variable, while GET will result in an error. GET may be further abbreviated to only consist of a name.&lt;br /&gt;
&lt;br /&gt;
GET further allows evaluation of [[User_Reference:Expression_Syntax|mathematical expressions]]. When the expression is invalid, or contains an unknown variable, an error is triggered.&lt;br /&gt;
&lt;br /&gt;
=====GET SYSTEM STATE=====&lt;br /&gt;
Prints the current system state. This will be one of Unavailable, Idle, Startup, Initialization, Resting, Suspended, ParamsModified, Running, Termination, Busy.&lt;br /&gt;
&lt;br /&gt;
=====GET CURRENT RUN FILE=====&lt;br /&gt;
Prints the full path to the current run file, or an empty string, if called outside Running state.&lt;br /&gt;
&lt;br /&gt;
=====WAIT FOR &amp;lt;system state&amp;gt; [&amp;lt;timeout seconds&amp;gt;]=====&lt;br /&gt;
Waits until the system is in the specified state. This may be one of Idle, Startup, Connected, Resting, Suspended, ParamsModified, Running, Busy, or a combination of these, separated with a pipe character: &amp;quot;Resting|Suspended&amp;quot;. When no timeout is given, this command waits indefinitely. If the wait is successful, i.e. system state matches one of the specified states, WAIT FOR will return a value of &amp;quot;true&amp;quot;. If timeout occurred, WAIT FOR will return &amp;quot;false&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
If the BCI2000 system is shut down while a script is executing a WAIT FOR command, the script will be terminated with a &amp;quot;wait aborted&amp;quot; error message.&lt;br /&gt;
&lt;br /&gt;
In more detail, user visible states are:&lt;br /&gt;
* Idle: System is shut down and does not do other processing than executing scripts.&lt;br /&gt;
* Startup: System has started up and is listening for incoming connections.&lt;br /&gt;
* Connected: All core modules have connected to the system.&lt;br /&gt;
* Resting: The system has been initialized but is not running.&lt;br /&gt;
* Suspended: The system has ended running and is behaving like in Resting.&lt;br /&gt;
* ParamsModified: In Suspended mode, parameter changes have been published and will be applied at Resume.&lt;br /&gt;
* Running: The system is running, processing brain signals, and displaying stimuli.&lt;br /&gt;
* Busy: The system is performing a transition from one state to another.&lt;br /&gt;
&lt;br /&gt;
As a synonym for &amp;quot;Connected,&amp;quot; &amp;quot;Initialization&amp;quot; is valid as well since it is compatible with the nomenclature in StateMachine.h. Still, it should be avoided because it is easily confused with, but very distinct from, the actions performed in the Initialize() phase.&lt;br /&gt;
&lt;br /&gt;
=====SLEEP &amp;amp;lt;time in seconds&amp;amp;gt;=====&lt;br /&gt;
Waits (sleeps) for the given amount of time. Timing resolution is 50ms. Tends to sleep a little longer than specified, with the error growing with duration.&lt;br /&gt;
&lt;br /&gt;
=====GET SYSTEM VERSION=====&lt;br /&gt;
Prints BCI2000 version information.&lt;br /&gt;
=====SETCONFIG, SET CONFIG=====&lt;br /&gt;
Applies current parameters to the system. Corresponds to the &#039;&#039;SetConfig&#039;&#039; button in the GUI version of the Operator module.&lt;br /&gt;
&lt;br /&gt;
=====START=====&lt;br /&gt;
Starts or resumes system operation, corresponding to the &#039;&#039;Start/Resume&#039;&#039; button in the GUI version of the Operator module.&lt;br /&gt;
=====STOP=====&lt;br /&gt;
Stops system operation. Corresponds to the &#039;&#039;Stop&#039;&#039; button in the GUI version of the Operator.&lt;br /&gt;
=====STARTUP SYSTEM=====&lt;br /&gt;
When in idle state, starts up the system to wait for incoming connections from core modules. Additionally, the following arguments may be given: 1) an IP address on which to listen (default is to listen on all addresses), and 2) a list of generic core module names with ports. The default configuration corresponds to these arguments:&lt;br /&gt;
 STARTUP SYSTEM * SignalSource:4000 SignalProcessing:4001 Application:4002&lt;br /&gt;
&lt;br /&gt;
A system log file may optionally be specified on this line, by inserting the &amp;lt;code&amp;gt;--SystemLogFile&amp;lt;/code&amp;gt; flag between the IP address and the module specifiers. For example:&lt;br /&gt;
&lt;br /&gt;
 STARTUP SYSTEM * --SystemLogFile=SOME_FILE.TXT SignalSource:4000 SignalProcessing:4001 Application:4002&lt;br /&gt;
&lt;br /&gt;
The system log file will record all operator log window messages for the current launch, until the system shuts down.  It may be helpful to use the variables &amp;lt;code&amp;gt;$YYYYMMDD&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;$HHMMSS&amp;lt;/code&amp;gt; to specify the filename.  Note that file name and path cannot contain spaces.&lt;br /&gt;
&lt;br /&gt;
=====SHUTDOWN SYSTEM=====&lt;br /&gt;
Shuts down core modules, and enters idle system state.&lt;br /&gt;
=====RESET SYSTEM=====&lt;br /&gt;
Shuts down the system, and clears all parameter, state, and event information.&lt;br /&gt;
&lt;br /&gt;
=====QUIT, EXIT [&amp;lt;result&amp;gt;]=====&lt;br /&gt;
Quits the operator module after terminating all BCI2000 modules. The optional &#039;&#039;result&#039;&#039; argument determines the result of the executed script.&lt;br /&gt;
&lt;br /&gt;
=====CLOSE CONNECTION, TERMINATE CONNECTION=====&lt;br /&gt;
In the context of a telnet or websocket connection, this command will terminate the connection.&lt;br /&gt;
In other contexts, such as event handlers, it will be ignored.&lt;br /&gt;
&lt;br /&gt;
=====SYSTEM &amp;lt;command line&amp;gt;=====&lt;br /&gt;
Executes a shell command, redirecting any console output into the command&#039;s script result. E.g., to obtain a directory listing, under Windows, you would enter&lt;br /&gt;
 SYSTEM DIR&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Arguments to the SYSTEM command are executed by the operating system&#039;s shell, and thus may require quoting different from the other scripting commands. E.g., writing&lt;br /&gt;
 SET mydir ${PARENT DIRECTORY $BCI2000LAUNCHDIR}; ECHO ${LIST FILES $mydir}&lt;br /&gt;
will list files in the BCI2000 main directory, independently of whether the path to that directory contains space characters or not. However, to obtain a directory listing through the SYSTEM command, you would need to write&lt;br /&gt;
 ECHO ${SYSTEM DIR &amp;quot;$mydir&amp;quot;}&lt;br /&gt;
to make sure the content of the variable &#039;&#039;mydir&#039;&#039; is interpreted as a single argument, independently of whether it contains space characters.&lt;br /&gt;
&lt;br /&gt;
=====LOG &amp;lt;message&amp;gt;=====&lt;br /&gt;
Append the specified message to the system log.&lt;br /&gt;
=====WARN &amp;lt;message&amp;gt;=====&lt;br /&gt;
Append the specified message to the system log, formatted as a warning.&lt;br /&gt;
=====ERROR &amp;lt;message&amp;gt;=====&lt;br /&gt;
Append the specified message to the system log, formatted as an error message.&lt;br /&gt;
&lt;br /&gt;
=====CAPTURE MESSAGES &amp;lt;message types&amp;gt;=====&lt;br /&gt;
Captures system log messages into a background buffer. When no message type is given, all messages are captured. When &amp;quot;None&amp;quot; is given as a message type, message capturing is disabled. Otherwise, the message type must be one of &amp;quot;Errors&amp;quot;, &amp;quot;Warnings&amp;quot;, &amp;quot;Debug&amp;quot;, &amp;quot;Log&amp;quot;. Multiple message types may be specified in a single command. When &amp;quot;None&amp;quot; appears within a single command, all preceding message types are ignored. Multiple CAPTURE MESSAGES commands are cumulative, except when &amp;quot;None&amp;quot; is specified as a message type.&lt;br /&gt;
&lt;br /&gt;
=====FLUSH MESSAGES=====&lt;br /&gt;
Clears the background message buffer, and returns its previous content. Use CAPTURE MESSAGES to capture messages into the background message buffer.&lt;br /&gt;
&lt;br /&gt;
====Operator-module defined Commands====&lt;br /&gt;
=====HIDE WINDOW [&amp;lt;name&amp;gt;], SHOW WINDOW [&amp;lt;name&amp;gt;]=====&lt;br /&gt;
Hides or shows the specified window. When called without a window name, the Operator module&#039;s main window is hidden or shown. The window name may be one of Main, Configuration, Log, Watches, and Visualizations. When &amp;quot;Watches&amp;quot; is given, the window state refers to visibility of the Watches area in the Visualizations window.&lt;br /&gt;
&lt;br /&gt;
=====MOVE WINDOW &amp;lt;name&amp;gt; &amp;lt;x&amp;gt; &amp;lt;y&amp;gt;, RESIZE WINDOW &amp;lt;name&amp;gt; &amp;lt;width&amp;gt; &amp;lt;height&amp;gt;=====&lt;br /&gt;
Moves resp. resizes the specified window with one of the above names.&lt;br /&gt;
Window decorations (title bar, frame) are taken into consideration such that the total size of the window matches the given width and height.&lt;br /&gt;
&lt;br /&gt;
=====ARRANGE WINDOW &amp;lt;name&amp;gt; &amp;lt;rows&amp;gt; &amp;lt;cols&amp;gt; &amp;lt;row&amp;gt; &amp;lt;col&amp;gt; [&amp;lt;rowspan&amp;gt; &amp;lt;colspan&amp;gt;]=====&lt;br /&gt;
Arranges the named window in a virtual &#039;&#039;rows&#039;&#039; x &#039;&#039;cols&#039;&#039; grid at grid position &#039;&#039;row, col&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Optional &#039;&#039;rowspan&#039;&#039; and &#039;&#039;colspan&#039;&#039; arguments may be given to specify the extension of the window across more than one row or column. &lt;br /&gt;
Using a &#039;&#039;rowspan&#039;&#039; of 0 will result in the window assuming its minimum height.&lt;br /&gt;
Likewise, a &#039;&#039;colspan&#039;&#039; of 0 will result in the window&#039;s minimum width.&lt;br /&gt;
&lt;br /&gt;
If multiple screens are present, windows are arranged on the screen that contains the Operator window.&lt;br /&gt;
&lt;br /&gt;
=====SET TITLE &amp;lt;title&amp;gt;=====&lt;br /&gt;
Sets the title of the main Operator window.&lt;br /&gt;
=====SET BUTTON &amp;lt;idx&amp;gt; &amp;lt;label&amp;gt; &amp;lt;commands&amp;gt;=====&lt;br /&gt;
Configures the function button with 1-based index &#039;&#039;idx&#039;&#039; such that it is labelled &#039;&#039;label&#039;&#039; and executes &#039;&#039;commands&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=====VISUALIZE WATCH [decimate &amp;lt;n&amp;gt;] [range &amp;lt;min&amp;gt; &amp;lt;max&amp;gt;] &amp;lt;expression1&amp;gt; ...=====&lt;br /&gt;
Adds a watch for the given expressions to the operator module&#039;s Watches window, and makes the Watches window visible if it is hidden. If the &#039;&#039;decimate&#039;&#039; clause is present, the command will create a watch which will be evaluated only for every &#039;&#039;n&#039;&#039;th sample in the state vector. If the &#039;&#039;range&#039;&#039; clause is present, display minimum and maximum will not be adjusted automatically but will be fixed to the values given.&lt;br /&gt;
&lt;br /&gt;
By default, &#039;&#039;decimate&#039;&#039; has a value of &amp;quot;auto&amp;quot;; this means that there is no decimation of evaluation (i.e., all samples are evaluated) but changes that occur within 1ms will be shortened into their maximum and minimum, and thus reported as only two values.&lt;br /&gt;
This has proven to be efficient for avoiding sluggishness from flooding the application with events.&lt;br /&gt;
&lt;br /&gt;
=====MOVE VISUALIZATON &amp;lt;visID&amp;gt; &amp;lt;x&amp;gt; &amp;lt;y&amp;gt;, RESIZE VISUALIZATION &amp;lt;visID&amp;gt; &amp;lt;width&amp;gt; &amp;lt;height&amp;gt;=====&lt;br /&gt;
Moves resp. resizes the specified visualization window.&lt;br /&gt;
Window decorations (title bar, frame) are taken into consideration such that the total size of the window matches the given width and height. If unknown, visualization IDs may be obtained from the Operator&#039;s &#039;&#039;Window-&amp;gt;Visualizations&#039;&#039; menu.&lt;br /&gt;
&lt;br /&gt;
=====ARRANGE VISUALIZATION &amp;lt;visID&amp;gt; &amp;lt;rows&amp;gt; &amp;lt;cols&amp;gt; &amp;lt;row&amp;gt; &amp;lt;col&amp;gt; [&amp;lt;rowspan&amp;gt; &amp;lt;colspan&amp;gt;]=====&lt;br /&gt;
Arranges the named visualization window in a virtual &#039;&#039;rows&#039;&#039; x &#039;&#039;cols&#039;&#039; grid at grid position &#039;&#039;row, col&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Optional &#039;&#039;rowspan&#039;&#039; and &#039;&#039;colspan&#039;&#039; arguments may be given to specify the extension of the window across more than one row or column. &lt;br /&gt;
Using a &#039;&#039;rowspan&#039;&#039; of 0 will result in the window assuming its minimum height.&lt;br /&gt;
Likewise, a &#039;&#039;colspan&#039;&#039; of 0 will result in the window&#039;s minimum width.&lt;br /&gt;
&lt;br /&gt;
If multiple screens are present, windows are arranged on the screen that contains the Operator window.&lt;br /&gt;
&lt;br /&gt;
=====RECORD VISUALIZATION &amp;lt;visID&amp;gt; [on|off]=====&lt;br /&gt;
Registers the named visualization for recording. The visualization name must be the short name as displayed in the &#039;&#039;View-&amp;gt;Visualizations&#039;&#039; menu. Switching a visualization recording to &amp;quot;on&amp;quot; is only possible in idle state (because an event for recording frame numbers must be registered in the system). When a visualization is registered for recording, its frames are stored immediately as they arrive at the operator module. Currently, only bitmap visualizations may be recorded.&lt;br /&gt;
&lt;br /&gt;
Example: Recording the application window&lt;br /&gt;
 RECORD VISUALIZATION ApplicationWindow on&lt;br /&gt;
 ...&lt;br /&gt;
 # after parameters have been loaded&lt;br /&gt;
 Set parameter VisualizeApplicationWindow 1&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
=====PUT NOTE &amp;lt;note&amp;gt;=====&lt;br /&gt;
Adds the given text to the [[User_Reference:Operator_Notes#Taking_Notes_during_recording_in_Operator|notes window]].&lt;br /&gt;
If the system is in &#039;&#039;Running&#039;&#039; state, the text will also be added to the current notes file as described under&lt;br /&gt;
[[User_Reference:Operator_Notes#Note_storage_and_file_format|&amp;quot;notes file&amp;quot;]].&lt;br /&gt;
&lt;br /&gt;
=====START TELNET &amp;lt;address&amp;gt;, STOP TELNET &amp;lt;address&amp;gt;=====&lt;br /&gt;
Starts or stops a telnet server listening at the given address. The address is in &amp;lt;IP&amp;gt;:&amp;lt;port&amp;gt; format.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IMPORTANT:&#039;&#039;&#039; You should not use this command on global internet addresses, as there is no authentication performed.&lt;br /&gt;
&lt;br /&gt;
=====START WEBSOCKET &amp;lt;address&amp;gt;, STOP WEBSOCKET &amp;lt;address&amp;gt;=====&lt;br /&gt;
Starts or stops a websocket server listening at the given address. The address is in &amp;lt;IP&amp;gt;:&amp;lt;port&amp;gt; format.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IMPORTANT:&#039;&#039;&#039; You should not use this command on global internet addresses, as there is no authentication performed.&lt;br /&gt;
&lt;br /&gt;
====Operator-module Commands for Soliciting Input from the User====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=====CHOOSE [INPUT] FILE[S] [OF TYPE &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]] [STARTING AT &amp;lt;dir&amp;gt;] [WITH PROMPT &amp;lt;message&amp;gt;]=====&lt;br /&gt;
Via the Qt graphical user interface, prompt the user to select an existing file (or multiple files, if the keyword FILES is used). Print the resulting file path(s).&lt;br /&gt;
(See the [[User_Reference:Custom_GUI_Commands|Custom GUI Commands]] page for details and examples.)&lt;br /&gt;
&lt;br /&gt;
=====CHOOSE [OUTPUT] FILE [OF TYPE &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]] [STARTING AT &amp;lt;dir&amp;gt;] [WITH PROMPT &amp;lt;message&amp;gt;]=====&lt;br /&gt;
Via the Qt graphical user interface, prompt the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists). Print the resulting file path.&lt;br /&gt;
(See the [[User_Reference:Custom_GUI_Commands|Custom GUI Commands]] page for details and examples.)&lt;br /&gt;
&lt;br /&gt;
=====CHOOSE DIRECTORY [STARTING AT &amp;lt;dir&amp;gt;] [WITH PROMPT &amp;lt;message&amp;gt;]=====&lt;br /&gt;
Via the Qt graphical user interface, prompt the user to specify a directory. Print the resulting directory path.&lt;br /&gt;
(See the [[User_Reference:Custom_GUI_Commands|Custom GUI Commands]] page for details and examples.)&lt;br /&gt;
&lt;br /&gt;
=====CUSTOM DIALOG [MESSAGE &amp;lt;msg&amp;gt;] [VAR &amp;lt;varname&amp;gt; &amp;lt;label&amp;gt; {[&amp;lt;options&amp;gt;]} ] [BUTTONS {&amp;lt;buttons&amp;gt;}] ... =====&lt;br /&gt;
Via the Qt graphical user interface, prompt the user with a modal dialog that can be flexibly customized.&lt;br /&gt;
(See the [[User_Reference:Custom_GUI_Commands|Custom GUI Commands]] page for details and examples.)&lt;br /&gt;
&lt;br /&gt;
===Predefined Variables===&lt;br /&gt;
The following variables exist when an Operator script is executed.&lt;br /&gt;
Some of these variables are marked with &#039;&#039;local&#039;&#039;. This means that they are not environment variables, i.e. they are invisible to child processes that are launched using the SYSTEM or START EXECUTABLE commands, and their values may be different between script invocations. In script code, they are accessed like ordinary variables.&lt;br /&gt;
====BCI2000LAUNCHDIR====&lt;br /&gt;
The full absolute path to the directory where the Operator module resides. This is also prepended to the PATH environment variable, such that executables from the current BCI2000 installation will have precedence over any other executable with the same name.&lt;br /&gt;
&lt;br /&gt;
On macOS, this is the path where the Operator module&#039;s application bundle resides. In the default configuration, this is the BCI2000 prog directory, both on macOS and on other platforms.&lt;br /&gt;
&lt;br /&gt;
====BCI2000BINARY====&lt;br /&gt;
The full absolute path to the Operator module.&lt;br /&gt;
====LogLevel (local)====&lt;br /&gt;
Determines the amount of log information written to the Operator log. This variable only affects log messages originating from the current script. May be 2 (display all log messages), 1 (display fewer log messages), or 0 (suppress all log messages). Set to 1 by default. Changes to this local variable are not propagated to any sub-scripts called. &#039;&#039;NOTE:&#039;&#039; Only log messages are controlled by this variable. Error messages originating from a script with &#039;LogLevel 0&#039; will still be displayed in the Operator log. When &#039;AbortOnError&#039; is set to 0, you may set &#039;LogLevel&#039; to -1 in order to display error messages. When &#039;AbortOnError&#039; is 1 (the default), error messages will always be displayed to indicate the reason for failure.&lt;br /&gt;
&lt;br /&gt;
====AbortOnError (local)====&lt;br /&gt;
Determines if a script is aborted when an error happens, or whether the error is silently ignored. Set to 1 by default (script is aborted on error). Changes to this local variable are not propagated to any sub-scripts called.&lt;br /&gt;
&lt;br /&gt;
====Result (local)====&lt;br /&gt;
The result of the last executed scripting command. When a script is executed by calling EXECUTE SCRIPT, the script&#039;s last executed command determines the result of the EXECUTE SCRIPT command itself.&lt;br /&gt;
&lt;br /&gt;
====0, 1, ... 9 (local)====&lt;br /&gt;
When a script file is being executed, these variables contain the arguments of the EXECUTE SCRIPT command.&lt;br /&gt;
&#039;&#039;$0&#039;&#039; resolves to the full absolute path to the current script file. Within scripts, all of the &#039;&#039;0-9&#039;&#039; variables are defined, and those that do not have a matching argument are empty.&lt;br /&gt;
&lt;br /&gt;
====YYYYMMDD (local)====&lt;br /&gt;
Local time at execution of the current script, in YYYYMMDD format. In interactive sessions, reflects the time when the session was initiated.&lt;br /&gt;
&lt;br /&gt;
====HHMMSS (local)====&lt;br /&gt;
Local time at execution of the current script, in HHMMSS format. In interactive sessions, reflects the time when the session was initiated.&lt;br /&gt;
&lt;br /&gt;
===Abbreviated commands and synonyms===&lt;br /&gt;
To minimize the need of consulting documentation, as well as for backward compatibility, a number of &#039;&#039;&#039;synonymous commands&#039;&#039;&#039; are provided. E.g., states may be added by INSERT STATE as well as ADD STATE, and the existence of a file may be queried by IS FILE as well as EXISTS FILE. For an overview over all allowed forms of commands, use the HELP ALL command.&lt;br /&gt;
&lt;br /&gt;
To simplify operation in interactive sessions, &#039;&#039;&#039;abbreviated commands&#039;&#039;&#039; exist. Currently, these are:&lt;br /&gt;
:&#039;&#039;&#039;cd&#039;&#039;&#039; for CHANGE DIRECTORY,&lt;br /&gt;
:&#039;&#039;&#039;pwd&#039;&#039;&#039; and &#039;&#039;&#039;cd&#039;&#039;&#039; without argument for CURRENT DIRECTORY,&lt;br /&gt;
:&#039;&#039;&#039;ls&#039;&#039;&#039; and &#039;&#039;&#039;dir&#039;&#039;&#039; for LIST DIRECTORY,&lt;br /&gt;
:&#039;&#039;&#039;mkdir&#039;&#039;&#039; for MAKE DIRECTORY,&lt;br /&gt;
:&#039;&#039;&#039;echo&#039;&#039;&#039; for WRITE LINE,&lt;br /&gt;
:&#039;&#039;&#039;realpath&#039;&#039;&#039; for REAL PATH,&lt;br /&gt;
:&#039;&#039;&#039;dirname&#039;&#039;&#039; for EXTRACT DIRECTORY,&lt;br /&gt;
:&#039;&#039;&#039;basename&#039;&#039;&#039; for EXTRACT FILE BASE.&lt;br /&gt;
&lt;br /&gt;
===Handlers===&lt;br /&gt;
In the Operator GUI, script execution is bound to a number of Operator Events (not to be confused with Event states, above) that occur during various [[Technical Reference:States of Operation|stages of BCI2000 system operation]]:&lt;br /&gt;
====OnConnect====&lt;br /&gt;
This handler runs at startup, as soon as all modules are connected to the operator module.&lt;br /&gt;
====OnSetConfig====&lt;br /&gt;
This handler runs each time a set of parameters is applied to the system. This happens when the user clicks the &#039;&#039;SetConfig&#039;&#039; button. Execution of the &#039;&#039;SETCONFIG&#039;&#039; command also runs this handler.&lt;br /&gt;
&lt;br /&gt;
====OnStart, OnResume====&lt;br /&gt;
These handlers are triggered by the &#039;&#039;Start&#039;&#039;/&#039;&#039;Resume&#039;&#039; button. One of these handlers is also triggered when the &#039;&#039;Running&#039;&#039; state variable is set to 1 from a script. Whether &#039;&#039;OnStart&#039;&#039; or &#039;&#039;OnResume&#039;&#039; is triggered depends on whether the system has been running before with the current set of parameters.&lt;br /&gt;
&lt;br /&gt;
====OnStartRun====&lt;br /&gt;
Similarly to OnStart and OnResume, this handler is triggered by the &#039;&#039;Start&#039;&#039;/&#039;&#039;Resume&#039;&#039; button. Unlike other event handlers, OnStartRun has an argument, which is the current run file.&lt;br /&gt;
&lt;br /&gt;
OnStart or OnResume are triggered immediately after &#039;&#039;Start&#039;&#039;/&#039;&#039;Resume&#039;&#039; has been pressed, whereas OnStartRun is deferred until modules have confirmed to be in Running state. This makes sure that the OnStartRun event handler receives a valid run file name.&lt;br /&gt;
&lt;br /&gt;
====OnNextFilePart====&lt;br /&gt;
This handler is triggered during a run, whenever the &#039;&#039;FilePart&#039;&#039; event state is incremented. It allows scripts to know when a new&lt;br /&gt;
partial file has begun. For further information, see the [[User_Reference:BCI2000FileWriter#FileSplittingCondition|FileSplittingCondition]] parameter.&lt;br /&gt;
&lt;br /&gt;
====OnSuspend/OnStopRun====&lt;br /&gt;
Triggered when the system goes from running into suspended mode. This happens whenever the &#039;&#039;Running&#039;&#039; state variable changes from 1 to 0. This may happen when the user clicks &#039;&#039;Suspend&#039;&#039;, when the application module switches the system into suspended mode, or when a script sets the &#039;&#039;Running&#039;&#039; state variable to 0.&lt;br /&gt;
&lt;br /&gt;
====OnShutdown====&lt;br /&gt;
Triggered when the operator module shuts down connections, and switches into idle state.&lt;br /&gt;
&lt;br /&gt;
====OnExit====&lt;br /&gt;
Triggered when the operator module exits. Execution of the QUIT command also triggers this handler. This handler is not available to the SET SCRIPT and CLEAR SCRIPT commands. Also, when both an OnShutdown and an OnExit script are defined, the OnExit script may be executed before the OnShutdown script.&lt;br /&gt;
&lt;br /&gt;
====Associating Scripts with Operator Events====&lt;br /&gt;
In the operator module&#039;s preferences dialog, script commands may be entered for each of the handlers listed above.&lt;br /&gt;
Scripts may be specified as paths to script files, or as immediate one-line scripts.&lt;br /&gt;
Entries that start with a minus sign (-) are treated as one-line scripts, which may contain multiple commands separated with semicolons.&lt;br /&gt;
&lt;br /&gt;
Scripts may also be specified from the command line used to start up the operator module. There, handler names are followed with the content of the respective preference entry, enclosed in double quotes (&amp;quot;...&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Finally, scripts may be specified using the SET SCRIPT command of the scripting language itself.&lt;br /&gt;
&lt;br /&gt;
===Examples===&lt;br /&gt;
====Making use of the Operator module&#039;s Function Buttons====&lt;br /&gt;
To add a state variable called &amp;quot;Artifact&amp;quot;, and to set it using the operator&#039;s function buttons, do this:&lt;br /&gt;
*Enter the following line under &amp;quot;After All Modules Connected&amp;quot; in the operator&#039;s preferences dialog (note the minus sign):&lt;br /&gt;
 -ADD STATE Artifact 1 0&lt;br /&gt;
*Under &amp;quot;Function Buttons&amp;quot;, enter &amp;quot;Set Artifact&amp;quot; as the name of button 1, and as its command, enter (note there is no minus sign):&lt;br /&gt;
 SET STATE Artifact 1&lt;br /&gt;
*Enter &amp;quot;Clear Artifact&amp;quot; as the name of button 2, and as its command, enter&lt;br /&gt;
 SET STATE Artifact 0&lt;br /&gt;
&lt;br /&gt;
====A fully automated BCI2000 session====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Echo Please enter a subject ID:&lt;br /&gt;
Set SubjectID ${Read line}&lt;br /&gt;
&lt;br /&gt;
Startup system&lt;br /&gt;
Start executable SignalGenerator&lt;br /&gt;
Start executable SpectralSignalProcessing&lt;br /&gt;
Start executable CursorTask&lt;br /&gt;
Wait for Connected&lt;br /&gt;
Load parameterfile &amp;quot;../parms/examples/CursorTask_SignalGenerator.prm&amp;quot;&lt;br /&gt;
For i in 1 2 3&lt;br /&gt;
  Load parameterfile &amp;quot;../parms/MyExperiment/Session$i.prm&amp;quot;&lt;br /&gt;
  Set parameter SubjectName $SubjectID&lt;br /&gt;
  Set parameter SubjectSession $i&lt;br /&gt;
  Set config&lt;br /&gt;
  Wait for Resting&lt;br /&gt;
  Start&lt;br /&gt;
  Wait for Suspended 1000&lt;br /&gt;
End&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Automating BCI2000 by Operator command line arguments====&lt;br /&gt;
The following example shows how to specify script commands from the command line.&lt;br /&gt;
It fully automates BCI2000 operation by loading a parameter file, applying parameters, starting the system once the parameters are applied, and quitting the system once the run is over. For better readability, the example is broken across lines, using the ^ DOS line continuation character.&lt;br /&gt;
&lt;br /&gt;
 operator.exe --OnConnect &amp;quot;-LOAD PARAMETERFILE ../parms/examples/CursorTask_SignalGenerator.prm; SETCONFIG&amp;quot; ^&lt;br /&gt;
              --OnSetConfig &amp;quot;-SET STATE Running 1&amp;quot;  ^&lt;br /&gt;
              --OnSuspend &amp;quot;-QUIT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
====Automatically arranging windows in a 4x2 grid====&lt;br /&gt;
The following example arranges Source and Roundtrip visualizations on the left side of the screen.&lt;br /&gt;
On the right side, a large area is dedicated to the Operator&#039;s log window, and the Operator&#039;s main window sits at the bottom right.&lt;br /&gt;
&lt;br /&gt;
 Arrange Visualization SRCD 4 2 1 1 2 1&lt;br /&gt;
 Arrange Visualization RNDT 4 2 3 1&lt;br /&gt;
 Arrange Window Main 4 2 4 2&lt;br /&gt;
 Arrange Window Log  4 2 1 2 3 1&lt;br /&gt;
&lt;br /&gt;
[[File:Operator_Arrangement.PNG|center|640px|border]]&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
[[User Reference:Module Command Line Options]], [[User Reference:Operator Module]], [[User Reference:BCI2000Shell]], [[Technical Reference:States of Operation]]&lt;br /&gt;
&lt;br /&gt;
[[Category:User Interface]]&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12093</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12093"/>
		<updated>2025-09-04T18:59:29Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* CUSTOM DIALOG ... */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
__FORCETOC__&lt;br /&gt;
&lt;br /&gt;
===CHOOSE ...===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CHOOSE&amp;lt;/code&amp;gt; family of commands prompt the user to specify file or directory paths, via the Qt graphical user interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILE&amp;lt;/code&amp;gt;  (or equivalently &amp;lt;code&amp;gt;CHOOSE FILE&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CHOOSE INPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select a single existing file, and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILES&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE FILES&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select one or more existing files, and prints the resulting file paths one per line (&amp;lt;code&amp;gt;FOR ... IN ...&amp;lt;/code&amp;gt; can iterate over these).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE OUTPUT FILE&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE OUTPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists) and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;&lt;br /&gt;
: Prompts the user to specify a directory, and prints the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
If the user cancels the dialog, the commands print nothing.&lt;br /&gt;
&lt;br /&gt;
The commands may be followed by one or more of the following optional clauses (they must appear in this order):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[OF] TYPE[S] &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This limits the view (via a drop-down file-type selector) to files that have the specified extension(s). This clause cannot be used with &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;.  Instead of a file extension (starting with a dot) you can alternatively specify a glob pattern (containing a star). You can include &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt; (or equivalently &amp;lt;code&amp;gt;*.*&amp;lt;/code&amp;gt;) in the list if you want to give the user the option of overriding the limitation.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[STARTING] AT &amp;lt;dir&amp;gt;&amp;lt;/code&amp;gt; (equivalently you can say &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;FROM&amp;lt;/code&amp;gt; if it reads better)&lt;br /&gt;
: This specifies where the dialog&#039;s file-system navigation should start (by default, it will start in the current working directory).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[WITH] PROMPT &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This specifies the text prompt at the top of the dialog.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
choose file of type .dat from ../data/samplefiles with prompt &amp;quot;Choose a data file for playback:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose output file of type .prm in ../parms with prompt &amp;quot;Save parameters as...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose directory starting at ../data with prompt &amp;quot;Select a subject directory:&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===CUSTOM DIALOG ...===&lt;br /&gt;
&lt;br /&gt;
This command assembles a flexibly customizable modal dialog for communicating with the user. The command returns (prints) a string denoting which button the user pressed to complete the dialog, and as a side effect it may set any environment variables that the command specifies.  If the user cancels the dialog, the command does nothing (prints nothing, does not change any environment variables).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command can be followed by as many clauses as you like. The main types of clause are &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog, in the order you provide. Possible clauses are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Each message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule. Simplest example: &amp;lt;pre&amp;gt;custom dialog message &amp;quot;Hello world!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. For example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used, in conjunction with an empty first/default option, to force the user to make an explicit selection, as in the following example (note the leading &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt; character inside the braces): &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, will be the one that gets highlighted by default and bound to the enter/return keystroke. If you do not specify a default, then &amp;quot;Ok&amp;quot; will be assumed to be the default button. If the designated default does not appear in the list of buttons, the buttons will all have equal status with no return-keystroke binding. The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke, and pressing this button is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).  For most purposes, you will probably not need to override the button configuration explicitly. In dialogs without &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are simply displaying messages to the user), the &amp;lt;code&amp;gt;BUTTONS {Ok} DEFAULT Ok&amp;lt;/code&amp;gt; configuration is assumed. In dialogs with one or more &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are asking the user for information), the &amp;lt;code&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel&amp;lt;/code&amp;gt; configuration is assumed.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TITLE &amp;lt;text&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This overrides the default dialog title &amp;quot;BCI2000&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;SPACING &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical spacing between successive &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; elements.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;WIDTH &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;HEIGHT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum height of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;LEFT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the horizontal coordinate of the dialog&#039;s left edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TOP &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical coordinate of the dialog&#039;s top edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Integrated &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; example====&lt;br /&gt;
&lt;br /&gt;
The following partial listing illustrates one way &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; might be used to implement a simplified launcher GUI, for a hypothetical auditory BCI experiment.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# [initialize system]&lt;br /&gt;
# [start up modules]&lt;br /&gt;
# [load baseline parameters for this BCI]&lt;br /&gt;
# [optionally, you could pre-initialize environment variables subjectName, runType and stimulusCondition]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
set environment launcherAction ${&lt;br /&gt;
    custom dialog &lt;br /&gt;
        title &amp;quot;Auditory BCI Launcher&amp;quot; &lt;br /&gt;
        var subjectName &amp;quot;Subject ID:&amp;quot; {} default $subjectName minimum 1 &lt;br /&gt;
        var runType &amp;quot;Run Type:&amp;quot; {Calibration|Free Selection} default $runType &lt;br /&gt;
        var stimulusCondition &amp;quot;Stimulus Condition:&amp;quot; {SlowStimuli.prm|FastStimuli.prm} default $stimulusCondition &lt;br /&gt;
        message &amp;quot;NB: each condition should be calibrated separately.&amp;quot; &lt;br /&gt;
        buttons {Quit|Launch} default Launch escape Quit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if [ $launcherAction == &amp;quot;&amp;quot; ]&lt;br /&gt;
    quit&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if [ $runType == Calibration ]&lt;br /&gt;
    load parameterfile ../parms/calib.prm       # let&#039;s assume you have created this&lt;br /&gt;
else&lt;br /&gt;
    load parameterfile ../parms/free.prm        # and this&lt;br /&gt;
end&lt;br /&gt;
load parameterfile ../parms/$stimulusCondition  # and these&lt;br /&gt;
set parameter SubjectName $subjectName&lt;br /&gt;
setconfig&lt;br /&gt;
show window   # unless you have some other remote-control mechanism for suspending/resuming runs&lt;br /&gt;
set state Running 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The resulting dialog looks like this:&lt;br /&gt;
&lt;br /&gt;
[[File:CustomDialogExample.png]]&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12092</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12092"/>
		<updated>2025-09-02T14:39:25Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* CHOOSE ... */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
__FORCETOC__&lt;br /&gt;
&lt;br /&gt;
===CHOOSE ...===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CHOOSE&amp;lt;/code&amp;gt; family of commands prompt the user to specify file or directory paths, via the Qt graphical user interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILE&amp;lt;/code&amp;gt;  (or equivalently &amp;lt;code&amp;gt;CHOOSE FILE&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CHOOSE INPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select a single existing file, and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILES&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE FILES&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select one or more existing files, and prints the resulting file paths one per line (&amp;lt;code&amp;gt;FOR ... IN ...&amp;lt;/code&amp;gt; can iterate over these).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE OUTPUT FILE&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE OUTPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists) and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;&lt;br /&gt;
: Prompts the user to specify a directory, and prints the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
If the user cancels the dialog, the commands print nothing.&lt;br /&gt;
&lt;br /&gt;
The commands may be followed by one or more of the following optional clauses (they must appear in this order):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[OF] TYPE[S] &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This limits the view (via a drop-down file-type selector) to files that have the specified extension(s). This clause cannot be used with &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;.  Instead of a file extension (starting with a dot) you can alternatively specify a glob pattern (containing a star). You can include &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt; (or equivalently &amp;lt;code&amp;gt;*.*&amp;lt;/code&amp;gt;) in the list if you want to give the user the option of overriding the limitation.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[STARTING] AT &amp;lt;dir&amp;gt;&amp;lt;/code&amp;gt; (equivalently you can say &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;FROM&amp;lt;/code&amp;gt; if it reads better)&lt;br /&gt;
: This specifies where the dialog&#039;s file-system navigation should start (by default, it will start in the current working directory).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[WITH] PROMPT &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This specifies the text prompt at the top of the dialog.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
choose file of type .dat from ../data/samplefiles with prompt &amp;quot;Choose a data file for playback:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose output file of type .prm in ../parms with prompt &amp;quot;Save parameters as...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose directory starting at ../data with prompt &amp;quot;Select a subject directory:&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===CUSTOM DIALOG ...===&lt;br /&gt;
&lt;br /&gt;
This command assembles a flexibly customizable modal dialog for communicating with the user. The command returns (prints) a string denoting which button the user pressed to complete the dialog, and as a side effect it may set any environment variables that the command specifies.  If the user cancels the dialog, the command does nothing (prints nothing, does not change any environment variables).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command can be followed by as many clauses as you like. The main types of clause are &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog, in the order you provide. Possible clauses are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Each message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule. Simplest example: &amp;lt;pre&amp;gt;custom dialog message &amp;quot;Hello world!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. For example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used, in conjunction with an empty first/default option, to force the user to make an explicit selection, as in the following example (note the leading &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt; character inside the braces): &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, will be the one that gets highlighted by default and bound to the enter/return keystroke. If you do not specify a default, then &amp;quot;Ok&amp;quot; will be assumed to be the default button; if the designated default does not appear in the list of buttons, the buttons will all have equal status with no return-keystroke binding). The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke, and pressing this button is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).  You will probably not need to configure the buttons explicitly in most cases. In dialogs without &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are simply displaying messages to the user), the &amp;lt;code&amp;gt;BUTTONS {Ok} DEFAULT Ok&amp;lt;/code&amp;gt; configuration is assumed. In dialogs with one or more &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are asking the user for information), the &amp;lt;code&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel&amp;lt;/code&amp;gt; configuration is assumed.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TITLE &amp;lt;text&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This overrides the default dialog title &amp;quot;BCI2000&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;SPACING &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical spacing between successive &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; elements.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;WIDTH &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;HEIGHT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum height of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;LEFT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the horizontal coordinate of the dialog&#039;s left edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TOP &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical coordinate of the dialog&#039;s top edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Integrated &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; example====&lt;br /&gt;
&lt;br /&gt;
The following partial listing illustrates one way &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; might be used to implement a simplified launcher GUI, for a hypothetical auditory BCI experiment.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# [initialize system]&lt;br /&gt;
# [start up modules]&lt;br /&gt;
# [load baseline parameters for this BCI]&lt;br /&gt;
# [optionally, you could pre-initialize environment variables subjectName, runType and stimulusCondition]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
set environment launcherAction ${&lt;br /&gt;
    custom dialog &lt;br /&gt;
        title &amp;quot;Auditory BCI Launcher&amp;quot; &lt;br /&gt;
        var subjectName &amp;quot;Subject ID:&amp;quot; {} default $subjectName minimum 1 &lt;br /&gt;
        var runType &amp;quot;Run Type:&amp;quot; {Calibration|Free Selection} default $runType &lt;br /&gt;
        var stimulusCondition &amp;quot;Stimulus Condition:&amp;quot; {SlowStimuli.prm|FastStimuli.prm} default $stimulusCondition &lt;br /&gt;
        message &amp;quot;NB: each condition should be calibrated separately.&amp;quot; &lt;br /&gt;
        buttons {Quit|Launch} default Launch escape Quit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if [ $launcherAction == &amp;quot;&amp;quot; ]&lt;br /&gt;
    quit&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if [ $runType == Calibration ]&lt;br /&gt;
    load parameterfile ../parms/calib.prm       # let&#039;s assume you have created this&lt;br /&gt;
else&lt;br /&gt;
    load parameterfile ../parms/free.prm        # and this&lt;br /&gt;
end&lt;br /&gt;
load parameterfile ../parms/$stimulusCondition  # and these&lt;br /&gt;
set parameter SubjectName $subjectName&lt;br /&gt;
setconfig&lt;br /&gt;
show window   # unless you have some other remote-control mechanism for suspending/resuming runs&lt;br /&gt;
set state Running 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The resulting dialog looks like this:&lt;br /&gt;
&lt;br /&gt;
[[File:CustomDialogExample.png]]&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12091</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12091"/>
		<updated>2025-09-01T18:05:07Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* Integrated CUSTOM DIALOG example */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
__FORCETOC__&lt;br /&gt;
&lt;br /&gt;
===CHOOSE ...===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CHOOSE&amp;lt;/code&amp;gt; family of commands prompt the user to specify file or directory paths, via the Qt graphical user interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILE&amp;lt;/code&amp;gt;  (or equivalently &amp;lt;code&amp;gt;CHOOSE FILE&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CHOOSE INPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select a single existing file, and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILES&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE FILES&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select one or more existing files, and prints the resulting file paths one per line (&amp;lt;code&amp;gt;FOR ... IN ...&amp;lt;/code&amp;gt; can iterate over these).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE OUTPUT FILE&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE OUTPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists) and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;&lt;br /&gt;
: Prompts the user to specify a directory, and prints the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
If the user cancels the dialog, the commands print nothing.&lt;br /&gt;
&lt;br /&gt;
The commands may be followed by one or more of the following optional clauses (they must appear in this order):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[OF] TYPE[S] &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This limits the view (via a drop-down file-type selector) to files that have the specified extension(s). This clause cannot be used with &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;.  Instead of a file extension (starting with a dot) you can alternatively specify a glob pattern (containing a star). You can include &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt; (or equivalently &amp;lt;code&amp;gt;*.*&amp;lt;/code&amp;gt;) in the list if you want to allow the user to override the limitation.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[STARTING] AT &amp;lt;dir&amp;gt;&amp;lt;/code&amp;gt; (equivalently you can say &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;FROM&amp;lt;/code&amp;gt; if it reads better)&lt;br /&gt;
: This specifies where the dialog&#039;s file-system navigation should start (by default, it will start in the current working directory).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[WITH] PROMPT &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This specifies the text prompt at the top of the dialog.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
choose file of type .dat from ../data/samplefiles with prompt &amp;quot;Choose a data file for playback:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose output file of type .prm in ../parms with prompt &amp;quot;Save parameters as...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose directory starting at ../data with prompt &amp;quot;Select a subject directory:&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===CUSTOM DIALOG ...===&lt;br /&gt;
&lt;br /&gt;
This command assembles a flexibly customizable modal dialog for communicating with the user. The command returns (prints) a string denoting which button the user pressed to complete the dialog, and as a side effect it may set any environment variables that the command specifies.  If the user cancels the dialog, the command does nothing (prints nothing, does not change any environment variables).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command can be followed by as many clauses as you like. The main types of clause are &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog, in the order you provide. Possible clauses are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Each message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule. Simplest example: &amp;lt;pre&amp;gt;custom dialog message &amp;quot;Hello world!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. For example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used, in conjunction with an empty first/default option, to force the user to make an explicit selection, as in the following example (note the leading &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt; character inside the braces): &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, will be the one that gets highlighted by default and bound to the enter/return keystroke. If you do not specify a default, then &amp;quot;Ok&amp;quot; will be assumed to be the default button; if the designated default does not appear in the list of buttons, the buttons will all have equal status with no return-keystroke binding). The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke, and pressing this button is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).  You will probably not need to configure the buttons explicitly in most cases. In dialogs without &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are simply displaying messages to the user), the &amp;lt;code&amp;gt;BUTTONS {Ok} DEFAULT Ok&amp;lt;/code&amp;gt; configuration is assumed. In dialogs with one or more &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are asking the user for information), the &amp;lt;code&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel&amp;lt;/code&amp;gt; configuration is assumed.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TITLE &amp;lt;text&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This overrides the default dialog title &amp;quot;BCI2000&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;SPACING &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical spacing between successive &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; elements.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;WIDTH &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;HEIGHT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum height of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;LEFT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the horizontal coordinate of the dialog&#039;s left edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TOP &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical coordinate of the dialog&#039;s top edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Integrated &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; example====&lt;br /&gt;
&lt;br /&gt;
The following partial listing illustrates one way &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; might be used to implement a simplified launcher GUI, for a hypothetical auditory BCI experiment.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# [initialize system]&lt;br /&gt;
# [start up modules]&lt;br /&gt;
# [load baseline parameters for this BCI]&lt;br /&gt;
# [optionally, you could pre-initialize environment variables subjectName, runType and stimulusCondition]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
set environment launcherAction ${&lt;br /&gt;
    custom dialog &lt;br /&gt;
        title &amp;quot;Auditory BCI Launcher&amp;quot; &lt;br /&gt;
        var subjectName &amp;quot;Subject ID:&amp;quot; {} default $subjectName minimum 1 &lt;br /&gt;
        var runType &amp;quot;Run Type:&amp;quot; {Calibration|Free Selection} default $runType &lt;br /&gt;
        var stimulusCondition &amp;quot;Stimulus Condition:&amp;quot; {SlowStimuli.prm|FastStimuli.prm} default $stimulusCondition &lt;br /&gt;
        message &amp;quot;NB: each condition should be calibrated separately.&amp;quot; &lt;br /&gt;
        buttons {Quit|Launch} default Launch escape Quit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if [ $launcherAction == &amp;quot;&amp;quot; ]&lt;br /&gt;
    quit&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if [ $runType == Calibration ]&lt;br /&gt;
    load parameterfile ../parms/calib.prm       # let&#039;s assume you have created this&lt;br /&gt;
else&lt;br /&gt;
    load parameterfile ../parms/free.prm        # and this&lt;br /&gt;
end&lt;br /&gt;
load parameterfile ../parms/$stimulusCondition  # and these&lt;br /&gt;
set parameter SubjectName $subjectName&lt;br /&gt;
setconfig&lt;br /&gt;
show window   # unless you have some other remote-control mechanism for suspending/resuming runs&lt;br /&gt;
set state Running 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The resulting dialog looks like this:&lt;br /&gt;
&lt;br /&gt;
[[File:CustomDialogExample.png]]&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12090</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12090"/>
		<updated>2025-09-01T18:01:12Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* CUSTOM DIALOG ... */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
__FORCETOC__&lt;br /&gt;
&lt;br /&gt;
===CHOOSE ...===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CHOOSE&amp;lt;/code&amp;gt; family of commands prompt the user to specify file or directory paths, via the Qt graphical user interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILE&amp;lt;/code&amp;gt;  (or equivalently &amp;lt;code&amp;gt;CHOOSE FILE&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CHOOSE INPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select a single existing file, and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILES&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE FILES&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select one or more existing files, and prints the resulting file paths one per line (&amp;lt;code&amp;gt;FOR ... IN ...&amp;lt;/code&amp;gt; can iterate over these).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE OUTPUT FILE&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE OUTPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists) and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;&lt;br /&gt;
: Prompts the user to specify a directory, and prints the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
If the user cancels the dialog, the commands print nothing.&lt;br /&gt;
&lt;br /&gt;
The commands may be followed by one or more of the following optional clauses (they must appear in this order):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[OF] TYPE[S] &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This limits the view (via a drop-down file-type selector) to files that have the specified extension(s). This clause cannot be used with &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;.  Instead of a file extension (starting with a dot) you can alternatively specify a glob pattern (containing a star). You can include &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt; (or equivalently &amp;lt;code&amp;gt;*.*&amp;lt;/code&amp;gt;) in the list if you want to allow the user to override the limitation.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[STARTING] AT &amp;lt;dir&amp;gt;&amp;lt;/code&amp;gt; (equivalently you can say &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;FROM&amp;lt;/code&amp;gt; if it reads better)&lt;br /&gt;
: This specifies where the dialog&#039;s file-system navigation should start (by default, it will start in the current working directory).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[WITH] PROMPT &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This specifies the text prompt at the top of the dialog.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
choose file of type .dat from ../data/samplefiles with prompt &amp;quot;Choose a data file for playback:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose output file of type .prm in ../parms with prompt &amp;quot;Save parameters as...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose directory starting at ../data with prompt &amp;quot;Select a subject directory:&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===CUSTOM DIALOG ...===&lt;br /&gt;
&lt;br /&gt;
This command assembles a flexibly customizable modal dialog for communicating with the user. The command returns (prints) a string denoting which button the user pressed to complete the dialog, and as a side effect it may set any environment variables that the command specifies.  If the user cancels the dialog, the command does nothing (prints nothing, does not change any environment variables).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command can be followed by as many clauses as you like. The main types of clause are &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog, in the order you provide. Possible clauses are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Each message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule. Simplest example: &amp;lt;pre&amp;gt;custom dialog message &amp;quot;Hello world!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. For example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used, in conjunction with an empty first/default option, to force the user to make an explicit selection, as in the following example (note the leading &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt; character inside the braces): &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, will be the one that gets highlighted by default and bound to the enter/return keystroke. If you do not specify a default, then &amp;quot;Ok&amp;quot; will be assumed to be the default button; if the designated default does not appear in the list of buttons, the buttons will all have equal status with no return-keystroke binding). The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke, and pressing this button is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).  You will probably not need to configure the buttons explicitly in most cases. In dialogs without &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are simply displaying messages to the user), the &amp;lt;code&amp;gt;BUTTONS {Ok} DEFAULT Ok&amp;lt;/code&amp;gt; configuration is assumed. In dialogs with one or more &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are asking the user for information), the &amp;lt;code&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel&amp;lt;/code&amp;gt; configuration is assumed.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TITLE &amp;lt;text&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This overrides the default dialog title &amp;quot;BCI2000&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;SPACING &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical spacing between successive &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; elements.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;WIDTH &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;HEIGHT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum height of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;LEFT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the horizontal coordinate of the dialog&#039;s left edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TOP &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical coordinate of the dialog&#039;s top edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Integrated &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; example====&lt;br /&gt;
&lt;br /&gt;
The following partial listing illustrates one way &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; might be used to implement a simplified launcher GUI, for a hypothetical auditory BCI experiment.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# [initialize system]&lt;br /&gt;
# [start up modules]&lt;br /&gt;
# [load baseline parameters for this BCI]&lt;br /&gt;
# [optionally, you could pre-initialize environment variables subjectName, runType and stimulusCondition]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
set environment launcherAction ${&lt;br /&gt;
    custom dialog &lt;br /&gt;
        title &amp;quot;Auditory BCI Launcher&amp;quot; &lt;br /&gt;
        var subjectName &amp;quot;Subject ID:&amp;quot; {} default $subjectName minimum 1 &lt;br /&gt;
        var runType &amp;quot;Run Type:&amp;quot; {Calibration|Free Selection} default $runType &lt;br /&gt;
        var stimulusCondition &amp;quot;Stimulus Condition:&amp;quot; {SlowStimuli.prm|FastStimuli.prm} default $stimulusCondition &lt;br /&gt;
        message &amp;quot;NB: each condition should be calibrated separately.&amp;quot; &lt;br /&gt;
        buttons {Quit|Launch} default Launch escape Quit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if [ $launcherAction == &amp;quot;&amp;quot; ]&lt;br /&gt;
    quit&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if [ $runType == Calibration ]&lt;br /&gt;
    load parameterfile ../parms/calib.prm       # let&#039;s assume you have created this&lt;br /&gt;
else&lt;br /&gt;
    load parameterfile ../parms/free.prm        # and this&lt;br /&gt;
end&lt;br /&gt;
load parameterfile ../parms/$stimulusCondition  # and these&lt;br /&gt;
set parameter SubjectName $subjectName&lt;br /&gt;
setconfig&lt;br /&gt;
show window&lt;br /&gt;
set state Running 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The resulting dialog looks like this:&lt;br /&gt;
&lt;br /&gt;
[[File:CustomDialogExample.png]]&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12089</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12089"/>
		<updated>2025-09-01T17:48:17Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* CHOOSE ... */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
__FORCETOC__&lt;br /&gt;
&lt;br /&gt;
===CHOOSE ...===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CHOOSE&amp;lt;/code&amp;gt; family of commands prompt the user to specify file or directory paths, via the Qt graphical user interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILE&amp;lt;/code&amp;gt;  (or equivalently &amp;lt;code&amp;gt;CHOOSE FILE&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CHOOSE INPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select a single existing file, and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILES&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE FILES&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select one or more existing files, and prints the resulting file paths one per line (&amp;lt;code&amp;gt;FOR ... IN ...&amp;lt;/code&amp;gt; can iterate over these).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE OUTPUT FILE&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE OUTPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists) and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;&lt;br /&gt;
: Prompts the user to specify a directory, and prints the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
If the user cancels the dialog, the commands print nothing.&lt;br /&gt;
&lt;br /&gt;
The commands may be followed by one or more of the following optional clauses (they must appear in this order):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[OF] TYPE[S] &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This limits the view (via a drop-down file-type selector) to files that have the specified extension(s). This clause cannot be used with &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;.  Instead of a file extension (starting with a dot) you can alternatively specify a glob pattern (containing a star). You can include &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt; (or equivalently &amp;lt;code&amp;gt;*.*&amp;lt;/code&amp;gt;) in the list if you want to allow the user to override the limitation.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[STARTING] AT &amp;lt;dir&amp;gt;&amp;lt;/code&amp;gt; (equivalently you can say &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;FROM&amp;lt;/code&amp;gt; if it reads better)&lt;br /&gt;
: This specifies where the dialog&#039;s file-system navigation should start (by default, it will start in the current working directory).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[WITH] PROMPT &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This specifies the text prompt at the top of the dialog.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
choose file of type .dat from ../data/samplefiles with prompt &amp;quot;Choose a data file for playback:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose output file of type .prm in ../parms with prompt &amp;quot;Save parameters as...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose directory starting at ../data with prompt &amp;quot;Select a subject directory:&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===CUSTOM DIALOG ...===&lt;br /&gt;
&lt;br /&gt;
This command assembles a flexibly customizable modal dialog for communicating with the user. The command returns (prints) a string denoting which button the user pressed to complete the dialog, and as a side effect it may set any environment variables that the command specifies.  If the user cancels the dialog, the command does nothing (prints nothing, does not change any environment variables).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command can be followed by as many clauses as you like. The main types of clause are &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog, in the order you provide. Possible clauses are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Each message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule. Simplest example: &amp;lt;pre&amp;gt;custom dialog message &amp;quot;Hello world!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. For example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used in conjunction with an empty first/default option, to force the user to make an explicit selection. For example (note the leading &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt; character inside the braces): &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, will be the one that gets highlighted by default and bound to the enter/return keystroke. If you do not specify a default, then &amp;quot;Ok&amp;quot; will be assumed to be the default button; if the designated default does not appear in the list of buttons, the buttons will all have equal status with no return-keystroke binding). The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke, and pressing this button is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).  You will probably not need to configure the buttons explicitly in most cases. In dialogs without &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are simply displaying messages to the user), the &amp;lt;code&amp;gt;BUTTONS {Ok} DEFAULT Ok&amp;lt;/code&amp;gt; configuration is assumed. In dialogs with one or more &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are asking the user for information), the &amp;lt;code&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel&amp;lt;/code&amp;gt; configuration is assumed.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TITLE &amp;lt;text&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This overrides the default dialog title &amp;quot;BCI2000&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;SPACING &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical spacing between successive &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; elements.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;WIDTH &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;HEIGHT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum height of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;LEFT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the horizontal coordinate of the dialog&#039;s left edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TOP &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical coordinate of the dialog&#039;s top edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Integrated &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; example====&lt;br /&gt;
&lt;br /&gt;
The following partial listing illustrates one way &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; might be used to implement a simplified launcher GUI, for a hypothetical auditory BCI experiment.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# [initialize system]&lt;br /&gt;
# [start up modules]&lt;br /&gt;
# [load baseline parameters for this BCI]&lt;br /&gt;
# [optionally, you could pre-initialize environment variables subjectName, runType and stimulusCondition]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
set environment launcherAction ${&lt;br /&gt;
    custom dialog &lt;br /&gt;
        title &amp;quot;Auditory BCI Launcher&amp;quot; &lt;br /&gt;
        var subjectName &amp;quot;Subject ID:&amp;quot; {} default $subjectName minimum 1 &lt;br /&gt;
        var runType &amp;quot;Run Type:&amp;quot; {Calibration|Free Selection} default $runType &lt;br /&gt;
        var stimulusCondition &amp;quot;Stimulus Condition:&amp;quot; {SlowStimuli.prm|FastStimuli.prm} default $stimulusCondition &lt;br /&gt;
        message &amp;quot;NB: each condition should be calibrated separately.&amp;quot; &lt;br /&gt;
        buttons {Quit|Launch} default Launch escape Quit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if [ $launcherAction == &amp;quot;&amp;quot; ]&lt;br /&gt;
    quit&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if [ $runType == Calibration ]&lt;br /&gt;
    load parameterfile ../parms/calib.prm       # let&#039;s assume you have created this&lt;br /&gt;
else&lt;br /&gt;
    load parameterfile ../parms/free.prm        # and this&lt;br /&gt;
end&lt;br /&gt;
load parameterfile ../parms/$stimulusCondition  # and these&lt;br /&gt;
set parameter SubjectName $subjectName&lt;br /&gt;
setconfig&lt;br /&gt;
show window&lt;br /&gt;
set state Running 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The resulting dialog looks like this:&lt;br /&gt;
&lt;br /&gt;
[[File:CustomDialogExample.png]]&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12088</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12088"/>
		<updated>2025-08-29T16:34:07Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* CUSTOM DIALOG ... */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
__FORCETOC__&lt;br /&gt;
&lt;br /&gt;
===CHOOSE ...===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CHOOSE&amp;lt;/code&amp;gt; family of commands prompt the user to specify file or directory paths, via the Qt graphical user interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILE&amp;lt;/code&amp;gt;  (or equivalently &amp;lt;code&amp;gt;CHOOSE FILE&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CHOOSE INPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select a single existing file, and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILES&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE FILES&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select one or more existing files, and prints the resulting file paths.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE OUTPUT FILE&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE OUTPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists) and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;&lt;br /&gt;
: Prompts the user to specify a directory, and prints the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
If the user cancels the dialog, the commands print nothing.&lt;br /&gt;
&lt;br /&gt;
The commands may be followed by one or more of the following optional clauses (they must appear in this order):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[OF] TYPE[S] &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This limits the view (via a drop-down file-type selector) to files that have the specified extension(s). This clause cannot be used with &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;.  Instead of a file extension (starting with a dot) you can alternatively specify a glob pattern (containing a star). You can include &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt; (or equivalently &amp;lt;code&amp;gt;*.*&amp;lt;/code&amp;gt;) in the list if you want to allow the user to override the limitation.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[STARTING] AT &amp;lt;dir&amp;gt;&amp;lt;/code&amp;gt; (equivalently you can say &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;FROM&amp;lt;/code&amp;gt; if it reads better)&lt;br /&gt;
: This specifies where the dialog&#039;s file-system navigation should start (by default, it will start in the current working directory).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[WITH] PROMPT &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This specifies the text prompt at the top of the dialog.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
choose file of type .dat from ../data/samplefiles with prompt &amp;quot;Choose a data file for playback:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose output file of type .prm in ../parms with prompt &amp;quot;Save parameters as...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose directory starting at ../data with prompt &amp;quot;Select a subject directory:&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===CUSTOM DIALOG ...===&lt;br /&gt;
&lt;br /&gt;
This command assembles a flexibly customizable modal dialog for communicating with the user. The command returns (prints) a string denoting which button the user pressed to complete the dialog, and as a side effect it may set any environment variables that the command specifies.  If the user cancels the dialog, the command does nothing (prints nothing, does not change any environment variables).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command can be followed by as many clauses as you like. The main types of clause are &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog, in the order you provide. Possible clauses are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Each message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule. Simplest example: &amp;lt;pre&amp;gt;custom dialog message &amp;quot;Hello world!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. For example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used in conjunction with an empty first/default option, to force the user to make an explicit selection. For example (note the leading &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt; character inside the braces): &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, will be the one that gets highlighted by default and bound to the enter/return keystroke. If you do not specify a default, then &amp;quot;Ok&amp;quot; will be assumed to be the default button; if the designated default does not appear in the list of buttons, the buttons will all have equal status with no return-keystroke binding). The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke, and pressing this button is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).  You will probably not need to configure the buttons explicitly in most cases. In dialogs without &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are simply displaying messages to the user), the &amp;lt;code&amp;gt;BUTTONS {Ok} DEFAULT Ok&amp;lt;/code&amp;gt; configuration is assumed. In dialogs with one or more &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are asking the user for information), the &amp;lt;code&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel&amp;lt;/code&amp;gt; configuration is assumed.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TITLE &amp;lt;text&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This overrides the default dialog title &amp;quot;BCI2000&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;SPACING &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical spacing between successive &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; elements.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;WIDTH &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;HEIGHT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum height of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;LEFT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the horizontal coordinate of the dialog&#039;s left edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TOP &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical coordinate of the dialog&#039;s top edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Integrated &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; example====&lt;br /&gt;
&lt;br /&gt;
The following partial listing illustrates one way &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; might be used to implement a simplified launcher GUI, for a hypothetical auditory BCI experiment.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# [initialize system]&lt;br /&gt;
# [start up modules]&lt;br /&gt;
# [load baseline parameters for this BCI]&lt;br /&gt;
# [optionally, you could pre-initialize environment variables subjectName, runType and stimulusCondition]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
set environment launcherAction ${&lt;br /&gt;
    custom dialog &lt;br /&gt;
        title &amp;quot;Auditory BCI Launcher&amp;quot; &lt;br /&gt;
        var subjectName &amp;quot;Subject ID:&amp;quot; {} default $subjectName minimum 1 &lt;br /&gt;
        var runType &amp;quot;Run Type:&amp;quot; {Calibration|Free Selection} default $runType &lt;br /&gt;
        var stimulusCondition &amp;quot;Stimulus Condition:&amp;quot; {SlowStimuli.prm|FastStimuli.prm} default $stimulusCondition &lt;br /&gt;
        message &amp;quot;NB: each condition should be calibrated separately.&amp;quot; &lt;br /&gt;
        buttons {Quit|Launch} default Launch escape Quit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if [ $launcherAction == &amp;quot;&amp;quot; ]&lt;br /&gt;
    quit&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if [ $runType == Calibration ]&lt;br /&gt;
    load parameterfile ../parms/calib.prm       # let&#039;s assume you have created this&lt;br /&gt;
else&lt;br /&gt;
    load parameterfile ../parms/free.prm        # and this&lt;br /&gt;
end&lt;br /&gt;
load parameterfile ../parms/$stimulusCondition  # and these&lt;br /&gt;
set parameter SubjectName $subjectName&lt;br /&gt;
setconfig&lt;br /&gt;
show window&lt;br /&gt;
set state Running 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The resulting dialog looks like this:&lt;br /&gt;
&lt;br /&gt;
[[File:CustomDialogExample.png]]&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12087</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12087"/>
		<updated>2025-08-29T16:05:37Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* Integrated CUSTOM DIALOG example */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
__FORCETOC__&lt;br /&gt;
&lt;br /&gt;
===CHOOSE ...===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CHOOSE&amp;lt;/code&amp;gt; family of commands prompt the user to specify file or directory paths, via the Qt graphical user interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILE&amp;lt;/code&amp;gt;  (or equivalently &amp;lt;code&amp;gt;CHOOSE FILE&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CHOOSE INPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select a single existing file, and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILES&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE FILES&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select one or more existing files, and prints the resulting file paths.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE OUTPUT FILE&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE OUTPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists) and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;&lt;br /&gt;
: Prompts the user to specify a directory, and prints the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
If the user cancels the dialog, the commands print nothing.&lt;br /&gt;
&lt;br /&gt;
The commands may be followed by one or more of the following optional clauses (they must appear in this order):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[OF] TYPE[S] &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This limits the view (via a drop-down file-type selector) to files that have the specified extension(s). This clause cannot be used with &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;.  Instead of a file extension (starting with a dot) you can alternatively specify a glob pattern (containing a star). You can include &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt; (or equivalently &amp;lt;code&amp;gt;*.*&amp;lt;/code&amp;gt;) in the list if you want to allow the user to override the limitation.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[STARTING] AT &amp;lt;dir&amp;gt;&amp;lt;/code&amp;gt; (equivalently you can say &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;FROM&amp;lt;/code&amp;gt; if it reads better)&lt;br /&gt;
: This specifies where the dialog&#039;s file-system navigation should start (by default, it will start in the current working directory).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[WITH] PROMPT &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This specifies the text prompt at the top of the dialog.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
choose file of type .dat from ../data/samplefiles with prompt &amp;quot;Choose a data file for playback:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose output file of type .prm in ../parms with prompt &amp;quot;Save parameters as...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose directory starting at ../data with prompt &amp;quot;Select a subject directory:&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===CUSTOM DIALOG ...===&lt;br /&gt;
&lt;br /&gt;
This command assembles a flexibly customizable modal dialog for communicating with the user. The command returns (prints) a string denoting which button the user pressed to complete the dialog, and as a side effect it may set any environment variables that the command specifies.  If the user cancels the dialog, the command does nothing (prints nothing, does not change any environment variables).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command can be followed by as many clauses as you like. The main types of clause are &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog, in the order you provide. Possible clauses are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Each message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule. Simplest example: &amp;lt;pre&amp;gt;custom dialog message &amp;quot;Hello world!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. For example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used in conjunction with an empty first/default option, to force the user to make an explicit selection. For example: &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1   # note the leading | character inside the braces&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, will be the one that gets highlighted by default and bound to the enter/return keystroke. If you do not specify a default, then &amp;quot;Ok&amp;quot; will be assumed to be the default button; if the designated default does not appear in the list of buttons, the buttons will all have equal status with no return-keystroke binding). The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke, and pressing this button is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).  You will probably not need to configure the buttons explicitly in most cases. In dialogs without &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are simply displaying messages to the user), the &amp;lt;code&amp;gt;BUTTONS {Ok} DEFAULT Ok&amp;lt;/code&amp;gt; configuration is assumed. In dialogs with one or more &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are asking the user for information), the &amp;lt;code&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel&amp;lt;/code&amp;gt; configuration is assumed.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TITLE &amp;lt;text&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This overrides the default dialog title &amp;quot;BCI2000&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;SPACING &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical spacing between successive &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; elements.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;WIDTH &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;HEIGHT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum height of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;LEFT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the horizontal coordinate of the dialog&#039;s left edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TOP &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical coordinate of the dialog&#039;s top edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Integrated &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; example====&lt;br /&gt;
&lt;br /&gt;
The following partial listing illustrates one way &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; might be used to implement a simplified launcher GUI, for a hypothetical auditory BCI experiment.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# [initialize system]&lt;br /&gt;
# [start up modules]&lt;br /&gt;
# [load baseline parameters for this BCI]&lt;br /&gt;
# [optionally, you could pre-initialize environment variables subjectName, runType and stimulusCondition]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
set environment launcherAction ${&lt;br /&gt;
    custom dialog &lt;br /&gt;
        title &amp;quot;Auditory BCI Launcher&amp;quot; &lt;br /&gt;
        var subjectName &amp;quot;Subject ID:&amp;quot; {} default $subjectName minimum 1 &lt;br /&gt;
        var runType &amp;quot;Run Type:&amp;quot; {Calibration|Free Selection} default $runType &lt;br /&gt;
        var stimulusCondition &amp;quot;Stimulus Condition:&amp;quot; {SlowStimuli.prm|FastStimuli.prm} default $stimulusCondition &lt;br /&gt;
        message &amp;quot;NB: each condition should be calibrated separately.&amp;quot; &lt;br /&gt;
        buttons {Quit|Launch} default Launch escape Quit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if [ $launcherAction == &amp;quot;&amp;quot; ]&lt;br /&gt;
    quit&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if [ $runType == Calibration ]&lt;br /&gt;
    load parameterfile ../parms/calib.prm       # let&#039;s assume you have created this&lt;br /&gt;
else&lt;br /&gt;
    load parameterfile ../parms/free.prm        # and this&lt;br /&gt;
end&lt;br /&gt;
load parameterfile ../parms/$stimulusCondition  # and these&lt;br /&gt;
set parameter SubjectName $subjectName&lt;br /&gt;
setconfig&lt;br /&gt;
show window&lt;br /&gt;
set state Running 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The resulting dialog looks like this:&lt;br /&gt;
&lt;br /&gt;
[[File:CustomDialogExample.png]]&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12086</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12086"/>
		<updated>2025-08-29T15:44:23Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* CUSTOM DIALOG ... */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
__FORCETOC__&lt;br /&gt;
&lt;br /&gt;
===CHOOSE ...===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CHOOSE&amp;lt;/code&amp;gt; family of commands prompt the user to specify file or directory paths, via the Qt graphical user interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILE&amp;lt;/code&amp;gt;  (or equivalently &amp;lt;code&amp;gt;CHOOSE FILE&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CHOOSE INPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select a single existing file, and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILES&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE FILES&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select one or more existing files, and prints the resulting file paths.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE OUTPUT FILE&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE OUTPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists) and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;&lt;br /&gt;
: Prompts the user to specify a directory, and prints the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
If the user cancels the dialog, the commands print nothing.&lt;br /&gt;
&lt;br /&gt;
The commands may be followed by one or more of the following optional clauses (they must appear in this order):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[OF] TYPE[S] &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This limits the view (via a drop-down file-type selector) to files that have the specified extension(s). This clause cannot be used with &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;.  Instead of a file extension (starting with a dot) you can alternatively specify a glob pattern (containing a star). You can include &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt; (or equivalently &amp;lt;code&amp;gt;*.*&amp;lt;/code&amp;gt;) in the list if you want to allow the user to override the limitation.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[STARTING] AT &amp;lt;dir&amp;gt;&amp;lt;/code&amp;gt; (equivalently you can say &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;FROM&amp;lt;/code&amp;gt; if it reads better)&lt;br /&gt;
: This specifies where the dialog&#039;s file-system navigation should start (by default, it will start in the current working directory).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[WITH] PROMPT &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This specifies the text prompt at the top of the dialog.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
choose file of type .dat from ../data/samplefiles with prompt &amp;quot;Choose a data file for playback:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose output file of type .prm in ../parms with prompt &amp;quot;Save parameters as...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose directory starting at ../data with prompt &amp;quot;Select a subject directory:&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===CUSTOM DIALOG ...===&lt;br /&gt;
&lt;br /&gt;
This command assembles a flexibly customizable modal dialog for communicating with the user. The command returns (prints) a string denoting which button the user pressed to complete the dialog, and as a side effect it may set any environment variables that the command specifies.  If the user cancels the dialog, the command does nothing (prints nothing, does not change any environment variables).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command can be followed by as many clauses as you like. The main types of clause are &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog, in the order you provide. Possible clauses are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Each message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule. Simplest example: &amp;lt;pre&amp;gt;custom dialog message &amp;quot;Hello world!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. For example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used in conjunction with an empty first/default option, to force the user to make an explicit selection. For example: &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1   # note the leading | character inside the braces&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, will be the one that gets highlighted by default and bound to the enter/return keystroke. If you do not specify a default, then &amp;quot;Ok&amp;quot; will be assumed to be the default button; if the designated default does not appear in the list of buttons, the buttons will all have equal status with no return-keystroke binding). The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke, and pressing this button is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).  You will probably not need to configure the buttons explicitly in most cases. In dialogs without &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are simply displaying messages to the user), the &amp;lt;code&amp;gt;BUTTONS {Ok} DEFAULT Ok&amp;lt;/code&amp;gt; configuration is assumed. In dialogs with one or more &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are asking the user for information), the &amp;lt;code&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel&amp;lt;/code&amp;gt; configuration is assumed.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TITLE &amp;lt;text&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This overrides the default dialog title &amp;quot;BCI2000&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;SPACING &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical spacing between successive &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; elements.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;WIDTH &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;HEIGHT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum height of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;LEFT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the horizontal coordinate of the dialog&#039;s left edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TOP &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical coordinate of the dialog&#039;s top edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Integrated &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; example====&lt;br /&gt;
&lt;br /&gt;
The following partial listing illustrates one way &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; might be used to implement a simplified launcher GUI, for a hypothetical auditory BCI experiment.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# [initialize system]&lt;br /&gt;
# [start up modules]&lt;br /&gt;
# [load baseline parameters for this BCI]&lt;br /&gt;
# [if you want, you can pre-initialize environment variables subjectName, runType and stimulusCondition]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
set environment launcherAction ${&lt;br /&gt;
    custom dialog &lt;br /&gt;
        title &amp;quot;Auditory BCI Launcher&amp;quot; &lt;br /&gt;
        var subjectName &amp;quot;Subject ID:&amp;quot; {} default $subjectName minimum 1 &lt;br /&gt;
        var runType &amp;quot;Run Type:&amp;quot; {Calibration|Free Selection} default $runType &lt;br /&gt;
        var stimulusCondition &amp;quot;Stimulus Condition:&amp;quot; {SlowStimuli.prm|FastStimuli.prm} default $stimulusCondition &lt;br /&gt;
        message &amp;quot;NB: each condition should be calibrated separately.&amp;quot; &lt;br /&gt;
        buttons {Quit|Launch} default Launch escape Quit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if [ $launcherAction == &amp;quot;&amp;quot; ]&lt;br /&gt;
    quit&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if [ $runType == Calibration ]&lt;br /&gt;
    load parameterfile ../parms/calib.prm       # let&#039;s assume you have created this&lt;br /&gt;
else&lt;br /&gt;
    load parameterfile ../parms/free.prm        # and this&lt;br /&gt;
end&lt;br /&gt;
load parameterfile ../parms/$stimulusCondition  # and these&lt;br /&gt;
set parameter SubjectName $subjectName&lt;br /&gt;
setconfig&lt;br /&gt;
show window&lt;br /&gt;
set state Running 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The resulting dialog looks like this:&lt;br /&gt;
&lt;br /&gt;
[[File:CustomDialogExample.png]]&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12085</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12085"/>
		<updated>2025-08-29T15:41:52Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* CUSTOM DIALOG ... */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
__FORCETOC__&lt;br /&gt;
&lt;br /&gt;
===CHOOSE ...===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CHOOSE&amp;lt;/code&amp;gt; family of commands prompt the user to specify file or directory paths, via the Qt graphical user interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILE&amp;lt;/code&amp;gt;  (or equivalently &amp;lt;code&amp;gt;CHOOSE FILE&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CHOOSE INPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select a single existing file, and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILES&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE FILES&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select one or more existing files, and prints the resulting file paths.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE OUTPUT FILE&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE OUTPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists) and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;&lt;br /&gt;
: Prompts the user to specify a directory, and prints the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
If the user cancels the dialog, the commands print nothing.&lt;br /&gt;
&lt;br /&gt;
The commands may be followed by one or more of the following optional clauses (they must appear in this order):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[OF] TYPE[S] &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This limits the view (via a drop-down file-type selector) to files that have the specified extension(s). This clause cannot be used with &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;.  Instead of a file extension (starting with a dot) you can alternatively specify a glob pattern (containing a star). You can include &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt; (or equivalently &amp;lt;code&amp;gt;*.*&amp;lt;/code&amp;gt;) in the list if you want to allow the user to override the limitation.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[STARTING] AT &amp;lt;dir&amp;gt;&amp;lt;/code&amp;gt; (equivalently you can say &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;FROM&amp;lt;/code&amp;gt; if it reads better)&lt;br /&gt;
: This specifies where the dialog&#039;s file-system navigation should start (by default, it will start in the current working directory).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[WITH] PROMPT &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This specifies the text prompt at the top of the dialog.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
choose file of type .dat from ../data/samplefiles with prompt &amp;quot;Choose a data file for playback:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose output file of type .prm in ../parms with prompt &amp;quot;Save parameters as...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose directory starting at ../data with prompt &amp;quot;Select a subject directory:&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===CUSTOM DIALOG ...===&lt;br /&gt;
&lt;br /&gt;
This command assembles a flexibly customizable modal dialog for communicating with the user. The command returns (prints) a string denoting which button the user pressed to complete the dialog, and as a side effect it may set any environment variables that the command specifies.  If the user cancels the dialog, the command does nothing (prints nothing, does not change any environment variables).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command can be followed by as many clauses as you like. The main types of clause are &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog, in the order you provide. Possible clauses are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Each message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule. Simplest example: &amp;lt;pre&amp;gt;custom dialog message &amp;quot;Hello world!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. For example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used in conjunction with an empty first/default option, to force the user to make an explicit selection. For example: &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1   # note the leading | character inside the braces&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, will be the one that gets highlighted by default and bound to the enter/return keystroke. If you do not specify a default, then &amp;quot;Ok&amp;quot; will be assumed to be the default button; if the designated default does not appear in the list of buttons, the buttons will all have equal status with no return-keystroke binding). The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke, and pressing this button is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).  You will probably not need to configure the buttons explicitly in most cases. In dialogs without &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are simply displaying messages to the user), the &amp;lt;code&amp;gt;BUTTONS {Ok} DEFAULT Ok&amp;lt;/code&amp;gt; configuration is assumed. In dialogs with one or more &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are asking the user for information), the &amp;lt;code&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel&amp;lt;/code&amp;gt; configuration is assumed.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TITLE &amp;lt;text&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This overrides the default dialog title &amp;quot;BCI2000&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;SPACING &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical spacing between successive &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; elements.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;WIDTH &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;HEIGHT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;LEFT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the horizontal coordinate of the dialog&#039;s left edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TOP &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical coordinate of the dialog&#039;s top edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Integrated &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; example====&lt;br /&gt;
&lt;br /&gt;
The following partial listing illustrates one way &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; might be used to implement a simplified launcher GUI, for a hypothetical auditory BCI experiment.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# [initialize system]&lt;br /&gt;
# [start up modules]&lt;br /&gt;
# [load baseline parameters for this BCI]&lt;br /&gt;
# [if you want, you can pre-initialize environment variables subjectName, runType and stimulusCondition]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
set environment launcherAction ${&lt;br /&gt;
    custom dialog &lt;br /&gt;
        title &amp;quot;Auditory BCI Launcher&amp;quot; &lt;br /&gt;
        var subjectName &amp;quot;Subject ID:&amp;quot; {} default $subjectName minimum 1 &lt;br /&gt;
        var runType &amp;quot;Run Type:&amp;quot; {Calibration|Free Selection} default $runType &lt;br /&gt;
        var stimulusCondition &amp;quot;Stimulus Condition:&amp;quot; {SlowStimuli.prm|FastStimuli.prm} default $stimulusCondition &lt;br /&gt;
        message &amp;quot;NB: each condition should be calibrated separately.&amp;quot; &lt;br /&gt;
        buttons {Quit|Launch} default Launch escape Quit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if [ $launcherAction == &amp;quot;&amp;quot; ]&lt;br /&gt;
    quit&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if [ $runType == Calibration ]&lt;br /&gt;
    load parameterfile ../parms/calib.prm       # let&#039;s assume you have created this&lt;br /&gt;
else&lt;br /&gt;
    load parameterfile ../parms/free.prm        # and this&lt;br /&gt;
end&lt;br /&gt;
load parameterfile ../parms/$stimulusCondition  # and these&lt;br /&gt;
set parameter SubjectName $subjectName&lt;br /&gt;
setconfig&lt;br /&gt;
show window&lt;br /&gt;
set state Running 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The resulting dialog looks like this:&lt;br /&gt;
&lt;br /&gt;
[[File:CustomDialogExample.png]]&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12084</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12084"/>
		<updated>2025-08-29T15:38:12Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* CHOOSE ... */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
__FORCETOC__&lt;br /&gt;
&lt;br /&gt;
===CHOOSE ...===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CHOOSE&amp;lt;/code&amp;gt; family of commands prompt the user to specify file or directory paths, via the Qt graphical user interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILE&amp;lt;/code&amp;gt;  (or equivalently &amp;lt;code&amp;gt;CHOOSE FILE&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CHOOSE INPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select a single existing file, and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILES&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE FILES&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select one or more existing files, and prints the resulting file paths.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE OUTPUT FILE&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE OUTPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists) and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;&lt;br /&gt;
: Prompts the user to specify a directory, and prints the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
If the user cancels the dialog, the commands print nothing.&lt;br /&gt;
&lt;br /&gt;
The commands may be followed by one or more of the following optional clauses (they must appear in this order):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[OF] TYPE[S] &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This limits the view (via a drop-down file-type selector) to files that have the specified extension(s). This clause cannot be used with &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;.  Instead of a file extension (starting with a dot) you can alternatively specify a glob pattern (containing a star). You can include &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt; (or equivalently &amp;lt;code&amp;gt;*.*&amp;lt;/code&amp;gt;) in the list if you want to allow the user to override the limitation.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[STARTING] AT &amp;lt;dir&amp;gt;&amp;lt;/code&amp;gt; (equivalently you can say &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;FROM&amp;lt;/code&amp;gt; if it reads better)&lt;br /&gt;
: This specifies where the dialog&#039;s file-system navigation should start (by default, it will start in the current working directory).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[WITH] PROMPT &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This specifies the text prompt at the top of the dialog.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
choose file of type .dat from ../data/samplefiles with prompt &amp;quot;Choose a data file for playback:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose output file of type .prm in ../parms with prompt &amp;quot;Save parameters as...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose directory starting at ../data with prompt &amp;quot;Select a subject directory:&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===CUSTOM DIALOG ...===&lt;br /&gt;
&lt;br /&gt;
This command assembles a flexibly customizable modal dialog for communicating with the user. The command returns (prints) a string denoting which button the user pressed to complete the dialog, and as a side effect it may set any environment variables that the command specifies.  If the user cancels the dialog, the command does nothing (prints nothing, does not change any environment variables).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command can be followed by as many clauses as you like. The main types of clause are &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog, in the order you provide. Possible clauses are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Each message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule. Simplest example: &amp;lt;pre&amp;gt;custom dialog message &amp;quot;Hello world!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. For example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used in conjunction with an empty first/default option, to force the user to make an explicit selection. For example: &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, will be the one that gets highlighted by default and bound to the enter/return keystroke. If you do not specify a default, then &amp;quot;Ok&amp;quot; will be assumed to be the default button; if the designated default does not appear in the list of buttons, the buttons will all have equal status with no return-keystroke binding). The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke, and pressing this button is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).  You will probably not need to configure the buttons explicitly in most cases. In dialogs without &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are simply displaying messages to the user), the &amp;lt;code&amp;gt;BUTTONS {Ok} DEFAULT Ok&amp;lt;/code&amp;gt; configuration is assumed. In dialogs with one or more &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are asking the user for information), the &amp;lt;code&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel&amp;lt;/code&amp;gt; configuration is assumed.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TITLE &amp;lt;text&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This overrides the default dialog title &amp;quot;BCI2000&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;SPACING &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical spacing between successive &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; elements.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;WIDTH &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;HEIGHT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;LEFT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the horizontal coordinate of the dialog&#039;s left edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TOP &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical coordinate of the dialog&#039;s top edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Integrated &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; example====&lt;br /&gt;
&lt;br /&gt;
The following partial listing illustrates one way &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; might be used to implement a simplified launcher GUI, for a hypothetical auditory BCI experiment.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# [initialize system]&lt;br /&gt;
# [start up modules]&lt;br /&gt;
# [load baseline parameters for this BCI]&lt;br /&gt;
# [if you want, you can pre-initialize environment variables subjectName, runType and stimulusCondition]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
set environment launcherAction ${&lt;br /&gt;
    custom dialog &lt;br /&gt;
        title &amp;quot;Auditory BCI Launcher&amp;quot; &lt;br /&gt;
        var subjectName &amp;quot;Subject ID:&amp;quot; {} default $subjectName minimum 1 &lt;br /&gt;
        var runType &amp;quot;Run Type:&amp;quot; {Calibration|Free Selection} default $runType &lt;br /&gt;
        var stimulusCondition &amp;quot;Stimulus Condition:&amp;quot; {SlowStimuli.prm|FastStimuli.prm} default $stimulusCondition &lt;br /&gt;
        message &amp;quot;NB: each condition should be calibrated separately.&amp;quot; &lt;br /&gt;
        buttons {Quit|Launch} default Launch escape Quit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if [ $launcherAction == &amp;quot;&amp;quot; ]&lt;br /&gt;
    quit&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if [ $runType == Calibration ]&lt;br /&gt;
    load parameterfile ../parms/calib.prm       # let&#039;s assume you have created this&lt;br /&gt;
else&lt;br /&gt;
    load parameterfile ../parms/free.prm        # and this&lt;br /&gt;
end&lt;br /&gt;
load parameterfile ../parms/$stimulusCondition  # and these&lt;br /&gt;
set parameter SubjectName $subjectName&lt;br /&gt;
setconfig&lt;br /&gt;
show window&lt;br /&gt;
set state Running 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The resulting dialog looks like this:&lt;br /&gt;
&lt;br /&gt;
[[File:CustomDialogExample.png]]&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12083</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12083"/>
		<updated>2025-08-29T15:28:12Z</updated>

		<summary type="html">&lt;p&gt;Jhill: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
__FORCETOC__&lt;br /&gt;
&lt;br /&gt;
===CHOOSE ...===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CHOOSE&amp;lt;/code&amp;gt; family of commands prompt the user to specify file or directory paths, via the Qt graphical user interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILE&amp;lt;/code&amp;gt;  (or equivalently &amp;lt;code&amp;gt;CHOOSE FILE&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CHOOSE INPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select a single existing file, and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILES&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE FILES&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select one or more existing files, and prints the resulting file paths.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE OUTPUT FILE&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE OUTPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists) and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;&lt;br /&gt;
: Prompts the user to specify a directory, and prints the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
If the user cancels the dialog, the commands print nothing.&lt;br /&gt;
&lt;br /&gt;
The commands may be followed by one or more of the following optional clauses (they must appear in this order):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[OF] TYPE[S] &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This limits the view (via a drop-down file-type selector) to files that have the specified extension(s). This clause cannot be used with &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;.  Instead of a file extension (starting with a dot) you can alternatively specify a glob pattern (containing a star). You can include &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt; (or equivalently &amp;lt;code&amp;gt;*.*&amp;lt;/code&amp;gt;) in the list if you want to allow the user to override the limitation.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[STARTING] AT &amp;lt;dir&amp;gt; ...]&amp;lt;/code&amp;gt; (equivalently you can say &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;FROM&amp;lt;/code&amp;gt; if it reads better)&lt;br /&gt;
: This specifies where the dialog&#039;s file-system navigation should start (by default, it will start in the current working directory).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[WITH] PROMPT &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This specifies the text prompt at the top of the dialog.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
choose file of type .dat from ../data/samplefiles with prompt &amp;quot;Choose a data file for playback:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose output file of type .prm in ../parms with prompt &amp;quot;Save parameters as...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose directory starting at ../data with prompt &amp;quot;Select a subject directory:&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===CUSTOM DIALOG ...===&lt;br /&gt;
&lt;br /&gt;
This command assembles a flexibly customizable modal dialog for communicating with the user. The command returns (prints) a string denoting which button the user pressed to complete the dialog, and as a side effect it may set any environment variables that the command specifies.  If the user cancels the dialog, the command does nothing (prints nothing, does not change any environment variables).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command can be followed by as many clauses as you like. The main types of clause are &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog, in the order you provide. Possible clauses are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Each message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule. Simplest example: &amp;lt;pre&amp;gt;custom dialog message &amp;quot;Hello world!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. For example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used in conjunction with an empty first/default option, to force the user to make an explicit selection. For example: &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, will be the one that gets highlighted by default and bound to the enter/return keystroke. If you do not specify a default, then &amp;quot;Ok&amp;quot; will be assumed to be the default button; if the designated default does not appear in the list of buttons, the buttons will all have equal status with no return-keystroke binding). The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke, and pressing this button is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).  You will probably not need to configure the buttons explicitly in most cases. In dialogs without &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are simply displaying messages to the user), the &amp;lt;code&amp;gt;BUTTONS {Ok} DEFAULT Ok&amp;lt;/code&amp;gt; configuration is assumed. In dialogs with one or more &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are asking the user for information), the &amp;lt;code&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel&amp;lt;/code&amp;gt; configuration is assumed.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TITLE &amp;lt;text&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This overrides the default dialog title &amp;quot;BCI2000&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;SPACING &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical spacing between successive &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; elements.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;WIDTH &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;HEIGHT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;LEFT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the horizontal coordinate of the dialog&#039;s left edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TOP &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical coordinate of the dialog&#039;s top edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Integrated &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; example====&lt;br /&gt;
&lt;br /&gt;
The following partial listing illustrates one way &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; might be used to implement a simplified launcher GUI, for a hypothetical auditory BCI experiment.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# [initialize system]&lt;br /&gt;
# [start up modules]&lt;br /&gt;
# [load baseline parameters for this BCI]&lt;br /&gt;
# [if you want, you can pre-initialize environment variables subjectName, runType and stimulusCondition]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
set environment launcherAction ${&lt;br /&gt;
    custom dialog &lt;br /&gt;
        title &amp;quot;Auditory BCI Launcher&amp;quot; &lt;br /&gt;
        var subjectName &amp;quot;Subject ID:&amp;quot; {} default $subjectName minimum 1 &lt;br /&gt;
        var runType &amp;quot;Run Type:&amp;quot; {Calibration|Free Selection} default $runType &lt;br /&gt;
        var stimulusCondition &amp;quot;Stimulus Condition:&amp;quot; {SlowStimuli.prm|FastStimuli.prm} default $stimulusCondition &lt;br /&gt;
        message &amp;quot;NB: each condition should be calibrated separately.&amp;quot; &lt;br /&gt;
        buttons {Quit|Launch} default Launch escape Quit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if [ $launcherAction == &amp;quot;&amp;quot; ]&lt;br /&gt;
    quit&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if [ $runType == Calibration ]&lt;br /&gt;
    load parameterfile ../parms/calib.prm       # let&#039;s assume you have created this&lt;br /&gt;
else&lt;br /&gt;
    load parameterfile ../parms/free.prm        # and this&lt;br /&gt;
end&lt;br /&gt;
load parameterfile ../parms/$stimulusCondition  # and these&lt;br /&gt;
set parameter SubjectName $subjectName&lt;br /&gt;
setconfig&lt;br /&gt;
show window&lt;br /&gt;
set state Running 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The resulting dialog looks like this:&lt;br /&gt;
&lt;br /&gt;
[[File:CustomDialogExample.png]]&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12082</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12082"/>
		<updated>2025-08-29T15:20:00Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* CHOOSE ... */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
__FORCETOC__&lt;br /&gt;
&lt;br /&gt;
===CHOOSE ...===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CHOOSE&amp;lt;/code&amp;gt; family of commands prompt the user to specify file or directory paths, via the Qt graphical user interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILE&amp;lt;/code&amp;gt;  (or equivalently &amp;lt;code&amp;gt;CHOOSE FILE&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CHOOSE INPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select a single existing file, and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILES&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE FILES&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select one or more existing files, and prints the resulting file paths.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE OUTPUT FILE&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE OUTPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists) and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;&lt;br /&gt;
: Prompts the user to specify a directory, and prints the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
If the user cancels the dialog, the commands print nothing.&lt;br /&gt;
&lt;br /&gt;
The commands may be followed by one or more of the following optional clauses (they must appear in this order):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[OF] TYPE[S] &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This limits the view (via a drop-down file-type selector) to files that have the specified extension(s). This clause cannot be used with &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;.  Instead of a file extension (starting with a dot) you can alternatively specify a glob pattern (containing a star).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[STARTING] AT &amp;lt;dir&amp;gt; ...]&amp;lt;/code&amp;gt; (equivalently you can say &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;FROM&amp;lt;/code&amp;gt; if it reads better)&lt;br /&gt;
: This specifies where the dialog&#039;s file-system navigation should start (by default, it will start in the current working directory).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[WITH] PROMPT &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This specifies the text prompt at the top of the dialog.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
choose file of type .dat from ../data/samplefiles with prompt &amp;quot;Choose a data file for playback:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose output file of type .prm in ../parms with prompt &amp;quot;Save parameters as...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose directory starting at ../data with prompt &amp;quot;Select a subject directory:&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===CUSTOM DIALOG ...===&lt;br /&gt;
&lt;br /&gt;
This command assembles a flexibly customizable modal dialog for communicating with the user. The command returns (prints) a string denoting which button the user pressed to complete the dialog, and as a side effect it may set any environment variables that the command specifies.  If the user cancels the dialog, the command does nothing (prints nothing, does not change any environment variables).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command can be followed by as many clauses as you like. The main types of clause are &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog, in the order you provide. Possible clauses are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Each message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule. Simplest example: &amp;lt;pre&amp;gt;custom dialog message &amp;quot;Hello world!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. For example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used in conjunction with an empty first/default option, to force the user to make an explicit selection. For example: &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, will be the one that gets highlighted by default and bound to the enter/return keystroke. If you do not specify a default, then &amp;quot;Ok&amp;quot; will be assumed to be the default button; if the designated default does not appear in the list of buttons, the buttons will all have equal status with no return-keystroke binding). The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke, and pressing this button is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).  You will probably not need to configure the buttons explicitly in most cases. In dialogs without &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are simply displaying messages to the user), the &amp;lt;code&amp;gt;BUTTONS {Ok} DEFAULT Ok&amp;lt;/code&amp;gt; configuration is assumed. In dialogs with one or more &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are asking the user for information), the &amp;lt;code&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel&amp;lt;/code&amp;gt; configuration is assumed.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TITLE &amp;lt;text&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This overrides the default dialog title &amp;quot;BCI2000&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;SPACING &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical spacing between successive &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; elements.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;WIDTH &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;HEIGHT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;LEFT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the horizontal coordinate of the dialog&#039;s left edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TOP &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical coordinate of the dialog&#039;s top edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Integrated &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; example====&lt;br /&gt;
&lt;br /&gt;
The following partial listing illustrates one way &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; might be used to implement a simplified launcher GUI, for a hypothetical auditory BCI experiment.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# [initialize system]&lt;br /&gt;
# [start up modules]&lt;br /&gt;
# [load baseline parameters for this BCI]&lt;br /&gt;
# [if you want, you can pre-initialize environment variables subjectName, runType and stimulusCondition]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
set environment launcherAction ${&lt;br /&gt;
    custom dialog &lt;br /&gt;
        title &amp;quot;Auditory BCI Launcher&amp;quot; &lt;br /&gt;
        var subjectName &amp;quot;Subject ID:&amp;quot; {} default $subjectName minimum 1 &lt;br /&gt;
        var runType &amp;quot;Run Type:&amp;quot; {Calibration|Free Selection} default $runType &lt;br /&gt;
        var stimulusCondition &amp;quot;Stimulus Condition:&amp;quot; {SlowStimuli.prm|FastStimuli.prm} default $stimulusCondition &lt;br /&gt;
        message &amp;quot;NB: each condition should be calibrated separately.&amp;quot; &lt;br /&gt;
        buttons {Quit|Launch} default Launch escape Quit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if [ $launcherAction == &amp;quot;&amp;quot; ]&lt;br /&gt;
    quit&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if [ $runType == Calibration ]&lt;br /&gt;
    load parameterfile ../parms/calib.prm       # let&#039;s assume you have created this&lt;br /&gt;
else&lt;br /&gt;
    load parameterfile ../parms/free.prm        # and this&lt;br /&gt;
end&lt;br /&gt;
load parameterfile ../parms/$stimulusCondition  # and these&lt;br /&gt;
set parameter SubjectName $subjectName&lt;br /&gt;
setconfig&lt;br /&gt;
show window&lt;br /&gt;
set state Running 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The resulting dialog looks like this:&lt;br /&gt;
&lt;br /&gt;
[[File:CustomDialogExample.png]]&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12081</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12081"/>
		<updated>2025-08-29T15:06:42Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* Integrated CUSTOM DIALOG example */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
__FORCETOC__&lt;br /&gt;
&lt;br /&gt;
===CHOOSE ...===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CHOOSE&amp;lt;/code&amp;gt; family of commands prompt the user to specify file or directory paths, via the Qt graphical user interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILE&amp;lt;/code&amp;gt;  (or equivalently &amp;lt;code&amp;gt;CHOOSE FILE&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CHOOSE INPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select a single existing file, and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILES&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE FILES&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select one or more existing files, and prints the resulting file paths.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE OUTPUT FILE&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE OUTPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists) and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;&lt;br /&gt;
: Prompts the user to specify a directory, and prints the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
The commands may be followed by one or more of the following optional clauses (they must appear in this order):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[OF] TYPE[S] &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This limits the view (via a drop-down file-type selector) to files that have the specified extension(s). This clause cannot be used with &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;.  Instead of a file extension (starting with a dot) you can alternatively specify a glob pattern (containing a star).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[STARTING] AT &amp;lt;dir&amp;gt; ...]&amp;lt;/code&amp;gt; (equivalently you can say &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;FROM&amp;lt;/code&amp;gt; if it reads better)&lt;br /&gt;
: This specifies where the dialog&#039;s file-system navigation should start (by default, it will start in the current working directory).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[WITH] PROMPT &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This specifies the text prompt at the top of the dialog.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
choose file of type .dat from ../data/samplefiles with prompt &amp;quot;Choose a data file for playback:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose output file of type .prm in ../parms with prompt &amp;quot;Save parameters as...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose directory starting at ../data with prompt &amp;quot;Select a subject directory:&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===CUSTOM DIALOG ...===&lt;br /&gt;
&lt;br /&gt;
This command assembles a flexibly customizable modal dialog for communicating with the user. The command returns (prints) a string denoting which button the user pressed to complete the dialog, and as a side effect it may set any environment variables that the command specifies.  If the user cancels the dialog, the command does nothing (prints nothing, does not change any environment variables).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command can be followed by as many clauses as you like. The main types of clause are &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog, in the order you provide. Possible clauses are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Each message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule. Simplest example: &amp;lt;pre&amp;gt;custom dialog message &amp;quot;Hello world!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. For example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used in conjunction with an empty first/default option, to force the user to make an explicit selection. For example: &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, will be the one that gets highlighted by default and bound to the enter/return keystroke. If you do not specify a default, then &amp;quot;Ok&amp;quot; will be assumed to be the default button; if the designated default does not appear in the list of buttons, the buttons will all have equal status with no return-keystroke binding). The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke, and pressing this button is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).  You will probably not need to configure the buttons explicitly in most cases. In dialogs without &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are simply displaying messages to the user), the &amp;lt;code&amp;gt;BUTTONS {Ok} DEFAULT Ok&amp;lt;/code&amp;gt; configuration is assumed. In dialogs with one or more &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are asking the user for information), the &amp;lt;code&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel&amp;lt;/code&amp;gt; configuration is assumed.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TITLE &amp;lt;text&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This overrides the default dialog title &amp;quot;BCI2000&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;SPACING &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical spacing between successive &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; elements.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;WIDTH &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;HEIGHT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;LEFT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the horizontal coordinate of the dialog&#039;s left edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TOP &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical coordinate of the dialog&#039;s top edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Integrated &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; example====&lt;br /&gt;
&lt;br /&gt;
The following partial listing illustrates one way &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; might be used to implement a simplified launcher GUI, for a hypothetical auditory BCI experiment.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# [initialize system]&lt;br /&gt;
# [start up modules]&lt;br /&gt;
# [load baseline parameters for this BCI]&lt;br /&gt;
# [if you want, you can pre-initialize environment variables subjectName, runType and stimulusCondition]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
set environment launcherAction ${&lt;br /&gt;
    custom dialog &lt;br /&gt;
        title &amp;quot;Auditory BCI Launcher&amp;quot; &lt;br /&gt;
        var subjectName &amp;quot;Subject ID:&amp;quot; {} default $subjectName minimum 1 &lt;br /&gt;
        var runType &amp;quot;Run Type:&amp;quot; {Calibration|Free Selection} default $runType &lt;br /&gt;
        var stimulusCondition &amp;quot;Stimulus Condition:&amp;quot; {SlowStimuli.prm|FastStimuli.prm} default $stimulusCondition &lt;br /&gt;
        message &amp;quot;NB: each condition should be calibrated separately.&amp;quot; &lt;br /&gt;
        buttons {Quit|Launch} default Launch escape Quit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if [ $launcherAction == &amp;quot;&amp;quot; ]&lt;br /&gt;
    quit&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if [ $runType == Calibration ]&lt;br /&gt;
    load parameterfile ../parms/calib.prm       # let&#039;s assume you have created this&lt;br /&gt;
else&lt;br /&gt;
    load parameterfile ../parms/free.prm        # and this&lt;br /&gt;
end&lt;br /&gt;
load parameterfile ../parms/$stimulusCondition  # and these&lt;br /&gt;
set parameter SubjectName $subjectName&lt;br /&gt;
setconfig&lt;br /&gt;
show window&lt;br /&gt;
set state Running 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The resulting dialog looks like this:&lt;br /&gt;
&lt;br /&gt;
[[File:CustomDialogExample.png]]&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12080</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12080"/>
		<updated>2025-08-29T15:05:55Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* Integrated CUSTOM DIALOG example */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
__FORCETOC__&lt;br /&gt;
&lt;br /&gt;
===CHOOSE ...===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CHOOSE&amp;lt;/code&amp;gt; family of commands prompt the user to specify file or directory paths, via the Qt graphical user interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILE&amp;lt;/code&amp;gt;  (or equivalently &amp;lt;code&amp;gt;CHOOSE FILE&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CHOOSE INPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select a single existing file, and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILES&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE FILES&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select one or more existing files, and prints the resulting file paths.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE OUTPUT FILE&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE OUTPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists) and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;&lt;br /&gt;
: Prompts the user to specify a directory, and prints the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
The commands may be followed by one or more of the following optional clauses (they must appear in this order):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[OF] TYPE[S] &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This limits the view (via a drop-down file-type selector) to files that have the specified extension(s). This clause cannot be used with &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;.  Instead of a file extension (starting with a dot) you can alternatively specify a glob pattern (containing a star).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[STARTING] AT &amp;lt;dir&amp;gt; ...]&amp;lt;/code&amp;gt; (equivalently you can say &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;FROM&amp;lt;/code&amp;gt; if it reads better)&lt;br /&gt;
: This specifies where the dialog&#039;s file-system navigation should start (by default, it will start in the current working directory).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[WITH] PROMPT &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This specifies the text prompt at the top of the dialog.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
choose file of type .dat from ../data/samplefiles with prompt &amp;quot;Choose a data file for playback:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose output file of type .prm in ../parms with prompt &amp;quot;Save parameters as...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose directory starting at ../data with prompt &amp;quot;Select a subject directory:&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===CUSTOM DIALOG ...===&lt;br /&gt;
&lt;br /&gt;
This command assembles a flexibly customizable modal dialog for communicating with the user. The command returns (prints) a string denoting which button the user pressed to complete the dialog, and as a side effect it may set any environment variables that the command specifies.  If the user cancels the dialog, the command does nothing (prints nothing, does not change any environment variables).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command can be followed by as many clauses as you like. The main types of clause are &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog, in the order you provide. Possible clauses are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Each message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule. Simplest example: &amp;lt;pre&amp;gt;custom dialog message &amp;quot;Hello world!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. For example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used in conjunction with an empty first/default option, to force the user to make an explicit selection. For example: &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, will be the one that gets highlighted by default and bound to the enter/return keystroke. If you do not specify a default, then &amp;quot;Ok&amp;quot; will be assumed to be the default button; if the designated default does not appear in the list of buttons, the buttons will all have equal status with no return-keystroke binding). The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke, and pressing this button is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).  You will probably not need to configure the buttons explicitly in most cases. In dialogs without &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are simply displaying messages to the user), the &amp;lt;code&amp;gt;BUTTONS {Ok} DEFAULT Ok&amp;lt;/code&amp;gt; configuration is assumed. In dialogs with one or more &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are asking the user for information), the &amp;lt;code&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel&amp;lt;/code&amp;gt; configuration is assumed.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TITLE &amp;lt;text&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This overrides the default dialog title &amp;quot;BCI2000&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;SPACING &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical spacing between successive &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; elements.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;WIDTH &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;HEIGHT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;LEFT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the horizontal coordinate of the dialog&#039;s left edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TOP &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical coordinate of the dialog&#039;s top edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Integrated &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; example====&lt;br /&gt;
&lt;br /&gt;
The following partial listing illustrates one way &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; might be used to implement a simplified launcher GUI, for a hypothetical auditory BCI experiment.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# [initialize system]&lt;br /&gt;
# [start up modules]&lt;br /&gt;
# [load common parameters]&lt;br /&gt;
# [if you want, you can pre-initialize environment variables subjectName, runType and stimulusCondition]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
set environment launcherAction ${&lt;br /&gt;
    custom dialog &lt;br /&gt;
        title &amp;quot;Auditory BCI Launcher&amp;quot; &lt;br /&gt;
        var subjectName &amp;quot;Subject ID:&amp;quot; {} default $subjectName minimum 1 &lt;br /&gt;
        var runType &amp;quot;Run Type:&amp;quot; {Calibration|Free Selection} default $runType &lt;br /&gt;
        var stimulusCondition &amp;quot;Stimulus Condition:&amp;quot; {SlowStimuli.prm|FastStimuli.prm} default $stimulusCondition &lt;br /&gt;
        message &amp;quot;NB: each condition should be calibrated separately.&amp;quot; &lt;br /&gt;
        buttons {Quit|Launch} default Launch escape Quit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if [ $launcherAction == &amp;quot;&amp;quot; ]&lt;br /&gt;
    quit&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if [ $runType == Calibration ]&lt;br /&gt;
    load parameterfile ../parms/calib.prm       # let&#039;s assume you have created this&lt;br /&gt;
else&lt;br /&gt;
    load parameterfile ../parms/free.prm        # and this&lt;br /&gt;
end&lt;br /&gt;
load parameterfile ../parms/$stimulusCondition  # and these&lt;br /&gt;
set parameter SubjectName $subjectName&lt;br /&gt;
setconfig&lt;br /&gt;
show window&lt;br /&gt;
set state Running 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The resulting dialog looks like this:&lt;br /&gt;
&lt;br /&gt;
[[File:CustomDialogExample.png]]&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12079</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12079"/>
		<updated>2025-08-29T15:04:55Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* Integrated CUSTOM DIALOG example */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
__FORCETOC__&lt;br /&gt;
&lt;br /&gt;
===CHOOSE ...===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CHOOSE&amp;lt;/code&amp;gt; family of commands prompt the user to specify file or directory paths, via the Qt graphical user interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILE&amp;lt;/code&amp;gt;  (or equivalently &amp;lt;code&amp;gt;CHOOSE FILE&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CHOOSE INPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select a single existing file, and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILES&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE FILES&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select one or more existing files, and prints the resulting file paths.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE OUTPUT FILE&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE OUTPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists) and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;&lt;br /&gt;
: Prompts the user to specify a directory, and prints the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
The commands may be followed by one or more of the following optional clauses (they must appear in this order):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[OF] TYPE[S] &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This limits the view (via a drop-down file-type selector) to files that have the specified extension(s). This clause cannot be used with &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;.  Instead of a file extension (starting with a dot) you can alternatively specify a glob pattern (containing a star).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[STARTING] AT &amp;lt;dir&amp;gt; ...]&amp;lt;/code&amp;gt; (equivalently you can say &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;FROM&amp;lt;/code&amp;gt; if it reads better)&lt;br /&gt;
: This specifies where the dialog&#039;s file-system navigation should start (by default, it will start in the current working directory).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[WITH] PROMPT &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This specifies the text prompt at the top of the dialog.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
choose file of type .dat from ../data/samplefiles with prompt &amp;quot;Choose a data file for playback:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose output file of type .prm in ../parms with prompt &amp;quot;Save parameters as...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose directory starting at ../data with prompt &amp;quot;Select a subject directory:&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===CUSTOM DIALOG ...===&lt;br /&gt;
&lt;br /&gt;
This command assembles a flexibly customizable modal dialog for communicating with the user. The command returns (prints) a string denoting which button the user pressed to complete the dialog, and as a side effect it may set any environment variables that the command specifies.  If the user cancels the dialog, the command does nothing (prints nothing, does not change any environment variables).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command can be followed by as many clauses as you like. The main types of clause are &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog, in the order you provide. Possible clauses are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Each message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule. Simplest example: &amp;lt;pre&amp;gt;custom dialog message &amp;quot;Hello world!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. For example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used in conjunction with an empty first/default option, to force the user to make an explicit selection. For example: &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, will be the one that gets highlighted by default and bound to the enter/return keystroke. If you do not specify a default, then &amp;quot;Ok&amp;quot; will be assumed to be the default button; if the designated default does not appear in the list of buttons, the buttons will all have equal status with no return-keystroke binding). The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke, and pressing this button is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).  You will probably not need to configure the buttons explicitly in most cases. In dialogs without &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are simply displaying messages to the user), the &amp;lt;code&amp;gt;BUTTONS {Ok} DEFAULT Ok&amp;lt;/code&amp;gt; configuration is assumed. In dialogs with one or more &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are asking the user for information), the &amp;lt;code&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel&amp;lt;/code&amp;gt; configuration is assumed.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TITLE &amp;lt;text&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This overrides the default dialog title &amp;quot;BCI2000&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;SPACING &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical spacing between successive &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; elements.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;WIDTH &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;HEIGHT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;LEFT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the horizontal coordinate of the dialog&#039;s left edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TOP &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical coordinate of the dialog&#039;s top edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Integrated &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; example====&lt;br /&gt;
&lt;br /&gt;
The following partial listing illustrates one way &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; might be used to implement a simplified launcher GUI, for a hypothetical auditory BCI experiment.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# [initialize system]&lt;br /&gt;
# [start up modules]&lt;br /&gt;
# [load common parameters]&lt;br /&gt;
# [pre-initialize environment variables subjectName, runType and stimulusCondition if you want]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
set environment launcherAction ${&lt;br /&gt;
    custom dialog &lt;br /&gt;
        title &amp;quot;Auditory BCI Launcher&amp;quot; &lt;br /&gt;
        var subjectName &amp;quot;Subject ID:&amp;quot; {} default $subjectName minimum 1 &lt;br /&gt;
        var runType &amp;quot;Run Type:&amp;quot; {Calibration|Free Selection} default $runType &lt;br /&gt;
        var stimulusCondition &amp;quot;Stimulus Condition:&amp;quot; {SlowStimuli.prm|FastStimuli.prm} default $stimulusCondition &lt;br /&gt;
        message &amp;quot;NB: each condition should be calibrated separately.&amp;quot; &lt;br /&gt;
        buttons {Quit|Launch} default Launch escape Quit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if [ $launcherAction == &amp;quot;&amp;quot; ]&lt;br /&gt;
    quit&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if [ $runType == Calibration ]&lt;br /&gt;
    load parameterfile ../parms/calib.prm       # let&#039;s assume you have created this&lt;br /&gt;
else&lt;br /&gt;
    load parameterfile ../parms/free.prm        # and this&lt;br /&gt;
end&lt;br /&gt;
load parameterfile ../parms/$stimulusCondition  # and these&lt;br /&gt;
set parameter SubjectName $subjectName&lt;br /&gt;
setconfig&lt;br /&gt;
show window&lt;br /&gt;
set state Running 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The resulting dialog looks like this:&lt;br /&gt;
&lt;br /&gt;
[[File:CustomDialogExample.png]]&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=File:CustomDialogExample.png&amp;diff=12078</id>
		<title>File:CustomDialogExample.png</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=File:CustomDialogExample.png&amp;diff=12078"/>
		<updated>2025-08-29T15:02:53Z</updated>

		<summary type="html">&lt;p&gt;Jhill: Jhill uploaded a new version of File:CustomDialogExample.png&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12077</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12077"/>
		<updated>2025-08-29T15:02:32Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* Integrated CUSTOM DIALOG example */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
__FORCETOC__&lt;br /&gt;
&lt;br /&gt;
===CHOOSE ...===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CHOOSE&amp;lt;/code&amp;gt; family of commands prompt the user to specify file or directory paths, via the Qt graphical user interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILE&amp;lt;/code&amp;gt;  (or equivalently &amp;lt;code&amp;gt;CHOOSE FILE&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CHOOSE INPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select a single existing file, and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILES&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE FILES&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select one or more existing files, and prints the resulting file paths.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE OUTPUT FILE&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE OUTPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists) and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;&lt;br /&gt;
: Prompts the user to specify a directory, and prints the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
The commands may be followed by one or more of the following optional clauses (they must appear in this order):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[OF] TYPE[S] &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This limits the view (via a drop-down file-type selector) to files that have the specified extension(s). This clause cannot be used with &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;.  Instead of a file extension (starting with a dot) you can alternatively specify a glob pattern (containing a star).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[STARTING] AT &amp;lt;dir&amp;gt; ...]&amp;lt;/code&amp;gt; (equivalently you can say &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;FROM&amp;lt;/code&amp;gt; if it reads better)&lt;br /&gt;
: This specifies where the dialog&#039;s file-system navigation should start (by default, it will start in the current working directory).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[WITH] PROMPT &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This specifies the text prompt at the top of the dialog.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
choose file of type .dat from ../data/samplefiles with prompt &amp;quot;Choose a data file for playback:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose output file of type .prm in ../parms with prompt &amp;quot;Save parameters as...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose directory starting at ../data with prompt &amp;quot;Select a subject directory:&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===CUSTOM DIALOG ...===&lt;br /&gt;
&lt;br /&gt;
This command assembles a flexibly customizable modal dialog for communicating with the user. The command returns (prints) a string denoting which button the user pressed to complete the dialog, and as a side effect it may set any environment variables that the command specifies.  If the user cancels the dialog, the command does nothing (prints nothing, does not change any environment variables).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command can be followed by as many clauses as you like. The main types of clause are &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog, in the order you provide. Possible clauses are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Each message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule. Simplest example: &amp;lt;pre&amp;gt;custom dialog message &amp;quot;Hello world!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. For example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used in conjunction with an empty first/default option, to force the user to make an explicit selection. For example: &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, will be the one that gets highlighted by default and bound to the enter/return keystroke. If you do not specify a default, then &amp;quot;Ok&amp;quot; will be assumed to be the default button; if the designated default does not appear in the list of buttons, the buttons will all have equal status with no return-keystroke binding). The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke, and pressing this button is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).  You will probably not need to configure the buttons explicitly in most cases. In dialogs without &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are simply displaying messages to the user), the &amp;lt;code&amp;gt;BUTTONS {Ok} DEFAULT Ok&amp;lt;/code&amp;gt; configuration is assumed. In dialogs with one or more &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are asking the user for information), the &amp;lt;code&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel&amp;lt;/code&amp;gt; configuration is assumed.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TITLE &amp;lt;text&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This overrides the default dialog title &amp;quot;BCI2000&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;SPACING &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical spacing between successive &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; elements.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;WIDTH &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;HEIGHT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;LEFT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the horizontal coordinate of the dialog&#039;s left edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TOP &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical coordinate of the dialog&#039;s top edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Integrated &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; example====&lt;br /&gt;
&lt;br /&gt;
The following partial listing illustrates one way &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; might be used to implement a simplified launcher GUI, for a hypothetical auditory BCI experiment.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# [initialize system]&lt;br /&gt;
# [start up modules]&lt;br /&gt;
# [load common parameters]&lt;br /&gt;
# [pre-initialize environment variables subjectName, runType and stimulusCondition if you want]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
set environment launcherAction ${&lt;br /&gt;
    custom dialog &lt;br /&gt;
        title &amp;quot;Auditory BCI Launcher&amp;quot; &lt;br /&gt;
        var subjectName &amp;quot;Subject ID:&amp;quot; {} default $subjectName minimum 1 &lt;br /&gt;
        var runType &amp;quot;Run Type:&amp;quot; {Calibration|Free Selection} default $runType &lt;br /&gt;
        var stimulusCondition &amp;quot;Stimulus Condition:&amp;quot; {SlowStimuli.prm|FastStimuli.prm} default $stimulusCondition &lt;br /&gt;
        message &amp;quot;NB: each condition should be calibrated separately.&amp;quot; &lt;br /&gt;
        buttons {Quit|Launch} default Launch escape Quit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if [ $launcherAction == &amp;quot;&amp;quot; ]&lt;br /&gt;
	quit&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if [ $runType == Calibration ]&lt;br /&gt;
	load parameterfile ../parms/calib.prm       # let&#039;s assume you have created this&lt;br /&gt;
else&lt;br /&gt;
	load parameterfile ../parms/free.prm        # and this&lt;br /&gt;
end&lt;br /&gt;
load parameterfile ../parms/$stimulusCondition  # and these&lt;br /&gt;
set parameter SubjectName $subjectName&lt;br /&gt;
setconfig&lt;br /&gt;
show window&lt;br /&gt;
set state Running 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The resulting dialog looks like this:&lt;br /&gt;
&lt;br /&gt;
[[File:CustomDialogExample.png]]&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12076</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12076"/>
		<updated>2025-08-28T22:40:51Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* Integrated example: */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
__FORCETOC__&lt;br /&gt;
&lt;br /&gt;
===CHOOSE ...===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CHOOSE&amp;lt;/code&amp;gt; family of commands prompt the user to specify file or directory paths, via the Qt graphical user interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILE&amp;lt;/code&amp;gt;  (or equivalently &amp;lt;code&amp;gt;CHOOSE FILE&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CHOOSE INPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select a single existing file, and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILES&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE FILES&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select one or more existing files, and prints the resulting file paths.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE OUTPUT FILE&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE OUTPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists) and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;&lt;br /&gt;
: Prompts the user to specify a directory, and prints the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
The commands may be followed by one or more of the following optional clauses (they must appear in this order):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[OF] TYPE[S] &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This limits the view (via a drop-down file-type selector) to files that have the specified extension(s). This clause cannot be used with &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;.  Instead of a file extension (starting with a dot) you can alternatively specify a glob pattern (containing a star).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[STARTING] AT &amp;lt;dir&amp;gt; ...]&amp;lt;/code&amp;gt; (equivalently you can say &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;FROM&amp;lt;/code&amp;gt; if it reads better)&lt;br /&gt;
: This specifies where the dialog&#039;s file-system navigation should start (by default, it will start in the current working directory).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[WITH] PROMPT &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This specifies the text prompt at the top of the dialog.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
choose file of type .dat from ../data/samplefiles with prompt &amp;quot;Choose a data file for playback:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose output file of type .prm in ../parms with prompt &amp;quot;Save parameters as...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose directory starting at ../data with prompt &amp;quot;Select a subject directory:&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===CUSTOM DIALOG ...===&lt;br /&gt;
&lt;br /&gt;
This command assembles a flexibly customizable modal dialog for communicating with the user. The command returns (prints) a string denoting which button the user pressed to complete the dialog, and as a side effect it may set any environment variables that the command specifies.  If the user cancels the dialog, the command does nothing (prints nothing, does not change any environment variables).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command can be followed by as many clauses as you like. The main types of clause are &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog, in the order you provide. Possible clauses are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Each message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule. Simplest example: &amp;lt;pre&amp;gt;custom dialog message &amp;quot;Hello world!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. For example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used in conjunction with an empty first/default option, to force the user to make an explicit selection. For example: &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, will be the one that gets highlighted by default and bound to the enter/return keystroke. If you do not specify a default, then &amp;quot;Ok&amp;quot; will be assumed to be the default button; if the designated default does not appear in the list of buttons, the buttons will all have equal status with no return-keystroke binding). The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke, and pressing this button is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).  You will probably not need to configure the buttons explicitly in most cases. In dialogs without &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are simply displaying messages to the user), the &amp;lt;code&amp;gt;BUTTONS {Ok} DEFAULT Ok&amp;lt;/code&amp;gt; configuration is assumed. In dialogs with one or more &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are asking the user for information), the &amp;lt;code&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel&amp;lt;/code&amp;gt; configuration is assumed.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TITLE &amp;lt;text&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This overrides the default dialog title &amp;quot;BCI2000&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;SPACING &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical spacing between successive &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; elements.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;WIDTH &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;HEIGHT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;LEFT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the horizontal coordinate of the dialog&#039;s left edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TOP &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical coordinate of the dialog&#039;s top edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Integrated &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
set environment launcherAction ${custom dialog title &amp;quot;Auditory BCI Launcher&amp;quot; var subjectName &amp;quot;Subject ID:&amp;quot; {} default $subjectName minimum 1 var runType &amp;quot;Run Type:&amp;quot; {Calibration|Free Selection} default $runType var condition &amp;quot;Stimulus Condition:&amp;quot; {SlowStimuli.prm|FastStimuli.prm} default $condition message &amp;quot;NB: each condition should be calibrated separately.&amp;quot; buttons {quit|Launch} default Launch escape quit}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
[[File:CustomDialogExample.png]]&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12075</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12075"/>
		<updated>2025-08-28T22:38:51Z</updated>

		<summary type="html">&lt;p&gt;Jhill: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
__FORCETOC__&lt;br /&gt;
&lt;br /&gt;
===CHOOSE ...===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CHOOSE&amp;lt;/code&amp;gt; family of commands prompt the user to specify file or directory paths, via the Qt graphical user interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILE&amp;lt;/code&amp;gt;  (or equivalently &amp;lt;code&amp;gt;CHOOSE FILE&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CHOOSE INPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select a single existing file, and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILES&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE FILES&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select one or more existing files, and prints the resulting file paths.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE OUTPUT FILE&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE OUTPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists) and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;&lt;br /&gt;
: Prompts the user to specify a directory, and prints the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
The commands may be followed by one or more of the following optional clauses (they must appear in this order):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[OF] TYPE[S] &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This limits the view (via a drop-down file-type selector) to files that have the specified extension(s). This clause cannot be used with &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;.  Instead of a file extension (starting with a dot) you can alternatively specify a glob pattern (containing a star).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[STARTING] AT &amp;lt;dir&amp;gt; ...]&amp;lt;/code&amp;gt; (equivalently you can say &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;FROM&amp;lt;/code&amp;gt; if it reads better)&lt;br /&gt;
: This specifies where the dialog&#039;s file-system navigation should start (by default, it will start in the current working directory).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[WITH] PROMPT &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This specifies the text prompt at the top of the dialog.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
choose file of type .dat from ../data/samplefiles with prompt &amp;quot;Choose a data file for playback:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose output file of type .prm in ../parms with prompt &amp;quot;Save parameters as...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose directory starting at ../data with prompt &amp;quot;Select a subject directory:&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===CUSTOM DIALOG ...===&lt;br /&gt;
&lt;br /&gt;
This command assembles a flexibly customizable modal dialog for communicating with the user. The command returns (prints) a string denoting which button the user pressed to complete the dialog, and as a side effect it may set any environment variables that the command specifies.  If the user cancels the dialog, the command does nothing (prints nothing, does not change any environment variables).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command can be followed by as many clauses as you like. The main types of clause are &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog, in the order you provide. Possible clauses are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Each message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule. Simplest example: &amp;lt;pre&amp;gt;custom dialog message &amp;quot;Hello world!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. For example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used in conjunction with an empty first/default option, to force the user to make an explicit selection. For example: &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, will be the one that gets highlighted by default and bound to the enter/return keystroke. If you do not specify a default, then &amp;quot;Ok&amp;quot; will be assumed to be the default button; if the designated default does not appear in the list of buttons, the buttons will all have equal status with no return-keystroke binding). The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke, and pressing this button is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).  You will probably not need to configure the buttons explicitly in most cases. In dialogs without &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are simply displaying messages to the user), the &amp;lt;code&amp;gt;BUTTONS {Ok} DEFAULT Ok&amp;lt;/code&amp;gt; configuration is assumed. In dialogs with one or more &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are asking the user for information), the &amp;lt;code&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel&amp;lt;/code&amp;gt; configuration is assumed.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TITLE &amp;lt;text&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This overrides the default dialog title &amp;quot;BCI2000&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;SPACING &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical spacing between successive &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; elements.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;WIDTH &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;HEIGHT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;LEFT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the horizontal coordinate of the dialog&#039;s left edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TOP &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical coordinate of the dialog&#039;s top edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Integrated example:====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
set environment launcherAction ${custom dialog title &amp;quot;Auditory BCI Launcher&amp;quot; var subjectName &amp;quot;Subject ID:&amp;quot; {} default $subjectName minimum 1 var runType &amp;quot;Run Type:&amp;quot; {Calibration|Free Selection} default $runType var condition &amp;quot;Stimulus Condition:&amp;quot; {SlowStimuli.prm|FastStimuli.prm} default $condition message &amp;quot;NB: each condition should be calibrated separately.&amp;quot; buttons {quit|Launch} default Launch escape quit}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
[[File:CustomDialogExample.png]]&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=File:CustomDialogExample.png&amp;diff=12074</id>
		<title>File:CustomDialogExample.png</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=File:CustomDialogExample.png&amp;diff=12074"/>
		<updated>2025-08-28T22:37:00Z</updated>

		<summary type="html">&lt;p&gt;Jhill: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12073</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12073"/>
		<updated>2025-08-28T21:09:49Z</updated>

		<summary type="html">&lt;p&gt;Jhill: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
__FORCETOC__&lt;br /&gt;
&lt;br /&gt;
===CHOOSE ...===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CHOOSE&amp;lt;/code&amp;gt; family of commands prompt the user to specify file or directory paths, via the Qt graphical user interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILE&amp;lt;/code&amp;gt;  (or equivalently &amp;lt;code&amp;gt;CHOOSE FILE&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CHOOSE INPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select a single existing file, and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILES&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE FILES&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select one or more existing files, and prints the resulting file paths.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE OUTPUT FILE&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE OUTPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists) and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;&lt;br /&gt;
: Prompts the user to specify a directory, and prints the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
The commands may be followed by one or more of the following optional clauses (they must appear in this order):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[OF] TYPE[S] &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This limits the view (via a drop-down file-type selector) to files that have the specified extension(s). This clause cannot be used with &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;.  Instead of a file extension (starting with a dot) you can alternatively specify a glob pattern (containing a star).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[STARTING] AT &amp;lt;dir&amp;gt; ...]&amp;lt;/code&amp;gt; (equivalently you can say &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;FROM&amp;lt;/code&amp;gt; if it reads better)&lt;br /&gt;
: This specifies where the dialog&#039;s file-system navigation should start (by default, it will start in the current working directory).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[WITH] PROMPT &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This specifies the text prompt at the top of the dialog.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
choose file of type .dat from ../data/samplefiles with prompt &amp;quot;Choose a data file for playback:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose output file of type .prm in ../parms with prompt &amp;quot;Save parameters as...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose directory starting at ../data with prompt &amp;quot;Select a subject directory:&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===CUSTOM DIALOG ...===&lt;br /&gt;
&lt;br /&gt;
This command assembles a flexibly customizable modal dialog for communicating with the user. The command returns (prints) a string denoting which button the user pressed to complete the dialog, and as a side effect it may set any environment variables that the command specifies.  If the user cancels the dialog, the command does nothing (prints nothing, does not change any environment variables).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command can be followed by as many clauses as you like. The main types of clause are &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog, in the order you provide. Possible clauses are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Each message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule. Simplest example: &amp;lt;pre&amp;gt;custom dialog message &amp;quot;Hello world!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. For example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used in conjunction with an empty first/default option, to force the user to make an explicit selection. For example: &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, will be the one that gets highlighted by default and bound to the enter/return keystroke. If you do not specify a default, then &amp;quot;Ok&amp;quot; will be assumed to be the default button; if the designated default does not appear in the list of buttons, the buttons will all have equal status with no return-keystroke binding). The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke, and pressing this button is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).  You will probably not need to configure the buttons explicitly in most cases. In dialogs without &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are simply displaying messages to the user), the &amp;lt;code&amp;gt;BUTTONS {Ok} DEFAULT Ok&amp;lt;/code&amp;gt; configuration is assumed. In dialogs with one or more &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are asking the user for information), the &amp;lt;code&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel&amp;lt;/code&amp;gt; configuration is assumed.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TITLE &amp;lt;text&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This overrides the default dialog title &amp;quot;BCI2000&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;SPACING &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical spacing between successive &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; elements.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;WIDTH &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;HEIGHT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;LEFT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the horizontal coordinate of the dialog&#039;s left edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TOP &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical coordinate of the dialog&#039;s top edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Integrated example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
set environment launcherAction ${custom dialog title &amp;quot;Auditory BCI Launcher&amp;quot; var subjectName &amp;quot;Subject ID:&amp;quot; {} default $subjectName minimum 1 var runType &amp;quot;Run Type:&amp;quot; {Calibration|Free Selection} default $runType var condition &amp;quot;Stimulus Condition:&amp;quot; {SlowStimuli.prm|FastStimuli.prm} default $condition message &amp;quot;NB: each condition should be calibrated separately.&amp;quot; buttons {quit|Launch} default Launch escape quit}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12072</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12072"/>
		<updated>2025-08-28T20:54:34Z</updated>

		<summary type="html">&lt;p&gt;Jhill: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
__FORCETOC__&lt;br /&gt;
&lt;br /&gt;
===CHOOSE ...===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CHOOSE&amp;lt;/code&amp;gt; family of commands prompt the user to specify file or directory paths, via the Qt graphical user interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILE&amp;lt;/code&amp;gt;  (or equivalently &amp;lt;code&amp;gt;CHOOSE FILE&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CHOOSE INPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select a single existing file, and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILES&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE FILES&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select one or more existing files, and prints the resulting file paths.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE OUTPUT FILE&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE OUTPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists) and prints the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;&lt;br /&gt;
: Prompts the user to specify a directory, and prints the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
The commands may be followed by one or more of the following optional clauses (they must appear in this order):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[OF] TYPE[S] &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This limits the view (via a drop-down file-type selector) to files that have the specified extension(s). This clause cannot be used with &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;.  Instead of a file extension (starting with a dot) you can alternatively specify a glob pattern (containing a star).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[STARTING] AT &amp;lt;dir&amp;gt; ...]&amp;lt;/code&amp;gt; (equivalently you can say &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;FROM&amp;lt;/code&amp;gt; if it reads better)&lt;br /&gt;
: This specifies where the dialog&#039;s file-system navigation should start (by default, it will start in the current working directory).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[WITH] PROMPT &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This specifies the text prompt at the top of the dialog.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
choose file of type .dat from ../data/samplefiles with prompt &amp;quot;Choose a data file for playback:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose output file of type .prm in ../parms with prompt &amp;quot;Save parameters as...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose directory starting at ../data with prompt &amp;quot;Select a subject directory:&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===CUSTOM DIALOG ...===&lt;br /&gt;
&lt;br /&gt;
This command assembles a flexibly customizable modal dialog for communicating with the user. The command returns (prints) a string denoting which button the user pressed to complete the dialog, and as a side effect it may set any environment variables that the command specifies.  If the user cancels the dialog, the command does nothing (prints nothing, does not change any environment variables).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command can be followed by as many clauses as you like. The main types of clause are &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog, in the order you provide. Possible clauses are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Each message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule. Simplest example: &amp;lt;pre&amp;gt;custom dialog message &amp;quot;Hello world!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. For example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used in conjunction with an empty first/default option, to force the user to make an explicit selection. For example: &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, will be the one that gets highlighted by default and bound to the enter/return keystroke. If you do not specify a default, then &amp;quot;Ok&amp;quot; will be assumed to be the default button; if the designated default does not appear in the list of buttons, the buttons will all have equal status with no return-keystroke binding). The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke, and pressing this button is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).  You will probably not need to configure the buttons explicitly in most cases. In dialogs without &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are simply displaying messages to the user), the &amp;lt;code&amp;gt;BUTTONS {Ok} DEFAULT Ok&amp;lt;/code&amp;gt; configuration is assumed. In dialogs with one or more &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are asking the user for information), the &amp;lt;code&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel&amp;lt;/code&amp;gt; configuration is assumed.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TITLE &amp;lt;text&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This overrides the default dialog title &amp;quot;BCI2000&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;SPACING &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical spacing between successive &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; elements.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;WIDTH &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;HEIGHT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;LEFT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the horizontal coordinate of the dialog&#039;s left edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TOP &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical coordinate of the dialog&#039;s top edge, in pixels.&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12071</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12071"/>
		<updated>2025-08-28T20:43:13Z</updated>

		<summary type="html">&lt;p&gt;Jhill: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
__FORCETOC__&lt;br /&gt;
&lt;br /&gt;
===CHOOSE ...===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CHOOSE&amp;lt;/code&amp;gt; family of commands prompt the user to specify file or directory paths, via the Qt graphical user interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILE&amp;lt;/code&amp;gt;  (or equivalently &amp;lt;code&amp;gt;CHOOSE FILE&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CHOOSE INPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select a single existing file. Print the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILES&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE FILES&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select one or more existing files. Print the resulting file paths.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE OUTPUT FILE&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE OUTPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists). Print the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;&lt;br /&gt;
: Prompts the user to specify a directory. Print the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
The commands may be followed by one or more of the following optional clauses (they must appear in this order):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[OF] TYPE[S] &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This limits the view (via a drop-down file-type selector) to files that have the specified extension(s). This clause cannot be used with &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;.  Instead of a file extension (starting with a dot) you can alternatively specify a glob pattern (containing a star).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[STARTING] AT &amp;lt;dir&amp;gt; ...]&amp;lt;/code&amp;gt; (equivalently you can say &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;FROM&amp;lt;/code&amp;gt; if it reads better)&lt;br /&gt;
: This specifies where the dialog&#039;s file-system navigation should start (by default, it will start in the current working directory).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[WITH] PROMPT &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This specifies the text prompt at the top of the dialog.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
choose file of type .dat from ../data/samplefiles with prompt &amp;quot;Choose a data file for playback:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose output file of type .prm in ../parms with prompt &amp;quot;Save parameters as...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose directory starting at ../data with prompt &amp;quot;Select a subject directory:&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===CUSTOM DIALOG ...===&lt;br /&gt;
&lt;br /&gt;
This command assembles a flexibly customizable modal dialog for communicating with the user. The command returns (prints) a string denoting which button the user pressed to complete the dialog, and as a side effect it may set any environment variables that the command specifies.  If the user cancels the dialog, the command does nothing (prints nothing, does not change any environment variables).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command can be followed by as many clauses as you like. The main types of clause are &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog, in the order you provide. Possible clauses are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Each message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule. Simplest example: &amp;lt;pre&amp;gt;custom dialog message &amp;quot;Hello world!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. For example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used in conjunction with an empty first/default option, to force the user to make an explicit selection. For example: &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, will be the one that gets highlighted by default and bound to the enter/return keystroke. If you do not specify a default, then &amp;quot;Ok&amp;quot; will be assumed to be the default button; if the designated default does not appear in the list of buttons, the buttons will all have equal status with no return-keystroke binding). The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke, and pressing this button is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).  You will probably not need to configure the buttons explicitly in most cases. In dialogs without &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are simply displaying messages to the user), the &amp;lt;code&amp;gt;BUTTONS {Ok} DEFAULT Ok&amp;lt;/code&amp;gt; configuration is assumed. In dialogs with one or more &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are asking the user for information), the &amp;lt;code&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel&amp;lt;/code&amp;gt; configuration is assumed.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TITLE &amp;lt;text&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This overrides the default dialog title &amp;quot;BCI2000&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;SPACING &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical spacing between successive &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; elements.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;WIDTH &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;HEIGHT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;LEFT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the horizontal coordinate of the dialog&#039;s left edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TOP &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical coordinate of the dialog&#039;s top edge, in pixels.&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12070</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12070"/>
		<updated>2025-08-28T20:36:29Z</updated>

		<summary type="html">&lt;p&gt;Jhill: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
==CHOOSE ...==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CHOOSE&amp;lt;/code&amp;gt; family of commands prompt the user to specify file or directory paths, via the Qt graphical user interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILE&amp;lt;/code&amp;gt;  (or equivalently &amp;lt;code&amp;gt;CHOOSE FILE&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CHOOSE INPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select a single existing file. Print the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILES&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE FILES&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select one or more existing files. Print the resulting file paths.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE OUTPUT FILE&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE OUTPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists). Print the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;&lt;br /&gt;
: Prompts the user to specify a directory. Print the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
The commands may be followed by one or more of the following optional clauses (they must appear in this order):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[OF] TYPE[S] &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This limits the view (via a drop-down file-type selector) to files that have the specified extension(s). This clause cannot be used with &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;.  Instead of a file extension (starting with a dot) you can alternatively specify a glob pattern (containing a star).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[STARTING] AT &amp;lt;dir&amp;gt; ...]&amp;lt;/code&amp;gt; (equivalently you can say &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;FROM&amp;lt;/code&amp;gt; if it reads better)&lt;br /&gt;
: This specifies where the dialog&#039;s file-system navigation should start (by default, it will start in the current working directory).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[WITH] PROMPT &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This specifies the text prompt at the top of the dialog.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
choose file of type .dat from ../data/samplefiles with prompt &amp;quot;Choose a data file for playback:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose output file of type .prm in ../parms with prompt &amp;quot;Save parameters as...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose directory starting at ../data with prompt &amp;quot;Select a subject directory:&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==CUSTOM DIALOG ...==&lt;br /&gt;
&lt;br /&gt;
This command assembles a flexibly customizable modal dialog for communicating with the user. The command returns (prints) a string denoting which button the user pressed to complete the dialog, and as a side effect it may set any environment variables that the command specifies.  If the user cancels the dialog, the command does nothing (prints nothing, does not change any environment variables).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command can be followed by as many clauses as you like. The main types of clause are &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog, in the order you provide.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Each message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule. Simplest example: &amp;lt;pre&amp;gt;custom dialog message &amp;quot;Hello world!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. For example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used in conjunction with an empty first/default option, to force the user to make an explicit selection. For example: &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, will be the one that gets highlighted by default and bound to the enter/return keystroke. If you do not specify a default, then &amp;quot;Ok&amp;quot; will be assumed to be the default button; if the designated default does not appear in the list of buttons, the buttons will all have equal status with no return-keystroke binding). The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke, and pressing this button is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).&lt;br /&gt;
: You will probably not need to configure the buttons explicitly in most cases. In dialogs with no &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are simply displaying messages to the user), the &amp;lt;code&amp;gt;BUTTONS {Ok} DEFAULT Ok&amp;lt;/code&amp;gt; configuration is assumed. In dialogs with one or more &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are asking the user for information), the &amp;lt;code&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel&amp;lt;/code&amp;gt; configuration is assumed.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TITLE &amp;lt;text&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This overrides the default dialog title &amp;quot;BCI2000&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;SPACING &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical spacing between successive &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; elements.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;WIDTH &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;HEIGHT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;LEFT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the horizontal coordinate of the dialog&#039;s left edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TOP &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical coordinate of the dialog&#039;s top edge, in pixels.&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12069</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12069"/>
		<updated>2025-08-28T20:34:27Z</updated>

		<summary type="html">&lt;p&gt;Jhill: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
==CHOOSE ...==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CHOOSE&amp;lt;/code&amp;gt; family of commands prompt the user to specify file or directory paths, via the Qt graphical user interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILE&amp;lt;/code&amp;gt;  (or equivalently &amp;lt;code&amp;gt;CHOOSE FILE&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CHOOSE INPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select a single existing file. Print the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILES&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE FILES&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select one or more existing files. Print the resulting file paths.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE OUTPUT FILE&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE OUTPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists). Print the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;&lt;br /&gt;
: Prompts the user to specify a directory. Print the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
The commands may be followed by one or more of the following optional clauses (they must appear in this order):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[OF] TYPE[S] &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This limits the view (via a drop-down file-type selector) to files that have the specified extension(s). This clause cannot be used with &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;.  Instead of a file extension (starting with a dot) you can alternatively specify a glob pattern (containing a star).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[STARTING] AT &amp;lt;dir&amp;gt; ...]&amp;lt;/code&amp;gt; (or equivalently &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;FROM&amp;lt;/code&amp;gt;)&lt;br /&gt;
: This specifies where the dialog&#039;s file-system navigation should start (by default, it&lt;br /&gt;
will start in the current working directory).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[WITH] PROMPT &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This specifies the text prompt at the top of the dialog.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
choose file of type .dat from ../data/samplefiles with prompt &amp;quot;Choose a data file for playback:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose output file of type .prm in ../parms with prompt &amp;quot;Save parameters as...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose directory starting at ../data with prompt &amp;quot;Select a subject directory:&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==CUSTOM DIALOG ...==&lt;br /&gt;
&lt;br /&gt;
This command assembles a flexibly customizable modal dialog for communicating with the user. The command returns (prints) a string denoting which button the user pressed to complete the dialog, and as a side effect it may set any environment variables that the command specifies.  If the user cancels the dialog, the command does nothing (prints nothing, does not change any environment variables).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command can be followed by as many clauses as you like. The main types of clause are &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog, in the order you provide.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Each message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule. Simplest example: &amp;lt;pre&amp;gt;custom dialog message &amp;quot;Hello world!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. For example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used in conjunction with an empty first/default option, to force the user to make an explicit selection. For example: &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, will be the one that gets highlighted by default and bound to the enter/return keystroke. If you do not specify a default, then &amp;quot;Ok&amp;quot; will be assumed to be the default button; if the designated default does not appear in the list of buttons, the buttons will all have equal status with no return-keystroke binding). The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke, and pressing this button is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).&lt;br /&gt;
: You will probably not need to configure the buttons explicitly in most cases. In dialogs with no &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are simply displaying messages to the user), the &amp;lt;code&amp;gt;BUTTONS {Ok} DEFAULT Ok&amp;lt;/code&amp;gt; configuration is assumed. In dialogs with one or more &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are asking the user for information), the &amp;lt;code&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel&amp;lt;/code&amp;gt; configuration is assumed.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TITLE &amp;lt;text&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This overrides the default dialog title &amp;quot;BCI2000&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;SPACING &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical spacing between successive &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; elements.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;WIDTH &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;HEIGHT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;LEFT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the horizontal coordinate of the dialog&#039;s left edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TOP &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical coordinate of the dialog&#039;s top edge, in pixels.&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12068</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12068"/>
		<updated>2025-08-28T20:33:34Z</updated>

		<summary type="html">&lt;p&gt;Jhill: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
=====CHOOSE ...=====&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CHOOSE&amp;lt;/code&amp;gt; family of commands prompt the user to specify file or directory paths, via the Qt graphical user interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILE&amp;lt;/code&amp;gt;  (or equivalently &amp;lt;code&amp;gt;CHOOSE FILE&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CHOOSE INPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select a single existing file. Print the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILES&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE FILES&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to select one or more existing files. Print the resulting file paths.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE OUTPUT FILE&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE OUTPUT&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Prompts the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists). Print the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;&lt;br /&gt;
: Prompts the user to specify a directory. Print the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
The commands may be followed by one or more of the following optional clauses (they must appear in this order):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[OF] TYPE[S] &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This limits the view (via a drop-down file-type selector) to files that have the specified extension(s). This clause cannot be used with &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;.  Instead of a file extension (starting with a dot) you can alternatively specify a glob pattern (containing a star).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[STARTING] AT &amp;lt;dir&amp;gt; ...]&amp;lt;/code&amp;gt; (or equivalently &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;FROM&amp;lt;/code&amp;gt;)&lt;br /&gt;
: This specifies where the dialog&#039;s file-system navigation should start (by default, it&lt;br /&gt;
will start in the current working directory).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[WITH] PROMPT &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This specifies the text prompt at the top of the dialog.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
choose file of type .dat from ../data/samplefiles with prompt &amp;quot;Choose a data file for playback:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose output file of type .prm in ../parms with prompt &amp;quot;Save parameters as...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose directory starting at ../data with prompt &amp;quot;Select a subject directory:&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====CUSTOM DIALOG ...=====&lt;br /&gt;
&lt;br /&gt;
This command assembles a flexibly customizable modal dialog for communicating with the user. The command returns (prints) a string denoting which button the user pressed to complete the dialog, and as a side effect it may set any environment variables that the command specifies.  If the user cancels the dialog, the command does nothing (prints nothing, does not change any environment variables).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command can be followed by as many clauses as you like. The main types of clause are &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog, in the order you provide.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Each message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule. Simplest example: &amp;lt;pre&amp;gt;custom dialog message &amp;quot;Hello world!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. For example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used in conjunction with an empty first/default option, to force the user to make an explicit selection. For example: &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, will be the one that gets highlighted by default and bound to the enter/return keystroke. If you do not specify a default, then &amp;quot;Ok&amp;quot; will be assumed to be the default button; if the designated default does not appear in the list of buttons, the buttons will all have equal status with no return-keystroke binding). The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke, and pressing this button is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).&lt;br /&gt;
: You will probably not need to configure the buttons explicitly in most cases. In dialogs with no &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are simply displaying messages to the user), the &amp;lt;code&amp;gt;BUTTONS {Ok} DEFAULT Ok&amp;lt;/code&amp;gt; configuration is assumed. In dialogs with one or more &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are asking the user for information), the &amp;lt;code&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel&amp;lt;/code&amp;gt; configuration is assumed.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TITLE &amp;lt;text&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This overrides the default dialog title &amp;quot;BCI2000&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;SPACING &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical spacing between successive &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; elements.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;WIDTH &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;HEIGHT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;LEFT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the horizontal coordinate of the dialog&#039;s left edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TOP &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical coordinate of the dialog&#039;s top edge, in pixels.&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12067</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12067"/>
		<updated>2025-08-28T20:29:38Z</updated>

		<summary type="html">&lt;p&gt;Jhill: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
=====CHOOSE ...=====&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CHOOSE&amp;lt;/code&amp;gt; family of commands prompt the user to specify file or directory paths, via the Qt graphical user interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILE&amp;lt;/code&amp;gt;  (or equivalently &amp;lt;code&amp;gt;CHOOSE FILE&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;CHOOSE INPUT&amp;lt;/code&amp;gt;) : Prompt the user to select a single existing file. Print the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE INPUT FILES&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE FILES&amp;lt;/code&amp;gt;) : Prompt the user to select one or more existing files. Print the resulting file paths.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE OUTPUT FILE&amp;lt;/code&amp;gt;  (or equivalently&amp;lt;code&amp;gt;CHOOSE OUTPUT&amp;lt;/code&amp;gt;) : Prompt the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists). Print the resulting file path.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt; : Prompt the user to specify a directory. Print the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
The commands may be followed by one or more of the following optional clauses (they must appear in this order):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[OF] TYPE[S] &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]&amp;lt;/code&amp;gt;&lt;br /&gt;
: Limit the choice, by default, to files that have the specified extension(s). This clause cannot be used with &amp;lt;code&amp;gt;CHOOSE DIRECTORY&amp;lt;/code&amp;gt;.  Instead of a file extension (starting with a dot) you can alternatively specify a glob pattern (containing a star).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[STARTING] AT &amp;lt;dir&amp;gt; ...]&amp;lt;/code&amp;gt; (or equivalently &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;FROM&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Specify where the dialog&#039;s file-system navigation should start (by default, it&lt;br /&gt;
will start in the current working directory).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;[WITH] PROMPT &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Specify the text prompt at the top of the dialog.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
choose file of type .dat from ../data/samplefiles with prompt &amp;quot;Choose a data file for playback:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose output file of type .prm in ../parms with prompt &amp;quot;Save parameters as...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
choose directory starting at ../data with prompt &amp;quot;Select a subject directory&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====CUSTOM DIALOG ...=====&lt;br /&gt;
&lt;br /&gt;
This command assembles a flexibly customizable modal dialog for communicating with the user. The command returns (prints) a string denoting which button the user pressed to complete the dialog, and as a side effect it may set any environment variables that the command specifies.  If the user cancels the dialog, the command does nothing (prints nothing, does not change any environment variables).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command can be followed by as many clauses as you like. The main types of clause are &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog, in the order you provide.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Each message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule. Simplest example: &amp;lt;pre&amp;gt;custom dialog message &amp;quot;Hello world!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. For example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used in conjunction with an empty first/default option, to force the user to make an explicit selection. For example: &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, will be the one that gets highlighted by default and bound to the enter/return keystroke. If you do not specify a default, then &amp;quot;Ok&amp;quot; will be assumed to be the default button; if the designated default does not appear in the list of buttons, the buttons will all have equal status with no return-keystroke binding). The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke, and pressing this button is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).&lt;br /&gt;
: You will probably not need to configure the buttons explicitly in most cases. In dialogs with no &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are simply displaying messages to the user), the &amp;lt;code&amp;gt;BUTTONS {Ok} DEFAULT Ok&amp;lt;/code&amp;gt; configuration is assumed. In dialogs with one or more &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses (where you are asking the user for information), the &amp;lt;code&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel&amp;lt;/code&amp;gt; configuration is assumed.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TITLE &amp;lt;text&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: This overrides the default dialog title &amp;quot;BCI2000&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;SPACING &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical spacing between successive &amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; elements.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;WIDTH &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;HEIGHT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the minimum width of the dialog in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;LEFT &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the horizontal coordinate of the dialog&#039;s left edge, in pixels.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;TOP &amp;lt;N&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Supply an integer value &amp;lt;code&amp;gt;N&amp;lt;/code&amp;gt; to specify the vertical coordinate of the dialog&#039;s top edge, in pixels.&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12066</id>
		<title>User Reference:Custom GUI Commands</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Custom_GUI_Commands&amp;diff=12066"/>
		<updated>2025-08-28T18:37:52Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* CUSTOM DIALOG [MESSAGE ] [VAR   {[]} ] [BUTTONS {}] ... */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;BCI2000&#039;s [[User_Reference:Operator_Module_Scripting|Operator Module Scripting]] capabilities include the ability to prompt the user for specific pieces of information via modal Qt dialogs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The expanded form of this documentation is still under construction. For now, here is the short summary:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=====CHOOSE [INPUT] FILE[S] [OF TYPE &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]] [STARTING AT &amp;lt;dir&amp;gt;] [WITH PROMPT &amp;lt;message&amp;gt;]=====&lt;br /&gt;
Via the Qt graphical user interface, prompt the user to select an existing file (or multiple files, if the keyword FILES is used). Print the resulting file path(s).&lt;br /&gt;
&lt;br /&gt;
=====CHOOSE [OUTPUT] FILE [OF TYPE &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]] [STARTING AT &amp;lt;dir&amp;gt;] [WITH PROMPT &amp;lt;message&amp;gt;]=====&lt;br /&gt;
Via the Qt graphical user interface, prompt the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists). Print the resulting file path.&lt;br /&gt;
&lt;br /&gt;
=====CHOOSE DIRECTORY [STARTING AT &amp;lt;dir&amp;gt;] [WITH PROMPT &amp;lt;message&amp;gt;]=====&lt;br /&gt;
Via the Qt graphical user interface, prompt the user to specify a directory. Print the resulting directory path.&lt;br /&gt;
&lt;br /&gt;
=====CUSTOM DIALOG [MESSAGE &amp;lt;msg&amp;gt;] [VAR &amp;lt;varname&amp;gt; &amp;lt;label&amp;gt; {[&amp;lt;options&amp;gt;]} ] [BUTTONS {&amp;lt;buttons&amp;gt;}] ... =====&lt;br /&gt;
Via the Qt graphical user interface, prompt the user with a modal dialog that can be flexibly customized.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; can be followed by as many clauses as you like. The main types of clause are&lt;br /&gt;
&amp;lt;code&amp;gt;MESSAGE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; clauses, which are rendered from top to bottom in the dialog,&lt;br /&gt;
in the order you provide.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;MESSAGE &amp;lt;msg&amp;gt;&amp;lt;/code&amp;gt; (e.g. &amp;lt;code&amp;gt;MESSAGE &amp;quot;Hello there!&amp;quot;&amp;lt;/code&amp;gt;)&lt;br /&gt;
: The message is rendered as text, word-wrapped to the width of the dialog window. &amp;lt;code&amp;gt;MESSAGE &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; can be used to create blank vertical space. Any message that consists only of dashes (e.g. &amp;lt;code&amp;gt;MESSAGE ---&amp;lt;/code&amp;gt;) will be turned into a horizontal rule.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {} [DEFAULT &amp;lt;defaultText&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This creates a text field that the user can fill in.  If you supply a &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, the specified default text is pre-filled. If you specify a &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; number of characters, the dialog buttons (except for the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) will be disabled until this text field contains at least that many characters. If the dialog is completed (by any button other than the designated &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt; button) then the environment variable designated by &amp;lt;code&amp;gt;&amp;lt;variableName&amp;gt;&amp;lt;/code&amp;gt; will be set to the contents of the text field. For example: &amp;lt;pre&amp;gt;custom dialog var subjectName &amp;quot;Subject Name:&amp;quot; {} default test minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;VAR &amp;lt;variableName&amp;gt; &amp;lt;visibleLabel&amp;gt; {&amp;lt;opt1&amp;gt;|&amp;lt;opt2&amp;gt;|...} [DEFAULT &amp;lt;defaultOption&amp;gt;] [MINIMUM &amp;lt;nChars&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This is almost the same as the text-field &amp;lt;code&amp;gt;VAR&amp;lt;/code&amp;gt; example above, except that the braces are not empty: the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;-delimited option labels inside the braces are then rendered as a drop-down menu with the specified limited set of options.  The &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt; subclause, if provided, determines which option is pre-selected (if it is omitted, or the &amp;lt;code&amp;gt;&amp;lt;defaultOption&amp;gt;&amp;lt;/code&amp;gt; does not match any of the options, then the first option is pre-selected).  The &amp;lt;code&amp;gt;MINIMUM&amp;lt;/code&amp;gt; subclause can be used in conjunction with an empty first/default option, to force the user to make an explicit selection. For example: &amp;lt;pre&amp;gt;custom dialog var runType &amp;quot;Run Type:&amp;quot; {|Calibration|Free Spelling} minimum 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;BUTTONS {&amp;lt;button1&amp;gt;|&amp;lt;button2&amp;gt;|...} [DEFAULT &amp;lt;defaultButton&amp;gt;] [ESCAPE &amp;lt;escapeButton&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
: This explicitly overrides the sequence of buttons at the bottom of the dialog. The button label designated as &amp;lt;code&amp;gt;DEFAULT&amp;lt;/code&amp;gt;, if any, is the one that is highlighted by default and bound to the enter/return keystroke (if you do not specify this, then &amp;quot;Ok&amp;quot; will be assumed to be the default button; if the designated default does not appear in the list of buttons, the buttons will all have equal status with no default and no return-keystroke binding). The button label designated as &amp;lt;code&amp;gt;ESCAPE&amp;lt;/code&amp;gt;, if any, is the one that is bound to the escape keystroke and is equivalent to closing the dialog without making a selection (the &amp;lt;code&amp;gt;CUSTOM DIALOG&amp;lt;/code&amp;gt; command will return the empty string in that case, and no environment variables will be touched).  You will probably not need to configure the buttons explicitly in most cases - the following configurations are assumed, if you do not explicitly override them: &amp;lt;pre&amp;gt;BUTTONS {cancel|Ok} DEFAULT Ok ESCAPE cancel # in cases where you are asking the user for information, i.e. you have at least one VAR&amp;lt;/pre&amp;gt;&amp;lt;pre&amp;gt;BUTTONS {Ok} DEFAULT Ok                      # in cases with no VAR clauses, where the dialog is just a message to the user&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Operator_Module_Scripting&amp;diff=12065</id>
		<title>User Reference:Operator Module Scripting</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Reference:Operator_Module_Scripting&amp;diff=12065"/>
		<updated>2025-08-28T17:59:22Z</updated>

		<summary type="html">&lt;p&gt;Jhill: /* Operator-module Commands for Soliciting Input from the User */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Operator scripts automate actions that the otherwise would be performed by the user, e.g. starting or suspending system operation.&lt;br /&gt;
Scripts may be contained in script files, or given immediately in the operator module&#039;s preferences dialog.&lt;br /&gt;
There is also an option to specify scripts from the [[User Reference:Module Command Line Options#Operator Module|command line]] when starting the operator module. When using the [[User_Reference:BCI2000Shell|BCI2000Shell]], or the [[Technical_Reference:Operator_Library|Operator Library]] from your own application, you may execute scripts at any time.&lt;br /&gt;
&lt;br /&gt;
In addition, the operator scripting language may be used to control an operator module over a [[User_Reference:Module_Command_Line_Options#--Telnet|Telnet]] or [[User_Reference:Module_Command_Line_Options#--WebSocket|WebSocket]] connection.&lt;br /&gt;
===Syntax===&lt;br /&gt;
&#039;&#039;&#039;Command separation.&#039;&#039;&#039; Scripts consist of sequences of the commands listed below. A command must be terminated with either a newline, or a semicolon (;).&lt;br /&gt;
This allows to put multiple commands into one line, separated by semicolon characters.&lt;br /&gt;
Commands are case-insensitive, variables and values may be case-sensitive, depending on context.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Comments.&#039;&#039;&#039; Lines starting with a &#039;#&#039; character are ignored. Such lines may be used to hold comments. In addition, when any of the first two lines of a script contains &amp;quot;#!&amp;quot; (the Unix shell invocation sequence), it will be ignored. In conjunction with [[User Reference:BCI2000Shell|BCI2000Shell]], this may be used to write Operator scripts that may be treated as executables.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Escaping.&#039;&#039;&#039; In order to resolve ambiguity about command arguments that contain white space, they must be included in double quotes, or the white space must be encoded in URL-fashion, e.g. &#039;&#039;%20&#039;&#039; instead of a space character. Similarly, when an argument contains a semicolon (;), it must be included in double quotes, or the semicolon must be encoded in URL-fashion, i.e. as &#039;&#039;%3B&#039;&#039;. Also, &amp;quot;$&amp;quot; characters indicate command substitution, so they should be encoded as &#039;&#039;%24&#039;&#039; if substitution is not desired.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Variable Substitution.&#039;&#039;&#039; When a command contains a dollar sign, alphanumeric characters following the dollar sign will be interpreted as the name of a variable: $NAME. The name will be matched against Expression variable names first, followed with Local variable names, and finally Environment variable names. When a match is found, $NAME will be replaced with the content of the matching variable. When no match is found, $NAME will be resolved to an empty string, without triggering an error.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Command Substitution.&#039;&#039;&#039; When part of a command is enclosed with ${...}, this subexpression will be substituted with the result of its execution as a command. E.g.,&lt;br /&gt;
 LOG &amp;quot;Current system state is: ${GET SYSTEM STATE}&amp;quot;&lt;br /&gt;
 LOG &amp;quot;The path environment variable is: ${PATH}&amp;quot;&lt;br /&gt;
Note that the last example uses the short form of the GET command, which will return the value of a PATH parameter or a PATH state if such exists. To make sure that only environment variables are matched, use the long form of the GET command:&lt;br /&gt;
 LOG MESSAGE &amp;quot;The path environment variable is: ${GET VARIABLE PATH}&amp;quot;&lt;br /&gt;
Substitutions may be nested, i.e. the following will work as expected:&lt;br /&gt;
 SET MyVar &amp;quot;LIST STATES&amp;quot;; LOG &amp;quot;States are: ${$MyVar}&amp;quot;&lt;br /&gt;
 SET MyVar &amp;quot;LIST STATES&amp;quot;; LOG &amp;quot;States are: ${${GET VARIABLE MyVar}}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Mathematical Expressions.&#039;&#039;&#039; A command may consist of a single [[User Reference:Expression Syntax|mathematical expression]]. This expression is then evaluated, and its result is returned as the command&#039;s result. As a special case, this allows the use of expression variables in ${...} substitutions. Consider for example&lt;br /&gt;
 x:=0; WHILE x&amp;lt;10; LOG ${x:=x+1}; END&lt;br /&gt;
There, the first command creates and initializes the expression variable x. In the WHILE condition, an expression is allowed as well as any command. In the LOG command, an expression appears in ${...}, which executes the expression in braces, and substitutes the result of the expression as an argument into the LOG command, which adds an entry to the Operator log. This results in a sequence of 10 log entries, containing the numbers from 1 to 10.&lt;br /&gt;
&lt;br /&gt;
===Commands===&lt;br /&gt;
====Control commands====&lt;br /&gt;
These commands allow conditional execution of parts of a script. When a condition is expected, any other scripting command may be given. Its result will be considered to represent a boolean value of &amp;quot;true&amp;quot; if it is empty, a nonzero number, or the string &amp;quot;true&amp;quot;. It will be taken to represent a boolean value of &amp;quot;false&amp;quot; if it contains a numeric value of zero, or any string that does not evaluate to a nonzero number. Note that identification of an empty value with &amp;quot;true&amp;quot; differs from string handling in the EVALUATE CONDITION command. This is because most scripting commands return nothing on success, but an error message on failure.&lt;br /&gt;
&lt;br /&gt;
The output of the SYSTEM and START EXECUTABLE commands is handled specially. There, the result code of the created child process is translated into a boolean value in the ordinary manner, treating a result code of zero as &amp;quot;true&amp;quot;, and any other result code as &amp;quot;false&amp;quot;. This allows to use external commands in the same way as in a native shell.&lt;br /&gt;
&lt;br /&gt;
=====IF &amp;lt;condition&amp;gt;; &amp;lt;if commands&amp;gt;; [ ELSEIF &amp;lt;condition&amp;gt;; &amp;lt;elseif commands&amp;gt;;] ... [ ELSE; &amp;lt;else commands&amp;gt;;] END=====&lt;br /&gt;
Executes &#039;&#039;if commands&#039;&#039; if &#039;&#039;condition&#039;&#039; evaluates to &amp;quot;true&amp;quot;. Otherwise, the &#039;&#039;elseif commands&#039;&#039; of the first matching &#039;&#039;elseif condition&#039;&#039; are executed. When none of the &#039;&#039;elseif conditions&#039;&#039; evaluates to &amp;quot;true&amp;quot;,  &#039;&#039;else commands&#039;&#039; are executed. ELSEIF and ELSE blocks may be omitted.&lt;br /&gt;
&lt;br /&gt;
=====WHILE &amp;lt;condition&amp;gt;; &amp;lt;loop commands&amp;gt;; END=====&lt;br /&gt;
Executes &#039;&#039;loop commands&#039;&#039; while &#039;&#039;condition&#039;&#039; evaluates to &#039;&#039;true&#039;&#039;.&lt;br /&gt;
=====DO; &amp;lt;loop commands&amp;gt;; UNTIL &amp;lt;condition&amp;gt;=====&lt;br /&gt;
Executes &#039;&#039;loop commands&#039;&#039; until &amp;quot;condition&amp;quot; evaluates to &#039;&#039;true&#039;&#039;.&lt;br /&gt;
=====FOR &amp;lt;name&amp;gt; IN &amp;lt;item1&amp;gt; &amp;lt;item2&amp;gt; ... ; &amp;lt;loop commands&amp;gt;; END=====&lt;br /&gt;
Creates a local variable with the specified name. Then, sequentially assigns each &#039;&#039;item&#039;&#039; to that variable, and executes &#039;&#039;loop commands&#039;&#039;. If an &#039;&#039;item&#039;&#039; contains newline characters, it is split up into multiple items, corresponding to the lines contained in the &#039;&#039;item&#039;&#039;. E.g.,&lt;br /&gt;
 FOR i IN top ${LIST FILES} bottom; LOG ${i}; END&lt;br /&gt;
will first write a log entry &amp;quot;top&amp;quot;. Then, it will create a log entry for each file in the current directory, and finally, it will create a log entry &amp;quot;bottom&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on Conditions====&lt;br /&gt;
=====EVALUATE CONDITION &amp;lt;left&amp;gt; [&amp;lt;op&amp;gt; [&amp;lt;right&amp;gt;]]=====&lt;br /&gt;
Evaluates a comparison between the &#039;&#039;left&#039;&#039; and &#039;&#039;right&#039;&#039; operands. As a comparison operator, the following may be specified: ==, !=, ~=, &amp;lt;, &amp;gt;, &amp;lt;=, &amp;gt;=. There, the != operator behaves identically to the ~= operator. When a test for equality is performed, the two operands are treated as strings, and compared in a case-insensitive manner. When any of the inequality tests is performed, the two operands are converted into floating-point numbers before comparison.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;right&#039;&#039; operand may be omitted, in which case it is treated as if an empty string were specified. Also, the &#039;&#039;op&#039;&#039; operator may be omitted, in which case the following rules apply regarding the remaining operand: If it is an empty string, or equal to the string &amp;quot;false&amp;quot; in case-insensitive comparison, the result is &amp;quot;false&amp;quot;. If entirely consists of the text representation of a floating-point number, the result is &amp;quot;false&amp;quot; if the number is 0, and &amp;quot;true&amp;quot; if the number is not 0.&lt;br /&gt;
&lt;br /&gt;
Inspired by the unix sh shells&#039; &amp;lt;tt&amp;gt;test&amp;lt;/tt&amp;gt; command, there exists a short form of the EVALUATE CONDITION command, where the arguments of EVALUATE CONDITION may appear within square brackets. This allows constructs such as&lt;br /&gt;
 IF [ ${MyVar} == MyValue ]; LOG Is equal; ELSE; LOG Is different; END&lt;br /&gt;
Note that the arguments to EVALUATE CONDITION must always be separated by white space, no matter whether its long or short form is used.&lt;br /&gt;
&lt;br /&gt;
Conditions may be combined logically using the operators &amp;amp;&amp;amp; and ||.   These go &#039;&#039;outside&#039;&#039; the square brackets.  Note also that whitespace around the comparison operators is critical, otherwise the conditional will be treated as a single string (which will always evaluate to &amp;quot;true&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
 IF [ ${foo} == foo ] || [ ${bar} == bar ]; LOG got a match; END&lt;br /&gt;
&lt;br /&gt;
====Commands operating on Local Variables====&lt;br /&gt;
Besides environment variables, there exist local variables in scripts. Local variables are inherited by sub-scripts executed with the EXECUTE SCRIPT command, but changes to the variable&#039;s values will not be propagated to the calling script.&lt;br /&gt;
=====SET VARIABLE &amp;lt;name&amp;gt; &amp;lt;value&amp;gt;=====&lt;br /&gt;
Sets the named variable to the specified value.&lt;br /&gt;
=====CLEAR VARIABLE &amp;lt;name&amp;gt;=====&lt;br /&gt;
Removes the named variable from memory.&lt;br /&gt;
=====GET VARIABLE &amp;lt;name&amp;gt;=====&lt;br /&gt;
Returns the variable&#039;s current value. When the variable does not exist, an empty value is returned rather than an error message.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on Environment Variables====&lt;br /&gt;
These scripting commands allow to read and modify environment variables. Changes to environment variables will be visible to child processes started with SYSTEM or START EXECUTABLE. Variable values are stored as strings. Variable names may not contain the equals sign.&lt;br /&gt;
=====SET ENVIRONMENT &amp;lt;name&amp;gt; &amp;lt;value&amp;gt;=====&lt;br /&gt;
Sets the named variable to the specified value.&lt;br /&gt;
=====CLEAR ENVIRONMENT &amp;lt;name&amp;gt;=====&lt;br /&gt;
Removes the named variable from memory.&lt;br /&gt;
=====GET ENVIRONMENT &amp;lt;name&amp;gt;=====&lt;br /&gt;
Returns the variable&#039;s current value. When the variable does not exist, an empty value is returned rather than an error message.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on Scripts====&lt;br /&gt;
=====SET SCRIPT &amp;lt;handler names&amp;gt; &amp;lt;scripting commands&amp;gt;=====&lt;br /&gt;
Associates a sequence of scripting commands with the named handler. Handlers are specified by names as given [[#Handlers|below]]. Multiple handlers may be specified by concatenating their names with a pipe character, e.g. &amp;quot;OnStart|OnResume&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Scripting commands must be included in double quotes, unless they consist of a single word.&lt;br /&gt;
When specifying a sequence of scripting commands, they must be separated with a semicolon character: &amp;quot;SetConfig; Start&amp;quot;. In order to use double quotes or semicolons within the commands themselves, encode these as you would in a URL, i.e. replace a double quote character with &#039;&#039;%22&#039;&#039;, and a semicolon with &#039;&#039;%3B&#039;&#039;: &amp;quot;Load Parameters %22my file%22&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
To use a script file rather than a literal script, use the EXECUTE SCRIPT command:&lt;br /&gt;
 SET SCRIPT OnConnect &amp;quot;EXECUTE SCRIPT myscript.txt&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=====GET SCRIPT &amp;lt;handler name&amp;gt;=====&lt;br /&gt;
Returns the script associated with the specified handler.&lt;br /&gt;
&lt;br /&gt;
=====CLEAR SCRIPT &amp;lt;handler names&amp;gt;=====&lt;br /&gt;
Clears scripts for the given handlers. Equivalent to calling SET SCRIPT with an empty script.&lt;br /&gt;
&lt;br /&gt;
=====EXECUTE SCRIPT &amp;lt;file or handler name&amp;gt; [&amp;lt;Arg1&amp;gt; &amp;lt;Arg2&amp;gt; ... &amp;lt;Arg9&amp;gt;]=====&lt;br /&gt;
Executes a script contained in a file, and optionally sets the script&#039;s local variables &#039;&#039;1&#039;&#039; to &#039;&#039;9&#039;&#039; to the specified values. To execute script commands already associated with a handler, provide a handler name rather than a file. When the script is executed successfully, the result of the last executed script command becomes the result of the EXECUTE SCRIPT command itself. Use &amp;quot;SET Result &amp;lt;value&amp;gt;&amp;quot; as the last command in a script in order to return a certain value.&lt;br /&gt;
&lt;br /&gt;
When you run a script through EXECUTE SCRIPT, it will inherit copies of variables from its calling script/command line. Variable changes will be local to the script, and will be lost when script execution is complete.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;AbortOnError&#039;&#039; variable determines whether a script is aborted when any of its commands result in an error message. &#039;&#039;AbortOnError&#039;&#039; is not inherited but defaults to 1 in any script.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on Parameters====&lt;br /&gt;
=====LOAD PARAMETERFILE &amp;lt;file&amp;gt;, LOAD PARAMETERS &amp;lt;file&amp;gt;=====&lt;br /&gt;
Loads a parameter file specified by its path and name. Relative paths are interpreted relative to the operator module&#039;s working directory at startup. Usually, this matches the executable&#039;s location in the &amp;lt;tt&amp;gt;prog&amp;lt;/tt&amp;gt; directory.&lt;br /&gt;
As the parameter file name must not contain white space, please use HTML-type encoding for white space characters, such as &amp;lt;tt&amp;gt;Documents%20and%20Settings&amp;lt;/tt&amp;gt; when referring to a user&#039;s &amp;quot;Documents and Settings&amp;quot; folder.&lt;br /&gt;
&lt;br /&gt;
NOTE: Only those parameters will be loaded that do exist at the time when this command is called. In idle state, no parameters exist other than created by ADD PARAMETER. After modules are connected and have published their parameters to the Operator module, a full set of parameters exist.&lt;br /&gt;
&lt;br /&gt;
=====ADD PARAMETER &amp;lt;parameter definition&amp;gt;=====&lt;br /&gt;
Adds a parameter to the system. The parameter is specified as a [[Technical_Reference:Parameter_Definition#Parameter_Lines|parameter line]]. This command may not be used after system initialization has completed, i.e. its use is restricted to the &amp;quot;Idle&amp;quot; and &amp;quot;Publishing&amp;quot; [[Technical_Reference:States_of_Operation#Publishing_Phase|phases of system operation]]. In terms of handlers, its use is restricted to the &#039;&#039;OnConnect&#039;&#039; handler.&lt;br /&gt;
=====EXISTS PARAMETER &amp;lt;name&amp;gt;=====&lt;br /&gt;
Returns &amp;quot;true&amp;quot; when the specified parameter exists in the system, and &amp;quot;false&amp;quot; otherwise.&lt;br /&gt;
&lt;br /&gt;
=====ISEMPTY PARAMETER &amp;lt;name&amp;gt;=====&lt;br /&gt;
Returns &amp;quot;true&amp;quot; when the specified parameter exists and has no values, &amp;quot;false&amp;quot; if it exists and has values.&lt;br /&gt;
&lt;br /&gt;
=====SET PARAMETER &amp;lt;name&amp;gt;[( idx1, idx2 )] &amp;lt;value&amp;gt;=====&lt;br /&gt;
Sets the named parameter to the specified value. Values that contain special characters, or whitespace must use the [[Technical_Reference:Parameter_Definition#Special_Characters|parameter value encoding]]. Use parentheses to specify indices or labels. Omitted indices default to 1.&lt;br /&gt;
&lt;br /&gt;
=====SET PARAMETER &amp;lt;parameter line&amp;gt;=====&lt;br /&gt;
Replace a parameter&#039;s value and definition with the information given in the [[Technical_Reference:Parameter_Definition#Parameter_Lines|parameter line]]. The parameter must exist in the system when this command is executed.&lt;br /&gt;
&lt;br /&gt;
=====GET PARAMETER &amp;lt;name&amp;gt;[( idx1, idx2 )]=====&lt;br /&gt;
Prints the value of the named parameter. Use parentheses to specify indices or labels.&lt;br /&gt;
&lt;br /&gt;
=====SET PARAMETERROWS &amp;lt;parameter name&amp;gt; &amp;lt;rows&amp;gt;=====&lt;br /&gt;
Sets the number of rows in the named parameter.&lt;br /&gt;
&lt;br /&gt;
=====GET PARAMETERROWS &amp;lt;parameter name&amp;gt;=====&lt;br /&gt;
Prints the number of rows in the named parameter.&lt;br /&gt;
&lt;br /&gt;
=====SET PARAMETERCOLS &amp;lt;parameter name&amp;gt;=====&lt;br /&gt;
Sets the number of columns in the named parameter.&lt;br /&gt;
&lt;br /&gt;
=====GET PARAMETERCOLS &amp;lt;parameter name&amp;gt;=====&lt;br /&gt;
Prints the number of columns in the named parameter.&lt;br /&gt;
&lt;br /&gt;
=====LIST PARAMETER &amp;lt;wildcard expression&amp;gt;, LIST PARAMETERS=====&lt;br /&gt;
Prints all parameters with names matching the wildcard expression, in form of parameter lines.&lt;br /&gt;
=====CLEAR PARAMETERS=====&lt;br /&gt;
Clears the list of parameters in the system. May only be executed in &#039;&#039;Idle&#039;&#039; and &#039;&#039;Publishing&#039;&#039; system states.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on States====&lt;br /&gt;
In BCI2000, there are three types of States that differ in their alignment to brain signal data (see [[Technical_Reference:State_Definition#Kinds_of_States|Kinds of States]]). This section applies to both Stream States, and normal States.&lt;br /&gt;
For Event States, see the next section.&lt;br /&gt;
&lt;br /&gt;
=====ADD STATE &amp;lt;name&amp;gt; &amp;lt;bit width&amp;gt; &amp;lt;initial value&amp;gt;=====&lt;br /&gt;
Adds a state variable to the system. State variables are defined by name, bit width, and initial value (see [[Technical Reference:State Definition]]). This command may not be used after system initialization has completed, i.e. its use is restricted to the &amp;quot;Idle&amp;quot; and &amp;quot;Publishing&amp;quot; [[Technical_Reference:States_of_Operation#Publishing_Phase|phases of system operation]]. In terms of handlers, its use is restricted to the &#039;&#039;OnConnect&#039;&#039; handler.&lt;br /&gt;
=====EXISTS STATE &amp;lt;name&amp;gt;=====&lt;br /&gt;
Returns &amp;quot;true&amp;quot; when the specified state exists in the system, and &amp;quot;false&amp;quot; otherwise.&lt;br /&gt;
&lt;br /&gt;
=====SET STATE &amp;lt;name&amp;gt; &amp;lt;value&amp;gt;, SET STATES &amp;lt;name1&amp;gt; &amp;lt;value1&amp;gt; &amp;lt;name2&amp;gt; &amp;lt;value2&amp;gt; ...=====&lt;br /&gt;
Sets the named state variable to the specified integer value by sending a state message to the source module.&lt;br /&gt;
Setting the &#039;&#039;Running&#039;&#039; state to 1 will start system operation, setting it to 0 will suspend the system.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;SET STATES&amp;lt;/tt&amp;gt; will atomically set the values of multiple states.&lt;br /&gt;
&lt;br /&gt;
=====GET STATE[(&amp;lt;sample&amp;gt;)] &amp;lt;name&amp;gt;=====&lt;br /&gt;
Gets the value of the named state. Note that state values are not updated from the application module when the &#039;&#039;OperatorBackLink&#039;&#039; parameter is 0. In that case, GET STATE will return the state&#039;s initial value.&lt;br /&gt;
&lt;br /&gt;
An optional one-based sample index may be given to indicate that the state value should be retrieved at the given sample position. Sample positions range from 1 to the number of samples per block present in the state vector. The number of samples per block may be retrieved using GET STATEVECTOR SAMPLES.&lt;br /&gt;
&lt;br /&gt;
By default, the state&#039;s value is retrieved for sample index 1.&lt;br /&gt;
&lt;br /&gt;
=====LIST STATE &amp;lt;wildcard expression&amp;gt;, LIST STATES=====&lt;br /&gt;
Lists all states, or states with names matching the given wildcard expression, in form of state lines.&lt;br /&gt;
=====CLEAR STATES=====&lt;br /&gt;
Clears the list of states in the system. May only be executed in &#039;&#039;Idle&#039;&#039; and &#039;&#039;Publishing&#039;&#039; system states.&lt;br /&gt;
&lt;br /&gt;
=====FREEZE STATES, THAW STATES=====&lt;br /&gt;
Freezes/thaws the values of all states in the state vector, without interfering with system operation.  &amp;quot;Freezing&amp;quot; creates, and &amp;quot;thawing&amp;quot; discards, a frozen snapshot of the state vector. For the duration of its existence, GET STATE calls will be diverted to the snapshot.  This is useful for ensuring that multiple GET STATE commands actually retrieve mutually-consistent values from different state variables (i.e. values from the same sample-block).&lt;br /&gt;
&lt;br /&gt;
=====GET STATEVECTOR SAMPLES=====&lt;br /&gt;
Returns the number of samples in the state vector per block of data. In the system&#039;s &amp;quot;Running&amp;quot; state, this matches the number of samples per block in the source data. Prior to the &amp;quot;Running&amp;quot; state, this is 1 because the state vector has not yet been updated from the application module.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on Events====&lt;br /&gt;
Events are a special type of state, which are recorded asynchronously, at single-sample resolution. Events may only be added while the system is in &amp;quot;idle&amp;quot; state. This kind of events is not related to [[#Handlers|Operator Events]] as defined below.&lt;br /&gt;
=====ADD EVENT &amp;lt;name&amp;gt; &amp;lt;bit width&amp;gt; &amp;lt;initial value&amp;gt;=====&lt;br /&gt;
Adds an event to the system. Like state variables, events are defined by name, bit width, and initial value (see [[Technical Reference:State Definition]]). This command may not be used after the system has started up, so it is typically executed within a telnet session before &#039;&#039;STARTUP&#039;&#039; has been called.&lt;br /&gt;
=====EXISTS EVENT &amp;lt;name&amp;gt;=====&lt;br /&gt;
Returns &amp;quot;true&amp;quot; when the specified event exists in the system, and &amp;quot;false&amp;quot; otherwise.&lt;br /&gt;
&lt;br /&gt;
=====SET EVENT &amp;lt;name&amp;gt; &amp;lt;value&amp;gt;=====&lt;br /&gt;
Asynchronously sets an event to the given value. Recording events requires the EventLink logger component to be present in the source module.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In versions prior to BCI2000 3.06, this command behaved as described for PULSE EVENT below, rather than as advertised. If you used SET EVENT in your scripts, it is recommended to replace it with PULSE EVENT in order to retain original behavior.&lt;br /&gt;
&lt;br /&gt;
=====PULSE EVENT &amp;lt;name&amp;gt; &amp;lt;value&amp;gt;=====&lt;br /&gt;
Asynchronously sets an event to the given value for a single sample duration. Recording events requires the EventLink logger component to be present in the source module.&lt;br /&gt;
&lt;br /&gt;
=====SET EVENTS [&amp;lt;name&amp;gt; &amp;lt;value&amp;gt;] [&amp;lt;name2&amp;gt; &amp;lt;value2&amp;gt;] ... =====&lt;br /&gt;
Asynchronously sets given events to their specified values. Using this command, rather than multiple SET EVENT commands in a row, ensures that all event changes are recorded at exactly the same point in time. Recording events requires the EventLink logger component to be present in the source module.&lt;br /&gt;
&lt;br /&gt;
=====PULSE EVENTS [&amp;lt;name&amp;gt; &amp;lt;value&amp;gt;] [&amp;lt;name2&amp;gt; &amp;lt;value2&amp;gt;] ... =====&lt;br /&gt;
Asynchronously sets given events to their specified values for a single sample duration. Using this command, rather than multiple PULSE EVENT commands in a row, ensures that all event changes are recorded at exactly the same point in time. Recording events requires the EventLink logger component to be present in the source module.&lt;br /&gt;
&lt;br /&gt;
=====GET EVENT[(&amp;lt;sample&amp;gt;)] &amp;lt;name&amp;gt;=====&lt;br /&gt;
Gets the value of the named event. Note that evemt values are not updated from the application module when the &#039;&#039;OperatorBackLink&#039;&#039; parameter is 0.&lt;br /&gt;
&lt;br /&gt;
An optional one-based sample index may be given to indicate that the event&#039;s value should be retrieved at the given sample position. Sample positions range from 1 to the number of samples per block present in the state vector. The number of samples per block may be retrieved using GET STATEVECTOR SAMPLES.&lt;br /&gt;
&lt;br /&gt;
By default, the event&#039;s value is retrieved for sample index 1.&lt;br /&gt;
&lt;br /&gt;
=====LIST EVENT &amp;lt;wildcard expression&amp;gt;, LIST EVENTS=====&lt;br /&gt;
Lists all events, or events with names matching the given wildcard expression, in form of state lines.&lt;br /&gt;
=====CLEAR EVENTS=====&lt;br /&gt;
Clears the list of events in the system. May only be executed in &#039;&#039;Idle&#039;&#039; state.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on VisProperties====&lt;br /&gt;
=====SET VISPROPERTY &amp;lt;visID&amp;gt;.&amp;lt;name&amp;gt; &amp;lt;value&amp;gt;=====&lt;br /&gt;
Sets the named [[Technical Reference:Visualization Properties|visualization property]] for the specified visualization ID to the given value. If the visualization ID contains a dot character, it must be encoded in [[Technical_Reference:Parameter_Definition#Special_Characters|parameter value encoding]]. E.g., setting the window width for the visualization ID &amp;quot;2.D1&amp;quot; would be written &amp;lt;code&amp;gt;SET VISPROPERTY 2%2ED1.Width 200&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=====RESET VISPROPERTY &amp;lt;visID&amp;gt;.&amp;lt;name&amp;gt;=====&lt;br /&gt;
Removes the named visualization property fro the specified visualization ID from the property store, effectively resetting its value to its default.&lt;br /&gt;
&lt;br /&gt;
=====GET VISPROPERTY &amp;lt;visID&amp;gt;.&amp;lt;name&amp;gt;=====&lt;br /&gt;
Prints the value of the named [[Technical Reference:Visualization Properties|visualization property]] for the specified visualization ID.&lt;br /&gt;
&lt;br /&gt;
=====SET VISPROPERTIES &amp;lt;property set ID&amp;gt;=====&lt;br /&gt;
Applies a set of visualization property values as given in the [[#VisPropertySets|VisPropertySets]] parameter. In that matrix-valued parameter, row labels specify visualization properties such as &amp;quot;SRCD.Left&amp;quot;, and columns represent sets of property values. Column labels are IDs of the corresponding property sets.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on the Control Signal====&lt;br /&gt;
=====GET SIGNAL( &amp;lt;channel index&amp;gt;, &amp;lt;element index&amp;gt; )=====&lt;br /&gt;
Prints the value of the control signal at the given indices. Indices are 1-based.&lt;br /&gt;
=====GET SIGNAL CHANNELS=====&lt;br /&gt;
Prints the number of channels in the control signal.&lt;br /&gt;
=====GET SIGNAL ELEMENTS=====&lt;br /&gt;
Prints the number of elements (samples) in the control signal.&lt;br /&gt;
=====FREEZE SIGNAL, THAW SIGNAL=====&lt;br /&gt;
Freezes/thaws the contents of the control signal, without interfering with system operation. &amp;quot;Freezing&amp;quot; creates, and &amp;quot;thawing&amp;quot; discards, a frozen snapshot of the control signal. For the duration of its existence, GET SIGNAL calls will be diverted to the snapshot. This is useful for ensuring that multiple GET SIGNAL commands actually retrieve mutually-consistent values from different elements in the control signal (i.e. values from the same sample-block).&lt;br /&gt;
&lt;br /&gt;
====Commands operating on Expressions====&lt;br /&gt;
=====EVALUATE EXPRESSION &amp;lt;expression&amp;gt;=====&lt;br /&gt;
This command treats the remainder of the command as a literal mathematical expression (for a description, see [[User Reference:Expression Syntax]]. An expression may contain variable assignments; such variables may then be used in later expressions. Note that expression variables are different from local and environment variables that may be accessed by GET/SET VARIABLE/ENVIRONMENT. Expression variables hold numerical values, while local and environment variables hold string values. Also, environment variables are accessible to child processes started with SYSTEM or START EXECUTABLE, while expression variables are accessible only to scripts. When a script is executed using the EXECUTE SCRIPT command, it will inherit a copy of all expression variables present. Changes to these variables from the executed script will not be visible in the parent script.&lt;br /&gt;
&lt;br /&gt;
=====CLEAR EXPRESSION VARIABLE &amp;lt;name&amp;gt;=====&lt;br /&gt;
Clears the named expression variable from storage.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on Watches====&lt;br /&gt;
A &amp;quot;Watch&amp;quot; is an object that consists of a set of expressions, and an action. Whenever the value of any of the expressions changes, the watch is &amp;quot;triggered&amp;quot;, and the action is executed. Watches allow client applications to respond to BCI2000 state changes in a reliable manner. Rather than polling information from BCI2000, a client may create a watch to be notified about changes of interest. This avoids the problem of missing short-lived changes, which is inherent in the polling approach.&lt;br /&gt;
&lt;br /&gt;
For watches created through operator scripting, the action consists of dumping values of all the expressions to a UDP port.&lt;br /&gt;
&lt;br /&gt;
The intended use of a watch from a client application is to create a separate thread that reads from the watch&#039;s UDP port in a blocking mode, and calls an appropriate handler function whenever it receives data.&lt;br /&gt;
The data sent will consist of a single UDP packet with a single line in ASCII format, terminated with a CRLF sequence. The line consists of tab-separated data fields, which contain the current values of the expressions specified when creating the watch. In addition, the first field contains a time stamp in the same time base as the &amp;lt;tt&amp;gt;SourceTime&amp;lt;/tt&amp;gt; state, wrapping around every 65536 ms. This time stamp represents the point in time where the expression value changed, with an accuracy of a single sample.&lt;br /&gt;
&lt;br /&gt;
=====ADD WATCH [decimate &amp;lt;n&amp;gt;] &amp;lt;expression1&amp;gt; &amp;lt;expression2&amp;gt; ... [AT &amp;lt;ip:port&amp;gt;]=====&lt;br /&gt;
Adds a watch for the listed expressions. Each expression&#039;s value will be reported in a separate field. When an address is specified in &amp;lt;tt&amp;gt;ip:port&amp;lt;/tt&amp;gt; format, the watch tries to open that port for output, and creation fails if that port is taken. Otherwise, a free port is chosen automatically. In both cases, successful creation of the watch is indicated by returning the output address in ASCII format. The address is also used to uniquely identify a watch in the context of a connection.&lt;br /&gt;
&lt;br /&gt;
When a &#039;&#039;decimate &amp;lt;n&amp;gt;&#039;&#039; clause is present, the watch will be created with decimation, i.e. it will only be evaluated for every &#039;&#039;n&#039;&#039;th&lt;br /&gt;
sample of the state vector.&lt;br /&gt;
&lt;br /&gt;
If a watch is created through a remote connection, it will use the remote host&#039;s external IP address for automatically chosen addresses. Otherwise, the output port will be associated with the machine&#039;s &amp;lt;tt&amp;gt;localhost&amp;lt;/tt&amp;gt; address.&lt;br /&gt;
&lt;br /&gt;
Watches may be created even if the system is currently running. In this case, the watch is triggered immediately, and sends its current expression values to its output port.&lt;br /&gt;
&lt;br /&gt;
=====ADD WATCH SYSTEM STATE [AT &amp;lt;address&amp;gt;]=====&lt;br /&gt;
Similar to the first variant of ADD WATCH, but will watch the system&#039;s state as reported by GET SYSTEM STATE.&lt;br /&gt;
&lt;br /&gt;
=====CLEAR WATCH &amp;lt;address&amp;gt;, CLEAR WATCHES [&amp;lt;wildcard-expression&amp;gt;]=====&lt;br /&gt;
Removes the watches specified by address, or those with their addresses matching a wildcard expression. If CLEAR WATCHES is called without argument, all watches will be deleted.&lt;br /&gt;
&lt;br /&gt;
=====TRIGGER WATCH &amp;lt;address&amp;gt;, TRIGGER WATCHES  [&amp;lt;wildcard-expression&amp;gt;]=====&lt;br /&gt;
Forces dumping of the watches&#039; current expression values to their output ports. Mostly useful for testing purposes.&lt;br /&gt;
&lt;br /&gt;
=====LIST WATCHES  [&amp;lt;wildcard-expression&amp;gt;]=====&lt;br /&gt;
Displays a list of existing watches, and their addresses.&lt;br /&gt;
&lt;br /&gt;
=====COUNT WATCHES  [&amp;lt;wildcard-expression&amp;gt;]=====&lt;br /&gt;
Returns the number of existing watches, or the number of watches whose addresses match the optional wildcard expression.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on Files, Directories, and Paths====&lt;br /&gt;
=====EXTRACT DIRECTORY &amp;lt;path&amp;gt;, EXTRACT FILE &amp;lt;path&amp;gt;, EXTRACT FILE BASE &amp;lt;path&amp;gt;=====&lt;br /&gt;
Extracts the directory or file portion of a given path. When the path specifies a non-existing directory, the directory name must be followed with a separator (&amp;quot;/&amp;quot;) in order to be recognized as a directory. The EXTRACT DIRECTORY command always returns its result with a trailing separator. The EXTRACT FILE BASE command returns the file portion without extension.&lt;br /&gt;
&lt;br /&gt;
=====IS DIRECTORY &amp;lt;path&amp;gt;, IS FILE &amp;lt;path&amp;gt;, IS PATH &amp;lt;path&amp;gt;=====&lt;br /&gt;
Determines whether the specified path points to an existing directory, file, or any of the two. The result is returned as one of the strings &amp;quot;true&amp;quot; or &amp;quot;false&amp;quot;.&lt;br /&gt;
=====PARENT DIRECTORY &amp;lt;path&amp;gt;=====&lt;br /&gt;
Returns the parent directory of the specified path, independently of whether the path points to a directory, or to a file.&lt;br /&gt;
=====CURRENT DIRECTORY=====&lt;br /&gt;
Returns the current working directory.&lt;br /&gt;
=====CHANGE DIRECTORY &amp;lt;path&amp;gt;=====&lt;br /&gt;
Changes the working directory.&lt;br /&gt;
=====MAKE DIRECTORY &amp;lt;path&amp;gt;=====&lt;br /&gt;
Creates a new directory with the given path. The directory&#039;s parent must exist for the command to succeed.&lt;br /&gt;
=====LIST DIRECTORY [&amp;lt;path&amp;gt; or &amp;lt;wildcard expression&amp;gt;]=====&lt;br /&gt;
Returns a listing of the specified directory, or the current working directory if no path is specified. The listing is in long form. You may use wildcard expressions in order to restrict the output.&lt;br /&gt;
=====LIST FILE &amp;lt;wildcard expression&amp;gt;=====&lt;br /&gt;
Returns a list of file names matching &#039;&#039;wildcard expression&#039;&#039; in the current directory.&lt;br /&gt;
=====LIST FILES [&amp;lt;directory&amp;gt; [&amp;lt;wildcard expression&amp;gt;]]=====&lt;br /&gt;
Returns a list of file names from the specified directory, matching &#039;&#039;wildcard expression&#039;&#039;. When &#039;&#039;wildcard expression&#039;&#039; is missing, all files are listed. When &#039;&#039;directory&#039;&#039; is missing, files in the current directory are listed.&lt;br /&gt;
=====LIST DIRECTORIES [&amp;lt;directory&amp;gt; [&amp;lt;wildcard expression&amp;gt;]]=====&lt;br /&gt;
Returns a list of directory names from the specified directory, matching &#039;&#039;wildcard expression&#039;&#039;. When &#039;&#039;wildcard expression&#039;&#039; is missing, all directories are listed. When &#039;&#039;directory&#039;&#039; is missing, directories in the current directory are listed.&lt;br /&gt;
&lt;br /&gt;
=====RENAME FILE &amp;lt;current path&amp;gt; &amp;lt;new path&amp;gt;, RENAME DIRECTORY &amp;lt;current path&amp;gt; &amp;lt;new name&amp;gt;=====&lt;br /&gt;
Renames a file resp. a directory. For files, a different path may be given in the second argument, resulting in that the file is moved to the location specified by the new path. For directories, the path up to the directory&#039;s name must stay the same.&lt;br /&gt;
=====REMOVE FILE &amp;lt;path&amp;gt;, REMOVE DIRECTORY &amp;lt;path&amp;gt;=====&lt;br /&gt;
Removes the specified file or directory. This command cannot be undone. The directory must be empty for the command to succeed.&lt;br /&gt;
=====FORCEREMOVE DIRECTORY &amp;lt;path&amp;gt;=====&lt;br /&gt;
Removes the specified directory and its contents. Symbolic links are treated as ordinary files, i.e. they are not followed. This command cannot be undone.&lt;br /&gt;
=====NORMALIZED PATH &amp;lt;path&amp;gt;=====&lt;br /&gt;
Returns &amp;lt;path&amp;gt;, with the following transformations applied:&lt;br /&gt;
*Removes relative elements (&amp;lt;tt&amp;gt;..&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;.&amp;lt;/tt&amp;gt;) as far as possible. For absolute paths, the result will not contain any relative elements; for relative paths, double-dots may appear at the beginning of the result if necessary.&lt;br /&gt;
If a relative path simplifies to the empty string, &amp;lt;tt&amp;gt;./&amp;lt;/tt&amp;gt; is returned. Thus, the result of NORMALIZED PATH is never empty, unless its input was empty.&lt;br /&gt;
*Replaces backward slashes with forward slashes to achieve uniformity across platforms.&lt;br /&gt;
*On case-insensitive file systems, replaces the spelling of names with the one stored in the file system.&lt;br /&gt;
*On Win32, replaces short (8.3) names with long ones.&lt;br /&gt;
&lt;br /&gt;
=====CANONICAL PATH &amp;lt;path&amp;gt;=====&lt;br /&gt;
If &amp;lt;path&amp;gt; points to an existing file or directory, CANONICAL PATH returns a valid absolute file path, suitable as an unambiguous representation for the object pointed to. Especially, two non-empty canonical path strings will compare equal if and only if they refer to the same file system object.&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;path&amp;gt; does not point to an existing file system object, construction of a canonical path is not possible due to lack of information about the named object, and CANONICAL PATH will return an empty string.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTES:&#039;&#039;&#039; The need for an unambiguous, or canonical, representation arises due to ambiguities in the string representation of paths, and in file systems themselves.&lt;br /&gt;
*Paths may contain relative elements: &amp;lt;tt&amp;gt;/mydir/../myfile&amp;lt;/tt&amp;gt; points to the same object as &amp;lt;tt&amp;gt;/myfile&amp;lt;/tt&amp;gt;.&lt;br /&gt;
*A path that involves symbolic links will point to the same object as a path containing one or more of those links in resolved form.&lt;br /&gt;
*File systems may be case-insensitive, or may even provide multiple distinct names for individual directory entries (Win32 short vs. long names).&lt;br /&gt;
&lt;br /&gt;
On &#039;&#039;&#039;Win32,&#039;&#039;&#039; CANONICAL PATH returns the short (8.3) representation of a path, using uppercase spelling, and backslashes as directory separators. Apart from efficiency considerations, this aesthetically unpleasing representation has been chosen to discourage its use for anything except comparing file system objects.&lt;br /&gt;
&lt;br /&gt;
On &#039;&#039;&#039;other systems,&#039;&#039;&#039; CANONICAL PATH will return the result of the POSIX &amp;lt;tt&amp;gt;realpath()&amp;lt;/tt&amp;gt; function.&lt;br /&gt;
&lt;br /&gt;
In both cases, a CANONICAL PATH will end with a native directory separator if, and only if, the object pointed to is a directory.&lt;br /&gt;
&lt;br /&gt;
=====REAL PATH &amp;lt;path&amp;gt;=====&lt;br /&gt;
On this command provides a work-alike for the POSIX &amp;lt;tt&amp;gt;realpath()&amp;lt;/tt&amp;gt; function.&lt;br /&gt;
If &amp;lt;path&amp;gt; is empty, or if &amp;lt;path&amp;gt; points to a non-existing object, the result will be empty. Otherwise, an absolute path will be returned, with symbolic links resolved, using forward slashes as directory separators, and with spelling normalized as described for NORMALIZED PATH. A forward slash will be appended if the path points to a directory.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; In principle, the path returned by REAL PATH should be just as unambiguous as the result of CANONICAL PATH. However, there are a few caveats:&lt;br /&gt;
* On case-insensitive file systems, two independently obtained results of REAL PATH might differ in case spelling even if referring to the same file system object. This should not be the case for CANONICAL PATH.&lt;br /&gt;
* Determining the result of CANONICAL PATH is a fast operation. In contrast, REAL PATH may be expensive to determine, as for each directory on the path a listing needs to be obtained, and a canonical path needs to be formed, and compared, for half of the listed directory entries on average.&lt;br /&gt;
* On Win32, quite some amount of complexity arises from backward compatibility layers, forbidden file names, multiple filesystem roots, etc. Internally calling &amp;lt;tt&amp;gt;GetShortPathName()&amp;lt;/tt&amp;gt;, CANONICAL PATH does not need to handle that complexity, and may be considered more reliable for identifying file system objects than REAL PATH.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on executables====&lt;br /&gt;
=====START EXECUTABLE &amp;lt;command line&amp;gt;=====&lt;br /&gt;
Behaves identically to CREATE PROCESS, except that it does not report a process id for the new process. For details, see CREATE PROCESS.&lt;br /&gt;
&lt;br /&gt;
=====CATEGORIZE EXECUTABLE &amp;lt;name or path&amp;gt;=====&lt;br /&gt;
BCI2000 keeps a list of executables/modules that have been built, and sorts them into categories. The CATEGORIZE EXECUTABLE command provides a way to retrieve that information. Given the name or path of an executable, it outputs one of the following categories:&lt;br /&gt;
* SignalSource,&lt;br /&gt;
* SignalProcessing,&lt;br /&gt;
* Application,&lt;br /&gt;
* Operator,&lt;br /&gt;
* Tool,&lt;br /&gt;
* Helper,&lt;br /&gt;
* Unknown.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on Lines of input/output====&lt;br /&gt;
=====WRITE LINE &amp;lt;line&amp;gt;=====&lt;br /&gt;
Writes a line of output. Destination depends on the context in which a script is executed. If the context is an Operator Handler, output is written as a log entry. If the context is a telnet session, output is written to the telnet connection. If the context is a [[User Reference:BCI2000Shell|BCI2000Shell]], output is written to the shell&#039;s stdout.&lt;br /&gt;
&lt;br /&gt;
=====READ LINE=====&lt;br /&gt;
Reads a line of input from the current execution context&#039;s input. If the command is executed within an Operator Handler, it will fail. If executed within a telnet session, the other side of the connection is prompted for input. If executed from within a [[User Reference:BCI2000Shell|BCI2000Shell]], input is read from the shell&#039;s stdin.&lt;br /&gt;
&lt;br /&gt;
====Commands operating on Processes in the Operating System====&lt;br /&gt;
=====CREATE PROCESS &amp;lt;command line&amp;gt;=====&lt;br /&gt;
Starts the specified executable with options. This command returns after the started program has finished initialization, i.e. it will detect load time failures such as missing DLLs on Windows. If the process is still running when CREATE PROCESS returns, its result will be an operating system process id (pid). If the process has terminated, CREATE PROCESS will report its exit code marked with an &amp;lt;tt&amp;gt;ExitCode&amp;lt;/tt&amp;gt; tag to allow distinction between a pid and an exit code.&lt;br /&gt;
Please note that CREATE PROCESS requires quoting of arguments differently from other scripting commands. For details, see the SYSTEM command.&lt;br /&gt;
&lt;br /&gt;
=====TERMINATE PROCESS &amp;lt;pid&amp;gt;=====&lt;br /&gt;
Tries to terminate the process with the given operating system pid, waiting for the process to terminate before returning. Will return &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt; to indicate that a suitable process existed but could not be terminated.&lt;br /&gt;
&lt;br /&gt;
=====WAIT FOR PROCESS &amp;lt;pid&amp;gt; [&amp;lt;timeout seconds&amp;gt; = infinite]=====&lt;br /&gt;
Waits for the process with the given operating system pid to terminate, or the timeout to expire. Returns &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt; to indicate that the process is still executing.&lt;br /&gt;
&lt;br /&gt;
=====SHOW PROCESS &amp;lt;pid&amp;gt;=====&lt;br /&gt;
Makes all windows visible which are associated with the process referred to by pid.&lt;br /&gt;
In addition, brings one of the process&#039; top level (desktop level) windows to the front for user interaction.&lt;br /&gt;
&lt;br /&gt;
=====HIDE PROCESS &amp;lt;pid&amp;gt;=====&lt;br /&gt;
Makes all windows invisible which are associated with the process referred to by pid.&lt;br /&gt;
&lt;br /&gt;
====Global commands====&lt;br /&gt;
=====HELP [&amp;lt;type&amp;gt;]=====&lt;br /&gt;
When called with a type argument, lists commands that exist for the specified type (e.g., SYSTEM, or FILE). When called without argument, lists all commands in their main form. HELP ALL will list all commands, including synonyms.&lt;br /&gt;
&lt;br /&gt;
=====SET &amp;lt;name&amp;gt; &amp;lt;value&amp;gt;, GET &amp;lt;name&amp;gt;, &amp;lt;name&amp;gt;=====&lt;br /&gt;
Allows to set or retrieve the value of local and environment variables. The name is matched against local and environment variables. When no variable with the given name is found, SET will create a local variable, while GET will result in an error. GET may be further abbreviated to only consist of a name.&lt;br /&gt;
&lt;br /&gt;
GET further allows evaluation of [[User_Reference:Expression_Syntax|mathematical expressions]]. When the expression is invalid, or contains an unknown variable, an error is triggered.&lt;br /&gt;
&lt;br /&gt;
=====GET SYSTEM STATE=====&lt;br /&gt;
Prints the current system state. This will be one of Unavailable, Idle, Startup, Initialization, Resting, Suspended, ParamsModified, Running, Termination, Busy.&lt;br /&gt;
&lt;br /&gt;
=====GET CURRENT RUN FILE=====&lt;br /&gt;
Prints the full path to the current run file, or an empty string, if called outside Running state.&lt;br /&gt;
&lt;br /&gt;
=====WAIT FOR &amp;lt;system state&amp;gt; [&amp;lt;timeout seconds&amp;gt;]=====&lt;br /&gt;
Waits until the system is in the specified state. This may be one of Idle, Startup, Connected, Resting, Suspended, ParamsModified, Running, Busy, or a combination of these, separated with a pipe character: &amp;quot;Resting|Suspended&amp;quot;. When no timeout is given, this command waits indefinitely. If the wait is successful, i.e. system state matches one of the specified states, WAIT FOR will return a value of &amp;quot;true&amp;quot;. If timeout occurred, WAIT FOR will return &amp;quot;false&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
If the BCI2000 system is shut down while a script is executing a WAIT FOR command, the script will be terminated with a &amp;quot;wait aborted&amp;quot; error message.&lt;br /&gt;
&lt;br /&gt;
In more detail, user visible states are:&lt;br /&gt;
* Idle: System is shut down and does not do other processing than executing scripts.&lt;br /&gt;
* Startup: System has started up and is listening for incoming connections.&lt;br /&gt;
* Connected: All core modules have connected to the system.&lt;br /&gt;
* Resting: The system has been initialized but is not running.&lt;br /&gt;
* Suspended: The system has ended running and is behaving like in Resting.&lt;br /&gt;
* ParamsModified: In Suspended mode, parameter changes have been published and will be applied at Resume.&lt;br /&gt;
* Running: The system is running, processing brain signals, and displaying stimuli.&lt;br /&gt;
* Busy: The system is performing a transition from one state to another.&lt;br /&gt;
&lt;br /&gt;
As a synonym for &amp;quot;Connected,&amp;quot; &amp;quot;Initialization&amp;quot; is valid as well since it is compatible with the nomenclature in StateMachine.h. Still, it should be avoided because it is easily confused with, but very distinct from, the actions performed in the Initialize() phase.&lt;br /&gt;
&lt;br /&gt;
=====SLEEP &amp;amp;lt;time in seconds&amp;amp;gt;=====&lt;br /&gt;
Waits (sleeps) for the given amount of time. Timing resolution is 50ms. Tends to sleep a little longer than specified, with the error growing with duration.&lt;br /&gt;
&lt;br /&gt;
=====GET SYSTEM VERSION=====&lt;br /&gt;
Prints BCI2000 version information.&lt;br /&gt;
=====SETCONFIG, SET CONFIG=====&lt;br /&gt;
Applies current parameters to the system. Corresponds to the &#039;&#039;SetConfig&#039;&#039; button in the GUI version of the Operator module.&lt;br /&gt;
&lt;br /&gt;
=====START=====&lt;br /&gt;
Starts or resumes system operation, corresponding to the &#039;&#039;Start/Resume&#039;&#039; button in the GUI version of the Operator module.&lt;br /&gt;
=====STOP=====&lt;br /&gt;
Stops system operation. Corresponds to the &#039;&#039;Stop&#039;&#039; button in the GUI version of the Operator.&lt;br /&gt;
=====STARTUP SYSTEM=====&lt;br /&gt;
When in idle state, starts up the system to wait for incoming connections from core modules. Additionally, the following arguments may be given: 1) an IP address on which to listen (default is to listen on all addresses), and 2) a list of generic core module names with ports. The default configuration corresponds to these arguments:&lt;br /&gt;
 STARTUP SYSTEM * SignalSource:4000 SignalProcessing:4001 Application:4002&lt;br /&gt;
&lt;br /&gt;
A system log file may optionally be specified on this line, by inserting the &amp;lt;code&amp;gt;--SystemLogFile&amp;lt;/code&amp;gt; flag between the IP address and the module specifiers. For example:&lt;br /&gt;
&lt;br /&gt;
 STARTUP SYSTEM * --SystemLogFile=SOME_FILE.TXT SignalSource:4000 SignalProcessing:4001 Application:4002&lt;br /&gt;
&lt;br /&gt;
The system log file will record all operator log window messages for the current launch, until the system shuts down.  It may be helpful to use the variables &amp;lt;code&amp;gt;$YYYYMMDD&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;$HHMMSS&amp;lt;/code&amp;gt; to specify the filename.  Note that file name and path cannot contain spaces.&lt;br /&gt;
&lt;br /&gt;
=====SHUTDOWN SYSTEM=====&lt;br /&gt;
Shuts down core modules, and enters idle system state.&lt;br /&gt;
=====RESET SYSTEM=====&lt;br /&gt;
Shuts down the system, and clears all parameter, state, and event information.&lt;br /&gt;
&lt;br /&gt;
=====QUIT, EXIT [&amp;lt;result&amp;gt;]=====&lt;br /&gt;
Quits the operator module after terminating all BCI2000 modules. The optional &#039;&#039;result&#039;&#039; argument determines the result of the executed script.&lt;br /&gt;
&lt;br /&gt;
=====CLOSE CONNECTION, TERMINATE CONNECTION=====&lt;br /&gt;
In the context of a telnet or websocket connection, this command will terminate the connection.&lt;br /&gt;
In other contexts, such as event handlers, it will be ignored.&lt;br /&gt;
&lt;br /&gt;
=====SYSTEM &amp;lt;command line&amp;gt;=====&lt;br /&gt;
Executes a shell command, redirecting any console output into the command&#039;s script result. E.g., to obtain a directory listing, under Windows, you would enter&lt;br /&gt;
 SYSTEM DIR&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Arguments to the SYSTEM command are executed by the operating system&#039;s shell, and thus may require quoting different from the other scripting commands. E.g., writing&lt;br /&gt;
 SET mydir ${PARENT DIRECTORY $BCI2000LAUNCHDIR}; ECHO ${LIST FILES $mydir}&lt;br /&gt;
will list files in the BCI2000 main directory, independently of whether the path to that directory contains space characters or not. However, to obtain a directory listing through the SYSTEM command, you would need to write&lt;br /&gt;
 ECHO ${SYSTEM DIR &amp;quot;$mydir&amp;quot;}&lt;br /&gt;
to make sure the content of the variable &#039;&#039;mydir&#039;&#039; is interpreted as a single argument, independently of whether it contains space characters.&lt;br /&gt;
&lt;br /&gt;
=====LOG &amp;lt;message&amp;gt;=====&lt;br /&gt;
Append the specified message to the system log.&lt;br /&gt;
=====WARN &amp;lt;message&amp;gt;=====&lt;br /&gt;
Append the specified message to the system log, formatted as a warning.&lt;br /&gt;
=====ERROR &amp;lt;message&amp;gt;=====&lt;br /&gt;
Append the specified message to the system log, formatted as an error message.&lt;br /&gt;
&lt;br /&gt;
=====CAPTURE MESSAGES &amp;lt;message types&amp;gt;=====&lt;br /&gt;
Captures system log messages into a background buffer. When no message type is given, all messages are captured. When &amp;quot;None&amp;quot; is given as a message type, message capturing is disabled. Otherwise, the message type must be one of &amp;quot;Errors&amp;quot;, &amp;quot;Warnings&amp;quot;, &amp;quot;Debug&amp;quot;, &amp;quot;Log&amp;quot;. Multiple message types may be specified in a single command. When &amp;quot;None&amp;quot; appears within a single command, all preceding message types are ignored. Multiple CAPTURE MESSAGES commands are cumulative, except when &amp;quot;None&amp;quot; is specified as a message type.&lt;br /&gt;
&lt;br /&gt;
=====FLUSH MESSAGES=====&lt;br /&gt;
Clears the background message buffer, and returns its previous content. Use CAPTURE MESSAGES to capture messages into the background message buffer.&lt;br /&gt;
&lt;br /&gt;
====Operator-module defined Commands====&lt;br /&gt;
=====HIDE WINDOW [&amp;lt;name&amp;gt;], SHOW WINDOW [&amp;lt;name&amp;gt;]=====&lt;br /&gt;
Hides or shows the specified window. When called without a window name, the Operator module&#039;s main window is hidden or shown. The window name may be one of Main, Configuration, Log, Watches, and Visualizations. When &amp;quot;Watches&amp;quot; is given, the window state refers to visibility of the Watches area in the Visualizations window.&lt;br /&gt;
&lt;br /&gt;
=====MOVE WINDOW &amp;lt;name&amp;gt; &amp;lt;x&amp;gt; &amp;lt;y&amp;gt;, RESIZE WINDOW &amp;lt;name&amp;gt; &amp;lt;width&amp;gt; &amp;lt;height&amp;gt;=====&lt;br /&gt;
Moves resp. resizes the specified window with one of the above names.&lt;br /&gt;
Window decorations (title bar, frame) are taken into consideration such that the total size of the window matches the given width and height.&lt;br /&gt;
&lt;br /&gt;
=====ARRANGE WINDOW &amp;lt;name&amp;gt; &amp;lt;rows&amp;gt; &amp;lt;cols&amp;gt; &amp;lt;row&amp;gt; &amp;lt;col&amp;gt; [&amp;lt;rowspan&amp;gt; &amp;lt;colspan&amp;gt;]=====&lt;br /&gt;
Arranges the named window in a virtual &#039;&#039;rows&#039;&#039; x &#039;&#039;cols&#039;&#039; grid at grid position &#039;&#039;row, col&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Optional &#039;&#039;rowspan&#039;&#039; and &#039;&#039;colspan&#039;&#039; arguments may be given to specify the extension of the window across more than one row or column. &lt;br /&gt;
Using a &#039;&#039;rowspan&#039;&#039; of 0 will result in the window assuming its minimum height.&lt;br /&gt;
Likewise, a &#039;&#039;colspan&#039;&#039; of 0 will result in the window&#039;s minimum width.&lt;br /&gt;
&lt;br /&gt;
If multiple screens are present, windows are arranged on the screen that contains the Operator window.&lt;br /&gt;
&lt;br /&gt;
=====SET TITLE &amp;lt;title&amp;gt;=====&lt;br /&gt;
Sets the title of the main Operator window.&lt;br /&gt;
=====SET BUTTON &amp;lt;idx&amp;gt; &amp;lt;label&amp;gt; &amp;lt;commands&amp;gt;=====&lt;br /&gt;
Configures the function button with 1-based index &#039;&#039;idx&#039;&#039; such that it is labelled &#039;&#039;label&#039;&#039; and executes &#039;&#039;commands&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=====VISUALIZE WATCH [decimate &amp;lt;n&amp;gt;] [range &amp;lt;min&amp;gt; &amp;lt;max&amp;gt;] &amp;lt;expression1&amp;gt; ...=====&lt;br /&gt;
Adds a watch for the given expressions to the operator module&#039;s Watches window, and makes the Watches window visible if it is hidden. If the &#039;&#039;decimate&#039;&#039; clause is present, the command will create a watch which will be evaluated only for every &#039;&#039;n&#039;&#039;th sample in the state vector. If the &#039;&#039;range&#039;&#039; clause is present, display minimum and maximum will not be adjusted automatically but will be fixed to the values given.&lt;br /&gt;
&lt;br /&gt;
By default, &#039;&#039;decimate&#039;&#039; has a value of &amp;quot;auto&amp;quot;; this means that there is no decimation of evaluation (i.e., all samples are evaluated) but changes that occur within 1ms will be shortened into their maximum and minimum, and thus reported as only two values.&lt;br /&gt;
This has proven to be efficient for avoiding sluggishness from flooding the application with events.&lt;br /&gt;
&lt;br /&gt;
=====MOVE VISUALIZATON &amp;lt;visID&amp;gt; &amp;lt;x&amp;gt; &amp;lt;y&amp;gt;, RESIZE VISUALIZATION &amp;lt;visID&amp;gt; &amp;lt;width&amp;gt; &amp;lt;height&amp;gt;=====&lt;br /&gt;
Moves resp. resizes the specified visualization window.&lt;br /&gt;
Window decorations (title bar, frame) are taken into consideration such that the total size of the window matches the given width and height. If unknown, visualization IDs may be obtained from the Operator&#039;s &#039;&#039;Window-&amp;gt;Visualizations&#039;&#039; menu.&lt;br /&gt;
&lt;br /&gt;
=====ARRANGE VISUALIZATION &amp;lt;visID&amp;gt; &amp;lt;rows&amp;gt; &amp;lt;cols&amp;gt; &amp;lt;row&amp;gt; &amp;lt;col&amp;gt; [&amp;lt;rowspan&amp;gt; &amp;lt;colspan&amp;gt;]=====&lt;br /&gt;
Arranges the named visualization window in a virtual &#039;&#039;rows&#039;&#039; x &#039;&#039;cols&#039;&#039; grid at grid position &#039;&#039;row, col&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Optional &#039;&#039;rowspan&#039;&#039; and &#039;&#039;colspan&#039;&#039; arguments may be given to specify the extension of the window across more than one row or column. &lt;br /&gt;
Using a &#039;&#039;rowspan&#039;&#039; of 0 will result in the window assuming its minimum height.&lt;br /&gt;
Likewise, a &#039;&#039;colspan&#039;&#039; of 0 will result in the window&#039;s minimum width.&lt;br /&gt;
&lt;br /&gt;
If multiple screens are present, windows are arranged on the screen that contains the Operator window.&lt;br /&gt;
&lt;br /&gt;
=====RECORD VISUALIZATION &amp;lt;visID&amp;gt; [on|off]=====&lt;br /&gt;
Registers the named visualization for recording. The visualization name must be the short name as displayed in the &#039;&#039;View-&amp;gt;Visualizations&#039;&#039; menu. Switching a visualization recording to &amp;quot;on&amp;quot; is only possible in idle state (because an event for recording frame numbers must be registered in the system). When a visualization is registered for recording, its frames are stored immediately as they arrive at the operator module. Currently, only bitmap visualizations may be recorded.&lt;br /&gt;
&lt;br /&gt;
Example: Recording the application window&lt;br /&gt;
 RECORD VISUALIZATION ApplicationWindow on&lt;br /&gt;
 ...&lt;br /&gt;
 # after parameters have been loaded&lt;br /&gt;
 Set parameter VisualizeApplicationWindow 1&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
=====PUT NOTE &amp;lt;note&amp;gt;=====&lt;br /&gt;
Adds the given text to the [[User_Reference:Operator_Notes#Taking_Notes_during_recording_in_Operator|notes window]].&lt;br /&gt;
If the system is in &#039;&#039;Running&#039;&#039; state, the text will also be added to the current notes file as described under&lt;br /&gt;
[[User_Reference:Operator_Notes#Note_storage_and_file_format|&amp;quot;notes file&amp;quot;]].&lt;br /&gt;
&lt;br /&gt;
=====START TELNET &amp;lt;address&amp;gt;, STOP TELNET &amp;lt;address&amp;gt;=====&lt;br /&gt;
Starts or stops a telnet server listening at the given address. The address is in &amp;lt;IP&amp;gt;:&amp;lt;port&amp;gt; format.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IMPORTANT:&#039;&#039;&#039; You should not use this command on global internet addresses, as there is no authentication performed.&lt;br /&gt;
&lt;br /&gt;
=====START WEBSOCKET &amp;lt;address&amp;gt;, STOP WEBSOCKET &amp;lt;address&amp;gt;=====&lt;br /&gt;
Starts or stops a websocket server listening at the given address. The address is in &amp;lt;IP&amp;gt;:&amp;lt;port&amp;gt; format.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IMPORTANT:&#039;&#039;&#039; You should not use this command on global internet addresses, as there is no authentication performed.&lt;br /&gt;
&lt;br /&gt;
====Operator-module Commands for Soliciting Input from the User====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=====CHOOSE [INPUT] FILE[S] [OF TYPE &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]] [STARTING AT &amp;lt;dir&amp;gt;] [WITH PROMPT &amp;lt;message&amp;gt;]=====&lt;br /&gt;
Via the Qt graphical user interface, prompt the user to select an existing file (or multiple files, if the keyword FILES is used). Print the resulting file path(s).&lt;br /&gt;
(See the [[User_Reference:Custom_GUI_Commands|Custom GUI Commands]] page for details and examples.)&lt;br /&gt;
&lt;br /&gt;
=====CHOOSE [OUTPUT] FILE [OF TYPE &amp;lt;.ext1&amp;gt; [&amp;lt;.ext2&amp;gt; ...]] [STARTING AT &amp;lt;dir&amp;gt;] [WITH PROMPT &amp;lt;message&amp;gt;]=====&lt;br /&gt;
Via the Qt graphical user interface, prompt the user to specify a file into which data can be saved (with an overwrite confirmation dialog if it already exists). Print the resulting file path.&lt;br /&gt;
(See the [[User_Reference:Custom_GUI_Commands|Custom GUI Commands]] page for details and examples.)&lt;br /&gt;
&lt;br /&gt;
=====CHOOSE DIRECTORY [STARTING AT &amp;lt;dir&amp;gt;] [WITH PROMPT &amp;lt;message&amp;gt;]=====&lt;br /&gt;
Via the Qt graphical user interface, prompt the user to specify a directory. Print the resulting directory path.&lt;br /&gt;
(See the [[User_Reference:Custom_GUI_Commands|Custom GUI Commands]] page for details and examples.)&lt;br /&gt;
&lt;br /&gt;
=====CUSTOM DIALOG [MESSAGE &amp;lt;msg&amp;gt;] [VAR &amp;lt;varname&amp;gt; &amp;lt;label&amp;gt; {[&amp;lt;options&amp;gt;]} ] [BUTTONS {&amp;lt;buttons&amp;gt;}] ... =====&lt;br /&gt;
Via the Qt graphical user interface, prompt the user with a modal dialog that can be flexibly customized.&lt;br /&gt;
(See the [[User_Reference:Custom_GUI_Commands|Custom GUI Commands]] page for details and examples.)&lt;br /&gt;
&lt;br /&gt;
===Predefined Variables===&lt;br /&gt;
The following variables exist when an Operator script is executed.&lt;br /&gt;
Some of these variables are marked with &#039;&#039;local&#039;&#039;. This means that they are not environment variables, i.e. they are invisible to child processes that are launched using the SYSTEM or START EXECUTABLE commands, and their values may be different between script invocations. In script code, they are accessed like ordinary variables.&lt;br /&gt;
====BCI2000LAUNCHDIR====&lt;br /&gt;
The full absolute path to the directory where the Operator module resides. This is also prepended to the PATH environment variable, such that executables from the current BCI2000 installation will have precedence over any other executable with the same name.&lt;br /&gt;
&lt;br /&gt;
On macOS, this is the path where the Operator module&#039;s application bundle resides. In the default configuration, this is the BCI2000 prog directory, both on macOS and on other platforms.&lt;br /&gt;
&lt;br /&gt;
====BCI2000BINARY====&lt;br /&gt;
The full absolute path to the Operator module.&lt;br /&gt;
====LogLevel (local)====&lt;br /&gt;
Determines the amount of log information written to the Operator log. This variable only affects log messages originating from the current script. May be 2 (display all log messages), 1 (display fewer log messages), or 0 (suppress all log messages). Set to 1 by default. Changes to this local variable are not propagated to any sub-scripts called. &#039;&#039;NOTE:&#039;&#039; Only log messages are controlled by this variable. Error messages originating from a script with &#039;LogLevel 0&#039; will still be displayed in the Operator log. When &#039;AbortOnError&#039; is set to 0, you may set &#039;LogLevel&#039; to -1 in order to display error messages. When &#039;AbortOnError&#039; is 1 (the default), error messages will always be displayed to indicate the reason for failure.&lt;br /&gt;
&lt;br /&gt;
====AbortOnError (local)====&lt;br /&gt;
Determines if a script is aborted when an error happens, or whether the error is silently ignored. Set to 1 by default (script is aborted on error). Changes to this local variable are not propagated to any sub-scripts called.&lt;br /&gt;
&lt;br /&gt;
====Result (local)====&lt;br /&gt;
The result of the last executed scripting command. When a script is executed by calling EXECUTE SCRIPT, the script&#039;s last executed command determines the result of the EXECUTE SCRIPT command itself.&lt;br /&gt;
&lt;br /&gt;
====0, 1, ... 9 (local)====&lt;br /&gt;
When a script file is being executed, these variables contain the arguments of the EXECUTE SCRIPT command.&lt;br /&gt;
&#039;&#039;$0&#039;&#039; resolves to the full absolute path to the current script file. Within scripts, all of the &#039;&#039;0-9&#039;&#039; variables are defined, and those that do not have a matching argument are empty.&lt;br /&gt;
&lt;br /&gt;
====YYYYMMDD (local)====&lt;br /&gt;
Local time at execution of the current script, in YYYYMMDD format. In interactive sessions, reflects the time when the session was initiated.&lt;br /&gt;
&lt;br /&gt;
====HHMMSS (local)====&lt;br /&gt;
Local time at execution of the current script, in HHMMSS format. In interactive sessions, reflects the time when the session was initiated.&lt;br /&gt;
&lt;br /&gt;
===Abbreviated commands and synonyms===&lt;br /&gt;
To minimize the need of consulting documentation, as well as for backward compatibility, a number of &#039;&#039;&#039;synonymous commands&#039;&#039;&#039; are provided. E.g., states may be added by INSERT STATE as well as ADD STATE, and the existence of a file may be queried by IS FILE as well as EXISTS FILE. For an overview over all allowed forms of commands, use the HELP ALL command.&lt;br /&gt;
&lt;br /&gt;
To simplify operation in interactive sessions, &#039;&#039;&#039;abbreviated commands&#039;&#039;&#039; exist. Currently, these are:&lt;br /&gt;
:&#039;&#039;&#039;cd&#039;&#039;&#039; for CHANGE DIRECTORY,&lt;br /&gt;
:&#039;&#039;&#039;pwd&#039;&#039;&#039; and &#039;&#039;&#039;cd&#039;&#039;&#039; without argument for CURRENT DIRECTORY,&lt;br /&gt;
:&#039;&#039;&#039;ls&#039;&#039;&#039; and &#039;&#039;&#039;dir&#039;&#039;&#039; for LIST DIRECTORY,&lt;br /&gt;
:&#039;&#039;&#039;mkdir&#039;&#039;&#039; for MAKE DIRECTORY,&lt;br /&gt;
:&#039;&#039;&#039;echo&#039;&#039;&#039; for WRITE LINE,&lt;br /&gt;
:&#039;&#039;&#039;realpath&#039;&#039;&#039; for REAL PATH,&lt;br /&gt;
:&#039;&#039;&#039;dirname&#039;&#039;&#039; for EXTRACT DIRECTORY,&lt;br /&gt;
:&#039;&#039;&#039;basename&#039;&#039;&#039; for EXTRACT FILE BASE.&lt;br /&gt;
&lt;br /&gt;
===Handlers===&lt;br /&gt;
In the Operator GUI, script execution is bound to a number of Operator Events (not to be confused with Event states, above) that occur during various [[Technical Reference:States of Operation|stages of BCI2000 system operation]]:&lt;br /&gt;
====OnConnect====&lt;br /&gt;
This handler runs at startup, as soon as all modules are connected to the operator module.&lt;br /&gt;
====OnSetConfig====&lt;br /&gt;
This handler runs each time a set of parameters is applied to the system. This happens when the user clicks the &#039;&#039;SetConfig&#039;&#039; button. Execution of the &#039;&#039;SETCONFIG&#039;&#039; command also runs this handler.&lt;br /&gt;
&lt;br /&gt;
====OnStart, OnResume====&lt;br /&gt;
These handlers are triggered by the &#039;&#039;Start&#039;&#039;/&#039;&#039;Resume&#039;&#039; button. One of these handlers is also triggered when the &#039;&#039;Running&#039;&#039; state variable is set to 1 from a script. Whether &#039;&#039;OnStart&#039;&#039; or &#039;&#039;OnResume&#039;&#039; is triggered depends on whether the system has been running before with the current set of parameters.&lt;br /&gt;
&lt;br /&gt;
====OnStartRun====&lt;br /&gt;
Similarly to OnStart and OnResume, this handler is triggered by the &#039;&#039;Start&#039;&#039;/&#039;&#039;Resume&#039;&#039; button. Unlike other event handlers, OnStartRun has an argument, which is the current run file.&lt;br /&gt;
&lt;br /&gt;
OnStart or OnResume are triggered immediately after &#039;&#039;Start&#039;&#039;/&#039;&#039;Resume&#039;&#039; has been pressed, whereas OnStartRun is deferred until modules have confirmed to be in Running state. This makes sure that the OnStartRun event handler receives a valid run file name.&lt;br /&gt;
&lt;br /&gt;
====OnNextFilePart====&lt;br /&gt;
This handler is triggered during a run, whenever the &#039;&#039;FilePart&#039;&#039; event state is incremented. It allows scripts to know when a new&lt;br /&gt;
partial file has begun. For further information, see the [[User_Reference:BCI2000FileWriter#FileSplittingCondition|FileSplittingCondition]] parameter.&lt;br /&gt;
&lt;br /&gt;
====OnSuspend/OnStopRun====&lt;br /&gt;
Triggered when the system goes from running into suspended mode. This happens whenever the &#039;&#039;Running&#039;&#039; state variable changes from 1 to 0. This may happen when the user clicks &#039;&#039;Suspend&#039;&#039;, when the application module switches the system into suspended mode, or when a script sets the &#039;&#039;Running&#039;&#039; state variable to 0.&lt;br /&gt;
&lt;br /&gt;
====OnShutdown====&lt;br /&gt;
Triggered when the operator module shuts down connections, and switches into idle state.&lt;br /&gt;
&lt;br /&gt;
====OnExit====&lt;br /&gt;
Triggered when the operator module exits. Execution of the QUIT command also triggers this handler. This handler is not available to the SET SCRIPT and CLEAR SCRIPT commands. Also, when both an OnShutdown and an OnExit script are defined, the OnExit script may be executed before the OnShutdown script.&lt;br /&gt;
&lt;br /&gt;
====Associating Scripts with Operator Events====&lt;br /&gt;
In the operator module&#039;s preferences dialog, script commands may be entered for each of the handlers listed above.&lt;br /&gt;
Scripts may be specified as paths to script files, or as immediate one-line scripts.&lt;br /&gt;
Entries that start with a minus sign (-) are treated as one-line scripts, which may contain multiple commands separated with semicolons.&lt;br /&gt;
&lt;br /&gt;
Scripts may also be specified from the command line used to start up the operator module. There, handler names are followed with the content of the respective preference entry, enclosed in double quotes (&amp;quot;...&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Finally, scripts may be specified using the SET SCRIPT command of the scripting language itself.&lt;br /&gt;
&lt;br /&gt;
===Examples===&lt;br /&gt;
====Making use of the Operator module&#039;s Function Buttons====&lt;br /&gt;
To add a state variable called &amp;quot;Artifact&amp;quot;, and to set it using the operator&#039;s function buttons, do this:&lt;br /&gt;
*Enter the following line under &amp;quot;After All Modules Connected&amp;quot; in the operator&#039;s preferences dialog (note the minus sign):&lt;br /&gt;
 -ADD STATE Artifact 1 0&lt;br /&gt;
*Under &amp;quot;Function Buttons&amp;quot;, enter &amp;quot;Set Artifact&amp;quot; as the name of button 1, and as its command, enter (note there is no minus sign):&lt;br /&gt;
 SET STATE Artifact 1&lt;br /&gt;
*Enter &amp;quot;Clear Artifact&amp;quot; as the name of button 2, and as its command, enter&lt;br /&gt;
 SET STATE Artifact 0&lt;br /&gt;
&lt;br /&gt;
====A fully automated BCI2000 session====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Echo Please enter a subject ID:&lt;br /&gt;
Set SubjectID ${Read line}&lt;br /&gt;
&lt;br /&gt;
Startup system&lt;br /&gt;
Start executable SignalGenerator&lt;br /&gt;
Start executable SpectralSignalProcessing&lt;br /&gt;
Start executable CursorTask&lt;br /&gt;
Wait for Connected&lt;br /&gt;
Load parameterfile &amp;quot;../parms/examples/CursorTask_SignalGenerator.prm&amp;quot;&lt;br /&gt;
For i in 1 2 3&lt;br /&gt;
  Load parameterfile &amp;quot;../parms/MyExperiment/Session$i.prm&amp;quot;&lt;br /&gt;
  Set parameter SubjectName $SubjectID&lt;br /&gt;
  Set parameter SubjectSession $i&lt;br /&gt;
  Set config&lt;br /&gt;
  Wait for Resting&lt;br /&gt;
  Start&lt;br /&gt;
  Wait for Suspended 1000&lt;br /&gt;
End&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Automating BCI2000 by Operator command line arguments====&lt;br /&gt;
The following example shows how to specify script commands from the command line.&lt;br /&gt;
It fully automates BCI2000 operation by loading a parameter file, applying parameters, starting the system once the parameters are applied, and quitting the system once the run is over. For better readability, the example is broken across lines, using the ^ DOS line continuation character.&lt;br /&gt;
&lt;br /&gt;
 operator.exe --OnConnect &amp;quot;-LOAD PARAMETERFILE ../parms/examples/CursorTask_SignalGenerator.prm; SETCONFIG&amp;quot; ^&lt;br /&gt;
              --OnSetConfig &amp;quot;-SET STATE Running 1&amp;quot;  ^&lt;br /&gt;
              --OnSuspend &amp;quot;-QUIT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
====Automatically arranging windows in a 4x2 grid====&lt;br /&gt;
The following example arranges Source and Roundtrip visualizations on the left side of the screen.&lt;br /&gt;
On the right side, a large area is dedicated to the Operator&#039;s log window, and the Operator&#039;s main window sits at the bottom right.&lt;br /&gt;
&lt;br /&gt;
 Arrange Visualization SRCD 4 2 1 1 2 1&lt;br /&gt;
 Arrange Visualization RNDT 4 2 3 1&lt;br /&gt;
 Arrange Window Main 4 2 4 2&lt;br /&gt;
 Arrange Window Log  4 2 1 2 3 1&lt;br /&gt;
&lt;br /&gt;
[[File:Operator_Arrangement.PNG|center|640px|border]]&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
[[User Reference:Module Command Line Options]], [[User Reference:Operator Module]], [[User Reference:BCI2000Shell]], [[Technical Reference:States of Operation]]&lt;br /&gt;
&lt;br /&gt;
[[Category:User Interface]]&lt;/div&gt;</summary>
		<author><name>Jhill</name></author>
	</entry>
</feed>