KSP-KOS / KOS

Fully programmable autopilot mod for KSP. Originally By Nivekk
Other
697 stars 230 forks source link

react to custom keystrokes #51

Open Voidi opened 10 years ago

Voidi commented 10 years ago

It would nice to have the possibility to define keys oder keycombinations that when hit trigger some action in my script For example: a program that implement some sort of autopilot that should accept commands.

Dunbaratu commented 10 years ago

In general the feature of accepting keyboard input in some form or another is a big deal that everyone seems to want, so maybe it should be a feature planned for a release milestone Very Soon Now. There are a lot of design issues to hash out but they should be dealt with and something done to implement key input.

I can think of the following design decisions that need to be made:

It could be argued that for some of the answers to the above questions, implementing it one way around allows the script writer to fake the other way, while doing it the other way around doesn't. (i.e. if the only input that exists is nonblocking, the script could be written to set up an input hook, and then go into a wait until that hook triggers and thus manually fake blocking mode, but the reverse isn't true - you can't turn blocking input into nonblocking input in the script.)

But in some cases trying to put the onus on the script writer to fake it generates a lot of busywork - like trying to implement line-at-a-time input from key-at-a-time input. So maybe both modes should be supported even though one could be built from the other.

I was reading the code the other day for how key input passes into the terminal, and I suspect that implementing this would in some way involve subclassing Interpreter to make a mode in which it still takes in all the same inputs and buffers them the same way, but doesn't try to parse them, instead letting the script code have access to the keyboard and type buffer. Interpreter already has all the code for buffering input, and for tracking where the cursor is, and for echoing input at he cursor location, etc.

goblin commented 9 years ago

One hacky way I've found for this is to use the keys HNJKLI with RCS disabled and then read these as SHIP:CONTROL:PILOTFORE etc. This way, if you have a ship that doesn't need RCS translation, you can read these 6 keys in your script and react to them.

However it's not pretty.

Another idea I had was to lock steering and read the PILOTYAW and similar values, but it seems that once you lock steering they always read as 0, so that doesn't work.

+1 for having a proper input system.

goblin commented 9 years ago

perhaps one could use the rover controls in a similar way.

pdbogen commented 9 years ago

Generally, I propose two modes: "hotkey" mode, which basically lets you bind keys to KOS, outside of KOS window focus. This would let you implement a fly-by-wire system where KOS translates keystrokes into changes in the ship state.

The other mode, "read from terminal," is a more normal terminal-like prompting for input. Mostly, I see this used at the beginning of scripts to prompt for required inputs. If it was implemented in a nonblocking fashion (e.g., select() polling to see if there's input available), this could substitute somewhat for hotkey mode, since it'd allowing issuing commands to a running script.

Support immediate or line-at-a-time input, or both? (React immediately when a key is pressed, or get no notification until the user types out a string and hits Enter. There are types of input that are easier one way {press a key to activate such-and-such mode} and types that are easier the other way {entering the latitude and longitude of a desired landing point} )

I think both of these are needed, but "immediate" doesn't need to be interrupt-like; scripts could be expected to poll (either for the keyboard in general or for specific keys.) Reading normally typed input from the kernel (as in your latter example) should be simple..

Support blocking or nonblocking input, or both? (The difference between "Wait for input to happen before execution continues to the next statement." versus "set up a hook to react when input happens, like ON AG# works, and continue executing right now.")

Note that you don't need hooks for nonblocking input; we can poll for input. That also lets us block, since we can just poll until we get the input we need. So, I think the answer is that both happens with the same KOS backend.

Should we give the script the ability to see a keyboard buffer, or if a keypress is not handled in time before the next keypress, should the old keypress be thrown away?

There should be two modes- one of which is "read a line of input from the terminal," the other of which is "detect keys held down right now." A stretch goal could be some logic like "watch for keypresses; were any keypresses down since watch?; reset watch" which would let a loop still run a "large" intervals but catch keypresses.

Should the script be able to suppress the printing of the key onscreen, or should it echo automatically to the screen like it typically would on an old-school terminal in is usual mode settings?

In "hotkey" mode, my expectation would be that it works without focus, and I'd expect that it wouldn't echo to the terminal. (n.b.: This would run the risk of clobbering other keybindings, so I guess the programmer would need to explicitly bind to specific keys?) In read-from-terminal mode, echoing seems like it'd be fine.

Tie input to terminal window focus? yes? (only allow the script to see keyboard input if the terminal window is focused at the time.)

In "hotkey" mode, the opposite should be true; like ship control keys, they should only be active when KSP is not focused.

In "read from terminal" mode, then yes; it should only see keyboard input when the windows is focused.

So maybe both modes should be supported even though one could be built from the other.

Yep! Though implementing the friendlier mode (i.e., the one that can be "faked") could be pushed down the road to a later release. Technical debt ftw...

goblin commented 9 years ago

I like that :-)

Please don't forget joysticks though. I guess it could be done via a "hotkey" mode somehow.

Would also be nice to have a choice on what to do with the regular flight inputs: (1) just read their value and let them control the ship as normal or (2) read their value but don't let them control the ship and then (2a) write their value from the script.

I guess that's what the PILOT* variables were intended for, but that didn't seem to work, i.e. when blocking the inputs, I could no longer read their value, they always returned 0 (maybe that's been changed with recent commits though)

Dunbaratu commented 9 years ago

This statement contradicts itself, confusing me:

Note that you don't need hooks for nonblocking input; we can poll for input. That also lets us block, since we can just poll until we get the input we need. So, I think the answer is that both happens with the same KOS backend.

Your desire for polling seems to be advocating for not needing BLOCKING input, rather than, as you described it, not needing NONBLOCKING input.

The polling method IS the NONBLOCKING method.

The BLOCKING method is that when you ask for a keypress and one isn't buffered up for you yet, the script halts until a key is pressed, which is what you're saying you don't need.

There should be two modes- one of which is "read a line of input from the terminal," the other of which is "detect keys held down right now." A stretch goal could be some logic like "watch for keypresses; were any keypresses down since watch?; reset watch" which would let a loop still run a "large" intervals but catch keypresses.

There's really 3 styles here:

Both of the final two could either be done blocking or nonblocking style, but the first one can only be nonblocking.

The first one is the only one that would be impossible to accomplish over a terminal line, as it is dependent on reading current keyboard state, rather than being something that can be done via the characters coming in on a stream interface.

pdbogen commented 9 years ago

This statement contradicts itself, confusing me:

Note that you don't need hooks for nonblocking input; we can poll for input. That also lets us block,

I meant only to indicate that hooks aren't needed for nonblocking input if we can poll for input.

There's really 3 styles here:

Yep, agreed on all points. I think the "buffering single keys" mode is not as "necessary" as the other two. It'd be a nice-to-have, but I think whole strings and no buffering/hotkey cover the majority of IO paradigms.

Dunbaratu commented 9 years ago

I think you misunderstood me. I don't mean hooks in the kerboscript - I mean hooks in the C# that then get marshaled up into polls for the script. We'd need hooks in OUR code to give polling abilities to the script code, because hooks is how KSP does it.

The place where buffering single keys matters is for people who want remote-able terminals. If your only choices were buffered entire lines, or immediate unbuffered polling taken from the game events in the gui, then there's no way for a remoted program to provide ANY interface other than typing strings and hitting enter.

pdbogen commented 9 years ago

I think you misunderstood me. I don't mean hooks in the kerboscript - I mean hooks in the C# that then get marshaled up into polls for the script. We'd need hooks in OUR code to give polling abilities to the script code, because hooks is how KSP does it.

Indeed I did! Fair enough.

The place where buffering single keys matters is for people who want remote-able terminals. If your only choices were buffered entire lines, or immediate unbuffered polling taken from the game events in the gui, then there's no way for a remoted program to provide ANY interface other than typing strings and hitting enter.

I agree there are definite use cases, but I think the majority of them can be adapted to either line-buffered or hotkeys. You mentioned a menu; instead of moving a cursor up and down, you could enter the selection number and press enter. Certainly, it's not ideal, but I mention it only to illustrate that a partial implementation is possible that doesn't leave anyone out in the cold.

Dunbaratu commented 9 years ago

I disagree a lot about not leaving someone out in the cold. Making it so that when the terminal is remote you can only see a line at a time, but when it's local you can read a key at a time (via polling) causes a situation I'm trying desperately to avoid - It makes it so that the decision as to whether a program is remotable or not is decided by the PROGRAMMER instead of by the USER. I'm thinking from my experience in UNIX command line usage... where the programmer just makes tools like vim, the bash command editor, and so on, without bothering to write special cases for whether the console is local or remote. It's up to the OS to make it so that local and remote terminals act almost identically, and not up to each individual application program to deal with it.

I'm trying to avoid "this program was only written to work in the local terminal. If you are trying to use it remotely in your setup, tough cookies".

SirDiazo commented 9 years ago

Okay, having read this, I'm worried that things are being made complicated for no good reason.

The terminal window is the terminal window for entering commands in kOS code. While the terminal window has focus, behavior should remain as it is.

While the terminal window does not have focus keyboard keys should control the active vessel as per the keybindings.

What it sounds like is being asked is a way to affect programs during run time by changing variables or starting/stopping scripts. For this my first thought is adding a row of buttons to the top of the terminal window that the player could click, or bind a key to, that players could activate to change program variables, or start a program or whatever. (Button behavior defined by code.)

While rather complicated to code, this keeps things straight.

Terminal window has focus? All keyboard input goes to text entry, buttons across the top of the window can be clicked with the mouse but keybindings to the buttons don't work.

Terminal window does not have focus? Keyboard entry controls the vessel as normal controls, buttons across the top of the terminal window can be mouse clicked or activated by their assigned keybindings.

This also keeps the same behavior for local and remote terminals, the buttons on the terminal window affect that terminal window.

pdbogen commented 9 years ago

I was referring only to the order in which features might be implemented, assuming that developing a reduced feature set now and expanding on it later would result in more value for KOS users faster. I wasn't suggesting that remote should behave differently from local.

pdbogen commented 9 years ago

@SirDiazo I have three uses cases for myself in mind with supporting this feature:

Although #1 and #2 are doable with your proposal of GUI buttons, fly-by-wire controls really aren't.

SirDiazo commented 9 years ago

@pdbogen My worry is that we are starting to get too many control states and the player is going to get confused. Right now we have 2 states:

Now you are talking about adding a 3rd state of fly-by-wire controls where inputs are modified by script. (I'm assuming while the terminal window does not have focus so it does treat keys as text entry.) How do I tell the difference between this mode and unfocused mode where commands go straight to the game world?

Having thought on it for a day, what is really needed is a new window "kOS buttons" or something that can grab focus and keystrokes so that the player knows when they are in this mode. Make it 6x3 buttons or something, so you have two sets of vessel controls and some buttons left over that you bind keys to.

By making it a separate window, that means I know what pressing 'A' will do.

In short, my concern here is not the feasibility of the control method, it's player confusion from too many options and/or lack of feedback on which options are enabled and doing what.

IE: Landed my cargo lifter next to my miner with kOS. Switch to the miner, dock and load up. Switch back to the lifter, what mode is all my kOS stuff in? Did I leave fly-by-wire enabled? Are my kOS scripts still running? This all needs feedback to the player somehow.

D.

pdbogen commented 9 years ago

@SirDiazo I'm pretty ok with this. In fact, it seems to fit with how ksp stock handles linear vs staging modes.

cherrydev commented 9 years ago

Can't this basically be done with the Action Groups Extended support? AGX allows you to attach action groups to arbitrary keys (or any input, really).

dcrockwell commented 8 years ago

Can't this basically be done with the Action Groups Extended support?

No. Action groups toggle instead of press. We need something that will support pressable inputs.

SirDiazo commented 8 years ago

AGX Dev here.

As of a few versions ago AGX now supports press and hold keys so that pressing down a key activates an action group and releasing the key deactivates it.

You would then query the state of the group so if AG15 is TRUE, key is held down, if AG15 is FALSE the key is released(not pressed down).

If you are using AGX, the HOLD/TAP button on the GUI just under the group naming text box toggles this behavior for that action group.

dcrockwell commented 8 years ago

@SirDiazo That's super awesome to learn! I think I'll be able to do a lot with this.