Revision db418a0a
b/qemu-char.c | ||
---|---|---|
538 | 538 |
} |
539 | 539 |
#endif /* !_WIN32 */ |
540 | 540 |
|
541 |
#define STDIO_MAX_CLIENTS 1 |
|
542 |
static int stdio_nb_clients; |
|
543 |
|
|
541 | 544 |
#ifndef _WIN32 |
542 | 545 |
|
543 | 546 |
typedef struct { |
... | ... | |
545 | 548 |
int max_size; |
546 | 549 |
} FDCharDriver; |
547 | 550 |
|
548 |
#define STDIO_MAX_CLIENTS 1 |
|
549 |
static int stdio_nb_clients = 0; |
|
550 | 551 |
|
551 | 552 |
static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len) |
552 | 553 |
{ |
... | ... | |
1451 | 1452 |
|
1452 | 1453 |
#else /* _WIN32 */ |
1453 | 1454 |
|
1455 |
static CharDriverState *stdio_clients[STDIO_MAX_CLIENTS]; |
|
1456 |
|
|
1454 | 1457 |
typedef struct { |
1455 | 1458 |
int max_size; |
1456 | 1459 |
HANDLE hcom, hrecv, hsend; |
... | ... | |
1459 | 1462 |
DWORD len; |
1460 | 1463 |
} WinCharState; |
1461 | 1464 |
|
1465 |
typedef struct { |
|
1466 |
HANDLE hStdIn; |
|
1467 |
HANDLE hInputReadyEvent; |
|
1468 |
HANDLE hInputDoneEvent; |
|
1469 |
HANDLE hInputThread; |
|
1470 |
uint8_t win_stdio_buf; |
|
1471 |
} WinStdioCharState; |
|
1472 |
|
|
1462 | 1473 |
#define NSENDBUF 2048 |
1463 | 1474 |
#define NRECVBUF 2048 |
1464 | 1475 |
#define MAXCONNECT 1 |
... | ... | |
1809 | 1820 |
|
1810 | 1821 |
return qemu_chr_open_win_file(fd_out, _chr); |
1811 | 1822 |
} |
1823 |
|
|
1824 |
static int win_stdio_write(CharDriverState *chr, const uint8_t *buf, int len) |
|
1825 |
{ |
|
1826 |
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); |
|
1827 |
DWORD dwSize; |
|
1828 |
int len1; |
|
1829 |
|
|
1830 |
len1 = len; |
|
1831 |
|
|
1832 |
while (len1 > 0) { |
|
1833 |
if (!WriteFile(hStdOut, buf, len1, &dwSize, NULL)) { |
|
1834 |
break; |
|
1835 |
} |
|
1836 |
buf += dwSize; |
|
1837 |
len1 -= dwSize; |
|
1838 |
} |
|
1839 |
|
|
1840 |
return len - len1; |
|
1841 |
} |
|
1842 |
|
|
1843 |
static void win_stdio_wait_func(void *opaque) |
|
1844 |
{ |
|
1845 |
CharDriverState *chr = opaque; |
|
1846 |
WinStdioCharState *stdio = chr->opaque; |
|
1847 |
INPUT_RECORD buf[4]; |
|
1848 |
int ret; |
|
1849 |
DWORD dwSize; |
|
1850 |
int i; |
|
1851 |
|
|
1852 |
ret = ReadConsoleInput(stdio->hStdIn, buf, sizeof(buf) / sizeof(*buf), |
|
1853 |
&dwSize); |
|
1854 |
|
|
1855 |
if (!ret) { |
|
1856 |
/* Avoid error storm */ |
|
1857 |
qemu_del_wait_object(stdio->hStdIn, NULL, NULL); |
|
1858 |
return; |
|
1859 |
} |
|
1860 |
|
|
1861 |
for (i = 0; i < dwSize; i++) { |
|
1862 |
KEY_EVENT_RECORD *kev = &buf[i].Event.KeyEvent; |
|
1863 |
|
|
1864 |
if (buf[i].EventType == KEY_EVENT && kev->bKeyDown) { |
|
1865 |
int j; |
|
1866 |
if (kev->uChar.AsciiChar != 0) { |
|
1867 |
for (j = 0; j < kev->wRepeatCount; j++) { |
|
1868 |
if (qemu_chr_be_can_write(chr)) { |
|
1869 |
uint8_t c = kev->uChar.AsciiChar; |
|
1870 |
qemu_chr_be_write(chr, &c, 1); |
|
1871 |
} |
|
1872 |
} |
|
1873 |
} |
|
1874 |
} |
|
1875 |
} |
|
1876 |
} |
|
1877 |
|
|
1878 |
static DWORD WINAPI win_stdio_thread(LPVOID param) |
|
1879 |
{ |
|
1880 |
CharDriverState *chr = param; |
|
1881 |
WinStdioCharState *stdio = chr->opaque; |
|
1882 |
int ret; |
|
1883 |
DWORD dwSize; |
|
1884 |
|
|
1885 |
while (1) { |
|
1886 |
|
|
1887 |
/* Wait for one byte */ |
|
1888 |
ret = ReadFile(stdio->hStdIn, &stdio->win_stdio_buf, 1, &dwSize, NULL); |
|
1889 |
|
|
1890 |
/* Exit in case of error, continue if nothing read */ |
|
1891 |
if (!ret) { |
|
1892 |
break; |
|
1893 |
} |
|
1894 |
if (!dwSize) { |
|
1895 |
continue; |
|
1896 |
} |
|
1897 |
|
|
1898 |
/* Some terminal emulator returns \r\n for Enter, just pass \n */ |
|
1899 |
if (stdio->win_stdio_buf == '\r') { |
|
1900 |
continue; |
|
1901 |
} |
|
1902 |
|
|
1903 |
/* Signal the main thread and wait until the byte was eaten */ |
|
1904 |
if (!SetEvent(stdio->hInputReadyEvent)) { |
|
1905 |
break; |
|
1906 |
} |
|
1907 |
if (WaitForSingleObject(stdio->hInputDoneEvent, INFINITE) |
|
1908 |
!= WAIT_OBJECT_0) { |
|
1909 |
break; |
|
1910 |
} |
|
1911 |
} |
|
1912 |
|
|
1913 |
qemu_del_wait_object(stdio->hInputReadyEvent, NULL, NULL); |
|
1914 |
return 0; |
|
1915 |
} |
|
1916 |
|
|
1917 |
static void win_stdio_thread_wait_func(void *opaque) |
|
1918 |
{ |
|
1919 |
CharDriverState *chr = opaque; |
|
1920 |
WinStdioCharState *stdio = chr->opaque; |
|
1921 |
|
|
1922 |
if (qemu_chr_be_can_write(chr)) { |
|
1923 |
qemu_chr_be_write(chr, &stdio->win_stdio_buf, 1); |
|
1924 |
} |
|
1925 |
|
|
1926 |
SetEvent(stdio->hInputDoneEvent); |
|
1927 |
} |
|
1928 |
|
|
1929 |
static void qemu_chr_set_echo_win_stdio(CharDriverState *chr, bool echo) |
|
1930 |
{ |
|
1931 |
WinStdioCharState *stdio = chr->opaque; |
|
1932 |
DWORD dwMode = 0; |
|
1933 |
|
|
1934 |
GetConsoleMode(stdio->hStdIn, &dwMode); |
|
1935 |
|
|
1936 |
if (echo) { |
|
1937 |
SetConsoleMode(stdio->hStdIn, dwMode | ENABLE_ECHO_INPUT); |
|
1938 |
} else { |
|
1939 |
SetConsoleMode(stdio->hStdIn, dwMode & ~ENABLE_ECHO_INPUT); |
|
1940 |
} |
|
1941 |
} |
|
1942 |
|
|
1943 |
static void win_stdio_close(CharDriverState *chr) |
|
1944 |
{ |
|
1945 |
WinStdioCharState *stdio = chr->opaque; |
|
1946 |
|
|
1947 |
if (stdio->hInputReadyEvent != INVALID_HANDLE_VALUE) { |
|
1948 |
CloseHandle(stdio->hInputReadyEvent); |
|
1949 |
} |
|
1950 |
if (stdio->hInputDoneEvent != INVALID_HANDLE_VALUE) { |
|
1951 |
CloseHandle(stdio->hInputDoneEvent); |
|
1952 |
} |
|
1953 |
if (stdio->hInputThread != INVALID_HANDLE_VALUE) { |
|
1954 |
TerminateThread(stdio->hInputThread, 0); |
|
1955 |
} |
|
1956 |
|
|
1957 |
g_free(chr->opaque); |
|
1958 |
g_free(chr); |
|
1959 |
stdio_nb_clients--; |
|
1960 |
} |
|
1961 |
|
|
1962 |
static int qemu_chr_open_win_stdio(QemuOpts *opts, CharDriverState **_chr) |
|
1963 |
{ |
|
1964 |
CharDriverState *chr; |
|
1965 |
WinStdioCharState *stdio; |
|
1966 |
DWORD dwMode; |
|
1967 |
int is_console = 0; |
|
1968 |
|
|
1969 |
if (stdio_nb_clients >= STDIO_MAX_CLIENTS |
|
1970 |
|| ((display_type != DT_NOGRAPHIC) && (stdio_nb_clients != 0))) { |
|
1971 |
return -EIO; |
|
1972 |
} |
|
1973 |
|
|
1974 |
chr = g_malloc0(sizeof(CharDriverState)); |
|
1975 |
stdio = g_malloc0(sizeof(WinStdioCharState)); |
|
1976 |
|
|
1977 |
stdio->hStdIn = GetStdHandle(STD_INPUT_HANDLE); |
|
1978 |
if (stdio->hStdIn == INVALID_HANDLE_VALUE) { |
|
1979 |
fprintf(stderr, "cannot open stdio: invalid handle\n"); |
|
1980 |
exit(1); |
|
1981 |
} |
|
1982 |
|
|
1983 |
is_console = GetConsoleMode(stdio->hStdIn, &dwMode) != 0; |
|
1984 |
|
|
1985 |
chr->opaque = stdio; |
|
1986 |
chr->chr_write = win_stdio_write; |
|
1987 |
chr->chr_close = win_stdio_close; |
|
1988 |
|
|
1989 |
if (stdio_nb_clients == 0) { |
|
1990 |
if (is_console) { |
|
1991 |
if (qemu_add_wait_object(stdio->hStdIn, |
|
1992 |
win_stdio_wait_func, chr)) { |
|
1993 |
fprintf(stderr, "qemu_add_wait_object: failed\n"); |
|
1994 |
} |
|
1995 |
} else { |
|
1996 |
DWORD dwId; |
|
1997 |
|
|
1998 |
stdio->hInputReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL); |
|
1999 |
stdio->hInputDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL); |
|
2000 |
stdio->hInputThread = CreateThread(NULL, 0, win_stdio_thread, |
|
2001 |
chr, 0, &dwId); |
|
2002 |
|
|
2003 |
if (stdio->hInputThread == INVALID_HANDLE_VALUE |
|
2004 |
|| stdio->hInputReadyEvent == INVALID_HANDLE_VALUE |
|
2005 |
|| stdio->hInputDoneEvent == INVALID_HANDLE_VALUE) { |
|
2006 |
fprintf(stderr, "cannot create stdio thread or event\n"); |
|
2007 |
exit(1); |
|
2008 |
} |
|
2009 |
if (qemu_add_wait_object(stdio->hInputReadyEvent, |
|
2010 |
win_stdio_thread_wait_func, chr)) { |
|
2011 |
fprintf(stderr, "qemu_add_wait_object: failed\n"); |
|
2012 |
} |
|
2013 |
} |
|
2014 |
} |
|
2015 |
|
|
2016 |
dwMode |= ENABLE_LINE_INPUT; |
|
2017 |
|
|
2018 |
stdio_clients[stdio_nb_clients++] = chr; |
|
2019 |
if (stdio_nb_clients == 1 && is_console) { |
|
2020 |
/* set the terminal in raw mode */ |
|
2021 |
/* ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS */ |
|
2022 |
dwMode |= ENABLE_PROCESSED_INPUT; |
|
2023 |
} |
|
2024 |
|
|
2025 |
SetConsoleMode(stdio->hStdIn, dwMode); |
|
2026 |
|
|
2027 |
chr->chr_set_echo = qemu_chr_set_echo_win_stdio; |
|
2028 |
qemu_chr_fe_set_echo(chr, false); |
|
2029 |
|
|
2030 |
*_chr = chr; |
|
2031 |
|
|
2032 |
return 0; |
|
2033 |
} |
|
1812 | 2034 |
#endif /* !_WIN32 */ |
1813 | 2035 |
|
1814 | 2036 |
/***********************************************************/ |
... | ... | |
2519 | 2741 |
{ .name = "pipe", .open = qemu_chr_open_win_pipe }, |
2520 | 2742 |
{ .name = "console", .open = qemu_chr_open_win_con }, |
2521 | 2743 |
{ .name = "serial", .open = qemu_chr_open_win }, |
2744 |
{ .name = "stdio", .open = qemu_chr_open_win_stdio }, |
|
2522 | 2745 |
#else |
2523 | 2746 |
{ .name = "file", .open = qemu_chr_open_file_out }, |
2524 | 2747 |
{ .name = "pipe", .open = qemu_chr_open_pipe }, |
Also available in: Unified diff