83Plus:Hooks:Catalog
General Information ------------------------------------------------------------
Catalog1HookPtr = 9BB4h _EnableCatalog1Hook = 5044h _DisableCatalog1Hook = 5047h Catalog1HookActive = 3 Catalog1HookFlag = 36h
Catalog2HookPtr = 9BC4h _EnableCatalog2Hook = 4F8Dh _DisableCatalog2Hook = 4F90h Catalog2HookActive = 6 Catalog2HookFlag = 34h
CatalogCurrent = 85DAh
Overview -----------------------------------------------------------------------
These two hooks are unique on the 83+, as they are, in many cases, the same hook. Although there are a few cases where the differ, in many cases the OS passes the same event to both hooks, one after another, effectivly resulting in the two hooks being chained. Consequently, it's best to document both hooks together, and also commenting on their interactions.
The TI Localization apps use the Catalog 2 hook for their activities (probably because the Catalog 2 hook also provides keypress notification, required to implement the Characters item it provides), so it would be possible to use the Catalog 1 hook to override some of their behaviors.
This document is formatted a little differently from normal, organizing by general event, not by hook specifics, and then discussing how each hook handles it.
Keypress Table -----------------------------------------------------------------
At the heart of the catalog hooks is the keypress table, which provides the ordering for the tokens in the list (since it's sorted.) Each entry in the table is two bytes long, the format depending on the whether the key is a one- or two-byte keypress:
- if it's a one byte keypress, then the first byte is zero, and the second byte is the value of the key.
- if it's a two byte keypress, the first byte is the prefix (FCh-FEh, but the OS seems to use FDh and FFh as well - anyone know why?), and the second byte is the other value.
The TI-OS stores this table on page 7 (tested in OS 1.16), but this might change, expecially with the TI-84+.
You can provide your own keypress table in a unique way. It's obvious that, inside the OS's implementation of the catalog, it would have to do something like "ld hl, table_start". However, after doing this, it always calls the Catalog hooks, allowing it to modify the value. It looks something like this internally (this is not the exact code):
ld hl, table_start ld a, 5 bit Catalog1HookActive, (iy + Catalog1HookFlag) call nz, CallCatalog1Hook bit Catalog2HookActive, (iy + Catalog2HookFlag) call nz, CallCatalog2Hook
where CallCatalog#Hook would return the registers and flags that the hook returned. Consequently, we are free to provide any value that we want.
It would seem that all we can do is just change range of tokens displayed, but it turns out that the OS only actually reads the table in one situation: when displaying a token, otherwise it's just manipulating the pointers without actually knowing where they are pointing! The cool part is we are able to change how this read occurs. Before drawing an item, the Catalog Hooks are called, with the table pointer being passed in HL. If we want, we can point this somewhere else (say somewhere in RAM, TI uses sFont_record), where we can put our own item that we copied there (realize that the read is performed with page 7 in the 4000h-7FFFh range, so we can't keep anything in flash.) The other interesting side effect is that we can copy anything we want to RAM: we could generate a virtual table on the fly.
So the easy method of reordering the catalog: replace all the OS-provided pointers with your own on your flash page, and when the display item event is fired, copy the item at the pointer provided into RAM, and give the OS the pointer to the area in RAM.
Event: Get Table Start ---------------------------------------------------
This event is passed to the Catalog 1 hook first.
Both Catalog Hooks: The OS wants the address of the keypress table. HL contains the address for the OS's table. If you want to provide your own table, change HL to its address.
Catalog 1 Hook Only: This message seems to get triggered in two cases:
- A = 5. If you don't want the message to be passed to the Catalog 2 hook, return with the zero flag reset. If you modify A, realize that whatever value you change it to will be passed to the Catalog 2 hook (should you permit it.) Although this could be useful, if you don't want to break the Catalog 2 hook, make sure you set A back to 5.
- A = 0Ah. This is called under some unknown circumstances (anyone know why?), but it seems acceptable to treat it as A = 5. In this case, you don't have to worry about trashing A; if you permit the Catalog 2 hook to be called under this condition, the TI-OS sets A = 5 for you.
Catalog 2 Hook Only: A = 5. HL may contain the address of the table provided by the Catalog 1 hook instead of the OS-provided address. Return flags are ignored.
Event: Get Table End -----------------------------------------------------
This event is passed to the Catalog 1 hook first. This event is similar to the previous event.
Both Catalog Hooks: A = 6. The OS wants the address of the keypress table. DE contains the OS's value. If you want to provide your own address, simply set DE.
Catalog 1 Hook Only: Returning with the zero flag reset prevents the Catalog 2 hook from processing the event. If you modify A, restore it as above.
Catalog 2 Hook Only: DE may contain the address provided by the Catalog 1 hook as above. Return flags ignored.
Event: Get Last Screen ---------------------------------------------------
This event is passed to the Catalog 2 hook only, A = 2.
The user has pressed up on the topmost item, so we must scroll back around to the last item. Here, we must provide in HL the pointer to the first item that must be displayed (so when displaying the bottom of the list, the first item shown.) HL will be set to the predefined OS value, but you can overwrite it. Return flags are ignored.
Event: Get Last Screen Item ----------------------------------------------
This event is passed to the Catalog 2 hook only, A = 3.
In the situation above, you must provide, in HL, the pointer to the item that will be selected. This will probably just be the pointer to the last item in the list, but you could make it different if you want. The return flags are ignored.
Event: Get Item from Letter ----------------------------------------------
This event is passed to the Catalog 1 hook first.
Both Catalog Hooks: A will be 4. The user has pressed a letter key, and we need to return the address of the item to be selected. DE is set to (key - 41h) * 2, where key is the ASCII value of the key. It's somewhat expected that you store a list of addresses; this would seem to be the most efficient way to do it anyways.
Catalog 1 Hook Only: Returning with zero reset will immediatly use the value in HL as the address of the entry of the keypress table we should display. The catalog 2 hook will not be called. Returning with zero set could result in one of two things happening:
- the Catalog 2 hook is not installed, at which point the OS will call LdHLInd and use that as the pointer to the keypress table. It's assuming that, by returning with zero set, you have essentially ignored the message, and HL is pointing inside it's lookup table. Realize that if you return with zero set you shouldn't trash HL!
- the Catalog 2 hook is installed, and how to handle HL is its decision
Make sure you restore A should you trash it.
Catalog 2 Hook Only: DE or HL could be modified by the Catalog 1 hook. Returning with zero set will immediately use the pointer in HL as a pointer to the item to be displayed next. Returning with zero set will cause LdHLInd to be called, treating the result as a pointer in the keypress table.
Event: Display Title -----------------------------------------------------
This event is passed to the Catalog 1 hook first.
Both Catalog Hooks: A = 7. The title of the catalog is about to be displayed, but this event can also be used as a generic catalog-is-open event (note: the Get Table Start event is called first!) There aren't any register inputs or outputs.
Catalog 1 Hook Only: If you modify A, make sure you set it back to 7, or the Catalog 2 app (if called) will not recieve the event properly. Return flags ignored.
Catalog 2 Hook Only: Returning with zero set causes the catalog to exit.
Event: Display Item ------------------------------------------------------
This event is passed to the Catalog 1 hook first.
Both Catalog Hooks: HL is the address of the key in the keypress table. Remember, if you want to provide your own key / token, you must copy the keypress data into RAM, and point HL to it.
Catalog 1 Hook Only: The accumulator is set to 9 for this event. Returning with zero reset will prevent drawing this item, and the Catalog 2 Hook will not be called.
Catalog 2 Hook Only: The accumulator is set to 1 for this event. HL contains whatever the Catalog 1 hook provided, either the OS provided pointer or a custom pointer (if it was called.) Returning with zero reset will prevent drawing the item.
Event: Key Press ---------------------------------------------------------
This event is passed to Catalog 2 only.
The accumulator is 8, B contains the keypress. You can modify it if you want. If you return with zero set, it will be canceled.
Note: If you want to look for up / down, then also check for kAlphaUp and kAlphaDown, since Alpha Lock is set by default in the catalog.