I'm trying to implement a serial cli where you can type and edit a command using a console like screen/minicom. In my testing, I'm using screen to connect to the serial interface. In trying to implement a delete character option, I'm not seeing the results I'm expecting.
I've been reading online on how to use ANSI escape sequences, which I'm finding that some such as ESC c to clear screen, and ESC[?25l to hide the cursor are working with my tests. But when I try to use ESC[1D to move the cursor to the left by 1, or any other cursor escape sequences, it isn't working as I would expect.
I've read through https://www.lihaoyi.com/post/BuildyourownCommandLinewithANSIescapecodes.html and https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797 for help on how to do this right.
For an example of some test code I'm using:
void SendESC(const char *code) {
Serial.write(27);
Serial.print(code);
}
void loop() {
char byteRead = Serial.read();
if (byteRead==8) {
if (m_buffer_read!=0) {
m_buffer_read--;
m_buffer[m_buffer_read] = '\0';
SendESC("[1000D");
SendESC("[0K");
Serial.print(m_line_indicator);
Serial.print(m_buffer);
size_t lineLen = strlen(m_line_indicator)+m_buffer_read;
char buf[7];
SendESC("[1000D");
sprintf(buf, "[%dC", lineLen);
SendESC(buf);
}
}
}
In running the above test, it seems like screen does not know the escape sequences are over and it does not pick up on the updated information. I can however confirm with a hex view of the serial data received that the escape sequences are being sent exactly as I expect.
Am I missing something?
Ok, so I cheated a bit and looked at the hexadecimal output from Linux over serial. Apparently Linux is using \x08\x1b[K to tell screen to delete, and also I learned that screen sends the ASCII code 127 instead of 8 for delete. I will continue to look at what Linux uses to finish developing this. Hopefully this helps someone else trying to do the same thing.
Related
The debugger seems to suppress viewing the contents of a UnicodeString in the Local Variable and Watch windows whenever the current function contains a UnicodeString::Length() call.
Running C++ Builder 10.3 Rio Enterprise (upgraded to 10.31 to try to solve the issue) where I have started a new project, added a button and put the following code in for the button. This a stripped down version of a large piece of code to track down and reproduce the issue.
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TFDQuery* qry = new TFDQuery(NULL);
UnicodeString search = "SELECT *\rFROM Client\rWHERE id>0;";
UnicodeString currLine;
int to, len;
qry->SQL->Clear();
to = search.Pos("\r");
while (to > 0) {
currLine = search.SubString(1, to-1);
qry->SQL->Add(currLine);
//len = search.Length()-1; // Offending line
search = search.SubString(to+1, 999999);
to = search.Pos("\r");
}
currLine = search;
qry->SQL->Add(currLine);
}
The picture below shows two different runs of this code. One is exactly as shown above (with one line commented out). The other shows with the line included.
My concern is that the the debugger only shows the apparent address of the variable named "search" and if I expand it, it shows "????", not the contents of the variable as shown by the arrow. Also note, the breakpoint is above the line that causes the debugger to switch views. Any ideas how I can get the contents of "search" to appear if I actually calculate the length of the substring (rather than placing "999999" for its length)?
After some experimenting, I can now partially answer my own question with a potential workaround. Replacing the "search.Length()" with "wcslen(search.c_str())" seems to work, at least it does not have the side effect of displaying only addresses for UnicodeStrings in the watch list and and local variables windows. At this point, I haven't thoroughly tested if this eventually raises some other problem. But why should I have to do this for such a fundamental type to the language?
I am trying to use libgpm, looks like the program detects mouse clicks,
but as a side effect it prints something like this to the terminal:
^[[M <7^[[M#<7^[[M <7^[[M#<7^[[M <7^[[M#<7^[[M <7^[[M#<7^[[M Y=^[[M#M<^[[M !=^[[M#)=
Even if I remove any calls to Gpm_Getc(), leaving the code as simple as this:
#include <gpm.h>
int main(int argc, char *argv[])
{
Gpm_Connect conn;
int c;
conn.eventMask = 0;
conn.defaultMask = ~0;
conn.minMod = 0;
conn.maxMod = ~0;
if (Gpm_Open(&conn, 0) == -1)
printf("Cannot connect to mouse server\n");
while (1);
Gpm_Close();
return 0;
}
I still see those gibberish codes. I reckon, they represent the mouse events. But in my code there is no direct instruction to print them. Why are they printed to my terminal? How can this be avoided?
I use gnome-terminal on linux, not a real console, if that matters.
If the TERM environment variable is xterm, GPM won't try to open the Linux console.
Instead, it simply turns on xterm mouse-mode (which makes the terminal send escape sequences), and it turns out, expects the application to handle that rather than transforming the escape sequences into its protocol.
From ncurses' viewpoint, for instance, that makes its behavior in a terminal emulator less than useful, and the library checks for this case and ignores GPM (since 2010).
I'm trying to get this snippet to work, but it seems it won't work in Windows. Under Linux it works just fine!
Here is the sample snippet of code demonstrating the usage:
tops = []
for ind, top in enumerate(lr.top):
color = colors.setdefault(top, COLORS[len(colors) % len(COLORS)])
if top in disconnected_tops:
top = '\033[1;4m' + top
if len(lr.loss_weight) > 0:
top = '{} * {}'.format(lr.loss_weight[ind], top)
tops.append('\033[{}m{}\033[0m'.format(color, top))
top_str = ', '.join(tops)
When the whole script is run, the escape character seems not to be working and weird characters show up on the screen. How do I get this to work on Windows?
I found the problem!
I had to use init() in the script that was missing originally!.
Seems init() is not needed in Linux based OSes!since if it were!, this shouldn't had worked there in first place!
Ok.Here is the documentation itself!:
On Windows, calling init() will filter ANSI escape sequences out of
any text sent to stdout or stderr, and replace them with equivalent
Win32 calls.
On other platforms, calling init() has no effect (unless you request
other optional functionality; see “Init Keyword Args”, below). By
design, this permits applications to call init() unconditionally on
all platforms, after which ANSI output should just work.
I'm just starting learning C++/XAML windows store app development but for the life of me I can't find a nice way to print variable values to the "Output" window in VS2012.
Debug.WriteLine() doesn't seem to exist for Windows Store apps and I can't find a way to print other than OutputDebugString() which I can't use to print variable values (without some heavy formatting).
Is there just an easy way to print the example line:
mouse position X: 12
for example, where 12 is an integer that comes from MouseDelta.
Thanks for your time,
Poncho
Not really, no. You could write a little function that formatted like printf and passed along the resulting string to OutputDebugString() but there's nothing more straightforward available.
I guess you could use ToString(), Platform::String::operator+, and Platform::String::Data() to accomplish this; though it's a little ugly:
OutputDebugString( ("mouse position X:" + MouseDelta.X.ToString())->Data() );
Here is a nice alternative: http://seaplusplus.com/2012/06/25/printf-debugging-in-metro-style-apps/, basically it allocates a console for your Windows Store App, obviously this will fail certification but given that this may be just for debug purposes only, it will fine. I'm copying the relevant code here:
// Include Windows.h for WINBASEAPI and WINAPI:
#include <Windows.h>
// Declare AllocConsole ourselves, since Windows.h omits it:
extern "C" WINBASEAPI int WINAPI AllocConsole();
auto main(Platform::Array<Platform::String^>^) -> int
{
AllocConsole();
std::wcout << L"Hello there!" << std::endl;
std::getchar();
return EXIT_SUCCESS;
}
However if you want to see such output inside your app, then you may want to use Console Class for Modern UI Apps which implements part of the .NET System.Console and can be safely used inside Windows Store apps.
This solution uses a wrapper around OutputDebugString:
void WinLog(const wchar_t *text, int n)
{
wchar_t buf[1024];
_snwprintf_s(buf, 1024, _TRUNCATE, L"%s %d\n", text, n);
OutputDebugString(buf);
}
which can be called as follows:
WinLog(L"The Answer is", 42);
My app reading escape sequences from terminal in raw mode. And when it's running on xterm I got F2 like "\eOQ". But when it's running in linux tty terminal (Switching by Ctrl-Alt-F1) I got "\e[[[B".
What is the correct way to determine that I got F2 independent from terminal type application running on?
If you're wanting to read terminal keypresses, you likely want to look at something like libtermkey , which abstracts the general problem away for you. Internally it uses a combination of terminfo lookups, or hardcoded knowledge of the extended xterm-like model for modified keypresses, so it can understand things like Ctrl-Up, which a regular curses/etc... cannot.
while((ret = termkey_waitkey(tk, &key)) != TERMKEY_RES_EOF) {
termkey_strfkey(tk, buffer, sizeof buffer, &key, TERMKEY_FORMAT_VIM);
printf("You pressed key %s\n", buffer);
if(key.type == TERMKEY_TYPE_FUNCTION &&
!key.modifiers &&
key.code.number = 2)
printf("Got F2\n");
}
Ok, as I got the best way to use [n]curses library. It is read terminfo (termcap) database and determine what mean escape sequence you got depend on terminal type.
It is not necessary using it's terminal graphics functions. To get correct escape sequences using curses you may do the following:
newterm(NULL, stdout, stdin);
raw();
noecho();
keypad();
ch = getch();
if (ch == KEY_F(2)) printf("Got F2");
endwin();
Also, it is probably possibly do it manually by reading terminfo database in you app.