terminal-win: ask the terminal for its cell size under ConPTY

ConPTY has no font, GetCurrentConsoleFont() reports 0x16, so the
terminal VOs fell back to a 320 pixel wide canvas and the mouse position
had no horizontal component. Send XTWINOPS 16 and parse it's reply, from
its key events, which carry no virtual key unlike a pressed key.
This commit is contained in:
Kacper Michajłow
2026-10-09 06:56:27 +02:00
parent 30a31b77d1
commit 6bd80b06f9
+48
View File
@@ -21,6 +21,7 @@
#include <fcntl.h>
#include <stdio.h>
#include <stdint.h>
#include <stdatomic.h>
#include <string.h>
#include <windows.h>
#include <io.h>
@@ -133,6 +134,9 @@ void terminal_get_size(int *w, int *h)
}
}
// Cell size the terminal reported, ConPTY has no font of its own
static atomic_int term_cell_w, term_cell_h;
static bool get_font_size(int *w, int *h)
{
CONSOLE_FONT_INFO finfo;
@@ -141,10 +145,24 @@ static bool get_font_size(int *w, int *h)
if (res) {
*w = finfo.dwFontSize.X;
*h = finfo.dwFontSize.Y;
if (*w <= 0) {
*w = atomic_load_explicit(&term_cell_w, memory_order_acquire);
*h = atomic_load_explicit(&term_cell_h, memory_order_relaxed);
}
}
return res;
}
// XTWINOPS 16: the terminal answers with CSI 6 ; height ; width t, which
// the input thread takes from its key events.
static void request_cell_size(void)
{
int fw = 0, fh = 0;
if (!is_vt[STDOUT_FILENO] || !get_font_size(&fw, &fh) || fw > 0)
return;
mp_console_write(hSTDOUT, (bstr)bstr0_lit("\033[16t"));
}
void terminal_get_size2(int *rows, int *cols, int *px_width, int *px_height)
{
int w = 0, h = 0, fw = 0, fh = 0;
@@ -169,6 +187,31 @@ static bool has_input_events(HANDLE h)
static DWORD last_buttons;
static bool take_reply(int c)
{
static char reply[32];
static int len;
if (c == '\033') {
len = 0;
} else if (!len) {
return false;
}
reply[len++] = c;
if (len == sizeof(reply) - 1) {
len = 0; // not a reply after all
} else if (len > 2 && c >= 0x40 && c <= 0x7e) {
reply[len] = '\0';
len = 0;
int w = 0, h = 0;
if (sscanf(reply, "\033[6;%d;%dt", &h, &w) == 2 && w > 0 && h > 0) {
atomic_store_explicit(&term_cell_h, h, memory_order_relaxed);
atomic_store_explicit(&term_cell_w, w, memory_order_release);
notify_resize();
}
}
return true;
}
static void read_input(HANDLE in)
{
// Process any input events in the buffer
@@ -188,6 +231,10 @@ static void read_input(HANDLE in)
if (!record->bKeyDown)
continue;
// A reply comes as characters without a virtual key, unlike a pressed key.
if (!record->wVirtualKeyCode && take_reply(record->uChar.UnicodeChar))
continue;
UINT vkey = record->wVirtualKeyCode;
bool ext = record->dwControlKeyState & ENHANCED_KEY;
@@ -305,6 +352,7 @@ void terminal_setup_getch(struct input_ctx *ictx)
return;
}
running = true;
request_cell_size();
}
}