📄 fl_win32.cxx
字号:
//// "$Id: Fl_win32.cxx,v 1.1.1.1 2003/08/07 21:18:40 jasonk Exp $"//// WIN32-specific code for the Fast Light Tool Kit (FLTK).//// Copyright 1998-1999 by Bill Spitzak and others.//// This library is free software; you can redistribute it and/or// modify it under the terms of the GNU Library General Public// License as published by the Free Software Foundation; either// version 2 of the License, or (at your option) any later version.//// This library is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU// Library General Public License for more details.//// You should have received a copy of the GNU Library General Public// License along with this library; if not, write to the Free Software// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307// USA.//// Please report all bugs and problems to "fltk-bugs@easysw.com".//// This file contains win32-specific code for fltk which is always linked// in. Search other files for "WIN32" or filenames ending in _win32.C// for other system-specific code.#include <config.h>#include <FL/Fl.H>#include <FL/win32.H>#include <FL/Fl_Window.H>#include <string.h>#include <stdlib.h>#include <sys/types.h>#include <time.h>#include <winsock.h>#include <ctype.h>//// WM_SYNCPAINT is an "undocumented" message, which is finally defined in// VC++ 6.0.//#ifndef WM_SYNCPAINT# define WM_SYNCPAINT 0x0088#endif /* !WM_SYNCPAINT */#ifndef WM_MOUSELEAVE# define WM_MOUSELEAVE 0x02a3#endif////////////////////////////////////////////////////////////////// interface to poll/select call:// fd's are only implemented for sockets. Microsoft Windows does not// have a unified IO system, so it doesn't support select() on files,// devices, or pipes... Also, unlike UNIX the Windows select() call// doesn't use the nfds parameter, so we don't need to keep track of// the maximum FD number...static fd_set fdsets[3];#define POLLIN 1#define POLLOUT 4#define POLLERR 8static int nfds = 0;static int fd_array_size = 0;static struct FD { int fd; short events; void (*cb)(int, void*); void* arg;} *fd = 0;void Fl::add_fd(int n, int events, void (*cb)(int, void*), void *v) { remove_fd(n,events); int i = nfds++; if (i >= fd_array_size) { fd_array_size = 2*fd_array_size+1; fd = (FD*)realloc(fd, fd_array_size*sizeof(FD)); } fd[i].fd = n; fd[i].events = events; fd[i].cb = cb; fd[i].arg = v; if (events & POLLIN) FD_SET(n, &fdsets[0]); if (events & POLLOUT) FD_SET(n, &fdsets[1]); if (events & POLLERR) FD_SET(n, &fdsets[2]);}void Fl::add_fd(int fd, void (*cb)(int, void*), void* v) { Fl::add_fd(fd, POLLIN, cb, v);}void Fl::remove_fd(int n, int events) { int i,j; for (i=j=0; i<nfds; i++) { if (fd[i].fd == n) { int e = fd[i].events & ~events; if (!e) continue; // if no events left, delete this fd fd[i].events = e; } // move it down in the array if necessary: if (j<i) { fd[j]=fd[i]; } j++; } nfds = j; if (events & POLLIN) FD_CLR(unsigned(n), &fdsets[0]); if (events & POLLOUT) FD_CLR(unsigned(n), &fdsets[1]); if (events & POLLERR) FD_CLR(unsigned(n), &fdsets[2]);}void Fl::remove_fd(int n) { remove_fd(n, -1);}MSG fl_msg;int fl_ready() { if (PeekMessage(&fl_msg, NULL, 0, 0, PM_NOREMOVE)) return 1; timeval t; t.tv_sec = 0; t.tv_usec = 0; fd_set fdt[3]; fdt[0] = fdsets[0]; fdt[1] = fdsets[1]; fdt[2] = fdsets[2]; return ::select(0,&fdt[0],&fdt[1],&fdt[2],&t);}double fl_wait(int timeout_flag, double time) { int have_message = 0; int timerid; if (nfds) { // For WIN32 we need to poll for socket input FIRST, since // the event queue is not something we can select() on... timeval t; t.tv_sec = 0; t.tv_usec = 0; fd_set fdt[3]; fdt[0] = fdsets[0]; fdt[1] = fdsets[1]; fdt[2] = fdsets[2]; if (::select(0,&fdt[0],&fdt[1],&fdt[2],&t)) { // We got something - do the callback! for (int i = 0; i < nfds; i ++) { int f = fd[i].fd; short revents = 0; if (FD_ISSET(f,&fdt[0])) revents |= POLLIN; if (FD_ISSET(f,&fdt[1])) revents |= POLLOUT; if (FD_ISSET(f,&fdt[2])) revents |= POLLERR; if (fd[i].events & revents) fd[i].cb(f, fd[i].arg); } } } // get the first message by waiting the correct amount of time: if (!timeout_flag) { // If we are monitoring sockets we need to check them periodically, // so set a timer in this case... if (nfds) { // First see if there is a message waiting... have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE); if (!have_message) { // If not then set a 1ms timer... timerid = SetTimer(NULL, 0, 1, NULL); GetMessage(&fl_msg, NULL, 0, 0); KillTimer(NULL, timerid); } } else { // Wait for a message... GetMessage(&fl_msg, NULL, 0, 0); } have_message = 1; } else { // Perform the requested timeout... have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE); if (!have_message && time > 0.0) { int t = (int)(time * 1000.0); if (t <= 0) t = 1; timerid = SetTimer(NULL, 0, t, NULL); GetMessage(&fl_msg, NULL, 0, 0); KillTimer(NULL, timerid); have_message = 1; } } // execute it, them execute any other messages that become ready during it: while (have_message) { TranslateMessage(&fl_msg); DispatchMessage(&fl_msg); have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE); } return time;}////////////////////////////////////////////////////////////////int Fl::x(){ RECT r; SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); return r.left;}int Fl::y(){ RECT r; SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); return r.top;}int Fl::h(){ RECT r; SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); return r.bottom - r.top;}int Fl::w(){ RECT r; SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); return r.right - r.left;}void Fl::get_mouse(int &x, int &y) { POINT p; GetCursorPos(&p); x = p.x; y = p.y;}////////////////////////////////////////////////////////////////HWND fl_capture;static int mouse_event(Fl_Window *window, int what, int button, WPARAM wParam, LPARAM lParam){ static int px, py, pmx, pmy; POINT pt; Fl::e_x = pt.x = (signed short)LOWORD(lParam); Fl::e_y = pt.y = (signed short)HIWORD(lParam); ClientToScreen(fl_xid(window), &pt); Fl::e_x_root = pt.x; Fl::e_y_root = pt.y; while (window->parent()) { Fl::e_x += window->x(); Fl::e_y += window->y(); window = window->window(); } ulong state = Fl::e_state & 0xff0000; // keep shift key states#if 0 // mouse event reports some shift flags, perhaps save them? if (wParam & MK_SHIFT) state |= FL_SHIFT; if (wParam & MK_CONTROL) state |= FL_CTRL;#endif if (wParam & MK_LBUTTON) state |= FL_BUTTON1; if (wParam & MK_MBUTTON) state |= FL_BUTTON2; if (wParam & MK_RBUTTON) state |= FL_BUTTON3; Fl::e_state = state; switch (what) { case 1: // double-click if (Fl::e_is_click) {Fl::e_clicks++; goto J1;} case 0: // single-click Fl::e_clicks = 0; J1: if (!fl_capture) SetCapture(fl_xid(window)); Fl::e_keysym = FL_Button + button; Fl::e_is_click = 1; px = pmx = Fl::e_x_root; py = pmy = Fl::e_y_root; return Fl::handle(FL_PUSH,window); case 2: // release: if (!fl_capture) ReleaseCapture(); Fl::e_keysym = FL_Button + button; return Fl::handle(FL_RELEASE,window); case 3: // move: default: // avoid compiler warning // MSWindows produces extra events even if mouse does not move, ignore em: if (Fl::e_x_root == pmx && Fl::e_y_root == pmy) return 1; pmx = Fl::e_x_root; pmy = Fl::e_y_root; if (abs(Fl::e_x_root-px)>5 || abs(Fl::e_y_root-py)>5) Fl::e_is_click = 0; return Fl::handle(FL_MOVE,window); }}// convert a MSWindows VK_x to an Fltk (X) Keysym:// See also the inverse converter in Fl_get_key_win32.C// This table is in numeric order by VK:static const struct {unsigned short vk, fltk, extended;} vktab[] = { {VK_BACK, FL_BackSpace}, {VK_TAB, FL_Tab}, {VK_CLEAR, FL_KP+'5', 0xff0b/*XK_Clear*/}, {VK_RETURN, FL_Enter, FL_KP_Enter}, {VK_SHIFT, FL_Shift_L, FL_Shift_R}, {VK_CONTROL, FL_Control_L, FL_Control_R}, {VK_MENU, FL_Alt_L, FL_Alt_R}, {VK_PAUSE, FL_Pause}, {VK_CAPITAL, FL_Caps_Lock}, {VK_ESCAPE, FL_Escape}, {VK_SPACE, ' '}, {VK_PRIOR, FL_KP+'9', FL_Page_Up}, {VK_NEXT, FL_KP+'3', FL_Page_Down}, {VK_END, FL_KP+'1', FL_End}, {VK_HOME, FL_KP+'7', FL_Home}, {VK_LEFT, FL_KP+'4', FL_Left}, {VK_UP, FL_KP+'8', FL_Up}, {VK_RIGHT, FL_KP+'6', FL_Right}, {VK_DOWN, FL_KP+'2', FL_Down}, {VK_SNAPSHOT, FL_Print}, // does not work on NT {VK_INSERT, FL_KP+'0', FL_Insert}, {VK_DELETE, FL_KP+'.', FL_Delete}, {VK_LWIN, FL_Meta_L}, {VK_RWIN, FL_Meta_R}, {VK_APPS, FL_Menu}, {VK_MULTIPLY, FL_KP+'*'}, {VK_ADD, FL_KP+'+'}, {VK_SUBTRACT, FL_KP+'-'}, {VK_DECIMAL, FL_KP+'.'}, {VK_DIVIDE, FL_KP+'/'}, {VK_NUMLOCK, FL_Num_Lock}, {VK_SCROLL, FL_Scroll_Lock}, {0xba, ';'}, {0xbb, '='}, {0xbc, ','}, {0xbd, '-'}, {0xbe, '.'}, {0xbf, '/'}, {0xc0, '`'}, {0xdb, '['}, {0xdc, '\\'}, {0xdd, ']'}, {0xde, '\''}};static int ms2fltk(int vk, int extended) { static unsigned short vklut[256]; static unsigned short extendedlut[256]; if (!vklut[1]) { // init the table unsigned int i; for (i = 0; i < 256; i++) vklut[i] = tolower(i); for (i=VK_F1; i<=VK_F16; i++) vklut[i] = i+(FL_F-(VK_F1-1)); for (i=VK_NUMPAD0; i<=VK_NUMPAD9; i++) vklut[i] = i+(FL_KP+'0'-VK_NUMPAD0); for (i = 0; i < sizeof(vktab)/sizeof(*vktab); i++) { vklut[vktab[i].vk] = vktab[i].fltk; extendedlut[vktab[i].vk] = vktab[i].extended; } for (i = 0; i < 256; i++) if (!extendedlut[i]) extendedlut[i] = vklut[i]; } return extended ? extendedlut[vk] : vklut[vk];}#if USE_COLORMAPextern HPALETTE fl_select_palette(void); // in fl_color_win32.C#endifstatic Fl_Window* resize_bug_fix;static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){ static char buffer[2]; static int cnt=0; if(uMsg == WM_SYNCPAINT) { if(cnt) { InvalidateRect(fl_window,0,FALSE); cnt = 0; } else cnt = 1; } else if (uMsg == WM_PAINT) cnt = 0; fl_msg.message = uMsg; Fl_Window *window = fl_find(hWnd); if (window) switch (uMsg) { case WM_QUIT: // this should not happen? Fl::fatal("WM_QUIT message"); case WM_CLOSE: // user clicked close box Fl::handle(FL_CLOSE, window); return 0; case WM_PAINT: { // This might be a better alternative, where we fully ignore NT's // "facilities" for painting. MS expects applications to paint according // to a very restrictive paradigm, and this is the way I found of // working around it. In a sense, we are using WM_PAINT simply as an // "exposure alert", like the X event. Fl_X *i = Fl_X::i(window); i->wait_for_expose = 0; // if region == entire window we should delete i->region, else if (window->damage()) { if (i->region) { InvalidateRgn(hWnd,i->region,FALSE); GetUpdateRgn(hWnd,i->region,0); } } else { if (!i->region) i->region = CreateRectRgn(0,0,0,0); GetUpdateRgn(hWnd,i->region,0); } window->clear_damage(window->damage()|FL_DAMAGE_EXPOSE); i->flush(); window->clear_damage(); // This convinces MSWindows we have painted whatever they wanted // us to paint, and stops it from sending WM_PAINT messages. ValidateRgn(hWnd,NULL); } break; case WM_LBUTTONDOWN: mouse_event(window, 0, 1, wParam, lParam); return 0; case WM_LBUTTONDBLCLK:mouse_event(window, 1, 1, wParam, lParam); return 0; case WM_LBUTTONUP: mouse_event(window, 2, 1, wParam, lParam); return 0; case WM_MBUTTONDOWN: mouse_event(window, 0, 2, wParam, lParam); return 0; case WM_MBUTTONDBLCLK:mouse_event(window, 1, 2, wParam, lParam); return 0; case WM_MBUTTONUP: mouse_event(window, 2, 2, wParam, lParam); return 0; case WM_RBUTTONDOWN: mouse_event(window, 0, 3, wParam, lParam); return 0; case WM_RBUTTONDBLCLK:mouse_event(window, 1, 3, wParam, lParam); return 0; case WM_RBUTTONUP: mouse_event(window, 2, 3, wParam, lParam); return 0; case WM_MOUSEMOVE: mouse_event(window, 3, 0, wParam, lParam); return 0;#ifdef WM_MOUSELEAVE case WM_MOUSELEAVE: Fl::handle(FL_LEAVE, window); break;#endif /* WM_MOUSELEAVE */ case WM_SETFOCUS: Fl::handle(FL_FOCUS, window); break; case WM_KILLFOCUS: Fl::handle(FL_UNFOCUS, window);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -