@DATABASE Libraries Manual
@NODE MAIN "Amiga RKM Libraries: 31 Commodities Exchange Library"
@INDEX Lib_Index/MAIN
@TOC Libraries_Manual/Add
This chapter describes Commodities Exchange, the library of routines used
to add a custom input handler to the Amiga.  With Commodities Exchange,
any program function can be associated with key combinations or other
input events globally allowing the creation utility programs that run in
the background for all tasks.

@{" Custom Input Handlers " link 31-1}                         @{" CxObject Errors " link 31-10}
@{" CxObjects " link 31-2}                                     @{" Uniqueness " link 31-11}
@{" Installing A Broker Object " link 31-3}                    @{" Signal CxObjects " link 31-12}
@{" CxMessages " link 31-4}                                    @{" Custom CxObjects " link 31-13}
@{" Commodity Tool Types " link 31-5}                          @{" Debug CxObjects " link 31-14}
@{" Filter Objects and Input Description Strings " link 31-6}  @{" The IX Structure " link 31-15}
@{" Connecting CxObjects " link 31-7}                          @{" Controlling CxMessages " link 31-16}
@{" Sender CxObjects " link 31-8}                              @{" New Input Events " link 31-17}
@{" Translate CxObjects " link 31-9}                           @{" Function Reference " link 31-18}

@ENDNODE

@NODE 31-1 "31 Commodities Exchange Library / Custom Input Handlers"
The input.device has a hand in almost all user input on the Amiga.  It
gathers input events from the keyboard, the gameport (mouse), and several
other sources, into one input "stream".  Special programs called input
event handlers intercept input events along this stream, examining and
sometimes changing the input events.  Both Intuition and the console
device use input handlers to process user input.

    @{" Figure 31-1: The Amiga Input Stream " link "ADCD_v1.2:Reference_Library/lib_pics/31-1.iff/Main"}

Using the input.device, a program can introduce its own custom handler
into the chain of input handlers at almost any point in the chain.  "Hot
key" programs, shell pop-up programs, and screen blankers all commonly use
custom input handlers to monitor user input before it gets to the
Intuition input handler.


    @{" Figure 31-2: A Custom Input Handler " link "ADCD_v1.2:Reference_Library/lib_pics/31-2.iff/Main"}

Custom input handlers do have their drawbacks, however.  Not only are
these handlers hard to program, but because there is no standard way to
implement and control them, multiple handlers often do not work well
together.  Their antisocial behavior can result in load order dependencies
and incompatibilities between different custom input handlers.  Even for
the expert user, having several custom input handlers coexist peacefully
can be next to impossible.

    @{" Figure 31-3: The Commodities Network " link "ADCD_v1.2:Reference_Library/lib_pics/31-3.iff/Main"}

Commodities Exchange eliminates these problems by providing a simple,
standardized way to program and control custom input handlers.  It is
divided into three parts: an Exec library, a controller program, and some
amiga.lib functions.

The Exec library is called commodities.library.  When it is first opened,
commodities.library establishes a single input handler just before
Intuition in the input chain.  When this input handler receives an input
event, it creates a @{"CxMessage" link 31-4} (Commodities Exchange Message) corresponding
to the input event, and diverts the CxMessage through the network of
Commodities Exchange input handlers (Figure 31-3).

These handlers are made up of trees of different @{"CxObjects" link 31-2} (Commodities
Exchange Objects), each of which performs a simple operation on the
@{"CxMessages" link 31-4}.  Any CxMessages that exit the network are returned to the
input.device's input stream as input events.

Through function calls to the commodities.library, an application can
install a custom input handler.  A Commodities Exchange application,
sometimes simply referred to as a commodity, uses the @{"CxObject" link 31-2} primitives
to do things such as filter certain @{"CxMessages" link 31-4}, translate CxMessages,
signal a task when a CxObject receives a CxMessage, send a message when a
CxObject receives a CxMessage, or if necessary, call a custom function
when a CxObject receives a CxMessage.

The controller program is called Commodities Exchange.  The user can
monitor and control all the currently running Commodities Exchange
applications from this one program.  The user can enable and disable a
commodity, kill a commodity, or, if the commodity has a window, ask the
commodity to show or hide its window.  When the user requests any of these
actions, the controller program sends the commodity a message, telling it
which action to perform.

The third component of Commodities Exchange is its scanned library
functions.  These functions are part of the amiga.lib scanned library.
They do a lot of the work involved with parsing command lines and Tool
Types.

Commodities Exchange is ideal for programs like hot keys/pop ups, screen
blankers, and mouse blankers that need to monitor all user input.
Commodities Exchange should never be used as an alternate method of
receiving user input for an application.  Other applications depend on
getting user input in some form or another from the input stream.   A
greedy program that diverts input to itself rather than letting the input
go to where the user expects it can seriously confuse the user, not to
mention compromise the advantages of multitasking.

@ENDNODE

@NODE 31-2 "31 Commodities Exchange Library / CxObjects"
CxObjects are the basic building blocks used to construct a commodity.  A
commodity uses CxObjects to take care of all manipulations of @{"CxMessages" link 31-4}.
When a CxMessage "arrives" at a CxObject, that CxObject carries out its
primitive action and then, if it has not deleted the CxMessage, it passes
the CxMessage on to the next CxObject.  A commodity links together
CxObjects into a tree, organizing these simple action objects to perform
some higher function.

A CxObject is in one of two states, active or inactive.  An active
CxObject performs its primitive action every time it receives a @{"CxMessage" link 31-4}.
If a CxObject is inactive, CxMessages bypass it, continuing to the
CxObject that follows the inactive one.  By default, all CxObjects except
the type called brokers are created in the active state.

Currently, there are seven types of CxObjects (Table 31-1).


   Object Type   Purpose
   -----------   -------
    @{"Broker" link 31-3}       Registers a new commodity with the commodity network
    @{"Filter" link 31-6}       Accepts or rejects input events based on criteria set
                 up by the application
    @{"Sender" link 31-8}       Sends a message to a message port
    @{"Translate" link 31-9}    Replaces the input event with a different one
    @{"Signal" link 31-12}       Signals a task
    @{"Custom" link 31-13}       Calls a custom function provided by the commodity
    @{"Debug" link 31-14}        Sends debug information out the serial port


                 Table 31-1: Commodities Exchange Object Types

@ENDNODE

@NODE 31-3 "31 Commodities Exchange Library / Installing A Broker Object"
The Commodities Exchange input handler maintains a master list of
@{"CxObjects" link 31-2} to which it diverts input events using @{"CxMessages" link 31-4}.  The
CxObjects in this master list are a special type of CxObject called
brokers.  The only thing a broker CxObject does is divert CxMessages to
its own personal list of CxObjects.  A commodity creates a broker and
attaches other CxObjects to it.  These attached objects take care of the
actual input handler related work of the commodity and make up the
broker's personal list.

The first program listing, @{"Broker.c" link ADCD_v1.2:Reference_Library/Libraries/lib_examples/broker.c/MAIN}, is a very simple example of a working
commodity.  It serves only to illustrate the basics of a commodity, not to
actually perform any useful function.  It shows how to set up a broker and
process commands from the controller program.

Besides opening commodities.library and creating an Exec message port,
setting up a commodity requires creating a broker.  The function
@{"CxBroker()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/CxBroker()} creates a broker and adds it to the master list.

    CxObj *CxBroker(struct NewBroker *nb, long *error);

@{"CxBroker()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/CxBroker()}'s first argument is a pointer to a @{"NewBroker" link ADCD_v1.2:Inc&AD2.1/includes/libraries/commodities.h/MAIN 47} structure:

    struct NewBroker {
        BYTE    nb_Version;
                    /* There is an implicit pad byte after this BYTE */
        BYTE    *nb_Name;
        BYTE    *nb_Title;
        BYTE    *nb_Descr;
        SHORT   nb_Unique;
        SHORT   nb_Flags;
        BYTE    nb_Pri;
                    /* There is an implicit pad byte after this BYTE */
        struct  MsgPort   *nb_Port;
        WORD    nb_ReservedChannel;
                    /* Unused, make zero for future compatibility */
    };

Commodities Exchange gets all the information it needs about the broker
from this structure.  NewBroker's nb_Version field contains the version
number of the NewBroker structure.  This should be set to NB_VERSION which
is defined in <libraries/@{"commodities.h" link ADCD_v1.2:Inc&AD2.1/includes/libraries/commodities.h/MAIN 45}>.  The nb_Name, nb_Title, and
nb_Descr point to strings which hold the name, title, and description of
the broker.  The two bit fields, @{"nb_Unique" link 31-11 7} and @{"nb_Flags" link 31-4-2 9}, toggle certain
features of Commodities Exchange based on their values.  They are
discussed in detail later in this chapter.

The nb_Pri field contains the broker's priority.  Commodities Exchange
inserts the broker into the master list based on this number.  Higher
priority brokers get @{"CxMessages" link 31-4} before lower priority brokers.

@{"CxBroker()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/CxBroker()}'s second argument is a pointer to a LONG.  If this pointer is
not NULL, CxBroker() fills in this field with one of the following error
return codes from <libraries/@{"commodities.h" link ADCD_v1.2:Inc&AD2.1/includes/libraries/commodities.h/MAIN 39}>:

    CBERR_OK        0        /* No error                         */
    CBERR_SYSERR    1        /* System error , no memory, etc    */
    CBERR_DUP       2        /* uniqueness violation             */
    CBERR_VERSION   3        /* didn't understand nb_VERSION     */

Once the broker object is created with @{"CxBroker()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/CxBroker()}, it must be activated
with @{"ActivateCxObj()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/ActivateCxObj()}.

    oldactivationvalue = LONG ActivateCxObj(CxObj *co,
                                            long newactivationvalue);

After successfully completing the initial set up and activating the
broker, a commodity can begin its input processing loop waiting for
@{"CxMessages" link 31-4} to arrive.

@ENDNODE

@NODE 31-4 "31 Commodities Exchange Library / CxMessages"
There are actually two types of CxMessages.  The first, @{"CXM_IEVENT" link ADCD_v1.2:Inc&AD2.1/includes/libraries/commodities.h/MAIN 100},
corresponds to an input event and travels through the Commodities Exchange
network.  The other type, @{"CXM_COMMAND" link ADCD_v1.2:Inc&AD2.1/includes/libraries/commodities.h/MAIN 113}, carries a command to a commodity.
A CXM_COMMAND normally comes from the controller program and is used to
pass user commands on to a commodity.  A commodity receives these commands
through an Exec message port that the commodity sets up before it calls
@{"CxBroker()" link 31-3 14}.  The @{"NewBroker" link 31-3 20}'s @{"nb_Port" link 31-3 32} field points to this message port.  A
commodity can tell the difference between the two types of CxMessages by
calling the @{"CxMsgType()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/CxMsgType()} function.

    ULONG  CxMsgType( CxMsg *cxm );
    UBYTE *CxMsgData( CxMsg *cxm );
    LONG   CxMsgID  ( CxMsg *cxm );

A CxMessage not only has a type, it can also have a data pointer as well
as an ID associated with it.  The data associated with a @{"CXM_IEVENT" link ADCD_v1.2:Inc&AD2.1/includes/libraries/commodities.h/MAIN 100}
CxMessage is an @{"InputEvent" link ADCD_v1.2:Reference_Library/Libraries/Lib_9/9-2} structure.  By using the @{"CxMsgData()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/CxMsgData()} function,
a commodity can obtain a pointer to the corresponding InputEvent of a
CXM_IEVENT message.  Commodities Exchange gives an ID of zero to any
CXM_IEVENT CxMessage that it introduces to the Commodities network but
certain @{"CxObjects" link 31-2} can assign an ID to them.

For a @{"CXM_COMMAND" link ADCD_v1.2:Inc&AD2.1/includes/libraries/commodities.h/MAIN 113} CxMessages, the data pointer is generally not used but
the ID specifies a command passed to the commodity from the user operating
the controller program.  The @{"CxMsgID()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/CxMsgID()} macro extracts the ID from a
CxMessage.

@{" A Simple Commodity Example " link ADCD_v1.2:Reference_Library/Libraries/lib_examples/broker.c/MAIN}
@{" Controller Commands " link 31-4-2}
@{" Shutting Down the Commodity " link 31-4-3}

@ENDNODE

@NODE 31-4-2 "31 / CxMessages / Controller Commands"
The commands that a commodity can receive from the controller program (as
defined in <libraries/@{"commodities.h" link ADCD_v1.2:Inc&AD2.1/includes/libraries/commodities.h/MAIN 121}>) are:

    CXCMD_DISABLE     /* please disable yourself       */
    CXCMD_ENABLE      /* please enable yourself        */
    CXCMD_KILL        /* go away for good              */
    CXCMD_APPEAR      /* open your window, if you can  */
    CXCMD_DISAPPEAR   /* hide your window              */

The CXCMD_DISABLE, CXCMD_ENABLE, and CXCMD_KILL commands correspond to the
similarly named controller program gadgets, Disable, Enable, and Kill;
CXCMD_APPEAR and CXCMD_DISAPPEAR correspond to the controller program
gadgets, Show and Hide.  These gadgets are ghosted in @{"Broker.c" link ADCD_v1.2:Reference_Library/Libraries/lib_examples/broker.c/MAIN} because it
has no window (It doesn't make much sense to give the user a chance to
click the Show and Hide gadgets).  In order to do this, Broker.c  has to
tell Commodities Exchange to ghost these gadgets.  When @{"CxBroker()" link 31-3 14} sets up
a @{"broker" link 31-3}, it looks at the @{"NewBroker.nb_Flags" link 31-3 28} field to see if the
COF_SHOW_HIDE bit (from <libraries/@{"commodities.h" link ADCD_v1.2:Inc&AD2.1/includes/libraries/commodities.h/MAIN 64}>) is set.  If it is, the
"Show" and "Hide" gadgets for this broker will be selectable.  Otherwise
they are ghosted and disabled.

@ENDNODE

@NODE 31-4-3 "31 / CxMessages / Shutting Down the Commodity"
Shutting down a commodity is easy.  After replying to all @{"CxMessages" link 31-4}
waiting at the @{"broker" link 31-3}'s message port, a commodity can delete its
@{"CxObjects" link 31-2}.  The @{"DeleteCxObj()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/DeleteCxObj()} function removes a single CxObject from the
Commodities network.  @{"DeleteCxObjAll()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/DeleteCxObjAll()} removes multiple objects.

    void DeleteCxObj( CxObj *co );
    void DeleteCxObjAll( CxObj *delete_co );

If a commodity has a lot of @{"CxObjects" link 31-2}, deleting each individually can be a
bit tedious.  @{"DeleteCxObjAll()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/DeleteCxObjAll()} will delete a CxObject and any other
CxObjects that are attached to it.  The @{"HotKey.c" link ADCD_v1.2:Reference_Library/Libraries/lib_examples/hotkey.c/MAIN} example given later in
this chapter uses this function to delete all its CxObjects.  A commodity
that uses DeleteCxObjAll() to delete all its CxObjects should make sure
that they are all connected to the main one.  (See the section
"@{"Connecting CxObjects" link 31-7}" below.)

After deleting its @{"CxObjects" link 31-2}, a commodity must take care of any @{"CxMessages" link 31-4}
that might have arrived at the message port just before the commodity
deleted its objects.

    while(msg = (CxMsg *)GetMsg(broker_mp))
        ReplyMsg((struct Message *)msg);

@ENDNODE

@NODE 31-5 "31 Commodities Exchange Library / Commodity Tool Types"
A goal of Commodities Exchange is to improve user control over input
handlers.  One way in which it accomplishes this goal is through the use
of standard icon Tool Types.  The user will expect commodities to
recognize the set of standard Tool Types:

        CX_PRIORITY
        CX_POPUP
        CX_POPKEY

CX_PRIORITY lets the user set the priority of a commodity.  The string
"CX_PRIORITY=" is a number from -128 to 127.  The higher the number, the
higher the priority of the commodity, giving it access to input events
before lower priority commodities.  All commodities should recognize
CX_PRIORITY.

CX_POPUP and CX_POPKEY are only relevant to commodities with a window.
The string "CX_POPUP=" should be followed by a "yes" or "no", telling the
commodity if it should or shouldn't show its window when it is first
launched.  CX_POPKEY is followed by a string describing the key to use as
a hot key for making the commodity's window appear (pop up).  The
description string for CX_POPKEY describes an input event.  The specific
format of the string is discussed in the next section
("@{"Filter Objects and the Input Description String" link 31-6}").

Commodities Exchange's support library functions simplify parsing
arguments from either the Workbench or the Shell (CLI).  A Workbench
launched commodity gets its arguments directly from the Tool Types in the
commodity's icon.  Shell launched commodities get their arguments from the
command line, but these arguments look exactly like the Tool Types from
the commodity's icon.  For example, the following command line sets the
priority of a commodity called HotKey to 5:

    HotKey "CX_PRIORITY=5"

Commodities Exchange has several support library functions used to parse
arguments:

    tooltypearray = UBYTE **ArgArrayInit(LONG argc, UBYTE **argv);
                    void    ArgArrayDone(void);

    tooltypevalue = STRPTR  ArgString(UBYTE **tooltypearray,
                                      STRPTR tooltype,
                                      STRPTR defaultvalue);
    tooltypevalue = LONG  *ArgInt(UBYTE **tooltypearray,
                                  STRPTR tooltype,
                                  LONG defaultvalue);

@{"ArgArrayInit()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/ArgArrayInit()} initializes a Tool Type array of strings which it creates
from the startup arguments, argc and argv.  It doesn't matter if these
startup arguments come from the Workbench or from a Shell, ArgArrayInit()
can extract arguments from either source.  Because ArgArrayInit() uses
some icon.library functions, a commodity is responsible for opening that
library before using the function.

@{"ArgArrayInit()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/ArgArrayInit()} also uses some resources that must be returned to the
system when the commodity is done.  @{"ArgArrayDone()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/ArgArrayDone()} performs this clean up.
Like ArgArrayInit(), ArgArrayDone() uses icon.library, so the library has
to remain open until ArgArrayDone() is finished.

The support library has two functions that use the Tool Type array set up
by @{"ArgArrayInit()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/ArgArrayInit()}, @{"ArgString()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/ArgString()} and @{"ArgInt()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/ArgInt()}.  ArgString() scans the Tool
Type array for a specific Tool Type.  If successful, it returns a pointer
to the value associated with that Tool Type.  If it doesn't find the Tool
Type, it returns the default value passed to it.  ArgInt() is similar to
ArgString().  It also scans the ArgArrayInit()'s Tool Type array, but it
returns a LONG rather than a string pointer.  ArgInt() extracts the
integer value associated with a Tool Type, or, if that Tool Type is not
present, it returns the default value.

Of course, these Tool Type parsing functions are not restricted to the
standard Commodities Exchange Tool Types.  A commodity that requires any
arguments should use these functions along with custom Tool Types to
obtain these values.  Because the Commodities Exchange standard arguments
are processed as Tool Types, the user will expect to enter other arguments
as Tool Types too.

@ENDNODE

@NODE 31-6 "31 Commodities Exchange / Filter Objects and Input Description Strings"
Because not all commodities are interested in every input event that makes
it way down the input chain, Commodities Exchange has a method for
filtering them.  A filter @{"CxObject" link 31-2} compares the @{"CxMessages" link 31-4} it receives to
a pattern.  If a CxMessage matches the pattern, the filter diverts the
CxMessage down its personal list of CxObjects.

    CxObj *CxFilter(UBYTE *descriptionstring);

The C macro @{"CxFilter()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/CxFilter()} (defined in <libraries/@{"commodities.h" link ADCD_v1.2:Inc&AD2.1/includes/libraries/commodities.h/MAIN 19}>) returns a
pointer to a filter @{"CxObject" link 31-2}.  The macro has only one argument, a pointer
to a string describing which input events to filter.  The following
regular expression outlines the format of the input event description
string (@{"CX_POPKEY" link 31-5} uses the same description string format):

    [class]  {[-] (qualifier|synonym)}  [[-] upstroke]  [highmap|ANSICode]

Class can be any one of the class strings in the table below.  Each class
string corresponds to a class of input event as defined in
<devices/@{"inputevent.h" link ADCD_v1.2:Inc&AD2.1/includes/devices/inputevent.h/MAIN 20}>.  Commodities Exchange will assume the class is
rawkey if the class is not explicitly stated.


     Class String      Input Event Class
     ------------      -----------------
    "rawkey"           IECLASS_RAWKEY
    "rawmouse"         IECLASS_RAWMOUSE
    "event"            IECLASS_EVENT
    "pointerpos"       IECLASS_POINTERPOS
    "timer"            IECLASS_TIMER
    "newprefs"         IECLASS_NEWPREFS
    "diskremoved"      IECLASS_DISKREMOVED
    "diskinserted"     IECLASS_DISKINSERTED


Qualifier is one of the qualifier strings from the table below.  Each
string corresponds to an input event qualifier as defined in
<devices/@{"inputevent.h" link ADCD_v1.2:Inc&AD2.1/includes/devices/inputevent.h/MAIN 161}>).  A dash preceding the qualifier string tells the
filter object not to care if that qualifier is present in the input event.
Notice that there can be more than one qualifier (or none at all) in the
input description string.


   Qualifier String    Input Event Class
   ----------------    -----------------
    "lshift"           IEQUALIFIER_LSHIFT
    "rshift"           IEQUALIFIER_RSHIFT
    "capslock"         IEQUALIFIER_CAPSLOCK
    "control"          IEQUALIFIER_CONTROL
    "lalt"             IEQUALIFIER_LALT
    "ralt"             IEQUALIFIER_RALT
    "lcommand"         IEQUALIFIER_LCOMMAND
    "rcommand"         IEQUALIFIER_RCOMMAND
    "numericpad"       IEQUALIFIER_NUMERICPAD
    "repeat"           IEQUALIFIER_REPEAT
    "midbutton"        IEQUALIFIER_MIDBUTTON
    "rbutton"          IEQUALIFIER_RBUTTON
    "leftbutton"       IEQUALIFIER_LEFTBUTTON
    "relativemouse"    IEQUALIFIER_RELATIVEMOUSE


Synonym is one of the synonym strings from the table below.  These
strings act as synonyms for groups of qualifiers.  Each string corresponds
to a synonym identifier as defined in <libraries/@{"commodities.h" link ADCD_v1.2:Inc&AD2.1/includes/libraries/commodities.h/MAIN 184}>.  A dash
preceding the synonym string tells the filter object not to care if that
synonym is present in the input event.  Notice that there can be more
than one synonym (or none at all) in the input description string.


    Synonym     Synonym
    String     Identifier
    -------    ----------
    "shift"    IXSYM_SHIFT    /* look for either shift key */
    "caps"     IXSYM_CAPS     /* look for either shift key or capslock */
    "alt"      IXSYM_ALT      /* look for either alt key */


Upstroke is the literal string "upstroke".  If this string is absent, the
filter considers only downstrokes.  If it is present alone, the filter
considers only upstrokes.  If preceded by a dash, the filter considers
both upstrokes and downstrokes.

Highmap is one of the following strings:

    "space", "backspace", "tab", "enter", "return", "esc", "del",
    "up", "down", "right", "left", "f1", "f2", "f3", "f4", "f5",
    "f6", "f7", "f8", "f9", "f10", "help".

ANSICode is a single character (for example `a') that Commodities Exchange
looks up in the system default keymap.

Here are some example description strings.  For function key F2 with the
left Shift and either Alt key pressed, the input description string would
be:

    "rawkey lshift alt f2"

To specify the key that produces an `a' (this may or may not be the A key
depending on the keymap), with or without any Shift, Alt, or control keys
pressed use:

    "-shift -alt -control a"

For a mouse move with the right mouse button down, use:

    "rawmouse rbutton"

To specify a timer event use:

    "timer"

@ENDNODE

@NODE 31-7 "31 Commodities Exchange Library / Connecting CxObjects"
A @{"CxObject" link 31-2} has to be inserted into the Commodities network before it can
process any @{"CxMessages" link 31-4}.  @{"AttachCxObj()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/AttachCxObj()} adds a CxObject to the personal
list of another CxObject.  The HotKey.c example uses it to attach its
@{"filter" link 31-6} to a @{"broker" link 31-3}.

    void AttachCxObj ( CxObj *headobj, CxObj *co);
    void InsertCxObj ( CxObj *headobj, CxObj *co, CxObj *co_pred );
    void EnqueueCxObj( CxObj *headobj, CxObj *co );
    void SetCxObjPri ( CxObj *co, long pri );
    void RemoveCxObj ( CxObj *co );

@{"AttachCxObj()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/AttachCxObj()} adds the @{"CxObject" link 31-2} to the end of headobj's personal list.
The ordering of a CxObject list determines which object gets @{"CxMessages" link 31-4}
first.  @{"InsertCxObj()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/InsertCxObj()} also inserts a CxObject, but it inserts it after
another CxObject already in the personal list (co_pred in the prototype
above).

@{"Brokers" link 31-3} aren't the only @{"CxObjects" link 31-2} with a priority.  All CxObjects have a
priority associated with them.  To change the priority of any CxObject,
use the @{"SetCxObjPri()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/SetCxObjPri()} function.  A commodity can use the priority to keep
CxObjects in a personal list sorted by their priority.  The
commodities.library function @{"EnqueueCxObj()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/EnqueueCxObj()} inserts a CxObject into
another CxObject's personal list based on priority.

Like its name implies, the @{"RemoveCxObj()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/RemoveCxObj()} function removes a @{"CxObject" link 31-2} from
a personal list.  Note that it is not necessary to remove a CxObject from
a list in order to delete it.

    @{" HotKey.c " link ADCD_v1.2:Reference_Library/Libraries/lib_examples/HotKey.c/MAIN}

@ENDNODE

@NODE 31-8 "31 Commodities Exchange Library / Sender CxObjects"
A @{"filter CxObject" link 31-6} by itself is not especially useful.  It needs some other
@{"CxObjects" link 31-2} attached to it.  A commodity interested in knowing if a specific
key was pressed uses a filter to detect and divert the corresponding
@{"CxMessage" link 31-4} down the filter's personal list.  The filter does this without
letting the commodity know what happened.  The sender CxObject can be
attached to a filter to notify a commodity that it received a CxMessage.
@{"CxSender()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/CxSender()} is a macro that creates a sender CxObject.

    senderCxObj = CxObj *CxSender(struct MsgPort *senderport, LONG cxmID);

@{"CxSender()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/CxSender()} supplies the sender with an Exec message port and an ID.  For
every @{"CxMessage" link 31-4} a sender receives, it sends a new CxMessage to the Exec
message port passed in CxSender().  Normally, the commodity creates this
port.  It is not unusual for a commodity's @{"broker" link 31-3} and sender(s) to share
an Exec message port.  The @{"HotKey.c" link ADCD_v1.2:Reference_Library/Libraries/lib_examples/hotkey.c/MAIN} example does this to avoid creating
unnecessary message ports.  A sender uses the ID (cxmID) passed to
CxSender() as the ID for all the CxMessages that the it transmits.  A
commodity uses the ID to monitor CxMessages from several senders at a
single message port.

A sender does several things when it receives a @{"CxMessage" link 31-4}.  First, it
duplicates the CxMessage's corresponding input event and creates a new
CxMessage.  Then, it points the new CxMessage's data field to the copy of
the input event and sets the new CxMessage's ID to the ID passed to
@{"CxSender()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/CxSender()}.  Finally, it sends the new CxMessage to the port passed to
CxSender(), asynchronously.

Because HotKey uses only one message port between its @{"broker" link 31-3} and sender
object, it has to extract the @{"CxMessage" link 31-4}'s type so it can tell if it is a
CXM_IEVENT or a CXM_COMMAND.  If HotKey gets a CXM_IEVENT, it compares the
CxMessage's ID to the sender's ID, EVT_HOTKEY, to see which sender sent
the CxMessage.  Of course HotKey has only one sender, so it only checks
for only one ID.  If it had more senders, HotKey would check for the ID of
each of the other senders as well.

Although HotKey doesn't use it, a @{"CXM_IEVENT CxMessage" link 31-4} contains a pointer
to the copy of an input event.  A commodity can extract this pointer
( using @{"CxMsgData()" link 31-4 10} ) if it needs to examine the input event copy.  This
pointer is only valid before the CxMessage reply.  Note that it does not
make any sense to modify the input event copy.

Senders are attached almost exclusively to @{"CxObjects" link 31-2} that filter out most
input events (usually a @{"filter CxObject" link 31-6}).  Because a sender sends a
@{"CxMessage" link 31-4} for every single input event it gets, it should only get a
select few input events.  The @{"AttachCxObj()" link 31-7} function can add a CxObject to
the end of a filter's (or some other filtering CxObject's) personal list.
A commodity should not attach a CxObject to a sender as a sender ignores
any CxObjects in its personal list.

@ENDNODE

@NODE 31-9 "31 Commodities Exchange Library / Translate CxObjects"
Normally, after a commodity processes a hot key input event, it needs to
eliminate that input event.  Other commodities may need to replace an
input event with a different one.  The translate @{"CxObject" link 31-2} can be used for
these purposes.

    translateCxObj = CxObj  *CxTranslate(struct InputEvent *newinputevent);

The macro @{"CxTranslate()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/CxTranslate()} creates a new translate @{"CxObject" link 31-2}.  CxTranslate()'s
only argument is a pointer to a chain of one or more @{"InputEvent" link ADCD_v1.2:Reference_Library/Libraries/Lib_9/9-2} structures.

When a translate @{"CxObject" link 31-2} receives a @{"CxMessage" link 31-4}, it eliminates the
CxMessage and its corresponding input event from the system.  The
translator introduces a new input event, which Commodities Exchange copies
from the @{"InputEvent" link ADCD_v1.2:Reference_Library/Libraries/Lib_9/9-2} structure passed to @{"CxTranslate()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/CxTranslate()} (newinputevent from
the function prototype above), in place of the deleted input event.

A translator is normally attached to some kind of @{"filtering CxObject" link 31-6}.  If
it wasn't, it would translate all input events into the same exact input
event.  Like the @{"sender CxObject" link 31-8}, a translator does not divert @{"CxMessages" link 31-4}
down its personal list, so it doesn't serve any purpose to add any to it.

    void SetTranslate( CxObj *translator, struct InputEvent *ie );

It is possible to change the @{"InputEvent" link ADCD_v1.2:Reference_Library/Libraries/Lib_9/9-2} structure that a translator looks
at when it creates and introduces new input events into the input stream.
The function @{"SetTranslate()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/SetTranslate()} accepts a pointer to the new InputEvent
structure, which the translator will duplicate and introduce when it
receives a @{"CxMessage" link 31-4}.

HotKey utilizes a special kind of translator.  Instead of supplying a new
input event, HotKey passes a NULL to @{"CxTranslate()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/CxTranslate()}.  If a translator has a
NULL new input event pointer, it does not introduce a new input event, but
still eliminates any @{"CxMessages" link 31-4} and corresponding input events it receives.

@ENDNODE

@NODE 31-10 "31 Commodities Exchange Library / CxObject Errors"
A Commodities Exchange function that acts on a @{"CxObject" link 31-6} records errors in
the CxObject's accumulated error field.  The function @{"CxObjError()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/CxObjError()} returns
a CxObject's error field.

    co_errorfield = LONG CxObjError( CxObj *co );

Each bit in the error field corresponds to a specific type of error.  The
following is a list of the currently defined @{"CxObject errors" link ADCD_v1.2:Inc&AD2.1/includes/libraries/commodities.h/MAIN 156} and their
corresponding bit mask constants.


    Error Constant    Meaning
    --------------    -------
    COERR_ISNULL      @{"CxObjError()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/CxObjError()} was passed a NULL.
    COERR_NULLATTACH  Someone tried to attach a NULL @{"CxObject" link 31-6} to this
                      CxObject.
    COERR_BADFILTER   This @{"filter CxObject" link 31-6} currently has an invalid
                      filter description.
    COERR_BADTYPE     Someone tried to perform a type specific function
                      on the wrong type of @{"CxObject" link 31-6} (for example calling
                      @{"SetFilter()" link 31-15 66} on a @{"sender CxObject" link 31-8}).


The remaining bits are reserved by Commodore for future use.  @{"HotKey.c" link ADCD_v1.2:Reference_Library/Libraries/lib_examples/hotkey.c/MAIN}
checks the error field of its @{"filter CxObject" link 31-6} to make sure the filter is
valid.  HotKey.c does not need to check the other objects with
@{"CxObjError()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/CxObjError()} because it already makes sure that these other objects are
not NULL, which is the only other kind of error the other objects can
cause in this situation.

Commodities Exchange has a function that clears a @{"CxObject" link 31-6}'s accumulated
error field, @{"ClearCxObjError()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/ClearCxObjError()}.

    void ClearCxObjError( CxObj *co );

A commodity should be careful about using this, especially on a @{"filter" link 31-4}.
If a commodity clears a filter's error field and the COERR_BADFILTER bit
is set, Commodities Exchange will think that the filter is OK and start
sending messages through it.

@ENDNODE

@NODE 31-11 "31 Commodities Exchange Library / Uniqueness"
When a commodity opens its @{"broker" link 31-3}, it can ask Commodities Exchange not to
launch another broker with the same name (@{"nb_Name" link 31-3 22}).  The purpose of the
uniqueness feature is to prevent the user from starting duplicate
commodities.  If a commodity asks, Commodities Exchange will not only
refuse to create a new, similarly named broker, but it will also notify
the original commodity if someone tries to do so.

A commodity tells Commodities Exchange not to allow duplicates by setting
certain bits in the @{"nb_Unique field" link ADCD_v1.2:Inc&AD2.1/includes/libraries/commodities.h/MAIN 59} of the @{"NewBroker" link 31-3 20} structure it sends to
@{"CxBroker()" link 31-3 14}:

    NBU_UNIQUE      bit 0
    NBU_NOTIFY      bit 1

Setting the NBU_UNIQUE bit prevents duplicate commodities.  Setting the
NBU_NOTIFY bit tells Commodities Exchange to notify a commodity if an
attempt was made to launch a duplicate.  Such a commodity will receive a
@{"CXM_COMMAND CxMessage" link 31-4} with an ID of @{"CXCMD_UNIQUE" link ADCD_v1.2:Inc&AD2.1/includes/libraries/commodities.h/MAIN 127} when someone tries to
duplicate it. Because the uniqueness feature uses the name a programmer
gives a commodity to differentiate it from other commodities, it is
possible for completely different commodities to share the same name,
preventing the two from coexisting.  For this reason, a commodity should
not use a name that is likely to be in use by other commodities (like
"filter" or "hotkey").  Instead, use a name that matches the commodity
name.

When @{"HotKey.c" link ADCD_v1.2:Reference_Library/Libraries/lib_examples/hotkey.c/MAIN} gets a @{"CXCMD_UNIQUE" link ADCD_v1.2:Inc&AD2.1/includes/libraries/commodities.h/MAIN 127} @{"CxMessage" link 31-4}, it shuts itself down.
HotKey.c and all the windowless commodities that come with the Release 2
Workbench shut themselves down when they get a CXCMD_UNIQUE CxMessage.
Because the user will expect all windowless commodities to work this way,
all windowless commodities should follow this standard.

When the user tries to launch a duplicate of a system commodity that has a
window, the system commodity moves its window to the front of the display,
as if the user had clicked the "Show" gadget in the controller program's
window.  A windowed commodity should mimic conventions set by existing
windowed system commodities, and move its window to the front of the
display.

@ENDNODE

@NODE 31-12 "31 Commodities Exchange Library / Signal CxObjects"
A commodity can use a @{"sender CxObject" link 31-8} to find out if a @{"CxMessage" link 31-4} has
"visited" a @{"CxObject" link 31-6}, but this method unnecessarily uses system resources.
A commodity that is only interested in knowing if such a visitation took
place does not need to see a corresponding input event or a CxMessage ID.
Instead, Commodities Exchange has a CxObject that uses an Exec signal.

    signalCxObj = CxObj  *CxSignal(struct Task *, LONG cx_signal);

@{"CxSignal()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/CxSignal()} sets up a signal @{"CxObject" link 31-2}.  When a signal CxObject receives a
@{"CxMessage" link 31-4}, it signals a task.  The commodity is responsible for
determining the proper task ID and allocating the signal.  Normally, a
commodity wants to be signalled so it uses @{"FindTask" link ADCD_v1.2:Reference_Library/Libraries/Lib_21/21-8 5}(NULL) to find it's own
task address.  Note that cx_signal from the above prototype is the signal
number as returned by @{"AllocSignal()" link ADCD_v1.2:Reference_Library/Libraries/Lib_22/22-1-1 5}, not the signal mask made from that
number.  For more information on signals, see the "@{"Exec Signals" link ADCD_v1.2:Reference_Library/Libraries/Lib_22/MAIN}" chapter.

The example @{"Divert.c" link ADCD_v1.2:Reference_Library/Libraries/lib_examples/divert.c/MAIN} (shown a little later in this chapter) uses a signal
@{"CxObject" link 31-2}.

@ENDNODE

@NODE 31-13 "31 Commodities Exchange Library / Custom CxObjects"
Although the @{"CxObjects" link 31-2} mentioned so far take care of most of the input
event handling a commodity needs to do, they cannot do it all.  This is
why Commodities Exchange has a custom CxObject.  When a custom CxObject
receives a @{"CxMessage" link 31-4}, it calls a function provided by the commodity.

    customCxObj = CxObj  *CxCustom(LONG *customfunction(), LONG  cxmID);

A custom @{"CxObject" link 31-2} is the only means by which a commodity can directly
modify input events as they pass through the Commodities network as
@{"CxMessages" link 31-4}.  For this reason, it is probably the most dangerous of the
CxObjects to use.

    A Warning About Custom CxObjects.
    ---------------------------------
    Unlike the rest of the code a commodities programmer writes, the
    code passed to a custom @{"CxObject" link 31-2} runs as part of the input.device
    task, putting severe restrictions on the function.  No DOS or
    Intuition functions can be called.  No assumptions can be made about
    the values of registers upon entry.  Any function passed to
    @{"CxCustom()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/CxCustom()} should be very quick and very simple, with a minimum of
    stack usage.

Commodities Exchange calls a custom @{"CxObject" link 31-2}'s function as follows:

    void customfunction(CxMsg *cxm, CxObj *customcxobj);

where cxm is a pointer to a @{"CxMessage" link 31-4} corresponding to a real input event,
and customcxobj is a pointer to the custom @{"CxObject" link 31-2}.  The custom function
can extract the pointer to the input event by calling @{"CxMsgData()" link 31-4 10}.  Before
passing the CxMessage to the custom function, Commodities Exchange sets
the CxMessage's ID to the ID passed to @{"CxCustom()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/CxCustom()}.

The following is an example of a custom @{"CxObject" link 31-2} function that swaps
the function of the left and right mouse buttons.


custom = CxCustom(CxFunction, 0L)

/* The custom function for the custom CxObject.  Any code for a */
/* custom CxObj must be short and sweet. This code runs as part */
/* of the input.device task                                     */
#define CODEMASK (0x00FF & IECODE_LBUTTON & IECODE_RBUTTON)
void CxFunction(register CxMsg *cxm, CxObj *co)
{
    struct InputEvent *ie;
    UWORD mousequals = 0x0000;

    /* Get the struct InputEvent associated with this CxMsg.  Unlike
     * the InputEvent extracted from a CxSender's CxMsg, this is a
     *  *REAL* input event, be careful with it.
     */
    ie = (struct InputEvent *)CxMsgData(cxm);

    /* Check to see if this input event is a left or right mouse button
     * by itself (a mouse button can also be a qualifier).  If it is,
     * flip the low order bit to switch leftbutton <--> rightbutton.
     */
    if (ie->ie_Class == IECLASS_RAWMOUSE)
        if ((ie->ie_Code & CODEMASK) == CODEMASK)  ie->ie_Code ^= 0x0001;

    /* Check the qualifiers. If a mouse button was down when this */
    /* input event occurred, set the other mouse button bit.      */
    if (ie->ie_Qualifier & IEQUALIFIER_RBUTTON)  mousequals |=
                                                   IEQUALIFIER_LEFTBUTTON;
    if (ie->ie_Qualifier & IEQUALIFIER_LEFTBUTTON)  mousequals |=
                                                      IEQUALIFIER_RBUTTON;

    /* clear the RBUTTON and LEFTBUTTON qualifier bits */
    ie->ie_Qualifier &= ~(IEQUALIFIER_LEFTBUTTON | IEQUALIFIER_RBUTTON);

    /* set the mouse button qualifier bits to their new values */
    ie->ie_Qualifier |= mousequals;
}

@ENDNODE

@NODE 31-14 "31 Commodities Exchange Library / Debug CxObjects"
The final @{"CxObject" link 31-2} is the debug CxObject.  When a debug CxObject receives
a @{"CxMessage" link 31-4}, it sends debugging information to the serial port using
@{"KPrintF()" link ADCD_v1.2:Inc&AD2.1/autodocs/debug_lib/KPrintF()}.

    debugCxObj  = CxObj  *CxDebug(LONG ID);

The debug @{"CxObject" link 31-2} will @{"KPrintF()" link ADCD_v1.2:Inc&AD2.1/autodocs/debug_lib/KPrintF()} the following information about itself,
the @{"CxMsg" link ADCD_v1.2:Inc&AD2.1/includes/libraries/commodities.h/MAIN 71}, and the corresponding @{"InputEvent" link ADCD_v1.2:Reference_Library/Libraries/Lib_9/9-2} structure:

    DEBUG NODE: 7CB5AB0, ID: 2
     CxMsg: 7CA6EF2, type: 0, data 2007CA destination 6F1E07CB
    dump IE: 7CA6F1E
     Class 1
     Code 40
     Qualifier 8000
     EventAddress 40001802

There has to be a terminal connected to the Amiga's serial port to receive
this information.  See the @{"KPrintF()" link ADCD_v1.2:Inc&AD2.1/autodocs/debug_lib/KPrintF()} Autodoc (debug.lib) for more details.
Note that the debug @{"CxObject" link 31-2} did not work before V37.

@ENDNODE

@NODE 31-15 "31 Commodities Exchange Library / The IX Structure"
Commodities Exchange does not use the input event description strings
discussed earlier to match input events.  Instead, Commodities Exchange
converts these strings to its own internal format.  These input
expressions are available for commodities to use instead of the input
description strings.  The following is the IX structure as defined in
<libraries/@{"commodities.h" link ADCD_v1.2:Inc&AD2.1/includes/libraries/commodities.h/MAIN 165}>:

    #define IX_VERSION   2

    struct InputXpression {
       UBYTE   ix_Version;     /* must be set to IX_VERSION  */
       UBYTE   ix_Class;       /* class must match exactly   */
       UWORD   ix_Code;
       UWORD   ix_CodeMask;    /* normally used for UPCODE   */
       UWORD   ix_Qualifier;
       UWORD   ix_QualMask;
       UWORD   ix_QualSame;    /* synonyms in qualifier      */
       };
    typedef struct InputXpression IX;

The ix_Version field contains the current version number of the
InputXpression structure.  The current version is defined as IX_VERSION.
The ix_Class field contains the @{"IECLASS_" link 31-6 16} constant (defined in
<devices/@{"inputevent.h" link ADCD_v1.2:Inc&AD2.1/includes/devices/inputevent.h/MAIN 18}>) of the class of input event sought.  Commodities
Exchange uses the ix_Code and ix_CodeMask fields to match the ie_Code
field of a struct @{"InputEvent" link ADCD_v1.2:Inc&AD2.1/includes/devices/inputevent.h/MAIN 196}.  The bits of ix_CodeMask indicate which bits
are relevant in the ix_Code field when trying to match against a ie_Code.
If any bits in ix_CodeMask are off, Commodities Exchange does not consider
the corresponding bit in ie_Code when trying to match input events.  This
is used primarily to mask out the @{"IECODE_UP_PREFIX" link ADCD_v1.2:Inc&AD2.1/includes/devices/inputevent.h/MAIN 122} bit of rawkey events,
making it easier to match both up and down presses of a particular key.

IX's qualifier fields, ix_Qualifier, ix_QualMask, and ix_QualSame, are
used to match the ie_Qualifier field of an @{"InputEvent" link ADCD_v1.2:Inc&AD2.1/includes/devices/inputevent.h/MAIN 196} structure.  The
ix_Qualifier and ix_QualMask fields work just like ix_Code and
ix_CodeMask.  The bits of ix_QualMask indicate which bits are relevant
when comparing ix_Qualifier to ie_Qualifier.  The ix_QualSame field tells
Commodities Exchange that certain qualifiers are equivalent:

    #define IXSYM_SHIFT  1  /* left- and right- shift are equivalent     */
    #define IXSYM_CAPS   2  /* either shift or caps lock are equivalent  */
    #define IXSYM_ALT    4  /* left- and right- alt are equivalent       */

For example, the input description string

    "rawkey -caps -lalt -relativemouse -upstroke ralt tab"

matches a tab upstroke or downstroke with the right Alt key pressed
whether or not the left Alt, either Shift, or the Caps Lock keys are down.
The following IX structure corresponds to that input description string:

    IX ix = {
        IX_VERSION,             /* The version */
        IECLASS_RAWKEY,         /* We're looking for a RAWKEY event */
        0x42,                   /* The key the usa0 keymap maps to a tab */
        0x00FF & (~IECODE_UP_PREFIX), /* We want up and down key presses */
        IEQUALIFIER_RALT,             /* The right alt key must be down */
        0xFFFF & ~(IEQUALIFIER_LALT | IEQUALIFIER_LSHIFT |
                   IEQUALIFIER_RSHIFT | IEQUALIFIER_CAPSLOCK |
                   IEQUALIFIER_RELATIVEMOUSE),
                   /* don't care about left alt, shift, capslock, or */
                   /* relativemouse qualifiers                       */
        IXSYM_CAPS  /* The shift keys and the capslock key */
                    /* qualifiers are all equivalent       */
    };

The @{"CxFilter()" link 31-6} macro only accepts a description string to describe an
input event.  A commodity can change this filter, however, with the
@{"SetFilter()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/SetFilter()} and @{"SetFilterIX()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/SetFilterIX()} function calls.

    void SetFilter( CxObj *filter, UBYTE *descrstring );
    void SetFilterIX( CxObj *filter, IX *ix );

@{"SetFilter()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/SetFilter()} and @{"SetFilterIX()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/SetFilterIX()} change which input events a @{"filter CxObject" link 31-6}
diverts.  SetFilter() accepts a pointer to an input description string.
SetFilterIX() accepts a pointer to an IX input expression.  A commodity
that uses either of these functions should check the filter's error code
with @{"CxObjError()" link 31-10} to make sure the change worked.

The function @{"ParseIX()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/ParseIX()} parses an input description string and translates
it into an IX input expression.

    errorcode = LONG ParseIX( UBYTE *descrstring, IX *ix );

Commodities Exchange uses @{"ParseIX()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/ParseIX()} to convert the description string in
@{"CxFilter()" link 31-6} to an IX input expression.  As was mentioned previously, as of
commodities.library version 37.3, ParseIX() does not work with certain
kinds of input strings.

@ENDNODE

@NODE 31-16 "31 Commodities Exchange Library / Controlling CxMessages"
A @{"Custom CxObject" link 31-13} has the power to directly manipulate the @{"CxMessages" link 31-4} that
travel around the Commodities network.  One way is to directly change
values in the corresponding input event.  Another way is to redirect (or
dispose of) the CxMessages.

    void DivertCxMsg ( CxMsg *cxm, CxObj *headobj, CxObj *retobj );
    void RouteCxMsg  ( CxMsg *cxm, CxObj *co );
    void DisposeCxMsg( CxMsg *cxm );

@{"DivertCxMsg()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/DivertCxMsg()} and @{"RouteCxMsg()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/RouteCxMsg()} dictate where the @{"CxMessage" link 31-4} will go next.
Conceptually, DivertCxMsg() is analogous to a subroutine in a program; the
CxMessage will travel down the personal list of a @{"CxObject" link 31-2} (headobj in the
prototype) until it gets to the end of that list.  It then returns and
visits the CxObject that follows the return CxObject (the return CxObject
in the prototype above is retobj).  RouteCxMsg() is analogous to a goto in
a program; it has no CxObject to return to.

@{"DisposeCxMsg()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/DisposeCxMsg()} removes a @{"CxMessage" link 31-4} from the network and releases its
resources.  The @{"translate CxObject" link 31-9} uses this function to remove a
CxMessage.

The example Divert.c shows how to use @{"DivertCxMsg()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/DivertCxMsg()} as well as a
@{"signal CxObject" link 31-12}.

    @{" divert.c " link ADCD_v1.2:Reference_Library/Libraries/lib_examples/divert.c/MAIN}

@ENDNODE

@NODE 31-17 "31 Commodities Exchange Library / New Input Events"
Commodities Exchange also has functions used to introduce new input events
to the input stream.

    struct InputEvent *InvertString( UBYTE *string, ULONG *keymap );
    void               FreeIEvents( struct InputEvent *ie );
    void               AddIEvents( struct InputEvent *ie );

@{"InvertString()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/InvertString()} is an amiga.lib function that accepts an ASCII string and
creates a linked list of input events that translate into the string using
the supplied keymap (or the system default if the key map is NULL).  The
NULL terminated string may contain ANSI character codes, an input
description enclosed in angle (<>) brackets, or one of the following
backslash escape characters:

    \r -- return
    \t -- tab
    \\ -- backslash

For example:

    abc<alt f1>\rhi there.

@{"FreeIEvents()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/FreeIEvents()} frees a list of input events allocated by @{"InvertString()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/InvertString()}.
@{"AddIEvents()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/AddIEvents()} is a commodities.library function that adds a linked list of
input events at the the top of the Commodities network.  Each input event
in the list is made into an individual @{"CxMessage" link 31-4}.  Note that if passed a
linked list of input events created by InvertString(), the order the
events appear in the string will be reversed.

    @{" PopShell.c " link ADCD_v1.2:Reference_Library/Libraries/lib_examples/PopShell.c/MAIN}

@ENDNODE

@NODE 31-18 "31 Commodities Exchange Library / Function Reference"
The following are brief descriptions of the Commodities Exchange functions
covered in this chapter.  All of these functions require Release 2 or a
later version of the Amiga operating system.  See the Amiga ROM Kernel
Reference Manual: Includes and Autodocs for details on each function call.


              Table 31-2: Commodities Exchange Functions
  _____________________________________________________________________
 |                                                                     |
 |         Function              Description                           |
 |=====================================================================|
 |         @{"CxBroker()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/CxBroker()}  Creates a @{"CxObject" link 31-2} of type @{"Broker" link 31-3}.              |
 |         @{"CxFilter()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/CxFilter()}  Creates a CxObject of type @{"Filter" link 31-6}.              |
 |         @{"CxSender()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/CxSender()}  Creates a CxObject of type @{"Sender" link 31-8}.              |
 |      @{"CxTranslate()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/CxTranslate()}  Creates a CxObject of type @{"Translate" link 31-9}.           |
 |         @{"CxSignal()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/CxSignal()}  Creates a CxObject of type @{"Signal" link 31-12}.              |
 |         @{"CxCustom()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/CxCustom()}  Creates a CxObject of type @{"Custom" link 31-13}.              |
 |          @{"CxDebug()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/CxDebug()}  Creates a CxObject of type @{"Debug" link 31-14}.               |
 |      @{"DeleteCxObj()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/DeleteCxObj()}  Frees a single CxObject                         |
 |   @{"DeleteCxObjAll()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/DeleteCxObjAll()}  Frees a group of connected CxObjects            |
 |---------------------------------------------------------------------|
 |    @{"ActivateCxObj()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/ActivateCxObj()}  Activates a newly created @{"CxObject" link 31-2} in the       |
 |                     commodities network.                            |
 |---------------------------------------------------------------------|
 |     @{"SetTranslate()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/SetTranslate()}  Sets up substitution of one input event for     |
 |                     another by translate CxObjects.                 |
 |---------------------------------------------------------------------|
 |        @{"CxMsgType()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/CxMsgType()}  Finds the type of a @{"CxMessage" link 31-4}.                  |
 |        @{"CxMsgData()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/CxMsgData()}  Returns the CxMessage data.                     |
 |          @{"CxMsgID()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/CxMsgID()}  Returns the CxMessage ID.                       |
 |---------------------------------------------------------------------|
 |       @{"CxObjError()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/CxObjError()}  Returns the @{"CxObject" link 31-2}'s accumulated error field. |
 |  @{"ClearCxObjError()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/ClearCxObjError()}  Clear the CxObject's accumulated error field.   |
 |---------------------------------------------------------------------|
 |     @{"ArgArrayInit()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/ArgArrayInit()}  Create a Tool Types array from argc and argv    |
 |                     (Workbench or Shell).                           |
 |     @{"ArgArrayDone()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/ArgArrayDone()}  Free the resources used by ArgArrayInit().      |
 |        @{"ArgString()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/ArgString()}  Return the string associated with a given Tool  |
 |                     Type in the array.                              |
 |           @{"ArgInt()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/ArgInt()}  Return the integer associated with a given Tool |
 |                     Type in the array.                              |
 |---------------------------------------------------------------------|
 |      @{"AttachCxObj()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/AttachCxObj()}  Attaches a @{"CxObject" link 31-2} to the end of a given       |
 |                     CxObject's list.                                |
 |      @{"InsertCxObj()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/InsertCxObj()}  Inserts a CxObject in a given position in a     |
 |                     CxObject's list.                                |
 |     @{"EnqueueCxObj()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/EnqueueCxObj()}  Inserts a CxObject in a CxObject's list by      |
 |                     priority.                                       |
 |      @{"SetCxObjPri()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/SetCxObjPri()}  Sets a CxObject's priority for EnqueueCxObj().  |
 |      @{"RemoveCxObj()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/RemoveCxObj()}  Removes a CxObject from a list.                 |
 |---------------------------------------------------------------------|
 |        @{"SetFilter()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/SetFilter()}  Set a @{"filter" link 31-6} for a @{"CxObject" link 31-2} from an input       |
 |                     description string.                             |
 |      @{"SetFilterIX()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/SetFilterIX()}  Set a filter for a CxObject from an IX data     |
 |                     structure.                                      |
 |---------------------------------------------------------------------|
 |          @{"ParseIX()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/ParseIX()}  Convert an input description string to an IX    |
 |                     data structure.                                 |
 |---------------------------------------------------------------------|
 |      @{"DivertCxMsg()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/DivertCxMsg()}  Divert a @{"CxMessage" link 31-4} to one @{"CxObject" link 31-2} and return   |
 |                     it to another.                                  |
 |       @{"RouteCxMsg()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/RouteCxMsg()}  Redirect a CxMessage to a new CxObject.         |
 |     @{"DisposeCxMsg()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/DisposeCxMsg()}  Cancel a CxMessage removing it from the         |
 |                     Commodities network.                            |
 |---------------------------------------------------------------------|
 |     @{"InvertString()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/InvertString()}  Creates a linked list of input events that      |
 |                     correspond to a given string.                   |
 |      @{"FreeIEvents()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/FreeIEvents()}  Frees the linked list of input events created   |
 |                     with InvertString().                            |
 |       @{"AddIEvents()" link ADCD_v1.2:Inc&AD2.1/autodocs/commodities/AddIEvents()}  Converts a list of input events to @{"CxMessages" link 31-4}   |
 |                     and puts them into the network.                 |
 |_____________________________________________________________________|

@ENDNODE
