@commandblockguy's currently unnamed CE hook manager:
- Executors - Each TI-OS hook has an associated entry point responsible for calling all user hooks for that type.
- Arrays - A null-terminated array of pointers to user hooks for a particular hook subtype, sorted by priority. The array is read by the hook executor each time it is called, and is completely overwritten by the hook manager every time a change is necessary.
- Manager - A library that is responsible for installing the hook executors and maintaining the hook arrays. The hook manager is only called when installing, changing, or viewing metadata of user hooks.
- Database - Internal data storage for the hook manager than consists of a list of hooks and their metadata.
- User hooks are like OS hooks, but are called by the hook executor rather than TI-OS.
- Each hook must start with
0x83
, like OS hooks. - All valid OS hooks are valid user hooks provided that they have the lowest priority of all hooks of their type.
- Rather than taking the hook subtype in
a
, as with OS hooks, the hooks should be registered by subtype whenever possible. - If a hook needs to process many values of
a
, a wildcard subtype can be used instead. - In addition to returning the value that the OS expects, user hooks should return a value in
d
(is this used by anything?). - If the return value of the function should be ignored and lower-priority user hooks should be processed,
d
should contain a non-zero value. - If the return value of the function should be passed on to TI-OS, ignoring lower-priority user hooks,
d
should contain zero.
- TI-OS calls the hook executor for the getcsc hook
- Hook executor backs up relevant input registers
- Hook executor calls the first wildcard user hook for the getcsc hook // should subtype-specific be processed before wildcards?
- User hook indicates that further hooks should be processed rather than returning to the OS
- Hook executor restores register backup
- Next wilcard user hook is
NULL
- hook executor moves on to the specific hook type (a
=0x1B
) - Hook executor calls the first subtype-specific user hook
- User hook checks the scan code and decides to take no action
- User hook indicates that further hooks should be processed rather than returning to the OS
- Hook executor calls the next subtype-specific user hook
- User hook checks the scan code and decides to open a menu
- User hook indicates that control should be given back to the OS
- Hook executor returns control to the OS
- if hook database does not exist, create it
- if hook database contains the hook to be installed:
- Yes. is the entry valid?
- Yes. return the pointer to it // should this behave differently?
- No. update the entry with the new pointer
- No. create a new entry for it
- Yes. is the entry valid?
- Refresh hooks for that OS hook type
- Check if the existing hook is our own hook executor ↳ If not, and hook is valid, create a new minimum-priority wildcard hook entry for it
- Copy the hook executor code into an appvar, ommitting unncessary portions (e.g. the wildcard checks if there are only subtype-specific hooks, or the return value checker if there is only one hook)
- Get all addresses of hooks of each subtype from the database, sorted by priority and ignoring invalid hooks, and copy them into the appvar
- Achive the appvar
- Get the data pointer from the appvar // Is there a better way of allocating memory than this, besides making an app? - maybe Mateo's relocation table system?
- Delete the appvar
- Call the OS
sethook
call
(probably need some work in terms of interface) C syntax is used for returns and arguments, though the final library may not use C functions.
refresh_hooks
: Regenerates hook executors and hook arrays for all types in the database. call at the beginning of the program to restore functionality.
bool refresh_hooks(void);
install_hook
: installs and enables a user hook from a pointer. returns NULL if installation failed or a pointer to the hook entry in the hook database. if the hook is already installed, a pointer to the existing entry is returned.
user_hook_entry_t *install_hook(uint24_t id, void *hook, uint8_t type, uint8_t subtype, uint8_t priority, const char *description);
uninstall_hook
: uninstalls a user hook
bool uninstall_hook(user_hook_entry_t *entry);
get_entry_by_id
: gets a pointer to a hook database entry by its unique id, or NULL if no such entry exists.
user_hook_entry_t *get_entry_by_id(uint24_t id);
set_priority
: sets the priority of a hook.
bool set_priority(user_hook_entry_t *entry, uint8_t priority);
check_hook_validity
: checks if a user hook is valid
bool check_hook_validity(user_hook_entry_t *entry);
- The hook database is stored in a regular appvar.
struct user_hook_entry_t {
uint24_t id;
void *hook; // pointer to the user hook
uint8_t type; // enum for which os hook to use
uint8_t subtype; // which value of a this user hook should fire for, or a
// "wildcard" magic value which causes the hook to fire for all subtypes
uint8_t priority; // process lowest priorities first
bool enabled;
char description[64];
// Maybe add a checksum, in addition to the 0x83 ?
}