Class: IO (Ruby 2.7.2)
Description: Class : IO - Ruby 2.7.2

### Home Classes Methods

### In Files

- io/console/console.c

### Parent

### Namespace

- MODULE IO::generic_readable
- CLASS IO::ConsoleMode

### Methods

- ::console
- ::console_size
- ::default_console_size
- #beep
- #check_winsize_changed
- #clear_screen
- #console_mode
- #console_mode=
- #cooked
- #cooked!
- #cursor
- #cursor=
- #cursor_down
- #cursor_left
- #cursor_right
- #cursor_up
- #echo=
- #echo?
- #erase_line
- #erase_screen
- #getch
- #getpass
- #goto
- #goto_column
- #iflush
- #ioflush
- #noecho
- #oflush
- #pressed?
- #raw
- #raw!
- #scroll_backward
- #scroll_forward
- #winsize
- #winsize=

### Class/Module Index

Quicksearch

- IO
- IO::generic_readable

No matching classes.

# IO

### Public Class Methods

console → # click to toggle source
console(sym, *args)

Returns an File instance opened console.

If `sym` is given, it will be sent to the opened console with `args` and the result will be returned instead of the console IO itself.

You must require ‘io/console’ to use this method.

                   static VALUE
    console_dev(int argc, VALUE *argv, VALUE klass)
    {
        VALUE con = 0;
        rb_io_t *fptr;
        VALUE sym = 0;

        rb_check_arity(argc, 0, UNLIMITED_ARGUMENTS);
        if (argc) {
            Check_Type(sym = argv[0], T_SYMBOL);
        }
        if (klass == rb_cIO) klass = rb_cFile;
        if (rb_const_defined(klass, id_console)) {
            con = rb_const_get(klass, id_console);
            if (!RB_TYPE_P(con, T_FILE) ||
                (!(fptr = RFILE(con)->fptr) || GetReadFD(fptr) == -1)) {
                rb_const_remove(klass, id_console);
                con = 0;
            }
        }
        if (sym) {
            if (sym == ID2SYM(id_close) && argc == 1) {
                if (con) {
                    rb_io_close(con);
                    rb_const_remove(klass, id_console);
                    con = 0;
                }
                return Qnil;
            }
        }
        if (!con) {
            VALUE args[2];
    #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H || defined HAVE_SGTTY_H
    # define CONSOLE_DEVICE "/dev/tty"
    #elif defined _WIN32
    # define CONSOLE_DEVICE "con$"
    # define CONSOLE_DEVICE_FOR_READING "conin$"
    # define CONSOLE_DEVICE_FOR_WRITING "conout$"
    #endif
    #ifndef CONSOLE_DEVICE_FOR_READING
    # define CONSOLE_DEVICE_FOR_READING CONSOLE_DEVICE
    #endif
    #ifdef CONSOLE_DEVICE_FOR_WRITING
            VALUE out;
            rb_io_t *ofptr;
    #endif
            int fd;

    #ifdef CONSOLE_DEVICE_FOR_WRITING
            fd = rb_cloexec_open(CONSOLE_DEVICE_FOR_WRITING, O_RDWR, 0);
            if (fd < 0) return Qnil;
            rb_update_max_fd(fd);
            args[1] = INT2FIX(O_WRONLY);
            args[0] = INT2NUM(fd);
            out = rb_class_new_instance(2, args, klass);
    #endif
            fd = rb_cloexec_open(CONSOLE_DEVICE_FOR_READING, O_RDWR, 0);
            if (fd < 0) {
    #ifdef CONSOLE_DEVICE_FOR_WRITING
                rb_io_close(out);
    #endif
                return Qnil;
            }
            rb_update_max_fd(fd);
            args[1] = INT2FIX(O_RDWR);
            args[0] = INT2NUM(fd);
            con = rb_class_new_instance(2, args, klass);
            GetOpenFile(con, fptr);
            fptr->pathv = rb_obj_freeze(rb_str_new2(CONSOLE_DEVICE));
    #ifdef CONSOLE_DEVICE_FOR_WRITING
            GetOpenFile(out, ofptr);
            ofptr->pathv = fptr->pathv;
            fptr->tied_io_for_writing = out;
            ofptr->mode |= FMODE_SYNC;
    #endif
            fptr->mode |= FMODE_SYNC;
            rb_const_set(klass, id_console, con);
        }
        if (sym) {
            return rb_f_send(argc, argv, con);
        }
        return con;
    }

console_size() click to toggle source
Alias for: default_console_size
default_console_size() click to toggle source

frozen_string_literal: false fallback to console window size

                   # File io/console/lib/console/size.rb, line 3
    def IO.default_console_size
      [
        ENV["LINES"].to_i.nonzero? || 25,
        ENV["COLUMNS"].to_i.nonzero? || 80,
      ]
    end

Also aliased as: console_size

### Public Instance Methods

beep() click to toggle source

                   static VALUE
    console_beep(VALUE io)
    {
        rb_io_t *fptr;
        int fd;

        GetOpenFile(io, fptr);
        fd = GetWriteFD(fptr);
    #ifdef _WIN32
        (void)fd;
        MessageBeep(0);
    #else
        if (write(fd, "\a", 1) < 0)
            rb_sys_fail(0);
    #endif
        return io;
    }

check_winsize_changed() click to toggle source

                   static VALUE
    console_check_winsize_changed(VALUE io)
    {
        rb_io_t *fptr;
        HANDLE h;
        DWORD num;

        GetOpenFile(io, fptr);
        h = (HANDLE)rb_w32_get_osfhandle(GetReadFD(fptr));
        while (GetNumberOfConsoleInputEvents(h, &num) && num > 0) {
            INPUT_RECORD rec;
            if (ReadConsoleInput(h, &rec, 1, &num)) {
                if (rec.EventType == WINDOW_BUFFER_SIZE_EVENT) {
                    rb_yield(Qnil);
                }
            }
        }
        return io;
    }

clear_screen() click to toggle source

                   static VALUE
    console_clear_screen(VALUE io)
    {
        console_erase_screen(io, INT2FIX(2));
        console_goto(io, INT2FIX(0), INT2FIX(0));
        return io;
    }

console_mode → mode click to toggle source

Returns a data represents the current console mode.

You must require ‘io/console’ to use this method.

                   static VALUE
    console_conmode_get(VALUE io)
    {
        conmode t;
        rb_io_t *fptr;
        int fd;

        GetOpenFile(io, fptr);
        fd = GetReadFD(fptr);
        if (!getattr(fd, &t)) rb_sys_fail(0);

        return conmode_new(cConmode, &t);
    }

console_mode = mode click to toggle source

Sets the console mode to `mode`.

You must require ‘io/console’ to use this method.

                   static VALUE
    console_conmode_set(VALUE io, VALUE mode)
    {
        conmode *t, r;
        rb_io_t *fptr;
        int fd;

        TypedData_Get_Struct(mode, conmode, &conmode_type, t);
        r = *t;
        GetOpenFile(io, fptr);
        fd = GetReadFD(fptr);
        if (!setattr(fd, &r)) rb_sys_fail(0);

        return mode;
    }

cooked {|io| } click to toggle source

Yields `self` within cooked mode.

    STDIN.cooked(&:gets)

will read and return a line with echo back and line editing.

You must require ‘io/console’ to use this method.

                   static VALUE
    console_cooked(VALUE io)
    {
        return ttymode(io, rb_yield, io, set_cookedmode, NULL);
    }

cooked! click to toggle source

Enables cooked mode.

If the terminal mode needs to be back, use io.cooked { … }.

You must require ‘io/console’ to use this method.

                   static VALUE
    console_set_cooked(VALUE io)
    {
        conmode t;
        rb_io_t *fptr;
        int fd;

        GetOpenFile(io, fptr);
        fd = GetReadFD(fptr);
        if (!getattr(fd, &t)) rb_sys_fail(0);
        set_cookedmode(&t, NULL);
        if (!setattr(fd, &t)) rb_sys_fail(0);
        return io;
    }

cursor() click to toggle source

                   static VALUE
    console_cursor_pos(VALUE io)
    {
        rb_io_t *fptr;
        int fd;
        rb_console_size_t ws;

        GetOpenFile(io, fptr);
        fd = GetWriteFD(fptr);
        if (!GetConsoleScreenBufferInfo((HANDLE)rb_w32_get_osfhandle(fd), &ws)) {
            rb_syserr_fail(LAST_ERROR, 0);
        }
        return rb_assoc_new(UINT2NUM(ws.dwCursorPosition.Y), UINT2NUM(ws.dwCursorPosition.X));
    }

