2 Skelton for retropc emulator
4 Author : Takeda.Toshiya
11 #include "../res/resource.h"
13 void OSD::initialize_console()
16 use_telnet = config.use_telnet;
18 svr_socket = cli_socket = INVALID_SOCKET;
21 void OSD::release_console()
26 BOOL WINAPI ctrl_c_handler(DWORD type)
31 void OSD::open_console(int width, int height, const _TCHAR* title)
33 int console_width = (width > 0) ? width : 120;
34 int console_height = (height > 0) ? height : 30;
35 int buffer_height = 9001;
37 if(console_count++ == 0) {
42 #define SET_RECT(rect, l, t, r, b) { \
48 CONSOLE_SCREEN_BUFFER_INFO csbi;
53 SetConsoleTitle(title);
54 SetConsoleCtrlHandler(ctrl_c_handler, TRUE);
55 RemoveMenu(GetSystemMenu(GetConsoleWindow(), FALSE), SC_CLOSE, MF_BYCOMMAND);
57 hStdIn = GetStdHandle(STD_INPUT_HANDLE);
58 hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
59 GetConsoleScreenBufferInfo(hStdOut, &csbi);
61 // window can't be bigger than buffer,
62 // buffer can't be smaller than window,
63 // so make a tiny window,
64 // set the required buffer,
65 // then set the required window
66 int min_width = min(csbi.srWindow.Right - csbi.srWindow.Left + 1, console_width);
67 int min_height = min(csbi.srWindow.Bottom - csbi.srWindow.Top + 1, console_height);
69 SET_RECT(rect, 0, csbi.srWindow.Top, min_width - 1, csbi.srWindow.Top + min_height - 1);
70 SetConsoleWindowInfo(hStdOut, TRUE, &rect);
72 coord.X = console_width;
73 coord.Y = buffer_height;
74 SetConsoleScreenBufferSize(hStdOut, coord);
76 SET_RECT(rect, 0, 0, console_width - 1, console_height - 1);
77 if(!SetConsoleWindowInfo(hStdOut, TRUE, &rect)) {
78 SetWindowPos(GetConsoleWindow(), NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
79 SetConsoleWindowInfo(hStdOut, TRUE, &rect);
81 SetConsoleTextAttribute(hStdOut, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
85 void OSD::close_console()
87 if(console_count > 0 && --console_count == 0) {
92 SetConsoleCtrlHandler(ctrl_c_handler, FALSE);
97 unsigned int OSD::get_console_code_page()
99 return GetConsoleCP();
102 void OSD::set_console_text_attribute(unsigned short attr)
104 unsigned short new_attr = 0;
109 if(attr & OSD_CONSOLE_BLUE ) new_attr |= 4;
110 if(attr & OSD_CONSOLE_GREEN ) new_attr |= 2;
111 if(attr & OSD_CONSOLE_RED ) new_attr |= 1;
112 if(attr & OSD_CONSOLE_INTENSITY) new_attr |= 8;
114 sprintf_s(buffer, 32, "\033[%dm\033[3%dm", (new_attr >> 3) & 1, (new_attr & 7));
118 if(attr & OSD_CONSOLE_BLUE ) new_attr |= FOREGROUND_BLUE;
119 if(attr & OSD_CONSOLE_GREEN ) new_attr |= FOREGROUND_GREEN;
120 if(attr & OSD_CONSOLE_RED ) new_attr |= FOREGROUND_RED;
121 if(attr & OSD_CONSOLE_INTENSITY) new_attr |= FOREGROUND_INTENSITY;
123 SetConsoleTextAttribute(hStdOut, attr);
126 void OSD::write_console(const _TCHAR* buffer, unsigned int length)
129 send_telnet(tchar_to_char(buffer));
133 WriteConsole(hStdOut, buffer, length, &dwWritten, NULL);
136 int OSD::read_console_input(_TCHAR* buffer, unsigned int length)
141 if(cli_socket != INVALID_SOCKET && (len = recv(cli_socket, temp, length, 0)) > 0) {
143 const _TCHAR *temp_t = char_to_tchar(temp);
144 for(int i = 0; i < len; i++) {
145 buffer[i] = temp_t[i];
150 telnet_closed = true;
156 unsigned int count = 0;
158 if(ReadConsoleInput(hStdIn, ir, min(16, length), &dwRead)) {
159 for(unsigned int i = 0; i < dwRead; i++) {
160 if((ir[i].EventType & KEY_EVENT) && ir[i].Event.KeyEvent.bKeyDown) {
162 if(ir[i].Event.KeyEvent.uChar.UnicodeChar) {
164 buffer[count++] = ir[i].Event.KeyEvent.uChar.UnicodeChar;
167 if(ir[i].Event.KeyEvent.uChar.AsciiChar) {
169 buffer[count++] = ir[i].Event.KeyEvent.uChar.AsciiChar;
172 } else if(ir[i].Event.KeyEvent.wVirtualKeyCode >= 0x25 && ir[i].Event.KeyEvent.wVirtualKeyCode <= 0x28) {
173 static const _TCHAR cursor[] = {_T('D'), _T('A'), _T('C'), _T('B')}; // left, up, right, down
174 if(count + 2 < length) {
175 buffer[count++] = 0x1b;
176 buffer[count++] = 0x5b;
177 buffer[count++] = cursor[ir[i].Event.KeyEvent.wVirtualKeyCode - 0x25];
186 bool OSD::is_console_key_pressed(int vk)
191 if(cli_socket != INVALID_SOCKET && (len = recv(cli_socket, temp, sizeof(temp), 0)) > 0) {
192 for(int i = 0; i < len; i++) {
199 telnet_closed = true;
204 HWND hWnd = GetForegroundWindow();
205 if(hWnd != NULL && hWnd == FindWindow(_T("ConsoleWindowClass"), NULL)) {
206 return ((GetAsyncKeyState(vk) & 0x8000) != 0);
211 bool OSD::is_console_closed()
214 return telnet_closed;
219 void OSD::close_debugger_console()
221 PostMessage(main_window_handle, WM_COMMAND, ID_CLOSE_DEBUGGER, 0L);
224 const _TCHAR *get_ttermpro_path()
226 static _TCHAR path[MAX_PATH] = {0};
228 if(_tgetenv(_T("ProgramFiles"))) {
229 my_stprintf_s(path, MAX_PATH, _T("%s\\teraterm\\ttermpro.exe"), _tgetenv(_T("ProgramFiles")));
234 const _TCHAR *get_ttermpro_x86_path()
236 static _TCHAR path[MAX_PATH] = {0};
238 if(_tgetenv(_T("ProgramFiles(x86)"))) {
239 my_stprintf_s(path, MAX_PATH, _T("%s\\teraterm\\ttermpro.exe"), _tgetenv(_T("ProgramFiles(x86)")));
244 const _TCHAR *get_putty_path()
246 static _TCHAR path[MAX_PATH] = {0};
248 if(_tgetenv(_T("ProgramFiles"))) {
249 my_stprintf_s(path, MAX_PATH, _T("%s\\PuTTY\\putty.exe"), _tgetenv(_T("ProgramFiles")));
254 const _TCHAR *get_putty_x86_path()
256 static _TCHAR path[MAX_PATH] = {0};
258 if(_tgetenv(_T("ProgramFiles(x86)"))) {
259 my_stprintf_s(path, MAX_PATH, _T("%s\\PuTTY\\putty.exe"), _tgetenv(_T("ProgramFiles(x86)")));
264 const _TCHAR *get_telnet_path()
266 static _TCHAR path[MAX_PATH] = {0};
268 if(_tgetenv(_T("windir")) != NULL) {
270 my_stprintf_s(path, MAX_PATH, _T("%s\\System32\\telnet.exe"), _tgetenv(_T("windir")));
272 // prevent System32 is redirected to SysWOW64 in 32bit process on Windows x64
273 my_stprintf_s(path, MAX_PATH, _T("%s\\Sysnative\\telnet.exe"), _tgetenv(_T("windir")));
279 const _TCHAR *get_telnet_x86_path()
281 static _TCHAR path[MAX_PATH] = {0};
283 if(_tgetenv(_T("windir")) != NULL) {
285 my_stprintf_s(path, MAX_PATH, _T("%s\\SysWOW64\\telnet.exe"), _tgetenv(_T("windir")));
287 // System32 will be redirected to SysWOW64 in 32bit process on Windows x64
288 my_stprintf_s(path, MAX_PATH, _T("%s\\System32\\telnet.exe"), _tgetenv(_T("windir")));
294 void OSD::open_telnet(const _TCHAR* title)
297 struct sockaddr_in svr_addr;
298 struct sockaddr_in cli_addr;
299 int cli_addr_len = sizeof(cli_addr);
301 int bind_stat = SOCKET_ERROR;
302 struct timeval timeout;
304 WSAStartup(MAKEWORD(2,0), &was_data);
306 if((svr_socket = socket(AF_INET, SOCK_STREAM, 0)) != INVALID_SOCKET) {
307 memset(&svr_addr, 0, sizeof(svr_addr));
308 svr_addr.sin_family = AF_INET;
309 svr_addr.sin_addr.s_addr = htonl(INADDR_ANY);
311 while(port < 65536) {
312 svr_addr.sin_port = htons(port);
313 if((bind_stat = bind(svr_socket, (struct sockaddr *)&svr_addr, sizeof(svr_addr))) == 0) {
316 port = (port == 23) ? 49152 : (port + 1);
322 setsockopt(svr_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
324 listen(svr_socket, 1);
326 _TCHAR command[MAX_PATH] = {0};
328 PROCESS_INFORMATION pi;
330 if(_taccess(get_ttermpro_path(), 0) == 0) {
331 my_stprintf_s(command, MAX_PATH, _T("%s localhost:%d /T=1"), get_ttermpro_path(), port);
332 } else if(_taccess(get_ttermpro_x86_path(), 0) == 0) {
333 my_stprintf_s(command, MAX_PATH, _T("%s localhost:%d /T=1"), get_ttermpro_x86_path(), port);
334 } else if(_taccess(get_putty_path(), 0) == 0) {
335 my_stprintf_s(command, MAX_PATH, _T("%s -telnet localhost %d"), get_putty_path(), port);
336 } else if(_taccess(get_putty_x86_path(), 0) == 0) {
337 my_stprintf_s(command, MAX_PATH, _T("%s -telnet localhost %d"), get_putty_x86_path(), port);
338 } else if(_taccess(get_telnet_path(), 0) == 0) {
339 my_stprintf_s(command, MAX_PATH, _T("%s -t vt100 localhost %d"), get_telnet_path(), port);
340 } else if(_taccess(get_telnet_x86_path(), 0) == 0) {
341 my_stprintf_s(command, MAX_PATH, _T("%s -t vt100 localhost %d"), get_telnet_x86_path(), port);
343 if(command[0] != _T('\0')) {
344 memset(&si, 0, sizeof(STARTUPINFO));
345 memset(&pi, 0, sizeof(PROCESS_INFORMATION));
346 CreateProcess(NULL, command, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
348 if((cli_socket = accept(svr_socket, (struct sockaddr *) &cli_addr, &cli_addr_len)) != INVALID_SOCKET) {
350 ioctlsocket(cli_socket, FIONBIO, &val);
351 telnet_closed = false;
353 sprintf_s(command, MAX_PATH, "\033]0;%s\007", tchar_to_char(title));
354 send_telnet(command);
356 uint8_t will_echo[] = {0xff, 0xfb, 0x01};
357 send(cli_socket, (char *)will_echo, 3, 0);
358 send_telnet("\033[2l"); // key unlock
359 send_telnet("\033[12h"); // local echo off
365 void OSD::close_telnet()
367 if(svr_socket != INVALID_SOCKET) {
368 shutdown(svr_socket, /*SD_BOTH*/2);
369 closesocket(svr_socket);
370 svr_socket = cli_socket = INVALID_SOCKET;
375 void OSD::send_telnet(const char* string)
377 if(cli_socket != INVALID_SOCKET) {
378 for(unsigned int i = 0; i < strlen(string); i++) {
379 if(string[i] == 0x0d || string[i] == 0x0a) {
380 send_telnet("\033E");
381 } else if(string[i] == 0x08) {
382 send_telnet("\033[1D");
384 send(cli_socket, &string[i], 1, 0);