Warning, /include/Geant4/toolx/Windows/pixwin is written in an unsupported language. File is not indexed.
0001 // Copyright (C) 2010, Guy Barrand. All rights reserved.
0002 // See the file tools.license for terms.
0003
0004 #ifndef toolx_Windows_pixwin
0005 #define toolx_Windows_pixwin
0006
0007 #include <windows.h>
0008 #include <windowsx.h>
0009 #include <wingdi.h>
0010
0011 #include <tools/sg/device_interactor>
0012 #include <tools/sg/keys>
0013
0014 #include <string>
0015
0016 #if defined(_MSC_VER) && _MSC_VER < 1900
0017 #elif defined(__MINGW32__)
0018 #else
0019 #define TOOLX_WINDOWS_TOUCH
0020 #endif
0021
0022 namespace toolx {
0023 namespace Windows {
0024
0025 #ifdef TOOLX_WINDOWS_TOUCH
0026 inline bool is_message_touch_event() {
0027 // from https://stackoverflow.com/questions/29857587/detect-if-wm-mousemove-is-caused-by-touch-pen.
0028 static const LONG_PTR c_SIGNATURE_MASK = 0xFFFFFF00;
0029 static const LONG_PTR c_MOUSEEVENTF_FROMTOUCH = 0xFF515700;
0030 LONG_PTR extraInfo = ::GetMessageExtraInfo();
0031 return ( ( extraInfo & c_SIGNATURE_MASK ) == c_MOUSEEVENTF_FROMTOUCH );
0032 }
0033 #endif
0034
0035 class pixwin {
0036 static const std::string& s_class() {
0037 static const std::string s_v("toolx::Windows::pixwin");
0038 return s_v;
0039 }
0040 static void register_class(){
0041 static bool s_done = false; //not const, then not thread safe.
0042 if(!s_done) {
0043 WNDCLASS wc;
0044 wc.style = CS_HREDRAW | CS_VREDRAW;
0045 wc.lpfnWndProc = (WNDPROC)proc;
0046 wc.cbClsExtra = 0;
0047 wc.cbWndExtra = 0;
0048 wc.hInstance = ::GetModuleHandle(NULL);
0049 wc.hIcon = LoadIcon(NULL,IDI_APPLICATION);
0050 wc.hCursor = LoadCursor(NULL,IDC_ARROW);
0051 wc.hbrBackground = GetSysColorBrush(COLOR_BTNFACE);
0052 wc.lpszMenuName = (PTSTR)s_class().c_str();
0053 wc.lpszClassName = (PTSTR)s_class().c_str();
0054 ::RegisterClass(&wc);
0055 s_done = true;
0056 }
0057 }
0058 public:
0059 virtual void resize(unsigned int,unsigned int){}
0060 virtual void paint() {}
0061 virtual void close(){}
0062
0063 virtual void left_button_up(unsigned int a_x,unsigned int a_y) {}
0064 virtual void left_button_down(unsigned int a_x,unsigned int a_y) {}
0065 virtual void mouse_move(unsigned int a_x,unsigned int a_y,bool) {}
0066 public:
0067 pixwin(HWND a_parent,unsigned int a_w,unsigned int a_h)
0068 :m_parent(a_parent)
0069 ,m_hwnd(0)
0070 ,m_touch_available(false)
0071 ,m_interactor(0)
0072 {
0073 register_class();
0074 m_hwnd = ::CreateWindow((PTSTR)s_class().c_str(),
0075 NULL,
0076 WS_CHILD | WS_VISIBLE,
0077 0,0,
0078 a_w,a_h,
0079 m_parent,NULL,
0080 GetWindowInstance(m_parent),
0081 NULL);
0082 if(!m_hwnd) return;
0083 ::SetWindowLongPtr(m_hwnd,GWLP_USERDATA,LONG_PTR(this));
0084
0085 #ifdef TOOLX_WINDOWS_TOUCH
0086 {BYTE digitizer_status = (BYTE)::GetSystemMetrics(SM_DIGITIZER);
0087 if((digitizer_status & (0x80 + 0x40)) == 0) {
0088 m_touch_available = false;
0089 } else {
0090 m_touch_available = true;
0091 if(!::RegisterTouchWindow(m_hwnd,0)) m_touch_available = false;
0092 }}
0093 #endif
0094
0095 }
0096 virtual ~pixwin(){
0097 if(m_hwnd) {
0098 ::SetWindowLongPtr(m_hwnd,GWLP_USERDATA,LONG_PTR(NULL));
0099 ::DestroyWindow(m_hwnd);
0100 m_hwnd = 0;
0101 }
0102 }
0103 protected:
0104 pixwin(const pixwin& a_from)
0105 :m_parent(a_from.m_parent)
0106 ,m_hwnd(0)
0107 ,m_touch_available(a_from.m_touch_available)
0108 ,m_interactor(0)
0109 {
0110 if(!m_parent) return;
0111 register_class();
0112 RECT rect;
0113 ::GetClientRect(m_parent,&rect);
0114 m_hwnd = ::CreateWindow((PTSTR)s_class().c_str(),
0115 NULL,
0116 WS_CHILD | WS_VISIBLE,
0117 0,0,
0118 rect.right-rect.left,
0119 rect.bottom-rect.top,
0120 m_parent,NULL,
0121 GetWindowInstance(m_parent),
0122 NULL);
0123 if(!m_hwnd) return;
0124 ::SetWindowLongPtr(m_hwnd,GWLP_USERDATA,LONG_PTR(this));
0125
0126 #ifdef TOOLX_WINDOWS_TOUCH
0127 if(a_from.m_touch_available) {
0128 if(!::RegisterTouchWindow(m_hwnd,0)) m_touch_available = false;
0129 }
0130 #endif
0131 }
0132 protected:
0133 pixwin& operator=(const pixwin&){return *this;}
0134 public:
0135 void set_client_area_size(unsigned int a_w,unsigned int a_h) {
0136 RECT rect;
0137 ::GetClientRect(m_hwnd,&rect);
0138 ::MoveWindow(m_hwnd,rect.left,rect.top,a_w,a_h,TRUE);
0139 }
0140 HWND hwnd() const {return m_hwnd;}
0141 void post_WM_PAINT() const {
0142 if(!m_hwnd) return;
0143 ::PostMessage(m_hwnd,WM_PAINT,(WPARAM)0,(LPARAM)0);
0144 }
0145 void send_WM_PAINT() const {
0146 if(!m_hwnd) return;
0147 ::SendMessage(m_hwnd,WM_PAINT,(WPARAM)0,(LPARAM)0);
0148 }
0149 void wm_paint() {paint();}
0150 public:
0151 void set_device_interactor(tools::sg::device_interactor* a_interactor) {m_interactor = a_interactor;} //we do not have ownership.
0152 protected:
0153 bool is_touch_event() {
0154 #ifdef TOOLX_WINDOWS_TOUCH
0155 if(!m_touch_available) return false;
0156 return is_message_touch_event();
0157 #else
0158 return false;
0159 #endif
0160 }
0161 protected:
0162 static LRESULT CALLBACK proc(HWND a_hwnd,UINT a_msg,WPARAM a_wparam,LPARAM a_lparam) {
0163 switch (a_msg) {
0164 case WM_SIZE:{
0165 int width = LOWORD(a_lparam);
0166 int height = HIWORD(a_lparam);
0167 pixwin* _this = (pixwin*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
0168 if(_this) {
0169 _this->resize(width,height);
0170 } else {
0171 // CreateWindow send a WM_SIZE but GWLP_USERDATA not yet set.
0172 }
0173 }return 0;
0174 case WM_PAINT:{
0175 pixwin* _this = (pixwin*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
0176 if(_this) _this->wm_paint();
0177 }return 0;
0178
0179 case WM_KEYDOWN:{
0180 pixwin* _this = (pixwin*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
0181 if(_this) {
0182 if(_this->m_interactor) {
0183 tools::sg::key_down_event event(_this->convert_key(a_wparam));
0184 _this->m_interactor->key_press(event);
0185 }
0186 }
0187 } return 0;
0188 case WM_KEYUP:{
0189 pixwin* _this = (pixwin*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
0190 if(_this) {
0191 if(_this->m_interactor) {
0192 tools::sg::key_up_event event(_this->convert_key(a_wparam));
0193 _this->m_interactor->key_release(event);
0194 }
0195 }
0196 } return 0;
0197
0198 case WM_LBUTTONDOWN:{
0199 pixwin* _this = (pixwin*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
0200 if(_this) {
0201 if(_this->m_interactor) {
0202 bool shift_modifier = ::GetKeyState(VK_SHIFT) & 0x8000;
0203 bool control_modifier = ::GetKeyState(VK_CONTROL) & 0x8000;
0204 tools::sg::mouse_down_event event(LOWORD(a_lparam),HIWORD(a_lparam),shift_modifier,control_modifier);
0205 _this->m_interactor->mouse_press(event);
0206 } else {
0207 RECT rect;
0208 ::GetClientRect(a_hwnd,&rect);
0209 unsigned int h = rect.bottom-rect.top;
0210 if(!_this->is_touch_event()) _this->left_button_down(LOWORD(a_lparam),h-HIWORD(a_lparam));
0211 }
0212 }
0213 }return 0;
0214 case WM_LBUTTONUP:{
0215 pixwin* _this = (pixwin*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
0216 if(_this) {
0217 if(_this->m_interactor) {
0218 bool shift_modifier = ::GetKeyState(VK_SHIFT) & 0x8000;
0219 bool control_modifier = ::GetKeyState(VK_CONTROL) & 0x8000;
0220 tools::sg::mouse_up_event event(LOWORD(a_lparam),HIWORD(a_lparam),shift_modifier,control_modifier);
0221 _this->m_interactor->mouse_release(event);
0222 } else {
0223 RECT rect;
0224 ::GetClientRect(a_hwnd,&rect);
0225 unsigned int h = rect.bottom-rect.top;
0226 if(!_this->is_touch_event()) _this->left_button_up(LOWORD(a_lparam),h-HIWORD(a_lparam));
0227 }
0228 }
0229 } return 0;
0230 case WM_MOUSEMOVE:{
0231 pixwin* _this = (pixwin*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
0232 if(_this) {
0233 WPARAM state = a_wparam;
0234 bool ldown = ((state & MK_LBUTTON)==MK_LBUTTON)?true:false;
0235 if(_this->m_interactor) {
0236 if(ldown) {
0237 bool shift_modifier = ::GetKeyState(VK_SHIFT) & 0x8000;
0238 bool control_modifier = ::GetKeyState(VK_CONTROL) & 0x8000;
0239 tools::sg::mouse_move_event event(LOWORD(a_lparam),HIWORD(a_lparam),shift_modifier,control_modifier,0,0,false);
0240 _this->m_interactor->mouse_move(event);
0241 }
0242 } else {
0243 RECT rect;
0244 ::GetClientRect(a_hwnd,&rect);
0245 unsigned int h = rect.bottom-rect.top;
0246 if(!_this->is_touch_event()) _this->mouse_move(LOWORD(a_lparam),h-HIWORD(a_lparam),ldown);
0247 }
0248 }
0249
0250 }return 0;
0251
0252 case WM_MOUSEWHEEL:{
0253 pixwin* _this = (pixwin*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
0254 if(_this) {
0255 if(_this->m_interactor) {
0256 bool shift_modifier = ::GetKeyState(VK_SHIFT) & 0x8000;
0257 bool control_modifier = ::GetKeyState(VK_CONTROL) & 0x8000;
0258 POINT p;
0259 p.x = LOWORD(a_lparam);
0260 p.y = HIWORD(a_lparam);
0261 if(!::ScreenToClient(a_hwnd,&p)) {}
0262 tools::sg::wheel_rotate_event event(GET_WHEEL_DELTA_WPARAM(a_wparam),int(p.x),int(p.y),shift_modifier,control_modifier);
0263 _this->m_interactor->wheel_rotate(event);
0264 }
0265 }
0266 } return 0;
0267
0268 #ifdef TOOLX_WINDOWS_TOUCH
0269 case WM_TOUCH:{
0270 pixwin* _this = (pixwin*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
0271 if(_this && _this->m_touch_available) {
0272 RECT rect;
0273 ::GetClientRect(a_hwnd,&rect);
0274 unsigned int h = rect.bottom-rect.top;
0275
0276 unsigned int num_inputs = (int)a_wparam;
0277 TOUCHINPUT* ti = new TOUCHINPUT[num_inputs];
0278 POINT p;
0279 if(::GetTouchInputInfo((HTOUCHINPUT)a_lparam,num_inputs,ti,sizeof(TOUCHINPUT))) {
0280 for(unsigned int i=0;i<num_inputs; ++i) {
0281 p.x = TOUCH_COORD_TO_PIXEL(ti[i].x);
0282 p.y = TOUCH_COORD_TO_PIXEL(ti[i].y);
0283 if(!::ScreenToClient(a_hwnd,&p)) {}
0284 if(ti[i].dwFlags & TOUCHEVENTF_DOWN) {
0285 _this->left_button_down(p.x,h-p.y);
0286 } else if (ti[i].dwFlags & TOUCHEVENTF_UP) {
0287 _this->left_button_up(p.x,h-p.y);
0288 } else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) {
0289 bool ldown = true; //we assume that a TOUCHEVENT_DOWN had been done.
0290 _this->mouse_move(p.x,h-p.y,ldown);
0291 }
0292 }
0293 }
0294 ::CloseTouchInputHandle((HTOUCHINPUT)a_lparam);
0295 delete [] ti;
0296 }
0297 }return 0;
0298 #endif //TOOLX_WINDOWS_TOUCH
0299 case WM_DESTROY:wm__destroy(a_hwnd);return 0;
0300 }
0301 return (DefWindowProc(a_hwnd,a_msg,a_wparam,a_lparam));
0302 }
0303 static bool SetWindowPixelFormat(HDC a_HDC){
0304 PIXELFORMATDESCRIPTOR pfd;
0305 pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
0306 pfd.nVersion = 1;
0307 pfd.dwFlags =
0308 PFD_DRAW_TO_WINDOW |
0309 PFD_SUPPORT_OPENGL |
0310 PFD_DOUBLEBUFFER |
0311 PFD_STEREO_DONTCARE;
0312 pfd.iPixelType = PFD_TYPE_RGBA;
0313 pfd.cColorBits = 32;
0314 pfd.cRedBits = 8;
0315 pfd.cRedShift = 16;
0316 pfd.cGreenBits = 8;
0317 pfd.cGreenShift = 8;
0318 pfd.cBlueBits = 8;
0319 pfd.cBlueShift = 0;
0320 pfd.cAlphaBits = 0;
0321 pfd.cAlphaShift = 0;
0322 pfd.cAccumBits = 64;
0323 pfd.cAccumRedBits = 16;
0324 pfd.cAccumGreenBits = 16;
0325 pfd.cAccumBlueBits = 16;
0326 pfd.cAccumAlphaBits = 0;
0327 pfd.cDepthBits = 32;
0328 pfd.cStencilBits = 8;
0329 pfd.cAuxBuffers = 0;
0330 pfd.iLayerType = PFD_MAIN_PLANE;
0331 pfd.bReserved = 0;
0332 pfd.dwLayerMask = 0;
0333 pfd.dwVisibleMask = 0;
0334 pfd.dwDamageMask = 0;
0335
0336 int pixelIndex = ::ChoosePixelFormat(a_HDC,&pfd);
0337 if (pixelIndex==0) {
0338 // Let's choose a default index.
0339 pixelIndex = 1;
0340 if (::DescribePixelFormat(a_HDC,
0341 pixelIndex,
0342 sizeof(PIXELFORMATDESCRIPTOR),
0343 &pfd)==0) {
0344 return false;
0345 }
0346 }
0347
0348 if (::SetPixelFormat(a_HDC,pixelIndex,&pfd)==FALSE) return false;
0349
0350 return true;
0351 }
0352 static void wm__destroy(HWND a_hwnd) {
0353 pixwin* _this = (pixwin*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
0354 if(_this) { //How to be sure that we have a pixwin* ???
0355 _this->close();
0356 if(_this->m_hwnd!=a_hwnd) {
0357 }
0358 _this->m_hwnd = 0;
0359 }
0360 ::SetWindowLongPtr(a_hwnd,GWLP_USERDATA,LONG_PTR(NULL));
0361 }
0362 protected:
0363 tools::key_code convert_key(WPARAM a_key) {
0364 if(a_key==VK_SHIFT) return tools::sg::key_shift();
0365 return (tools::key_code)a_key;
0366 }
0367 protected:
0368 HWND m_parent;
0369 HWND m_hwnd;
0370 bool m_touch_available;
0371 tools::sg::device_interactor* m_interactor;
0372 };
0373
0374 }}
0375
0376
0377 #endif