cursor=(p1) click to toggle source

                   static VALUE
    console_cursor_set(VALUE io, VALUE cpos)
    {
        cpos = rb_convert_type(cpos, T_ARRAY, "Array", "to_ary");
        if (RARRAY_LEN(cpos) != 2) rb_raise(rb_eArgError, "expected 2D coordinate");
        return console_goto(io, RARRAY_AREF(cpos, 0), RARRAY_AREF(cpos, 1));
    }

cursor_down(p1) click to toggle source

                   static VALUE
    console_cursor_down(VALUE io, VALUE val)
    {
        return console_move(io, +NUM2INT(val), 0);
    }

cursor_left(p1) click to toggle source

                   static VALUE
    console_cursor_left(VALUE io, VALUE val)
    {
        return console_move(io, 0, -NUM2INT(val));
    }

cursor_right(p1) click to toggle source

                   static VALUE
    console_cursor_right(VALUE io, VALUE val)
    {
        return console_move(io, 0, +NUM2INT(val));
    }

cursor_up(p1) click to toggle source

                   static VALUE
    console_cursor_up(VALUE io, VALUE val)
    {
        return console_move(io, -NUM2INT(val), 0);
    }

echo = flag click to toggle source

Enables/disables echo back. On some platforms, all combinations of this flags and raw/cooked mode may not be valid.

You must require ‘io/console’ to use this method.

                   static VALUE
    console_set_echo(VALUE io, VALUE f)
    {
        conmode t;
        rb_io_t *fptr;
        int fd;

        GetOpenFile(io, fptr);
        fd = GetReadFD(fptr);
        if (!getattr(fd, &t)) rb_sys_fail(0);
        if (RTEST(f))
            set_echo(&t, NULL);
        else
            set_noecho(&t, NULL);
        if (!setattr(fd, &t)) rb_sys_fail(0);
        return io;
    }

echo? → true or false click to toggle source

Returns `true` if echo back is enabled.

You must require ‘io/console’ to use this method.

                   static VALUE
    console_echo_p(VALUE io)
    {
        conmode t;
        rb_io_t *fptr;
        int fd;

        GetOpenFile(io, fptr);
        fd = GetReadFD(fptr);
        if (!getattr(fd, &t)) rb_sys_fail(0);
        return echo_p(&t) ? Qtrue : Qfalse;
    }

erase_line(p1) click to toggle source

                   static VALUE
    console_erase_line(VALUE io, VALUE val)
    {
        rb_io_t *fptr;
        HANDLE h;
        rb_console_size_t ws;
        COORD *pos = &ws.dwCursorPosition;
        DWORD w;
        int mode = mode_in_range(val, 2, "line erase");

        GetOpenFile(io, fptr);
        h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
        if (!GetConsoleScreenBufferInfo(h, &ws)) {
            rb_syserr_fail(LAST_ERROR, 0);
        }
        w = winsize_col(&ws);
        switch (mode) {
          case 0:                   /* after cursor */
            w -= pos->X;
            break;
          case 1:                   /* before *and* cursor */
            w = pos->X + 1;
            pos->X = 0;
            break;
          case 2:                   /* entire line */
            pos->X = 0;
            break;
        }
        constat_clear(h, ws.wAttributes, w, *pos);
        return io;
    }

erase_screen(p1) click to toggle source

                   static VALUE
    console_erase_screen(VALUE io, VALUE val)
    {
        rb_io_t *fptr;
        HANDLE h;
        rb_console_size_t ws;
        COORD *pos = &ws.dwCursorPosition;
        DWORD w;
        int mode = mode_in_range(val, 3, "screen erase");

        GetOpenFile(io, fptr);
        h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
        if (!GetConsoleScreenBufferInfo(h, &ws)) {
            rb_syserr_fail(LAST_ERROR, 0);
        }
        w = winsize_col(&ws);
        switch (mode) {
          case 0:   /* erase after cursor */
            w = (w * (ws.srWindow.Bottom - pos->Y + 1) - pos->X);
            break;
          case 1:   /* erase before *and* cursor */
            w = (w * (pos->Y - ws.srWindow.Top) + pos->X + 1);
            pos->X = 0;
            pos->Y = ws.srWindow.Top;
            break;
          case 2:   /* erase entire screen */
            w = (w * winsize_row(&ws));
            pos->X = 0;
            pos->Y = ws.srWindow.Top;
            break;
          case 3:   /* erase entire screen */
            w = (w * ws.dwSize.Y);
            pos->X = 0;
            pos->Y = 0;
            break;
        }
        constat_clear(h, ws.wAttributes, w, *pos);
        return io;
    }

getch(min: nil, time: nil, intr: nil) → char click to toggle source

Reads and returns a character in raw mode.

See #raw for details on the parameters.

You must require ‘io/console’ to use this method.

                   static VALUE
    console_getch(int argc, VALUE *argv, VALUE io)
    {
        rawmode_arg_t opts, *optp = rawmode_opt(&argc, argv, 0, 0, &opts);
    #ifndef _WIN32
        return ttymode(io, getc_call, io, set_rawmode, optp);
    #else
        rb_io_t *fptr;
        VALUE str;
        wint_t c;
        int w, len;
        char buf[8];
        wint_t wbuf[2];
        struct timeval *to = NULL, tv;

        GetOpenFile(io, fptr);
        if (optp) {
            if (optp->vtime) {
                to = &tv;
                tv.tv_sec = optp->vtime / 10;
                tv.tv_usec = (optp->vtime % 10) * 100000;
            }
            if (optp->vmin != 1) {
                rb_warning("min option ignored");
            }
            if (optp->intr) {
                w = rb_wait_for_single_fd(fptr->fd, RB_WAITFD_IN, to);
                if (w < 0) rb_eof_error();
                if (!(w & RB_WAITFD_IN)) return Qnil;
            }
            else {
                rb_warning("vtime option ignored if intr flag is unset");
            }
        }
        len = (int)(VALUE)rb_thread_call_without_gvl(nogvl_getch, wbuf, RUBY_UBF_IO, 0);
        switch (len) {
          case 0:
            return Qnil;
          case 2:
            buf[0] = (char)wbuf[0];
            c = wbuf[1];
            len = 1;
            do {
                buf[len++] = (unsigned char)c;
            } while ((c >>= CHAR_BIT) && len < (int)sizeof(buf));
            return rb_str_new(buf, len);
          default:
            c = wbuf[0];
            len = rb_uv_to_utf8(buf, c);
            str = rb_utf8_str_new(buf, len);
            return rb_str_conv_enc(str, NULL, rb_default_external_encoding());
        }
    #endif
    }

getpass(prompt=nil) → string click to toggle source

Reads and returns a line without echo back. Prints `prompt` unless it is `nil`.

You must require ‘io/console’ to use this method.

                   static VALUE
    console_getpass(int argc, VALUE *argv, VALUE io)
    {
        VALUE str, wio;

        rb_check_arity(argc, 0, 1);
        wio = rb_io_get_write_io(io);
        if (wio == io && io == rb_stdin) wio = rb_stderr;
        prompt(argc, argv, wio);
        str = rb_ensure(getpass_call, io, puts_call, wio);
        return str_chomp(str);
    }

goto(p1, p2) click to toggle source

                   static VALUE
    console_goto(VALUE io, VALUE y, VALUE x)
    {
        rb_io_t *fptr;
        int fd;
        COORD pos;

        GetOpenFile(io, fptr);
        fd = GetWriteFD(fptr);
        pos.X = NUM2UINT(x);
        pos.Y = NUM2UINT(y);
        if (!SetConsoleCursorPosition((HANDLE)rb_w32_get_osfhandle(fd), pos)) {
            rb_syserr_fail(LAST_ERROR, 0);
        }
        return io;
    }

goto_column(p1) click to toggle source

                   static VALUE
    console_goto_column(VALUE io, VALUE val)
    {
        rb_io_t *fptr;
        HANDLE h;
        rb_console_size_t ws;
        COORD *pos = &ws.dwCursorPosition;

        GetOpenFile(io, fptr);
        h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
        if (!GetConsoleScreenBufferInfo(h, &ws)) {
            rb_syserr_fail(LAST_ERROR, 0);
        }
        pos->X = NUM2INT(val);
        if (!SetConsoleCursorPosition(h, *pos)) {
            rb_syserr_fail(LAST_ERROR, 0);
        }
        return io;
    }

