Recently, I've been trying to get VYSION to run when the [prgm] key is pressed, by way of a GetKey hook. I have the code for that here, which is an adapted version of code I found in this thread:
Code:
include 'include/ez80.inc'
include 'include/tiformat.inc'
include 'include/ti84pceg.inc'
format ti executable 'HS'

_Program:
    call InstallStartHook
    ret


_hook_start_addr:
    virtual at ti.pixelShadow2
_hook_start:
    db $83
    ld (ti.plotSScreen),a
    cp ti.kPrgm       ; was Prgms pressed?
    ret nz
    ld hl,$D007E0
    ld b,(hl)
    ld a,ti.kQuit
    cp b
    jr nz,return
    call RelocBase
RelocBase:
    pop ix
    lea hl,ix-RelocBase+ShellPrgm ;actual program running stuff
    res   ti.progExecuting,(iy + ti.newDispF)
    res   ti.cmdExec,(iy + ti.cmdFlags)
    call ti.Mov9ToOP1
    call ti.ExecutePrgm
    ld a,0
    ld (ti.plotSScreen),a
    call ti.HomeUp
return:
    ld a,(ti.plotSScreen)
    ret
ShellPrgm:
    db ti.ProtProgObj,"VYSION", 0
load code: $-_hook_start from _hook_start
end virtual
db code


InstallStartHook:
    ld   hl,_hook_start_addr
   ld   de,ti.pixelShadow2
   ld   bc,lengthof code
   ldir
   ld   hl,ti.pixelShadow2
    ;jp ti.plotSScreen
   jq   ti.SetGetKeyHook
    ret

ClearStartHook:
    call ti.ClrGetKeyHook
    ret
With MathPrint on, the shell loads correctly the first time the hook is run, but after that, the cursor gets stuck in the top left corner of the screen, resetting the calc when [clear] is pressed. With it off, the cursor returns to the correct position, but operations fail to execute, eventually bricking the calc when the hook is attempted to be run again:


When talking with people in Discord about this, I was given to understand that I need to somehow reload the home screen, using a command such as ti.newContext0 or ti.SetupHome, but these do not seem to work. Anyone who has knowledge of hooks and can see what's going wrong here, help would be much appreciated.
Hello there.

I believe using ExecutePrgm might be part of the problem, since it's not acting like a proper home entry, so the OS doesn't digest it, especially when coming back from VYSION.
I'm not a CE|CSE specialist at all, but i've learnt that when messing with hooks, it's usually safer to accurately simulate what you would do without them, to avoid unexpected consequences, such as stack leaks, etc.
In your case, the algorithm would look like this :

1) switch to home context, using newContext, or newContext0 (not sure if that would work if home is already up though, but i guess so)
2) simulate a [CLEAR] keypress (in case the [PRGM] key is pressed while the current entry isn't empty)
3) simulate the entry to load VYSION (i would simulate all keys one after another, but there's probably an easier way to do it)
4) simulate an [ENTER] keypress

Of course, that's way more complicated than your original code.
the_mad_joob wrote:
Hello there.

I believe using ExecutePrgm might be part of the problem, since it's not acting like a proper home entry, so the OS doesn't digest it, especially when coming back from VYSION.
I'm not a CE|CSE specialist at all, but i've learnt that when messing with hooks, it's usually safer to accurately simulate what you would do without them, to avoid unexpected consequences, such as stack leaks, etc.
In your case, the algorithm would look like this :

1) switch to home context, using newContext, or newContext0 (not sure if that would work if home is already up though, but i guess so)
2) simulate a [CLEAR] keypress (in case the [PRGM] key is pressed while the current entry isn't empty)
3) simulate the entry to load VYSION (i would simulate all keys one after another, but there's probably an easier way to do it)
4) simulate an [ENTER] keypress

Of course, that's way more complicated than your original code.

This is almost exactly how you should do it properly. The only things I would change are the steps 2 and 3; delete the entry program and load the command to execute instead. Then just use JForceCmd to simulate the [enter] keypress in 4.
MateoConLechuga wrote:
This is almost exactly how you should do it properly. The only things I would change are the steps 2 and 3; delete the entry program and load the command to execute instead. Then just use JForceCmd to simulate the [enter] keypress in 4.

That's the easier way i was talking about, yes, assuming updating the entry prog actually is the only thing to do.
Using jforcecmd isn't a bad idea then, assuming it properly kills system apps the same way it kills user apps.
Also, you need to include a check to see if there's actually enough free RAM for the entry prog data, of course.

