mud/lib/lib/chario.c
2020-09-06 05:43:07 -07:00

251 lines
8.0 KiB
C

/* Character Input/Output handler.
* Character mode is meant to allow the user to issue special
* requests to the mud using escape sequences. However, it is
* not always as simple as "escape character X".
*
* This inherited object manages a get_char() loop that accumulates
* input into CharStuff["charbuffer"], and watches for sets of
* substrings that match known escape sequences, such as "up arrow"
* and the like, which are not just one character.
*
* When an ESC is received (it is assumed that the driver translates
* 0x1b to 0x1e with the ANSI_SUBSTITUTE define, making '30' the
* escape char) then the subsequent input is not put into
* CharStuff["charbuffer"] but rather into CharStuff["escape"]
* until a recognized escape sequence is completed in
* CharStuff["escape"] or until some arbitrary number of characters
* being input indicates that an unknown escape sequence has
* been received. At that point the escape sequence is either
* processed or discarded, and accumulation into CharStuff["charbuffer"]
* resumes.
* -Crat 08FEB2009
*
* Wow what's that even mean?
* -Crat 22SEP2009
*/
#include <daemons.h>
#include <lib.h>
#include "include/nmsh.h"
#define CHAR_DEBUG 0
private static mapping CharStuff;
int rEsc();
void create(){
CharStuff = ([
"charmode" : 1, /* are we in character mode */
"noecho" : 1, /* do we echo input characters */
"charbuffer" : "", /* what we've typed of this line so far */
"tempbuffer" : "", /* the last line, before alias expansion */
"charshell" : 0, /* hell if i remember */
]);
}
static int ReceiveChars(string str){
string s;
int c;
if(!this_object()) return 0;
if(str){
c = str[0];
s = str[0..0];
}
if(!CharStuff["charbuffer"]) CharStuff["charbuffer"] = "";
#if CHAR_DEBUG
if(sizeof(str) > 1) debug("unexpected string: "+str);
else debug("CHARIO received: "+s+", aka: "+c, "black");
#endif
if(!sizeof(CharStuff["escape"]) && (c > 31 && c < 127)){
/* Printable character, and we're not waiting on an ESC seq,
* Let's add it to the character buffer, and then
* "normalize" any Pinkfish sequences.
*/
CharStuff["charbuffer"] += s;
if(sizeof(CharStuff["charbuffer"]) > 1 && last(CharStuff["charbuffer"],2) == "%^"){
/* replace pinkfish to avoid weirdness */
CharStuff["charbuffer"] = truncate(CharStuff["charbuffer"],2);
CharStuff["charbuffer"] += "%%^^";
}
this_object()->rAscii(s);
get_char("ReceiveChars", CharStuff["noecho"]);
return 1;
}
if(sizeof(CharStuff["escape"]) &&
member_array(30, CharStuff["escape"]) != -1){
int cl;
string esc;
CharStuff["escape"] += s;
esc = CharStuff["escape"];
if(last(esc,1) == "H" || last(esc,1) == "R" || sizeof(esc) > 10){
cl = 1;
this_object()->rAnsi(esc);
}
else if(sizeof(esc) > 2 && esc[1] == 91){
switch(esc[2]){
case 65 : this_object()->rArrow("up"); cl = 1; break;
case 66 : this_object()->rArrow("down"); cl = 1; break;
case 68 : this_object()->rArrow("left"); cl = 1; break;
case 67 : this_object()->rArrow("right"); cl = 1; break;
case 51 :
if(sizeof(esc) > 3 && esc[3] == 126){
this_object()->rDel();
cl = 1;
}
break;
}
}
if(cl) CharStuff["escape"] = "";
get_char("ReceiveChars", CharStuff["noecho"]);
return 1;
}
switch(c){
case 0 : case 8 : case 127 : this_object()->rBackspace(); break;
case 1 : this_object()->rCtrl("a"); break;
case 2 : this_object()->rCtrl("b"); break;
case 3 : this_object()->rCtrl("c"); break;
case 4 : this_object()->rCtrl("d"); break;
case 5 : this_object()->rCtrl("e"); break;
case 6 : this_object()->rCtrl("f"); break;
case 7 : this_object()->rCtrl("g"); break;
case 9 : this_object()->rCtrl("i"); break; /* aka Tab */
case 10 : case 13: this_object()->rEnter(); break;
case 11 : this_object()->rCtrl("k"); break;
case 12 : this_object()->rCtrl("l"); break;
case 14 : this_object()->rCtrl("n"); break;
case 15 : this_object()->rCtrl("o"); break;
case 16 : this_object()->rCtrl("p"); break;
case 17 : this_object()->rCtrl("q"); break;
case 18 : this_object()->rCtrl("r"); break;
case 19 : this_object()->rCtrl("s"); break;
case 20 : this_object()->rCtrl("t"); break;
case 21 : this_object()->rCtrl("u"); break;
case 22 : this_object()->rCtrl("v"); break;
case 23 : this_object()->rCtrl("w"); break;
case 24 : this_object()->rCtrl("x"); break;
case 25 : this_object()->rCtrl("y"); break;
case 26 : this_object()->rCtrl("z"); break;
case 28 : this_object()->rCtrl("28"); break;
case 30 : rEsc(); break;
case 31 : this_object()->rCtrl("31"); break;
}
if(!this_object()){
// Probably a warmboot or userload
return 0;
}
if(in_edit(this_object())) CharStuff["noecho"] = 0;
else CharStuff["noecho"] = 1;
#ifdef __GET_CHAR_IS_BUFFERED__
if(CharStuff["charmode"]) get_char("ReceiveChars", CharStuff["noecho"]);
#endif
this_object()->RedrawPrompt();
return CharStuff["charmode"];
}
varargs int CancelCharmode(int extra){
int ret = 1;
#if CHAR_DEBUG
debug("cancelling! stack: "+get_stack());
#endif
if(!CharStuff) CharStuff = ([]);
flush_messages();
CharStuff["charbuffer"] = "";
if(!CharStuff["charmode"] && !query_charmode(this_object())) return 0;
CharStuff["charmode"] = 0;
#ifdef __DSLIB__
remove_get_char(this_object());
remove_charmode(this_object());
#else
ReceiveChars(sprintf("%c",13));
#endif
if(extra) ReceiveChars(sprintf("%c",13));
this_object()->SetProperty("was_charmode", 0);
this_object()->SetProperty("reprompt", 0);
return ret;
}
int SetCharmode(int x){
if(!x) CharStuff["charmode"] = 0;
#ifdef __GET_CHAR_IS_BUFFERED__
else CharStuff["charmode"] = 1;
remove_get_char(this_object());
if(!(this_object()->GetCedmode())){
get_char("ReceiveChars", CharStuff["noecho"]);
}
else get_char("ReceiveChar", CharStuff["noecho"]);
#endif
return CharStuff["charmode"];
}
int GetCharmode(){
if(!CharStuff) CharStuff = ([]);
return CharStuff["charmode"];
}
static string GetCharbuffer(){
if(!CharStuff) CharStuff = ([]);
return (CharStuff["charbuffer"] || "" );
}
static string SetCharbuffer(string str){
if(!CharStuff) CharStuff = ([]);
return CharStuff["charbuffer"] = ( str || "" );
}
static string GetTempbuffer(){
if(!CharStuff) CharStuff = ([]);
return (CharStuff["tempbuffer"] || "" );
}
static string SetTempbuffer(string str){
if(!CharStuff) CharStuff = ([]);
return CharStuff["tempbuffer"] = ( str || "" );
}
void CheckCharmode(){
if(!in_edit() && !in_input() && this_object()->GetProperty("was_charmode")){
CharStuff["charmode"] = 1;
}
if(CharStuff["charmode"] && !query_charmode(this_object())){
if(!in_edit() && !in_input()) SetCharmode(CharStuff["charmode"]);
if(!this_player() || this_player() != this_object()){
SetCharmode(1);
this_object()->RedrawPrompt();
}
}
if(!CharStuff["charmode"] && query_charmode(this_object()) > 0){
CancelCharmode();
}
}
void heart_beat(){
CheckCharmode();
}
int rEsc(){
CharStuff["escape"] = sprintf("%c", 30);
if(in_edit(this_object())) CharStuff["noecho"] = 0;
else CharStuff["noecho"] = 1;
return 1;
}
int SetNoEcho(int x){
if(x) CharStuff["noecho"] = 1;
else CharStuff["noecho"] = 0;
return CharStuff["noecho"];
}
int GetNoEcho(){
return CharStuff["noecho"];
}