iflush click to toggle source

Flushes input buffer in kernel.

You must require ‘io/console’ to use this method.

                   static VALUE
    console_iflush(VALUE io)
    {
        rb_io_t *fptr;
        int fd;

        GetOpenFile(io, fptr);
        fd = GetReadFD(fptr);
    #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
        if (tcflush(fd, TCIFLUSH)) rb_sys_fail(0);
    #endif
        (void)fd;
        return io;
    }

ioflush click to toggle source

Flushes input and output buffers in kernel.

You must require ‘io/console’ to use this method.

                   static VALUE
    console_ioflush(VALUE io)
    {
        rb_io_t *fptr;
    #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
        int fd1, fd2;
    #endif

        GetOpenFile(io, fptr);
    #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
        fd1 = GetReadFD(fptr);
        fd2 = GetWriteFD(fptr);
        if (fd2 != -1 && fd1 != fd2) {
            if (tcflush(fd1, TCIFLUSH)) rb_sys_fail(0);
            if (tcflush(fd2, TCOFLUSH)) rb_sys_fail(0);
        }
        else {
            if (tcflush(fd1, TCIOFLUSH)) rb_sys_fail(0);
        }
    #endif
        return io;
    }

noecho {|io| } click to toggle source

Yields `self` with disabling echo back.

    STDIN.noecho(&:gets)

will read and return a line without echo back.

You must require ‘io/console’ to use this method.

                   static VALUE
    console_noecho(VALUE io)
    {
        return ttymode(io, rb_yield, io, set_noecho, NULL);
    }

oflush click to toggle source

Flushes output buffer in kernel.

You must require ‘io/console’ to use this method.

                   static VALUE
    console_oflush(VALUE io)
    {
        rb_io_t *fptr;
        int fd;

        GetOpenFile(io, fptr);
        fd = GetWriteFD(fptr);
    #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
        if (tcflush(fd, TCOFLUSH)) rb_sys_fail(0);
    #endif
        (void)fd;
        return io;
    }

pressed?(p1) click to toggle source

                   static VALUE
    console_key_pressed_p(VALUE io, VALUE k)
    {
        int vk = -1;

        if (FIXNUM_P(k)) {
            vk = NUM2UINT(k);
        }
        else {
            const struct vktable *t;
            const char *kn;
            if (SYMBOL_P(k)) {
                k = rb_sym2str(k);
                kn = RSTRING_PTR(k);
            }
            else {
                kn = StringValuePtr(k);
            }
            t = console_win32_vk(kn, RSTRING_LEN(k));
            if (!t || (vk = (short)t->vk) == -1) {
                rb_raise(rb_eArgError, "unknown virtual key code: % "PRIsVALUE, k);
            }
        }
        return GetKeyState(vk) & 0x80 ? Qtrue : Qfalse;
    }

raw(min: nil, time: nil, intr: nil) {|io| } click to toggle source

Yields `self` within raw mode, and returns the result of the block.

    STDIN.raw(&:gets)

will read and return a line without echo back and line editing.

The parameter `min` specifies the minimum number of bytes that should be received when a read operation is performed. (default: 1)

The parameter `time` specifies the timeout in seconds with a precision of 1/10 of a second. (default: 0)

If the parameter `intr` is `true`, enables break, interrupt, quit, and suspend special characters.

Refer to the manual page of termios for further details.

You must require ‘io/console’ to use this method.

                   static VALUE
    console_raw(int argc, VALUE *argv, VALUE io)
    {
        rawmode_arg_t opts, *optp = rawmode_opt(&argc, argv, 0, 0, &opts);
        return ttymode(io, rb_yield, io, set_rawmode, optp);
    }

raw!(min: nil, time: nil, intr: nil) → io click to toggle source

Enables raw mode, and returns `io`.

If the terminal mode needs to be back, use `io.raw { ... }`.

See #raw for details on the parameters.

You must require ‘io/console’ to use this method.

                   static VALUE
    console_set_raw(int argc, VALUE *argv, VALUE io)
    {
        conmode t;
        rb_io_t *fptr;
        int fd;
        rawmode_arg_t opts, *optp = rawmode_opt(&argc, argv, 0, 0, &opts);

        GetOpenFile(io, fptr);
        fd = GetReadFD(fptr);
        if (!getattr(fd, &t)) rb_sys_fail(0);
        set_rawmode(&t, optp);
        if (!setattr(fd, &t)) rb_sys_fail(0);
        return io;
    }

