/************************************************************************/ /* KEGS: Apple //gs Emulator */ /* Copyright 2002 by Kent Dickey */ /* */ /* This code is covered by the GNU GPL */ /* */ /* The KEGS web page is kegs.sourceforge.net */ /* You may contact the author at: kadickey@alumni.princeton.edu */ /************************************************************************/ const char rcsid_windriver_c[] = "@(#)$KmKId: windriver.c,v 1.11 2004-11-24 16:43:46-05 kentd Exp $"; /* Based on code from Chea Chee Keong from KEGS32, which is available at */ /* http://www.geocities.com/akilgard/kegs32 */ #define WIN32_LEAN_AND_MEAN /* Tell windows we want less header gunk */ #define STRICT /* Tell Windows we want compile type checks */ #include #include #include #include #include #include "defc.h" #include "protos_windriver.h" extern int Verbose; extern int g_warp_pointer; extern int g_screen_depth; extern int g_force_depth; int g_screen_mdepth = 0; extern int g_quit_sim_now; int g_use_shmem = 1; int g_has_focus = 0; int g_auto_repeat_on = -1; extern Kimage g_mainwin_kimage; HDC g_main_dc; HDC g_main_cdc; int g_main_height = 0; int g_win_capslock_down = 0; extern word32 g_palette_8to1624[256]; extern word32 g_a2palette_8to1624[256]; extern word32 g_full_refresh_needed; extern int g_border_sides_refresh_needed; extern int g_border_special_refresh_needed; extern int g_status_refresh_needed; extern int g_lores_colors[]; extern int g_cur_a2_stat; extern int g_a2vid_palette; extern int g_installed_full_superhires_colormap; extern int g_screen_redraw_skip_amt; extern word32 g_a2_screen_buffer_changed; HWND g_hwnd_main; BITMAPINFO *g_bmapinfo_ptr = 0; volatile BITMAPINFOHEADER *g_bmaphdr_ptr = 0; int g_num_a2_keycodes = 0; extern char *g_status_ptrs[MAX_STATUS_LINES]; int g_win_button_states = 0; /* this table is used to search for the Windows VK_* in col 1 or 2 */ /* flags bit 8 is or'ed into the VK, so we can distinguish keypad keys */ /* regardless of numlock */ int g_a2_key_to_wsym[][3] = { { 0x35, VK_ESCAPE, 0 }, { 0x7a, VK_F1, 0 }, { 0x7b, VK_F2, 0 }, { 0x63, VK_F3, 0 }, { 0x76, VK_F4, 0 }, { 0x60, VK_F5, 0 }, { 0x61, VK_F6, 0 }, { 0x62, VK_F7, 0 }, { 0x64, VK_F8, 0 }, { 0x65, VK_F9, 0 }, { 0x6d, VK_F10, 0 }, { 0x67, VK_F11, 0 }, { 0x6f, VK_F12, 0 }, { 0x69, VK_F13, 0 }, { 0x6b, VK_F14, 0 }, { 0x71, VK_F15, 0 }, { 0x7f, VK_PAUSE, VK_CANCEL+0x100 }, { 0x32, 0xc0, 0 }, /* '`' */ { 0x12, '1', 0 }, { 0x13, '2', 0 }, { 0x14, '3', 0 }, { 0x15, '4', 0 }, { 0x17, '5', 0 }, { 0x16, '6', 0 }, { 0x1a, '7', 0 }, { 0x1c, '8', 0 }, { 0x19, '9', 0 }, { 0x1d, '0', 0 }, { 0x1b, 0xbd, 0 }, /* '-' */ { 0x18, 0xbb, 0 }, /* '=' */ { 0x33, VK_BACK, 0 }, /* backspace */ { 0x72, VK_INSERT+0x100, 0 }, /* Insert key */ /* { 0x73, XK_Home, 0 }, alias VK_HOME to be KP_Equal! */ { 0x74, VK_PRIOR+0x100, 0 }, /* pageup */ { 0x47, VK_NUMLOCK, VK_NUMLOCK+0x100 }, /* clear */ { 0x51, VK_HOME+0x100, 0 }, /* KP_equal is HOME key */ { 0x4b, VK_DIVIDE, VK_DIVIDE+0x100 }, { 0x43, VK_MULTIPLY, VK_MULTIPLY+0x100 }, { 0x30, VK_TAB, 0 }, { 0x0c, 'Q', 0 }, { 0x0d, 'W', 0 }, { 0x0e, 'E', 0 }, { 0x0f, 'R', 0 }, { 0x11, 'T', 0 }, { 0x10, 'Y', 0 }, { 0x20, 'U', 0 }, { 0x22, 'I', 0 }, { 0x1f, 'O', 0 }, { 0x23, 'P', 0 }, { 0x21, 0xdb, 0 }, /* [ */ { 0x1e, 0xdd, 0 }, /* ] */ { 0x2a, 0xdc, 0 }, /* backslash, bar */ { 0x75, VK_DELETE+0x100, 0 }, { 0x77, VK_END+0x100, VK_END }, { 0x79, VK_NEXT+0x100, 0 }, { 0x59, VK_NUMPAD7, VK_HOME }, { 0x5b, VK_NUMPAD8, VK_UP }, { 0x5c, VK_NUMPAD9, VK_PRIOR }, { 0x4e, VK_SUBTRACT, VK_SUBTRACT+0x100 }, // { 0x39, VK_CAPITAL, 0 }, // Handled specially! { 0x00, 'A', 0 }, { 0x01, 'S', 0 }, { 0x02, 'D', 0 }, { 0x03, 'F', 0 }, { 0x05, 'G', 0 }, { 0x04, 'H', 0 }, { 0x26, 'J', 0 }, { 0x28, 'K', 0 }, { 0x25, 'L', 0 }, { 0x29, 0xba, 0 }, /* ; */ { 0x27, 0xde, 0 }, /* single quote */ { 0x24, VK_RETURN, 0 }, { 0x56, VK_NUMPAD4, VK_LEFT }, { 0x57, VK_NUMPAD5, VK_CLEAR }, { 0x58, VK_NUMPAD6, VK_RIGHT }, { 0x45, VK_ADD, 0 }, { 0x38, VK_SHIFT, 0 }, { 0x06, 'Z', 0 }, { 0x07, 'X', 0 }, { 0x08, 'C', 0 }, { 0x09, 'V', 0 }, { 0x0b, 'B', 0 }, { 0x2d, 'N', 0 }, { 0x2e, 'M', 0 }, { 0x2b, 0xbc, 0 }, /* , */ { 0x2f, 0xbe, 0 }, /* . */ { 0x2c, 0xbf, 0 }, /* / */ { 0x3e, VK_UP+0x100, 0 }, { 0x53, VK_NUMPAD1, VK_END }, { 0x54, VK_NUMPAD2, VK_DOWN }, { 0x55, VK_NUMPAD3, VK_NEXT }, { 0x36, VK_CONTROL, VK_CONTROL+0x100 }, { 0x3a, VK_SNAPSHOT+0x100, VK_MENU+0x100 },/* Opt=prntscrn or alt-r */ { 0x37, VK_SCROLL, VK_MENU }, /* Command=scr_lock or alt-l */ { 0x31, ' ', 0 }, { 0x3b, VK_LEFT+0x100, 0 }, { 0x3d, VK_DOWN+0x100, 0 }, { 0x3c, VK_RIGHT+0x100, 0 }, { 0x52, VK_NUMPAD0, VK_INSERT }, { 0x41, VK_DECIMAL, VK_DECIMAL }, { 0x4c, VK_RETURN+0x100, 0 }, { -1, -1, -1 } }; int win_nonblock_read_stdin(int fd, char *bufptr, int len) { HANDLE oshandle; DWORD dwret; int ret; errno = EAGAIN; oshandle = (HANDLE)_get_osfhandle(fd); // get stdin handle dwret = WaitForSingleObject(oshandle, 1); // wait 1msec for data ret = -1; if(dwret == WAIT_OBJECT_0) { ret = read(fd, bufptr, len); } return ret; } void x_dialog_create_kegs_conf(const char *str) { } int x_show_alert(int is_fatal, const char *str) { return 0; } int win_update_mouse(int x, int y, int button_states, int buttons_valid) { int buttons_changed; buttons_changed = ((g_win_button_states & buttons_valid) != button_states); g_win_button_states = (g_win_button_states & ~buttons_valid) | (button_states & buttons_valid); if(g_warp_pointer && (x == A2_WINDOW_WIDTH/2) && (y == A2_WINDOW_HEIGHT/2) && (!buttons_changed) ) { /* tell adb routs to recenter but ignore this motion */ update_mouse(x, y, 0, -1); return 0; } return update_mouse(x, y, button_states, buttons_valid & 7); } void win_event_mouse(WPARAM wParam, LPARAM lParam) { POINT pt; word32 flags; int buttons; int x, y; int motion; flags = wParam; x = LOWORD(lParam) - BASE_MARGIN_LEFT; y = HIWORD(lParam) - BASE_MARGIN_TOP; buttons = (flags & 1) + (((flags >> 1) & 1) << 2) + (((flags >> 4) & 1) << 1); #if 0 printf("Mouse at %d, %d fl: %08x, but: %d\n", x, y, flags, buttons); #endif motion = win_update_mouse(x, y, buttons, 7); if(motion && g_warp_pointer) { /* move mouse to center of screen */ pt.x = BASE_MARGIN_LEFT + A2_WINDOW_WIDTH/2; pt.y = BASE_MARGIN_TOP + A2_WINDOW_HEIGHT/2; ClientToScreen(g_hwnd_main, &pt); SetCursorPos(pt.x, pt.y); } } void win_event_key(HWND hwnd, UINT raw_vk, BOOL down, int repeat, UINT flags) { word32 vk; int a2code; int is_up; int capslock_down; int i; if((flags & 0x4000) && down) { /* auto-repeating, just ignore it */ return; } vk = raw_vk + (flags & 0x100); #if 0 printf("Key event, vk=%04x, down:%d, repeat: %d, flags: %08x\n", vk, down, repeat, flags); #endif /* remap a few keys here.. sigh */ if((vk & 0xff) == VK_APPS) { /* remap to command */ vk = VK_MENU; } if((vk & 0xff) == VK_CAPITAL) { // Windows gives us up-and-down events of the actual key // Use GetKeyState to get the true toggle state, and pass // that on to the adb interface capslock_down = GetKeyState(VK_CAPITAL) & 0x01; if(capslock_down != g_win_capslock_down) { g_win_capslock_down = capslock_down; adb_physical_key_update(0x39, !capslock_down); } return; // Do no more processing! } /* search a2key_to_wsym to find wsym in col 1 or 2 */ i = 0; is_up = !down; for(i = g_num_a2_keycodes-1; i >= 0; i--) { a2code = g_a2_key_to_wsym[i][0]; if((vk == g_a2_key_to_wsym[i][1]) || (vk == g_a2_key_to_wsym[i][2])) { vid_printf("Found vk:%04x = %02x\n", vk, a2code); adb_physical_key_update(a2code, is_up); return; } } printf("VK: %04x unknown\n", vk); } void win_event_quit(HWND hwnd) { g_quit_sim_now = 1; my_exit(0); } void win_event_redraw() { g_full_refresh_needed = -1; g_a2_screen_buffer_changed = -1; g_status_refresh_needed = 1; g_border_sides_refresh_needed = 1; g_border_special_refresh_needed = 1; } LRESULT CALLBACK win_event_handler(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam) { switch(umsg) { case WM_MOUSEMOVE: case WM_LBUTTONDOWN: case WM_LBUTTONUP: case WM_MBUTTONDOWN: case WM_MBUTTONUP: case WM_RBUTTONDOWN: case WM_RBUTTONUP: win_event_mouse(wParam, lParam); return 0; case WM_PAINT: win_event_redraw(); break; } switch(umsg) { HANDLE_MSG(hwnd, WM_KEYUP, win_event_key); HANDLE_MSG(hwnd, WM_KEYDOWN, win_event_key); HANDLE_MSG(hwnd, WM_SYSKEYUP, win_event_key); HANDLE_MSG(hwnd, WM_SYSKEYDOWN, win_event_key); HANDLE_MSG(hwnd, WM_DESTROY, win_event_quit); } #if 0 switch(umsg) { case WM_NCACTIVATE: case WM_NCHITTEST: case WM_NCMOUSEMOVE: case WM_SETCURSOR: case WM_LBUTTONDOWN: case WM_LBUTTONUP: case WM_RBUTTONDOWN: case WM_CONTEXTMENU: case WM_RBUTTONUP: case WM_MBUTTONDOWN: case WM_MBUTTONUP: case WM_PAINT: break; default: printf("Got umsg2: %d\n", umsg); } #endif return DefWindowProc(hwnd, umsg, wParam, lParam); } int main(int argc, char **argv) { WNDCLASS wndclass; RECT rect; int height; InitCommonControls(); wndclass.style = 0; wndclass.lpfnWndProc = (WNDPROC)win_event_handler; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = GetModuleHandle(NULL); wndclass.hIcon = LoadIcon((HINSTANCE)NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW); wndclass.hbrBackground = GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = "kegswin"; // Register the window if(!RegisterClass(&wndclass)) { printf("Registering window failed\n"); exit(1); } height = X_A2_WINDOW_HEIGHT + (MAX_STATUS_LINES * 16) + 32; g_main_height = height; g_hwnd_main = CreateWindow("kegswin", "KEGSWIN - Apple //gs Emulator", WS_TILED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, X_A2_WINDOW_WIDTH, height, NULL, NULL, GetModuleHandle(NULL), NULL); printf("g_hwnd_main = %p, height = %d\n", g_hwnd_main, height); GetWindowRect(g_hwnd_main, &rect); printf("...rect is: %ld, %ld, %ld, %ld\n", rect.left, rect.top, rect.right, rect.bottom); g_main_dc = GetDC(g_hwnd_main); SetTextColor(g_main_dc, 0); SetBkColor(g_main_dc, 0xffffff); g_main_cdc = CreateCompatibleDC(g_main_dc); g_screen_depth = 24; g_screen_mdepth = 32; // Call kegsmain return kegsmain(argc, argv); } void check_input_events() { MSG msg; while(PeekMessage(&msg, g_hwnd_main, 0, 0, PM_NOREMOVE)) { if(GetMessage(&msg, g_hwnd_main, 0, 0) > 0) { TranslateMessage(&msg); DispatchMessage(&msg); } else { printf("GetMessage returned <= 0\n"); my_exit(2); } } return; } void x_update_color(int col_num, int red, int green, int blue, word32 rgb) { } void x_update_physical_colormap() { } void show_xcolor_array() { int i; for(i = 0; i < 256; i++) { printf("%02x: %08x\n", i, g_palette_8to1624[i]); } } void xdriver_end() { printf("xdriver_end\n"); } void x_get_kimage(Kimage *kimage_ptr) { byte *ptr; int width; int height; int depth, mdepth; int size; width = kimage_ptr->width_req; height = kimage_ptr->height; depth = kimage_ptr->depth; mdepth = kimage_ptr->mdepth; size = 0; if(depth == g_screen_depth) { /* Use g_bmapinfo_ptr, adjusting width, height */ g_bmaphdr_ptr->biWidth = width; g_bmaphdr_ptr->biHeight = -height; kimage_ptr->dev_handle = CreateDIBSection(g_main_dc, g_bmapinfo_ptr, DIB_RGB_COLORS, (VOID **)&(kimage_ptr->data_ptr), NULL, 0); } else { /* allocate buffers for video.c to draw into */ size = (width*height*mdepth) >> 3; ptr = (byte *)malloc(size); if(ptr == 0) { printf("malloc for data failed, mdepth: %d\n", mdepth); exit(2); } kimage_ptr->data_ptr = ptr; kimage_ptr->dev_handle = (void *)-1; } printf("kim: %p, dev:%p data: %p, size: %08x\n", kimage_ptr, kimage_ptr->dev_handle, kimage_ptr->data_ptr, size); return; } void dev_video_init() { int extra_size; int lores_col; int a2code; int i; printf("Preparing graphics system\n"); g_num_a2_keycodes = 0; for(i = 0; i < 0x7f; i++) { a2code = g_a2_key_to_wsym[i][0]; if(a2code < 0) { g_num_a2_keycodes = i; } } g_screen_depth = 24; g_screen_mdepth = 32; extra_size = sizeof(RGBQUAD); if(g_screen_depth == 8) { extra_size = 256 * sizeof(RGBQUAD); } g_bmapinfo_ptr = (BITMAPINFO *)GlobalAlloc(GPTR, sizeof(BITMAPINFOHEADER) + extra_size); g_bmaphdr_ptr = (BITMAPINFOHEADER *)g_bmapinfo_ptr; g_bmaphdr_ptr->biSize = sizeof(BITMAPINFOHEADER); g_bmaphdr_ptr->biWidth = A2_WINDOW_WIDTH; g_bmaphdr_ptr->biHeight = -A2_WINDOW_HEIGHT; g_bmaphdr_ptr->biPlanes = 1; g_bmaphdr_ptr->biBitCount = g_screen_mdepth; g_bmaphdr_ptr->biCompression = BI_RGB; g_bmaphdr_ptr->biClrUsed = 0; video_get_kimages(); if(g_screen_depth != 8) { // Allocate g_mainwin_kimage video_get_kimage(&g_mainwin_kimage, 0, g_screen_depth, g_screen_mdepth); } for(i = 0; i < 256; i++) { lores_col = g_lores_colors[i & 0xf]; video_update_color_raw(i, lores_col); g_a2palette_8to1624[i] = g_palette_8to1624[i]; } g_installed_full_superhires_colormap = 1; ShowWindow(g_hwnd_main, SW_SHOWDEFAULT); UpdateWindow(g_hwnd_main); printf("Done with dev_video_init\n"); fflush(stdout); } void x_redraw_status_lines() { COLORREF oldtextcolor, oldbkcolor; char *buf; int line; int len; int height; int margin; height = 16; margin = 0; oldtextcolor = SetTextColor(g_main_dc, 0); oldbkcolor = SetBkColor(g_main_dc, 0xffffff); for(line = 0; line < MAX_STATUS_LINES; line++) { buf = g_status_ptrs[line]; if(buf != 0) { len = strlen(buf); TextOut(g_main_dc, 10, X_A2_WINDOW_HEIGHT + height*line + margin, buf, len); } } SetTextColor(g_main_dc, oldtextcolor); SetBkColor(g_main_dc, oldbkcolor); } void x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy, int width, int height) { void *bitm_old; POINT point; point.x = 0; point.y = 0; ClientToScreen(g_hwnd_main, &point); bitm_old = SelectObject(g_main_cdc, kimage_ptr->dev_handle); BitBlt(g_main_dc, destx, desty, width, height, g_main_cdc, srcx, srcy, SRCCOPY); SelectObject(g_main_cdc, bitm_old); } void x_push_done() { } void x_auto_repeat_on(int must) { } void x_auto_repeat_off(int must) { } void x_hide_pointer(int do_hide) { if(do_hide) { ShowCursor(0); } else { ShowCursor(1); } } void x_full_screen(int do_full) { return; }