mirror of https://github.com/adamdruppe/arsd.git
getline convenience function
This commit is contained in:
parent
1933833c7b
commit
8f09236fc9
140
terminal.d
140
terminal.d
|
|
@ -17,7 +17,6 @@
|
||||||
module terminal;
|
module terminal;
|
||||||
|
|
||||||
// FIXME: ctrl+d eof on stdin
|
// FIXME: ctrl+d eof on stdin
|
||||||
// FIXME: sig hup
|
|
||||||
|
|
||||||
// FIXME: http://msdn.microsoft.com/en-us/library/windows/desktop/ms686016%28v=vs.85%29.aspx
|
// FIXME: http://msdn.microsoft.com/en-us/library/windows/desktop/ms686016%28v=vs.85%29.aspx
|
||||||
|
|
||||||
|
|
@ -26,7 +25,8 @@ version(linux)
|
||||||
|
|
||||||
version(Posix) {
|
version(Posix) {
|
||||||
__gshared bool windowSizeChanged = false;
|
__gshared bool windowSizeChanged = false;
|
||||||
__gshared bool interrupted = false;
|
__gshared bool interrupted = false; /// you might periodically check this in a long operation and abort if it is set. Remember it is volatile. It is also sent through the input event loop via RealTimeConsoleInput
|
||||||
|
__gshared bool hangedUp = false; /// similar to interrupted.
|
||||||
|
|
||||||
version(with_eventloop)
|
version(with_eventloop)
|
||||||
struct SignalFired {}
|
struct SignalFired {}
|
||||||
|
|
@ -51,6 +51,17 @@ version(Posix) {
|
||||||
catch(Exception) {}
|
catch(Exception) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
extern(C)
|
||||||
|
void hangupSignalHandler(int sigNumber) nothrow {
|
||||||
|
hangedUp = true;
|
||||||
|
version(with_eventloop) {
|
||||||
|
import arsd.eventloop;
|
||||||
|
try
|
||||||
|
send(SignalFired());
|
||||||
|
catch(Exception) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// parts of this were taken from Robik's ConsoleD
|
// parts of this were taken from Robik's ConsoleD
|
||||||
|
|
@ -260,6 +271,7 @@ enum Color : ushort {
|
||||||
/// Note: these flags can be OR'd together to select more than one option at a time.
|
/// Note: these flags can be OR'd together to select more than one option at a time.
|
||||||
///
|
///
|
||||||
/// Ctrl+C and other keyboard input is always captured, though it may be line buffered if you don't use raw.
|
/// Ctrl+C and other keyboard input is always captured, though it may be line buffered if you don't use raw.
|
||||||
|
/// The rationale for that is to ensure the Terminal destructor has a chance to run, since the terminal is a shared resource and should be put back before the program terminates.
|
||||||
enum ConsoleInputFlags {
|
enum ConsoleInputFlags {
|
||||||
raw = 0, /// raw input returns keystrokes immediately, without line buffering
|
raw = 0, /// raw input returns keystrokes immediately, without line buffering
|
||||||
echo = 1, /// do you want to automatically echo input back to the user?
|
echo = 1, /// do you want to automatically echo input back to the user?
|
||||||
|
|
@ -267,7 +279,10 @@ enum ConsoleInputFlags {
|
||||||
paste = 4, /// capture paste events (note: without this, paste can come through as keystrokes)
|
paste = 4, /// capture paste events (note: without this, paste can come through as keystrokes)
|
||||||
size = 8, /// window resize events
|
size = 8, /// window resize events
|
||||||
|
|
||||||
allInputEvents = 8|4|2, /// subscribe to all input events.
|
releasedKeys = 64, /// key release events. Not reliable on Posix.
|
||||||
|
|
||||||
|
allInputEvents = 8|4|2, /// subscribe to all input events. Note: in previous versions, this also returned release events. It no longer does, use allInputEventsWithRelease if you want them.
|
||||||
|
allInputEventsWithRelease = allInputEvents|releasedKeys, /// subscribe to all input events, including (unreliable on Posix) key release events.
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Defines how terminal output should be handled.
|
/// Defines how terminal output should be handled.
|
||||||
|
|
@ -282,7 +297,7 @@ enum ConsoleOutputType {
|
||||||
/// Some methods will try not to send unnecessary commands to the screen. You can override their judgement using a ForceOption parameter, if present
|
/// Some methods will try not to send unnecessary commands to the screen. You can override their judgement using a ForceOption parameter, if present
|
||||||
enum ForceOption {
|
enum ForceOption {
|
||||||
automatic = 0, /// automatically decide what to do (best, unless you know for sure it isn't right)
|
automatic = 0, /// automatically decide what to do (best, unless you know for sure it isn't right)
|
||||||
neverSend = -1, /// never send the data. This will only update Terminal's internal state. Use with caution because this can
|
neverSend = -1, /// never send the data. This will only update Terminal's internal state. Use with caution.
|
||||||
alwaysSend = 1, /// always send the data, even if it doesn't seem necessary
|
alwaysSend = 1, /// always send the data, even if it doesn't seem necessary
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -658,6 +673,9 @@ http://msdn.microsoft.com/en-us/library/windows/desktop/ms683193%28v=vs.85%29.as
|
||||||
showCursor();
|
showCursor();
|
||||||
reset();
|
reset();
|
||||||
flush();
|
flush();
|
||||||
|
|
||||||
|
if(lineGetter !is null)
|
||||||
|
lineGetter.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
version(Windows)
|
version(Windows)
|
||||||
|
|
@ -665,8 +683,15 @@ http://msdn.microsoft.com/en-us/library/windows/desktop/ms683193%28v=vs.85%29.as
|
||||||
reset();
|
reset();
|
||||||
flush();
|
flush();
|
||||||
showCursor();
|
showCursor();
|
||||||
|
|
||||||
|
if(lineGetter !is null)
|
||||||
|
lineGetter.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// lazily initialized and preserved between calls to getline for a bit of efficiency (only a bit)
|
||||||
|
// and some history storage.
|
||||||
|
LineGetter lineGetter;
|
||||||
|
|
||||||
int _currentForeground = Color.DEFAULT;
|
int _currentForeground = Color.DEFAULT;
|
||||||
int _currentBackground = Color.DEFAULT;
|
int _currentBackground = Color.DEFAULT;
|
||||||
bool reverseVideo = false;
|
bool reverseVideo = false;
|
||||||
|
|
@ -1083,6 +1108,31 @@ http://msdn.microsoft.com/en-us/library/windows/desktop/ms683193%28v=vs.85%29.as
|
||||||
_cursorX = 0;
|
_cursorX = 0;
|
||||||
_cursorY = 0;
|
_cursorY = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// gets a line, including user editing. Convenience method around the LineGetter class and RealTimeConsoleInput facilities - use them if you need more control.
|
||||||
|
/// You really shouldn't call this if stdin isn't actually a user-interactive terminal! So if you expect people to pipe data to your app, check for that or use something else.
|
||||||
|
// FIXME: add a method to make it easy to check if stdin is actually a tty and use other methods there.
|
||||||
|
string getline(string prompt = null) {
|
||||||
|
if(lineGetter is null)
|
||||||
|
lineGetter = new LineGetter(&this);
|
||||||
|
// since the struct might move (it shouldn't, this should be unmovable!) but since
|
||||||
|
// it technically might, I'm updating the pointer before using it just in case.
|
||||||
|
lineGetter.terminal = &this;
|
||||||
|
|
||||||
|
lineGetter.prompt = prompt;
|
||||||
|
|
||||||
|
auto line = lineGetter.getline();
|
||||||
|
|
||||||
|
// lineGetter leaves us exactly where it was when the user hit enter, giving best
|
||||||
|
// flexibility to real-time input and cellular programs. The convenience function,
|
||||||
|
// however, wants to do what is right in most the simple cases, which is to actually
|
||||||
|
// print the line (echo would be enabled without RealTimeConsoleInput anyway and they
|
||||||
|
// did hit enter), so we'll do that here too.
|
||||||
|
writePrintableString("\n");
|
||||||
|
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/+
|
/+
|
||||||
|
|
@ -1121,6 +1171,7 @@ struct RealTimeConsoleInput {
|
||||||
private int fdIn;
|
private int fdIn;
|
||||||
private sigaction_t oldSigWinch;
|
private sigaction_t oldSigWinch;
|
||||||
private sigaction_t oldSigIntr;
|
private sigaction_t oldSigIntr;
|
||||||
|
private sigaction_t oldHupIntr;
|
||||||
private termios old;
|
private termios old;
|
||||||
ubyte[128] hack;
|
ubyte[128] hack;
|
||||||
// apparently termios isn't the size druntime thinks it is (at least on 32 bit, sometimes)....
|
// apparently termios isn't the size druntime thinks it is (at least on 32 bit, sometimes)....
|
||||||
|
|
@ -1210,6 +1261,16 @@ struct RealTimeConsoleInput {
|
||||||
sigaction(SIGINT, &n, &oldSigIntr);
|
sigaction(SIGINT, &n, &oldSigIntr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
import core.sys.posix.signal;
|
||||||
|
sigaction_t n;
|
||||||
|
n.sa_handler = &hangupSignalHandler;
|
||||||
|
n.sa_mask = cast(sigset_t) 0;
|
||||||
|
n.sa_flags = 0;
|
||||||
|
sigaction(SIGHUP, &n, &oldHupIntr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if(flags & ConsoleInputFlags.mouse) {
|
if(flags & ConsoleInputFlags.mouse) {
|
||||||
// basic button press+release notification
|
// basic button press+release notification
|
||||||
|
|
@ -1273,6 +1334,10 @@ struct RealTimeConsoleInput {
|
||||||
}
|
}
|
||||||
if(windowSizeChanged)
|
if(windowSizeChanged)
|
||||||
send(checkWindowSizeChanged());
|
send(checkWindowSizeChanged());
|
||||||
|
if(hangedUp) {
|
||||||
|
hangedUp = false;
|
||||||
|
send(InputEvent(HangupEvent()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
import arsd.eventloop;
|
import arsd.eventloop;
|
||||||
|
|
@ -1295,6 +1360,7 @@ struct RealTimeConsoleInput {
|
||||||
sigaction(SIGWINCH, &oldSigWinch, null);
|
sigaction(SIGWINCH, &oldSigWinch, null);
|
||||||
}
|
}
|
||||||
sigaction(SIGINT, &oldSigIntr, null);
|
sigaction(SIGINT, &oldSigIntr, null);
|
||||||
|
sigaction(SIGHUP, &oldHupIntr, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// we're just undoing everything the constructor did, in reverse order, same criteria
|
// we're just undoing everything the constructor did, in reverse order, same criteria
|
||||||
|
|
@ -1333,12 +1399,16 @@ struct RealTimeConsoleInput {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get one character from the terminal, discarding other
|
/// Get one character from the terminal, discarding other
|
||||||
/// events in the process.
|
/// events in the process. Returns dchar.init upon receiving end-of-file.
|
||||||
dchar getch() {
|
dchar getch() {
|
||||||
auto event = nextEvent();
|
auto event = nextEvent();
|
||||||
while(event.type != InputEvent.Type.CharacterEvent || event.characterEvent.eventType == CharacterEvent.Type.Released) {
|
while(event.type != InputEvent.Type.CharacterEvent || event.characterEvent.eventType == CharacterEvent.Type.Released) {
|
||||||
if(event.type == InputEvent.Type.UserInterruptionEvent)
|
if(event.type == InputEvent.Type.UserInterruptionEvent)
|
||||||
throw new Exception("Ctrl+c");
|
throw new Exception("Ctrl+c");
|
||||||
|
if(event.type == InputEvent.Type.HangupEvent)
|
||||||
|
throw new Exception("Hangup");
|
||||||
|
if(event.type == InputEvent.Type.EndOfFileEvent)
|
||||||
|
return dchar.init;
|
||||||
event = nextEvent();
|
event = nextEvent();
|
||||||
}
|
}
|
||||||
return event.characterEvent.character;
|
return event.characterEvent.character;
|
||||||
|
|
@ -1441,6 +1511,11 @@ struct RealTimeConsoleInput {
|
||||||
return InputEvent(UserInterruptionEvent());
|
return InputEvent(UserInterruptionEvent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(hangedUp) {
|
||||||
|
hangedUp = false;
|
||||||
|
return InputEvent(HangupEvent());
|
||||||
|
}
|
||||||
|
|
||||||
version(Posix)
|
version(Posix)
|
||||||
if(windowSizeChanged) {
|
if(windowSizeChanged) {
|
||||||
return checkWindowSizeChanged();
|
return checkWindowSizeChanged();
|
||||||
|
|
@ -1499,6 +1574,10 @@ struct RealTimeConsoleInput {
|
||||||
e.eventType = ev.bKeyDown ? CharacterEvent.Type.Pressed : CharacterEvent.Type.Released;
|
e.eventType = ev.bKeyDown ? CharacterEvent.Type.Pressed : CharacterEvent.Type.Released;
|
||||||
ne.eventType = ev.bKeyDown ? NonCharacterKeyEvent.Type.Pressed : NonCharacterKeyEvent.Type.Released;
|
ne.eventType = ev.bKeyDown ? NonCharacterKeyEvent.Type.Pressed : NonCharacterKeyEvent.Type.Released;
|
||||||
|
|
||||||
|
// only send released events when specifically requested
|
||||||
|
if(!(flags & ConsoleInputFlags.releasedKeys) && !ev.bKeyDown)
|
||||||
|
break;
|
||||||
|
|
||||||
e.modifierState = ev.dwControlKeyState;
|
e.modifierState = ev.dwControlKeyState;
|
||||||
ne.modifierState = ev.dwControlKeyState;
|
ne.modifierState = ev.dwControlKeyState;
|
||||||
|
|
||||||
|
|
@ -1582,16 +1661,20 @@ struct RealTimeConsoleInput {
|
||||||
terminal.flush(); // make sure all output is sent out before we try to get input
|
terminal.flush(); // make sure all output is sent out before we try to get input
|
||||||
|
|
||||||
InputEvent[] charPressAndRelease(dchar character) {
|
InputEvent[] charPressAndRelease(dchar character) {
|
||||||
|
if((flags & ConsoleInputFlags.releasedKeys))
|
||||||
return [
|
return [
|
||||||
InputEvent(CharacterEvent(CharacterEvent.Type.Pressed, character, 0)),
|
InputEvent(CharacterEvent(CharacterEvent.Type.Pressed, character, 0)),
|
||||||
InputEvent(CharacterEvent(CharacterEvent.Type.Released, character, 0)),
|
InputEvent(CharacterEvent(CharacterEvent.Type.Released, character, 0)),
|
||||||
];
|
];
|
||||||
|
else return [ InputEvent(CharacterEvent(CharacterEvent.Type.Pressed, character, 0)) ];
|
||||||
}
|
}
|
||||||
InputEvent[] keyPressAndRelease(NonCharacterKeyEvent.Key key, uint modifiers = 0) {
|
InputEvent[] keyPressAndRelease(NonCharacterKeyEvent.Key key, uint modifiers = 0) {
|
||||||
|
if((flags & ConsoleInputFlags.releasedKeys))
|
||||||
return [
|
return [
|
||||||
InputEvent(NonCharacterKeyEvent(NonCharacterKeyEvent.Type.Pressed, key, modifiers)),
|
InputEvent(NonCharacterKeyEvent(NonCharacterKeyEvent.Type.Pressed, key, modifiers)),
|
||||||
InputEvent(NonCharacterKeyEvent(NonCharacterKeyEvent.Type.Released, key, modifiers)),
|
InputEvent(NonCharacterKeyEvent(NonCharacterKeyEvent.Type.Released, key, modifiers)),
|
||||||
];
|
];
|
||||||
|
else return [ InputEvent(NonCharacterKeyEvent(NonCharacterKeyEvent.Type.Pressed, key, modifiers)) ];
|
||||||
}
|
}
|
||||||
|
|
||||||
char[30] sequenceBuffer;
|
char[30] sequenceBuffer;
|
||||||
|
|
@ -1880,7 +1963,7 @@ struct RealTimeConsoleInput {
|
||||||
if(c == -1)
|
if(c == -1)
|
||||||
return null; // interrupted; give back nothing so the other level can recheck signal flags
|
return null; // interrupted; give back nothing so the other level can recheck signal flags
|
||||||
if(c == 0)
|
if(c == 0)
|
||||||
throw new Exception("stdin has reached end of file"); // FIXME: return this as an event instead
|
return [InputEvent(EndOfFileEvent())];
|
||||||
if(c == '\033') {
|
if(c == '\033') {
|
||||||
if(timedCheckForInput(50)) {
|
if(timedCheckForInput(50)) {
|
||||||
// escape sequence
|
// escape sequence
|
||||||
|
|
@ -2020,8 +2103,16 @@ struct SizeChangedEvent {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// the user hitting ctrl+c will send this
|
/// the user hitting ctrl+c will send this
|
||||||
|
/// You should drop what you're doing and perhaps exit when this happens.
|
||||||
struct UserInterruptionEvent {}
|
struct UserInterruptionEvent {}
|
||||||
|
|
||||||
|
/// If the user hangs up (for example, closes the terminal emulator without exiting the app), this is sent.
|
||||||
|
/// If you receive it, you should generally cleanly exit.
|
||||||
|
struct HangupEvent {}
|
||||||
|
|
||||||
|
/// Sent upon receiving end-of-file from stdin.
|
||||||
|
struct EndOfFileEvent {}
|
||||||
|
|
||||||
interface CustomEvent {}
|
interface CustomEvent {}
|
||||||
|
|
||||||
version(Windows)
|
version(Windows)
|
||||||
|
|
@ -2055,10 +2146,12 @@ struct InputEvent {
|
||||||
enum Type {
|
enum Type {
|
||||||
CharacterEvent, ///.
|
CharacterEvent, ///.
|
||||||
NonCharacterKeyEvent, /// .
|
NonCharacterKeyEvent, /// .
|
||||||
PasteEvent, /// .
|
PasteEvent, /// The user pasted some text. Not always available, the pasted text might come as a series of character events instead.
|
||||||
MouseEvent, /// only sent if you subscribed to mouse events
|
MouseEvent, /// only sent if you subscribed to mouse events
|
||||||
SizeChangedEvent, /// only sent if you subscribed to size events
|
SizeChangedEvent, /// only sent if you subscribed to size events
|
||||||
UserInterruptionEvent, /// the user hit ctrl+c
|
UserInterruptionEvent, /// the user hit ctrl+c
|
||||||
|
EndOfFileEvent, /// stdin has received an end of file
|
||||||
|
HangupEvent, /// the terminal hanged up - for example, if the user closed a terminal emulator
|
||||||
CustomEvent /// .
|
CustomEvent /// .
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2081,6 +2174,10 @@ struct InputEvent {
|
||||||
return sizeChangedEvent;
|
return sizeChangedEvent;
|
||||||
else static if(T == Type.UserInterruptionEvent)
|
else static if(T == Type.UserInterruptionEvent)
|
||||||
return userInterruptionEvent;
|
return userInterruptionEvent;
|
||||||
|
else static if(T == Type.EndOfFileEvent)
|
||||||
|
return endOfFileEvent;
|
||||||
|
else static if(T == Type.HangupEvent)
|
||||||
|
return hangupEvent;
|
||||||
else static if(T == Type.CustomEvent)
|
else static if(T == Type.CustomEvent)
|
||||||
return customEvent;
|
return customEvent;
|
||||||
else static assert(0, "Type " ~ T.stringof ~ " not added to the get function");
|
else static assert(0, "Type " ~ T.stringof ~ " not added to the get function");
|
||||||
|
|
@ -2111,6 +2208,14 @@ struct InputEvent {
|
||||||
t = Type.UserInterruptionEvent;
|
t = Type.UserInterruptionEvent;
|
||||||
userInterruptionEvent = c;
|
userInterruptionEvent = c;
|
||||||
}
|
}
|
||||||
|
this(HangupEvent c) {
|
||||||
|
t = Type.HangupEvent;
|
||||||
|
hangupEvent = c;
|
||||||
|
}
|
||||||
|
this(EndOfFileEvent c) {
|
||||||
|
t = Type.EndOfFileEvent;
|
||||||
|
endOfFileEvent = c;
|
||||||
|
}
|
||||||
this(CustomEvent c) {
|
this(CustomEvent c) {
|
||||||
t = Type.CustomEvent;
|
t = Type.CustomEvent;
|
||||||
customEvent = c;
|
customEvent = c;
|
||||||
|
|
@ -2125,6 +2230,8 @@ struct InputEvent {
|
||||||
MouseEvent mouseEvent;
|
MouseEvent mouseEvent;
|
||||||
SizeChangedEvent sizeChangedEvent;
|
SizeChangedEvent sizeChangedEvent;
|
||||||
UserInterruptionEvent userInterruptionEvent;
|
UserInterruptionEvent userInterruptionEvent;
|
||||||
|
HangupEvent hangupEvent;
|
||||||
|
EndOfFileEvent endOfFileEvent;
|
||||||
CustomEvent customEvent;
|
CustomEvent customEvent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2137,16 +2244,22 @@ void main() {
|
||||||
//terminal.color(Color.DEFAULT, Color.DEFAULT);
|
//terminal.color(Color.DEFAULT, Color.DEFAULT);
|
||||||
|
|
||||||
//
|
//
|
||||||
|
/*
|
||||||
auto getter = new LineGetter(&terminal, "test");
|
auto getter = new LineGetter(&terminal, "test");
|
||||||
getter.prompt = "> ";
|
getter.prompt = "> ";
|
||||||
terminal.writeln("\n" ~ getter.getline());
|
terminal.writeln("\n" ~ getter.getline());
|
||||||
terminal.writeln("\n" ~ getter.getline());
|
terminal.writeln("\n" ~ getter.getline());
|
||||||
terminal.writeln("\n" ~ getter.getline());
|
terminal.writeln("\n" ~ getter.getline());
|
||||||
getter.dispose();
|
getter.dispose();
|
||||||
|
*/
|
||||||
|
|
||||||
|
terminal.writeln(terminal.getline());
|
||||||
|
terminal.writeln(terminal.getline());
|
||||||
|
terminal.writeln(terminal.getline());
|
||||||
|
|
||||||
//input.getch();
|
//input.getch();
|
||||||
|
|
||||||
return;
|
// return;
|
||||||
//
|
//
|
||||||
|
|
||||||
terminal.setTitle("Basic I/O");
|
terminal.setTitle("Basic I/O");
|
||||||
|
|
@ -2165,6 +2278,8 @@ void main() {
|
||||||
terminal.writef("%s\n", event.type);
|
terminal.writef("%s\n", event.type);
|
||||||
final switch(event.type) {
|
final switch(event.type) {
|
||||||
case InputEvent.Type.UserInterruptionEvent:
|
case InputEvent.Type.UserInterruptionEvent:
|
||||||
|
case InputEvent.Type.HangupEvent:
|
||||||
|
case InputEvent.Type.EndOfFileEvent:
|
||||||
timeToBreak = true;
|
timeToBreak = true;
|
||||||
version(with_eventloop) {
|
version(with_eventloop) {
|
||||||
import arsd.eventloop;
|
import arsd.eventloop;
|
||||||
|
|
@ -2638,12 +2753,17 @@ class LineGetter {
|
||||||
/// returns false when there's nothing more to do
|
/// returns false when there's nothing more to do
|
||||||
bool workOnLine(InputEvent e) {
|
bool workOnLine(InputEvent e) {
|
||||||
switch(e.type) {
|
switch(e.type) {
|
||||||
|
case InputEvent.Type.EndOfFileEvent:
|
||||||
|
justHitTab = false;
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
case InputEvent.Type.CharacterEvent:
|
case InputEvent.Type.CharacterEvent:
|
||||||
if(e.characterEvent.eventType == CharacterEvent.Type.Released)
|
if(e.characterEvent.eventType == CharacterEvent.Type.Released)
|
||||||
return true;
|
return true;
|
||||||
/* Insert the character (unless it is backspace, tab, or some other control char) */
|
/* Insert the character (unless it is backspace, tab, or some other control char) */
|
||||||
auto ch = e.characterEvent.character;
|
auto ch = e.characterEvent.character;
|
||||||
switch(ch) {
|
switch(ch) {
|
||||||
|
case 4: // ctrl+d will also send a newline-equivalent
|
||||||
case '\r':
|
case '\r':
|
||||||
case '\n':
|
case '\n':
|
||||||
justHitTab = false;
|
justHitTab = false;
|
||||||
|
|
@ -2779,6 +2899,10 @@ class LineGetter {
|
||||||
/* I'll take this as canceling the line. */
|
/* I'll take this as canceling the line. */
|
||||||
throw new Exception("user canceled"); // FIXME
|
throw new Exception("user canceled"); // FIXME
|
||||||
break;
|
break;
|
||||||
|
case InputEvent.Type.HangupEvent:
|
||||||
|
/* I'll take this as canceling the line. */
|
||||||
|
throw new Exception("user hanged up"); // FIXME
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
/* ignore. ideally it wouldn't be passed to us anyway! */
|
/* ignore. ideally it wouldn't be passed to us anyway! */
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue