Geant4 Cross Reference |
1 // Copyright (C) 2010, Guy Barrand. All rights reserved. 2 // See the file tools.license for terms. 3 4 #ifndef toolx_Windows_pixwin 5 #define toolx_Windows_pixwin 6 7 #include <windows.h> 8 #include <windowsx.h> 9 #include <wingdi.h> 10 11 #include <tools/sg/device_interactor> 12 #include <tools/sg/keys> 13 //#include <tools/log_file> 14 15 #include <string> 16 17 #if defined(_MSC_VER) && _MSC_VER < 1900 18 #elif defined(__MINGW32__) 19 #else 20 #define TOOLX_WINDOWS_TOUCH 21 #endif 22 23 namespace toolx { 24 namespace Windows { 25 26 #ifdef TOOLX_WINDOWS_TOUCH 27 inline bool is_message_touch_event() { 28 // from https://stackoverflow.com/questions/29857587/detect-if-wm-mousemove-is-caused-by-touch-pen. 29 static const LONG_PTR c_SIGNATURE_MASK = 0xFFFFFF00; 30 static const LONG_PTR c_MOUSEEVENTF_FROMTOUCH = 0xFF515700; 31 LONG_PTR extraInfo = ::GetMessageExtraInfo(); 32 return ( ( extraInfo & c_SIGNATURE_MASK ) == c_MOUSEEVENTF_FROMTOUCH ); 33 } 34 #endif 35 36 class pixwin { 37 static const std::string& s_class() { 38 static const std::string s_v("toolx::Windows::pixwin"); 39 return s_v; 40 } 41 static void register_class(){ 42 static bool s_done = false; //not const, then not thread safe. 43 if(!s_done) { 44 WNDCLASS wc; 45 wc.style = CS_HREDRAW | CS_VREDRAW; 46 wc.lpfnWndProc = (WNDPROC)proc; 47 wc.cbClsExtra = 0; 48 wc.cbWndExtra = 0; 49 wc.hInstance = ::GetModuleHandle(NULL); 50 wc.hIcon = LoadIcon(NULL,IDI_APPLICATION); 51 wc.hCursor = LoadCursor(NULL,IDC_ARROW); 52 wc.hbrBackground = GetSysColorBrush(COLOR_BTNFACE); 53 wc.lpszMenuName = (PTSTR)s_class().c_str(); 54 wc.lpszClassName = (PTSTR)s_class().c_str(); 55 ::RegisterClass(&wc); 56 s_done = true; 57 } 58 } 59 public: 60 virtual void resize(unsigned int,unsigned int){} 61 //virtual void paint(HDC) {} 62 virtual void paint() {} 63 virtual void close(){} 64 65 virtual void left_button_up(unsigned int a_x,unsigned int a_y) {} 66 virtual void left_button_down(unsigned int a_x,unsigned int a_y) {} 67 virtual void mouse_move(unsigned int a_x,unsigned int a_y,bool) {} 68 public: 69 pixwin(HWND a_parent,unsigned int a_w,unsigned int a_h) 70 :m_parent(a_parent) 71 ,m_hwnd(0) 72 ,m_touch_available(false) 73 ,m_interactor(0) 74 { 75 register_class(); 76 m_hwnd = ::CreateWindow((PTSTR)s_class().c_str(), 77 //m_hwnd = ::CreateWindowEx(WS_EX_LAYERED,s_class().c_str(), 78 NULL, 79 WS_CHILD | WS_VISIBLE, 80 0,0, 81 a_w,a_h, 82 m_parent,NULL, 83 GetWindowInstance(m_parent), 84 NULL); 85 if(!m_hwnd) return; 86 ::SetWindowLongPtr(m_hwnd,GWLP_USERDATA,LONG_PTR(this)); 87 88 #ifdef TOOLX_WINDOWS_TOUCH 89 {BYTE digitizer_status = (BYTE)::GetSystemMetrics(SM_DIGITIZER); 90 if((digitizer_status & (0x80 + 0x40)) == 0) { 91 m_touch_available = false; 92 } else { 93 //BYTE nInputs = (BYTE)::GetSystemMetrics(SM_MAXIMUMTOUCHES); 94 m_touch_available = true; 95 if(!::RegisterTouchWindow(m_hwnd,0)) m_touch_available = false; 96 }} 97 #endif 98 99 } 100 virtual ~pixwin(){ 101 if(m_hwnd) { 102 ::SetWindowLongPtr(m_hwnd,GWLP_USERDATA,LONG_PTR(NULL)); 103 ::DestroyWindow(m_hwnd); 104 m_hwnd = 0; 105 } 106 } 107 protected: 108 pixwin(const pixwin& a_from) 109 :m_parent(a_from.m_parent) 110 ,m_hwnd(0) 111 ,m_touch_available(a_from.m_touch_available) 112 ,m_interactor(0) 113 { 114 if(!m_parent) return; 115 register_class(); 116 RECT rect; 117 ::GetClientRect(m_parent,&rect); 118 m_hwnd = ::CreateWindow((PTSTR)s_class().c_str(), 119 NULL, 120 WS_CHILD | WS_VISIBLE, 121 0,0, 122 rect.right-rect.left, 123 rect.bottom-rect.top, 124 m_parent,NULL, 125 GetWindowInstance(m_parent), 126 NULL); 127 if(!m_hwnd) return; 128 ::SetWindowLongPtr(m_hwnd,GWLP_USERDATA,LONG_PTR(this)); 129 130 #ifdef TOOLX_WINDOWS_TOUCH 131 if(a_from.m_touch_available) { 132 if(!::RegisterTouchWindow(m_hwnd,0)) m_touch_available = false; 133 } 134 #endif 135 } 136 protected: 137 pixwin& operator=(const pixwin&){return *this;} 138 public: 139 void set_client_area_size(unsigned int a_w,unsigned int a_h) { 140 RECT rect; 141 ::GetClientRect(m_hwnd,&rect); 142 ::MoveWindow(m_hwnd,rect.left,rect.top,a_w,a_h,TRUE); 143 } 144 HWND hwnd() const {return m_hwnd;} 145 void wm_paint() {paint();} 146 public: 147 void set_device_interactor(tools::sg::device_interactor* a_interactor) {m_interactor = a_interactor;} //we do not have ownership. 148 protected: 149 bool is_touch_event() { 150 #ifdef TOOLX_WINDOWS_TOUCH 151 if(!m_touch_available) return false; 152 return is_message_touch_event(); 153 #else 154 return false; 155 #endif 156 } 157 protected: 158 static LRESULT CALLBACK proc(HWND a_hwnd,UINT a_msg,WPARAM a_wparam,LPARAM a_lparam) { 159 switch (a_msg) { 160 case WM_SIZE:{ 161 int width = LOWORD(a_lparam); 162 int height = HIWORD(a_lparam); 163 pixwin* _this = (pixwin*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA); 164 if(_this) { 165 _this->resize(width,height); 166 } else { 167 // CreateWindow send a WM_SIZE but GWLP_USERDATA not yet set. 168 } 169 }return 0; 170 case WM_PAINT:{ 171 pixwin* _this = (pixwin*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA); 172 if(_this) _this->wm_paint(); 173 }return 0; 174 175 case WM_KEYDOWN:{ 176 pixwin* _this = (pixwin*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA); 177 if(_this) { 178 if(_this->m_interactor) { 179 tools::sg::key_down_event event(_this->convert_key(a_wparam)); 180 _this->m_interactor->key_press(event); 181 } 182 } 183 } return 0; 184 case WM_KEYUP:{ 185 pixwin* _this = (pixwin*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA); 186 if(_this) { 187 if(_this->m_interactor) { 188 tools::sg::key_up_event event(_this->convert_key(a_wparam)); 189 _this->m_interactor->key_release(event); 190 } 191 } 192 } return 0; 193 194 case WM_LBUTTONDOWN:{ 195 pixwin* _this = (pixwin*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA); 196 if(_this) { 197 if(_this->m_interactor) { 198 tools::sg::mouse_down_event event(LOWORD(a_lparam),HIWORD(a_lparam)); 199 _this->m_interactor->mouse_press(event); 200 } else { 201 RECT rect; 202 ::GetClientRect(a_hwnd,&rect); 203 unsigned int h = rect.bottom-rect.top; 204 if(!_this->is_touch_event()) _this->left_button_down(LOWORD(a_lparam),h-HIWORD(a_lparam)); 205 } 206 } 207 }return 0; 208 case WM_LBUTTONUP:{ 209 pixwin* _this = (pixwin*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA); 210 if(_this) { 211 if(_this->m_interactor) { 212 tools::sg::mouse_up_event event(LOWORD(a_lparam),HIWORD(a_lparam)); 213 _this->m_interactor->mouse_release(event); 214 } else { 215 RECT rect; 216 ::GetClientRect(a_hwnd,&rect); 217 unsigned int h = rect.bottom-rect.top; 218 if(!_this->is_touch_event()) _this->left_button_up(LOWORD(a_lparam),h-HIWORD(a_lparam)); 219 } 220 } 221 } return 0; 222 case WM_MOUSEMOVE:{ 223 pixwin* _this = (pixwin*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA); 224 if(_this) { 225 if(_this->m_interactor) { 226 tools::sg::mouse_move_event event(LOWORD(a_lparam),HIWORD(a_lparam),0,0,false); 227 _this->m_interactor->mouse_move(event); 228 } else { 229 WPARAM state = a_wparam; 230 bool ldown = ((state & MK_LBUTTON)==MK_LBUTTON)?true:false; 231 RECT rect; 232 ::GetClientRect(a_hwnd,&rect); 233 unsigned int h = rect.bottom-rect.top; 234 if(!_this->is_touch_event()) _this->mouse_move(LOWORD(a_lparam),h-HIWORD(a_lparam),ldown); 235 } 236 } 237 238 }return 0; 239 240 case WM_MOUSEWHEEL:{ 241 pixwin* _this = (pixwin*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA); 242 if(_this) { 243 if(_this->m_interactor) { 244 tools::sg::wheel_rotate_event event(GET_WHEEL_DELTA_WPARAM(a_wparam)); 245 _this->m_interactor->wheel_rotate(event); 246 } 247 } 248 } return 0; 249 250 #ifdef TOOLX_WINDOWS_TOUCH 251 case WM_TOUCH:{ 252 pixwin* _this = (pixwin*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA); 253 if(_this && _this->m_touch_available) { 254 RECT rect; 255 //::GetWindowRect(hwnd,&rect); ??? 256 ::GetClientRect(a_hwnd,&rect); 257 unsigned int h = rect.bottom-rect.top; 258 259 unsigned int num_inputs = (int)a_wparam; 260 //::printf("debug : WM_TOUCH : 001 : %d\n",num_inputs); 261 TOUCHINPUT* ti = new TOUCHINPUT[num_inputs]; 262 POINT p; 263 if(::GetTouchInputInfo((HTOUCHINPUT)a_lparam,num_inputs,ti,sizeof(TOUCHINPUT))) { 264 for(unsigned int i=0;i<num_inputs; ++i) { 265 p.x = TOUCH_COORD_TO_PIXEL(ti[i].x); 266 p.y = TOUCH_COORD_TO_PIXEL(ti[i].y); 267 if(!::ScreenToClient(a_hwnd,&p)) {} 268 if(ti[i].dwFlags & TOUCHEVENTF_DOWN) { 269 //::printf("debug : TOUCHEVENTF_DOWN %lu %lu\n",p.x,p.y); 270 _this->left_button_down(p.x,h-p.y); 271 } else if (ti[i].dwFlags & TOUCHEVENTF_UP) { 272 //::printf("debug : TOUCHEVENTF_UP %lu %lu\n",p.x,p.y); 273 _this->left_button_up(p.x,h-p.y); 274 } else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) { 275 bool ldown = true; //we assume that a TOUCHEVENT_DOWN had been done. 276 //::printf("debug : TOUCHEVENTF_MOVE %lu %lu\n",p.x,p.y); 277 _this->mouse_move(p.x,h-p.y,ldown); 278 } 279 } 280 } 281 ::CloseTouchInputHandle((HTOUCHINPUT)a_lparam); 282 delete [] ti; 283 } 284 }return 0; 285 #endif //TOOLX_WINDOWS_TOUCH 286 case WM_DESTROY:wm__destroy(a_hwnd);return 0; 287 } 288 return (DefWindowProc(a_hwnd,a_msg,a_wparam,a_lparam)); 289 } 290 static bool SetWindowPixelFormat(HDC a_HDC){ 291 PIXELFORMATDESCRIPTOR pfd; 292 pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); 293 pfd.nVersion = 1; 294 pfd.dwFlags = 295 PFD_DRAW_TO_WINDOW | 296 PFD_SUPPORT_OPENGL | 297 PFD_DOUBLEBUFFER | 298 PFD_STEREO_DONTCARE; 299 pfd.iPixelType = PFD_TYPE_RGBA; 300 pfd.cColorBits = 32; 301 pfd.cRedBits = 8; 302 pfd.cRedShift = 16; 303 pfd.cGreenBits = 8; 304 pfd.cGreenShift = 8; 305 pfd.cBlueBits = 8; 306 pfd.cBlueShift = 0; 307 pfd.cAlphaBits = 0; 308 pfd.cAlphaShift = 0; 309 pfd.cAccumBits = 64; 310 pfd.cAccumRedBits = 16; 311 pfd.cAccumGreenBits = 16; 312 pfd.cAccumBlueBits = 16; 313 pfd.cAccumAlphaBits = 0; 314 pfd.cDepthBits = 32; 315 pfd.cStencilBits = 8; 316 pfd.cAuxBuffers = 0; 317 pfd.iLayerType = PFD_MAIN_PLANE; 318 pfd.bReserved = 0; 319 pfd.dwLayerMask = 0; 320 pfd.dwVisibleMask = 0; 321 pfd.dwDamageMask = 0; 322 323 int pixelIndex = ::ChoosePixelFormat(a_HDC,&pfd); 324 if (pixelIndex==0) { 325 // Let's choose a default index. 326 pixelIndex = 1; 327 if (::DescribePixelFormat(a_HDC, 328 pixelIndex, 329 sizeof(PIXELFORMATDESCRIPTOR), 330 &pfd)==0) { 331 return false; 332 } 333 } 334 335 if (::SetPixelFormat(a_HDC,pixelIndex,&pfd)==FALSE) return false; 336 337 return true; 338 } 339 static void wm__destroy(HWND a_hwnd) { 340 pixwin* _this = (pixwin*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA); 341 if(_this) { //How to be sure that we have a pixwin* ??? 342 _this->close(); 343 if(_this->m_hwnd!=a_hwnd) { 344 //::printf("WinTk::Component::wm_destroy : HWND mismatch !\n"); 345 } 346 _this->m_hwnd = 0; 347 } 348 ::SetWindowLongPtr(a_hwnd,GWLP_USERDATA,LONG_PTR(NULL)); 349 } 350 protected: 351 tools::key_code convert_key(WPARAM a_key) { 352 if(a_key==VK_SHIFT) return tools::sg::key_shift(); 353 return (tools::key_code)a_key; 354 } 355 protected: 356 HWND m_parent; 357 HWND m_hwnd; 358 bool m_touch_available; 359 tools::sg::device_interactor* m_interactor; 360 }; 361 362 }} 363 364 365 #endif