diff -urN readline-8.3/input.c.orig readline-8.3/input.c
--- readline-8.3/input.c.orig	2025-05-02 15:29:05.000000000 +0200
+++ readline-8.3/input.c	2025-07-08 14:05:06.507168500 +0200
@@ -179,6 +179,14 @@
 static unsigned char ibuffer[512];
 static int ibuffer_len = sizeof (ibuffer) - 1;
 
+#if defined (__MINGW32__)
+#include <windows.h>
+static int _win32_getch (void);
+static int _win32_kbhit (void);
+static char _win32_buf[16] = {'0'};
+static int _win32_bufidx = 0;
+#endif
+
 #define any_typein (push_index != pop_index)
 
 int
@@ -190,7 +198,11 @@
 int
 _rl_pushed_input_available (void)
 {
-  return (push_index != pop_index);
+  return (push_index != pop_index)
+#if defined (__MINGW32__)
+    || _win32_bufidx > 0
+#endif
+    ;
 }
 
 /* Return the amount of space available in the buffer for stuffing
@@ -326,7 +338,7 @@
      that we read it normally. */
    if (result == -1)
      {
-       chars_avail = isatty (tty) ? _kbhit () : 0;
+       chars_avail = isatty (tty) ? _win32_kbhit () : 0;
        result = 0;
      }
 #endif
@@ -425,7 +437,7 @@
 
 #if defined (__MINGW32__)
   if (isatty (tty))
-    return (_kbhit ());
+    return (_win32_kbhit ());
 #endif
 
   return 0;
@@ -829,6 +841,139 @@
   return (c);
 }
 
+#if defined (__MINGW32__)
+#define _WIN32_READ_NOCHAR (-2)
+
+static int
+_win32_getch_internal (int block)
+{
+  INPUT_RECORD rec;
+  DWORD evRead, waitResult;
+  HANDLE hInput = (HANDLE) _get_osfhandle (fileno (rl_instream));
+
+  if (_win32_bufidx > 0)
+    return _win32_buf[--_win32_bufidx];
+
+  hInput = (HANDLE) _get_osfhandle (fileno (rl_instream));
+
+  do
+    {
+      if (! block)
+        {
+          if (WaitForSingleObject (hInput, _keyboard_input_timeout/1000) != WAIT_OBJECT_0)
+            return _WIN32_READ_NOCHAR;
+        }
+
+      if (! ReadConsoleInputW (hInput, &rec, 1, &evRead) || evRead != 1)
+        return EOF;
+
+      switch (rec.EventType)
+        {
+          case KEY_EVENT:
+            if ((rec.Event.KeyEvent.bKeyDown &&
+               (rec.Event.KeyEvent.wVirtualKeyCode < VK_SHIFT ||
+                rec.Event.KeyEvent.wVirtualKeyCode > VK_MENU)) ||
+               (!rec.Event.KeyEvent.bKeyDown &&
+                rec.Event.KeyEvent.wVirtualKeyCode == VK_MENU &&
+                rec.Event.KeyEvent.uChar.UnicodeChar))
+              {
+                if (rec.Event.KeyEvent.uChar.UnicodeChar)
+                  {
+                    int result = (int) rec.Event.KeyEvent.uChar.UnicodeChar;
+                    char charbuf[5] = {0};
+                    wchar_t unicode[2] = {result, 0};
+                    int utf16_code_units = 1;
+                    if ((unicode[0] & 0xF800) == 0xD800)  /* outside BMP */
+                      {
+                        ReadConsoleInputW (hInput, &rec, 1, &evRead);
+                        unicode[1] = (int) rec.Event.KeyEvent.uChar.UnicodeChar;
+                        utf16_code_units++;
+                      }
+                    /* convert to current codepage or UTF-8 byte sequence */
+                    unsigned int codepage = CP_THREAD_ACP;
+                    if (_rl_utf8locale)
+                      codepage = CP_UTF8;
+                    int len = WideCharToMultiByte (codepage, 0,
+                                                   (wchar_t *) &unicode, utf16_code_units,
+                                                   charbuf, 5, NULL, NULL);
+                    /* buffer is read from back to front */
+                    for (int i=0; i<len-1; i++)
+                      _win32_buf[_win32_bufidx++] = (unsigned char) charbuf[len-i-1];
+
+                    return (int) (unsigned char) charbuf[0];
+                  }
+
+                switch (rec.Event.KeyEvent.wVirtualKeyCode)
+                  {
+                    /* buffer is read from back to front */
+                    case VK_UP:
+                      _win32_buf[_win32_bufidx++] = 'A';
+                      _win32_buf[_win32_bufidx++] = '[';
+                      return 0x1b;  /* ESC */
+                    case VK_DOWN:
+                      _win32_buf[_win32_bufidx++] = 'B';
+                      _win32_buf[_win32_bufidx++] = '[';
+                      return 0x1b;  /* ESC */
+                    case VK_RIGHT:
+                      _win32_buf[_win32_bufidx++] = 'C';
+                      _win32_buf[_win32_bufidx++] = '[';
+                      return 0x1b;  /* ESC */
+                    case VK_LEFT:
+                      _win32_buf[_win32_bufidx++] = 'D';
+                      _win32_buf[_win32_bufidx++] = '[';
+                      return 0x1b;  /* ESC */
+                    case VK_HOME:
+                      _win32_buf[_win32_bufidx++] = 'H';
+                      _win32_buf[_win32_bufidx++] = '[';
+                      return 0x1b;  /* ESC */
+                    case VK_END:
+                      _win32_buf[_win32_bufidx++] = 'F';
+                      _win32_buf[_win32_bufidx++] = '[';
+                      return 0x1b;  /* ESC */
+                    case VK_DELETE:
+                      _win32_buf[_win32_bufidx++] = 8;
+                      _win32_buf[_win32_bufidx++] = 'C';
+                      _win32_buf[_win32_bufidx++] = '[';
+                      return 0x1b;  /* ESC */
+                    default:
+                      break;
+                  }
+              }
+            break;
+
+          case WINDOW_BUFFER_SIZE_EVENT:
+            rl_resize_terminal ();
+            break;
+
+          default:
+            break;
+        }
+    }
+  while (1);
+}
+
+static int 
+_win32_kbhit (void)
+{
+  int result;
+
+  result = _win32_getch_internal (0);
+  if (result == _WIN32_READ_NOCHAR
+      || result == EOF)
+    return 0;
+
+  _win32_buf[_win32_bufidx++] = result;
+
+  return _win32_bufidx;
+}
+
+static int
+_win32_getch (void)
+{
+  return (_win32_getch_internal (1));
+}
+#endif
+
 int
 rl_getc (FILE *stream)
 {
@@ -863,7 +1008,7 @@
 
 #if defined (__MINGW32__)
       if (isatty (fd))
-	return (_getch ());	/* "There is no error return." */
+        return (_win32_getch ());
 #endif
       result = 0;
 #if defined (HAVE_PSELECT) || defined (HAVE_SELECT)
