anicolao / npa

Neptune's Pride Agent
GNU General Public License v3.0
8 stars 6 forks source link

API of sorts? #11

Closed Ethrel closed 1 year ago

Ethrel commented 1 year ago

TL;DR: Would npa be amenable to a basic api of some kind to allow access to hotkeys and their labels?

So, in putting together the mobile app, I was considering making some kind of ui with the hotkey buttons kinda like the controls menu, but easier to access and having the ability to put "common" controls at easier reach. I have some nifty ideas for how to put that together, but that's a tangent.

And so, would npa be amenable to a basic api of some kind? Mainly, a way to get a list of hotkeys and their labels. Because of the packed and minified code served from the official iOS source, there's no good way for me to hook into that without it being explicitly made to do so. I have found a way to inject some code that allows access, but as soon as the code is re-minified with code changes, the symbols could (most likely would) change and break it all.

The alternative would be to publish the source map file and I'd have to work out exactly how to trace a symbol through the maps to get the minified symbol names to inject proper code. This is also do-able, and would allow for expansion to whatever I (and others) may want access to, but it is harder and hackier.

If just given access to the hotkeys and their labels, I could trigger Mousetrap in the same way the controls menu does. This would mean that there is never a feature that mobile has that the extension doesn't, because I'd just be calling the extension-provided hotkeys.

I do have a bit of code that is working in my local code, but haven't written tests or anything like that. Before adding a huge amount of effort, I just wanted to reach out to see if npa would be amenable to the idea and willing to take a PR to accomplish that goal. Right now, the code I've got just adds an object to the NeptunesPride object (NeptunesPride.Agent) that contains a single method (getHoykeys) that grabs and returns a dictionary (associative array? Map? So many languages, so many names) of hotkey keys and HotkeyCallback object values.

I am definitely open to hearing other thoughts and ideas to accomplish similar goals, should they be presented.

anicolao commented 1 year ago

Sorry it is taking me so long to answer this! I am definitely supportive and have a lot of thoughts, but it'll be a few hours before I can post a first real response.

Ethrel commented 1 year ago

Absolutely! I'd love to hear your thoughts.

anicolao commented 1 year ago

OK let's start with what's already possible, and figure out an API or use what's there according to what seems best/easiest.

First off the users can create buttons by emailing themselves hotkeys. Try creating a thread to nobody (thus just to yourself) in game and putting in:

[[hotkey:,]] [[hotkey:.]]

to create two buttons that look like this:

image

The mechanism that makes that work is that the message text is passed through Crux.format which turns the [[hotkey:x]] into a button. So we can use that to get a list of hotkeys! Try running this function by injecting it into the page:


function listHotKeys() {
    const ret = [];
    for (let modifier of ['shift+', 'ctrl+', '']) {
        for (let key of '`1234567890-=~!@#$%^&*()_+qwertyuiop[]\asdfghjkl;zxcvbnm,./{}|:"<>?\'') {
            const description = Crux.format(`[[hotkey:${modifier}${key}]]`, {}).split(/[<>]/)[2];
            if (description && !description.startsWith('Trigger hotkey')) {
                console.log(`Hotkey ${modifier}${key} is ${description}`);
                ret.push({modifier, key, description});
            }
        }
    }
    return ret;
}

You can also just copy & paste the above into the console in Chrome to see what happens, and call it by typing listHotKeys() at the prompt.

The result is an array with the hotkey modifier, key, and description text:

image

So that is one way to get what you specifically asked for here - a list of hotkeys - though it exposed a bug in my code where I failed to process hotkeys with modifiers (fixed in my development machine but not yet even committed to be pushed up).

To use this in the Android app, you could inject the function and call it, or you could create markup with [[hotkey:key]] and render it in the game UI. Also note that the script in the span given back by Crux.format is the script you need to eval in the webview to make the hotkey happen, so it might be worth extracting.

Thoughts?

anicolao commented 1 year ago

Heh I just noticed that < and > don't get handled properly by my sample code. Here is a hopefully fixed version


function listHotKeys() {
    const ret = [];
    for (let modifier of ['shift+', 'ctrl+', '']) {
        for (let key of '`1234567890-=~!@#$%^&*()_+qwertyuiop[]\asdfghjkl;zxcvbnm,./{}|:"<>?\'') {
            const span = Crux.format(`[[hotkey:${modifier}${key}]]`, {}).replaceAll('">"', '"&gt;"');
            const description = span.split(/[<>]/)[2];
            if (description && span.indexOf('Trigger hotkey') === -1) {
                console.log(`Hotkey ${modifier}${key} is ${description}`);
                ret.push({modifier, key, description});
            }
        }
    }
    return ret;
}
Ethrel commented 1 year ago

Oh, cool! I hadn't dug deep enough to realize I could just do it like that. That will absolutely work for what I was looking for, and I don't see any reason to need more that that, as long as newly added functionality either works through hotkey like that or just works as a lot of the other pieces do. It feels like an inefficient way to do things, but as far as actual processor time it's not actually that horrible.

I think that'll work. Thanks!

I'll close this for now, and if there's some major flaw, I'll just re-open it. I'm not at home so can't run the tests and start integration yet.