1 2 3 /* This version of microEmacs is based on the public domain C 4 * version written by Dave G. Conroy. 5 * The D programming language version is written by Walter Bright. 6 * http://www.digitalmars.com/d/ 7 * This program is in the public domain. 8 */ 9 10 /* 11 * The routines in this file provide support for computers with 12 * WIN32 console I/O support. 13 */ 14 15 module console; 16 17 version (Windows) 18 { 19 20 import std.stdio; 21 import core.stdc.stdlib; 22 import core.stdc..string; 23 import core.sys.windows.windows; 24 import core.sys.windows.winuser; 25 26 import ed; 27 import disp; 28 29 30 enum BEL = 0x07; /* BEL character. */ 31 enum ESC = 0x1B; /* ESC character. */ 32 33 34 static HANDLE hStdin; // console input handle 35 static DWORD fdwSaveOldMode; 36 37 static INPUT_RECORD lookaheadir; 38 static int lookahead; // !=0 if data in lookaheadir 39 40 /* 41 * Standard terminal interface dispatch table. Most of the fields point into 42 * "termio" code. 43 */ 44 45 46 47 struct TERM 48 { 49 int t_nrow; /* Number of rows. */ 50 int t_ncol; /* Number of columns. */ 51 52 void t_open() /* Open terminal at the start. */ 53 { 54 hStdin = GetStdHandle(STD_INPUT_HANDLE); 55 if (hStdin == INVALID_HANDLE_VALUE) 56 { printf("getstdhandle\n"); 57 exit(EXIT_FAILURE); 58 } 59 60 if (!GetConsoleMode(hStdin,&fdwSaveOldMode)) 61 { printf("getconsolemode\n"); 62 exit(EXIT_FAILURE); 63 } 64 65 if (!SetConsoleMode(hStdin,ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT)) 66 { printf("setconsolemode\n"); 67 exit(EXIT_FAILURE); 68 } 69 70 disp_open(); 71 disp_setcursortype(DISP_CURSORBLOCK); 72 t_ncol = disp_state.numcols; 73 t_nrow = disp_state.numrows; 74 } 75 76 void t_close() /* Close terminal at end. */ 77 { 78 disp_close(); 79 80 if (!SetConsoleMode(hStdin,fdwSaveOldMode)) 81 { printf("restore console mode\n"); 82 exit(EXIT_FAILURE); 83 } 84 } 85 86 int t_getchar() /* Get character from keyboard. */ 87 { 88 INPUT_RECORD buf; 89 DWORD cNumRead; 90 int c; 91 92 while (1) 93 { 94 if (lookahead) 95 { buf = lookaheadir; 96 lookahead = 0; 97 } 98 else if (!ReadConsoleInputW(hStdin,&buf,1,&cNumRead)) 99 { c = 3; // ^C 100 goto Lret; 101 } 102 103 switch (buf.EventType) 104 { 105 case MOUSE_EVENT: 106 mstat_update(&buf.MouseEvent); 107 continue; 108 109 default: 110 continue; // ignore 111 112 case KEY_EVENT: 113 c = win32_keytran(&buf.KeyEvent); 114 if (!c) 115 continue; 116 goto Lret; 117 } 118 } 119 120 Lret: 121 return c; 122 } 123 124 void t_putchar(int c) /* Put character to display. */ 125 { 126 disp_putc(c); 127 } 128 129 void t_flush() /* Flush output buffers. */ 130 { 131 disp_flush(); 132 } 133 134 void t_move(int row, int col) /* Move the cursor, origin 0. */ 135 { 136 disp_move(row, col); 137 } 138 139 void t_eeol() /* Erase to end of line. */ 140 { 141 disp_eeol(); 142 } 143 144 void t_eeop() /* Erase to end of page. */ 145 { 146 disp_eeop(); 147 } 148 149 void t_beep() /* Beep. */ 150 { 151 disp_putc(BEL); 152 } 153 154 void t_standout() /* Start standout mode */ 155 { 156 disp_startstand(); 157 } 158 159 void t_standend() /* End standout mode */ 160 { 161 disp_endstand(); 162 } 163 164 void t_scrollup() /* Scroll the screen up */ 165 { 166 } 167 168 void t_scrolldn() /* Scroll the screen down */ 169 /* Note: scrolling routines do */ 170 /* not save cursor position. */ 171 { 172 } 173 174 void t_setcursor(int insertmode) 175 { 176 disp_setcursortype(insertmode ? DISP_CURSORBLOCK : DISP_CURSORUL); 177 } 178 } 179 180 TERM term; 181 182 /******************************************** 183 */ 184 185 void updateline(int row,attchar_t[] buffer,attchar_t[] physical) 186 { 187 int col; 188 int numcols; 189 CHAR_INFO *psb; 190 CHAR_INFO[256] sbbuf; 191 CHAR_INFO *sb; 192 COORD sbsize; 193 static COORD sbcoord; 194 SMALL_RECT sdrect; 195 196 sbsize.X = cast(short)disp_state.numcols; 197 sbsize.Y = 1; 198 sbcoord.X = 0; 199 sbcoord.Y = 0; 200 sdrect.Left = 0; 201 sdrect.Top = cast(short)row; 202 sdrect.Right = cast(short)(disp_state.numcols - 1); 203 sdrect.Bottom = cast(short)row; 204 numcols = disp_state.numcols; 205 sb = sbbuf.ptr; 206 if (numcols > sbbuf.length) 207 { 208 sb = cast(CHAR_INFO *)alloca(numcols * CHAR_INFO.sizeof); 209 } 210 for (col = 0; col < numcols; col++) 211 { 212 auto c = buffer[col].chr; 213 sb[col].UnicodeChar = cast(WCHAR)c; 214 sb[col].Attributes = buffer[col].attr; 215 if (c >= 0x10000) 216 { 217 /* Calculate surrogate pairs, but don't know yet how they 218 * work, if at all, with WriteConsoleOutput() 219 */ 220 auto c0 = cast(wchar)((((c - 0x10000) >> 10) & 0x3FF) + 0xD800); 221 auto c1 = cast(wchar)(((c - 0x10000) & 0x3FF) + 0xDC00); 222 } 223 //printf("col = %2d, x%2x, '%c'\n",col,sb[col].AsciiChar,sb[col].AsciiChar); 224 } 225 if (!WriteConsoleOutputW(cast(HANDLE)disp_state.handle,sb,sbsize,sbcoord,&sdrect)) 226 { 227 // error 228 } 229 physical[] = buffer[]; 230 } 231 232 /********************************* 233 */ 234 235 extern (C) int msm_init() 236 { 237 return GetSystemMetrics(SM_MOUSEPRESENT); 238 } 239 240 extern (C) 241 { 242 void msm_term() { } 243 void msm_showcursor() { } 244 void msm_hidecursor() { } 245 } 246 247 struct msm_status // current state of mouse 248 { 249 uint row; 250 uint col; 251 int buttons; 252 } 253 254 msm_status mstat; 255 256 /************************* 257 * Fold MOUSE_EVENT into mstat. 258 */ 259 260 static void mstat_update(MOUSE_EVENT_RECORD *pme) 261 { 262 mstat.row = pme.dwMousePosition.Y; 263 mstat.col = pme.dwMousePosition.X; 264 mstat.buttons = pme.dwButtonState & 3; 265 } 266 267 extern (C) int msm_getstatus(uint *pcol,uint *prow) 268 { 269 INPUT_RECORD buf; 270 DWORD cNumRead; 271 272 if (lookahead) 273 { buf = lookaheadir; 274 cNumRead = 1; 275 } 276 else if (!PeekConsoleInputA(hStdin,&buf,1,&cNumRead)) 277 goto Lret; 278 279 if (cNumRead) 280 switch (buf.EventType) 281 { 282 case MOUSE_EVENT: 283 mstat_update(&buf.MouseEvent); 284 goto default; 285 286 default: 287 Ldiscard: 288 if (lookahead) 289 lookahead = 0; 290 else 291 ReadConsoleInputA(hStdin,&buf,1,&cNumRead); // discard 292 break; 293 294 case KEY_EVENT: 295 if (mstat.buttons & 3) 296 goto Ldiscard; 297 break; 298 } 299 300 Lret: 301 *prow = mstat.row; 302 *pcol = mstat.col; 303 return mstat.buttons; 304 } 305 306 /************************************* 307 * Translate key from WIN32 to IBM PC style. 308 * Params: 309 * pkey = pointer to key data 310 * Returns: 311 * 0 if ignore it 312 * References: 313 * https://github.com/dlang/druntime/blob/master/src/core/sys/windows/wincon.d 314 */ 315 316 static uint win32_keytran(KEY_EVENT_RECORD *pkey) 317 { 318 if (!pkey.bKeyDown) 319 return 0; // ignore button up events 320 uint c = pkey.UnicodeChar; 321 /+ 322 printf("RepeatCount %x VirtualKeyCode %x VirtualScanCode %x UnicodeChar %x AsciiChar %x ControlKeyState %x\n", 323 pkey.wRepeatCount, pkey.wVirtualKeyCode, pkey.wVirtualScanCode, pkey.UnicodeChar, pkey.AsciiChar, 324 pkey.dwControlKeyState); 325 +/ 326 if (c == 0) 327 { 328 switch (pkey.wVirtualScanCode) 329 { 330 case 0x1D: // Ctrl 331 case 0x38: // Alt 332 case 0x2A: // Left Shift 333 case 0x36: // Right Shift 334 break; // ignore 335 default: 336 c = (pkey.wVirtualScanCode << 8) & 0xFF00; 337 if (pkey.dwControlKeyState & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED)) 338 { 339 switch (c) 340 { case 0x4700: c = 0x7700; break; // Home 341 case 0x4F00: c = 0x7500; break; // End 342 case 0x4900: c = 0x8400; break; // PgUp 343 case 0x5100: c = 0x7600; break; // PgDn 344 default: c = 0; break; 345 } 346 } 347 break; 348 } 349 } 350 else if (pkey.dwControlKeyState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED)) 351 { 352 c = (pkey.wVirtualScanCode << 8) & 0xFF00; 353 } 354 Lret: 355 return c; 356 } 357 358 /************************** 359 * Return when there are unread chars ready in the input. 360 */ 361 362 void ttwaitkeys() 363 { 364 } 365 366 /************************************* 367 * Wait for any input (yield to other processes). 368 */ 369 370 void ttyield() 371 { 372 if (!lookahead) 373 { 374 DWORD cNumRead; 375 376 if (!ReadConsoleInputA(hStdin,&lookaheadir,1,&cNumRead)) 377 { printf("readconsoleinput\n"); 378 goto Lret; 379 } 380 } 381 lookahead = 1; 382 Lret: ; 383 } 384 385 /************************************* 386 */ 387 388 int ttkeysininput() 389 { 390 INPUT_RECORD buf; 391 DWORD cNumRead; 392 393 if (lookahead) 394 { buf = lookaheadir; 395 cNumRead = 1; 396 } 397 else if (!PeekConsoleInputA(hStdin,&buf,1,&cNumRead)) 398 goto Lret; 399 400 if (cNumRead) 401 { 402 switch (buf.EventType) 403 { 404 case MOUSE_EVENT: 405 mstat_update(&buf.MouseEvent); 406 goto default; 407 408 default: 409 Ldiscard: 410 if (lookahead) 411 lookahead = 0; 412 else 413 ReadConsoleInputA(hStdin,&buf,1,&cNumRead); // discard 414 cNumRead = 0; 415 break; 416 417 case KEY_EVENT: 418 if (!win32_keytran(&buf.KeyEvent)) 419 goto Ldiscard; 420 break; 421 } 422 } 423 424 Lret: 425 return cNumRead != 0; 426 } 427 428 extern (C) void popen() { assert(0); } 429 430 void setClipboard(const(char)[] s) 431 { 432 if (OpenClipboard(null)) 433 { 434 EmptyClipboard(); 435 436 HGLOBAL hmem = GlobalAlloc(GMEM_MOVEABLE, (s.length + 1) * char.sizeof); 437 if (hmem) 438 { 439 auto p = cast(char*)GlobalLock(hmem); 440 memcpy(p, s.ptr, s.length * char.sizeof); 441 p[s.length] = 0; 442 GlobalUnlock(hmem); 443 444 SetClipboardData(CF_TEXT, hmem); 445 } 446 CloseClipboard(); 447 } 448 } 449 450 char[] getClipboard() 451 { 452 char[] s = null; 453 if (IsClipboardFormatAvailable(CF_TEXT) && 454 OpenClipboard(null)) 455 { 456 HANDLE h = GetClipboardData(CF_TEXT); // CF_UNICODETEXT is UTF-16 457 if (h) 458 { 459 auto p = cast(char*)GlobalLock(h); 460 if (p) 461 { 462 size_t length = strlen(p); 463 s = p[0 .. length].dup; 464 } 465 GlobalUnlock(h); 466 } 467 CloseClipboard(); 468 } 469 return s; 470 } 471 472 /*********************** 473 * Open browser on help file. 474 */ 475 476 int help(bool f, int n) 477 { 478 printf("\nhelp \n"); 479 char[MAX_PATH + 1] resolved_name = void; 480 if (GetModuleFileNameA(NULL, resolved_name.ptr, MAX_PATH + 1)) 481 { 482 size_t len = strlen(resolved_name.ptr); 483 size_t i; 484 for (i = len; i; --i) 485 { 486 if (resolved_name[i] == '/' || 487 resolved_name[i] == '\\' || 488 resolved_name[i] == ':') 489 { 490 ++i; 491 break; 492 } 493 } 494 immutable(char)[7] doc = "me.html"; 495 if (i + doc.sizeof <= MAX_PATH) 496 { 497 import std.process; 498 memcpy(resolved_name.ptr + i, doc.ptr, doc.sizeof); 499 printf("\nhelp2 '%.*s'\n", cast(int)(i + doc.sizeof), resolved_name.ptr); 500 browse(cast(string)resolved_name[0 .. i + doc.sizeof]); 501 } 502 } 503 return ed.FALSE; 504 } 505 506 } 507 else 508 { 509 510 import ed; 511 512 /*********************** 513 * Open browser on help file. 514 */ 515 516 int help(bool f, int n) 517 { 518 return ed.FALSE; 519 } 520 521 } 522