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