scroll_backward(p1) click to toggle source

                   static VALUE
    console_scroll_backward(VALUE io, VALUE val)
    {
        return console_scroll(io, -NUM2INT(val));
    }

scroll_forward(p1) click to toggle source

                   static VALUE
    console_scroll_forward(VALUE io, VALUE val)
    {
        return console_scroll(io, +NUM2INT(val));
    }

winsize → [rows, columns] click to toggle source

Returns console size.

You must require ‘io/console’ to use this method.

                   static VALUE
    console_winsize(VALUE io)
    {
        rb_io_t *fptr;
        int fd;
        rb_console_size_t ws;

        GetOpenFile(io, fptr);
        fd = GetWriteFD(fptr);
        if (!getwinsize(fd, &ws)) rb_sys_fail(0);
        return rb_assoc_new(INT2NUM(winsize_row(&ws)), INT2NUM(winsize_col(&ws)));
    }

winsize = [rows, columns] click to toggle source

Tries to set console size. The effect depends on the platform and the running environment.

You must require ‘io/console’ to use this method.

                   static VALUE
    console_set_winsize(VALUE io, VALUE size)
    {
        rb_io_t *fptr;
        rb_console_size_t ws;
    #if defined _WIN32
        HANDLE wh;
        int newrow, newcol;
        BOOL ret;
    #endif
        VALUE row, col, xpixel, ypixel;
        const VALUE *sz;
        int fd;
        long sizelen;

        GetOpenFile(io, fptr);
        size = rb_Array(size);
        if ((sizelen = RARRAY_LEN(size)) != 2 && sizelen != 4) {
            rb_raise(rb_eArgError,
                     "wrong number of arguments (given %ld, expected 2 or 4)",
                     sizelen);
        }
        sz = RARRAY_CONST_PTR(size);
        row = sz[0], col = sz[1], xpixel = ypixel = Qnil;
        if (sizelen == 4) xpixel = sz[2], ypixel = sz[3];
        fd = GetWriteFD(fptr);
    #if defined TIOCSWINSZ
        ws.ws_row = ws.ws_col = ws.ws_xpixel = ws.ws_ypixel = 0;
    #define SET(m) ws.ws_##m = NIL_P(m) ? 0 : (unsigned short)NUM2UINT(m)
        SET(row);
        SET(col);
        SET(xpixel);
        SET(ypixel);
    #undef SET
        if (!setwinsize(fd, &ws)) rb_sys_fail(0);
    #elif defined _WIN32
        wh = (HANDLE)rb_w32_get_osfhandle(fd);
    #define SET(m) new##m = NIL_P(m) ? 0 : (unsigned short)NUM2UINT(m)
        SET(row);
        SET(col);
    #undef SET
        if (!NIL_P(xpixel)) (void)NUM2UINT(xpixel);
        if (!NIL_P(ypixel)) (void)NUM2UINT(ypixel);
        if (!GetConsoleScreenBufferInfo(wh, &ws)) {
            rb_syserr_fail(LAST_ERROR, "GetConsoleScreenBufferInfo");
        }
        ws.dwSize.X = newcol;
        ret = SetConsoleScreenBufferSize(wh, ws.dwSize);
        ws.srWindow.Left = 0;
        ws.srWindow.Top = 0;
        ws.srWindow.Right = newcol-1;
        ws.srWindow.Bottom = newrow-1;
        if (!SetConsoleWindowInfo(wh, TRUE, &ws.srWindow)) {
            rb_syserr_fail(LAST_ERROR, "SetConsoleWindowInfo");
        }
        /* retry when shrinking buffer after shrunk window */
        if (!ret && !SetConsoleScreenBufferSize(wh, ws.dwSize)) {
            rb_syserr_fail(LAST_ERROR, "SetConsoleScreenBufferInfo");
        }
        /* remove scrollbar if possible */
        if (!SetConsoleWindowInfo(wh, TRUE, &ws.srWindow)) {
            rb_syserr_fail(LAST_ERROR, "SetConsoleWindowInfo");
        }
    #endif
        return io;
    }