Skip to content

Instantly share code, notes, and snippets.

@adriweb
Forked from commandblockguy/hook_manager.txt
Last active February 23, 2020 13:59
Show Gist options
  • Save adriweb/4851ab3a0b1c250fc216b9b0a8ccac06 to your computer and use it in GitHub Desktop.
Save adriweb/4851ab3a0b1c250fc216b9b0a8ccac06 to your computer and use it in GitHub Desktop.
Random incomprehensible scrawlings about hook manager spec

@commandblockguy's currently unnamed CE hook manager:

Hook system components:

  • 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 principles:

  • 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.

Example program flow on hook fire:

User presses the 1 key

  1. TI-OS calls the hook executor for the getcsc hook
  2. Hook executor backs up relevant input registers
  3. Hook executor calls the first wildcard user hook for the getcsc hook // should subtype-specific be processed before wildcards?
  4. User hook indicates that further hooks should be processed rather than returning to the OS
  5. Hook executor restores register backup
  6. Next wilcard user hook is NULL - hook executor moves on to the specific hook type (a = 0x1B)
  7. Hook executor calls the first subtype-specific user hook
  8. User hook checks the scan code and decides to take no action
  9. User hook indicates that further hooks should be processed rather than returning to the OS
  10. Hook executor calls the next subtype-specific user hook
  11. User hook checks the scan code and decides to open a menu
  12. User hook indicates that control should be given back to the OS
  13. Hook executor returns control to the OS

User hook installation procedure:

  1. if hook database does not exist, create it
  2. 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
  3. Refresh hooks for that OS hook type

Refreshing hooks for a particular OS hook type:

  1. 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
  2. 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)
  3. Get all addresses of hooks of each subtype from the database, sorted by priority and ignoring invalid hooks, and copy them into the appvar
  4. Achive the appvar
  5. 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?
  6. Delete the appvar
  7. Call the OS sethook call

User-facing hook manager functions:

(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 ?
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment