类 IO
公共类方法
返回一个打开的控制台 File 实例。
如果给定 sym
,它将与 args
一起发送到打开的控制台,并将返回结果,而不是控制台 IO
本身。
您必须要求 ‘io/console’ 才能使用此方法。
static VALUE console_dev(int argc, VALUE *argv, VALUE klass) { VALUE con = 0; VALUE sym = 0; rb_check_arity(argc, 0, UNLIMITED_ARGUMENTS); if (argc) { Check_Type(sym = argv[0], T_SYMBOL); } // Force the class to be File. 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) || RTEST(rb_io_closed_p(con))) { 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) { #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; VALUE path = rb_obj_freeze(rb_str_new2(CONSOLE_DEVICE)); #ifdef CONSOLE_DEVICE_FOR_WRITING fd = rb_cloexec_open(CONSOLE_DEVICE_FOR_WRITING, O_RDWR, 0); if (fd < 0) return Qnil; out = rb_io_open_descriptor(klass, fd, FMODE_WRITABLE | FMODE_SYNC, path, Qnil, NULL); #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; } con = rb_io_open_descriptor(klass, fd, FMODE_READWRITE | FMODE_SYNC, path, Qnil, NULL); #ifdef CONSOLE_DEVICE_FOR_WRITING rb_io_set_write_io(con, out); #endif rb_const_set(klass, id_console, con); } if (sym) { return rb_f_send(argc, argv, con); } return con; }
回退到控制台窗口大小
# 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
公共实例方法
static VALUE console_beep(VALUE io) { #ifdef _WIN32 MessageBeep(0); #else int fd = GetWriteFD(io); if (write(fd, "\a", 1) < 0) sys_fail(io); #endif return io; }
static VALUE console_check_winsize_changed(VALUE io) { HANDLE h; DWORD num; h = (HANDLE)rb_w32_get_osfhandle(GetReadFD(io)); 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; }
static VALUE console_clear_screen(VALUE io) { console_erase_screen(io, INT2FIX(2)); console_goto(io, INT2FIX(0), INT2FIX(0)); return io; }
返回表示当前控制台模式的数据。
您必须要求 ‘io/console’ 才能使用此方法。
static VALUE console_conmode_get(VALUE io) { conmode t; int fd = GetReadFD(io); if (!getattr(fd, &t)) sys_fail(io); return conmode_new(cConmode, &t); }
将控制台模式设置为 mode
。
您必须要求 ‘io/console’ 才能使用此方法。
static VALUE console_conmode_set(VALUE io, VALUE mode) { conmode *t, r; int fd = GetReadFD(io); TypedData_Get_Struct(mode, conmode, &conmode_type, t); r = *t; if (!setattr(fd, &r)) sys_fail(io); return mode; }
在 cooked 模式下生成 self
。
STDIN.cooked(&:gets)
将读取并返回带有回显和行编辑功能的一行。
您必须要求 ‘io/console’ 才能使用此方法。
static VALUE console_cooked(VALUE io) { return ttymode(io, rb_yield, io, set_cookedmode, NULL); }
启用 cooked 模式。
如果需要返回终端模式,请使用 io.cooked { … }。
您必须要求 ‘io/console’ 才能使用此方法。
static VALUE console_set_cooked(VALUE io) { conmode t; int fd = GetReadFD(io); if (!getattr(fd, &t)) sys_fail(io); set_cookedmode(&t, NULL); if (!setattr(fd, &t)) sys_fail(io); return io; }
返回当前光标位置,以包含两个整数元素的数组形式表示(行,列)。
io.cursor # => [3, 5]
您必须要求 ‘io/console’ 才能使用此方法。
static VALUE console_cursor_pos(VALUE io) { #ifdef _WIN32 rb_console_size_t ws; int fd = GetWriteFD(io); 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)); #else static const struct query_args query = {"\033[6n", 0}; VALUE resp = console_vt_response(0, 0, io, &query); VALUE row, column, term; unsigned int r, c; if (!RB_TYPE_P(resp, T_ARRAY) || RARRAY_LEN(resp) != 3) return Qnil; term = RARRAY_AREF(resp, 2); if (!RB_TYPE_P(term, T_STRING) || RSTRING_LEN(term) != 1) return Qnil; if (RSTRING_PTR(term)[0] != 'R') return Qnil; row = RARRAY_AREF(resp, 0); column = RARRAY_AREF(resp, 1); rb_ary_resize(resp, 2); r = NUM2UINT(row) - 1; c = NUM2UINT(column) - 1; RARRAY_ASET(resp, 0, INT2NUM(r)); RARRAY_ASET(resp, 1, INT2NUM(c)); return resp; #endif }
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)); }
static VALUE console_cursor_down(VALUE io, VALUE val) { return console_move(io, +NUM2INT(val), 0); }
static VALUE console_cursor_left(VALUE io, VALUE val) { return console_move(io, 0, -NUM2INT(val)); }
static VALUE console_cursor_right(VALUE io, VALUE val) { return console_move(io, 0, +NUM2INT(val)); }
static VALUE console_cursor_up(VALUE io, VALUE val) { return console_move(io, -NUM2INT(val), 0); }
启用/禁用回显。在某些平台上,此标志和 raw/cooked 模式的所有组合可能无效。
您必须要求 ‘io/console’ 才能使用此方法。
static VALUE console_set_echo(VALUE io, VALUE f) { conmode t; int fd = GetReadFD(io); if (!getattr(fd, &t)) sys_fail(io); if (RTEST(f)) set_echo(&t, NULL); else set_noecho(&t, NULL); if (!setattr(fd, &t)) sys_fail(io); return io; }
如果启用了回显,则返回 true
。
您必须要求 ‘io/console’ 才能使用此方法。
static VALUE console_echo_p(VALUE io) { conmode t; int fd = GetReadFD(io); if (!getattr(fd, &t)) sys_fail(io); return echo_p(&t) ? Qtrue : Qfalse; }
static VALUE console_erase_line(VALUE io, VALUE val) { int mode = mode_in_range(val, 2, "line erase"); #ifdef _WIN32 HANDLE h; rb_console_size_t ws; COORD *pos = &ws.dwCursorPosition; DWORD w; h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(io)); 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; #else rb_io_write(io, rb_sprintf("\x1b[%dK", mode)); #endif return io; }
static VALUE console_erase_screen(VALUE io, VALUE val) { int mode = mode_in_range(val, 3, "screen erase"); #ifdef _WIN32 HANDLE h; rb_console_size_t ws; COORD *pos = &ws.dwCursorPosition; DWORD w; h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(io)); 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); #else rb_io_write(io, rb_sprintf("\x1b[%dJ", mode)); #endif return io; }
在 raw 模式下读取并返回一个字符。
有关参数的详细信息,请参见 IO#raw
。
您必须要求 ‘io/console’ 才能使用此方法。
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 len; char buf[8]; wint_t wbuf[2]; # ifndef HAVE_RB_IO_WAIT struct timeval *to = NULL, tv; # else VALUE timeout = Qnil; # endif GetOpenFile(io, fptr); if (optp) { if (optp->vtime) { # ifndef HAVE_RB_IO_WAIT to = &tv; # else struct timeval tv; # endif tv.tv_sec = optp->vtime / 10; tv.tv_usec = (optp->vtime % 10) * 100000; # ifdef HAVE_RB_IO_WAIT timeout = rb_fiber_scheduler_make_timeout(&tv); # endif } switch (optp->vmin) { case 1: /* default */ break; case 0: /* return nil when timed out */ if (optp->vtime) break; /* fallthru */ default: rb_warning("min option larger than 1 ignored"); } if (optp->intr) { # ifndef HAVE_RB_IO_WAIT int 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 VALUE result = rb_io_wait(io, RB_INT2NUM(RUBY_IO_READABLE), timeout); if (!RTEST(result)) return Qnil; # endif } else if (optp->vtime) { rb_warning("Non-zero 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 }
读取并返回一行,不回显。除非 nil
,否则打印 prompt
。
从返回的字符串中删除终止读取行的换行符,请参见 String#chomp!。
您必须要求 ‘io/console’ 才能使用此方法。
require 'io/console' IO::console.getpass("Enter password:") Enter password: # => "mypassword"
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); rb_io_flush(wio); str = rb_ensure(getpass_call, io, puts_call, wio); return str_chomp(str); }
static VALUE console_goto(VALUE io, VALUE y, VALUE x) { #ifdef _WIN32 COORD pos; int fd = GetWriteFD(io); pos.X = NUM2UINT(x); pos.Y = NUM2UINT(y); if (!SetConsoleCursorPosition((HANDLE)rb_w32_get_osfhandle(fd), pos)) { rb_syserr_fail(LAST_ERROR, 0); } #else rb_io_write(io, rb_sprintf("\x1b[%d;%dH", NUM2UINT(y)+1, NUM2UINT(x)+1)); #endif return io; }
static VALUE console_goto_column(VALUE io, VALUE val) { #ifdef _WIN32 HANDLE h; rb_console_size_t ws; COORD *pos = &ws.dwCursorPosition; h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(io)); if (!GetConsoleScreenBufferInfo(h, &ws)) { rb_syserr_fail(LAST_ERROR, 0); } pos->X = NUM2INT(val); if (!SetConsoleCursorPosition(h, *pos)) { rb_syserr_fail(LAST_ERROR, 0); } #else rb_io_write(io, rb_sprintf("\x1b[%dG", NUM2UINT(val)+1)); #endif return io; }
刷新内核中的输入缓冲区。
您必须要求 ‘io/console’ 才能使用此方法。
static VALUE console_iflush(VALUE io) { #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H int fd = GetReadFD(io); if (tcflush(fd, TCIFLUSH)) sys_fail(io); #endif return io; }
刷新内核中的输入和输出缓冲区。
您必须要求 ‘io/console’ 才能使用此方法。
static VALUE console_ioflush(VALUE io) { #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H int fd1 = GetReadFD(io); int fd2 = GetWriteFD(io); if (fd2 != -1 && fd1 != fd2) { if (tcflush(fd1, TCIFLUSH)) sys_fail(io); if (tcflush(fd2, TCOFLUSH)) sys_fail(io); } else { if (tcflush(fd1, TCIOFLUSH)) sys_fail(io); } #endif return io; }
禁用回显,并以 self
为参数执行代码块。
STDIN.noecho(&:gets)
将读取并返回一行,不进行回显。
您必须要求 ‘io/console’ 才能使用此方法。
static VALUE console_noecho(VALUE io) { return ttymode(io, rb_yield, io, set_noecho, NULL); }
刷新内核中的输出缓冲区。
您必须要求 ‘io/console’ 才能使用此方法。
static VALUE console_oflush(VALUE io) { int fd = GetWriteFD(io); #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H if (tcflush(fd, TCOFLUSH)) sys_fail(io); #endif (void)fd; return io; }
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; }
在原始模式下以 self
为参数执行代码块,并返回代码块的结果。
STDIN.raw(&:gets)
将读取并返回一行,不进行回显和行编辑。
参数 min
指定读取操作时应接收的最小字节数。(默认值:1)
参数 time
指定超时时间(以秒为单位),精度为 1/10 秒。(默认值:0)
如果参数 intr
为 true
,则启用中断、退出和暂停特殊字符。
有关详细信息,请参阅 termios 手册页。
您必须要求 ‘io/console’ 才能使用此方法。
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); }
启用原始模式,并返回 io
。
如果需要恢复终端模式,请使用 io.raw { ... }
。
有关参数的详细信息,请参见 IO#raw
。
您必须要求 ‘io/console’ 才能使用此方法。
static VALUE console_set_raw(int argc, VALUE *argv, VALUE io) { conmode t; rawmode_arg_t opts, *optp = rawmode_opt(&argc, argv, 0, 0, &opts); int fd = GetReadFD(io); if (!getattr(fd, &t)) sys_fail(io); set_rawmode(&t, optp); if (!setattr(fd, &t)) sys_fail(io); return io; }
static VALUE console_scroll_backward(VALUE io, VALUE val) { return console_scroll(io, -NUM2INT(val)); }
static VALUE console_scroll_forward(VALUE io, VALUE val) { return console_scroll(io, +NUM2INT(val)); }
返回控制台大小。
您必须要求 ‘io/console’ 才能使用此方法。
static VALUE console_winsize(VALUE io) { rb_console_size_t ws; int fd = GetWriteFD(io); if (!getwinsize(fd, &ws)) sys_fail(io); return rb_assoc_new(INT2NUM(winsize_row(&ws)), INT2NUM(winsize_col(&ws))); }
尝试设置控制台大小。效果取决于平台和运行环境。
您必须要求 ‘io/console’ 才能使用此方法。
static VALUE console_set_winsize(VALUE io, VALUE size) { rb_console_size_t ws; #if defined _WIN32 HANDLE wh; int newrow, newcol; BOOL ret; #endif VALUE row, col, xpixel, ypixel; const VALUE *sz; long sizelen; int fd; 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(io); #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)) sys_fail(io); #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; }