github.com/gop9/olt@v0.0.0-20200202132135-d956aad50b08/gio/app/internal/windows/windows.go (about) 1 // SPDX-License-Identifier: Unlicense OR MIT 2 3 // +build windows 4 5 package windows 6 7 import ( 8 "fmt" 9 "runtime" 10 "time" 11 "unsafe" 12 13 syscall "golang.org/x/sys/windows" 14 ) 15 16 type Rect struct { 17 Left, Top, Right, Bottom int32 18 } 19 20 type WndClassEx struct { 21 CbSize uint32 22 Style uint32 23 LpfnWndProc uintptr 24 CnClsExtra int32 25 CbWndExtra int32 26 HInstance syscall.Handle 27 HIcon syscall.Handle 28 HCursor syscall.Handle 29 HbrBackground syscall.Handle 30 LpszMenuName *uint16 31 LpszClassName *uint16 32 HIconSm syscall.Handle 33 } 34 35 type Msg struct { 36 Hwnd syscall.Handle 37 Message uint32 38 WParam uintptr 39 LParam uintptr 40 Time uint32 41 Pt Point 42 LPrivate uint32 43 } 44 45 type Point struct { 46 X, Y int32 47 } 48 49 const ( 50 CS_HREDRAW = 0x0002 51 CS_VREDRAW = 0x0001 52 CS_OWNDC = 0x0020 53 54 CW_USEDEFAULT = -2147483648 55 56 IDC_ARROW = 32512 57 58 INFINITE = 0xFFFFFFFF 59 60 LOGPIXELSX = 88 61 62 MDT_EFFECTIVE_DPI = 0 63 64 MONITOR_DEFAULTTOPRIMARY = 1 65 66 SIZE_MAXIMIZED = 2 67 SIZE_MINIMIZED = 1 68 SIZE_RESTORED = 0 69 70 SW_SHOWDEFAULT = 10 71 72 USER_TIMER_MINIMUM = 0x0000000A 73 74 VK_CONTROL = 0x11 75 VK_LWIN = 0x5B 76 VK_MENU = 0x12 77 VK_RWIN = 0x5C 78 VK_SHIFT = 0x10 79 80 VK_BACK = 0x08 81 VK_DELETE = 0x2e 82 VK_DOWN = 0x28 83 VK_END = 0x23 84 VK_ESCAPE = 0x1b 85 VK_HOME = 0x24 86 VK_LEFT = 0x25 87 VK_NEXT = 0x22 88 VK_PRIOR = 0x21 89 VK_RIGHT = 0x27 90 VK_RETURN = 0x0d 91 VK_SPACE = 0x20 92 VK_TAB = 0x09 93 VK_UP = 0x26 94 95 VK_F1 = 0x70 96 VK_F2 = 0x71 97 VK_F3 = 0x72 98 VK_F4 = 0x73 99 VK_F5 = 0x74 100 VK_F6 = 0x75 101 VK_F7 = 0x76 102 VK_F8 = 0x77 103 VK_F9 = 0x78 104 VK_F10 = 0x79 105 VK_F11 = 0x7A 106 VK_F12 = 0x7B 107 108 VK_OEM_1 = 0xba 109 VK_OEM_PLUS = 0xbb 110 VK_OEM_COMMA = 0xbc 111 VK_OEM_MINUS = 0xbd 112 VK_OEM_PERIOD = 0xbe 113 VK_OEM_2 = 0xbf 114 VK_OEM_3 = 0xc0 115 VK_OEM_4 = 0xdb 116 VK_OEM_5 = 0xdc 117 VK_OEM_6 = 0xdd 118 VK_OEM_7 = 0xde 119 VK_OEM_102 = 0xe2 120 121 UNICODE_NOCHAR = 65535 122 123 WM_CANCELMODE = 0x001F 124 WM_CHAR = 0x0102 125 WM_CREATE = 0x0001 126 WM_DPICHANGED = 0x02E0 127 WM_DESTROY = 0x0002 128 WM_ERASEBKGND = 0x0014 129 WM_KEYDOWN = 0x0100 130 WM_KEYUP = 0x0101 131 WM_LBUTTONDOWN = 0x0201 132 WM_LBUTTONUP = 0x0202 133 WM_MBUTTONDOWN = 0x0207 134 WM_MBUTTONUP = 0x0208 135 WM_MOUSEMOVE = 0x0200 136 WM_MOUSEWHEEL = 0x020A 137 WM_PAINT = 0x000F 138 WM_QUIT = 0x0012 139 WM_SETFOCUS = 0x0007 140 WM_KILLFOCUS = 0x0008 141 WM_SHOWWINDOW = 0x0018 142 WM_SIZE = 0x0005 143 WM_SYSKEYDOWN = 0x0104 144 WM_RBUTTONDOWN = 0x0204 145 WM_RBUTTONUP = 0x0205 146 WM_TIMER = 0x0113 147 WM_UNICHAR = 0x0109 148 WM_USER = 0x0400 149 150 WS_CLIPCHILDREN = 0x00010000 151 WS_CLIPSIBLINGS = 0x04000000 152 WS_VISIBLE = 0x10000000 153 WS_OVERLAPPED = 0x00000000 154 WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | 155 WS_MINIMIZEBOX | WS_MAXIMIZEBOX 156 WS_CAPTION = 0x00C00000 157 WS_SYSMENU = 0x00080000 158 WS_THICKFRAME = 0x00040000 159 WS_MINIMIZEBOX = 0x00020000 160 WS_MAXIMIZEBOX = 0x00010000 161 162 WS_EX_APPWINDOW = 0x00040000 163 WS_EX_WINDOWEDGE = 0x00000100 164 165 QS_ALLINPUT = 0x04FF 166 167 MWMO_WAITALL = 0x0001 168 MWMO_INPUTAVAILABLE = 0x0004 169 170 WAIT_OBJECT_0 = 0 171 172 PM_REMOVE = 0x0001 173 PM_NOREMOVE = 0x0000 174 ) 175 176 var ( 177 kernel32 = syscall.NewLazySystemDLL("kernel32.dll") 178 _GetModuleHandleW = kernel32.NewProc("GetModuleHandleW") 179 180 user32 = syscall.NewLazySystemDLL("user32.dll") 181 _AdjustWindowRectEx = user32.NewProc("AdjustWindowRectEx") 182 _CallMsgFilter = user32.NewProc("CallMsgFilterW") 183 _CreateWindowEx = user32.NewProc("CreateWindowExW") 184 _DefWindowProc = user32.NewProc("DefWindowProcW") 185 _DestroyWindow = user32.NewProc("DestroyWindow") 186 _DispatchMessage = user32.NewProc("DispatchMessageW") 187 _GetClientRect = user32.NewProc("GetClientRect") 188 _GetDC = user32.NewProc("GetDC") 189 _GetKeyState = user32.NewProc("GetKeyState") 190 _GetMessage = user32.NewProc("GetMessageW") 191 _GetMessageTime = user32.NewProc("GetMessageTime") 192 _KillTimer = user32.NewProc("KillTimer") 193 _LoadCursor = user32.NewProc("LoadCursorW") 194 _MonitorFromPoint = user32.NewProc("MonitorFromPoint") 195 _MsgWaitForMultipleObjectsEx = user32.NewProc("MsgWaitForMultipleObjectsEx") 196 _PeekMessage = user32.NewProc("PeekMessageW") 197 _PostMessage = user32.NewProc("PostMessageW") 198 _PostQuitMessage = user32.NewProc("PostQuitMessage") 199 _ReleaseCapture = user32.NewProc("ReleaseCapture") 200 _RegisterClassExW = user32.NewProc("RegisterClassExW") 201 _ReleaseDC = user32.NewProc("ReleaseDC") 202 _ScreenToClient = user32.NewProc("ScreenToClient") 203 _ShowWindow = user32.NewProc("ShowWindow") 204 _SetCapture = user32.NewProc("SetCapture") 205 _SetForegroundWindow = user32.NewProc("SetForegroundWindow") 206 _SetFocus = user32.NewProc("SetFocus") 207 _SetProcessDPIAware = user32.NewProc("SetProcessDPIAware") 208 _SetTimer = user32.NewProc("SetTimer") 209 _TranslateMessage = user32.NewProc("TranslateMessage") 210 _UnregisterClass = user32.NewProc("UnregisterClassW") 211 _UpdateWindow = user32.NewProc("UpdateWindow") 212 213 shcore = syscall.NewLazySystemDLL("shcore") 214 _GetDpiForMonitor = shcore.NewProc("GetDpiForMonitor") 215 216 gdi32 = syscall.NewLazySystemDLL("gdi32") 217 _GetDeviceCaps = gdi32.NewProc("GetDeviceCaps") 218 ) 219 220 func GetModuleHandle() (syscall.Handle, error) { 221 h, _, err := _GetModuleHandleW.Call(uintptr(0)) 222 if h == 0 { 223 return 0, fmt.Errorf("GetModuleHandleW failed: %v", err) 224 } 225 return syscall.Handle(h), nil 226 } 227 228 func AdjustWindowRectEx(r *Rect, dwStyle uint32, bMenu int, dwExStyle uint32) { 229 _AdjustWindowRectEx.Call(uintptr(unsafe.Pointer(r)), uintptr(dwStyle), uintptr(bMenu), uintptr(dwExStyle)) 230 issue34474KeepAlive(r) 231 } 232 233 func CallMsgFilter(m *Msg, nCode uintptr) bool { 234 r, _, _ := _CallMsgFilter.Call(uintptr(unsafe.Pointer(m)), nCode) 235 issue34474KeepAlive(m) 236 return r != 0 237 } 238 239 func CreateWindowEx(dwExStyle uint32, lpClassName uint16, lpWindowName string, dwStyle uint32, x, y, w, h int32, hWndParent, hMenu, hInstance syscall.Handle, lpParam uintptr) (syscall.Handle, error) { 240 wname := syscall.StringToUTF16Ptr(lpWindowName) 241 hwnd, _, err := _CreateWindowEx.Call( 242 uintptr(dwExStyle), 243 uintptr(lpClassName), 244 uintptr(unsafe.Pointer(wname)), 245 uintptr(dwStyle), 246 uintptr(x), uintptr(y), 247 uintptr(w), uintptr(h), 248 uintptr(hWndParent), 249 uintptr(hMenu), 250 uintptr(hInstance), 251 uintptr(lpParam)) 252 issue34474KeepAlive(wname) 253 if hwnd == 0 { 254 return 0, fmt.Errorf("CreateWindowEx failed: %v", err) 255 } 256 return syscall.Handle(hwnd), nil 257 } 258 259 func DefWindowProc(hwnd syscall.Handle, msg uint32, wparam, lparam uintptr) uintptr { 260 r, _, _ := _DefWindowProc.Call(uintptr(hwnd), uintptr(msg), wparam, lparam) 261 return r 262 } 263 264 func DestroyWindow(hwnd syscall.Handle) { 265 _DestroyWindow.Call(uintptr(hwnd)) 266 } 267 268 func DispatchMessage(m *Msg) { 269 _DispatchMessage.Call(uintptr(unsafe.Pointer(m))) 270 issue34474KeepAlive(m) 271 } 272 273 func GetClientRect(hwnd syscall.Handle, r *Rect) { 274 _GetClientRect.Call(uintptr(hwnd), uintptr(unsafe.Pointer(r))) 275 issue34474KeepAlive(r) 276 } 277 278 func GetDC(hwnd syscall.Handle) (syscall.Handle, error) { 279 hdc, _, err := _GetDC.Call(uintptr(hwnd)) 280 if hdc == 0 { 281 return 0, fmt.Errorf("GetDC failed: %v", err) 282 } 283 return syscall.Handle(hdc), nil 284 } 285 286 func getDeviceCaps(hdc syscall.Handle, index int32) int { 287 c, _, _ := _GetDeviceCaps.Call(uintptr(hdc), uintptr(index)) 288 return int(c) 289 } 290 291 func getDpiForMonitor(hmonitor syscall.Handle, dpiType uint32) int { 292 var dpiX, dpiY uintptr 293 _GetDpiForMonitor.Call(uintptr(hmonitor), uintptr(dpiType), uintptr(unsafe.Pointer(&dpiX)), uintptr(unsafe.Pointer(&dpiY))) 294 return int(dpiX) 295 } 296 297 // GetSystemDPI returns the effective DPI of the system. 298 func GetSystemDPI() int { 299 // Check for getDpiForMonitor, introduced in Windows 8.1. 300 if _GetDpiForMonitor.Find() == nil { 301 hmon := monitorFromPoint(Point{}, MONITOR_DEFAULTTOPRIMARY) 302 return getDpiForMonitor(hmon, MDT_EFFECTIVE_DPI) 303 } else { 304 // Fall back to the physical device DPI. 305 screenDC, err := GetDC(0) 306 if err != nil { 307 return 96 308 } 309 defer ReleaseDC(screenDC) 310 return getDeviceCaps(screenDC, LOGPIXELSX) 311 } 312 } 313 314 func GetKeyState(nVirtKey int32) int16 { 315 c, _, _ := _GetKeyState.Call(uintptr(nVirtKey)) 316 return int16(c) 317 } 318 319 func GetMessage(m *Msg, hwnd syscall.Handle, wMsgFilterMin, wMsgFilterMax uint32) int32 { 320 r, _, _ := _GetMessage.Call(uintptr(unsafe.Pointer(m)), 321 uintptr(hwnd), 322 uintptr(wMsgFilterMin), 323 uintptr(wMsgFilterMax)) 324 issue34474KeepAlive(m) 325 return int32(r) 326 } 327 328 func GetMessageTime() time.Duration { 329 r, _, _ := _GetMessageTime.Call() 330 return time.Duration(r) * time.Millisecond 331 } 332 333 func KillTimer(hwnd syscall.Handle, nIDEvent uintptr) error { 334 r, _, err := _SetTimer.Call(uintptr(hwnd), uintptr(nIDEvent), 0, 0) 335 if r == 0 { 336 return fmt.Errorf("KillTimer failed: %v", err) 337 } 338 return nil 339 } 340 341 func LoadCursor(curID uint16) (syscall.Handle, error) { 342 h, _, err := _LoadCursor.Call(0, uintptr(curID)) 343 if h == 0 { 344 return 0, fmt.Errorf("LoadCursorW failed: %v", err) 345 } 346 return syscall.Handle(h), nil 347 } 348 349 func monitorFromPoint(pt Point, flags uint32) syscall.Handle { 350 r, _, _ := _MonitorFromPoint.Call(uintptr(pt.X), uintptr(pt.Y), uintptr(flags)) 351 return syscall.Handle(r) 352 } 353 354 func MsgWaitForMultipleObjectsEx(nCount uint32, pHandles uintptr, millis, mask, flags uint32) (uint32, error) { 355 r, _, err := _MsgWaitForMultipleObjectsEx.Call(uintptr(nCount), pHandles, uintptr(millis), uintptr(mask), uintptr(flags)) 356 res := uint32(r) 357 if res == 0xFFFFFFFF { 358 return 0, fmt.Errorf("MsgWaitForMultipleObjectsEx failed: %v", err) 359 } 360 return res, nil 361 } 362 363 func PeekMessage(m *Msg, hwnd syscall.Handle, wMsgFilterMin, wMsgFilterMax, wRemoveMsg uint32) bool { 364 r, _, _ := _PeekMessage.Call(uintptr(unsafe.Pointer(m)), uintptr(hwnd), uintptr(wMsgFilterMin), uintptr(wMsgFilterMax), uintptr(wRemoveMsg)) 365 issue34474KeepAlive(m) 366 return r != 0 367 } 368 369 func PostQuitMessage(exitCode uintptr) { 370 _PostQuitMessage.Call(exitCode) 371 } 372 373 func PostMessage(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) error { 374 r, _, err := _PostMessage.Call(uintptr(hwnd), uintptr(msg), wParam, lParam) 375 if r == 0 { 376 return fmt.Errorf("PostMessage failed: %v", err) 377 } 378 return nil 379 } 380 381 func ReleaseCapture() bool { 382 r, _, _ := _ReleaseCapture.Call() 383 return r != 0 384 } 385 386 func RegisterClassEx(cls *WndClassEx) (uint16, error) { 387 a, _, err := _RegisterClassExW.Call(uintptr(unsafe.Pointer(cls))) 388 issue34474KeepAlive(cls) 389 if a == 0 { 390 return 0, fmt.Errorf("RegisterClassExW failed: %v", err) 391 } 392 return uint16(a), nil 393 } 394 395 func ReleaseDC(hdc syscall.Handle) { 396 _ReleaseDC.Call(uintptr(hdc)) 397 } 398 399 func SetForegroundWindow(hwnd syscall.Handle) { 400 _SetForegroundWindow.Call(uintptr(hwnd)) 401 } 402 403 func SetFocus(hwnd syscall.Handle) { 404 _SetFocus.Call(uintptr(hwnd)) 405 } 406 407 func SetProcessDPIAware() { 408 _SetProcessDPIAware.Call() 409 } 410 411 func SetCapture(hwnd syscall.Handle) syscall.Handle { 412 r, _, _ := _SetCapture.Call(uintptr(hwnd)) 413 return syscall.Handle(r) 414 } 415 416 func SetTimer(hwnd syscall.Handle, nIDEvent uintptr, uElapse uint32, timerProc uintptr) error { 417 r, _, err := _SetTimer.Call(uintptr(hwnd), uintptr(nIDEvent), uintptr(uElapse), timerProc) 418 if r == 0 { 419 return fmt.Errorf("SetTimer failed: %v", err) 420 } 421 return nil 422 } 423 424 func ScreenToClient(hwnd syscall.Handle, p *Point) { 425 _ScreenToClient.Call(uintptr(hwnd), uintptr(unsafe.Pointer(p))) 426 issue34474KeepAlive(p) 427 } 428 429 func ShowWindow(hwnd syscall.Handle, nCmdShow int32) { 430 _ShowWindow.Call(uintptr(hwnd), uintptr(nCmdShow)) 431 } 432 433 func TranslateMessage(m *Msg) { 434 _TranslateMessage.Call(uintptr(unsafe.Pointer(m))) 435 issue34474KeepAlive(m) 436 } 437 438 func UnregisterClass(cls uint16, hInst syscall.Handle) { 439 _UnregisterClass.Call(uintptr(cls), uintptr(hInst)) 440 } 441 442 func UpdateWindow(hwnd syscall.Handle) { 443 _UpdateWindow.Call(uintptr(hwnd)) 444 } 445 446 // issue34474KeepAlive calls runtime.KeepAlive as a 447 // workaround for golang.org/issue/34474. 448 func issue34474KeepAlive(v interface{}) { 449 runtime.KeepAlive(v) 450 }