The <events.h> header file
This header file contains the following functions:
ABT_dialog CAT_dialog EV_captureEvents
EV_centralDispatcher EV_clearPasteString EV_defaultHandler
EV_eventLoop EV_getAppID EV_getc
EV_getSplitRect EV_notifySwitchGraph EV_paintOneWindow
EV_paintWindows EV_registerMenu EV_restorePainting
EV_sendEvent EV_sendEventSide EV_sendString
EV_setCmdCheck EV_setCmdState EV_setFKeyState
EV_startApp EV_startSide EV_startTask
EV_suspendPainting EV_switch MO_currentOptions
MO_defaults MO_digestOptions MO_isMultigraphTask
MO_modeDialog MO_notifyModeChange MO_sendQuit
the following global variables:
EV_hook ModeSettings
and the following predefined types:
Bool EVENT EVENT_HANDLER
EventIDs HANDLE MO_OPTIONS
NULL PaintFlags SCR_RECT
ST_ACTIVITIES StandardTaskIDs StartTypes
WIN_RECT WINDOW WinFlags
NOTE: Event driving functions are intended mainly for making flash applications, although some
of them may be useful even in user programs. Anyway, they are intended for serious programmers,
not for the beginners. Don't try to make an event driven application if you don't understand well
what is written here!
Functions
Sets the event message handler (i.e. installs an event driven application).
EV_captureEvents sets a new event message handler to the routine pointed to by NewHandler,
overriding any current handler. NewHandler is the pointer of type EVENT_HANDLER,
which is the pointer to a void function (i.e. procedure) which accept one parameter of
EVENT type. If NewHandler is NULL,
EV_captureEvents restores the standard event handler (which depends of the current application
like "Home Screen", "Graph", etc.). EV_captureEvents returns the pointer to the previous installed
event handler.
Any event handler is, in fact, an event driven application. All built-in flash applications like
"Home screen", "Graph", "Text editor", "Geometry" etc. and all add-in flash applications are event driven applications. Also,
"About" and "Catalog" dialogs and "Error message" dialogs are also event driven applications
(maybe the word "applets" is better for them). The whole idea of event driving is as follows:
instead of having an application which has an internal "main loop" in which all processing are
performed, an event driven application accepts a message (or event), checks the type of the
event (a keypress is, for example, one type of the event), process it, then exits immediately
after processing the event. So, the user need to make a loop in which necessary events are
collected and dispatched (using EV_sendEvent) to the application.
The main advance of such approach is in the fact that the main loop is under the control of
the user, even if the application itself may be written by somebody else. So, the user can
decide in the loop what events will be send to an application etc. This would not be possible
if the "main loop" is the part of the application itself. For example, if the user makes a
loop in which events are dispatched to two or more applications, it is easy to estabilish a
kind of multitasking. Note that each modern operating system (for example Windows or UNIX) is
based on such event dispatching/handling mechanism!
To understand more about event driving applications, you need to read about all other
functions in this header file (especially EV_eventLoop,
EV_sendEvent and EV_defaultHandler
may be very useful in user programs). Probably the most frequent usage of these functions in
user programs will be to access the text editor
application (see textedit.h header file), which is event driven.
In this header file, there is also a good example about using some of event functions.
NOTE: If you want to "hook" on the existing event handler instead to complete overriding the
current handler, it is better to use EV_hook.
Enters the loop in which main event messages are collected and dispatched.
EV_eventLoop enters the (endless) loop in which main events are collected and dispatched to
the current application. In the normal operation of the calculator (i.e. when no user
program is running), the TIOS is just in this loop. Calling this function in the user program
makes sense (and may be very useful if you are happy with set of events which are processed in
this function) only if the program installs a custom event handler using
EV_captureEvents function, so the events may be trapped by
the user program.
Here is the exact description what happens in the each iteration of this loop (not in
exact order, but this is not important):
- If there are no activities (keypresses etc.) for a long time, and if the
timer APD_TIMER expires (see
OSRegisterTimer), the calculator is
turned off.
- If a key is pressed, the event CM_KEYPRESS is
send (using EV_sendEvent) to the current application. Note
if the current application is "Home screen", this may cause evaluation of the input
line (if the pressed key was ENTER key), including execution of user programs, etc.
This may also cause changing of the current application (for example, if the user pressed
APPS key).
- If there is a string in the event paste buffer (see EV_sendString),
the content of the buffer is processed exactly as if all codes in the buffer are typed from
the keyboard (i.e. a sequence of CM_KEYPRESS events
are send to the current application).
- If there is no keypress, if the cursor is enabled (see CU_start)
and if CURSOR_TIMER expires (see
OSRegisterTimer),
CM_BLINK event is send to the current application.
- If a global variable which contains the error code is non-zero, an error dialog is
displayed (using ERD_dialog).
- If there are twin symbols (see SymAddTwin) in the VAT
table, they are deleted. This performs cleaning up the RAM after executing of archived
programs.
- If painting is enabled (see EV_suspendPainting and
EV_restorePainting), event CM_WPAINT
is send using EV_paintOneWindow function.
- If there are no other activities, CM_IDLE event is send to the
current application, and the function idle is called.
Note that when an user ASM program is started, the current application is always "Home screen",
until the user change the current application using EV_startApp or
install the own event driven "task" using EV_captureEvents.
So, if you simple call EV_eventLoop in the your program, without previous usage of
EV_captureEvents or EV_startApp,
you will have an illusion that you are not in the your program but in the home screen, because
all collected events will be dispatched to the "Home screen" application. Note that in this
case, there is no way to exit this loop, and your program will stay "resident" and
"locked" in the memory forever, although you will not be aware of the fact that your program
is still "running" - you will be able to execute everything,
including running other programs etc.
As EV_eventLoop enters the endless loop, the only method (and this is the proposed method in
TIOS) to exit the loop is to throw an error from the user event handler installed using
EV_captureEvents. This is possible because in the event loop
there is no error handlers in place, so ER_throw passes
control to the previous level of error handler. In terms of normal operation (i.e. while you
are typing in the home screen) this is handled
by EV_centralDispatcher, which restarts the event loop.
However, in custom event handling it is used to return from the event loop to the calling code.
To achieve this, you need to catch errors using ER_catch
or using TRY...ONERR...ENDTRY
construction. So, the typical usage of EV_eventLoop function in user programs is:
EV_captureEvents (UserHandler);
TRY
EV_eventLoop (); // The only way to exit from this is
ONERR // to throw an error from the event handler!
EV_captureEvents (NULL);
ENDTRY
Of course, user handler must decide what to do with events dispatched by EV_eventLoop. Very
nice example of usage of this methodology is given in textedit.h
header file. Another example may be found with the description of
CAT_dialog function.
These principles are used often in TIOS. For example, error dialogs are principally
implemented as follows (although there are no obvious reasons why events are used in this
example):
void ERD_EventHandler (EVENT *ev)
{
if (ev->Type == CM_KEYPRESS)
switch (ev->Key.Code)
{
case KEY_ENTER: ER_throw(1);
// Exit from event loop: ENTER key pressed
case KEY_ESC: ER_throw(2);
// Another exit: ESC key pressed
case KEY_OFF: EV_defaultHandler (ev);
// OFF key pressed: allow the machine to be switched off
}
}
short ERD_dialog (short err_no, short prog_flag)
{
EV_captureEvents (ERD_EventHandler);
// Display the dialog
TRY
EV_eventLoop();
ONERR
switch(errCode)
{
case 1: // Restore the screen and return KEY_ENTER code
case 2: // Restore the screen and return KEY_ESC code
}
ENDTRY
}
To exit from EV_eventLoop, the best idea is to throw error codes less than 8, as they are
never used as error codes in normal error handling.
Enters the main controlling loop of the TIOS.
As the name suggests this is the main controlling loop of the entire TIOS. This
functions initializes all installed applications by sending CM_INIT
event to them, starts the "Home screen" application, then calls EV_eventLoop
under an error handler, so if any error appeared during execution of the event loop, it will
be catched by the error handler, which will first dispatch the error code to
ERD_process then restart the event loop.
NOTE: As far as I know, there is no any need to call this function from your program. This
will enter the endless loop, which can not be broken even by throwing an error from the
event handler (the method used to exit from EV_eventLoop), because
the event loop is now executed under the internal error handler (maybe the only method to exit
from such loop is using longjmp from the event handler, but
I don't believe that such barbaric method would leave the system in a stable state).
short EV_getAppID (char *TaskName);
Finds a task ID number for an application.
EV_getAppID returns a task ID number for the task/application whose internal name is
TaskName, or returns -1 if the application is not found.
Each application (including both built-in applications and external
Flash applications) has a unique internal name (max. 8 characters). This function
is introduced to make compatibility with all AMS versions, because
task ID numbers are inconsistent between AMS versions. On AMS 1.xx, built-in flash
applications has fixed ID numbers attached to them, but on AMS 2.xx the task ID is
simply the handle of the application control block (this is why it is quite hard to
add flash applications on AMS 1.xx). So, always use EV_getAppID to determine the
task ID number for an application Internal names of built-in applications are given
in the following table:
Application name | Internal name |
Home screen | TIHOME |
Y= Editor | TIEQUED |
Window Editor | TIWINDED |
Graph | TIGRAPH |
Table | TITABLED |
Data/Matrix Editor | TIDMED |
Program Editor | TIPRGMED |
Text Editor | TITEXTED |
Numeric Solver | TIINSLVR |
Self Test | TISLFTST |
NOTE: Although this function was not officially introduced before AMS 2.xx, it is here
implemented to work even on AMS 1.xx! However, there is one difference between this
function, and the function with the same name in Flash Studio SDK. This implementation
of EV_getAppID returns -1 if the application is not found, but EV_getAppID from Flash
Studio SDK returns zero under the same conditions. The convention used in Flash Studio
is not consistent with the fact that "Home screen" application has the ID number 0 on
AMS 1.xx. That's why the value for "not found" is slightly changed in this implementation.
void EV_sendEvent (short TaskID, EVENT *event);
Sends an event message from the current side.
EV_sendEvent sends the event message described in the structure pointed to by event
to the task/application with ID number TaskID (see below for more info about task
IDs). Note that the user need to pre-fill only Type field of the event structure
and eventually extra field (if the message has extra information attached). All
other fields will be filled by EV_sendEvent function before sending the message.
The Type field of the event structure is interpreted as following:
- If Type >= 0x700, the message is an event command message (like CM_KEYPRESS,
CM_WPAINT, etc. These codes are defined in enum EventIDs. These
messages are the most common messages, and such messages are the most usable messages
in user applications. See EventIDs for detailed description of meaning
of such messages.
- If 0x500 <= Type < 0x700, the message is a custom command message. The interpretation
of such messages is strictly task-dependent. The TIOS uses such messages in dialogs, etc.
- If Type < 0x500, XR_string (see XR_stringPtr)
is send as the message. This is used for internal purposes in TIOS.
Here is the description what EV_sendEvent exactly does:
- If EV_hook pointer is not NULL, then a routine
pointed to by it is called, passing event to it.
- If there is an user event handler installed (using EV_captureEvents),
the user handler is called, and event is passed to it. In this case, parameter
TaskID is ignored. The only exception is when the message is CM_WPAINT.
In this case, the user handler is called only if TaskID is AP_NULL.
- If there is no user event handler installed, the message event is send to the
default application-dependent event handler, which is determined by parameter TaskID.
Note that default application-dependent event handler will not be called if there is an
user event handler installed. The exception is when the message is CM_WPAINT.
This message is always dispatched to the default application-dependent handler, except if
TaskID is AP_NULL.
Note that task ID numbers are inconsistent between AMS versions, so always call
EV_getAppID before to determine an appropriate task ID,
or use special task IDs AP_CURRENT,
AP_RUNNING and AP_NONE,
which are AMS-independent.
If you want to send an event from the user event handler, you can enter into
the infinite recursion. Here is an example how to avoid this. The following program will
change the behaviour of the ENTER key to behave like pressing DIAMOND+ENTER.
So, run the following program. After this, the ENTER key will behave like DIAMOND+ENTER
(note that the program is "resident": it is active for whole time, although you have
feeling that you are in "Home screen" for example). The ENTER key will remain redefined
until the user press DIAMOND+ENTER. After this, the original function of the ENTER key
is restored, and the program finishes working.
#include <tigcclib.h>
int _ti89, _ti92plus;
void Handler (EVENT *ev)
{
if (ev->Type == CM_KEYPRESS)
{
if (ev->extra.Key.Code == KEY_DIAMOND + KEY_ENTER)
ER_throwVar (1);
if (ev->extra.Key.Code == KEY_ENTER)
ev->extra.Key.Code = KEY_DIAMOND + KEY_ENTER;
}
EV_captureEvents (NULL); // Send the event to the default
EV_sendEvent (AP_CURRENT,ev); // application handler, but be careful
EV_captureEvents (Handler); // to avoid infinite recursion!
}
void _main (void)
{
EV_captureEvents (Handler);
TRY
EV_eventLoop();
ONERR
EV_captureEvents(NULL);
ENDTRY
}
Of course, this program is not extremely useful: the much easier method to achieve the same
functionality is to turn the calculator in "APPROX" mode. But, note that this is just an
example, which should give you an idea how to redefine the keyboard.
NOTE: The destination application does not have to be started or active to receive
messages. You should first start the application using EV_startApp
if it is important that the application be on the screen before it receives an event.
void EV_sendEventSide (short TaskID, EVENT *event, unsigned short Side);
Sends an event message from the given side.
EV_sendEventSide is very similar to EV_sendEvent. The only difference
is in the fact that EV_sendEventSide fills the field Side of the event structure with
the value of parameter Side. EV_sendEvent fills this
field with the current side number (0 = left or top side, 1 = right or bottom side). This
field allows message handler to determine from which side (of course, in split screen mode)
the message is sent, so it allows some primitive kind of multitasking.
Processes an event message using the default handler.
EV_defaultHandler performs some default actions with most common messages (event is the
pointer to the message which need to be processed). This function is very useful in user event
handlers, and it is often called to process any unhandled messages in handlers. Not all
messages are supported in EV_defaultHandler. This is a list of supported message types (unsupported
types are simply ignored) together with the description of the action performed by EV_defaultHandler:
CM_ACTIVATE |
Registers and starts the menu for the running application (see EV_registerMenu). |
CM_DEACTIVATE |
Ends custom and normal menus. |
CM_KEYPRESS |
Handles tokens, system and mode keys. This is maybe the most useful action performed by EV_defaultHandler.
If the keypress is a simple key (i.e. a single character), nothing will happen. If the keypress
is a token (like "sin", "ln" etc.), the appropriate string is send (as a
CM_STRING message) to the
application. The summary effects will be that the application will receive token as a sequence
of single keypresses. So, tokens are all sent via EV_sendString and
do not have to be processed as single keypresses (note that this will not cause problems if called
from user event handlers, although it may cause the recursion; see textedit.h header
file for an useful example). If the keypress is system or mode key (see
QSysKey and QModeKey), the
corresponding action associated with the key (for example, opening a menu or a dialog) will
be performed (see the example below this table).
The chosen menu item is then sent as a CM_STRING message to the current
application (note however that VAR-LINK uses a CM_HSTRING message
instead), except for toolbar menus, where an appropriate menu ID is send as a message.
Command keypresses STO, RCL, SWITCH, MODE, APPS, MEM, INS, CUT, PASTE etc. and OFF key (code
4363) are also handled via this handler, and all of them cause usual actions (keypresses like
CUT, PASTE etc. only send an appropriate message to the application).
|
CM_STRING |
Pastes the string in the event paste buffer. More precise, it sets an internal
static pointer to points to event->extra.pasteText
and does not nothing more. The event loop (see EV_eventLoop)
will then send the string as individual keypresses to the current application.
This means that the paste buffer is exported from the code, so this allows pasting
large amounts of text.
|
CM_HSTRING |
Frees the memory associated with handle event->extra.hPasteText. |
CM_STORE |
Sends CM_KEYPRESS event filled with key code 22 (right arrow) to the current application. |
CM_RECALL |
Performs usual actions for the RCL key (open Recall dialog, etc.).
After execution of the Recall dialog, the content of the variable is sent to the current
application as a CM_STRING message.
|
Useful examples for this functions may be found in textedit.h header
file. Here is another simple example which ilustrates how you can open the "CHAR" menu. This
may be useful if you want to make your user input routine which allows inserting extra characters:
EVENT ev;
...
ev.Type = CM_KEYPRESS;
ev.extra.Key.Code = KEY_CHAR;
EV_defaultHandler (&ev);
After execution of the menu, the selected character will be send as the event to the
current application (it may be captured through an user event handler).
Clears the event paste buffer.
EV_clearPasteString clears event paste buffer, i.e. clears the static pointer
to the paste buffer (see default action for CM_STRING message in
EV_defaultHandler), and eventually frees the memory
occupied for dinamically pasted string (sent via CM_HSTRING
message).
Sends XR string to the running application.
EV_sendString is an internal function which sends the XR string (see
XR_stringPtr) to the running application via
CM_STRING message. XR_String is the code of
the XR string which will be send.
Waits for the keypress, then fills an event structure with the keypress.
EV_getc is a function similar like ngetchx. It waits for
a keypress, and returns the keycode of the keypress. But, in addition to
ngetchx, it also fills the structure pointed to by event
with appropriate CM_KEYPRESS event. Parameter busy
may be ACTIVITY_IDLE, ACTIVITY_BUSY, ACTIVITY_PAUSED or ACTIVITY_NORMAL (these
constants are defined in enum ST_ACTIVITIES). This
parameter determines the indicator in the status line which will be displayed
(see ST_busy for more info).
If there is no keypress and the cursor timer expires (cca 0.5 seconds), the
message CM_BLINK is stored in the event structure
instead, and the function returns zero (no keypresses). Also, this routine
puts the calculator into low power mode until a character is available,
and it will automatically power down the calculator if a key has not
been pressed after a few minutes.
Repaints the topmost window.
EV_paintOneWindows searches through a linked list of windows (see
wingraph.h header file) for the first window
which has WF_DIRTY flag set. If the founded window
is visible (i.e. if WF_VISIBLE flag is set), the
CM_WPAINT message is sent to the application which
is the owner of the window (note that WinOpen
stores the task ID of the current application in TaskID field of the
WINDOW structure). See also notes about
EV_sendEvent. After sending this message,
WF_DIRTY flag of the window is cleared, and this flag is
set in all other windows in the linked list of windows which overlap with this
window (because repainting of this window may cause trashing of another windows).
EV_paintOneWindow returns TRUE if the window was "painted"
(more precise, if CM_WPAINT message is sent), else
returns FALSE (i.e. if none to paint).
Here is an example which ilustrates that painting of all TIOS windows is "event
driven". Suppose that you make very simplified loop which "simulates" normal behaviour
of the calculator when it is in the home screen:
while (TRUE)
{
EV_getc (ACTIVITY_NORMAL, &ev);
EV_sendEvent (AP_CURRENT, &ev);
}
If you try this program, you will notice that although you can type in statements, execute
user programs etc. from this loop, nothing happens on the screen when you type in
2 + 3 <ENTER> (i.e. result 5 is not displayed). This is because the
"Home screen" application didn't receive a message which forces redrawing of the Home screen.
You can see that everything will be correct if you make the following loop:
while (TRUE)
{
EV_getc (ACTIVITY_NORMAL, &ev);
EV_sendEvent (AP_CURRENT, &ev);
EV_paintOneWindow ();
}
Repaints all windows.
If painting is enabled (see EV_suspendPainting),
EV_paintWindows repeatedly calls EV_paintOneWindow
until it returns FALSE (no more to paint). So, the effect will
be "repainting" of all "dirty" windows.
Suspends window painting.
EV_suspendPainting sets a flag which indicates that window painting is suspended
(see EV_eventLoop and EV_paintWindows).
Returns PAINTING_ENABLED or PAINTING_SUSPENDED
depending of whether painting was enabled or disabled before calling this function (these constants
are defined in enum PaintFlags), so the returned value may be later
used in EV_restorePainting function.
Restores previous state of window painting.
EV_restorePainting suspends or enables window painting, depending of whether blockPaint
is PAINTING_ENABLED or PAINTING_SUSPENDED
(these constants are defined in enum PaintFlags). The main purpose of
this function is to restore previous state after usage of EV_suspendPainting
function. EV_restorePainting also returns previous state of painting enable flag
(PAINTING_ENABLED or PAINTING_SUSPENDED)
before calling this function.
WIN_RECT *EV_getSplitRect (unsigned short Side);
Gets the screen rectangle for a given side.
EV_getSplitRect consults various calculator mode settings ("Split Screen": "FULL",
"LEFT-RIGHT" or "TOP-BOTTOM" and "Split Aspect Ratio": "1:1", "1:2" or "2:1") to determine
dimensions of the rectangular area in which the application will be executed. Parameter
Side determines wanted side, and it need to be s 0 or 1 (0 = left or top side,
1 = right or bottom side). EV_getSplitRect returns the static pointer to the
SCR_RECT structure which describes the determined rectangular
area.
Starts a particular task in the running application.
EV_startTask sends CM_STARTTASK message to the running application.
Field StartType of the event structure will be filled from StartType
parameter of this function (this is the only message in which StartType field
is significant). Field r (in extra field) of the event structure will be
filled from the result of executing EV_getSplitRect function
(with current side given to it as the parameter).
How StartType will be interpreted, depends of the concrete application. Usually,
three types of "starting" are supported: AP_START_CURRENT,
AP_START_NEW and AP_START_OPEN (these
constants are defined in enum StartTypes. For example, Text and
Data/Matrix editor may be started in three submodes: "Current", "Open" and "New".
Under normal circumstances, you should start another task with
AP_START_CURRENT.
Starts an application from any state.
EV_startApp is dedicated to "start the application". It changes current application to
TaskID and sends a sequence of messages to it (how they will be interpreted
depends of the concrete application), so this command may be used for changing the
current application.
It is not likely that following information will be very useful for you (except if
you are an expert who wants to make a new high perfomance flash application), but anyway
here is the pseudo-code which describes what exactly EV_startApp does:
if TaskID is equal to the current application
if StartType is AP_START_CURRENT
send CM_START_CURRENT to the current application
else {change task}
send CM_UNFOCUS, CM_DEACTIVATE and CM_ENDTASK to the current application
call EV_startTask, passing StartTask to it
send CM_ACTIVATE and CM_FOCUS to the current application
endif
else {new application}
send CM_UNFOCUS and CM_DEACTIVATE to the current application
if TaskID is equal to the application on the other side
and if the calculator is in "two-graph" mode
or TaskID is not "Graph", "Window Editor", "Table" nor "Y= Editor"
set current application to TaskID
invert current side
call EV_notifySwitchGraph
if StartType is not AP_START_CURRENT
send CM_ENDTASK to the new application
call EV_startTask, passing StartTask to it
endif
else
send CM_ENDTASK to the current application
set current application to TaskID
call EV_startTask, passing StartTask to it
endif
send CM_ACTIVATE and CM_FOCUS to the new application
endif
Under normal circumstances, you should start another application with
StartType set to AP_START_CURRENT.
NOTE: Task ID numbers are inconsistent between AMS versions (see EV_getAppID for
more info). So, if you for example want to start the "Numeric Solver" application, the AMS-independent
way for doing this is
EV_startApp (EV_getAppID ("TIINSLVR"), AP_START_CURRENT);
Also, some common applications (like "Graph", "Table" or "Home screen") may be started
safely using some commands from bascmd.h header file.
Starts the given side.
EV_startSide first sends CM_STARTTASK message to the application
with ID number TaskID. Field StartType of the event structure will be set
to AP_START_CURRENT, and field r (in extra field)
of the event structure will be filled from the result of executing EV_getSplitRect
function (with Side given to it as the parameter). See EV_startTask.
This is all if the current side is not equal to Side, else messages
CM_ACTIVATE and CM_FOCUS will also be send
to the task TaskID and side Side (using EV_sendEventSide).
EV_startSide also fills the variable pointed to by saveTaskID with TaskID (I
don't know what is purpose of this). See also EV_startApp.
Performs switching of sides.
EV_switch performs side switching. It does nothing if the current "Split Screen" mode is "FULL".
Else, it sends CM_UNFOCUS and CM_DEACTIVATE messages,
inverts current side, sets the current application to the application on the other side, calls
EV_notifySwitchGraph, and finally, sends
CM_ACTIVATE and CM_FOCUS messages to the
new application.
NOTE: In AMS 2.xx, this function is extended to allow switching between the current application
and the application which last ran before the current application.
Notify appropriate applications of graph switching.
EV_notifySwitchGraph does nothing if the calculator is not in "two-graph" mode, else sends
CM_SWITCH_GRAPH message to "Graph", "Window Editor", "Table"
and "Y= Editor" applications (these applications are so-called "multigraph" applications).
Attaches a menu to an application.
Applications can register toolbar menus with the system event handler. EV_registerMenu
registers the toolbar menu pointed to by MenuPtr with the current application.
MenuPtr is exactly the same pointer as expected in MenuBegin
function. Note that registering the menu will not automatically display nor activate the menu.
The application will draw the menu (using MenuBegin) on
receiving of CM_ACTIVATE message. So if you for example attach a new
menu on the "Home screen" application, you need to send CM_ACTIVATE
message to it too. Also, before calling EV_registerMenu, CM_ACTIVATE
message should to be send to the application.
When a menu is attached to the application, each keypress event (CM_KEYPRESS
message) which represents keys F1, F2 etc. activates the menu (more precise, it is dispatched
to MenuKey function). After execution of
MenuKey, the value returned from it (this is ret_val
of the selected item, see MenuAddText) is send as the event
to the application. So, ret_val for each menu item must be carefully planed: if you
want to have "Cut" option in the menu, its ret_val needs to be 0x720
(CM_MENU_CUT). Options which represents tokens (as in "Algebra" and
"Calc" submenus) have ret_val less than 0x500, because tokens are send as XR strings
(see XR_stringPtr). If you planed to create a serious
event driven applications which have toolbar menus (flash application for example), it must
behave on the same way (i.e. its event handler must process F-key events as described), and
it must respond on CM_ACTIVATE message as described above. Of course, how to
put an application in Flash ROM without TI certificate and TI professional SDK is greater
problem...
NOTE: Sending NULL to EV_registerMenu unattach the toolbar menu from the
application. Here is a dirty example which first removes menu from the "Home screen" application,
then changes parameters of "Home screen" parent window to expand "Home screen" stack area into
the menu area (but note that only reset would restore the original state after execution of
this program):
EVENT ev;
ev.Type = CM_DEACTIVATE;
EV_sendEvent (AP_CURRENT, &ev);
EV_registerMenu (NULL);
ev.Type = CM_ACTIVATE;
EV_sendEvent (AP_CURRENT, &ev);
FirstWindow->Client.xy.y0 = 0;
FirstWindow->Window.xy.y0 = 0;
FirstWindow->Clip.xy.y0 = 0;
Changes the status (active/inactive) of a toolbox in the menu associated with current application.
EV_setFKeyState changes the status of the toolbox Item (0 = first, 1 = second
etc.) which belongs to the menu associated with the current application
(see also MenuTopStat).
State is a Boolean value: when it is TRUE, the toolbox will be
active, and when it is FALSE, the toolbox will be inactive (i.e. it will be
dimmed, and it can not be selected).
EV_setFKeyState also can force redrawing of the menu after changing state: to do this,
set Boolean parameter Redraw to TRUE.
Avoid menu redraw flicker when enabling/disabling several
function keys by specifying FALSE for redraw in all but the
last call to this routine.
Changes the status (active/inactive) of a menu command in the current application.
EV_setCmdState is similar to EV_setFKeyState, but works with
command pulldown menus associated with main toolbar menu which belongs to the current application.
EV_setCmdState changes status of the command item which has its ret_val
(see EV_registerMenu) equal to the cmd. For example,
if you execute
EV_setCmdState (CM_MENU_CUT, FALSE);
in your program, you will see that "Cut" command in the "Home screen" menu will be disabled
(note that "Home screen" is the current application if you didn't use EV_startApp
in your program). CM_MENU_CUT is, of course, code of "Cut" menu command.
See also MenuSubStat.
Checks/unchecks menu command in the current application (???).
This is suspicious function related to (also suspicious) MenuCheck
from menus.h header file.
In according to info presented by Gareth James, EV_setCmdCheck checks/unchecks items
in command pulldown menus associated with main toolbar menu which belongs to the current
application. EV_setCmdCheck should check/uncheck the command item which has its ret_val
(see EV_registerMenu) equal to the cmd.
State should be a Boolean value: TRUE
for checking and FALSE for unchecking, although value 2 is also considered
from some reason. But, note that I didn't succeed to make this function working,
I don't know why. Any info is welcomed.
Fills in options structure from current mode settings.
MO_currentOptions fills the structure pointed to by ModeSettings
from current mode settings. It should always be called before using MO_digestOptions.
Sets default mode settings.
MO_defaults resets options structure (i.e. fills the structure pointed to by
ModeSettings with default settings), then calls
MO_digestOptions to dispatch these settings to
applications.
Updates system mode settings from options structure.
MO_digestOptions "digests" options from ModeSettings structure
into the various TIOS system variables. It should be changed after each change of options
structure to notify the calculator about changes. This routine may change the status line
indicators. It also notifies all applications about eventual changes, if there was any
essential changes (using MO_notifyModeChange). If new
mode settings need change of current application or side, it may also quit an application
(see MO_sendQuit), switch sides, start a new applications/tasks
etc. which in fact means sending a sequence of messages to applications (see
EV_startApp etc.).
Parameter Folder is the index (ordinal number) of the current folder in the folder
list. Under normal conditions, you should always pass zero to this parameter. The mode dialog
box calls MO_digestOptions with non-zero argument to indicate which folder name is highlighted
in the "Current Folder" popup menu.
Checks whether a task is multigraph task.
MO_isMultigraphTask returns TRUE if the task with ID number TaskID
is "Y= Editor", "Window Editor", "Graph" or "Table" (these tasks are tasks which may
be doubled in two different part of the screen), else returns FALSE.
Sends mode change notify message to all applications.
MO_notifyModeChange sends CM_MODE_CHANGE message to all applications
(note that "Graph" application will first receive this message). This function also has one
parameter Flags which is ignored on AMS 1.xx, but used in AMS 2.xx. It contains a
set of flags which describes what exactly was changed. This parameter is attached to message
in the extra field of the message, so it gives more info to applications what they
need to check. At the moment, I don't have exact information what each bit in Flags
represent.
Quits an application on given side.
MO_sendQuit quits an application on side Side (0 = left/top, 1 = right/bottom).
This is what pressing on QUIT key does.
More precise, if Side is equal to the current side, the side will receive
CM_UNFOCUS and CM_DEACTIVATE messages.
After this, the application will receive CM_ENDTASK message.
Finally, the application on side Side will be set to CM_NULL.
If the application on side Side is already CM_NULL,
nothing will be performed.
NOTE: If you don't understand what "quiting" means, try MO_sendQuit(AP_CURRENT, 0) from
your program to "quit" the "Home screen" application.
You will notice that the menu will dissappear. Later, executing commands will not show results
in the home screen, because "repainting" of the "Home screen" window will be suspended
(the application is set to CM_NULL).
Executes "MODE" dialog.
MO_modeDialog opens the "MODE" dialog, and allows the user to set mode options. If the user
pressed ENTER key, MO_digestOptions will be called to
"digest" new settings to TIOS. If the user pressed ESC key, nothing will happen. In each
case, the dialog will be removed from the screen after pressing ENTER or ESC.
Starts "CATALOG" dialog "applet".
"CATALOG" dialog is an event driven "applet". CAT_dialog draws the dialog on the screen, installs
its own event handler, then exits (without stopping the caller program). It does not enter into a
loop (like normal dialogs does) which ends only on pressing ENTER or ESC. Its event handler
restores previously installed handler after pressing ENTER or ESC, but if the pressed key was ENTER
key, the selected command from the catalog is send as CM_STRING message
after restoring the user handler (which need to be captured via user event handler). That's
why it is not so easy to use CAT_dialog in user programs, but this is also not very hard.
Here is an example, which opens a "CATALOG" dialog, and displays in the help screen a message
which tells what the user selected from the catalog:
#include <events.h>
#include <string.h>
#include <statline.h>
int _ti89, _ti92plus;
char *ptr = NULL; // Global data must be initialized in "nostub" mode
void Handler (EVENT *ev)
{
if (ev->Type == CM_STRING) ptr = ev->extra.pasteText;
ER_throwVar (1);
}
void _main (void)
{
EVENT ev;
char buffer[100];
ptr = NULL;
EV_captureEvents (Handler);
CAT_dialog ();
TRY
EV_eventLoop ();
ONERR
EV_captureEvents (NULL);
ENDTRY
if (ptr != NULL)
{
sprintf (buffer, "You selected \"%s\".", ptr);
ST_helpMsg (buffer);
}
else ST_helpMsg ("You pressed ESC.");
ev.Type = CM_UNFOCUS; // This is more due to some
EV_sendEvent (AP_CURRENT, &ev); // aesthetical reasons
}
Note that it is important that EV_captureEvents must be called
before calling of CAT_dialog. This example is a good test whether you understand principles of
event handling or not.
Starts "ABOUT" dialog "applet".
"ABOUT" dialog is an event driven "applet", which works exactly like "CATALOG" dialog applet.
See CAT_dialog for more info about event driven dialogs.
Global variables
EV_hook is a global pointer variable which points to the "hook" event handler (or
NULL if there is no "hook" handler installed. Hook handler hooks
events like EV_captureEvents, however, the application
handler (either default application handler or user handler installed with
EV_captureEvents) is still called afterwards (see
EV_sendEvent for more info. This is probably meant for
debugging purposes as it is never used in TIOS.
Using EV_hook you can capture all messages and process them as you like, without
overriding current handlers. So, you can use it to change behaviour of some events,
or add new functionalities. DoorsOS for example uses EV_hook to add SHIFT+ON feature.
You also can hook the APPS key and display a different menu in which your application
set will be listed (then you can start your own event driven application via
EV_captureEvents). If you understood principles
described in this info file, this is not so hard. If you didn't understand what
is written here, don't try to play with this...
MO_OPTIONS *const ModeSettings;
ModeSettings is the constant pointer to MO_OPTIONS structure,
which keeps all mode settings together. But note that this structure is "auxilary": TIOS
consults other variables to check various mode settings when necessary. So, values in this
structure are actual only after calling MO_currentOptions, and
after changing one or more values in this structure, you need to call
MO_digestOptions to inform TIOS about changes. So, if you
want for example to change "Display Digits" settings to "FIX 4" and "Complex Format" to
"POLAR", you should do:
MO_currentOptions ();
ModeSettings->Fix = 5;
ModeSettings->Complex = 3;
MO_digestOptions (0);
Predefined types
Bool is enumerated type for describing true or false values. It is defined as
enum Bool {FALSE, TRUE};
EventIDs is enumerated type for describing ID numbers of system messages (they are
stored in Type field of EVENT structure. All possible
ID numbers (everything is in hex) are described in the following table. "Extra field" describes which
subfield in extra union field of EVENT structure
is used for storing extra information (if any).
Code |
Message name |
Description |
Extra field |
700 |
CM_IDLE |
Idle (idle is called after message sent).
This message is sent to the active application when there are no other
events to process. The application might use this event to
take care of some background processing or update an animated display.
This message is used for example in spinning of 3D graph. |
|
701 |
CM_INIT |
Init application. This message is sent
from EV_centralDispatcher after a reset
or when batteries are inserted. |
|
702 |
CM_STARTTASK |
Start Task (in rect r). This message is sent
to a task when it is being started. r is a rectangle with the requested window
location and size chosen by the user from the mode screen settings.
The application passes it to WinOpen to create
its initial window. StartType field of the message is checked here
(see EV_startTask), because some applications display a
"Current/Open/New" submenu on the APPS menu, so this field is needed to tell
the application which submenu command was selected by the user. |
r |
703 |
CM_ACTIVATE |
Activate. Applications usually respond to this message by
highlighting their window border to make it apparent to the user which application
is active, by setting menu command states,
and by updating (or activating) registered menus (see EV_registerMenu.
|
|
704 |
CM_FOCUS |
Focus. Applications usually respond to this message by getting Mode options, and by
giving the focus to the application editor (see TE_focus
in textedit.h header file).
This usually means making the cursor flashing. |
|
705 |
CM_UNFOCUS |
UnFocus. Usually used on switching sides.
When used on the text editor, it means turning of the cursor flashing.
|
|
706 |
CM_DEACTIVATE |
DeActivate.
This message is sent to the active application to inform it that it no longer
holds the interactive center of attention. Applications usually respond to this
message by hiding menus and releasing the memory occupied by them. |
|
707 |
CM_ENDTASK |
End Task. Applications usually respond to this message by hiding windows and doing
various cleanups. |
|
708 |
CM_START_CURRENT |
Start current.
This message only notifies the current application that the user has chosen to
start the same application again. Usually ignored.
|
|
710 |
CM_KEYPRESS |
Keypress. This is the most common event. Note that a lot of system and mode events
(opening system menus, dialogs etc.) are also processed as keypresses. They all have correct
keypresses attached to them (usually DIAMOND + ...). Tokens
are usually send via EV_sendString and do not have to be
processed as single keypresses. All special keypresses may be passed to
EV_defaultHandler for further processing.
|
Key |
720 |
CM_MENU_CUT |
Menu command: Cut.
Dedicated for cutting selected text to the clipboard.
All similar (text editing) events should eventually be handled by
TE_handleEvent (the default text editor handler).
|
|
721 |
CM_MENU_COPY |
Menu command: Copy. Dedicated for copying selected text to the clipboard.
Should eventually be handled by the default text editor handler. |
|
722 |
CM_MENU_PASTE |
Menu command: Paste.
Dedicated for pasting text from the clipboard to the edit buffer at the cursor position,
replacing any eventually selected text.
Should eventually be handled by the default text editor handler.
|
|
723 |
CM_STRING |
Paste static (constant) text into the event paste buffer (in fact, it only sets a pointer
to PasteText). See EV_eventLoop and EV_sendString. |
PasteText |
724 |
CM_HSTRING |
Paste dynamic text, associated with a handle.
The handle is released back to the heap by the default text edit handler after the paste is
complete.
|
hPasteText |
725 |
CM_DEL |
DEL (backspace) keypress. Dedicated for deleting selected text,
or one character to the left of the cursor if no text is selected.
Should eventually be handled by the default text editor handler.
|
|
726 |
CM_CLR |
CLR keypress.
Dedicated for clearing selected text (if no text is selected, clear from cursor
to end of edit buffer, and if cursor is at end of edit buffer, clear all
text from edit buffer).
Should eventually be handled by the default text editor handler.
|
|
727 |
CM_MENU_CLEAR |
Menu command: Clear.
The application should decide decides what it means.
|
|
728 |
CM_MENU_FIND |
Menu command: Find. The application should decide decides what it means. |
|
730 |
CM_INSERT |
Insert key. Dedicated for
switching between text insert mode and overstrike mode.
Should eventually be handled by the default text editor handler.
|
|
740 |
CM_BLINK |
Flash cursor (0.5 sec timer expired, see EV_eventLoop). |
|
750 |
CM_STORE |
"Store" keypress. The default handler convert this message to the right arrow character. |
|
751 |
CM_RECALL |
"RCL" keypress. The default event handler
displays a dialog box for the user to enter the name of a
variable to recall. The chosen variable’s contents are pasted
at the edit cursor.
|
|
760 |
CM_WPAINT |
Paint window. Pointer to a window which need to be painted is attached.
Applications should check to see if it belongs to the application and to redraw it if it is.
See EV_paintWindows. These are not sent to the capturing hook,
unless an application ID number is set to CM_NULL (force redraw).
WinOpen stores the current application ID number
in TaskId field of WINDOW structure. |
w |
770 |
CM_MENU_OPEN |
Menu command: Open... (the application should decide how to handle
this and similar event messages; there are no default actions for them). |
|
771 |
CM_MENU_SAVE_AS |
Menu command: Save Copy As... |
|
772 |
CM_MENU_NEW |
Menu command: New... |
|
773 |
CM_MENU_FORMAT |
Menu command: Format... |
|
774 |
CM_MENU_ABOUT |
Menu command: About... |
|
780 |
CM_MODE_CHANGE |
Notify Mode Change (see MO_notifyModeChange). |
|
781 |
CM_SWITCH_GRAPH |
Notify Switch Graph (this message is sent to "Graph", "Window Editor",
"Table" and "Y= Editor" applications only). |
|
7C0 |
CM_GEOMETRY |
Geometry Open Data. |
|
StandardTaskIDs is enumerated type which describes standard task "magic" numbers
which works independently on actual task ID numbers, so they are AMS-independent
(see EV_sendEvent). It is defined as
enum StandardTaskIDs {AP_NULL = -3, AP_RUNNING = -2, AP_CURRENT = -1};
"Running" application is the application which has attached and activated toolbar menu (this
does not need to be equal to "Current" application). "Null" application is special value used for
overriding CM_WPAINT block (see EV_sendEvent).
See also MO_sendQuit.
StartTypes is a pseudo-enumeration which describes standard "start types" used in
EV_startTask command, on such way to be compatible with
all AMS versions. It is defined using macros, but it behaves as it is defined as
enum StartTypes {AP_START_CURRENT = 0, AP_START_NEW = 0x10,
AP_START_OPEN = 0x20, AP_START_ERROR = 0x30};
on AMS 1.xx, and
enum StartTypes {AP_START_CURRENT = 0, AP_START_NEW = 1,
AP_START_OPEN = 2, AP_START_ERROR = 3};
on AMS 2.xx.
PaintFlags is enumerated type which described constants used in
EV_suspendPainting and
EV_restorePainting functions. It is defined as
enum PaintFlags {PAINTING_ENABLED = 0, PAINTING_SUSPENDED = 2}
WinFlags is enumerated type for describing various flags which control the window
manager. These flags are used in WinOpen command,
and they are stored in WINDOW structure.
Usage of
some of them are still not very clear to me. See WinOpen
to see what I know about them (any additional info is welcomed). WinFlags is defined as
enum WinFlags {WF_SYS_ALLOC = 0x0001, WF_STEAL_MEM = 0x0002,
WF_DONT_REALLOC = 0x0004, WF_ROUNDEDBORDER = 0x0008,
WF_SAVE_SCR = 0x0010, WF_DUP_SCR = 0x0020, WF_TTY = 0x0040,
WF_ACTIVE = 0x0080, WF_NOBORDER = 0x0100, WF_NOBOLD = 0x0200,
WF_DUP_ON = 0x0400, WF_VIRTUAL = 0x0800, WF_TITLE = 0x1000,
WF_DIRTY = 0x2000, WF_TRY_SAVE_SCR = 0x4010, WF_VISIBLE = 0x8000};
WF_DIRTY and WF_VISIBLE are used in event driven applications, see EV_paintOneWindow
function.
ST_ACTIVITIES is enumerated type which contains some constants used in EV_getc
function. It is defined as
enum ST_ACTIVITIES {ACTIVITY_IDLE, ACTIVITY_BUSY, ACTIVITY_PAUSED,
ACTIVITY_NORMAL};
For more info, see function ST_busy and enum ST_MODES
from statline.h header file.
NULL is a null-pointer value, defined as (void *) 0.
EVENT_HANDLER is a pointer type, which points to a void function (procedure) which
accepts one parameter which is a pointer to EVENT type. It is
defined as
typedef void (* EVENT_HANDLER) (EVENT *);
See EV_captureEvents and EV_hook
for more info.
HANDLE is a type which represents handles associated to allocated memory
blocks. It is defined as
typedef unsigned short HANDLE;
EVENT is a structure which describes an event message which is used in event driven applications.
It is defined as
typedef struct EventStruct
{
unsigned short Type; // ID code of the message, see EventIDs
unsigned short RunningApp; // Task ID of the sender of the message
unsigned short Side; // Side from which message is send
unsigned short StatusFlags; // Status line flags
union
{ // Message-dependent extra information: see EventIDs
WINDOW *w;
WIN_RECT *r;
char *pasteText;
HANDLE hPasteText;
struct
{
unsigned short Mod; // Key modifiers (SHIFT, etc.)
unsigned short Code; // Key code
} Key;
} extra;
unsigned char StartType; // Used only in CM_STARTTASK message
} EVENT;
MO_OPTIONS is a structure which collects all system mode settings together. All fields
in this structure are in fact indices of appropriate menu options in "MODE" dialogs. The only
exceptions are fields Split1App and Split2App: they contains task ID
numbers of appropriate applications. This structure is defined as
typedef struct
{
unsigned short CurrentFolder;
unsigned short SplitScreen;
unsigned short NumGraphs;
unsigned short Graph1; // Graph mode for first application
unsigned short Graph2; // Graph mode for second application
unsigned short Split1App;
unsigned short Split2App;
unsigned short SplitRatio;
unsigned short Angle;
unsigned short ExactApprox;
unsigned short Fix; // Display Digits
unsigned short Exp; // Exponential Form
unsigned short Vector;
unsigned short Complex;
unsigned short Pretty;
unsigned short Base;
unsigned short UnitSystem;
unsigned short CustomUnits;
} MO_OPTIONS;
WINDOW is the main window-describing structure which is used in all window-based TIOS
functions. It is defied as
typedef struct WindowStruct
{
unsigned short Flags; // Window flags
unsigned char CurFont; // Current font
unsigned char CurAttr; // Current attribute
unsigned char Background; // Current background attribute
short TaskId; // Task ID of owner
short CurX, CurY; // Current (x,y) position (relative coordinates)
short CursorX, CursorY; // Cursor (x,y) position
SCR_RECT Client; // Client region of the window (excludes border)
SCR_RECT Window; // Entire window region including border
SCR_RECT Clip; // Current clipping region
SCR_RECT Port; // Port region for duplicate screen
unsigned short DupScr; // Handle of the duplicated or saved screen area
struct WindowStruct *Next; // Pointer to the next window in linked list
char *Title; // Pointer to the (optional) title
} WINDOW;
See wingraph.h header file for more info.
SCR_RECT is a scructure (more precise, an union) for defining a rectangular area
using psysical screen coordinates. It is defined as
typedef union
{
struct
{
unsigned char x0, y0, x1, y1;
} xy;
unsigned long l;
} SCR_RECT;
Instead of giving four coordinates x0, y0, x1 and y1,
it is possible to give all together using a field l which is a packed long
number. See graph.h and
wingraph.h header files for more info.
WIN_RECT is a scructure for defining a rectangular area using logical screen coordinates.
It is defined as
typedef struct
{
short x0, y0, x1, y1;
} WIN_RECT;
See graph.h and
wingraph.h header files for more info.