Linux console cursor position

How to get current keyboard cursor position in Linux terminal

I am dealing with an issue in Ubuntu. I want to get current keyboard cursor position in terminal via Gcc any assist.

There’s nothing in the C standard to give you that information. You may want to use curses to do cursor positioning and similar things.

Usually the answer to the underlying question here is either «Use ncurses» or «use GNU Readline» or some variation on those themes, depending on what you actually want to do.

1 Answer 1

«Terminal» is a program, or more accurately a description of a large class of programs, which implements a graphical interface emulating an external terminal (which would have been connected to your computer via a serial cable, or in some similar fashion). Your program communicates with the terminal emulator through a kind of bidirectional pipe (a «pseudoterminal») implemented by the operating system; to your program it looks like a pair of ordinary streams ( stdin and stdout ).

Linux itself has a terminal emulator, called «the console», which can be used instead of a window manager. Few programmers use it these days, but it’s still there if you want to experiment. The console is a «terminal» (and there are usually several of them which you can switch between using a control+function key). As you might expect from the words «terminal» and «pseudoterminal», these basically look the same to your application.

There are a ton of details, which I’m skipping over because it would take a book to describe the whole thing.

The only connection between your program and the terminal (or pseudoterminal) is that you can send it a stream of characters, and you can receive a stream of characters from it. There is no other communication. There’s no hidden operating system interface, because the terminal emulator is not part of the operating system. It’s not even part of the window manager. It’s just another userland application running without special privileges, just like your application.

You often want to do things other than just send characters to the output device. Maybe you want to clear the screen, or move the cursor to another location, or change the colour of the text or the background. All of these things are done by sending specially coded sequences interspersed with the text you’re displaying. The operating system doesn’t mediate or verify these sequences, and there’s no definitive standard for how the terminal emulator should interpret them, but there is common framework which most terminal emulators conform to, to some extent, which makes it possible to actually write code which doesn’t need to know exactly which terminal emulator is being used at the moment. The terminfo library is commonly used to describe the available terminals; by convention, the environment variable TERM contains the name of the relevant terminfo configuration, and that configuration can be used to create concrete control sequence strings suitable for the configured terminal [Note 1].

Now let’s get back to your initial question: «how do I find out the current cursor location?» That’s one of a small number of possible queries, which are also implemented as control sequences. Specifically, you send the terminal a control sequnce which asks it where the cursor is (usually the four characters \x1B[6n ) and the terminal eventually replies with a control sequence which might look something like \x1B12,7R meaning that the cursor was on row 12 at column 7 at the moment that the control sequence was sent [Note 2]. So you could use terminfo to help you send the query and then attempt to parse the reply when it comes.

Читайте также:  Linux setting stack size

Note that the response is not synchronous with the query, since the user could be typing while the query is sent. (However, the response is sent as a contiguous sequence.) So part of the parsing process is disentangling the user input from the query response.

My guess is that you don’t actually want to do all that work. In most cases, if you want to write a console application which does something less boring than just write output sequentially to a terminal window, you should use ncurses (also maintained by Thomas Dickey) or some other similar library. Ncurses takes full responsibility for maintaining the console image, jumping through the necessary hoops to communicate with the terminal emulator; one of its features is to keep track of the current cursor position [Note 3].

Another option, if you are only trying to provide better line editing and tab completion, is to use the GNU Readline library, or similar interfaces available for other operating systems.

Notes

  1. This might or might not be the terminal you’re actually using, since TERM is just an environment variable. You could set it yourself if you wanted it.
  2. I took those codes from man 4 console_codes ; another good source of information is Thomas Dickey’s terse list of code sequences understood by xterm .
  3. As far as I know, Ncurses does not use the cursor-position query to figure out where the cursor is on the screen. It maintains its own copy of the screen being displayed, which includes the current cursor position. You can use the macro getyx() to ask for what it considers the current cursor position.

Источник

How do I move the console cursor to (x, y) on unix?

I have used and on windows for this kind of thing, but on unix the only thing I can find is , which uses a lot of C and doesn’t support a lot of C++ functions. How can I move the console cursor to (x, y), while also being able to do object-oriented programming? Edit: I’m trying to make simple games in C++ using the console as a display. I know it’s not ideal to do so, but this is for a project that can’t use Visual C++ or any other graphics. Think something like snake or minesweeper. I need to be able to cout in different locations, without updating the entire screen in the process. It needs to be compatible with unix systems.

1 Answer 1

One very simple way is through ANSI escape codes:

#include void moveCursor(std::ostream& os, int col, int row) < os int main()

The sequence [ row , col H (the escape character is ASCII 27 or octal '\033' ) performs absolut cursor positioning. On most common terminals this should place one "X" in the top-left corner, and the second in column 13, row 8 (counts are 1-based).

Edit: hvd’s comment is of course spot-on: This is very simple, but ncurses is complex for a reason. It is guaranteed to work more reliably and in a much wider variety of settings than a plain escape code. Depending on what you actually want to achieve, I agree with hvd that you should be very careful before picking this simple hack as the solution to your problem.

Читайте также:  Adding alias in linux

Источник

Set and read cursor position in terminal (windows and linux)

I wanted to overwrite the output for my sensor readings and do this in a platform independent way, via C/C++.

On windows, you can simply [1]:

#include COORD GetCursorPosition() < HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_SCREEN_BUFFER_INFO bufferInfo; GetConsoleScreenBufferInfo(h, &amp;bufferInfo); return bufferInfo.dwCursorPosition; >void SetCursorPosition(int XPos, int YPos)

On linux, you can use terminal commands (this possibly also works on other systems) to set the position. Unfortunately, reading the position is not so easy. The simplest way is to count the newlines and move the cursor, \r and up as many times as necessary, see commands below [2].

#include void SetCursorPosition(int XPos, int YPos) < printf("\033[%d;%dH",YPos+1,XPos+1); >void getCursor(int* x, int* y) < printf("\033[6n"); /* This escape sequence !writes! the current coordinates to the terminal. We then have to read it from there, see [4,5]. Needs , and some others */ scanf("\033[%d;%dR", x, y); > // Or platform independent using (n)curses #include // similar name for windows initscr(); // is required before getxy call getyx(curscr, y, x); void getyx(WINDOW *win, int y, int x);
- Position the Cursor: \033[;H Or \033[;f puts the cursor at line L and column C. - Move the cursor up N lines: \033[A - Move the cursor down N lines: \033[B - Move the cursor forward N columns: \033[C - Move the cursor backward N columns: \033[D - Clear the screen, move to (0,0): \033[2J - Erase to end of line: \033[K - Save cursor position: \033[s - Restore cursor position: \033[u

Источник

How to get the cursor position in bash?

Unfortunately, this prints characters to the standard output and I want to do it silently. Besides, this is not very portable. Is there a pure-bash way to achieve this ?

7 Answers 7

You have to resort to dirty tricks:

#!/bin/bash # based on a script from http://invisible-island.net/xterm/xterm.faq.html exec < /dev/tty oldstty=$(stty -g) stty raw -echo min 0 # on my system, the following line can be replaced by the line below it echo -en "\033[6n" >/dev/tty # tput u7 > /dev/tty # when TERM=xterm (and relatives) IFS=';' read -r -d R -a pos stty $oldstty # change from one-based to zero based so they work with: tput cup $row $col row=$(($ - 1)) # strip off the esc-[ col=$(($ - 1)) 

I'm using this command in PROMPT_COMMAND in order to find the horizontal cursor position so I can print a % in reverse video and then a new line whenever the output of the last command doesn't end with a newline. However I think the read or other commands needed are swallowing text when I paste multi-line commands into my shell. Any known solution to this?

You need to surround non-printing sequences with \[ and \] so their lengths aren't counted in the length of the prompt as documented here if you're not doing that. The stty should protect the read , but I'm not sure. Or you might need to save and restore stdin if the problem stems from the exec line. You might also try the technique linked to in a comment above this one.

@tooster: Yeah, there shouldn't be any output in shell startup scripts. EOF is never (or exceedingly rarely) missing. You mean a final newline is missing. Here is my attempt at providing that zsh feature in Bash. Here is someone's variation on that technique (with links to more).

Читайте также:  Узнать версию линукс через терминал

@Tooster: The echo of escape sequences (or tput ) that causes the cursor position to be emitted which is used in my answer here is the one that may be the output that vscode doesn't like. This is similar to the problem with ssh when startup scripts produce output, btw.

You could tell read to work silently with the -s flag:

echo -en "\E[6n" read -sdR CURPOS CURPOS=$

And then CURPOS is equal to something like 21;3 .

Thanks for this, I had to fill the rest of the line in a Makefile and ended up with this inside a function: echo "\033[6n\c"; read -sdR CURPOS; COLS_LEFT="$$(expr $$TERM_COLS - $$(echo $$ | cut -d';' -f 2;) + 1)";

echo -en "\033[6n"; sleep 1; read -sdR This method is incorrect. You have to disable lflag ECHO before the echo command.

In case anyone else is looking for this, I came across another solution here: https://github.com/dylanaraps/pure-bash-bible#get-the-current-cursor-position

Below is a slightly modified version with comments.

#!/usr/bin/env bash # # curpos -- demonstrate a method for fetching the cursor position in bash # modified version of https://github.com/dylanaraps/pure-bash-bible#get-the-current-cursor-position # #======================================================================================== #- #- THE METHOD #- #- IFS='[;' read -p $'\e[6n' -d R -a pos -rs || echo "failed with error: $? ; $" #- #- THE BREAKDOWN #- #- $'\e[6n' # escape code, [6n; #- #- This is the escape code that queries the cursor postion. see XTerm Control Sequences (1) #- #- same as: #- $ echo -en '\033[6n' #- $ 6;1R # '^[[6;1R' with nonprintable characters #- #- read -p $'\e[6n' # read [-p prompt] #- #- Passes the escape code via the prompt flag on the read command. #- #- IFS='[;' # characters used as word delimiter by read #- #- '^[[6;1R' is split into array ( '^[' '6' '1' ) #- Note: the first element is a nonprintable character #- #- -d R # [-d delim] #- #- Tell read to stop at the R character instead of the default newline. #- See also help read. #- #- -a pos # [-a array] #- #- Store the results in an array named pos. #- Alternately you can specify variable names with positions:    #- Or leave it blank to have all results stored in the string REPLY #- #- -rs # raw, silent #- #- -r raw input, disable backslash escape #- -s silent mode #- #- || echo "failed with error: $? ; $" #- #- error handling #- #- --- #- (1) XTerm Control Sequences #- http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Functions-using-CSI-_-ordered-by-the-final-character_s_ #======================================================================================== #- #- CAVEATS #- #- - if this is run inside of a loop also using read, it may cause trouble. #- to avoid this, use read -u 9 in your while loop. See safe-find.sh (*) #- #- #- --- #- (2) safe-find.sh by l0b0 #- https://github.com/l0b0/tilde/blob/master/examples/safe-find.sh #========================================================================================= #================================================================ # fetch_cursor_position: returns the users cursor position # at the time the function was called # output ":" #================================================================ fetch_cursor_position() < local pos IFS='[;' read -p $'\e[6n' -d R -a pos -rs || echo "failed with error: $? ; $" echo "$:$" > #---------------------------------------------------------------------- # print ten lines of random widths then fetch the cursor position #---------------------------------------------------------------------- # MAX=$(( $(tput cols) - 15 )) for i in ; do cols=$(( $RANDOM % $MAX )) printf "%$s" | tr " " "=" echo " $(fetch_cursor_position)" done 

Источник

Оцените статью
Adblock
detector