Issue
Getting the current mouse pointer position in Python is trivial, through the use of the Windows API ctypes
libraries. However, it seem that taking the step from the mouse pointer's screen position position (x,y), to get the current text cursor position of the current terminal window, seem a huge difficulty.
In addition it makes it worse that the programmer community keep confusing mouse pointer position with text cursor position. Historically there never was a mouse "cursor" so when people are saying "cursor", they should mean text cursor, and not the other way around. Because of this error, Stackoverflow is full of questions and answers, relating to "cursor", but seemingly none relates to getting the terminal shell's current character position. [The cursed cursor!]
To get the relative mouse pointer position:
from ctypes import windll, wintypes, byref
def get_cursor_pos():
cursor = wintypes.POINT()
windll.user32.GetCursorPos(byref(cursor))
return (cursor.x, cursor.y)
while(1): print('{}\t\t\r'.format(get_cursor_pos()), end='')
I want to have a function that give me the last position in terms of character row and column. Perhaps something like this:
def cpos():
xy = here_be_magic()
return xy
# Clear screen and start from top:
print('\x1b[H', end='');
print('12345', end='', flush=True); xy=cpos(); print('( {},{})'.format(xy[0],xy[1]),end='', flush=True)
# 12345 (1,5) # written on top of blank screen
How do I get the text
cursor position in (row,column) inside my terminal?
(And without making any assumptions and having to write my own window manager?)
Ultimately I hope to use this to find the last cursor position in any terminal window, (and possibly used by any program?)
Possibly related (but not useful) SO Questions:
- get current key cursors position text [C#]
- How to get the text cursor position in Windows? [mouse?]
- How to get the current cursor position in python readline [mouse?]
- How to change cursor position in powershell console
- python ctypes, pass double pointer by reference
- Python and ctypes: how to correctly pass "pointer-to-pointer" into DLL?
UPDATE (2022-01-17)
Looking through the MS documentation, I am now convinced it should be possible to get this from the (older, non-VT-based) API call, GetConsoleScreenBufferInfo
which is given like this.
BOOL WINAPI GetConsoleScreenBufferInfo(
_In_ HANDLE hConsoleOutput, # A handle to the console screen buffer. The handle must have the GENERIC_READ access right.
_Out_ PCONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo # A pointer to a CONSOLE_SCREEN_BUFFER_INFO structure that receives the console screen buffer information.
);
typedef struct _CONSOLE_SCREEN_BUFFER_INFO {
COORD dwSize; # contains the size of the console screen buffer, in character columns and rows.
COORD dwCursorPosition; # contains the column and row coordinates of the cursor in the console screen buffer.
WORD wAttributes; # Character attributes (divided into two classes: color and DBCS)
SMALL_RECT srWindow; # A SMALL_RECT structure that contains the console screen buffer coordinates of the upper-left and lower-right corners of the display window.
COORD dwMaximumWindowSize; # A COORD structure that contains the maximum size of the console window, in character columns and rows, given the current screen buffer size and font and the screen size.
} CONSOLE_SCREEN_BUFFER_INFO; #
# Defines the coordinates of a character cell in a console screen buffer.
# The origin of the coordinate system (0,0) is at the top, left cell of the buffer.
typedef struct _COORD {
SHORT X; # The horizontal coordinate or column value. The units depend on the function call.
SHORT Y; # The vertical coordinate or row value. The units depend on the function call.
} COORD, *PCOORD;
typedef struct _SMALL_RECT {
SHORT Left;
SHORT Top;
SHORT Right;
SHORT Bottom;
} SMALL_RECT;
So in light of this, I was thinking the following would work.
cls='\x1b[H'
from ctypes import windll, wintypes, byref
def cpos():
cursor = wintypes._COORD(ctypes.c_short)
windll.kernel32.GetConsoleScreenBufferInfo(byref(cursor))
return (cursor.X, cursor.Y)
cpos()
# TypeError: '_ctypes.PyCSimpleType' object cannot be interpreted as an integer
Solution
The problem was to locate the various Structure definitions. After having experimented significantly, I've got the following working solution.
#!/usr/bin/env python -u
# -*- coding: UTF-8 -*-
#------------------------------------------------------------------------------
from ctypes import windll, wintypes, Structure, c_short, c_ushort, byref, c_ulong
from readline import console
#------------------------------------------------
# Win32 API
#------------------------------------------------
SHORT = c_short
WORD = c_ushort
DWORD = c_ulong
STD_OUTPUT_HANDLE = DWORD(-11) # $CONOUT
# These are already defined, so no need to redefine.
COORD = wintypes._COORD
SMALL_RECT = wintypes.SMALL_RECT
CONSOLE_SCREEN_BUFFER_INFO = console.CONSOLE_SCREEN_BUFFER_INFO
#------------------------------------------------
# Main
#------------------------------------------------
wk32 = windll.kernel32
hSo = wk32.GetStdHandle(STD_OUTPUT_HANDLE)
GetCSBI = wk32.GetConsoleScreenBufferInfo
def cpos():
csbi = CONSOLE_SCREEN_BUFFER_INFO()
GetCSBI(hSo, byref(csbi))
xy = csbi.dwCursorPosition
return '({},{})'.format(xy.X,xy.Y)
cls='\x1b[H'
print('\n'*61)
print(cls+'12345', end='', flush=True); print(' {}'.format(cpos()), flush=True)
# 12345 (5,503)
Answered By - not2qubit
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.