EDIT :
I take it back, jforcecmd is NOT a good idea, since the OS is expecting the hook to terminate at some point, which will never happen.
How about a hybrid solution then :
1) check if enough free RAM for the home entry
2) if yes, update entry program
3) switch to home with newContext|newContext0
4) exit hook & simulate [ENTER] key (using a secondary hook would work, but there might be another way)
First of all, thanks to everyone for the help! To recap, based on what has been said so far:
1. check if enough ram for the home entry
2. update edit buffer to contain the entry program (prgmVYSION in my case)
3. switch to home context
4. simulate [enter] press- maybe I could do this with ti.SendKPress?
the_mad_joob wrote:
I take it back, jforcecmd is NOT a good idea, since the OS is expecting the hook to terminate at some point, which will never happen.

I disagree here. We aren't expecting to ever return from the hook in the case another app is loaded from the shell. It won't be a problem to just force execution from inside the hook, as the stacks are cleaned up by the command.

I might be wrong though; I'd need to double check just to be sure. It would be nice though to avoid having to do weird stuff.
I got this working a few minutes ago. Thanks to both of you for helping out with it! I did use JForceCmd, and haven't noticed any real issues with it, so I'm going to stick with that for now.
MateoConLechuga wrote:
I disagree here. We aren't expecting to ever return from the hook in the case another app is loaded from the shell. It won't be a problem to just force execution from inside the hook, as the stacks are cleaned up by the command.

I might be wrong though; I'd need to double check just to be sure. It would be nice though to avoid having to do weird stuff.

Looks like you were right, it seems functional, without any stack leak, though i checked on a TI-84+SE.

epsilon5 wrote:
I got this working a few minutes ago. Thanks to both of you for helping out with it! I did use JForceCmd, and haven't noticed any real issues with it, so I'm going to stick with that for now.

Cool !

#####

On a side note, i just discovered that on the TI-84+[SE], cursor hooks are never called from the homescreen if mathprint is on (at least on OS 2.55).
That's another thing to add to the list of incompatibilities...
So I actually found it easier/smaller to just insert into the edit buffer rather than into the entry program. Who would have guessed. Stupid Mateo. Anyway, since it's trivial to just modify the homescreen edit buffer, I did that instead. This program will run the VYSION program when the [pgrm] key is pressed.

Since Cemetech can't perserve tabs in code boxes even though I've opened multiple issues about it, I also put it here so the tabs are kept: https://paste.ee/p/TMziQ


Code:
include 'include/ez80.inc'
include 'include/tiformat.inc'
include 'include/ti84pceg.inc'
format ti executable 'RUNSHELL'

hook_reloc_addr := ti.pixelShadow2

   ld   hl,hook            ; copy hook to temp location
   ld   de,hook_reloc_addr
   push   de
   ld   bc,lengthof hook_code
   ldir
   pop   hl
   jp   ti.SetGetKeyHook

hook:
   db   hook_code

virtual at hook_reloc_addr
hook_start:
   db   $83
   cp   a,ti.kPrgm         ; check if [prgm] pressed
   ret   nz
   ld   a,ti.cxCmd
   call   ti.NewContext0         ; switch to homescreen
   call   ti.BufClear         ; clear input buffer
   ld   de,(ti.t2ByteTok shl 8) or ti.tasm
   call   ti.BufInsert
   ret   z
   ld   hl,prgm_name
   ld   b,prgm_name.len
.insert:
   push   bc
   push   hl
   ld   de,0
   ld   e,(hl)
   call   ti.BufInsert         ; insert program name
   pop   hl
   pop   bc
   ret   z
   inc   hl
   djnz   .insert
   ld   a,ti.kEnter
   jp   ti.JForceCmd         ; press enter
prgm_name:
   db   ti.tProg,'VYSION'
.len := $-prgm_name
   load hook_code: $-hook_start from hook_start
end virtual
MateoConLechuga wrote:
So I actually found it easier/smaller to just insert into the edit buffer rather than into the entry program.

Good job !
It's indeed a lot more convenient.
Thanks Mateo, I'll try that solution out later today.

For future reference to others trying to solve this, I'll include all of my attempts at this below. This was what I initially tried, but I did so using the recall queue, meaning that the [enter] keypress was registered before the edit buffer was updated, meaning it didn't work correctly:
Code:
include 'include/ez80.inc'
include 'include/tiformat.inc'
include 'include/ti84pceg.inc'
format ti executable 'HS'
 
_Program:
    call InstallStartHook
    ret
 
 
_hook_start_addr:
    virtual at ti.pixelShadow2
_hook_start:
    db $83
    ld (ti.plotSScreen),a
    cp ti.kPrgm       ; was Prgms pressed?
    ret nz
    ;check if edit is open
    ;call ti.NewContext0
    ld hl, ShellPrgm
    ld de,ti.saveSScreen
    ld bc,7
    ldir
    ld hl,ti.saveSScreen
    ld (ti.rclQueue),hl
    ld (ti.rclQueueEnd),de
    set 7, (iy+0Eh)
    set 2, (iy+33h)
    ;call ti.SendKPress
    jp ti.JForceCmd
    ret
