1 /* -*- c-basic-offset: 8 -*- 2 rdesktop: A Remote Desktop Protocol client. 3 win32 calls 4 Copyright (C) Jay Sorg 2006 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License along 17 with this program; if not, write to the Free Software Foundation, Inc., 18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 */ 20 21 #include "precomp.h" 22 23 #include "uimain.h" 24 25 extern char g_username[]; 26 extern char g_hostname[]; 27 extern char g_servername[]; 28 extern char g_password[]; 29 extern char g_shell[]; 30 extern char g_directory[]; 31 extern char g_domain[]; 32 extern int g_width; 33 extern int g_height; 34 extern int g_tcp_sck; 35 extern int g_server_depth; 36 extern int g_tcp_port_rdp; /* in tcp.c */ 37 extern int pal_entries[]; 38 39 static HWND g_Wnd = 0; 40 static HINSTANCE g_Instance = 0; 41 static HCURSOR g_cursor = 0; 42 static int g_block = 0; 43 static int g_xoff = 0; /* offset from window to client coords */ 44 static int g_yoff = 0; 45 static int g_xscroll = 0; /* current scroll position */ 46 static int g_yscroll = 0; 47 static int g_screen_width = 0; 48 static int g_screen_height = 0; 49 static int g_wnd_cwidth = 0; /* set from WM_SIZE */ 50 static int g_wnd_cheight = 0; 51 static int g_fullscreen = 0; 52 static int g_workarea = 0; 53 static int g_mousex = 0; /* in client coords */ 54 static int g_mousey = 0; 55 //static int g_width_height_set = 0; 56 57 static int g_clip_left = 0; 58 static int g_clip_top = 0; 59 static int g_clip_right = 800; 60 static int g_clip_bottom = 600; 61 static RECT g_wnd_clip; /* this client area of whats actually visible */ 62 /* set from WM_SIZE */ 63 64 /*****************************************************************************/ 65 static void 66 str_to_uni(TCHAR * sizex, char * size1) 67 { 68 int len; 69 int i; 70 71 len = strlen(size1); 72 for (i = 0; i < len; i++) 73 { 74 sizex[i] = size1[i]; 75 } 76 sizex[len] = 0; 77 } 78 79 /*****************************************************************************/ 80 static void 81 uni_to_str(char * sizex, TCHAR * size1) 82 { 83 int len; 84 int i; 85 86 len = lstrlen(size1); 87 for (i = 0; i < len; i++) 88 { 89 sizex[i] = (char)size1[i]; 90 } 91 sizex[len] = 0; 92 } 93 94 /*****************************************************************************/ 95 /* returns non zero if it processed something */ 96 static int 97 check_sck(void) 98 { 99 fd_set rfds; 100 struct timeval tm; 101 int count; 102 int rv; 103 104 rv = 0; 105 if (g_block == 0) 106 { 107 g_block = 1; 108 /* see if there really is data */ 109 FD_ZERO(&rfds); 110 FD_SET((unsigned int)g_tcp_sck, &rfds); 111 ZeroMemory(&tm, sizeof(tm)); 112 count = select(g_tcp_sck + 1, &rfds, 0, 0, &tm); 113 if (count > 0) 114 { 115 if (ui_read_wire()) 116 { 117 rv = 1; 118 } 119 else 120 { 121 PostQuitMessage(0); 122 } 123 } 124 g_block = 0; 125 } 126 return rv; 127 } 128 129 /*****************************************************************************/ 130 void 131 mi_error(char * msg) 132 { 133 #ifdef WITH_DEBUG 134 printf(msg); 135 #else /* WITH_DEBUG */ 136 TCHAR lmsg[512]; 137 TCHAR ltitle[512]; 138 139 str_to_uni(lmsg, msg); 140 str_to_uni(ltitle, "Error"); 141 MessageBox(g_Wnd, lmsg, ltitle, MB_OK); 142 #endif /* WITH_DEBUG */ 143 } 144 145 /*****************************************************************************/ 146 static int 147 get_scan_code_from_ascii(int code) 148 { 149 int rv; 150 151 rv = 0; 152 switch (code & 0xff) 153 { 154 case 0x30: rv = 0x0b; break; // 0 155 case 0x31: rv = 0x02; break; // 1 156 case 0x32: rv = 0x03; break; // 2 157 case 0x33: rv = 0x04; break; // 3 158 case 0x34: rv = 0x05; break; // 4 159 case 0x35: rv = 0x06; break; // 5 160 case 0x36: rv = 0x07; break; // 6 161 case 0x37: rv = 0x08; break; // 7 162 case 0x38: rv = 0x09; break; // 8 163 case 0x39: rv = 0x0a; break; // 9 164 165 case 0xbd: rv = 0x0c; break; // - 166 case 0xbb: rv = 0x0d; break; // = 167 case 0x08: rv = 0x0e; break; // backspace 168 case 0x09: rv = 0x0f; break; // tab 169 case 0xdb: rv = 0x1b; break; // ] 170 case 0xdd: rv = 0x1a; break; // [ 171 case 0x14: rv = 0x3a; break; // capslock 172 case 0xba: rv = 0x27; break; // ; 173 case 0xde: rv = 0x28; break; // ' 174 case 0x10: rv = 0x2a; break; // shift 175 case 0xbc: rv = 0x33; break; // , 176 case 0xbe: rv = 0x34; break; // . 177 case 0xbf: rv = 0x35; break; // / 178 case 0x0d: rv = 0x1c; break; // enter 179 case 0x27: rv = 0x4d; break; // arrow right 180 case 0x25: rv = 0x4b; break; // arrow left 181 case 0x26: rv = 0x48; break; // arrow up 182 case 0x28: rv = 0x50; break; // arrow down 183 case 0x20: rv = 0x39; break; // space 184 case 0xdc: rv = 0x2b; break; // backslash 185 case 0xc0: rv = 0x29; break; // ` 186 case 0x11: rv = 0x1d; break; // ctl 187 188 case 0x41: rv = 0x1e; break; // a 189 case 0x42: rv = 0x30; break; // b 190 case 0x43: rv = 0x2e; break; // c 191 case 0x44: rv = 0x20; break; // d 192 case 0x45: rv = 0x12; break; // e 193 case 0x46: rv = 0x21; break; // f 194 case 0x47: rv = 0x22; break; // g 195 case 0x48: rv = 0x23; break; // h 196 case 0x49: rv = 0x17; break; // i 197 case 0x4a: rv = 0x24; break; // j 198 case 0x4b: rv = 0x25; break; // k 199 case 0x4c: rv = 0x26; break; // l 200 case 0x4d: rv = 0x32; break; // m 201 case 0x4e: rv = 0x31; break; // n 202 case 0x4f: rv = 0x18; break; // o 203 case 0x50: rv = 0x19; break; // p 204 case 0x51: rv = 0x10; break; // q 205 case 0x52: rv = 0x13; break; // r 206 case 0x53: rv = 0x1f; break; // s 207 case 0x54: rv = 0x14; break; // t 208 case 0x55: rv = 0x16; break; // u 209 case 0x56: rv = 0x2f; break; // v 210 case 0x57: rv = 0x11; break; // w 211 case 0x58: rv = 0x2d; break; // x 212 case 0x59: rv = 0x15; break; // y 213 case 0x5a: rv = 0x2c; break; // z 214 } 215 return rv; 216 } 217 218 /*****************************************************************************/ 219 static void 220 mi_scroll(int dx, int dy) 221 { 222 HRGN rgn; 223 224 rgn = CreateRectRgn(0, 0, 0, 0); 225 ScrollWindowEx(g_Wnd, dx, dy, 0, 0, rgn, 0, SW_ERASE); 226 InvalidateRgn(g_Wnd, rgn, 0); 227 DeleteObject(rgn); 228 } 229 230 /*****************************************************************************/ 231 int 232 mi_read_keyboard_state(void) 233 { 234 short keydata; 235 int code; 236 237 code = 0; 238 keydata = GetKeyState(VK_SCROLL); 239 if (keydata & 0x0001) 240 { 241 code |= 1; 242 } 243 keydata = GetKeyState(VK_NUMLOCK); 244 if (keydata & 0x0001) 245 { 246 code |= 2; 247 } 248 keydata = GetKeyState(VK_CAPITAL); 249 if (keydata & 0x0001) 250 { 251 code |= 4; 252 } 253 return code; 254 } 255 256 /*****************************************************************************/ 257 static void 258 mi_check_modifier(void) 259 { 260 int code; 261 262 code = mi_read_keyboard_state(); 263 ui_set_modifier_state(code); 264 } 265 266 /*****************************************************************************/ 267 static LRESULT 268 handle_WM_SETCURSOR(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 269 { 270 if (g_mousex >= g_wnd_clip.left && 271 g_mousey >= g_wnd_clip.top && 272 g_mousex < g_wnd_clip.right && 273 g_mousey < g_wnd_clip.bottom) 274 { 275 SetCursor(g_cursor); 276 } 277 /* need default behavoir here */ 278 return DefWindowProc(hWnd, message, wParam, lParam); 279 } 280 281 /*****************************************************************************/ 282 static LRESULT 283 handle_WM_NCHITTEST(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 284 { 285 POINT pt; 286 287 pt.x = LOWORD(lParam); 288 pt.y = HIWORD(lParam); 289 if (ScreenToClient(g_Wnd, &pt)) 290 { 291 g_mousex = pt.x; 292 g_mousey = pt.y; 293 } 294 return DefWindowProc(hWnd, message, wParam, lParam); 295 } 296 297 /*****************************************************************************/ 298 static LRESULT 299 handle_WM_MOUSEMOVE(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 300 { 301 g_mousex = LOWORD(lParam); 302 g_mousey = HIWORD(lParam); 303 ui_mouse_move(g_mousex + g_xscroll, g_mousey + g_yscroll); 304 return 0; 305 } 306 307 /*****************************************************************************/ 308 static LRESULT 309 handle_WM_LBUTTONDOWN(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 310 { 311 g_mousex = LOWORD(lParam); 312 g_mousey = HIWORD(lParam); 313 ui_mouse_button(1, g_mousex + g_xscroll, g_mousey + g_yscroll, 1); 314 return 0; 315 } 316 317 /*****************************************************************************/ 318 static LRESULT 319 handle_WM_LBUTTONUP(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 320 { 321 g_mousex = LOWORD(lParam); 322 g_mousey = HIWORD(lParam); 323 ui_mouse_button(1, g_mousex + g_xscroll, g_mousey + g_yscroll, 0); 324 return 0; 325 } 326 327 /*****************************************************************************/ 328 static LRESULT 329 handle_WM_RBUTTONDOWN(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 330 { 331 g_mousex = LOWORD(lParam); 332 g_mousey = HIWORD(lParam); 333 ui_mouse_button(2, g_mousex + g_xscroll, g_mousey + g_yscroll, 1); 334 return 0; 335 } 336 337 /*****************************************************************************/ 338 static LRESULT 339 handle_WM_RBUTTONUP(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 340 { 341 g_mousex = LOWORD(lParam); 342 g_mousey = HIWORD(lParam); 343 ui_mouse_button(2, g_mousex + g_xscroll, g_mousey + g_yscroll, 0); 344 return 0; 345 } 346 347 /*****************************************************************************/ 348 static LRESULT 349 handle_WM_MBUTTONDOWN(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 350 { 351 g_mousex = LOWORD(lParam); 352 g_mousey = HIWORD(lParam); 353 ui_mouse_button(3, g_mousex + g_xscroll, g_mousey + g_yscroll, 1); 354 return 0; 355 } 356 357 /*****************************************************************************/ 358 static LRESULT 359 handle_WM_MBUTTONUP(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 360 { 361 g_mousex = LOWORD(lParam); 362 g_mousey = HIWORD(lParam); 363 ui_mouse_button(3, g_mousex + g_xscroll, g_mousey + g_yscroll, 0); 364 return 0; 365 } 366 367 /*****************************************************************************/ 368 static LRESULT 369 handle_WM_MOUSEWHEEL(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 370 { 371 int delta; 372 373 delta = ((signed short)HIWORD(wParam)); /* GET_WHEEL_DELTA_WPARAM(wParam); */ 374 if (delta > 0) 375 { 376 ui_mouse_button(4, 0, 0, 1); 377 ui_mouse_button(4, 0, 0, 0); 378 } 379 else 380 { 381 ui_mouse_button(5, 0, 0, 1); 382 ui_mouse_button(5, 0, 0, 0); 383 } 384 return 0; 385 } 386 387 /*****************************************************************************/ 388 static LRESULT 389 handle_WM_KEY(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 390 { 391 int scancode; 392 int ext; 393 int down; 394 395 ext = HIWORD(lParam); 396 scancode = ext; 397 down = !(ext & 0x8000); 398 scancode &= 0xff; 399 if (scancode == 0) 400 { 401 scancode = get_scan_code_from_ascii(wParam); 402 } 403 ext &= 0x0100; 404 if (scancode == 0x0045) /* num lock */ 405 { 406 ext &= ~0x0100; 407 } 408 if (down) 409 { 410 ui_key_down(scancode, ext); 411 } 412 else 413 { 414 ui_key_up(scancode, ext); 415 } 416 return 0; 417 } 418 419 /*****************************************************************************/ 420 static LRESULT 421 handle_WM_PAINT(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 422 { 423 PAINTSTRUCT ps; 424 RECT rect; 425 HBRUSH brush; 426 427 BeginPaint(hWnd, &ps); 428 /* paint the area outside the rdp screen with one colour */ 429 rect = ps.rcPaint; 430 rect.left = UI_MAX(rect.left, g_width); 431 if (!IsRectEmpty(&rect)) 432 { 433 brush = CreateSolidBrush(RGB(0, 0, 255)); 434 FillRect(ps.hdc, &rect, brush); 435 DeleteObject(brush); 436 } 437 rect = ps.rcPaint; 438 rect.top = UI_MAX(rect.top, g_height); 439 if (!IsRectEmpty(&rect)) 440 { 441 brush = CreateSolidBrush(RGB(0, 0, 255)); 442 FillRect(ps.hdc, &rect, brush); 443 DeleteObject(brush); 444 } 445 rect = ps.rcPaint; 446 EndPaint(hWnd, &ps); 447 ui_invalidate(rect.left + g_xscroll, 448 rect.top + g_yscroll, 449 (rect.right - rect.left) + 1, 450 (rect.bottom - rect.top) + 1); 451 return 0; 452 } 453 454 /*****************************************************************************/ 455 static LRESULT 456 handle_WM_SIZE(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 457 { 458 int oldxscroll; 459 int oldyscroll; 460 461 if (wParam == SIZE_MINIMIZED) 462 { 463 return DefWindowProc(hWnd, message, wParam, lParam); 464 } 465 g_wnd_cwidth = LOWORD(lParam); /* client width / height */ 466 g_wnd_cheight = HIWORD(lParam); 467 g_wnd_clip.left = 0; 468 g_wnd_clip.top = 0; 469 g_wnd_clip.right = g_wnd_clip.left + g_wnd_cwidth; 470 g_wnd_clip.bottom = g_wnd_clip.top + g_wnd_cheight; 471 if (g_wnd_cwidth < g_width || g_wnd_cheight < g_height) 472 { 473 SetScrollRange(g_Wnd, SB_HORZ, 0, g_width - g_wnd_cwidth, 1); 474 SetScrollRange(g_Wnd, SB_VERT, 0, g_height - g_wnd_cheight, 1); 475 } 476 oldxscroll = g_xscroll; 477 oldyscroll = g_yscroll; 478 if (g_wnd_cwidth >= g_width) 479 { 480 g_xscroll = 0; 481 } 482 else 483 { 484 g_xscroll = UI_MIN(g_xscroll, g_width - g_wnd_cwidth); 485 } 486 if (g_wnd_cheight >= g_height) 487 { 488 g_yscroll = 0; 489 } 490 else 491 { 492 g_yscroll = UI_MIN(g_yscroll, g_height - g_wnd_cheight); 493 } 494 mi_scroll(oldxscroll - g_xscroll, oldyscroll - g_yscroll); 495 if (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED) 496 { 497 /* check the caps, num, and scroll lock here */ 498 mi_check_modifier(); 499 } 500 return 0; 501 } 502 503 /*****************************************************************************/ 504 static LRESULT 505 handle_WM_SIZING(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 506 { 507 LPRECT prect; 508 int width; 509 int height; 510 int style; 511 512 prect = (LPRECT) lParam; /* total window rect */ 513 width = (prect->right - prect->left) - (g_xoff * 2); 514 height = (prect->bottom - prect->top) - (g_yoff + g_xoff); 515 if (height < g_height || width < g_width) 516 { 517 style = GetWindowLongPtr(g_Wnd, GWL_STYLE); 518 if (!(style & WS_HSCROLL)) 519 { 520 style |= WS_HSCROLL | WS_VSCROLL; 521 SetWindowLongPtr(g_Wnd, GWL_STYLE, style); 522 g_xscroll = 0; 523 g_yscroll = 0; 524 SetScrollPos(g_Wnd, SB_HORZ, g_xscroll, 1); 525 SetScrollPos(g_Wnd, SB_VERT, g_yscroll, 1); 526 } 527 } 528 else if (height >= g_height && width >= g_width) 529 { 530 style = GetWindowLongPtr(g_Wnd, GWL_STYLE); 531 if (style & WS_HSCROLL) 532 { 533 style &= ~WS_HSCROLL; 534 style &= ~WS_VSCROLL; 535 SetWindowLongPtr(g_Wnd, GWL_STYLE, style); 536 g_xscroll = 0; 537 g_yscroll = 0; 538 } 539 } 540 return 0; 541 } 542 543 /*****************************************************************************/ 544 static LRESULT 545 handle_WM_HSCROLL(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 546 { 547 int code; 548 int oldxscroll; 549 550 code = (int) LOWORD(wParam); /* scroll bar value */ 551 if (code == SB_LINELEFT) 552 { 553 oldxscroll = g_xscroll; 554 g_xscroll--; 555 g_xscroll = UI_MAX(g_xscroll, 0); 556 SetScrollPos(g_Wnd, SB_HORZ, g_xscroll, 1); 557 mi_scroll(oldxscroll - g_xscroll, 0); 558 } 559 else if (code == SB_LINERIGHT) 560 { 561 oldxscroll = g_xscroll; 562 g_xscroll++; 563 g_xscroll = UI_MIN(g_xscroll, g_width - g_wnd_cwidth); 564 SetScrollPos(g_Wnd, SB_HORZ, g_xscroll, 1); 565 mi_scroll(oldxscroll - g_xscroll, 0); 566 } 567 else if (code == SB_PAGELEFT) 568 { 569 oldxscroll = g_xscroll; 570 g_xscroll -= g_wnd_cwidth / 2; 571 g_xscroll = UI_MAX(g_xscroll, 0); 572 SetScrollPos(g_Wnd, SB_HORZ, g_xscroll, 1); 573 mi_scroll(oldxscroll - g_xscroll, 0); 574 } 575 else if (code == SB_PAGERIGHT) 576 { 577 oldxscroll = g_xscroll; 578 g_xscroll += g_wnd_cwidth / 2; 579 g_xscroll = UI_MIN(g_xscroll, g_width - g_wnd_cwidth); 580 SetScrollPos(g_Wnd, SB_HORZ, g_xscroll, 1); 581 mi_scroll(oldxscroll - g_xscroll, 0); 582 } 583 else if (code == SB_BOTTOM) 584 { 585 oldxscroll = g_xscroll; 586 g_xscroll = g_width - g_wnd_cwidth; 587 SetScrollPos(g_Wnd, SB_HORZ, g_xscroll, 1); 588 mi_scroll(oldxscroll - g_xscroll, 0); 589 } 590 else if (code == SB_TOP) 591 { 592 oldxscroll = g_xscroll; 593 g_xscroll = 0; 594 SetScrollPos(g_Wnd, SB_HORZ, g_xscroll, 1); 595 mi_scroll(oldxscroll - g_xscroll, 0); 596 } 597 else if (code == SB_THUMBPOSITION) 598 { 599 oldxscroll = g_xscroll; 600 g_xscroll = (signed short) HIWORD(wParam); 601 SetScrollPos(g_Wnd, SB_HORZ, g_xscroll, 1); 602 mi_scroll(oldxscroll - g_xscroll, 0); 603 } 604 return 0; 605 } 606 607 /*****************************************************************************/ 608 static LRESULT 609 handle_WM_VSCROLL(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 610 { 611 int code; 612 int oldyscroll; 613 614 code = (int) LOWORD(wParam); /* scroll bar value */ 615 if (code == SB_LINELEFT) 616 { 617 oldyscroll = g_yscroll; 618 g_yscroll--; 619 g_yscroll = UI_MAX(g_yscroll, 0); 620 SetScrollPos(g_Wnd, SB_VERT, g_yscroll, 1); 621 mi_scroll(0, oldyscroll - g_yscroll); 622 } 623 else if (code == SB_LINERIGHT) 624 { 625 oldyscroll = g_yscroll; 626 g_yscroll++; 627 g_yscroll = UI_MIN(g_yscroll, g_height - g_wnd_cheight); 628 SetScrollPos(g_Wnd, SB_VERT, g_yscroll, 1); 629 mi_scroll(0, oldyscroll - g_yscroll); 630 } 631 else if (code == SB_PAGELEFT) 632 { 633 oldyscroll = g_yscroll; 634 g_yscroll -= g_wnd_cheight / 2; 635 g_yscroll = UI_MAX(g_yscroll, 0); 636 SetScrollPos(g_Wnd, SB_VERT, g_yscroll, 1); 637 mi_scroll(0, oldyscroll - g_yscroll); 638 } 639 else if (code == SB_PAGERIGHT) 640 { 641 oldyscroll = g_yscroll; 642 g_yscroll += g_wnd_cheight / 2; 643 g_yscroll = UI_MIN(g_yscroll, g_height - g_wnd_cheight); 644 SetScrollPos(g_Wnd, SB_VERT, g_yscroll, 1); 645 mi_scroll(0, oldyscroll - g_yscroll); 646 } 647 else if (code == SB_BOTTOM) 648 { 649 oldyscroll = g_yscroll; 650 g_yscroll = g_height - g_wnd_cheight; 651 SetScrollPos(g_Wnd, SB_VERT, g_yscroll, 1); 652 mi_scroll(0, oldyscroll - g_yscroll); 653 } 654 else if (code == SB_TOP) 655 { 656 oldyscroll = g_yscroll; 657 g_yscroll = 0; 658 SetScrollPos(g_Wnd, SB_VERT, g_yscroll, 1); 659 mi_scroll(0, oldyscroll - g_yscroll); 660 } 661 else if (code == SB_THUMBPOSITION) 662 { 663 oldyscroll = g_yscroll; 664 g_yscroll = (signed short) HIWORD(wParam); 665 SetScrollPos(g_Wnd, SB_VERT, g_yscroll, 1); 666 mi_scroll(0, oldyscroll - g_yscroll); 667 } 668 return 0; 669 } 670 671 672 /*****************************************************************************/ 673 LRESULT CALLBACK 674 WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 675 { 676 switch (message) 677 { 678 case WM_SETCURSOR: 679 return handle_WM_SETCURSOR(hWnd, message, wParam, lParam); 680 case 0x0084: /* WinCE don't have this WM_NCHITTEST: */ 681 return handle_WM_NCHITTEST(hWnd, message, wParam, lParam); 682 case WM_MOUSEMOVE: 683 return handle_WM_MOUSEMOVE(hWnd, message, wParam, lParam); 684 case WM_LBUTTONDOWN: 685 return handle_WM_LBUTTONDOWN(hWnd, message, wParam, lParam); 686 case WM_LBUTTONUP: 687 return handle_WM_LBUTTONUP(hWnd, message, wParam, lParam); 688 case WM_RBUTTONDOWN: 689 return handle_WM_RBUTTONDOWN(hWnd, message, wParam, lParam); 690 case WM_RBUTTONUP: 691 return handle_WM_RBUTTONUP(hWnd, message, wParam, lParam); 692 case WM_MBUTTONDOWN: 693 return handle_WM_MBUTTONDOWN(hWnd, message, wParam, lParam); 694 case WM_MBUTTONUP: 695 return handle_WM_MBUTTONUP(hWnd, message, wParam, lParam); 696 /* some windows compilers don't have these defined like vc6 */ 697 case 0x020a: /* WM_MOUSEWHEEL: */ 698 return handle_WM_MOUSEWHEEL(hWnd, message, wParam, lParam); 699 case WM_KEYDOWN: 700 case WM_KEYUP: 701 case WM_SYSKEYDOWN: 702 case WM_SYSKEYUP: 703 return handle_WM_KEY(hWnd, message, wParam, lParam); 704 case WM_CHAR: 705 case WM_DEADCHAR: 706 case WM_SYSCHAR: 707 case WM_SYSDEADCHAR: 708 break; 709 case WM_PAINT: 710 return handle_WM_PAINT(hWnd, message, wParam, lParam); 711 case WM_DESTROY: 712 PostQuitMessage(0); 713 break; 714 case WM_APP + 1: 715 case WM_TIMER: 716 check_sck(); 717 break; 718 case WM_SIZE: 719 return handle_WM_SIZE(hWnd, message, wParam, lParam); 720 case 532: /* not defined in wince WM_SIZING: */ 721 return handle_WM_SIZING(hWnd, message, wParam, lParam); 722 case WM_HSCROLL: 723 return handle_WM_HSCROLL(hWnd, message, wParam, lParam); 724 case WM_VSCROLL: 725 return handle_WM_VSCROLL(hWnd, message, wParam, lParam); 726 case WM_SETFOCUS: 727 mi_check_modifier(); 728 return DefWindowProc(hWnd, message, wParam, lParam); 729 default: 730 return DefWindowProc(hWnd, message, wParam, lParam); 731 } 732 return 0; 733 } 734 735 /*****************************************************************************/ 736 static HRGN 737 mi_clip(HDC dc) 738 { 739 HRGN rgn; 740 741 rgn = CreateRectRgn(g_clip_left + g_xoff - g_xscroll, 742 g_clip_top + g_yoff - g_yscroll, 743 g_clip_right + g_xoff - g_xscroll, 744 g_clip_bottom + g_yoff - g_yscroll); 745 SelectClipRgn(dc, rgn); 746 IntersectClipRect(dc, g_wnd_clip.left + g_xoff, g_wnd_clip.top + g_yoff, 747 g_wnd_clip.right + g_xoff, g_wnd_clip.bottom + g_yoff); 748 return rgn; 749 } 750 751 /*****************************************************************************/ 752 /* returns non zero if ok */ 753 int 754 mi_create_window(void) 755 { 756 RECT rc; 757 WNDCLASS wc; 758 TCHAR classname[512]; 759 TCHAR caption[512]; 760 DWORD style; 761 int x; 762 int y; 763 int w; 764 int h; 765 766 if (g_Wnd != 0 || g_Instance != 0) 767 { 768 return 0; 769 } 770 g_Instance = GetModuleHandle(NULL); 771 ZeroMemory(&wc, sizeof(wc)); 772 wc.lpfnWndProc = WndProc; /* points to window procedure */ 773 /* name of window class */ 774 str_to_uni(classname, "rdesktop"); 775 wc.lpszClassName = classname; 776 str_to_uni(caption, "ReactOS Remote Desktop"); 777 wc.hIcon = LoadIcon(g_Instance, 778 MAKEINTRESOURCE(IDI_MSTSC)); 779 /* Register the window class. */ 780 if (!RegisterClass(&wc)) 781 { 782 return 0; /* Failed to register window class */ 783 } 784 rc.left = 0; 785 rc.right = rc.left + UI_MIN(g_width, g_screen_width); 786 rc.top = 0; 787 rc.bottom = rc.top + UI_MIN(g_height, g_screen_height); 788 789 if (g_fullscreen) 790 { 791 style = WS_POPUP; 792 } 793 else 794 { 795 style = WS_OVERLAPPED | WS_CAPTION | WS_POPUP | WS_MINIMIZEBOX | 796 WS_SYSMENU | WS_SIZEBOX | WS_MAXIMIZEBOX; 797 } 798 if (g_screen_width < g_width || g_screen_height < g_height) 799 { 800 style |= WS_HSCROLL | WS_VSCROLL; 801 } 802 AdjustWindowRectEx(&rc, style, 0, 0); 803 x = CW_USEDEFAULT; 804 y = CW_USEDEFAULT; 805 w = rc.right - rc.left; 806 h = rc.bottom - rc.top; 807 808 g_Wnd = CreateWindow(wc.lpszClassName, caption, 809 style, x, y, w, h, 810 (HWND) NULL, (HMENU) NULL, g_Instance, 811 (LPVOID) NULL); 812 g_clip_left = 0; 813 g_clip_top = 0; 814 g_clip_right = g_clip_left + g_width; 815 g_clip_bottom = g_clip_top + g_height; 816 if (g_workarea) 817 { 818 ShowWindow(g_Wnd, SW_SHOWMAXIMIZED); 819 } 820 else 821 { 822 ShowWindow(g_Wnd, SW_SHOWNORMAL); 823 } 824 UpdateWindow(g_Wnd); 825 826 WSAAsyncSelect(g_tcp_sck, g_Wnd, WM_APP + 1, FD_READ); 827 SetTimer(g_Wnd, 1, 333, 0); 828 829 return 1; 830 } 831 832 /*****************************************************************************/ 833 int 834 mi_main_loop(void) 835 { 836 MSG msg; 837 838 while (GetMessage(&msg, NULL, 0, 0)) 839 { 840 TranslateMessage(&msg); 841 DispatchMessage(&msg); 842 } 843 return msg.wParam; 844 } 845 846 /*****************************************************************************/ 847 void 848 mi_warning(char * msg) 849 { 850 } 851 852 /*****************************************************************************/ 853 static void 854 mi_show_error(char * caption) 855 { 856 LPVOID lpMsgBuf; 857 TCHAR lcaption[512]; 858 859 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 860 NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 861 (LPTSTR) &lpMsgBuf, 0, NULL); 862 #ifdef WITH_DEBUG 863 printf(lpMsgBuf); 864 #else /* WITH_DEBUG */ 865 str_to_uni(lcaption, caption); 866 MessageBox(g_Wnd, (LPTSTR) lpMsgBuf, lcaption, 867 MB_OK | MB_ICONINFORMATION); 868 #endif /* WITH_DEBUG */ 869 LocalFree(lpMsgBuf); 870 } 871 872 /*****************************************************************************/ 873 void 874 mi_paint_rect(char * data, int width, int height, int x, int y, int cx, int cy) 875 { 876 HBITMAP bitmap; 877 BITMAPINFO bi; 878 HDC dc; 879 HDC maindc; 880 HGDIOBJ save; 881 HRGN rgn; 882 void * bits; 883 int i; 884 int j; 885 int colour; 886 int red; 887 int green; 888 int blue; 889 int index; 890 891 ZeroMemory(&bi, sizeof(bi)); 892 bi.bmiHeader.biSize = sizeof(bi.bmiHeader); 893 bi.bmiHeader.biWidth = width; 894 bi.bmiHeader.biHeight = -height; 895 bi.bmiHeader.biPlanes = 1; 896 bi.bmiHeader.biBitCount = 32; 897 bi.bmiHeader.biCompression = BI_RGB; 898 maindc = GetWindowDC(g_Wnd); 899 bitmap = CreateDIBSection(maindc, &bi, DIB_RGB_COLORS, (void **) &bits, 0, 0); 900 if (bitmap == 0) 901 { 902 mi_show_error("CreateDIBSection failed"); 903 } 904 905 if (g_server_depth == 8) 906 { 907 for (i = cy - 1; i >= 0; i--) 908 { 909 for (j = cx - 1; j >= 0; j--) 910 { 911 colour = ((unsigned char*)data)[i * cx + j]; 912 red = (pal_entries[colour & 0xff] & 0xff0000) >> 16; 913 green = (pal_entries[colour & 0xff] & 0xff00) >> 8; 914 blue = pal_entries[colour & 0xff] & 0xff; 915 MAKE_COLOUR32(colour, red, green, blue); 916 ((unsigned int*)bits)[i * cx + j] = colour; 917 } 918 } 919 } 920 else if (g_server_depth == 15) 921 { 922 for (i = cy - 1; i >= 0; i--) 923 { 924 for (j = cx - 1; j >= 0; j--) 925 { 926 colour = ((unsigned short*)data)[i * cx + j]; 927 SPLIT_COLOUR15(colour, red, green, blue); 928 MAKE_COLOUR32(colour, red, green, blue); 929 ((unsigned int*)bits)[i * cx + j] = colour; 930 } 931 } 932 } 933 else if (g_server_depth == 16) 934 { 935 for (i = cy - 1; i >= 0; i--) 936 { 937 for (j = cx - 1; j >= 0; j--) 938 { 939 colour = ((unsigned short*)data)[i * cx + j]; 940 SPLIT_COLOUR16(colour, red, green, blue); 941 MAKE_COLOUR32(colour, red, green, blue); 942 ((unsigned int*)bits)[i * cx + j] = colour; 943 } 944 } 945 } 946 else if (g_server_depth == 24) 947 { 948 for (i = cy - 1; i >= 0; i--) 949 { 950 for (j = cx - 1; j >= 0; j--) 951 { 952 index = (i * cx + j) * 3; 953 red = ((unsigned char*)data)[index + 2]; 954 green = ((unsigned char*)data)[index + 1]; 955 blue = ((unsigned char*)data)[index]; 956 MAKE_COLOUR32(colour, red, green, blue); 957 ((unsigned int*)bits)[i * cx + j] = colour; 958 } 959 } 960 } 961 else if (g_server_depth == 32) 962 { 963 memcpy(bits, data, cx*cy*4); 964 } 965 dc = CreateCompatibleDC(maindc); 966 if (dc == 0) 967 { 968 mi_show_error("CreateCompatibleDC failed"); 969 } 970 save = SelectObject(dc, bitmap); 971 rgn = mi_clip(maindc); 972 BitBlt(maindc, x + g_xoff - g_xscroll, y + g_yoff - g_yscroll, cx, cy, dc, 973 0, 0, SRCCOPY); 974 SelectObject(dc, save); 975 DeleteObject(bitmap); 976 DeleteDC(dc); 977 ReleaseDC(g_Wnd, maindc); 978 DeleteObject(rgn); 979 980 } 981 982 static INT 983 GetPortNumber(PCHAR szAddress) 984 { 985 PCHAR szPort; 986 INT iPort = TCP_PORT_RDP; 987 988 szPort = strtok(szAddress, ":"); 989 990 if (szPort != NULL) 991 { 992 szPort = strtok(NULL, ":"); 993 994 if (szPort != NULL) 995 { 996 iPort = atoi(szPort); 997 998 if (iPort <= 0 || iPort > 0xFFFF) 999 iPort = TCP_PORT_RDP; 1000 } 1001 } 1002 1003 return iPort; 1004 } 1005 1006 static VOID 1007 SetDomainAndUsername(PCHAR pName) 1008 { 1009 PCHAR pDomain; 1010 PCHAR pUsername; 1011 1012 strcpy(g_domain, ""); 1013 strcpy(g_username, ""); 1014 1015 pDomain = strtok(pName, "\\"); 1016 1017 if(pDomain == NULL) 1018 return; 1019 1020 pUsername = strtok(NULL, "\\"); 1021 1022 if(pUsername == NULL) 1023 { 1024 strcpy(g_username, pDomain); 1025 return; 1026 } 1027 1028 strcpy(g_username, pUsername); 1029 strcpy(g_domain, pDomain); 1030 return; 1031 } 1032 1033 static BOOL 1034 ParseCommandLine(LPWSTR lpCmdLine, 1035 PRDPSETTINGS pRdpSettings, 1036 BOOL *bSkipDlg) 1037 { 1038 LPWSTR lpStr = lpCmdLine; 1039 WCHAR szSeps[] = L"/"; 1040 LPWSTR lpToken; 1041 BOOL bRet = TRUE; 1042 1043 *bSkipDlg = TRUE; 1044 1045 if (*lpCmdLine != L'/') 1046 { 1047 LoadRdpSettingsFromFile(pRdpSettings, lpCmdLine); 1048 } 1049 else 1050 { 1051 /* default to screen size, 16bpp */ 1052 SetIntegerToSettings(pRdpSettings, L"session bpp", 16); 1053 SetIntegerToSettings(pRdpSettings, L"desktopwidth", GetSystemMetrics(SM_CXSCREEN)); 1054 SetIntegerToSettings(pRdpSettings, L"desktopheight", GetSystemMetrics(SM_CYSCREEN)); 1055 1056 lpToken = wcstok(lpStr, szSeps); 1057 while (lpToken) 1058 { 1059 if (wcsncmp(lpToken, L"edit", 4) == 0) 1060 { 1061 lpToken += 5; 1062 LoadRdpSettingsFromFile(pRdpSettings, lpToken); 1063 *bSkipDlg = FALSE; 1064 break; 1065 } 1066 1067 if (*lpToken == L'v') 1068 { 1069 lpToken += 2; 1070 SetStringToSettings(pRdpSettings, L"full address", lpToken); 1071 } 1072 else if (*lpToken == L'w') 1073 { 1074 lpToken += 2; 1075 SetIntegerToSettings(pRdpSettings, L"desktopwidth", _wtoi(lpToken)); 1076 } 1077 else if (*lpToken == L'h') 1078 { 1079 lpToken += 2; 1080 SetIntegerToSettings(pRdpSettings, L"desktopheight", _wtoi(lpToken)); 1081 } 1082 else if (*lpToken == L'f') 1083 { 1084 SetIntegerToSettings(pRdpSettings, L"screen mode id", 2); 1085 } 1086 1087 lpToken = wcstok(NULL, szSeps); 1088 } 1089 } 1090 1091 return bRet; 1092 } 1093 1094 /*****************************************************************************/ 1095 int WINAPI 1096 wWinMain(HINSTANCE hInstance, 1097 HINSTANCE hPrevInstance, 1098 LPWSTR lpCmdLine, 1099 int nCmdShow) 1100 { 1101 PRDPSETTINGS pRdpSettings; 1102 WSADATA d; 1103 int ret = 1; 1104 1105 if (WSAStartup(MAKEWORD(2, 0), &d) == 0) 1106 { 1107 pRdpSettings = HeapAlloc(GetProcessHeap(), 1108 0, 1109 sizeof(RDPSETTINGS)); 1110 if (pRdpSettings) 1111 { 1112 pRdpSettings->pSettings = NULL; 1113 pRdpSettings->NumSettings = 0; 1114 1115 if (InitRdpSettings(pRdpSettings)) 1116 { 1117 BOOL bSkipDlg = FALSE; 1118 1119 if (*lpCmdLine) 1120 ParseCommandLine(lpCmdLine, pRdpSettings,&bSkipDlg); 1121 else 1122 LoadRdpSettingsFromFile(pRdpSettings, NULL); 1123 1124 if (bSkipDlg || OpenRDPConnectDialog(hInstance, 1125 pRdpSettings)) 1126 { 1127 char szValue[MAXVALUE]; 1128 DWORD dwSize = MAXVALUE; 1129 1130 uni_to_str(szValue, GetStringFromSettings(pRdpSettings, L"full address")); 1131 1132 /* GetPortNumber also removes possible trailing port number from address */ 1133 g_tcp_port_rdp = GetPortNumber(szValue); 1134 strcpy(g_servername, szValue); 1135 uni_to_str(szValue, GetStringFromSettings(pRdpSettings, L"username")); 1136 SetDomainAndUsername(szValue); 1137 strcpy(g_password, ""); 1138 if (GetComputerNameA(szValue, &dwSize)) 1139 strcpy(g_hostname, szValue); 1140 else 1141 strcpy(g_hostname, tcp_get_address()); 1142 g_server_depth = GetIntegerFromSettings(pRdpSettings, L"session bpp"); 1143 g_screen_width = GetSystemMetrics(SM_CXSCREEN); 1144 g_screen_height = GetSystemMetrics(SM_CYSCREEN); 1145 g_width = GetIntegerFromSettings(pRdpSettings, L"desktopwidth"); 1146 g_height = GetIntegerFromSettings(pRdpSettings, L"desktopheight"); 1147 if (GetIntegerFromSettings(pRdpSettings, L"screen mode id") == 2) 1148 { 1149 g_fullscreen = 1; 1150 g_xoff = 0; 1151 g_yoff = 0; 1152 } 1153 else 1154 { 1155 g_xoff = GetSystemMetrics(SM_CXEDGE) * 2; 1156 g_yoff = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYEDGE) * 2; 1157 } 1158 1159 ui_main(); 1160 ret = 0; 1161 } 1162 1163 HeapFree(GetProcessHeap(), 1164 0, 1165 pRdpSettings->pSettings); 1166 } 1167 1168 HeapFree(GetProcessHeap(), 1169 0, 1170 pRdpSettings); 1171 } 1172 1173 WSACleanup(); 1174 } 1175 1176 return ret; 1177 } 1178 1179 1180 /*****************************************************************************/ 1181 void 1182 mi_begin_update(void) 1183 { 1184 } 1185 1186 /*****************************************************************************/ 1187 void 1188 mi_end_update(void) 1189 { 1190 } 1191 1192 /*****************************************************************************/ 1193 void 1194 mi_fill_rect(int x, int y, int cx, int cy, int colour) 1195 { 1196 HBRUSH brush; 1197 RECT rect; 1198 HDC maindc; 1199 HRGN rgn; 1200 int red; 1201 int green; 1202 int blue; 1203 1204 if (g_server_depth == 8) 1205 { 1206 red = (pal_entries[colour & 0xff] & 0xff0000) >> 16; 1207 green = (pal_entries[colour & 0xff] & 0xff00) >> 8; 1208 blue = pal_entries[colour & 0xff] & 0xff; 1209 } 1210 else if (g_server_depth == 15) 1211 { 1212 SPLIT_COLOUR15(colour, red, green, blue); 1213 } 1214 else if (g_server_depth == 16) 1215 { 1216 SPLIT_COLOUR16(colour, red, green, blue); 1217 } 1218 else if (g_server_depth == 24 || g_server_depth == 32) 1219 { 1220 red = (colour>>16)&0xff; 1221 green = (colour>>8)&0xff; 1222 blue = colour&0xff; 1223 } 1224 maindc = GetWindowDC(g_Wnd); 1225 rgn = mi_clip(maindc); 1226 brush = CreateSolidBrush(RGB(red, green, blue)); 1227 rect.left = x + g_xoff - g_xscroll; 1228 rect.top = y + g_yoff - g_yscroll; 1229 rect.right = rect.left + cx; 1230 rect.bottom = rect.top + cy; 1231 FillRect(maindc, &rect, brush); 1232 DeleteObject(brush); 1233 ReleaseDC(g_Wnd, maindc); 1234 DeleteObject(rgn); 1235 } 1236 1237 /*****************************************************************************/ 1238 void 1239 mi_line(int x1, int y1, int x2, int y2, int colour) 1240 { 1241 HPEN pen; 1242 HDC maindc; 1243 HGDIOBJ save; 1244 HRGN rgn; 1245 int red; 1246 int green; 1247 int blue; 1248 1249 if (g_server_depth == 8) 1250 { 1251 red = (pal_entries[colour & 0xff] & 0xff0000) >> 16; 1252 green = (pal_entries[colour & 0xff] & 0xff00) >> 8; 1253 blue = pal_entries[colour & 0xff] & 0xff; 1254 } 1255 else if (g_server_depth == 15) 1256 { 1257 SPLIT_COLOUR15(colour, red, green, blue); 1258 } 1259 else if (g_server_depth == 16) 1260 { 1261 SPLIT_COLOUR16(colour, red, green, blue); 1262 } 1263 else if (g_server_depth == 24 || g_server_depth == 32) 1264 { 1265 red = (colour>>16)&0xff; 1266 green = (colour>>8)&0xff; 1267 blue = colour&0xff; 1268 } 1269 maindc = GetWindowDC(g_Wnd); 1270 rgn = mi_clip(maindc); 1271 pen = CreatePen(PS_SOLID, 0, RGB(red, green, blue)); 1272 save = SelectObject(maindc, pen); 1273 MoveToEx(maindc, x1 + g_xoff - g_xscroll, y1 + g_yoff - g_yscroll, 0); 1274 LineTo(maindc, x2 + g_xoff - g_xscroll, y2 + g_yoff - g_yscroll); 1275 SelectObject(maindc, save); 1276 DeleteObject(pen); 1277 ReleaseDC(g_Wnd, maindc); 1278 DeleteObject(rgn); 1279 } 1280 1281 /*****************************************************************************/ 1282 void 1283 mi_screen_copy(int x, int y, int cx, int cy, int srcx, int srcy) 1284 { 1285 RECT rect; 1286 RECT clip_rect; 1287 RECT draw_rect; 1288 HRGN rgn; 1289 int ok_to_ScrollWindowEx; 1290 1291 ok_to_ScrollWindowEx = 1; 1292 1293 if (!ok_to_ScrollWindowEx) 1294 { 1295 rgn = CreateRectRgn(x - g_xscroll, y - g_yscroll, 1296 (x - g_xscroll) + cx, 1297 (y - g_yscroll) + cy); 1298 InvalidateRgn(g_Wnd, rgn, 0); 1299 DeleteObject(rgn); 1300 } 1301 else 1302 { 1303 /* this is all in client coords */ 1304 rect.left = srcx - g_xscroll; 1305 rect.top = srcy - g_yscroll; 1306 rect.right = rect.left + cx; 1307 rect.bottom = rect.top + cy; 1308 clip_rect.left = g_clip_left - g_xscroll; 1309 clip_rect.top = g_clip_top - g_yscroll; 1310 clip_rect.right = g_clip_right - g_xscroll; 1311 clip_rect.bottom = g_clip_bottom - g_yscroll; 1312 if (IntersectRect(&draw_rect, &clip_rect, &g_wnd_clip)) 1313 { 1314 rgn = CreateRectRgn(0, 0, 0, 0); 1315 ScrollWindowEx(g_Wnd, x - srcx, y - srcy, &rect, &draw_rect, 1316 rgn, 0, SW_ERASE); 1317 InvalidateRgn(g_Wnd, rgn, 0); 1318 DeleteObject(rgn); 1319 } 1320 } 1321 } 1322 1323 /*****************************************************************************/ 1324 void 1325 mi_set_clip(int x, int y, int cx, int cy) 1326 { 1327 g_clip_left = x; 1328 g_clip_top = y; 1329 g_clip_right = g_clip_left + cx; 1330 g_clip_bottom = g_clip_top + cy; 1331 } 1332 1333 /*****************************************************************************/ 1334 void 1335 mi_reset_clip(void) 1336 { 1337 g_clip_left = 0; 1338 g_clip_top = 0; 1339 g_clip_right = g_clip_left + g_width; 1340 g_clip_bottom = g_clip_top + g_height; 1341 } 1342 1343 /*****************************************************************************/ 1344 void * 1345 mi_create_cursor(unsigned int x, unsigned int y, 1346 int width, int height, 1347 unsigned char * andmask, unsigned char * xormask) 1348 { 1349 HCURSOR hCur; 1350 1351 hCur = CreateCursor(g_Instance, x, y, width, height, andmask, xormask); 1352 if (hCur == 0) 1353 { 1354 hCur = LoadCursor(NULL, IDC_ARROW); 1355 } 1356 return hCur; 1357 } 1358 1359 /*****************************************************************************/ 1360 void 1361 mi_destroy_cursor(void * cursor) 1362 { 1363 if (g_cursor == cursor) 1364 { 1365 g_cursor = 0; 1366 } 1367 DestroyCursor(cursor); 1368 } 1369 1370 /*****************************************************************************/ 1371 void 1372 mi_set_cursor(void * cursor) 1373 { 1374 g_cursor = cursor; 1375 SetCursor(g_cursor); 1376 } 1377 1378 /*****************************************************************************/ 1379 void 1380 mi_set_null_cursor(void) 1381 { 1382 } 1383 1384