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  }