NotEnoughMemory:
    ld hl, String_Mem
    call ti.PutS
    ret
NotInEditor:
    ld hl, String_Editor
    call ti.PutS
    ret
ShellPrgm:
    db ti.tProg, "VYSION"
String_Mem:
    db "Not enough memory...", 0
String_Editor:
    db "Not in editor...", 0
load code: $-_hook_start from _hook_start
end virtual
db code
Permanent link to that can be found here.

My other solution (note that this is a file to be included in a C project, and will have to be adapted slightly to work on its own), which did seem to work correctly for the most part, but didn't clear out the current homescreen entry correctly (well, it did, but only for a split second):

Code:
public _InstallStartHook
public _ClearStartHook
 
include 'include/ez80.inc'
include 'include/tiformat.inc'
include 'include/ti84pceg.inc'
 
_hook_start_addr:
    virtual at ti.appData
_hook_start:
    db $83
    ;ld (ti.plotSScreen),a
    cp ti.kPrgm       ; was Prgms pressed?
    ret nz
    ld a, ti.cxCmd
    call ti.NewContext         ; just attempt a cleanup now
   call ti.CursorOff
   call ti.RunIndicOff
    ;check if there's enough memory
    ld hl,9
    call ti.EnoughMem
    jq c,NotEnoughMemory
    ;delete the entry program
    ld hl,Prog_Name
    ;ld de,ti.OP1
    ;ld bc,3     ; type (1) + name (1) + zero (1)
    ;ldir
    call ti.Mov9ToOP1
    call ti.ChkFindSym
    ;ret c
    call ti.DelVarArc
    ;create the new program
    ld hl,Prog_Name
    call ti.Mov9ToOP1
    ld hl,9 ;the data is 9 bytes long
    ld a, ti.ProgObj
    call ti.CreateVar
    ;write the stuff to it
    inc de
    inc de
    ld hl, Prog_Data
    ld bc, Prog_Data_End - Prog_Data
    ldir
    ld a, ti.kEnter
    call ti.JForceCmd
    ret
NotEnoughMemory:
    ld hl, String_Mem
    call ti.PutS
    ret
NotInEditor:
    ld hl, String_Editor
    call ti.PutS
    ret
Prog_Name:
    db ti.ProgObj, "#", 0
Prog_Data:
    db $bb, $6a, ti.tProg, "VYSION"
Prog_Data_End:
String_Mem:
    db "Not enough memory...", 0
String_Editor:
    db "Not in editor...", 0
load code: $-_hook_start from _hook_start
end virtual
db code
 
 
_InstallStartHook:
    ld iy, ti.flags
    ld   hl,_hook_start_addr
   ld   de,ti.appData
   ld   bc,lengthof code
   ldir
   ld   hl,ti.appData
    ;jp ti.plotSScreen
   call ti.SetGetKeyHook
    set 0, (iy + ti.hookflags1)
    set 5, (iy + ti.hookflags1)
    ;call   ti.ClrScrn
   ;call   ti.HomeUp
    ;ld hl, String_Success
   ;call   ti.PutS
;.getkey:
    ;wait for a keypress
   ;call   ti.GetCSC
   ;or   a,a
   ;jr   z,.getkey
    ret
;String_Success:
    ;db "Successfully installed.", 0
 
_ClearStartHook:
    ;all of this is probably unnecessary
    ld iy, ti.flags
    call ti.ClrGetKeyHook
    call ti.ClrRawKeyHook
    res 0, (iy + ti.hookflags1)
    res 5, (iy + ti.hookflags1)
    ret
Permanent link to that can be found here.

My final question: you seem to have put your hook at ti.pixelShadow2, which I've heard is a bad place to keep hook permanently. The hook would likely be set each time the program is run anyway, so I don't think this is too much of a big deal, but is there a better location? I'd been putting mine at ti.appData in testing, but I'm not sure if this was ideal.
epsilon5 wrote:
My final question: you seem to have put your hook at ti.pixelShadow2, which I've heard is a bad place to keep hook permanently. The hook would likely be set each time the program is run anyway, so I don't think this is too much of a big deal, but is there a better location? I'd been putting mine at ti.appData in testing, but I'm not sure if this was ideal.

Put it in an archived appvar. PixelShadow2 is the best place to test hooks if you aren't running other programs or using C. There is no RAM location that is safe for hooks, period.
Just got all that done, adapting Mateo's code to be position independent and to be in an archived appvar, as well as reworking the hook install code to compensate for the new changes. Everything's incorporated into the main program and working, as far as I can tell. Thanks to Mateo again!
To make things even more permanent, you can also build an algorithm that make your appvar the very first in the archive space, so that you're sure it won't be moved upon garbage collecting.
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement