KeyboardListener - InputFocus
Right,
Currently I've been looking into creating a "more" command, however the simple feature, that it should display a bit of text and wait for a keypress, has caused a couple of issues. These should be resolved (either due to code needing changing, or my infomation needing changing. I'm still learning my way around a very small part of JNode)
The main one is that the CommandShell and ThreadCommandInvoker are both given the keyboard event before the command. The commandshell consumes nearly all keystrokes, and the ThreadCommandInvoker takes the Ctrl-+ important keystrokes. This leaves the command with nothing.
The solutions I can see are the following:
First:- Run the event chain the other way. In otherwords give the command first choice on the keypress. This would give an instant working model, however commands could swallow all keypresses, including Ctrl-c etc. Which is obviously incorrect.
Second:- Make CommandShell ignore all its keypresses. This way the command only gets the none reserved keypresses.
However, this is slightly inflexible. The CommandShell has to be told when to stop listening for the keypresses, which is feasible. But if a different situation happens in which say two commands are to be run, both which depend on key presses. With one in the background, the other in the foreground, both may receive keypresses, or if the background process consumes them, the foreground process is seemed to be starved. This is also able to be worked around.
Finally should the command always be denied the catching of the Ctrl+{X} keypresses? Could there be a command which causes problems if terminated in such a fashion. What if you wanted to run a shell, within a shell etc...
Third:
Thinking about this, the KeybordListener seems to direct for commands to be be part of the event dispatch. For the reasons above. My thoughts were to, using the existing framework, create a second dispatch system. So instead of the Commands receiving keyboard events from the Console. It recieves them via its Shell. This way, the Shell only dispatches events when the command is in the forground, and the command could choose to capture certain key combinations that CommandShell/ThreadCommandInvoker would normally capture.
The CommandShell would need information about if it was running a command (which is think is reasonable).
Comments, info which i've missed, etc
Evan
- Login to post comments
Proposal: implementing more
The more command reads its input stream. It writes some of the characters to its output stream. It stops and listens for a keyboard event. On a keyboard event, it reads more of its input stream and writes more of its output stream. Then, again, it stops and listens for a keyboard event.
The more command demonstrates an essential part of an operating system: a stable mechanism for a subprogram.
cat readme.txt | more
The cat command is invoked with no input stream. A pipe is used as the output stream of the cat command and the input stream of the more command.
The shell is responsible for creating the cat command object, the more command object, the command context for cat, the command context for more, and the pipe between the two commands.
The cat command is not allowed to handle keyboard events at all. A request to enable keyboard events throws an exception.
The more command is allowed to handle regular keyboard events. On the q keypress, for example, the more command returns its return code.
The more command is attached to the shell. In turn, the cat command is attached to the more command.
Things have moved on a bit ...
... since the original article was posted.
The command shell etc have been changed so that a command should be able to use InputStream.read, etc on its standard input to read input. This works works with all kinds of standard input. In the case where standard input comes from the console, the input driver provides echoing, line editing and history.
Depending on which command interpreter and command invoker you select (see Note below), you can run commands like:
cat > foo.txt
cat < foo.txt | grep FISH
Given the above, there are two approaches to implementing "more". One approach is to have it process keyboard events as you suggest. This has advantages ... but it has the disadvantage that the "more" command would only work in situations where keyboard events were available. For example, if I was connected into a JNode box via "ssh", a JNode "more" command wouldn't work if it depended on Keyboard events. (I'm not saying that keyboard event processing is wrong. Its just that any JNode command that uses this approach presents problems when used remotely.)
The other approach (which I prefer) is to allow "more" to acquire its own console input stream. The analogy is with classic UNIX "more", which gets an interactive input stream by opening "/dev/tty". This approach requires two new bits of functionality in the JNode input layer. First, it needs the functional equivalent of open("/dev/tty"). Second, a command like "more" needs to be able control the behavior of the console input driver for a particular input stream; e.g. switch line editing on or off.
[Note: the command redirection will only works properly with the "proclet" and (yet to be implemented) "isolate" command invokers. The problem is that a classic Java application expects "java.lang.System.in" to be set to "standard input", and so on. If you are pipelining commands (for example) each one needs a different standard input ... but they share the same global System.in.]
Proposal: keyboard event chaining
The following proposal enables the dispatch of keyboard events to the "current" command class. A shell is a command class. A shell is also a container for command classes because a shell runs a command class. A command class has a specific lifecycle. The lifecycle rules are enforced by the shell, not the command class.
The following life cycle is insufficient for keyboard event chaining.
1. A shell loads a command class.
2. A shell executes a command class.
The following life cycle is proposed.
1. A shell loads a command class.
2. A shell creates a command context.
3. A shell executes a command class.
4. A shell discards a command context.
A command context is used by a command class to enables a command class to get listen for keyboard events.
A shell invokes another shell. The child shell inherits the command context of its parent.
1. It loads a command class.
2. It installs itself as a command context.
3. It invokes a command class.
4. It removes itself as a command context.
A keyboard event is dispatched. It is dispatched to the shell. When a shell has not invoked a command class, it handles the keyboard event itself, editing the command line. When a shell has invoked a command class, it dispatches a keyboard event to the command class.
Further, a command class invokes the exec method to run other commands.
1. It loads a command class.
2. It creates a command context.
3. It executes the command.
4. It discards the command context.
Therefore, this proposal suggests that an exec method should be part of the API, part of the base class for all commands. This exec method should control the life cycle of a child command, including the mechanism to receive keyboard events.