diff options
Diffstat (limited to 'ext/io/console')
| -rw-r--r-- | ext/io/console/.document | 2 | ||||
| -rwxr-xr-x | ext/io/console/buildgem.sh | 5 | ||||
| -rw-r--r-- | ext/io/console/console.c | 2019 | ||||
| -rw-r--r-- | ext/io/console/depend | 199 | ||||
| -rw-r--r-- | ext/io/console/extconf.rb | 61 | ||||
| -rw-r--r-- | ext/io/console/io-console.gemspec | 53 | ||||
| -rw-r--r-- | ext/io/console/lib/console/size.rb | 23 | ||||
| -rw-r--r-- | ext/io/console/win32_vk.chksum | 1 | ||||
| -rw-r--r-- | ext/io/console/win32_vk.inc | 1390 | ||||
| -rw-r--r-- | ext/io/console/win32_vk.list | 166 |
10 files changed, 3919 insertions, 0 deletions
diff --git a/ext/io/console/.document b/ext/io/console/.document new file mode 100644 index 0000000000..945a377256 --- /dev/null +++ b/ext/io/console/.document @@ -0,0 +1,2 @@ +console.c +lib/size.rb diff --git a/ext/io/console/buildgem.sh b/ext/io/console/buildgem.sh new file mode 100755 index 0000000000..65fe545e1e --- /dev/null +++ b/ext/io/console/buildgem.sh @@ -0,0 +1,5 @@ +#!/bin/sh -e +cd ${0%/*} +trap "mv depend.$$ depend" 0 2 +${RUBY-ruby} -i.$$ -pe 'exit if /^win32_vk/' depend +${GEM-gem} build io-console.gemspec diff --git a/ext/io/console/console.c b/ext/io/console/console.c new file mode 100644 index 0000000000..5f3c9478f7 --- /dev/null +++ b/ext/io/console/console.c @@ -0,0 +1,2019 @@ +/* -*- c-file-style: "ruby"; indent-tabs-mode: t -*- */ +/* + * console IO module + */ + +static const char *const +IO_CONSOLE_VERSION = "0.8.2"; + +#include "ruby.h" +#include "ruby/io.h" +#include "ruby/thread.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +#ifdef HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif + +#if defined HAVE_TERMIOS_H +# include <termios.h> +typedef struct termios conmode; + +static int +setattr(int fd, conmode *t) +{ + while (tcsetattr(fd, TCSANOW, t)) { + if (errno != EINTR) return 0; + } + return 1; +} +# define getattr(fd, t) (tcgetattr(fd, t) == 0) +#elif defined HAVE_TERMIO_H +# include <termio.h> +typedef struct termio conmode; +# define setattr(fd, t) (ioctl(fd, TCSETAF, t) == 0) +# define getattr(fd, t) (ioctl(fd, TCGETA, t) == 0) +#elif defined HAVE_SGTTY_H +# include <sgtty.h> +typedef struct sgttyb conmode; +# ifdef HAVE_STTY +# define setattr(fd, t) (stty(fd, t) == 0) +# else +# define setattr(fd, t) (ioctl((fd), TIOCSETP, (t)) == 0) +# endif +# ifdef HAVE_GTTY +# define getattr(fd, t) (gtty(fd, t) == 0) +# else +# define getattr(fd, t) (ioctl((fd), TIOCGETP, (t)) == 0) +# endif +#elif defined _WIN32 +#include <winioctl.h> +#include <conio.h> +typedef DWORD conmode; + +#define LAST_ERROR rb_w32_map_errno(GetLastError()) +#define SET_LAST_ERROR (errno = LAST_ERROR, 0) + +static int +setattr(int fd, conmode *t) +{ + int x = SetConsoleMode((HANDLE)rb_w32_get_osfhandle(fd), *t); + if (!x) errno = LAST_ERROR; + return x; +} + +static int +getattr(int fd, conmode *t) +{ + int x = GetConsoleMode((HANDLE)rb_w32_get_osfhandle(fd), t); + if (!x) errno = LAST_ERROR; + return x; +} +#endif +#ifndef SET_LAST_ERROR +#define SET_LAST_ERROR (0) +#endif + +#define CSI "\x1b\x5b" + +static ID id_getc, id_close; +static ID id_gets, id_flush, id_chomp_bang; + +#ifndef HAVE_RB_INTERNED_STR_CSTR +# define rb_str_to_interned_str(str) rb_str_freeze(str) +# define rb_interned_str_cstr(str) rb_str_freeze(rb_usascii_str_new_cstr(str)) +#endif + +#if defined HAVE_RUBY_FIBER_SCHEDULER_H +# include "ruby/fiber/scheduler.h" +#elif defined HAVE_RB_SCHEDULER_TIMEOUT +extern VALUE rb_scheduler_timeout(struct timeval *timeout); +# define rb_fiber_scheduler_make_timeout rb_scheduler_timeout +#endif + +#ifndef HAVE_RB_IO_DESCRIPTOR +static int +io_descriptor_fallback(VALUE io) +{ + rb_io_t *fptr; + GetOpenFile(io, fptr); + return fptr->fd; +} +#define rb_io_descriptor io_descriptor_fallback +#endif + +#ifndef HAVE_RB_IO_PATH +static VALUE +io_path_fallback(VALUE io) +{ + rb_io_t *fptr; + GetOpenFile(io, fptr); + return fptr->pathv; +} +#define rb_io_path io_path_fallback +#endif + +#ifndef HAVE_RB_IO_GET_WRITE_IO +static VALUE +io_get_write_io_fallback(VALUE io) +{ + rb_io_t *fptr; + GetOpenFile(io, fptr); + VALUE wio = fptr->tied_io_for_writing; + return wio ? wio : io; +} +#define rb_io_get_write_io io_get_write_io_fallback +#endif + +#ifndef DHAVE_RB_SYSERR_FAIL_STR +# define rb_syserr_fail_str(e, mesg) rb_exc_raise(rb_syserr_new_str(e, mesg)) +#endif + +#define sys_fail(io) do { \ + int err = errno; \ + rb_syserr_fail_str(err, rb_io_path(io)); \ +} while (0) + +#ifndef HAVE_RB_F_SEND +#ifndef RB_PASS_CALLED_KEYWORDS +# define rb_funcallv_kw(recv, mid, arg, argv, kw_splat) rb_funcallv(recv, mid, arg, argv) +#endif + +static ID id___send__; + +static VALUE +rb_f_send(int argc, VALUE *argv, VALUE recv) +{ + VALUE sym = argv[0]; + ID vid = rb_check_id(&sym); + if (vid) { + --argc; + ++argv; + } + else { + vid = id___send__; + } + return rb_funcallv_kw(recv, vid, argc, argv, RB_PASS_CALLED_KEYWORDS); +} +#endif + +enum rawmode_opt_ids { + kwd_min, + kwd_time, + kwd_intr, + rawmode_opt_id_count +}; +static ID rawmode_opt_ids[rawmode_opt_id_count]; + +typedef struct { + int vmin; + int vtime; + int intr; +} rawmode_arg_t; + +#ifndef UNDEF_P +# define UNDEF_P(obj) ((obj) == Qundef) +#endif +#ifndef NIL_OR_UNDEF_P +# define NIL_OR_UNDEF_P(obj) (NIL_P(obj) || UNDEF_P(obj)) +#endif + +static rawmode_arg_t * +rawmode_opt(int *argcp, VALUE *argv, int min_argc, int max_argc, rawmode_arg_t *opts) +{ + int argc = *argcp; + rawmode_arg_t *optp = NULL; + VALUE vopts = Qnil; + VALUE optvals[rawmode_opt_id_count]; +#ifdef RB_SCAN_ARGS_PASS_CALLED_KEYWORDS + argc = rb_scan_args(argc, argv, "*:", NULL, &vopts); +#else + if (argc > min_argc) { + vopts = rb_check_hash_type(argv[argc-1]); + if (!NIL_P(vopts)) { + argv[argc-1] = vopts; + vopts = rb_extract_keywords(&argv[argc-1]); + if (!argv[argc-1]) *argcp = --argc; + if (!vopts) vopts = Qnil; + } + } +#endif + rb_check_arity(argc, min_argc, max_argc); + if (rb_get_kwargs(vopts, rawmode_opt_ids, + 0, rawmode_opt_id_count, optvals)) { + VALUE vmin = optvals[kwd_min]; + VALUE vtime = optvals[kwd_time]; + VALUE intr = optvals[kwd_intr]; + /* default values by `stty raw` */ + opts->vmin = 1; + opts->vtime = 0; + opts->intr = 0; + if (!NIL_OR_UNDEF_P(vmin)) { + opts->vmin = NUM2INT(vmin); + optp = opts; + } + if (!NIL_OR_UNDEF_P(vtime)) { + VALUE v10 = INT2FIX(10); + vtime = rb_funcall3(vtime, '*', 1, &v10); + opts->vtime = NUM2INT(vtime); + optp = opts; + } + switch (intr) { + case Qtrue: + opts->intr = 1; + optp = opts; + break; + case Qfalse: + opts->intr = 0; + optp = opts; + break; + case Qundef: + case Qnil: + break; + default: + rb_raise(rb_eArgError, "true or false expected as intr: %"PRIsVALUE, + intr); + } + } + return optp; +} + +static void +set_rawmode(conmode *t, void *arg) +{ +#ifdef HAVE_CFMAKERAW + cfmakeraw(t); + t->c_lflag &= ~(ECHOE|ECHOK); +#elif defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H + t->c_iflag &= ~(IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|ISTRIP|INLCR|IGNCR|ICRNL|IXON|IXOFF|IXANY|IMAXBEL); + t->c_oflag &= ~OPOST; + t->c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|ICANON|ISIG|IEXTEN|XCASE); + t->c_cflag &= ~(CSIZE|PARENB); + t->c_cflag |= CS8; + t->c_cc[VMIN] = 1; + t->c_cc[VTIME] = 0; +#elif defined HAVE_SGTTY_H + t->sg_flags &= ~ECHO; + t->sg_flags |= RAW; +#elif defined _WIN32 + *t = 0; +#endif + if (arg) { + const rawmode_arg_t *r = arg; +#ifdef VMIN + if (r->vmin >= 0) t->c_cc[VMIN] = r->vmin; +#endif +#ifdef VTIME + if (r->vtime >= 0) t->c_cc[VTIME] = r->vtime; +#endif +#ifdef ISIG + if (r->intr) { + t->c_iflag |= BRKINT; + t->c_lflag |= ISIG; + t->c_oflag |= OPOST; + } +#endif + (void)r; + } +} + +static void +set_cookedmode(conmode *t, void *arg) +{ +#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H + t->c_iflag |= (BRKINT|ISTRIP|ICRNL|IXON); + t->c_oflag |= OPOST; + t->c_lflag |= (ECHO|ECHOE|ECHOK|ECHONL|ICANON|ISIG|IEXTEN); +#elif defined HAVE_SGTTY_H + t->sg_flags |= ECHO; + t->sg_flags &= ~RAW; +#elif defined _WIN32 + *t |= ENABLE_ECHO_INPUT|ENABLE_LINE_INPUT|ENABLE_PROCESSED_INPUT; +#endif +} + +static void +set_noecho(conmode *t, void *arg) +{ +#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H + t->c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); +#elif defined HAVE_SGTTY_H + t->sg_flags &= ~ECHO; +#elif defined _WIN32 + *t &= ~ENABLE_ECHO_INPUT; +#endif +} + +static void +set_echo(conmode *t, void *arg) +{ +#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H + t->c_lflag |= (ECHO | ECHOE | ECHOK | ECHONL); +#elif defined HAVE_SGTTY_H + t->sg_flags |= ECHO; +#elif defined _WIN32 + *t |= ENABLE_ECHO_INPUT; +#endif +} + +static int +echo_p(conmode *t) +{ +#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H + return (t->c_lflag & (ECHO | ECHONL)) != 0; +#elif defined HAVE_SGTTY_H + return (t->sg_flags & ECHO) != 0; +#elif defined _WIN32 + return (*t & ENABLE_ECHO_INPUT) != 0; +#endif +} + +static int +set_ttymode(int fd, conmode *t, void (*setter)(conmode *, void *), void *arg) +{ + conmode r; + if (!getattr(fd, t)) return 0; + r = *t; + setter(&r, arg); + return setattr(fd, &r); +} + +#define GetReadFD(io) rb_io_descriptor(io) +#define GetWriteFD(io) rb_io_descriptor(rb_io_get_write_io(io)) + +#define FD_PER_IO 2 + +static VALUE +ttymode(VALUE io, VALUE (*func)(VALUE), VALUE farg, void (*setter)(conmode *, void *), void *arg) +{ + int status = -1; + int error = 0; + int fd[FD_PER_IO]; + conmode t[FD_PER_IO]; + VALUE result = Qnil; + + fd[0] = GetReadFD(io); + if (fd[0] != -1) { + if (set_ttymode(fd[0], t+0, setter, arg)) { + status = 0; + } + else { + error = errno; + fd[0] = -1; + } + } + fd[1] = GetWriteFD(io); + if (fd[1] != -1 && fd[1] != fd[0]) { + if (set_ttymode(fd[1], t+1, setter, arg)) { + status = 0; + } + else { + error = errno; + fd[1] = -1; + } + } + if (status == 0) { + result = rb_protect(func, farg, &status); + } + if (fd[0] != -1 && fd[0] == GetReadFD(io)) { + if (!setattr(fd[0], t+0)) { + error = errno; + status = -1; + } + } + if (fd[1] != -1 && fd[1] != fd[0] && fd[1] == GetWriteFD(io)) { + if (!setattr(fd[1], t+1)) { + error = errno; + status = -1; + } + } + if (status) { + if (status == -1) { + rb_syserr_fail(error, 0); + } + rb_jump_tag(status); + } + return result; +} + +#if !defined _WIN32 +struct ttymode_callback_args { + VALUE (*func)(VALUE, VALUE); + VALUE io; + VALUE farg; +}; + +static VALUE +ttymode_callback(VALUE args) +{ + struct ttymode_callback_args *argp = (struct ttymode_callback_args *)args; + return argp->func(argp->io, argp->farg); +} + +static VALUE +ttymode_with_io(VALUE io, VALUE (*func)(VALUE, VALUE), VALUE farg, void (*setter)(conmode *, void *), void *arg) +{ + struct ttymode_callback_args cargs; + cargs.func = func; + cargs.io = io; + cargs.farg = farg; + return ttymode(io, ttymode_callback, (VALUE)&cargs, setter, arg); +} +#endif + +/* + * call-seq: + * io.raw(min: nil, time: nil, intr: nil) {|io| } + * + * 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); +} + +/* + * call-seq: + * io.raw!(min: nil, time: nil, intr: nil) -> io + * + * Enables raw mode, and returns +io+. + * + * If the terminal mode needs to be back, use <code>io.raw { ... }</code>. + * + * See IO#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; + 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; +} + +/* + * call-seq: + * io.cooked {|io| } + * + * 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); +} + +/* + * call-seq: + * io.cooked! + * + * 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; + int fd = GetReadFD(io); + if (!getattr(fd, &t)) sys_fail(io); + set_cookedmode(&t, NULL); + if (!setattr(fd, &t)) sys_fail(io); + return io; +} + +#ifndef _WIN32 +static VALUE +getc_call(VALUE io) +{ + return rb_funcallv(io, id_getc, 0, 0); +} +#else +static void * +nogvl_getch(void *p) +{ + int len = 0; + wint_t *buf = p, c = _getwch(); + + switch (c) { + case WEOF: + break; + case 0x00: + case 0xe0: + buf[len++] = c; + c = _getwch(); + /* fall through */ + default: + buf[len++] = c; + break; + } + return (void *)(VALUE)len; +} +#endif + +/* + * call-seq: + * io.getch(min: nil, time: nil, intr: nil) -> char + * + * Reads and returns a character in raw mode. + * + * See IO#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 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 +} + +/* + * call-seq: + * io.noecho {|io| } + * + * 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); +} + +/* + * call-seq: + * io.echo = flag + * + * 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; + 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; +} + +/* + * call-seq: + * io.echo? -> true or false + * + * 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; + int fd = GetReadFD(io); + + if (!getattr(fd, &t)) sys_fail(io); + return echo_p(&t) ? Qtrue : Qfalse; +} + +static const rb_data_type_t conmode_type = { + "console-mode", + {0, RUBY_TYPED_DEFAULT_FREE,}, + 0, 0, + RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; +static VALUE cConmode; + +static VALUE +conmode_alloc(VALUE klass) +{ + return rb_data_typed_object_zalloc(klass, sizeof(conmode), &conmode_type); +} + +static VALUE +conmode_new(VALUE klass, const conmode *t) +{ + VALUE obj = conmode_alloc(klass); + *(conmode *)DATA_PTR(obj) = *t; + return obj; +} + +static VALUE +conmode_init_copy(VALUE obj, VALUE obj2) +{ + conmode *t = rb_check_typeddata(obj, &conmode_type); + conmode *t2 = rb_check_typeddata(obj2, &conmode_type); + *t = *t2; + return obj; +} + +static VALUE +conmode_set_echo(VALUE obj, VALUE f) +{ + conmode *t = rb_check_typeddata(obj, &conmode_type); + if (RTEST(f)) + set_echo(t, NULL); + else + set_noecho(t, NULL); + return obj; +} + +static VALUE +conmode_set_raw(int argc, VALUE *argv, VALUE obj) +{ + conmode *t = rb_check_typeddata(obj, &conmode_type); + rawmode_arg_t opts, *optp = rawmode_opt(&argc, argv, 0, 0, &opts); + + set_rawmode(t, optp); + return obj; +} + +static VALUE +conmode_raw_new(int argc, VALUE *argv, VALUE obj) +{ + conmode *r = rb_check_typeddata(obj, &conmode_type); + conmode t = *r; + rawmode_arg_t opts, *optp = rawmode_opt(&argc, argv, 0, 0, &opts); + + set_rawmode(&t, optp); + return conmode_new(rb_obj_class(obj), &t); +} + +/* + * call-seq: + * io.console_mode -> mode + * + * 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; + int fd = GetReadFD(io); + + if (!getattr(fd, &t)) sys_fail(io); + + return conmode_new(cConmode, &t); +} + +/* + * call-seq: + * io.console_mode = mode + * + * 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; + int fd = GetReadFD(io); + + TypedData_Get_Struct(mode, conmode, &conmode_type, t); + r = *t; + + if (!setattr(fd, &r)) sys_fail(io); + + return mode; +} + +#if defined TIOCGWINSZ +typedef struct winsize rb_console_size_t; +#define getwinsize(fd, buf) (ioctl((fd), TIOCGWINSZ, (buf)) == 0) +#define setwinsize(fd, buf) (ioctl((fd), TIOCSWINSZ, (buf)) == 0) +#define winsize_row(buf) (buf)->ws_row +#define winsize_col(buf) (buf)->ws_col +#elif defined _WIN32 +typedef CONSOLE_SCREEN_BUFFER_INFO rb_console_size_t; +#define getwinsize(fd, buf) ( \ + GetConsoleScreenBufferInfo((HANDLE)rb_w32_get_osfhandle(fd), (buf)) || \ + SET_LAST_ERROR) +#define winsize_row(buf) ((buf)->srWindow.Bottom - (buf)->srWindow.Top + 1) +#define winsize_col(buf) (buf)->dwSize.X +#endif + +#if defined TIOCGWINSZ || defined _WIN32 +#define USE_CONSOLE_GETSIZE 1 +#endif + +#ifdef USE_CONSOLE_GETSIZE +/* + * call-seq: + * io.winsize -> [rows, columns] + * + * Returns console size. + * + * You must require 'io/console' to use this method. + */ +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))); +} + +static VALUE console_scroll(VALUE io, int line); +static VALUE console_goto(VALUE io, VALUE y, VALUE x); + +/* + * call-seq: + * io.winsize = [rows, columns] + * + * 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_console_size_t ws; +#if defined _WIN32 + HANDLE wh; + int newrow, newcol; + COORD oldsize; + SMALL_RECT oldwindow; +#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"); + } + oldsize = ws.dwSize; + oldwindow = ws.srWindow; + if (ws.srWindow.Right + 1 < newcol) { + ws.dwSize.X = newcol; + } + if (ws.dwSize.Y < newrow) { + ws.dwSize.Y = newrow; + } + /* expand screen buffer first if needed */ + if (!SetConsoleScreenBufferSize(wh, ws.dwSize)) { + rb_syserr_fail(LAST_ERROR, "SetConsoleScreenBufferInfo"); + } + /* refresh ws for new dwMaximumWindowSize */ + if (!GetConsoleScreenBufferInfo(wh, &ws)) { + rb_syserr_fail(LAST_ERROR, "GetConsoleScreenBufferInfo"); + } + /* check new size before modifying buffer content */ + if (newrow <= 0 || newcol <= 0 || + newrow > ws.dwMaximumWindowSize.Y || + newcol > ws.dwMaximumWindowSize.X) { + SetConsoleScreenBufferSize(wh, oldsize); + /* remove scrollbar if possible */ + SetConsoleWindowInfo(wh, TRUE, &oldwindow); + rb_raise(rb_eArgError, "out of range winsize: [%d, %d]", newrow, newcol); + } + /* shrink screen buffer width */ + ws.dwSize.X = newcol; + /* shrink screen buffer height if window height were the same */ + if (oldsize.Y == ws.srWindow.Bottom - ws.srWindow.Top + 1) { + ws.dwSize.Y = newrow; + } + ws.srWindow.Left = 0; + ws.srWindow.Right = newcol - 1; + ws.srWindow.Bottom = ws.srWindow.Top + newrow -1; + if (ws.dwCursorPosition.Y > ws.srWindow.Bottom) { + console_scroll(io, ws.dwCursorPosition.Y - ws.srWindow.Bottom); + ws.dwCursorPosition.Y = ws.srWindow.Bottom; + console_goto(io, INT2FIX(ws.dwCursorPosition.Y), INT2FIX(ws.dwCursorPosition.X)); + } + if (ws.srWindow.Bottom > ws.dwSize.Y - 1) { + console_scroll(io, ws.srWindow.Bottom - (ws.dwSize.Y - 1)); + ws.dwCursorPosition.Y -= ws.srWindow.Bottom - (ws.dwSize.Y - 1); + console_goto(io, INT2FIX(ws.dwCursorPosition.Y), INT2FIX(ws.dwCursorPosition.X)); + ws.srWindow.Bottom = ws.dwSize.Y - 1; + } + ws.srWindow.Top = ws.srWindow.Bottom - (newrow - 1); + /* perform changes to winsize */ + if (!SetConsoleWindowInfo(wh, TRUE, &ws.srWindow)) { + int last_error = LAST_ERROR; + SetConsoleScreenBufferSize(wh, oldsize); + rb_syserr_fail(last_error, "SetConsoleWindowInfo"); + } + /* perform screen buffer shrinking if necessary */ + if ((ws.dwSize.Y < oldsize.Y || ws.dwSize.X < oldsize.X) && + !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; +} +#endif + +#ifdef _WIN32 +/* + * call-seq: + * io.check_winsize_changed { ... } -> io + * + * Yields while console input events are queued. + * + * This method is Windows only. + * + * You must require 'io/console' to use this method. + */ +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; +} +#else +#define console_check_winsize_changed rb_f_notimplement +#endif + +/* + * call-seq: + * io.iflush + * + * Flushes input buffer in kernel. + * + * You must require 'io/console' to use this method. + */ +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; +} + +/* + * call-seq: + * io.oflush + * + * Flushes output buffer in kernel. + * + * You must require 'io/console' to use this method. + */ +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; +} + +/* + * call-seq: + * io.ioflush + * + * Flushes input and output buffers in kernel. + * + * You must require 'io/console' to use this method. + */ +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; +} + +/* + * call-seq: + * io.beep + * + * Beeps on the output console. + * + * You must require 'io/console' to use this method. + */ +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 int +mode_in_range(VALUE val, int high, const char *modename) +{ + int mode; + if (NIL_P(val)) return 0; + if (!RB_INTEGER_TYPE_P(val)) { + wrong_value: + rb_raise(rb_eArgError, "wrong %s mode: %"PRIsVALUE, modename, val); + } + if ((mode = NUM2INT(val)) < 0 || mode > high) { + goto wrong_value; + } + return mode; +} + +#if defined _WIN32 +static void +constat_clear(HANDLE handle, WORD attr, DWORD len, COORD pos) +{ + DWORD written; + + FillConsoleOutputAttribute(handle, attr, len, pos, &written); + FillConsoleOutputCharacterW(handle, L' ', len, pos, &written); +} + +static VALUE +console_scroll(VALUE io, int line) +{ + HANDLE h; + rb_console_size_t ws; + + h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(io)); + if (!GetConsoleScreenBufferInfo(h, &ws)) { + rb_syserr_fail(LAST_ERROR, 0); + } + if (line) { + SMALL_RECT scroll; + COORD destination; + CHAR_INFO fill; + scroll.Left = 0; + scroll.Top = line > 0 ? line : 0; + scroll.Right = winsize_col(&ws) - 1; + scroll.Bottom = winsize_row(&ws) - 1 + (line < 0 ? line : 0); + destination.X = 0; + destination.Y = line < 0 ? -line : 0; + fill.Char.UnicodeChar = L' '; + fill.Attributes = ws.wAttributes; + + ScrollConsoleScreenBuffer(h, &scroll, NULL, destination, &fill); + } + return io; +} + +#define GPERF_DOWNCASE 1 +#define GPERF_CASE_STRCMP 1 +#define gperf_case_strcmp STRCASECMP +#include "win32_vk.inc" + +/* + * call-seq: + * io.pressed?(key) -> bool + * + * Returns +true+ if +key+ is pressed. +key+ may be a virtual key + * code or its name (String or Symbol) with out "VK_" prefix. + * + * This method is Windows only. + * + * You must require 'io/console' to use this method. + */ +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; +} +#else +struct query_args { + char qstr[6]; + unsigned char opt; +}; + +static int +direct_query(VALUE io, const struct query_args *query) +{ + if (RB_TYPE_P(io, T_FILE)) { + VALUE wio = rb_io_get_write_io(io); + VALUE s = rb_str_new_cstr(query->qstr); + rb_io_write(wio, s); + rb_io_flush(wio); + return 1; + } + return 0; +} + +static VALUE +read_vt_response(VALUE io, VALUE query) +{ + struct query_args *qargs = (struct query_args *)query; + VALUE result, b; + int opt = 0; + int num = 0; + if (qargs) { + opt = qargs->opt; + if (!direct_query(io, qargs)) return Qnil; + } + if (rb_io_getbyte(io) != INT2FIX(0x1b)) return Qnil; + if (rb_io_getbyte(io) != INT2FIX('[')) return Qnil; + result = rb_ary_new(); + while (!NIL_P(b = rb_io_getbyte(io))) { + int c = NUM2UINT(b); + if (c == ';') { + rb_ary_push(result, INT2NUM(num)); + num = 0; + } + else if (ISDIGIT(c)) { + num = num * 10 + c - '0'; + } + else if (opt && c == opt) { + opt = 0; + } + else { + char last = (char)c; + rb_ary_push(result, INT2NUM(num)); + b = rb_str_new(&last, 1); + break; + } + } + return rb_ary_push(result, b); +} + +static VALUE +console_vt_response(int argc, VALUE *argv, VALUE io, const struct query_args *qargs) +{ + rawmode_arg_t opts, *optp = rawmode_opt(&argc, argv, 0, 1, &opts); + VALUE query = (VALUE)qargs; + VALUE ret = ttymode_with_io(io, read_vt_response, query, set_rawmode, optp); + return ret; +} + +static VALUE +console_scroll(VALUE io, int line) +{ + if (line) { + VALUE s = rb_sprintf(CSI "%d%c", line < 0 ? -line : line, + line < 0 ? 'T' : 'S'); + rb_io_write(io, s); + } + return io; +} + +# define console_key_pressed_p rb_f_notimplement +#endif + +/* + * call-seq: + * io.cursor -> [row, column] + * + * Returns the current cursor position as a two-element array of integers (row, column) + * + * io.cursor # => [3, 5] + * + * You must require 'io/console' to use this method. + */ +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 - ws.srWindow.Top), 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 +} + +/* + * call-seq: + * io.goto(line, column) -> io + * + * Set the cursor position at +line+ and +column+. + * + * You must require 'io/console' to use this method. + */ +static VALUE +console_goto(VALUE io, VALUE y, VALUE x) +{ +#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 = NUM2UINT(x); + pos->Y = ws.srWindow.Top + NUM2UINT(y); + if (!SetConsoleCursorPosition(h, *pos)) { + rb_syserr_fail(LAST_ERROR, 0); + } +#else + rb_io_write(io, rb_sprintf(CSI "%d;%dH", NUM2UINT(y)+1, NUM2UINT(x)+1)); +#endif + return io; +} + +static VALUE +console_move(VALUE io, int y, int x) +{ +#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 += x; + pos->Y += y; + if (!SetConsoleCursorPosition(h, *pos)) { + rb_syserr_fail(LAST_ERROR, 0); + } +#else + if (x || y) { + VALUE s = rb_str_new_cstr(""); + if (y) rb_str_catf(s, CSI "%d%c", y < 0 ? -y : y, y < 0 ? 'A' : 'B'); + if (x) rb_str_catf(s, CSI "%d%c", x < 0 ? -x : x, x < 0 ? 'D' : 'C'); + rb_io_write(io, s); + rb_io_flush(io); + } +#endif + return io; +} + +/* + * call-seq: + * io.goto_column(column) -> io + * + * Set the cursor position at +column+ in the same line of the current + * position. + * + * You must require 'io/console' to use this method. + */ +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(CSI "%dG", NUM2UINT(val)+1)); +#endif + return io; +} + +/* + * call-seq: + * io.erase_line(mode) -> io + * + * Erases the line at the cursor corresponding to +mode+. + * +mode+ may be either: + * 0: after cursor + * 1: before and cursor + * 2: entire line + * + * You must require 'io/console' to use this method. + */ +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(CSI "%dK", mode)); +#endif + return io; +} + +/* + * call-seq: + * io.erase_screen(mode) -> io + * + * Erases the screen at the cursor corresponding to +mode+. + * +mode+ may be either: + * 0: after cursor + * 1: before and cursor + * 2: entire screen + * + * You must require 'io/console' to use this method. + */ +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(CSI "%dJ", mode)); +#endif + return io; +} + +/* + * call-seq: + * io.cursor = [line, column] -> io + * + * Same as <tt>io.goto(line, column)</tt> + * + * See IO#goto. + * + * You must require 'io/console' to use this method. + */ +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)); +} + +/* + * call-seq: + * io.cursor_up(n) -> io + * + * Moves the cursor up +n+ lines. + * + * You must require 'io/console' to use this method. + */ +static VALUE +console_cursor_up(VALUE io, VALUE val) +{ + return console_move(io, -NUM2INT(val), 0); +} + +/* + * call-seq: + * io.cursor_down(n) -> io + * + * Moves the cursor down +n+ lines. + * + * You must require 'io/console' to use this method. + */ +static VALUE +console_cursor_down(VALUE io, VALUE val) +{ + return console_move(io, +NUM2INT(val), 0); +} + +/* + * call-seq: + * io.cursor_left(n) -> io + * + * Moves the cursor left +n+ columns. + * + * You must require 'io/console' to use this method. + */ +static VALUE +console_cursor_left(VALUE io, VALUE val) +{ + return console_move(io, 0, -NUM2INT(val)); +} + +/* + * call-seq: + * io.cursor_right(n) -> io + * + * Moves the cursor right +n+ columns. + * + * You must require 'io/console' to use this method. + */ +static VALUE +console_cursor_right(VALUE io, VALUE val) +{ + return console_move(io, 0, +NUM2INT(val)); +} + +/* + * call-seq: + * io.scroll_forward(n) -> io + * + * Scrolls the entire scrolls forward +n+ lines. + * + * You must require 'io/console' to use this method. + */ +static VALUE +console_scroll_forward(VALUE io, VALUE val) +{ + return console_scroll(io, +NUM2INT(val)); +} + +/* + * call-seq: + * io.scroll_backward(n) -> io + * + * Scrolls the entire scrolls backward +n+ lines. + * + * You must require 'io/console' to use this method. + */ +static VALUE +console_scroll_backward(VALUE io, VALUE val) +{ + return console_scroll(io, -NUM2INT(val)); +} + +/* + * call-seq: + * io.clear_screen -> io + * + * Clears the entire screen and moves the cursor top-left corner. + * + * You must require 'io/console' to use this method. + */ +static VALUE +console_clear_screen(VALUE io) +{ + console_erase_screen(io, INT2FIX(2)); + console_goto(io, INT2FIX(0), INT2FIX(0)); + return io; +} + +#ifndef HAVE_RB_IO_OPEN_DESCRIPTOR +static VALUE +io_open_descriptor_fallback(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, void *encoding) +{ + VALUE arguments[2] = { + (rb_update_max_fd(descriptor), INT2NUM(descriptor)), + INT2FIX(mode), + }; + + VALUE self = rb_class_new_instance(2, arguments, klass); + + rb_io_t *fptr; + GetOpenFile(self, fptr); + fptr->pathv = path; + fptr->mode |= mode; + + return self; +} +#define rb_io_open_descriptor io_open_descriptor_fallback +#endif + +#ifndef HAVE_RB_IO_CLOSED_P +static VALUE +rb_io_closed_p(VALUE io) +{ + rb_io_t *fptr = RFILE(io)->fptr; + return fptr->fd == -1 ? Qtrue : Qfalse; +} +#endif + +#if defined(RB_EXT_RACTOR_SAFE) && defined(HAVE_RB_RACTOR_LOCAL_STORAGE_VALUE_NEWKEY) +# define USE_RACTOR_STORAGE 1 +#else +# define USE_RACTOR_STORAGE 0 +#endif + +#if USE_RACTOR_STORAGE +#include "ruby/ractor.h" +static rb_ractor_local_key_t key_console_dev; + +static bool +console_dev_get(VALUE klass, VALUE *dev) +{ + return rb_ractor_local_storage_value_lookup(key_console_dev, dev); +} + +static void +console_dev_set(VALUE klass, VALUE value) +{ + rb_ractor_local_storage_value_set(key_console_dev, value); +} + +static void +console_dev_remove(VALUE klass) +{ + console_dev_set(klass, Qnil); +} + +#else + +static ID id_console; + +static int +console_dev_get(VALUE klass, VALUE *dev) +{ + if (rb_const_defined(klass, id_console)) { + *dev = rb_const_get(klass, id_console); + return 1; + } + return 0; +} + +static void +console_dev_set(VALUE klass, VALUE value) +{ + rb_const_set(klass, id_console, value); +} + +static void +console_dev_remove(VALUE klass) +{ + rb_const_remove(klass, id_console); +} + +#endif + +/* + * call-seq: + * IO.console -> #<File:/dev/tty> + * IO.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; + VALUE sym = 0; + + if (argc) { + Check_Type(sym = argv[0], T_SYMBOL); + } + + /* Force the class to be File. */ + if (klass == rb_cIO) klass = rb_cFile; + + if (console_dev_get(klass, &con)) { + if (!RB_TYPE_P(con, T_FILE) || RTEST(rb_io_closed_p(con))) { + console_dev_remove(klass); + con = 0; + } + } + + if (sym) { + if (sym == ID2SYM(id_close) && argc == 1) { + if (con) { + rb_io_close(con); + console_dev_remove(klass); + 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; +#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 + console_dev_set(klass, con); + } + + if (sym) { + return rb_f_send(argc, argv, con); + } + + return con; +} + +/* + * call-seq: + * io.getch(min: nil, time: nil, intr: nil) -> char + * + * See IO#getch. + */ +static VALUE +io_getch(int argc, VALUE *argv, VALUE io) +{ + return rb_funcallv(io, id_getc, argc, argv); +} + +static VALUE +puts_call(VALUE io) +{ + return rb_io_write(io, rb_default_rs); +} + +static VALUE +gets_call(VALUE io) +{ + return rb_funcallv(io, id_gets, 0, 0); +} + +static VALUE +getpass_call(VALUE io) +{ + return ttymode(io, rb_io_gets, io, set_noecho, NULL); +} + +static void +prompt(int argc, VALUE *argv, VALUE io) +{ + if (argc > 0 && !NIL_P(argv[0])) { + VALUE str = argv[0]; + StringValueCStr(str); + rb_io_write(io, str); + } +} + +static VALUE +str_chomp(VALUE str) +{ + if (!NIL_P(str)) { + const VALUE rs = rb_default_rs; /* rvalue in TruffleRuby */ + rb_funcallv(str, id_chomp_bang, 1, &rs); + } + return str; +} + +/* + * call-seq: + * io.getpass(prompt=nil) -> string + * + * Reads and returns a line without echo back. + * Prints +prompt+ unless it is +nil+. + * + * The newline character that terminates the + * read line is removed from the returned string, + * see String#chomp!. + * + * You must require 'io/console' to use this method. + * + * 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); +} + +/* + * call-seq: + * io.getpass(prompt=nil) -> string + * + * See IO#getpass. + */ +static VALUE +io_getpass(int argc, VALUE *argv, VALUE io) +{ + VALUE str; + + rb_check_arity(argc, 0, 1); + prompt(argc, argv, io); + rb_check_funcall(io, id_flush, 0, 0); + str = rb_ensure(gets_call, io, puts_call, io); + return str_chomp(str); +} + +#if defined(_WIN32) || defined(HAVE_TTYNAME_R) || defined(HAVE_TTYNAME) +/* + * call-seq: + * io.ttyname -> string or nil + * + * Returns name of associated terminal (tty) if +io+ is not a tty. + * Returns +nil+ otherwise. + */ +static VALUE +console_ttyname(VALUE io) +{ + int fd = rb_io_descriptor(io); + if (!isatty(fd)) return Qnil; +# if defined _WIN32 + return rb_usascii_str_new_lit("con"); +# elif defined HAVE_TTYNAME_R + { + char termname[1024], *tn = termname; + size_t size = sizeof(termname); + int e; + if (ttyname_r(fd, tn, size) == 0) + return rb_interned_str_cstr(tn); + if ((e = errno) == ERANGE) { + VALUE s = rb_str_new(0, size); + while (1) { + tn = RSTRING_PTR(s); + size = rb_str_capacity(s); + if (ttyname_r(fd, tn, size) == 0) { + return rb_str_to_interned_str(rb_str_resize(s, strlen(tn))); + } + if ((e = errno) != ERANGE) break; + if ((size *= 2) >= INT_MAX/2) break; + rb_str_resize(s, size); + } + } + rb_syserr_fail_str(e, rb_sprintf("ttyname_r(%d)", fd)); + UNREACHABLE_RETURN(Qnil); + } +# elif defined HAVE_TTYNAME + { + const char *tn = ttyname(fd); + if (!tn) { + int e = errno; + rb_syserr_fail_str(e, rb_sprintf("ttyname(%d)", fd)); + } + return rb_interned_str_cstr(tn); + } +# else +# error No ttyname function +# endif +} +#else +# define console_ttyname rb_f_notimplement +#endif + +/* + * IO console methods + */ +void +Init_console(void) +{ +#if USE_RACTOR_STORAGE + RB_EXT_RACTOR_SAFE(true); +#endif + +#undef rb_intern +#if USE_RACTOR_STORAGE + key_console_dev = rb_ractor_local_storage_value_newkey(); +#else + id_console = rb_intern("console"); +#endif + id_getc = rb_intern("getc"); + id_gets = rb_intern("gets"); + id_flush = rb_intern("flush"); + id_chomp_bang = rb_intern("chomp!"); + id_close = rb_intern("close"); +#define init_rawmode_opt_id(name) \ + rawmode_opt_ids[kwd_##name] = rb_intern(#name) + init_rawmode_opt_id(min); + init_rawmode_opt_id(time); + init_rawmode_opt_id(intr); +#ifndef HAVE_RB_F_SEND + id___send__ = rb_intern("__send__"); +#endif + InitVM(console); +} + +void +InitVM_console(void) +{ + rb_define_method(rb_cIO, "raw", console_raw, -1); + rb_define_method(rb_cIO, "raw!", console_set_raw, -1); + rb_define_method(rb_cIO, "cooked", console_cooked, 0); + rb_define_method(rb_cIO, "cooked!", console_set_cooked, 0); + rb_define_method(rb_cIO, "getch", console_getch, -1); + rb_define_method(rb_cIO, "echo=", console_set_echo, 1); + rb_define_method(rb_cIO, "echo?", console_echo_p, 0); + rb_define_method(rb_cIO, "console_mode", console_conmode_get, 0); + rb_define_method(rb_cIO, "console_mode=", console_conmode_set, 1); + rb_define_method(rb_cIO, "noecho", console_noecho, 0); + rb_define_method(rb_cIO, "winsize", console_winsize, 0); + rb_define_method(rb_cIO, "winsize=", console_set_winsize, 1); + rb_define_method(rb_cIO, "iflush", console_iflush, 0); + rb_define_method(rb_cIO, "oflush", console_oflush, 0); + rb_define_method(rb_cIO, "ioflush", console_ioflush, 0); + rb_define_method(rb_cIO, "beep", console_beep, 0); + rb_define_method(rb_cIO, "goto", console_goto, 2); + rb_define_method(rb_cIO, "cursor", console_cursor_pos, 0); + rb_define_method(rb_cIO, "cursor=", console_cursor_set, 1); + rb_define_method(rb_cIO, "cursor_up", console_cursor_up, 1); + rb_define_method(rb_cIO, "cursor_down", console_cursor_down, 1); + rb_define_method(rb_cIO, "cursor_left", console_cursor_left, 1); + rb_define_method(rb_cIO, "cursor_right", console_cursor_right, 1); + rb_define_method(rb_cIO, "goto_column", console_goto_column, 1); + rb_define_method(rb_cIO, "erase_line", console_erase_line, 1); + rb_define_method(rb_cIO, "erase_screen", console_erase_screen, 1); + rb_define_method(rb_cIO, "scroll_forward", console_scroll_forward, 1); + rb_define_method(rb_cIO, "scroll_backward", console_scroll_backward, 1); + rb_define_method(rb_cIO, "clear_screen", console_clear_screen, 0); + rb_define_method(rb_cIO, "pressed?", console_key_pressed_p, 1); + rb_define_method(rb_cIO, "check_winsize_changed", console_check_winsize_changed, 0); + rb_define_method(rb_cIO, "getpass", console_getpass, -1); + rb_define_method(rb_cIO, "ttyname", console_ttyname, 0); + rb_define_singleton_method(rb_cIO, "console", console_dev, -1); + { + /* :nodoc: */ + VALUE mReadable = rb_define_module_under(rb_cIO, "generic_readable"); + rb_define_method(mReadable, "getch", io_getch, -1); + rb_define_method(mReadable, "getpass", io_getpass, -1); + } + { + /* :nodoc: */ + cConmode = rb_define_class_under(rb_cIO, "ConsoleMode", rb_cObject); + rb_define_const(cConmode, "VERSION", rb_obj_freeze(rb_str_new_cstr(IO_CONSOLE_VERSION))); + rb_define_alloc_func(cConmode, conmode_alloc); + rb_undef_method(cConmode, "initialize"); + rb_define_method(cConmode, "initialize_copy", conmode_init_copy, 1); + rb_define_method(cConmode, "echo=", conmode_set_echo, 1); + rb_define_method(cConmode, "raw!", conmode_set_raw, -1); + rb_define_method(cConmode, "raw", conmode_raw_new, -1); + } +} diff --git a/ext/io/console/depend b/ext/io/console/depend new file mode 100644 index 0000000000..150a138d4d --- /dev/null +++ b/ext/io/console/depend @@ -0,0 +1,199 @@ +# AUTOGENERATED DEPENDENCIES START +console.o: $(RUBY_EXTCONF_H) +console.o: $(arch_hdrdir)/ruby/config.h +console.o: $(hdrdir)/ruby.h +console.o: $(hdrdir)/ruby/assert.h +console.o: $(hdrdir)/ruby/backward.h +console.o: $(hdrdir)/ruby/backward/2/assume.h +console.o: $(hdrdir)/ruby/backward/2/attributes.h +console.o: $(hdrdir)/ruby/backward/2/bool.h +console.o: $(hdrdir)/ruby/backward/2/inttypes.h +console.o: $(hdrdir)/ruby/backward/2/limits.h +console.o: $(hdrdir)/ruby/backward/2/long_long.h +console.o: $(hdrdir)/ruby/backward/2/stdalign.h +console.o: $(hdrdir)/ruby/backward/2/stdarg.h +console.o: $(hdrdir)/ruby/defines.h +console.o: $(hdrdir)/ruby/encoding.h +console.o: $(hdrdir)/ruby/fiber/scheduler.h +console.o: $(hdrdir)/ruby/intern.h +console.o: $(hdrdir)/ruby/internal/abi.h +console.o: $(hdrdir)/ruby/internal/anyargs.h +console.o: $(hdrdir)/ruby/internal/arithmetic.h +console.o: $(hdrdir)/ruby/internal/arithmetic/char.h +console.o: $(hdrdir)/ruby/internal/arithmetic/double.h +console.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +console.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +console.o: $(hdrdir)/ruby/internal/arithmetic/int.h +console.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +console.o: $(hdrdir)/ruby/internal/arithmetic/long.h +console.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +console.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +console.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +console.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +console.o: $(hdrdir)/ruby/internal/arithmetic/short.h +console.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +console.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +console.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +console.o: $(hdrdir)/ruby/internal/assume.h +console.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +console.o: $(hdrdir)/ruby/internal/attr/artificial.h +console.o: $(hdrdir)/ruby/internal/attr/cold.h +console.o: $(hdrdir)/ruby/internal/attr/const.h +console.o: $(hdrdir)/ruby/internal/attr/constexpr.h +console.o: $(hdrdir)/ruby/internal/attr/deprecated.h +console.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +console.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +console.o: $(hdrdir)/ruby/internal/attr/error.h +console.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +console.o: $(hdrdir)/ruby/internal/attr/forceinline.h +console.o: $(hdrdir)/ruby/internal/attr/format.h +console.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +console.o: $(hdrdir)/ruby/internal/attr/noalias.h +console.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +console.o: $(hdrdir)/ruby/internal/attr/noexcept.h +console.o: $(hdrdir)/ruby/internal/attr/noinline.h +console.o: $(hdrdir)/ruby/internal/attr/nonnull.h +console.o: $(hdrdir)/ruby/internal/attr/noreturn.h +console.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +console.o: $(hdrdir)/ruby/internal/attr/pure.h +console.o: $(hdrdir)/ruby/internal/attr/restrict.h +console.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +console.o: $(hdrdir)/ruby/internal/attr/warning.h +console.o: $(hdrdir)/ruby/internal/attr/weakref.h +console.o: $(hdrdir)/ruby/internal/cast.h +console.o: $(hdrdir)/ruby/internal/compiler_is.h +console.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +console.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +console.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +console.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +console.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +console.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +console.o: $(hdrdir)/ruby/internal/compiler_since.h +console.o: $(hdrdir)/ruby/internal/config.h +console.o: $(hdrdir)/ruby/internal/constant_p.h +console.o: $(hdrdir)/ruby/internal/core.h +console.o: $(hdrdir)/ruby/internal/core/rarray.h +console.o: $(hdrdir)/ruby/internal/core/rbasic.h +console.o: $(hdrdir)/ruby/internal/core/rbignum.h +console.o: $(hdrdir)/ruby/internal/core/rclass.h +console.o: $(hdrdir)/ruby/internal/core/rdata.h +console.o: $(hdrdir)/ruby/internal/core/rfile.h +console.o: $(hdrdir)/ruby/internal/core/rhash.h +console.o: $(hdrdir)/ruby/internal/core/robject.h +console.o: $(hdrdir)/ruby/internal/core/rregexp.h +console.o: $(hdrdir)/ruby/internal/core/rstring.h +console.o: $(hdrdir)/ruby/internal/core/rstruct.h +console.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +console.o: $(hdrdir)/ruby/internal/ctype.h +console.o: $(hdrdir)/ruby/internal/dllexport.h +console.o: $(hdrdir)/ruby/internal/dosish.h +console.o: $(hdrdir)/ruby/internal/encoding/coderange.h +console.o: $(hdrdir)/ruby/internal/encoding/ctype.h +console.o: $(hdrdir)/ruby/internal/encoding/encoding.h +console.o: $(hdrdir)/ruby/internal/encoding/pathname.h +console.o: $(hdrdir)/ruby/internal/encoding/re.h +console.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +console.o: $(hdrdir)/ruby/internal/encoding/string.h +console.o: $(hdrdir)/ruby/internal/encoding/symbol.h +console.o: $(hdrdir)/ruby/internal/encoding/transcode.h +console.o: $(hdrdir)/ruby/internal/error.h +console.o: $(hdrdir)/ruby/internal/eval.h +console.o: $(hdrdir)/ruby/internal/event.h +console.o: $(hdrdir)/ruby/internal/fl_type.h +console.o: $(hdrdir)/ruby/internal/gc.h +console.o: $(hdrdir)/ruby/internal/glob.h +console.o: $(hdrdir)/ruby/internal/globals.h +console.o: $(hdrdir)/ruby/internal/has/attribute.h +console.o: $(hdrdir)/ruby/internal/has/builtin.h +console.o: $(hdrdir)/ruby/internal/has/c_attribute.h +console.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +console.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +console.o: $(hdrdir)/ruby/internal/has/extension.h +console.o: $(hdrdir)/ruby/internal/has/feature.h +console.o: $(hdrdir)/ruby/internal/has/warning.h +console.o: $(hdrdir)/ruby/internal/intern/array.h +console.o: $(hdrdir)/ruby/internal/intern/bignum.h +console.o: $(hdrdir)/ruby/internal/intern/class.h +console.o: $(hdrdir)/ruby/internal/intern/compar.h +console.o: $(hdrdir)/ruby/internal/intern/complex.h +console.o: $(hdrdir)/ruby/internal/intern/cont.h +console.o: $(hdrdir)/ruby/internal/intern/dir.h +console.o: $(hdrdir)/ruby/internal/intern/enum.h +console.o: $(hdrdir)/ruby/internal/intern/enumerator.h +console.o: $(hdrdir)/ruby/internal/intern/error.h +console.o: $(hdrdir)/ruby/internal/intern/eval.h +console.o: $(hdrdir)/ruby/internal/intern/file.h +console.o: $(hdrdir)/ruby/internal/intern/hash.h +console.o: $(hdrdir)/ruby/internal/intern/io.h +console.o: $(hdrdir)/ruby/internal/intern/load.h +console.o: $(hdrdir)/ruby/internal/intern/marshal.h +console.o: $(hdrdir)/ruby/internal/intern/numeric.h +console.o: $(hdrdir)/ruby/internal/intern/object.h +console.o: $(hdrdir)/ruby/internal/intern/parse.h +console.o: $(hdrdir)/ruby/internal/intern/proc.h +console.o: $(hdrdir)/ruby/internal/intern/process.h +console.o: $(hdrdir)/ruby/internal/intern/random.h +console.o: $(hdrdir)/ruby/internal/intern/range.h +console.o: $(hdrdir)/ruby/internal/intern/rational.h +console.o: $(hdrdir)/ruby/internal/intern/re.h +console.o: $(hdrdir)/ruby/internal/intern/ruby.h +console.o: $(hdrdir)/ruby/internal/intern/select.h +console.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +console.o: $(hdrdir)/ruby/internal/intern/set.h +console.o: $(hdrdir)/ruby/internal/intern/signal.h +console.o: $(hdrdir)/ruby/internal/intern/sprintf.h +console.o: $(hdrdir)/ruby/internal/intern/string.h +console.o: $(hdrdir)/ruby/internal/intern/struct.h +console.o: $(hdrdir)/ruby/internal/intern/thread.h +console.o: $(hdrdir)/ruby/internal/intern/time.h +console.o: $(hdrdir)/ruby/internal/intern/variable.h +console.o: $(hdrdir)/ruby/internal/intern/vm.h +console.o: $(hdrdir)/ruby/internal/interpreter.h +console.o: $(hdrdir)/ruby/internal/iterator.h +console.o: $(hdrdir)/ruby/internal/memory.h +console.o: $(hdrdir)/ruby/internal/method.h +console.o: $(hdrdir)/ruby/internal/module.h +console.o: $(hdrdir)/ruby/internal/newobj.h +console.o: $(hdrdir)/ruby/internal/scan_args.h +console.o: $(hdrdir)/ruby/internal/special_consts.h +console.o: $(hdrdir)/ruby/internal/static_assert.h +console.o: $(hdrdir)/ruby/internal/stdalign.h +console.o: $(hdrdir)/ruby/internal/stdbool.h +console.o: $(hdrdir)/ruby/internal/stdckdint.h +console.o: $(hdrdir)/ruby/internal/symbol.h +console.o: $(hdrdir)/ruby/internal/value.h +console.o: $(hdrdir)/ruby/internal/value_type.h +console.o: $(hdrdir)/ruby/internal/variable.h +console.o: $(hdrdir)/ruby/internal/warning_push.h +console.o: $(hdrdir)/ruby/internal/xmalloc.h +console.o: $(hdrdir)/ruby/io.h +console.o: $(hdrdir)/ruby/missing.h +console.o: $(hdrdir)/ruby/onigmo.h +console.o: $(hdrdir)/ruby/oniguruma.h +console.o: $(hdrdir)/ruby/ractor.h +console.o: $(hdrdir)/ruby/ruby.h +console.o: $(hdrdir)/ruby/st.h +console.o: $(hdrdir)/ruby/subst.h +console.o: $(hdrdir)/ruby/thread.h +console.o: console.c +# AUTOGENERATED DEPENDENCIES END + +win32_vk.inc: win32_vk.list + +.list.inc: + ( \ + $(RUBY) -anF, \ + -e 'BEGIN {puts "#define UNDEFINED_VK (unsigned short)-1"}' \ + -e 'n=$$F[1] and (n.strip!; /\AVK_/=~n) and' \ + -e 'puts(%[#ifndef #{n}\n# define #{n} UNDEFINED_VK\n#endif])' \ + $< && \ + gperf --ignore-case -L ANSI-C -E -C -P -p -j1 -i 1 -g -o -t -K ofs -N console_win32_vk -k* $< \ + | sed -f $(top_srcdir)/tool/gperf.sed \ + ) > $(@F) + +.SUFFIXES: .chksum .list .inc + +.list.chksum: + @$(RUBY) -I$(top_srcdir)/tool -rchecksum \ + -e "Checksum.update(ARGV) {|k|k.copy(k.target) rescue k.make(k.target)}" \ + -- --make=$(MAKE) -I$(srcdir) $(<F) $(@F:.chksum=.inc) diff --git a/ext/io/console/extconf.rb b/ext/io/console/extconf.rb new file mode 100644 index 0000000000..dd3d221ae5 --- /dev/null +++ b/ext/io/console/extconf.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: false +require 'mkmf' + +# `--target-rbconfig` compatibility for Ruby 3.3 or earlier +# See https://bugs.ruby-lang.org/issues/20345 +MakeMakefile::RbConfig ||= ::RbConfig + +have_func("rb_syserr_fail_str(0, Qnil)") or +have_func("rb_syserr_new_str(0, Qnil)") or + abort + +have_func("rb_interned_str_cstr") +have_func("rb_io_path", "ruby/io.h") +have_func("rb_io_descriptor", "ruby/io.h") +have_func("rb_io_get_write_io", "ruby/io.h") +have_func("rb_io_closed_p", "ruby/io.h") +have_func("rb_io_open_descriptor", "ruby/io.h") +have_func("rb_ractor_local_storage_value_newkey") + +is_wasi = /wasi/ =~ MakeMakefile::RbConfig::CONFIG["platform"] +# `ok` can be `true`, `false`, or `nil`: +# * `true` : Required headers and functions available, proceed regular build. +# * `false`: Required headers or functions not available, abort build. +# * `nil` : Unsupported compilation target, generate dummy Makefile. +# +# Skip building io/console on WASI, as it does not support termios.h. +ok = true if (RUBY_ENGINE == "ruby" && !is_wasi) || RUBY_ENGINE == "truffleruby" +hdr = nil +case +when macro_defined?("_WIN32", "") + # rb_w32_map_errno: 1.8.7 + vk_header = File.exist?("#$srcdir/win32_vk.list") ? "chksum" : "inc" + vk_header = "#{'{$(srcdir)}' if $nmake == ?m}win32_vk.#{vk_header}" +when hdr = %w"termios.h termio.h".find {|h| have_header(h)} + have_func("cfmakeraw", hdr) +when have_header(hdr = "sgtty.h") + %w"stty gtty".each {|f| have_func(f, hdr)} +else + ok = false +end if ok +case ok +when true + have_header("sys/ioctl.h") if hdr + # rb_check_hash_type: 1.9.3 + # rb_io_get_write_io: 1.9.1 + # rb_cloexec_open: 2.0.0 + # rb_funcallv: 2.1.0 + # RARRAY_CONST_PTR: 2.1.0 + # rb_sym2str: 2.2.0 + if have_macro("HAVE_RUBY_FIBER_SCHEDULER_H") + $defs << "-D""HAVE_RB_IO_WAIT=1" + elsif have_func("rb_scheduler_timeout") # 3.0 + have_func("rb_io_wait") + end + have_func("ttyname_r") or have_func("ttyname") + create_makefile("io/console") {|conf| + conf << "\n""VK_HEADER = #{vk_header}\n" + } +when nil + File.write("Makefile", dummy_makefile($srcdir).join("")) +end diff --git a/ext/io/console/io-console.gemspec b/ext/io/console/io-console.gemspec new file mode 100644 index 0000000000..0a19992734 --- /dev/null +++ b/ext/io/console/io-console.gemspec @@ -0,0 +1,53 @@ +# -*- ruby -*- +_VERSION = ["", "ext/io/console/"].find do |dir| + begin + break File.open(File.join(__dir__, "#{dir}console.c")) {|f| + f.gets("\nIO_CONSOLE_VERSION ") + f.gets[/"(.+)"/, 1] + } + rescue Errno::ENOENT + end +end + +Gem::Specification.new do |s| + s.name = "io-console" + s.version = _VERSION + s.summary = "Console interface" + s.email = "nobu@ruby-lang.org" + s.description = "add console capabilities to IO instances." + s.required_ruby_version = ">= 2.6.0" + s.homepage = "https://github.com/ruby/io-console" + s.metadata["source_code_url"] = s.homepage + s.metadata["changelog_uri"] = s.homepage + "/releases" + s.authors = ["Nobu Nakada"] + s.require_path = %[lib] + s.files = %w[ + .document + BSDL + COPYING + README.md + ext/io/console/console.c + ext/io/console/extconf.rb + ext/io/console/win32_vk.inc + lib/io/console/size.rb + ] + s.extensions = %w[ext/io/console/extconf.rb] + + if Gem::Platform === s.platform and s.platform =~ 'java' + s.files.delete_if {|f| f.start_with?("ext/")} + s.extensions.clear + s.require_paths.unshift('lib/ffi') + s.files.concat(%w[ + lib/ffi/io/console.rb + lib/ffi/io/console/bsd_console.rb + lib/ffi/io/console/common.rb + lib/ffi/io/console/linux_console.rb + lib/ffi/io/console/native_console.rb + lib/ffi/io/console/stty_console.rb + lib/ffi/io/console/stub_console.rb + lib/ffi/io/console/version.rb + ]) + end + + s.licenses = ["Ruby", "BSD-2-Clause"] +end diff --git a/ext/io/console/lib/console/size.rb b/ext/io/console/lib/console/size.rb new file mode 100644 index 0000000000..14b9a74b22 --- /dev/null +++ b/ext/io/console/lib/console/size.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: false +# fallback to console window size +def IO.default_console_size + [ + ENV["LINES"].to_i.nonzero? || 25, + ENV["COLUMNS"].to_i.nonzero? || 80, + ] +end + +begin + require 'io/console' +rescue LoadError + class << IO + alias console_size default_console_size + end +else + # returns console window size + def IO.console_size + console.winsize + rescue NoMethodError + default_console_size + end +end diff --git a/ext/io/console/win32_vk.chksum b/ext/io/console/win32_vk.chksum new file mode 100644 index 0000000000..bc9fff7560 --- /dev/null +++ b/ext/io/console/win32_vk.chksum @@ -0,0 +1 @@ +src="win32_vk.list", len=3269, checksum=34076 diff --git a/ext/io/console/win32_vk.inc b/ext/io/console/win32_vk.inc new file mode 100644 index 0000000000..348e6be5ed --- /dev/null +++ b/ext/io/console/win32_vk.inc @@ -0,0 +1,1390 @@ +#define UNDEFINED_VK (unsigned short)-1 +#ifndef VK_LBUTTON +# define VK_LBUTTON UNDEFINED_VK +#endif +#ifndef VK_RBUTTON +# define VK_RBUTTON UNDEFINED_VK +#endif +#ifndef VK_CANCEL +# define VK_CANCEL UNDEFINED_VK +#endif +#ifndef VK_MBUTTON +# define VK_MBUTTON UNDEFINED_VK +#endif +#ifndef VK_XBUTTON1 +# define VK_XBUTTON1 UNDEFINED_VK +#endif +#ifndef VK_XBUTTON2 +# define VK_XBUTTON2 UNDEFINED_VK +#endif +#ifndef VK_BACK +# define VK_BACK UNDEFINED_VK +#endif +#ifndef VK_TAB +# define VK_TAB UNDEFINED_VK +#endif +#ifndef VK_CLEAR +# define VK_CLEAR UNDEFINED_VK +#endif +#ifndef VK_RETURN +# define VK_RETURN UNDEFINED_VK +#endif +#ifndef VK_SHIFT +# define VK_SHIFT UNDEFINED_VK +#endif +#ifndef VK_CONTROL +# define VK_CONTROL UNDEFINED_VK +#endif +#ifndef VK_MENU +# define VK_MENU UNDEFINED_VK +#endif +#ifndef VK_PAUSE +# define VK_PAUSE UNDEFINED_VK +#endif +#ifndef VK_CAPITAL +# define VK_CAPITAL UNDEFINED_VK +#endif +#ifndef VK_KANA +# define VK_KANA UNDEFINED_VK +#endif +#ifndef VK_HANGEUL +# define VK_HANGEUL UNDEFINED_VK +#endif +#ifndef VK_HANGUL +# define VK_HANGUL UNDEFINED_VK +#endif +#ifndef VK_JUNJA +# define VK_JUNJA UNDEFINED_VK +#endif +#ifndef VK_FINAL +# define VK_FINAL UNDEFINED_VK +#endif +#ifndef VK_HANJA +# define VK_HANJA UNDEFINED_VK +#endif +#ifndef VK_KANJI +# define VK_KANJI UNDEFINED_VK +#endif +#ifndef VK_ESCAPE +# define VK_ESCAPE UNDEFINED_VK +#endif +#ifndef VK_CONVERT +# define VK_CONVERT UNDEFINED_VK +#endif +#ifndef VK_NONCONVERT +# define VK_NONCONVERT UNDEFINED_VK +#endif +#ifndef VK_ACCEPT +# define VK_ACCEPT UNDEFINED_VK +#endif +#ifndef VK_MODECHANGE +# define VK_MODECHANGE UNDEFINED_VK +#endif +#ifndef VK_SPACE +# define VK_SPACE UNDEFINED_VK +#endif +#ifndef VK_PRIOR +# define VK_PRIOR UNDEFINED_VK +#endif +#ifndef VK_NEXT +# define VK_NEXT UNDEFINED_VK +#endif +#ifndef VK_END +# define VK_END UNDEFINED_VK +#endif +#ifndef VK_HOME +# define VK_HOME UNDEFINED_VK +#endif +#ifndef VK_LEFT +# define VK_LEFT UNDEFINED_VK +#endif +#ifndef VK_UP +# define VK_UP UNDEFINED_VK +#endif +#ifndef VK_RIGHT +# define VK_RIGHT UNDEFINED_VK +#endif +#ifndef VK_DOWN +# define VK_DOWN UNDEFINED_VK +#endif +#ifndef VK_SELECT +# define VK_SELECT UNDEFINED_VK +#endif +#ifndef VK_PRINT +# define VK_PRINT UNDEFINED_VK +#endif +#ifndef VK_EXECUTE +# define VK_EXECUTE UNDEFINED_VK +#endif +#ifndef VK_SNAPSHOT +# define VK_SNAPSHOT UNDEFINED_VK +#endif +#ifndef VK_INSERT +# define VK_INSERT UNDEFINED_VK +#endif +#ifndef VK_DELETE +# define VK_DELETE UNDEFINED_VK +#endif +#ifndef VK_HELP +# define VK_HELP UNDEFINED_VK +#endif +#ifndef VK_LWIN +# define VK_LWIN UNDEFINED_VK +#endif +#ifndef VK_RWIN +# define VK_RWIN UNDEFINED_VK +#endif +#ifndef VK_APPS +# define VK_APPS UNDEFINED_VK +#endif +#ifndef VK_SLEEP +# define VK_SLEEP UNDEFINED_VK +#endif +#ifndef VK_NUMPAD0 +# define VK_NUMPAD0 UNDEFINED_VK +#endif +#ifndef VK_NUMPAD1 +# define VK_NUMPAD1 UNDEFINED_VK +#endif +#ifndef VK_NUMPAD2 +# define VK_NUMPAD2 UNDEFINED_VK +#endif +#ifndef VK_NUMPAD3 +# define VK_NUMPAD3 UNDEFINED_VK +#endif +#ifndef VK_NUMPAD4 +# define VK_NUMPAD4 UNDEFINED_VK +#endif +#ifndef VK_NUMPAD5 +# define VK_NUMPAD5 UNDEFINED_VK +#endif +#ifndef VK_NUMPAD6 +# define VK_NUMPAD6 UNDEFINED_VK +#endif +#ifndef VK_NUMPAD7 +# define VK_NUMPAD7 UNDEFINED_VK +#endif +#ifndef VK_NUMPAD8 +# define VK_NUMPAD8 UNDEFINED_VK +#endif +#ifndef VK_NUMPAD9 +# define VK_NUMPAD9 UNDEFINED_VK +#endif +#ifndef VK_MULTIPLY +# define VK_MULTIPLY UNDEFINED_VK +#endif +#ifndef VK_ADD +# define VK_ADD UNDEFINED_VK +#endif +#ifndef VK_SEPARATOR +# define VK_SEPARATOR UNDEFINED_VK +#endif +#ifndef VK_SUBTRACT +# define VK_SUBTRACT UNDEFINED_VK +#endif +#ifndef VK_DECIMAL +# define VK_DECIMAL UNDEFINED_VK +#endif +#ifndef VK_DIVIDE +# define VK_DIVIDE UNDEFINED_VK +#endif +#ifndef VK_F1 +# define VK_F1 UNDEFINED_VK +#endif +#ifndef VK_F2 +# define VK_F2 UNDEFINED_VK +#endif +#ifndef VK_F3 +# define VK_F3 UNDEFINED_VK +#endif +#ifndef VK_F4 +# define VK_F4 UNDEFINED_VK +#endif +#ifndef VK_F5 +# define VK_F5 UNDEFINED_VK +#endif +#ifndef VK_F6 +# define VK_F6 UNDEFINED_VK +#endif +#ifndef VK_F7 +# define VK_F7 UNDEFINED_VK +#endif +#ifndef VK_F8 +# define VK_F8 UNDEFINED_VK +#endif +#ifndef VK_F9 +# define VK_F9 UNDEFINED_VK +#endif +#ifndef VK_F10 +# define VK_F10 UNDEFINED_VK +#endif +#ifndef VK_F11 +# define VK_F11 UNDEFINED_VK +#endif +#ifndef VK_F12 +# define VK_F12 UNDEFINED_VK +#endif +#ifndef VK_F13 +# define VK_F13 UNDEFINED_VK +#endif +#ifndef VK_F14 +# define VK_F14 UNDEFINED_VK +#endif +#ifndef VK_F15 +# define VK_F15 UNDEFINED_VK +#endif +#ifndef VK_F16 +# define VK_F16 UNDEFINED_VK +#endif +#ifndef VK_F17 +# define VK_F17 UNDEFINED_VK +#endif +#ifndef VK_F18 +# define VK_F18 UNDEFINED_VK +#endif +#ifndef VK_F19 +# define VK_F19 UNDEFINED_VK +#endif +#ifndef VK_F20 +# define VK_F20 UNDEFINED_VK +#endif +#ifndef VK_F21 +# define VK_F21 UNDEFINED_VK +#endif +#ifndef VK_F22 +# define VK_F22 UNDEFINED_VK +#endif +#ifndef VK_F23 +# define VK_F23 UNDEFINED_VK +#endif +#ifndef VK_F24 +# define VK_F24 UNDEFINED_VK +#endif +#ifndef VK_NUMLOCK +# define VK_NUMLOCK UNDEFINED_VK +#endif +#ifndef VK_SCROLL +# define VK_SCROLL UNDEFINED_VK +#endif +#ifndef VK_OEM_NEC_EQUAL +# define VK_OEM_NEC_EQUAL UNDEFINED_VK +#endif +#ifndef VK_OEM_FJ_JISHO +# define VK_OEM_FJ_JISHO UNDEFINED_VK +#endif +#ifndef VK_OEM_FJ_MASSHOU +# define VK_OEM_FJ_MASSHOU UNDEFINED_VK +#endif +#ifndef VK_OEM_FJ_TOUROKU +# define VK_OEM_FJ_TOUROKU UNDEFINED_VK +#endif +#ifndef VK_OEM_FJ_LOYA +# define VK_OEM_FJ_LOYA UNDEFINED_VK +#endif +#ifndef VK_OEM_FJ_ROYA +# define VK_OEM_FJ_ROYA UNDEFINED_VK +#endif +#ifndef VK_LSHIFT +# define VK_LSHIFT UNDEFINED_VK +#endif +#ifndef VK_RSHIFT +# define VK_RSHIFT UNDEFINED_VK +#endif +#ifndef VK_LCONTROL +# define VK_LCONTROL UNDEFINED_VK +#endif +#ifndef VK_RCONTROL +# define VK_RCONTROL UNDEFINED_VK +#endif +#ifndef VK_LMENU +# define VK_LMENU UNDEFINED_VK +#endif +#ifndef VK_RMENU +# define VK_RMENU UNDEFINED_VK +#endif +#ifndef VK_BROWSER_BACK +# define VK_BROWSER_BACK UNDEFINED_VK +#endif +#ifndef VK_BROWSER_FORWARD +# define VK_BROWSER_FORWARD UNDEFINED_VK +#endif +#ifndef VK_BROWSER_REFRESH +# define VK_BROWSER_REFRESH UNDEFINED_VK +#endif +#ifndef VK_BROWSER_STOP +# define VK_BROWSER_STOP UNDEFINED_VK +#endif +#ifndef VK_BROWSER_SEARCH +# define VK_BROWSER_SEARCH UNDEFINED_VK +#endif +#ifndef VK_BROWSER_FAVORITES +# define VK_BROWSER_FAVORITES UNDEFINED_VK +#endif +#ifndef VK_BROWSER_HOME +# define VK_BROWSER_HOME UNDEFINED_VK +#endif +#ifndef VK_VOLUME_MUTE +# define VK_VOLUME_MUTE UNDEFINED_VK +#endif +#ifndef VK_VOLUME_DOWN +# define VK_VOLUME_DOWN UNDEFINED_VK +#endif +#ifndef VK_VOLUME_UP +# define VK_VOLUME_UP UNDEFINED_VK +#endif +#ifndef VK_MEDIA_NEXT_TRACK +# define VK_MEDIA_NEXT_TRACK UNDEFINED_VK +#endif +#ifndef VK_MEDIA_PREV_TRACK +# define VK_MEDIA_PREV_TRACK UNDEFINED_VK +#endif +#ifndef VK_MEDIA_STOP +# define VK_MEDIA_STOP UNDEFINED_VK +#endif +#ifndef VK_MEDIA_PLAY_PAUSE +# define VK_MEDIA_PLAY_PAUSE UNDEFINED_VK +#endif +#ifndef VK_LAUNCH_MAIL +# define VK_LAUNCH_MAIL UNDEFINED_VK +#endif +#ifndef VK_LAUNCH_MEDIA_SELECT +# define VK_LAUNCH_MEDIA_SELECT UNDEFINED_VK +#endif +#ifndef VK_LAUNCH_APP1 +# define VK_LAUNCH_APP1 UNDEFINED_VK +#endif +#ifndef VK_LAUNCH_APP2 +# define VK_LAUNCH_APP2 UNDEFINED_VK +#endif +#ifndef VK_OEM_1 +# define VK_OEM_1 UNDEFINED_VK +#endif +#ifndef VK_OEM_PLUS +# define VK_OEM_PLUS UNDEFINED_VK +#endif +#ifndef VK_OEM_COMMA +# define VK_OEM_COMMA UNDEFINED_VK +#endif +#ifndef VK_OEM_MINUS +# define VK_OEM_MINUS UNDEFINED_VK +#endif +#ifndef VK_OEM_PERIOD +# define VK_OEM_PERIOD UNDEFINED_VK +#endif +#ifndef VK_OEM_2 +# define VK_OEM_2 UNDEFINED_VK +#endif +#ifndef VK_OEM_3 +# define VK_OEM_3 UNDEFINED_VK +#endif +#ifndef VK_OEM_4 +# define VK_OEM_4 UNDEFINED_VK +#endif +#ifndef VK_OEM_5 +# define VK_OEM_5 UNDEFINED_VK +#endif +#ifndef VK_OEM_6 +# define VK_OEM_6 UNDEFINED_VK +#endif +#ifndef VK_OEM_7 +# define VK_OEM_7 UNDEFINED_VK +#endif +#ifndef VK_OEM_8 +# define VK_OEM_8 UNDEFINED_VK +#endif +#ifndef VK_OEM_AX +# define VK_OEM_AX UNDEFINED_VK +#endif +#ifndef VK_OEM_102 +# define VK_OEM_102 UNDEFINED_VK +#endif +#ifndef VK_ICO_HELP +# define VK_ICO_HELP UNDEFINED_VK +#endif +#ifndef VK_ICO_00 +# define VK_ICO_00 UNDEFINED_VK +#endif +#ifndef VK_PROCESSKEY +# define VK_PROCESSKEY UNDEFINED_VK +#endif +#ifndef VK_ICO_CLEAR +# define VK_ICO_CLEAR UNDEFINED_VK +#endif +#ifndef VK_PACKET +# define VK_PACKET UNDEFINED_VK +#endif +#ifndef VK_OEM_RESET +# define VK_OEM_RESET UNDEFINED_VK +#endif +#ifndef VK_OEM_JUMP +# define VK_OEM_JUMP UNDEFINED_VK +#endif +#ifndef VK_OEM_PA1 +# define VK_OEM_PA1 UNDEFINED_VK +#endif +#ifndef VK_OEM_PA2 +# define VK_OEM_PA2 UNDEFINED_VK +#endif +#ifndef VK_OEM_PA3 +# define VK_OEM_PA3 UNDEFINED_VK +#endif +#ifndef VK_OEM_WSCTRL +# define VK_OEM_WSCTRL UNDEFINED_VK +#endif +#ifndef VK_OEM_CUSEL +# define VK_OEM_CUSEL UNDEFINED_VK +#endif +#ifndef VK_OEM_ATTN +# define VK_OEM_ATTN UNDEFINED_VK +#endif +#ifndef VK_OEM_FINISH +# define VK_OEM_FINISH UNDEFINED_VK +#endif +#ifndef VK_OEM_COPY +# define VK_OEM_COPY UNDEFINED_VK +#endif +#ifndef VK_OEM_AUTO +# define VK_OEM_AUTO UNDEFINED_VK +#endif +#ifndef VK_OEM_ENLW +# define VK_OEM_ENLW UNDEFINED_VK +#endif +#ifndef VK_OEM_BACKTAB +# define VK_OEM_BACKTAB UNDEFINED_VK +#endif +#ifndef VK_ATTN +# define VK_ATTN UNDEFINED_VK +#endif +#ifndef VK_CRSEL +# define VK_CRSEL UNDEFINED_VK +#endif +#ifndef VK_EXSEL +# define VK_EXSEL UNDEFINED_VK +#endif +#ifndef VK_EREOF +# define VK_EREOF UNDEFINED_VK +#endif +#ifndef VK_PLAY +# define VK_PLAY UNDEFINED_VK +#endif +#ifndef VK_ZOOM +# define VK_ZOOM UNDEFINED_VK +#endif +#ifndef VK_NONAME +# define VK_NONAME UNDEFINED_VK +#endif +#ifndef VK_PA1 +# define VK_PA1 UNDEFINED_VK +#endif +#ifndef VK_OEM_CLEAR +# define VK_OEM_CLEAR UNDEFINED_VK +#endif +/* ANSI-C code produced by gperf version 3.1 */ +/* Command-line: gperf --ignore-case -L ANSI-C -E -C -P -p -j1 -i 1 -g -o -t -K ofs -N console_win32_vk -k'*' win32_vk.list */ + +#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ + && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ + && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ + && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ + && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ + && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ + && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ + && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ + && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ + && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ + && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ + && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ + && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ + && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ + && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ + && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ + && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ + && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ + && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ + && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ + && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ + && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ + && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) +/* The character set is not based on ISO-646. */ +#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>." +#endif + +#line 1 "win32_vk.list" + +struct vktable {short ofs; unsigned short vk;}; +static const struct vktable *console_win32_vk(const char *, size_t); +#line 5 "win32_vk.list" +struct vktable; +/* maximum key range = 245, duplicates = 0 */ + +#ifndef GPERF_DOWNCASE +#define GPERF_DOWNCASE 1 +static unsigned char gperf_downcase[256] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, + 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, + 255 + }; +#endif + +#ifndef GPERF_CASE_STRCMP +#define GPERF_CASE_STRCMP 1 +static int +gperf_case_strcmp (register const char *s1, register const char *s2) +{ + for (;;) + { + unsigned char c1 = gperf_downcase[(unsigned char)*s1++]; + unsigned char c2 = gperf_downcase[(unsigned char)*s2++]; + if (c1 != 0 && c1 == c2) + continue; + return (int)c1 - (int)c2; + } +} +#endif + +#ifdef __GNUC__ +__inline +#else +#ifdef __cplusplus +inline +#endif +#endif +static unsigned int +hash (register const char *str, register size_t len) +{ + static const unsigned short asso_values[] = + { + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 51, 74, + 80, 116, 127, 124, 95, 140, 77, 53, 7, 3, + 257, 257, 257, 257, 257, 1, 11, 1, 55, 1, + 25, 84, 31, 33, 13, 16, 2, 28, 8, 1, + 6, 10, 1, 1, 3, 4, 45, 18, 73, 79, + 30, 257, 257, 257, 257, 5, 257, 1, 11, 1, + 55, 1, 25, 84, 31, 33, 13, 16, 2, 28, + 8, 1, 6, 10, 1, 1, 3, 4, 45, 18, + 73, 79, 30, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257 + }; + register unsigned int hval = (unsigned int)len; + + switch (hval) + { + default: + hval += asso_values[(unsigned char)str[18]]; + /*FALLTHROUGH*/ + case 18: + hval += asso_values[(unsigned char)str[17]]; + /*FALLTHROUGH*/ + case 17: + hval += asso_values[(unsigned char)str[16]]; + /*FALLTHROUGH*/ + case 16: + hval += asso_values[(unsigned char)str[15]]; + /*FALLTHROUGH*/ + case 15: + hval += asso_values[(unsigned char)str[14]]; + /*FALLTHROUGH*/ + case 14: + hval += asso_values[(unsigned char)str[13]]; + /*FALLTHROUGH*/ + case 13: + hval += asso_values[(unsigned char)str[12]]; + /*FALLTHROUGH*/ + case 12: + hval += asso_values[(unsigned char)str[11]]; + /*FALLTHROUGH*/ + case 11: + hval += asso_values[(unsigned char)str[10]]; + /*FALLTHROUGH*/ + case 10: + hval += asso_values[(unsigned char)str[9]]; + /*FALLTHROUGH*/ + case 9: + hval += asso_values[(unsigned char)str[8]]; + /*FALLTHROUGH*/ + case 8: + hval += asso_values[(unsigned char)str[7]]; + /*FALLTHROUGH*/ + case 7: + hval += asso_values[(unsigned char)str[6]]; + /*FALLTHROUGH*/ + case 6: + hval += asso_values[(unsigned char)str[5]]; + /*FALLTHROUGH*/ + case 5: + hval += asso_values[(unsigned char)str[4]]; + /*FALLTHROUGH*/ + case 4: + hval += asso_values[(unsigned char)str[3]]; + /*FALLTHROUGH*/ + case 3: + hval += asso_values[(unsigned char)str[2]+2]; + /*FALLTHROUGH*/ + case 2: + hval += asso_values[(unsigned char)str[1]]; + /*FALLTHROUGH*/ + case 1: + hval += asso_values[(unsigned char)str[0]]; + break; + } + return (unsigned int)hval; +} + +struct stringpool_t + { + char stringpool_str12[sizeof("UP")]; + char stringpool_str13[sizeof("APPS")]; + char stringpool_str14[sizeof("CRSEL")]; + char stringpool_str15[sizeof("SPACE")]; + char stringpool_str16[sizeof("SCROLL")]; + char stringpool_str17[sizeof("ESCAPE")]; + char stringpool_str18[sizeof("CANCEL")]; + char stringpool_str19[sizeof("ACCEPT")]; + char stringpool_str20[sizeof("SEPARATOR")]; + char stringpool_str21[sizeof("SELECT")]; + char stringpool_str22[sizeof("CONTROL")]; + char stringpool_str23[sizeof("OEM_CLEAR")]; + char stringpool_str24[sizeof("OEM_RESET")]; + char stringpool_str25[sizeof("OEM_AUTO")]; + char stringpool_str26[sizeof("OEM_CUSEL")]; + char stringpool_str28[sizeof("KANA")]; + char stringpool_str29[sizeof("OEM_PLUS")]; + char stringpool_str30[sizeof("PRIOR")]; + char stringpool_str31[sizeof("OEM_ATTN")]; + char stringpool_str32[sizeof("PAUSE")]; + char stringpool_str33[sizeof("BACK")]; + char stringpool_str34[sizeof("PACKET")]; + char stringpool_str35[sizeof("RCONTROL")]; + char stringpool_str36[sizeof("LCONTROL")]; + char stringpool_str37[sizeof("END")]; + char stringpool_str38[sizeof("HOME")]; + char stringpool_str39[sizeof("PRINT")]; + char stringpool_str40[sizeof("NUMLOCK")]; + char stringpool_str41[sizeof("LEFT")]; + char stringpool_str42[sizeof("JUNJA")]; + char stringpool_str43[sizeof("MENU")]; + char stringpool_str44[sizeof("OEM_WSCTRL")]; + char stringpool_str45[sizeof("OEM_ENLW")]; + char stringpool_str46[sizeof("NEXT")]; + char stringpool_str47[sizeof("RWIN")]; + char stringpool_str48[sizeof("LWIN")]; + char stringpool_str49[sizeof("CAPITAL")]; + char stringpool_str50[sizeof("HELP")]; + char stringpool_str51[sizeof("NONAME")]; + char stringpool_str52[sizeof("RBUTTON")]; + char stringpool_str53[sizeof("LBUTTON")]; + char stringpool_str54[sizeof("OEM_NEC_EQUAL")]; + char stringpool_str56[sizeof("INSERT")]; + char stringpool_str57[sizeof("HANJA")]; + char stringpool_str60[sizeof("SNAPSHOT")]; + char stringpool_str61[sizeof("ATTN")]; + char stringpool_str62[sizeof("TAB")]; + char stringpool_str63[sizeof("OEM_BACKTAB")]; + char stringpool_str64[sizeof("ICO_CLEAR")]; + char stringpool_str65[sizeof("CONVERT")]; + char stringpool_str66[sizeof("RETURN")]; + char stringpool_str67[sizeof("OEM_JUMP")]; + char stringpool_str71[sizeof("BROWSER_STOP")]; + char stringpool_str72[sizeof("FINAL")]; + char stringpool_str73[sizeof("ZOOM")]; + char stringpool_str74[sizeof("KANJI")]; + char stringpool_str75[sizeof("DELETE")]; + char stringpool_str76[sizeof("OEM_COMMA")]; + char stringpool_str77[sizeof("SUBTRACT")]; + char stringpool_str79[sizeof("MBUTTON")]; + char stringpool_str80[sizeof("F9")]; + char stringpool_str81[sizeof("SHIFT")]; + char stringpool_str82[sizeof("RSHIFT")]; + char stringpool_str83[sizeof("LSHIFT")]; + char stringpool_str84[sizeof("ADD")]; + char stringpool_str85[sizeof("NONCONVERT")]; + char stringpool_str86[sizeof("EXSEL")]; + char stringpool_str87[sizeof("OEM_1")]; + char stringpool_str88[sizeof("OEM_AX")]; + char stringpool_str89[sizeof("BROWSER_BACK")]; + char stringpool_str90[sizeof("OEM_8")]; + char stringpool_str91[sizeof("OEM_MINUS")]; + char stringpool_str92[sizeof("PLAY")]; + char stringpool_str93[sizeof("OEM_2")]; + char stringpool_str94[sizeof("CLEAR")]; + char stringpool_str95[sizeof("OEM_FJ_TOUROKU")]; + char stringpool_str96[sizeof("OEM_PA1")]; + char stringpool_str97[sizeof("ICO_HELP")]; + char stringpool_str98[sizeof("BROWSER_SEARCH")]; + char stringpool_str99[sizeof("SLEEP")]; + char stringpool_str101[sizeof("F1")]; + char stringpool_str102[sizeof("OEM_PA2")]; + char stringpool_str103[sizeof("OEM_COPY")]; + char stringpool_str104[sizeof("F8")]; + char stringpool_str105[sizeof("F19")]; + char stringpool_str106[sizeof("RIGHT")]; + char stringpool_str107[sizeof("F2")]; + char stringpool_str108[sizeof("OEM_6")]; + char stringpool_str109[sizeof("F18")]; + char stringpool_str111[sizeof("VOLUME_UP")]; + char stringpool_str114[sizeof("MEDIA_STOP")]; + char stringpool_str115[sizeof("OEM_PERIOD")]; + char stringpool_str117[sizeof("EREOF")]; + char stringpool_str121[sizeof("BROWSER_HOME")]; + char stringpool_str122[sizeof("F6")]; + char stringpool_str124[sizeof("BROWSER_REFRESH")]; + char stringpool_str126[sizeof("PA1")]; + char stringpool_str127[sizeof("PROCESSKEY")]; + char stringpool_str128[sizeof("DECIMAL")]; + char stringpool_str129[sizeof("OEM_3")]; + char stringpool_str130[sizeof("RMENU")]; + char stringpool_str131[sizeof("LMENU")]; + char stringpool_str132[sizeof("OEM_FJ_MASSHOU")]; + char stringpool_str133[sizeof("NUMPAD0")]; + char stringpool_str134[sizeof("HANGUL")]; + char stringpool_str135[sizeof("NUMPAD9")]; + char stringpool_str136[sizeof("HANGEUL")]; + char stringpool_str137[sizeof("OEM_5")]; + char stringpool_str138[sizeof("OEM_PA3")]; + char stringpool_str139[sizeof("VOLUME_MUTE")]; + char stringpool_str140[sizeof("OEM_4")]; + char stringpool_str141[sizeof("LAUNCH_MAIL")]; + char stringpool_str142[sizeof("OEM_FJ_JISHO")]; + char stringpool_str143[sizeof("F3")]; + char stringpool_str144[sizeof("OEM_FJ_ROYA")]; + char stringpool_str145[sizeof("OEM_FJ_LOYA")]; + char stringpool_str147[sizeof("DOWN")]; + char stringpool_str149[sizeof("OEM_FINISH")]; + char stringpool_str151[sizeof("F5")]; + char stringpool_str153[sizeof("OEM_7")]; + char stringpool_str154[sizeof("F4")]; + char stringpool_str155[sizeof("F17")]; + char stringpool_str156[sizeof("NUMPAD1")]; + char stringpool_str157[sizeof("ICO_00")]; + char stringpool_str159[sizeof("NUMPAD8")]; + char stringpool_str162[sizeof("NUMPAD2")]; + char stringpool_str164[sizeof("LAUNCH_APP1")]; + char stringpool_str165[sizeof("BROWSER_FORWARD")]; + char stringpool_str167[sizeof("F7")]; + char stringpool_str170[sizeof("LAUNCH_APP2")]; + char stringpool_str171[sizeof("MULTIPLY")]; + char stringpool_str174[sizeof("EXECUTE")]; + char stringpool_str176[sizeof("BROWSER_FAVORITES")]; + char stringpool_str177[sizeof("NUMPAD6")]; + char stringpool_str179[sizeof("F16")]; + char stringpool_str182[sizeof("F10")]; + char stringpool_str185[sizeof("VOLUME_DOWN")]; + char stringpool_str188[sizeof("F20")]; + char stringpool_str189[sizeof("MEDIA_PREV_TRACK")]; + char stringpool_str191[sizeof("MODECHANGE")]; + char stringpool_str197[sizeof("F14")]; + char stringpool_str198[sizeof("NUMPAD3")]; + char stringpool_str199[sizeof("XBUTTON1")]; + char stringpool_str203[sizeof("F24")]; + char stringpool_str205[sizeof("XBUTTON2")]; + char stringpool_str206[sizeof("NUMPAD5")]; + char stringpool_str209[sizeof("NUMPAD4")]; + char stringpool_str215[sizeof("MEDIA_PLAY_PAUSE")]; + char stringpool_str217[sizeof("LAUNCH_MEDIA_SELECT")]; + char stringpool_str218[sizeof("F11")]; + char stringpool_str220[sizeof("OEM_102")]; + char stringpool_str221[sizeof("MEDIA_NEXT_TRACK")]; + char stringpool_str222[sizeof("NUMPAD7")]; + char stringpool_str224[sizeof("F21")]; + char stringpool_str226[sizeof("F13")]; + char stringpool_str229[sizeof("F12")]; + char stringpool_str232[sizeof("F23")]; + char stringpool_str235[sizeof("F22")]; + char stringpool_str242[sizeof("F15")]; + char stringpool_str256[sizeof("DIVIDE")]; + }; +static const struct stringpool_t stringpool_contents = + { + "UP", + "APPS", + "CRSEL", + "SPACE", + "SCROLL", + "ESCAPE", + "CANCEL", + "ACCEPT", + "SEPARATOR", + "SELECT", + "CONTROL", + "OEM_CLEAR", + "OEM_RESET", + "OEM_AUTO", + "OEM_CUSEL", + "KANA", + "OEM_PLUS", + "PRIOR", + "OEM_ATTN", + "PAUSE", + "BACK", + "PACKET", + "RCONTROL", + "LCONTROL", + "END", + "HOME", + "PRINT", + "NUMLOCK", + "LEFT", + "JUNJA", + "MENU", + "OEM_WSCTRL", + "OEM_ENLW", + "NEXT", + "RWIN", + "LWIN", + "CAPITAL", + "HELP", + "NONAME", + "RBUTTON", + "LBUTTON", + "OEM_NEC_EQUAL", + "INSERT", + "HANJA", + "SNAPSHOT", + "ATTN", + "TAB", + "OEM_BACKTAB", + "ICO_CLEAR", + "CONVERT", + "RETURN", + "OEM_JUMP", + "BROWSER_STOP", + "FINAL", + "ZOOM", + "KANJI", + "DELETE", + "OEM_COMMA", + "SUBTRACT", + "MBUTTON", + "F9", + "SHIFT", + "RSHIFT", + "LSHIFT", + "ADD", + "NONCONVERT", + "EXSEL", + "OEM_1", + "OEM_AX", + "BROWSER_BACK", + "OEM_8", + "OEM_MINUS", + "PLAY", + "OEM_2", + "CLEAR", + "OEM_FJ_TOUROKU", + "OEM_PA1", + "ICO_HELP", + "BROWSER_SEARCH", + "SLEEP", + "F1", + "OEM_PA2", + "OEM_COPY", + "F8", + "F19", + "RIGHT", + "F2", + "OEM_6", + "F18", + "VOLUME_UP", + "MEDIA_STOP", + "OEM_PERIOD", + "EREOF", + "BROWSER_HOME", + "F6", + "BROWSER_REFRESH", + "PA1", + "PROCESSKEY", + "DECIMAL", + "OEM_3", + "RMENU", + "LMENU", + "OEM_FJ_MASSHOU", + "NUMPAD0", + "HANGUL", + "NUMPAD9", + "HANGEUL", + "OEM_5", + "OEM_PA3", + "VOLUME_MUTE", + "OEM_4", + "LAUNCH_MAIL", + "OEM_FJ_JISHO", + "F3", + "OEM_FJ_ROYA", + "OEM_FJ_LOYA", + "DOWN", + "OEM_FINISH", + "F5", + "OEM_7", + "F4", + "F17", + "NUMPAD1", + "ICO_00", + "NUMPAD8", + "NUMPAD2", + "LAUNCH_APP1", + "BROWSER_FORWARD", + "F7", + "LAUNCH_APP2", + "MULTIPLY", + "EXECUTE", + "BROWSER_FAVORITES", + "NUMPAD6", + "F16", + "F10", + "VOLUME_DOWN", + "F20", + "MEDIA_PREV_TRACK", + "MODECHANGE", + "F14", + "NUMPAD3", + "XBUTTON1", + "F24", + "XBUTTON2", + "NUMPAD5", + "NUMPAD4", + "MEDIA_PLAY_PAUSE", + "LAUNCH_MEDIA_SELECT", + "F11", + "OEM_102", + "MEDIA_NEXT_TRACK", + "NUMPAD7", + "F21", + "F13", + "F12", + "F23", + "F22", + "F15", + "DIVIDE" + }; +#define stringpool ((const char *) &stringpool_contents) +const struct vktable * +console_win32_vk (register const char *str, register size_t len) +{ + enum + { + TOTAL_KEYWORDS = 160, + MIN_WORD_LENGTH = 2, + MAX_WORD_LENGTH = 19, + MIN_HASH_VALUE = 12, + MAX_HASH_VALUE = 256 + }; + + static const struct vktable wordlist[] = + { + {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, + {-1}, {-1}, {-1}, +#line 40 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str12, VK_UP}, +#line 52 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str13, VK_APPS}, +#line 159 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str14, VK_CRSEL}, +#line 34 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str15, VK_SPACE}, +#line 95 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str16, VK_SCROLL}, +#line 29 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str17, VK_ESCAPE}, +#line 9 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str18, VK_CANCEL}, +#line 32 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str19, VK_ACCEPT}, +#line 66 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str20, VK_SEPARATOR}, +#line 43 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str21, VK_SELECT}, +#line 18 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str22, VK_CONTROL}, +#line 166 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str23, VK_OEM_CLEAR}, +#line 145 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str24, VK_OEM_RESET}, +#line 155 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str25, VK_OEM_AUTO}, +#line 151 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str26, VK_OEM_CUSEL}, + {-1}, +#line 22 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str28, VK_KANA}, +#line 127 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str29, VK_OEM_PLUS}, +#line 35 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str30, VK_PRIOR}, +#line 152 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str31, VK_OEM_ATTN}, +#line 20 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str32, VK_PAUSE}, +#line 13 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str33, VK_BACK}, +#line 144 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str34, VK_PACKET}, +#line 105 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str35, VK_RCONTROL}, +#line 104 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str36, VK_LCONTROL}, +#line 37 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str37, VK_END}, +#line 38 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str38, VK_HOME}, +#line 44 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str39, VK_PRINT}, +#line 94 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str40, VK_NUMLOCK}, +#line 39 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str41, VK_LEFT}, +#line 25 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str42, VK_JUNJA}, +#line 19 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str43, VK_MENU}, +#line 150 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str44, VK_OEM_WSCTRL}, +#line 156 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str45, VK_OEM_ENLW}, +#line 36 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str46, VK_NEXT}, +#line 51 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str47, VK_RWIN}, +#line 50 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str48, VK_LWIN}, +#line 21 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str49, VK_CAPITAL}, +#line 49 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str50, VK_HELP}, +#line 164 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str51, VK_NONAME}, +#line 8 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str52, VK_RBUTTON}, +#line 7 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str53, VK_LBUTTON}, +#line 96 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str54, VK_OEM_NEC_EQUAL}, + {-1}, +#line 47 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str56, VK_INSERT}, +#line 27 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str57, VK_HANJA}, + {-1}, {-1}, +#line 46 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str60, VK_SNAPSHOT}, +#line 158 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str61, VK_ATTN}, +#line 14 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str62, VK_TAB}, +#line 157 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str63, VK_OEM_BACKTAB}, +#line 143 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str64, VK_ICO_CLEAR}, +#line 30 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str65, VK_CONVERT}, +#line 16 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str66, VK_RETURN}, +#line 146 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str67, VK_OEM_JUMP}, + {-1}, {-1}, {-1}, +#line 111 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str71, VK_BROWSER_STOP}, +#line 26 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str72, VK_FINAL}, +#line 163 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str73, VK_ZOOM}, +#line 28 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str74, VK_KANJI}, +#line 48 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str75, VK_DELETE}, +#line 128 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str76, VK_OEM_COMMA}, +#line 67 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str77, VK_SUBTRACT}, + {-1}, +#line 10 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str79, VK_MBUTTON}, +#line 78 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str80, VK_F9}, +#line 17 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str81, VK_SHIFT}, +#line 103 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str82, VK_RSHIFT}, +#line 102 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str83, VK_LSHIFT}, +#line 65 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str84, VK_ADD}, +#line 31 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str85, VK_NONCONVERT}, +#line 160 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str86, VK_EXSEL}, +#line 126 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str87, VK_OEM_1}, +#line 138 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str88, VK_OEM_AX}, +#line 108 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str89, VK_BROWSER_BACK}, +#line 137 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str90, VK_OEM_8}, +#line 129 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str91, VK_OEM_MINUS}, +#line 162 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str92, VK_PLAY}, +#line 131 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str93, VK_OEM_2}, +#line 15 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str94, VK_CLEAR}, +#line 99 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str95, VK_OEM_FJ_TOUROKU}, +#line 147 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str96, VK_OEM_PA1}, +#line 140 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str97, VK_ICO_HELP}, +#line 112 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str98, VK_BROWSER_SEARCH}, +#line 53 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str99, VK_SLEEP}, + {-1}, +#line 70 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str101, VK_F1}, +#line 148 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str102, VK_OEM_PA2}, +#line 154 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str103, VK_OEM_COPY}, +#line 77 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str104, VK_F8}, +#line 88 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str105, VK_F19}, +#line 41 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str106, VK_RIGHT}, +#line 71 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str107, VK_F2}, +#line 135 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str108, VK_OEM_6}, +#line 87 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str109, VK_F18}, + {-1}, +#line 117 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str111, VK_VOLUME_UP}, + {-1}, {-1}, +#line 120 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str114, VK_MEDIA_STOP}, +#line 130 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str115, VK_OEM_PERIOD}, + {-1}, +#line 161 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str117, VK_EREOF}, + {-1}, {-1}, {-1}, +#line 114 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str121, VK_BROWSER_HOME}, +#line 75 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str122, VK_F6}, + {-1}, +#line 110 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str124, VK_BROWSER_REFRESH}, + {-1}, +#line 165 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str126, VK_PA1}, +#line 142 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str127, VK_PROCESSKEY}, +#line 68 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str128, VK_DECIMAL}, +#line 132 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str129, VK_OEM_3}, +#line 107 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str130, VK_RMENU}, +#line 106 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str131, VK_LMENU}, +#line 98 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str132, VK_OEM_FJ_MASSHOU}, +#line 54 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str133, VK_NUMPAD0}, +#line 24 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str134, VK_HANGUL}, +#line 63 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str135, VK_NUMPAD9}, +#line 23 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str136, VK_HANGEUL}, +#line 134 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str137, VK_OEM_5}, +#line 149 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str138, VK_OEM_PA3}, +#line 115 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str139, VK_VOLUME_MUTE}, +#line 133 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str140, VK_OEM_4}, +#line 122 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str141, VK_LAUNCH_MAIL}, +#line 97 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str142, VK_OEM_FJ_JISHO}, +#line 72 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str143, VK_F3}, +#line 101 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str144, VK_OEM_FJ_ROYA}, +#line 100 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str145, VK_OEM_FJ_LOYA}, + {-1}, +#line 42 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str147, VK_DOWN}, + {-1}, +#line 153 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str149, VK_OEM_FINISH}, + {-1}, +#line 74 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str151, VK_F5}, + {-1}, +#line 136 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str153, VK_OEM_7}, +#line 73 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str154, VK_F4}, +#line 86 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str155, VK_F17}, +#line 55 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str156, VK_NUMPAD1}, +#line 141 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str157, VK_ICO_00}, + {-1}, +#line 62 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str159, VK_NUMPAD8}, + {-1}, {-1}, +#line 56 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str162, VK_NUMPAD2}, + {-1}, +#line 124 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str164, VK_LAUNCH_APP1}, +#line 109 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str165, VK_BROWSER_FORWARD}, + {-1}, +#line 76 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str167, VK_F7}, + {-1}, {-1}, +#line 125 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str170, VK_LAUNCH_APP2}, +#line 64 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str171, VK_MULTIPLY}, + {-1}, {-1}, +#line 45 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str174, VK_EXECUTE}, + {-1}, +#line 113 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str176, VK_BROWSER_FAVORITES}, +#line 60 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str177, VK_NUMPAD6}, + {-1}, +#line 85 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str179, VK_F16}, + {-1}, {-1}, +#line 79 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str182, VK_F10}, + {-1}, {-1}, +#line 116 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str185, VK_VOLUME_DOWN}, + {-1}, {-1}, +#line 89 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str188, VK_F20}, +#line 119 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str189, VK_MEDIA_PREV_TRACK}, + {-1}, +#line 33 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str191, VK_MODECHANGE}, + {-1}, {-1}, {-1}, {-1}, {-1}, +#line 83 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str197, VK_F14}, +#line 57 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str198, VK_NUMPAD3}, +#line 11 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str199, VK_XBUTTON1}, + {-1}, {-1}, {-1}, +#line 93 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str203, VK_F24}, + {-1}, +#line 12 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str205, VK_XBUTTON2}, +#line 59 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str206, VK_NUMPAD5}, + {-1}, {-1}, +#line 58 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str209, VK_NUMPAD4}, + {-1}, {-1}, {-1}, {-1}, {-1}, +#line 121 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str215, VK_MEDIA_PLAY_PAUSE}, + {-1}, +#line 123 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str217, VK_LAUNCH_MEDIA_SELECT}, +#line 80 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str218, VK_F11}, + {-1}, +#line 139 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str220, VK_OEM_102}, +#line 118 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str221, VK_MEDIA_NEXT_TRACK}, +#line 61 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str222, VK_NUMPAD7}, + {-1}, +#line 90 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str224, VK_F21}, + {-1}, +#line 82 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str226, VK_F13}, + {-1}, {-1}, +#line 81 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str229, VK_F12}, + {-1}, {-1}, +#line 92 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str232, VK_F23}, + {-1}, {-1}, +#line 91 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str235, VK_F22}, + {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, +#line 84 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str242, VK_F15}, + {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, + {-1}, {-1}, {-1}, {-1}, +#line 69 "win32_vk.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str256, VK_DIVIDE} + }; + + if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) + { + register unsigned int key = hash (str, len); + + if (key <= MAX_HASH_VALUE) + { + register int o = wordlist[key].ofs; + if (o >= 0) + { + register const char *s = o + stringpool; + + if ((((unsigned char)*str ^ (unsigned char)*s) & ~32) == 0 && !gperf_case_strcmp (str, s)) + return &wordlist[key]; + } + } + } + return 0; +} diff --git a/ext/io/console/win32_vk.list b/ext/io/console/win32_vk.list new file mode 100644 index 0000000000..5df3d6da57 --- /dev/null +++ b/ext/io/console/win32_vk.list @@ -0,0 +1,166 @@ +%{ +struct vktable {short ofs; unsigned short vk;}; +static const struct vktable *console_win32_vk(const char *, size_t); +%} +struct vktable +%% +LBUTTON, VK_LBUTTON +RBUTTON, VK_RBUTTON +CANCEL, VK_CANCEL +MBUTTON, VK_MBUTTON +XBUTTON1, VK_XBUTTON1 +XBUTTON2, VK_XBUTTON2 +BACK, VK_BACK +TAB, VK_TAB +CLEAR, VK_CLEAR +RETURN, VK_RETURN +SHIFT, VK_SHIFT +CONTROL, VK_CONTROL +MENU, VK_MENU +PAUSE, VK_PAUSE +CAPITAL, VK_CAPITAL +KANA, VK_KANA +HANGEUL, VK_HANGEUL +HANGUL, VK_HANGUL +JUNJA, VK_JUNJA +FINAL, VK_FINAL +HANJA, VK_HANJA +KANJI, VK_KANJI +ESCAPE, VK_ESCAPE +CONVERT, VK_CONVERT +NONCONVERT, VK_NONCONVERT +ACCEPT, VK_ACCEPT +MODECHANGE, VK_MODECHANGE +SPACE, VK_SPACE +PRIOR, VK_PRIOR +NEXT, VK_NEXT +END, VK_END +HOME, VK_HOME +LEFT, VK_LEFT +UP, VK_UP +RIGHT, VK_RIGHT +DOWN, VK_DOWN +SELECT, VK_SELECT +PRINT, VK_PRINT +EXECUTE, VK_EXECUTE +SNAPSHOT, VK_SNAPSHOT +INSERT, VK_INSERT +DELETE, VK_DELETE +HELP, VK_HELP +LWIN, VK_LWIN +RWIN, VK_RWIN +APPS, VK_APPS +SLEEP, VK_SLEEP +NUMPAD0, VK_NUMPAD0 +NUMPAD1, VK_NUMPAD1 +NUMPAD2, VK_NUMPAD2 +NUMPAD3, VK_NUMPAD3 +NUMPAD4, VK_NUMPAD4 +NUMPAD5, VK_NUMPAD5 +NUMPAD6, VK_NUMPAD6 +NUMPAD7, VK_NUMPAD7 +NUMPAD8, VK_NUMPAD8 +NUMPAD9, VK_NUMPAD9 +MULTIPLY, VK_MULTIPLY +ADD, VK_ADD +SEPARATOR, VK_SEPARATOR +SUBTRACT, VK_SUBTRACT +DECIMAL, VK_DECIMAL +DIVIDE, VK_DIVIDE +F1, VK_F1 +F2, VK_F2 +F3, VK_F3 +F4, VK_F4 +F5, VK_F5 +F6, VK_F6 +F7, VK_F7 +F8, VK_F8 +F9, VK_F9 +F10, VK_F10 +F11, VK_F11 +F12, VK_F12 +F13, VK_F13 +F14, VK_F14 +F15, VK_F15 +F16, VK_F16 +F17, VK_F17 +F18, VK_F18 +F19, VK_F19 +F20, VK_F20 +F21, VK_F21 +F22, VK_F22 +F23, VK_F23 +F24, VK_F24 +NUMLOCK, VK_NUMLOCK +SCROLL, VK_SCROLL +OEM_NEC_EQUAL, VK_OEM_NEC_EQUAL +OEM_FJ_JISHO, VK_OEM_FJ_JISHO +OEM_FJ_MASSHOU, VK_OEM_FJ_MASSHOU +OEM_FJ_TOUROKU, VK_OEM_FJ_TOUROKU +OEM_FJ_LOYA, VK_OEM_FJ_LOYA +OEM_FJ_ROYA, VK_OEM_FJ_ROYA +LSHIFT, VK_LSHIFT +RSHIFT, VK_RSHIFT +LCONTROL, VK_LCONTROL +RCONTROL, VK_RCONTROL +LMENU, VK_LMENU +RMENU, VK_RMENU +BROWSER_BACK, VK_BROWSER_BACK +BROWSER_FORWARD, VK_BROWSER_FORWARD +BROWSER_REFRESH, VK_BROWSER_REFRESH +BROWSER_STOP, VK_BROWSER_STOP +BROWSER_SEARCH, VK_BROWSER_SEARCH +BROWSER_FAVORITES, VK_BROWSER_FAVORITES +BROWSER_HOME, VK_BROWSER_HOME +VOLUME_MUTE, VK_VOLUME_MUTE +VOLUME_DOWN, VK_VOLUME_DOWN +VOLUME_UP, VK_VOLUME_UP +MEDIA_NEXT_TRACK, VK_MEDIA_NEXT_TRACK +MEDIA_PREV_TRACK, VK_MEDIA_PREV_TRACK +MEDIA_STOP, VK_MEDIA_STOP +MEDIA_PLAY_PAUSE, VK_MEDIA_PLAY_PAUSE +LAUNCH_MAIL, VK_LAUNCH_MAIL +LAUNCH_MEDIA_SELECT, VK_LAUNCH_MEDIA_SELECT +LAUNCH_APP1, VK_LAUNCH_APP1 +LAUNCH_APP2, VK_LAUNCH_APP2 +OEM_1, VK_OEM_1 +OEM_PLUS, VK_OEM_PLUS +OEM_COMMA, VK_OEM_COMMA +OEM_MINUS, VK_OEM_MINUS +OEM_PERIOD, VK_OEM_PERIOD +OEM_2, VK_OEM_2 +OEM_3, VK_OEM_3 +OEM_4, VK_OEM_4 +OEM_5, VK_OEM_5 +OEM_6, VK_OEM_6 +OEM_7, VK_OEM_7 +OEM_8, VK_OEM_8 +OEM_AX, VK_OEM_AX +OEM_102, VK_OEM_102 +ICO_HELP, VK_ICO_HELP +ICO_00, VK_ICO_00 +PROCESSKEY, VK_PROCESSKEY +ICO_CLEAR, VK_ICO_CLEAR +PACKET, VK_PACKET +OEM_RESET, VK_OEM_RESET +OEM_JUMP, VK_OEM_JUMP +OEM_PA1, VK_OEM_PA1 +OEM_PA2, VK_OEM_PA2 +OEM_PA3, VK_OEM_PA3 +OEM_WSCTRL, VK_OEM_WSCTRL +OEM_CUSEL, VK_OEM_CUSEL +OEM_ATTN, VK_OEM_ATTN +OEM_FINISH, VK_OEM_FINISH +OEM_COPY, VK_OEM_COPY +OEM_AUTO, VK_OEM_AUTO +OEM_ENLW, VK_OEM_ENLW +OEM_BACKTAB, VK_OEM_BACKTAB +ATTN, VK_ATTN +CRSEL, VK_CRSEL +EXSEL, VK_EXSEL +EREOF, VK_EREOF +PLAY, VK_PLAY +ZOOM, VK_ZOOM +NONAME, VK_NONAME +PA1, VK_PA1 +OEM_CLEAR, VK_OEM_CLEAR |
