mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-04 08:55:35 +00:00
app/internal/windows: split out Windows syscalls from package window
Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
+116
-551
@@ -4,7 +4,6 @@ package window
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
"runtime"
|
||||
"sync"
|
||||
@@ -14,6 +13,8 @@ import (
|
||||
|
||||
syscall "golang.org/x/sys/windows"
|
||||
|
||||
"gioui.org/app/internal/windows"
|
||||
|
||||
"gioui.org/f32"
|
||||
"gioui.org/io/key"
|
||||
"gioui.org/io/pointer"
|
||||
@@ -22,39 +23,6 @@ import (
|
||||
|
||||
var winMap = make(map[syscall.Handle]*window)
|
||||
|
||||
type rect struct {
|
||||
left, top, right, bottom int32
|
||||
}
|
||||
|
||||
type wndClassEx struct {
|
||||
cbSize uint32
|
||||
style uint32
|
||||
lpfnWndProc uintptr
|
||||
cnClsExtra int32
|
||||
cbWndExtra int32
|
||||
hInstance syscall.Handle
|
||||
hIcon syscall.Handle
|
||||
hCursor syscall.Handle
|
||||
hbrBackground syscall.Handle
|
||||
lpszMenuName *uint16
|
||||
lpszClassName *uint16
|
||||
hIconSm syscall.Handle
|
||||
}
|
||||
|
||||
type msg struct {
|
||||
hwnd syscall.Handle
|
||||
message uint32
|
||||
wParam uintptr
|
||||
lParam uintptr
|
||||
time uint32
|
||||
pt point
|
||||
lPrivate uint32
|
||||
}
|
||||
|
||||
type point struct {
|
||||
x, y int32
|
||||
}
|
||||
|
||||
type window struct {
|
||||
hwnd syscall.Handle
|
||||
hdc syscall.Handle
|
||||
@@ -69,134 +37,7 @@ type window struct {
|
||||
animating bool
|
||||
}
|
||||
|
||||
const (
|
||||
_CS_HREDRAW = 0x0002
|
||||
_CS_VREDRAW = 0x0001
|
||||
_CS_OWNDC = 0x0020
|
||||
|
||||
_CW_USEDEFAULT = -2147483648
|
||||
|
||||
_IDC_ARROW = 32512
|
||||
|
||||
_INFINITE = 0xFFFFFFFF
|
||||
|
||||
_LOGPIXELSX = 88
|
||||
|
||||
_MDT_EFFECTIVE_DPI = 0
|
||||
|
||||
_MONITOR_DEFAULTTOPRIMARY = 1
|
||||
|
||||
_SIZE_MAXIMIZED = 2
|
||||
_SIZE_MINIMIZED = 1
|
||||
_SIZE_RESTORED = 0
|
||||
|
||||
_SW_SHOWDEFAULT = 10
|
||||
|
||||
_USER_TIMER_MINIMUM = 0x0000000A
|
||||
|
||||
_VK_CONTROL = 0x11
|
||||
_VK_LWIN = 0x5B
|
||||
_VK_MENU = 0x12
|
||||
_VK_RWIN = 0x5C
|
||||
_VK_SHIFT = 0x10
|
||||
|
||||
_VK_BACK = 0x08
|
||||
_VK_DELETE = 0x2e
|
||||
_VK_DOWN = 0x28
|
||||
_VK_END = 0x23
|
||||
_VK_ESCAPE = 0x1b
|
||||
_VK_HOME = 0x24
|
||||
_VK_LEFT = 0x25
|
||||
_VK_NEXT = 0x22
|
||||
_VK_PRIOR = 0x21
|
||||
_VK_RIGHT = 0x27
|
||||
_VK_RETURN = 0x0d
|
||||
_VK_SPACE = 0x20
|
||||
_VK_TAB = 0x09
|
||||
_VK_UP = 0x26
|
||||
|
||||
_VK_F1 = 0x70
|
||||
_VK_F2 = 0x71
|
||||
_VK_F3 = 0x72
|
||||
_VK_F4 = 0x73
|
||||
_VK_F5 = 0x74
|
||||
_VK_F6 = 0x75
|
||||
_VK_F7 = 0x76
|
||||
_VK_F8 = 0x77
|
||||
_VK_F9 = 0x78
|
||||
_VK_F10 = 0x79
|
||||
_VK_F11 = 0x7A
|
||||
_VK_F12 = 0x7B
|
||||
|
||||
_VK_OEM_1 = 0xba
|
||||
_VK_OEM_PLUS = 0xbb
|
||||
_VK_OEM_COMMA = 0xbc
|
||||
_VK_OEM_MINUS = 0xbd
|
||||
_VK_OEM_PERIOD = 0xbe
|
||||
_VK_OEM_2 = 0xbf
|
||||
_VK_OEM_3 = 0xc0
|
||||
_VK_OEM_4 = 0xdb
|
||||
_VK_OEM_5 = 0xdc
|
||||
_VK_OEM_6 = 0xdd
|
||||
_VK_OEM_7 = 0xde
|
||||
_VK_OEM_102 = 0xe2
|
||||
|
||||
_UNICODE_NOCHAR = 65535
|
||||
|
||||
_WM_CANCELMODE = 0x001F
|
||||
_WM_CHAR = 0x0102
|
||||
_WM_CREATE = 0x0001
|
||||
_WM_DPICHANGED = 0x02E0
|
||||
_WM_DESTROY = 0x0002
|
||||
_WM_ERASEBKGND = 0x0014
|
||||
_WM_KEYDOWN = 0x0100
|
||||
_WM_KEYUP = 0x0101
|
||||
_WM_LBUTTONDOWN = 0x0201
|
||||
_WM_LBUTTONUP = 0x0202
|
||||
_WM_MBUTTONDOWN = 0x0207
|
||||
_WM_MBUTTONUP = 0x0208
|
||||
_WM_MOUSEMOVE = 0x0200
|
||||
_WM_MOUSEWHEEL = 0x020A
|
||||
_WM_PAINT = 0x000F
|
||||
_WM_QUIT = 0x0012
|
||||
_WM_SETFOCUS = 0x0007
|
||||
_WM_KILLFOCUS = 0x0008
|
||||
_WM_SHOWWINDOW = 0x0018
|
||||
_WM_SIZE = 0x0005
|
||||
_WM_SYSKEYDOWN = 0x0104
|
||||
_WM_RBUTTONDOWN = 0x0204
|
||||
_WM_RBUTTONUP = 0x0205
|
||||
_WM_TIMER = 0x0113
|
||||
_WM_UNICHAR = 0x0109
|
||||
_WM_USER = 0x0400
|
||||
|
||||
_WS_CLIPCHILDREN = 0x00010000
|
||||
_WS_CLIPSIBLINGS = 0x04000000
|
||||
_WS_VISIBLE = 0x10000000
|
||||
_WS_OVERLAPPED = 0x00000000
|
||||
_WS_OVERLAPPEDWINDOW = _WS_OVERLAPPED | _WS_CAPTION | _WS_SYSMENU | _WS_THICKFRAME |
|
||||
_WS_MINIMIZEBOX | _WS_MAXIMIZEBOX
|
||||
_WS_CAPTION = 0x00C00000
|
||||
_WS_SYSMENU = 0x00080000
|
||||
_WS_THICKFRAME = 0x00040000
|
||||
_WS_MINIMIZEBOX = 0x00020000
|
||||
_WS_MAXIMIZEBOX = 0x00010000
|
||||
|
||||
_WS_EX_APPWINDOW = 0x00040000
|
||||
_WS_EX_WINDOWEDGE = 0x00000100
|
||||
|
||||
_QS_ALLINPUT = 0x04FF
|
||||
|
||||
_MWMO_WAITALL = 0x0001
|
||||
_MWMO_INPUTAVAILABLE = 0x0004
|
||||
|
||||
_WAIT_OBJECT_0 = 0
|
||||
|
||||
_PM_REMOVE = 0x0001
|
||||
_PM_NOREMOVE = 0x0000
|
||||
)
|
||||
|
||||
const _WM_REDRAW = _WM_USER + 0
|
||||
const _WM_REDRAW = windows.WM_USER + 0
|
||||
|
||||
var onceMu sync.Mutex
|
||||
var mainDone = make(chan struct{})
|
||||
@@ -227,9 +68,9 @@ func NewWindow(window Callbacks, opts *Options) error {
|
||||
w.w = window
|
||||
w.w.SetDriver(w)
|
||||
defer w.w.Event(system.DestroyEvent{})
|
||||
showWindow(w.hwnd, _SW_SHOWDEFAULT)
|
||||
setForegroundWindow(w.hwnd)
|
||||
setFocus(w.hwnd)
|
||||
windows.ShowWindow(w.hwnd, windows.SW_SHOWDEFAULT)
|
||||
windows.SetForegroundWindow(w.hwnd)
|
||||
windows.SetFocus(w.hwnd)
|
||||
if err := w.loop(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -239,42 +80,42 @@ func NewWindow(window Callbacks, opts *Options) error {
|
||||
}
|
||||
|
||||
func createNativeWindow(opts *Options) (*window, error) {
|
||||
setProcessDPIAware()
|
||||
windows.SetProcessDPIAware()
|
||||
cfg := configForDC()
|
||||
hInst, err := getModuleHandle()
|
||||
hInst, err := windows.GetModuleHandle()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
curs, err := loadCursor(_IDC_ARROW)
|
||||
curs, err := windows.LoadCursor(windows.IDC_ARROW)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wcls := wndClassEx{
|
||||
cbSize: uint32(unsafe.Sizeof(wndClassEx{})),
|
||||
style: _CS_HREDRAW | _CS_VREDRAW | _CS_OWNDC,
|
||||
lpfnWndProc: syscall.NewCallback(windowProc),
|
||||
hInstance: hInst,
|
||||
hCursor: curs,
|
||||
lpszClassName: syscall.StringToUTF16Ptr("GioWindow"),
|
||||
wcls := windows.WndClassEx{
|
||||
CbSize: uint32(unsafe.Sizeof(windows.WndClassEx{})),
|
||||
Style: windows.CS_HREDRAW | windows.CS_VREDRAW | windows.CS_OWNDC,
|
||||
LpfnWndProc: syscall.NewCallback(windowProc),
|
||||
HInstance: hInst,
|
||||
HCursor: curs,
|
||||
LpszClassName: syscall.StringToUTF16Ptr("GioWindow"),
|
||||
}
|
||||
cls, err := registerClassEx(&wcls)
|
||||
cls, err := windows.RegisterClassEx(&wcls)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wr := rect{
|
||||
right: int32(cfg.Px(opts.Width)),
|
||||
bottom: int32(cfg.Px(opts.Height)),
|
||||
wr := windows.Rect{
|
||||
Right: int32(cfg.Px(opts.Width)),
|
||||
Bottom: int32(cfg.Px(opts.Height)),
|
||||
}
|
||||
dwStyle := uint32(_WS_OVERLAPPEDWINDOW)
|
||||
dwExStyle := uint32(_WS_EX_APPWINDOW | _WS_EX_WINDOWEDGE)
|
||||
adjustWindowRectEx(&wr, dwStyle, 0, dwExStyle)
|
||||
hwnd, err := createWindowEx(dwExStyle,
|
||||
dwStyle := uint32(windows.WS_OVERLAPPEDWINDOW)
|
||||
dwExStyle := uint32(windows.WS_EX_APPWINDOW | windows.WS_EX_WINDOWEDGE)
|
||||
windows.AdjustWindowRectEx(&wr, dwStyle, 0, dwExStyle)
|
||||
hwnd, err := windows.CreateWindowEx(dwExStyle,
|
||||
cls,
|
||||
opts.Title,
|
||||
dwStyle|_WS_CLIPSIBLINGS|_WS_CLIPCHILDREN,
|
||||
_CW_USEDEFAULT, _CW_USEDEFAULT,
|
||||
wr.right-wr.left,
|
||||
wr.bottom-wr.top,
|
||||
dwStyle|windows.WS_CLIPSIBLINGS|windows.WS_CLIPCHILDREN,
|
||||
windows.CW_USEDEFAULT, windows.CW_USEDEFAULT,
|
||||
wr.Right-wr.Left,
|
||||
wr.Bottom-wr.Top,
|
||||
0,
|
||||
0,
|
||||
hInst,
|
||||
@@ -285,7 +126,7 @@ func createNativeWindow(opts *Options) (*window, error) {
|
||||
w := &window{
|
||||
hwnd: hwnd,
|
||||
}
|
||||
w.hdc, err = getDC(hwnd)
|
||||
w.hdc, err = windows.GetDC(hwnd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -295,86 +136,86 @@ func createNativeWindow(opts *Options) (*window, error) {
|
||||
func windowProc(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) uintptr {
|
||||
w := winMap[hwnd]
|
||||
switch msg {
|
||||
case _WM_UNICHAR:
|
||||
if wParam == _UNICODE_NOCHAR {
|
||||
case windows.WM_UNICHAR:
|
||||
if wParam == windows.UNICODE_NOCHAR {
|
||||
// Tell the system that we accept WM_UNICHAR messages.
|
||||
return 1
|
||||
}
|
||||
fallthrough
|
||||
case _WM_CHAR:
|
||||
case windows.WM_CHAR:
|
||||
if r := rune(wParam); unicode.IsPrint(r) {
|
||||
w.w.Event(key.EditEvent{Text: string(r)})
|
||||
}
|
||||
// The message is processed.
|
||||
return 1
|
||||
case _WM_DPICHANGED:
|
||||
case windows.WM_DPICHANGED:
|
||||
// Let Windows know we're prepared for runtime DPI changes.
|
||||
return 1
|
||||
case _WM_ERASEBKGND:
|
||||
case windows.WM_ERASEBKGND:
|
||||
// Avoid flickering between GPU content and background color.
|
||||
return 1
|
||||
case _WM_KEYDOWN, _WM_SYSKEYDOWN:
|
||||
case windows.WM_KEYDOWN, windows.WM_SYSKEYDOWN:
|
||||
if n, ok := convertKeyCode(wParam); ok {
|
||||
w.w.Event(key.Event{Name: n, Modifiers: getModifiers()})
|
||||
}
|
||||
case _WM_LBUTTONDOWN:
|
||||
case windows.WM_LBUTTONDOWN:
|
||||
w.pointerButton(pointer.ButtonLeft, true, lParam, getModifiers())
|
||||
case _WM_LBUTTONUP:
|
||||
case windows.WM_LBUTTONUP:
|
||||
w.pointerButton(pointer.ButtonLeft, false, lParam, getModifiers())
|
||||
case _WM_RBUTTONDOWN:
|
||||
case windows.WM_RBUTTONDOWN:
|
||||
w.pointerButton(pointer.ButtonRight, true, lParam, getModifiers())
|
||||
case _WM_RBUTTONUP:
|
||||
case windows.WM_RBUTTONUP:
|
||||
w.pointerButton(pointer.ButtonRight, false, lParam, getModifiers())
|
||||
case _WM_MBUTTONDOWN:
|
||||
case windows.WM_MBUTTONDOWN:
|
||||
w.pointerButton(pointer.ButtonMiddle, true, lParam, getModifiers())
|
||||
case _WM_MBUTTONUP:
|
||||
case windows.WM_MBUTTONUP:
|
||||
w.pointerButton(pointer.ButtonMiddle, false, lParam, getModifiers())
|
||||
case _WM_CANCELMODE:
|
||||
case windows.WM_CANCELMODE:
|
||||
w.w.Event(pointer.Event{
|
||||
Type: pointer.Cancel,
|
||||
})
|
||||
case _WM_SETFOCUS:
|
||||
case windows.WM_SETFOCUS:
|
||||
w.w.Event(key.FocusEvent{Focus: true})
|
||||
case _WM_KILLFOCUS:
|
||||
case windows.WM_KILLFOCUS:
|
||||
w.w.Event(key.FocusEvent{Focus: false})
|
||||
case _WM_MOUSEMOVE:
|
||||
case windows.WM_MOUSEMOVE:
|
||||
x, y := coordsFromlParam(lParam)
|
||||
p := f32.Point{X: float32(x), Y: float32(y)}
|
||||
w.w.Event(pointer.Event{
|
||||
Type: pointer.Move,
|
||||
Source: pointer.Mouse,
|
||||
Position: p,
|
||||
Time: getMessageTime(),
|
||||
Time: windows.GetMessageTime(),
|
||||
})
|
||||
case _WM_MOUSEWHEEL:
|
||||
case windows.WM_MOUSEWHEEL:
|
||||
w.scrollEvent(wParam, lParam)
|
||||
case _WM_DESTROY:
|
||||
case windows.WM_DESTROY:
|
||||
w.dead = true
|
||||
case _WM_PAINT:
|
||||
case windows.WM_PAINT:
|
||||
w.draw(true)
|
||||
case _WM_SIZE:
|
||||
case windows.WM_SIZE:
|
||||
switch wParam {
|
||||
case _SIZE_MINIMIZED:
|
||||
case windows.SIZE_MINIMIZED:
|
||||
w.setStage(system.StagePaused)
|
||||
case _SIZE_MAXIMIZED, _SIZE_RESTORED:
|
||||
case windows.SIZE_MAXIMIZED, windows.SIZE_RESTORED:
|
||||
w.setStage(system.StageRunning)
|
||||
}
|
||||
}
|
||||
return defWindowProc(hwnd, msg, wParam, lParam)
|
||||
return windows.DefWindowProc(hwnd, msg, wParam, lParam)
|
||||
}
|
||||
|
||||
func getModifiers() key.Modifiers {
|
||||
var kmods key.Modifiers
|
||||
if getKeyState(_VK_LWIN)&0x1000 != 0 || getKeyState(_VK_RWIN)&0x1000 != 0 {
|
||||
if windows.GetKeyState(windows.VK_LWIN)&0x1000 != 0 || windows.GetKeyState(windows.VK_RWIN)&0x1000 != 0 {
|
||||
kmods |= key.ModSuper
|
||||
}
|
||||
if getKeyState(_VK_MENU)&0x1000 != 0 {
|
||||
if windows.GetKeyState(windows.VK_MENU)&0x1000 != 0 {
|
||||
kmods |= key.ModAlt
|
||||
}
|
||||
if getKeyState(_VK_CONTROL)&0x1000 != 0 {
|
||||
if windows.GetKeyState(windows.VK_CONTROL)&0x1000 != 0 {
|
||||
kmods |= key.ModCtrl
|
||||
}
|
||||
if getKeyState(_VK_SHIFT)&0x1000 != 0 {
|
||||
if windows.GetKeyState(windows.VK_SHIFT)&0x1000 != 0 {
|
||||
kmods |= key.ModShift
|
||||
}
|
||||
return kmods
|
||||
@@ -385,14 +226,14 @@ func (w *window) pointerButton(btn pointer.Buttons, press bool, lParam uintptr,
|
||||
if press {
|
||||
typ = pointer.Press
|
||||
if w.pointerBtns == 0 {
|
||||
setCapture(w.hwnd)
|
||||
windows.SetCapture(w.hwnd)
|
||||
}
|
||||
w.pointerBtns |= btn
|
||||
} else {
|
||||
typ = pointer.Release
|
||||
w.pointerBtns &^= btn
|
||||
if w.pointerBtns == 0 {
|
||||
releaseCapture()
|
||||
windows.ReleaseCapture()
|
||||
}
|
||||
}
|
||||
x, y := coordsFromlParam(lParam)
|
||||
@@ -402,7 +243,7 @@ func (w *window) pointerButton(btn pointer.Buttons, press bool, lParam uintptr,
|
||||
Source: pointer.Mouse,
|
||||
Position: p,
|
||||
Buttons: w.pointerBtns,
|
||||
Time: getMessageTime(),
|
||||
Time: windows.GetMessageTime(),
|
||||
Modifiers: kmods,
|
||||
})
|
||||
}
|
||||
@@ -417,37 +258,37 @@ func (w *window) scrollEvent(wParam, lParam uintptr) {
|
||||
x, y := coordsFromlParam(lParam)
|
||||
// The WM_MOUSEWHEEL coordinates are in screen coordinates, in contrast
|
||||
// to other mouse events.
|
||||
np := point{x: int32(x), y: int32(y)}
|
||||
screenToClient(w.hwnd, &np)
|
||||
p := f32.Point{X: float32(np.x), Y: float32(np.y)}
|
||||
np := windows.Point{X: int32(x), Y: int32(y)}
|
||||
windows.ScreenToClient(w.hwnd, &np)
|
||||
p := f32.Point{X: float32(np.X), Y: float32(np.Y)}
|
||||
dist := float32(int16(wParam >> 16))
|
||||
w.w.Event(pointer.Event{
|
||||
Type: pointer.Move,
|
||||
Source: pointer.Mouse,
|
||||
Position: p,
|
||||
Scroll: f32.Point{Y: -dist},
|
||||
Time: getMessageTime(),
|
||||
Time: windows.GetMessageTime(),
|
||||
})
|
||||
}
|
||||
|
||||
// Adapted from https://blogs.msdn.microsoft.com/oldnewthing/20060126-00/?p=32513/
|
||||
func (w *window) loop() error {
|
||||
msg := new(msg)
|
||||
msg := new(windows.Msg)
|
||||
for !w.dead {
|
||||
w.mu.Lock()
|
||||
anim := w.animating
|
||||
w.mu.Unlock()
|
||||
if anim && !peekMessage(msg, w.hwnd, 0, 0, _PM_NOREMOVE) {
|
||||
if anim && !windows.PeekMessage(msg, w.hwnd, 0, 0, windows.PM_NOREMOVE) {
|
||||
w.draw(false)
|
||||
continue
|
||||
}
|
||||
getMessage(msg, w.hwnd, 0, 0)
|
||||
if msg.message == _WM_QUIT {
|
||||
postQuitMessage(msg.wParam)
|
||||
windows.GetMessage(msg, w.hwnd, 0, 0)
|
||||
if msg.Message == windows.WM_QUIT {
|
||||
windows.PostQuitMessage(msg.WParam)
|
||||
break
|
||||
}
|
||||
translateMessage(msg)
|
||||
dispatchMessage(msg)
|
||||
windows.TranslateMessage(msg)
|
||||
windows.DispatchMessage(msg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -462,7 +303,7 @@ func (w *window) SetAnimating(anim bool) {
|
||||
}
|
||||
|
||||
func (w *window) postRedraw() {
|
||||
if err := postMessage(w.hwnd, _WM_REDRAW, 0, 0); err != nil {
|
||||
if err := windows.PostMessage(w.hwnd, _WM_REDRAW, 0, 0); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
@@ -473,10 +314,10 @@ func (w *window) setStage(s system.Stage) {
|
||||
}
|
||||
|
||||
func (w *window) draw(sync bool) {
|
||||
var r rect
|
||||
getClientRect(w.hwnd, &r)
|
||||
w.width = int(r.right - r.left)
|
||||
w.height = int(r.bottom - r.top)
|
||||
var r windows.Rect
|
||||
windows.GetClientRect(w.hwnd, &r)
|
||||
w.width = int(r.Right - r.Left)
|
||||
w.height = int(r.Bottom - r.Top)
|
||||
cfg := configForDC()
|
||||
cfg.now = time.Now()
|
||||
w.w.Event(FrameEvent{
|
||||
@@ -493,11 +334,11 @@ func (w *window) draw(sync bool) {
|
||||
|
||||
func (w *window) destroy() {
|
||||
if w.hdc != 0 {
|
||||
releaseDC(w.hdc)
|
||||
windows.ReleaseDC(w.hdc)
|
||||
w.hdc = 0
|
||||
}
|
||||
if w.hwnd != 0 {
|
||||
destroyWindow(w.hwnd)
|
||||
windows.DestroyWindow(w.hwnd)
|
||||
w.hwnd = 0
|
||||
}
|
||||
}
|
||||
@@ -518,79 +359,79 @@ func convertKeyCode(code uintptr) (string, bool) {
|
||||
}
|
||||
var r string
|
||||
switch code {
|
||||
case _VK_ESCAPE:
|
||||
case windows.VK_ESCAPE:
|
||||
r = key.NameEscape
|
||||
case _VK_LEFT:
|
||||
case windows.VK_LEFT:
|
||||
r = key.NameLeftArrow
|
||||
case _VK_RIGHT:
|
||||
case windows.VK_RIGHT:
|
||||
r = key.NameRightArrow
|
||||
case _VK_RETURN:
|
||||
case windows.VK_RETURN:
|
||||
r = key.NameReturn
|
||||
case _VK_UP:
|
||||
case windows.VK_UP:
|
||||
r = key.NameUpArrow
|
||||
case _VK_DOWN:
|
||||
case windows.VK_DOWN:
|
||||
r = key.NameDownArrow
|
||||
case _VK_HOME:
|
||||
case windows.VK_HOME:
|
||||
r = key.NameHome
|
||||
case _VK_END:
|
||||
case windows.VK_END:
|
||||
r = key.NameEnd
|
||||
case _VK_BACK:
|
||||
case windows.VK_BACK:
|
||||
r = key.NameDeleteBackward
|
||||
case _VK_DELETE:
|
||||
case windows.VK_DELETE:
|
||||
r = key.NameDeleteForward
|
||||
case _VK_PRIOR:
|
||||
case windows.VK_PRIOR:
|
||||
r = key.NamePageUp
|
||||
case _VK_NEXT:
|
||||
case windows.VK_NEXT:
|
||||
r = key.NamePageDown
|
||||
case _VK_F1:
|
||||
case windows.VK_F1:
|
||||
r = "F1"
|
||||
case _VK_F2:
|
||||
case windows.VK_F2:
|
||||
r = "F2"
|
||||
case _VK_F3:
|
||||
case windows.VK_F3:
|
||||
r = "F3"
|
||||
case _VK_F4:
|
||||
case windows.VK_F4:
|
||||
r = "F4"
|
||||
case _VK_F5:
|
||||
case windows.VK_F5:
|
||||
r = "F5"
|
||||
case _VK_F6:
|
||||
case windows.VK_F6:
|
||||
r = "F6"
|
||||
case _VK_F7:
|
||||
case windows.VK_F7:
|
||||
r = "F7"
|
||||
case _VK_F8:
|
||||
case windows.VK_F8:
|
||||
r = "F8"
|
||||
case _VK_F9:
|
||||
case windows.VK_F9:
|
||||
r = "F9"
|
||||
case _VK_F10:
|
||||
case windows.VK_F10:
|
||||
r = "F10"
|
||||
case _VK_F11:
|
||||
case windows.VK_F11:
|
||||
r = "F11"
|
||||
case _VK_F12:
|
||||
case windows.VK_F12:
|
||||
r = "F12"
|
||||
case _VK_TAB:
|
||||
case windows.VK_TAB:
|
||||
r = key.NameTab
|
||||
case _VK_SPACE:
|
||||
case windows.VK_SPACE:
|
||||
r = "Space"
|
||||
case _VK_OEM_1:
|
||||
case windows.VK_OEM_1:
|
||||
r = ";"
|
||||
case _VK_OEM_PLUS:
|
||||
case windows.VK_OEM_PLUS:
|
||||
r = "+"
|
||||
case _VK_OEM_COMMA:
|
||||
case windows.VK_OEM_COMMA:
|
||||
r = ","
|
||||
case _VK_OEM_MINUS:
|
||||
case windows.VK_OEM_MINUS:
|
||||
r = "-"
|
||||
case _VK_OEM_PERIOD:
|
||||
case windows.VK_OEM_PERIOD:
|
||||
r = "."
|
||||
case _VK_OEM_2:
|
||||
case windows.VK_OEM_2:
|
||||
r = "/"
|
||||
case _VK_OEM_3:
|
||||
case windows.VK_OEM_3:
|
||||
r = "`"
|
||||
case _VK_OEM_4:
|
||||
case windows.VK_OEM_4:
|
||||
r = "["
|
||||
case _VK_OEM_5, _VK_OEM_102:
|
||||
case windows.VK_OEM_5, windows.VK_OEM_102:
|
||||
r = "\\"
|
||||
case _VK_OEM_6:
|
||||
case windows.VK_OEM_6:
|
||||
r = "]"
|
||||
case _VK_OEM_7:
|
||||
case windows.VK_OEM_7:
|
||||
r = "'"
|
||||
default:
|
||||
return "", false
|
||||
@@ -599,7 +440,7 @@ func convertKeyCode(code uintptr) (string, bool) {
|
||||
}
|
||||
|
||||
func configForDC() config {
|
||||
dpi := getSystemDPI()
|
||||
dpi := windows.GetSystemDPI()
|
||||
const inchPrDp = 1.0 / 96.0
|
||||
ppdp := float32(dpi) * inchPrDp
|
||||
return config{
|
||||
@@ -607,279 +448,3 @@ func configForDC() config {
|
||||
pxPerSp: ppdp,
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
kernel32 = syscall.NewLazySystemDLL("kernel32.dll")
|
||||
_GetModuleHandleW = kernel32.NewProc("GetModuleHandleW")
|
||||
|
||||
user32 = syscall.NewLazySystemDLL("user32.dll")
|
||||
_AdjustWindowRectEx = user32.NewProc("AdjustWindowRectEx")
|
||||
_CallMsgFilter = user32.NewProc("CallMsgFilterW")
|
||||
_CreateWindowEx = user32.NewProc("CreateWindowExW")
|
||||
_DefWindowProc = user32.NewProc("DefWindowProcW")
|
||||
_DestroyWindow = user32.NewProc("DestroyWindow")
|
||||
_DispatchMessage = user32.NewProc("DispatchMessageW")
|
||||
_GetClientRect = user32.NewProc("GetClientRect")
|
||||
_GetDC = user32.NewProc("GetDC")
|
||||
_GetKeyState = user32.NewProc("GetKeyState")
|
||||
_GetMessage = user32.NewProc("GetMessageW")
|
||||
_GetMessageTime = user32.NewProc("GetMessageTime")
|
||||
_KillTimer = user32.NewProc("KillTimer")
|
||||
_LoadCursor = user32.NewProc("LoadCursorW")
|
||||
_MonitorFromPoint = user32.NewProc("MonitorFromPoint")
|
||||
_MsgWaitForMultipleObjectsEx = user32.NewProc("MsgWaitForMultipleObjectsEx")
|
||||
_PeekMessage = user32.NewProc("PeekMessageW")
|
||||
_PostMessage = user32.NewProc("PostMessageW")
|
||||
_PostQuitMessage = user32.NewProc("PostQuitMessage")
|
||||
_ReleaseCapture = user32.NewProc("ReleaseCapture")
|
||||
_RegisterClassExW = user32.NewProc("RegisterClassExW")
|
||||
_ReleaseDC = user32.NewProc("ReleaseDC")
|
||||
_ScreenToClient = user32.NewProc("ScreenToClient")
|
||||
_ShowWindow = user32.NewProc("ShowWindow")
|
||||
_SetCapture = user32.NewProc("SetCapture")
|
||||
_SetForegroundWindow = user32.NewProc("SetForegroundWindow")
|
||||
_SetFocus = user32.NewProc("SetFocus")
|
||||
_SetProcessDPIAware = user32.NewProc("SetProcessDPIAware")
|
||||
_SetTimer = user32.NewProc("SetTimer")
|
||||
_TranslateMessage = user32.NewProc("TranslateMessage")
|
||||
_UnregisterClass = user32.NewProc("UnregisterClassW")
|
||||
_UpdateWindow = user32.NewProc("UpdateWindow")
|
||||
|
||||
shcore = syscall.NewLazySystemDLL("shcore")
|
||||
_GetDpiForMonitor = shcore.NewProc("GetDpiForMonitor")
|
||||
|
||||
gdi32 = syscall.NewLazySystemDLL("gdi32")
|
||||
_GetDeviceCaps = gdi32.NewProc("GetDeviceCaps")
|
||||
)
|
||||
|
||||
func getModuleHandle() (syscall.Handle, error) {
|
||||
h, _, err := _GetModuleHandleW.Call(uintptr(0))
|
||||
if h == 0 {
|
||||
return 0, fmt.Errorf("GetModuleHandleW failed: %v", err)
|
||||
}
|
||||
return syscall.Handle(h), nil
|
||||
}
|
||||
|
||||
func adjustWindowRectEx(r *rect, dwStyle uint32, bMenu int, dwExStyle uint32) {
|
||||
_AdjustWindowRectEx.Call(uintptr(unsafe.Pointer(r)), uintptr(dwStyle), uintptr(bMenu), uintptr(dwExStyle))
|
||||
issue34474KeepAlive(r)
|
||||
}
|
||||
|
||||
func callMsgFilter(m *msg, nCode uintptr) bool {
|
||||
r, _, _ := _CallMsgFilter.Call(uintptr(unsafe.Pointer(m)), nCode)
|
||||
issue34474KeepAlive(m)
|
||||
return r != 0
|
||||
}
|
||||
|
||||
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) {
|
||||
wname := syscall.StringToUTF16Ptr(lpWindowName)
|
||||
hwnd, _, err := _CreateWindowEx.Call(
|
||||
uintptr(dwExStyle),
|
||||
uintptr(lpClassName),
|
||||
uintptr(unsafe.Pointer(wname)),
|
||||
uintptr(dwStyle),
|
||||
uintptr(x), uintptr(y),
|
||||
uintptr(w), uintptr(h),
|
||||
uintptr(hWndParent),
|
||||
uintptr(hMenu),
|
||||
uintptr(hInstance),
|
||||
uintptr(lpParam))
|
||||
issue34474KeepAlive(wname)
|
||||
if hwnd == 0 {
|
||||
return 0, fmt.Errorf("CreateWindowEx failed: %v", err)
|
||||
}
|
||||
return syscall.Handle(hwnd), nil
|
||||
}
|
||||
|
||||
func defWindowProc(hwnd syscall.Handle, msg uint32, wparam, lparam uintptr) uintptr {
|
||||
r, _, _ := _DefWindowProc.Call(uintptr(hwnd), uintptr(msg), wparam, lparam)
|
||||
return r
|
||||
}
|
||||
|
||||
func destroyWindow(hwnd syscall.Handle) {
|
||||
_DestroyWindow.Call(uintptr(hwnd))
|
||||
}
|
||||
|
||||
func dispatchMessage(m *msg) {
|
||||
_DispatchMessage.Call(uintptr(unsafe.Pointer(m)))
|
||||
issue34474KeepAlive(m)
|
||||
}
|
||||
|
||||
func getClientRect(hwnd syscall.Handle, r *rect) {
|
||||
_GetClientRect.Call(uintptr(hwnd), uintptr(unsafe.Pointer(r)))
|
||||
issue34474KeepAlive(r)
|
||||
}
|
||||
|
||||
func getDC(hwnd syscall.Handle) (syscall.Handle, error) {
|
||||
hdc, _, err := _GetDC.Call(uintptr(hwnd))
|
||||
if hdc == 0 {
|
||||
return 0, fmt.Errorf("GetDC failed: %v", err)
|
||||
}
|
||||
return syscall.Handle(hdc), nil
|
||||
}
|
||||
|
||||
func getDeviceCaps(hdc syscall.Handle, index int32) int {
|
||||
c, _, _ := _GetDeviceCaps.Call(uintptr(hdc), uintptr(index))
|
||||
return int(c)
|
||||
}
|
||||
|
||||
func getDpiForMonitor(hmonitor syscall.Handle, dpiType uint32) int {
|
||||
var dpiX, dpiY uintptr
|
||||
_GetDpiForMonitor.Call(uintptr(hmonitor), uintptr(dpiType), uintptr(unsafe.Pointer(&dpiX)), uintptr(unsafe.Pointer(&dpiY)))
|
||||
return int(dpiX)
|
||||
}
|
||||
|
||||
// getSystemDPI returns the effective DPI of the system.
|
||||
func getSystemDPI() int {
|
||||
// Check for GetDpiForMonitor, introduced in Windows 8.1.
|
||||
if _GetDpiForMonitor.Find() == nil {
|
||||
hmon := monitorFromPoint(point{}, _MONITOR_DEFAULTTOPRIMARY)
|
||||
return getDpiForMonitor(hmon, _MDT_EFFECTIVE_DPI)
|
||||
} else {
|
||||
// Fall back to the physical device DPI.
|
||||
screenDC, err := getDC(0)
|
||||
if err != nil {
|
||||
return 96
|
||||
}
|
||||
defer releaseDC(screenDC)
|
||||
return getDeviceCaps(screenDC, _LOGPIXELSX)
|
||||
}
|
||||
}
|
||||
|
||||
func getKeyState(nVirtKey int32) int16 {
|
||||
c, _, _ := _GetKeyState.Call(uintptr(nVirtKey))
|
||||
return int16(c)
|
||||
}
|
||||
|
||||
func getMessage(m *msg, hwnd syscall.Handle, wMsgFilterMin, wMsgFilterMax uint32) int32 {
|
||||
r, _, _ := _GetMessage.Call(uintptr(unsafe.Pointer(m)),
|
||||
uintptr(hwnd),
|
||||
uintptr(wMsgFilterMin),
|
||||
uintptr(wMsgFilterMax))
|
||||
issue34474KeepAlive(m)
|
||||
return int32(r)
|
||||
}
|
||||
|
||||
func getMessageTime() time.Duration {
|
||||
r, _, _ := _GetMessageTime.Call()
|
||||
return time.Duration(r) * time.Millisecond
|
||||
}
|
||||
|
||||
func killTimer(hwnd syscall.Handle, nIDEvent uintptr) error {
|
||||
r, _, err := _SetTimer.Call(uintptr(hwnd), uintptr(nIDEvent), 0, 0)
|
||||
if r == 0 {
|
||||
return fmt.Errorf("KillTimer failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadCursor(curID uint16) (syscall.Handle, error) {
|
||||
h, _, err := _LoadCursor.Call(0, uintptr(curID))
|
||||
if h == 0 {
|
||||
return 0, fmt.Errorf("LoadCursorW failed: %v", err)
|
||||
}
|
||||
return syscall.Handle(h), nil
|
||||
}
|
||||
|
||||
func monitorFromPoint(pt point, flags uint32) syscall.Handle {
|
||||
r, _, _ := _MonitorFromPoint.Call(uintptr(pt.x), uintptr(pt.y), uintptr(flags))
|
||||
return syscall.Handle(r)
|
||||
}
|
||||
|
||||
func msgWaitForMultipleObjectsEx(nCount uint32, pHandles uintptr, millis, mask, flags uint32) (uint32, error) {
|
||||
r, _, err := _MsgWaitForMultipleObjectsEx.Call(uintptr(nCount), pHandles, uintptr(millis), uintptr(mask), uintptr(flags))
|
||||
res := uint32(r)
|
||||
if res == 0xFFFFFFFF {
|
||||
return 0, fmt.Errorf("MsgWaitForMultipleObjectsEx failed: %v", err)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func peekMessage(m *msg, hwnd syscall.Handle, wMsgFilterMin, wMsgFilterMax, wRemoveMsg uint32) bool {
|
||||
r, _, _ := _PeekMessage.Call(uintptr(unsafe.Pointer(m)), uintptr(hwnd), uintptr(wMsgFilterMin), uintptr(wMsgFilterMax), uintptr(wRemoveMsg))
|
||||
issue34474KeepAlive(m)
|
||||
return r != 0
|
||||
}
|
||||
|
||||
func postQuitMessage(exitCode uintptr) {
|
||||
_PostQuitMessage.Call(exitCode)
|
||||
}
|
||||
|
||||
func postMessage(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) error {
|
||||
r, _, err := _PostMessage.Call(uintptr(hwnd), uintptr(msg), wParam, lParam)
|
||||
if r == 0 {
|
||||
return fmt.Errorf("PostMessage failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func releaseCapture() bool {
|
||||
r, _, _ := _ReleaseCapture.Call()
|
||||
return r != 0
|
||||
}
|
||||
|
||||
func registerClassEx(cls *wndClassEx) (uint16, error) {
|
||||
a, _, err := _RegisterClassExW.Call(uintptr(unsafe.Pointer(cls)))
|
||||
issue34474KeepAlive(cls)
|
||||
if a == 0 {
|
||||
return 0, fmt.Errorf("RegisterClassExW failed: %v", err)
|
||||
}
|
||||
return uint16(a), nil
|
||||
}
|
||||
|
||||
func releaseDC(hdc syscall.Handle) {
|
||||
_ReleaseDC.Call(uintptr(hdc))
|
||||
}
|
||||
|
||||
func setForegroundWindow(hwnd syscall.Handle) {
|
||||
_SetForegroundWindow.Call(uintptr(hwnd))
|
||||
}
|
||||
|
||||
func setFocus(hwnd syscall.Handle) {
|
||||
_SetFocus.Call(uintptr(hwnd))
|
||||
}
|
||||
|
||||
func setProcessDPIAware() {
|
||||
_SetProcessDPIAware.Call()
|
||||
}
|
||||
|
||||
func setCapture(hwnd syscall.Handle) syscall.Handle {
|
||||
r, _, _ := _SetCapture.Call(uintptr(hwnd))
|
||||
return syscall.Handle(r)
|
||||
}
|
||||
|
||||
func setTimer(hwnd syscall.Handle, nIDEvent uintptr, uElapse uint32, timerProc uintptr) error {
|
||||
r, _, err := _SetTimer.Call(uintptr(hwnd), uintptr(nIDEvent), uintptr(uElapse), timerProc)
|
||||
if r == 0 {
|
||||
return fmt.Errorf("SetTimer failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func screenToClient(hwnd syscall.Handle, p *point) {
|
||||
_ScreenToClient.Call(uintptr(hwnd), uintptr(unsafe.Pointer(p)))
|
||||
issue34474KeepAlive(p)
|
||||
}
|
||||
|
||||
func showWindow(hwnd syscall.Handle, nCmdShow int32) {
|
||||
_ShowWindow.Call(uintptr(hwnd), uintptr(nCmdShow))
|
||||
}
|
||||
|
||||
func translateMessage(m *msg) {
|
||||
_TranslateMessage.Call(uintptr(unsafe.Pointer(m)))
|
||||
issue34474KeepAlive(m)
|
||||
}
|
||||
|
||||
func unregisterClass(cls uint16, hInst syscall.Handle) {
|
||||
_UnregisterClass.Call(uintptr(cls), uintptr(hInst))
|
||||
}
|
||||
|
||||
func updateWindow(hwnd syscall.Handle) {
|
||||
_UpdateWindow.Call(uintptr(hwnd))
|
||||
}
|
||||
|
||||
// issue34474KeepAlive calls runtime.KeepAlive as a
|
||||
// workaround for golang.org/issue/34474.
|
||||
func issue34474KeepAlive(v interface{}) {
|
||||
runtime.KeepAlive(v)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,450 @@
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
// +build windows
|
||||
|
||||
package windows
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
syscall "golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
type Rect struct {
|
||||
Left, Top, Right, Bottom int32
|
||||
}
|
||||
|
||||
type WndClassEx struct {
|
||||
CbSize uint32
|
||||
Style uint32
|
||||
LpfnWndProc uintptr
|
||||
CnClsExtra int32
|
||||
CbWndExtra int32
|
||||
HInstance syscall.Handle
|
||||
HIcon syscall.Handle
|
||||
HCursor syscall.Handle
|
||||
HbrBackground syscall.Handle
|
||||
LpszMenuName *uint16
|
||||
LpszClassName *uint16
|
||||
HIconSm syscall.Handle
|
||||
}
|
||||
|
||||
type Msg struct {
|
||||
Hwnd syscall.Handle
|
||||
Message uint32
|
||||
WParam uintptr
|
||||
LParam uintptr
|
||||
Time uint32
|
||||
Pt Point
|
||||
LPrivate uint32
|
||||
}
|
||||
|
||||
type Point struct {
|
||||
X, Y int32
|
||||
}
|
||||
|
||||
const (
|
||||
CS_HREDRAW = 0x0002
|
||||
CS_VREDRAW = 0x0001
|
||||
CS_OWNDC = 0x0020
|
||||
|
||||
CW_USEDEFAULT = -2147483648
|
||||
|
||||
IDC_ARROW = 32512
|
||||
|
||||
INFINITE = 0xFFFFFFFF
|
||||
|
||||
LOGPIXELSX = 88
|
||||
|
||||
MDT_EFFECTIVE_DPI = 0
|
||||
|
||||
MONITOR_DEFAULTTOPRIMARY = 1
|
||||
|
||||
SIZE_MAXIMIZED = 2
|
||||
SIZE_MINIMIZED = 1
|
||||
SIZE_RESTORED = 0
|
||||
|
||||
SW_SHOWDEFAULT = 10
|
||||
|
||||
USER_TIMER_MINIMUM = 0x0000000A
|
||||
|
||||
VK_CONTROL = 0x11
|
||||
VK_LWIN = 0x5B
|
||||
VK_MENU = 0x12
|
||||
VK_RWIN = 0x5C
|
||||
VK_SHIFT = 0x10
|
||||
|
||||
VK_BACK = 0x08
|
||||
VK_DELETE = 0x2e
|
||||
VK_DOWN = 0x28
|
||||
VK_END = 0x23
|
||||
VK_ESCAPE = 0x1b
|
||||
VK_HOME = 0x24
|
||||
VK_LEFT = 0x25
|
||||
VK_NEXT = 0x22
|
||||
VK_PRIOR = 0x21
|
||||
VK_RIGHT = 0x27
|
||||
VK_RETURN = 0x0d
|
||||
VK_SPACE = 0x20
|
||||
VK_TAB = 0x09
|
||||
VK_UP = 0x26
|
||||
|
||||
VK_F1 = 0x70
|
||||
VK_F2 = 0x71
|
||||
VK_F3 = 0x72
|
||||
VK_F4 = 0x73
|
||||
VK_F5 = 0x74
|
||||
VK_F6 = 0x75
|
||||
VK_F7 = 0x76
|
||||
VK_F8 = 0x77
|
||||
VK_F9 = 0x78
|
||||
VK_F10 = 0x79
|
||||
VK_F11 = 0x7A
|
||||
VK_F12 = 0x7B
|
||||
|
||||
VK_OEM_1 = 0xba
|
||||
VK_OEM_PLUS = 0xbb
|
||||
VK_OEM_COMMA = 0xbc
|
||||
VK_OEM_MINUS = 0xbd
|
||||
VK_OEM_PERIOD = 0xbe
|
||||
VK_OEM_2 = 0xbf
|
||||
VK_OEM_3 = 0xc0
|
||||
VK_OEM_4 = 0xdb
|
||||
VK_OEM_5 = 0xdc
|
||||
VK_OEM_6 = 0xdd
|
||||
VK_OEM_7 = 0xde
|
||||
VK_OEM_102 = 0xe2
|
||||
|
||||
UNICODE_NOCHAR = 65535
|
||||
|
||||
WM_CANCELMODE = 0x001F
|
||||
WM_CHAR = 0x0102
|
||||
WM_CREATE = 0x0001
|
||||
WM_DPICHANGED = 0x02E0
|
||||
WM_DESTROY = 0x0002
|
||||
WM_ERASEBKGND = 0x0014
|
||||
WM_KEYDOWN = 0x0100
|
||||
WM_KEYUP = 0x0101
|
||||
WM_LBUTTONDOWN = 0x0201
|
||||
WM_LBUTTONUP = 0x0202
|
||||
WM_MBUTTONDOWN = 0x0207
|
||||
WM_MBUTTONUP = 0x0208
|
||||
WM_MOUSEMOVE = 0x0200
|
||||
WM_MOUSEWHEEL = 0x020A
|
||||
WM_PAINT = 0x000F
|
||||
WM_QUIT = 0x0012
|
||||
WM_SETFOCUS = 0x0007
|
||||
WM_KILLFOCUS = 0x0008
|
||||
WM_SHOWWINDOW = 0x0018
|
||||
WM_SIZE = 0x0005
|
||||
WM_SYSKEYDOWN = 0x0104
|
||||
WM_RBUTTONDOWN = 0x0204
|
||||
WM_RBUTTONUP = 0x0205
|
||||
WM_TIMER = 0x0113
|
||||
WM_UNICHAR = 0x0109
|
||||
WM_USER = 0x0400
|
||||
|
||||
WS_CLIPCHILDREN = 0x00010000
|
||||
WS_CLIPSIBLINGS = 0x04000000
|
||||
WS_VISIBLE = 0x10000000
|
||||
WS_OVERLAPPED = 0x00000000
|
||||
WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME |
|
||||
WS_MINIMIZEBOX | WS_MAXIMIZEBOX
|
||||
WS_CAPTION = 0x00C00000
|
||||
WS_SYSMENU = 0x00080000
|
||||
WS_THICKFRAME = 0x00040000
|
||||
WS_MINIMIZEBOX = 0x00020000
|
||||
WS_MAXIMIZEBOX = 0x00010000
|
||||
|
||||
WS_EX_APPWINDOW = 0x00040000
|
||||
WS_EX_WINDOWEDGE = 0x00000100
|
||||
|
||||
QS_ALLINPUT = 0x04FF
|
||||
|
||||
MWMO_WAITALL = 0x0001
|
||||
MWMO_INPUTAVAILABLE = 0x0004
|
||||
|
||||
WAIT_OBJECT_0 = 0
|
||||
|
||||
PM_REMOVE = 0x0001
|
||||
PM_NOREMOVE = 0x0000
|
||||
)
|
||||
|
||||
var (
|
||||
kernel32 = syscall.NewLazySystemDLL("kernel32.dll")
|
||||
_GetModuleHandleW = kernel32.NewProc("GetModuleHandleW")
|
||||
|
||||
user32 = syscall.NewLazySystemDLL("user32.dll")
|
||||
_AdjustWindowRectEx = user32.NewProc("AdjustWindowRectEx")
|
||||
_CallMsgFilter = user32.NewProc("CallMsgFilterW")
|
||||
_CreateWindowEx = user32.NewProc("CreateWindowExW")
|
||||
_DefWindowProc = user32.NewProc("DefWindowProcW")
|
||||
_DestroyWindow = user32.NewProc("DestroyWindow")
|
||||
_DispatchMessage = user32.NewProc("DispatchMessageW")
|
||||
_GetClientRect = user32.NewProc("GetClientRect")
|
||||
_GetDC = user32.NewProc("GetDC")
|
||||
_GetKeyState = user32.NewProc("GetKeyState")
|
||||
_GetMessage = user32.NewProc("GetMessageW")
|
||||
_GetMessageTime = user32.NewProc("GetMessageTime")
|
||||
_KillTimer = user32.NewProc("KillTimer")
|
||||
_LoadCursor = user32.NewProc("LoadCursorW")
|
||||
_MonitorFromPoint = user32.NewProc("MonitorFromPoint")
|
||||
_MsgWaitForMultipleObjectsEx = user32.NewProc("MsgWaitForMultipleObjectsEx")
|
||||
_PeekMessage = user32.NewProc("PeekMessageW")
|
||||
_PostMessage = user32.NewProc("PostMessageW")
|
||||
_PostQuitMessage = user32.NewProc("PostQuitMessage")
|
||||
_ReleaseCapture = user32.NewProc("ReleaseCapture")
|
||||
_RegisterClassExW = user32.NewProc("RegisterClassExW")
|
||||
_ReleaseDC = user32.NewProc("ReleaseDC")
|
||||
_ScreenToClient = user32.NewProc("ScreenToClient")
|
||||
_ShowWindow = user32.NewProc("ShowWindow")
|
||||
_SetCapture = user32.NewProc("SetCapture")
|
||||
_SetForegroundWindow = user32.NewProc("SetForegroundWindow")
|
||||
_SetFocus = user32.NewProc("SetFocus")
|
||||
_SetProcessDPIAware = user32.NewProc("SetProcessDPIAware")
|
||||
_SetTimer = user32.NewProc("SetTimer")
|
||||
_TranslateMessage = user32.NewProc("TranslateMessage")
|
||||
_UnregisterClass = user32.NewProc("UnregisterClassW")
|
||||
_UpdateWindow = user32.NewProc("UpdateWindow")
|
||||
|
||||
shcore = syscall.NewLazySystemDLL("shcore")
|
||||
_GetDpiForMonitor = shcore.NewProc("GetDpiForMonitor")
|
||||
|
||||
gdi32 = syscall.NewLazySystemDLL("gdi32")
|
||||
_GetDeviceCaps = gdi32.NewProc("GetDeviceCaps")
|
||||
)
|
||||
|
||||
func GetModuleHandle() (syscall.Handle, error) {
|
||||
h, _, err := _GetModuleHandleW.Call(uintptr(0))
|
||||
if h == 0 {
|
||||
return 0, fmt.Errorf("GetModuleHandleW failed: %v", err)
|
||||
}
|
||||
return syscall.Handle(h), nil
|
||||
}
|
||||
|
||||
func AdjustWindowRectEx(r *Rect, dwStyle uint32, bMenu int, dwExStyle uint32) {
|
||||
_AdjustWindowRectEx.Call(uintptr(unsafe.Pointer(r)), uintptr(dwStyle), uintptr(bMenu), uintptr(dwExStyle))
|
||||
issue34474KeepAlive(r)
|
||||
}
|
||||
|
||||
func CallMsgFilter(m *Msg, nCode uintptr) bool {
|
||||
r, _, _ := _CallMsgFilter.Call(uintptr(unsafe.Pointer(m)), nCode)
|
||||
issue34474KeepAlive(m)
|
||||
return r != 0
|
||||
}
|
||||
|
||||
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) {
|
||||
wname := syscall.StringToUTF16Ptr(lpWindowName)
|
||||
hwnd, _, err := _CreateWindowEx.Call(
|
||||
uintptr(dwExStyle),
|
||||
uintptr(lpClassName),
|
||||
uintptr(unsafe.Pointer(wname)),
|
||||
uintptr(dwStyle),
|
||||
uintptr(x), uintptr(y),
|
||||
uintptr(w), uintptr(h),
|
||||
uintptr(hWndParent),
|
||||
uintptr(hMenu),
|
||||
uintptr(hInstance),
|
||||
uintptr(lpParam))
|
||||
issue34474KeepAlive(wname)
|
||||
if hwnd == 0 {
|
||||
return 0, fmt.Errorf("CreateWindowEx failed: %v", err)
|
||||
}
|
||||
return syscall.Handle(hwnd), nil
|
||||
}
|
||||
|
||||
func DefWindowProc(hwnd syscall.Handle, msg uint32, wparam, lparam uintptr) uintptr {
|
||||
r, _, _ := _DefWindowProc.Call(uintptr(hwnd), uintptr(msg), wparam, lparam)
|
||||
return r
|
||||
}
|
||||
|
||||
func DestroyWindow(hwnd syscall.Handle) {
|
||||
_DestroyWindow.Call(uintptr(hwnd))
|
||||
}
|
||||
|
||||
func DispatchMessage(m *Msg) {
|
||||
_DispatchMessage.Call(uintptr(unsafe.Pointer(m)))
|
||||
issue34474KeepAlive(m)
|
||||
}
|
||||
|
||||
func GetClientRect(hwnd syscall.Handle, r *Rect) {
|
||||
_GetClientRect.Call(uintptr(hwnd), uintptr(unsafe.Pointer(r)))
|
||||
issue34474KeepAlive(r)
|
||||
}
|
||||
|
||||
func GetDC(hwnd syscall.Handle) (syscall.Handle, error) {
|
||||
hdc, _, err := _GetDC.Call(uintptr(hwnd))
|
||||
if hdc == 0 {
|
||||
return 0, fmt.Errorf("GetDC failed: %v", err)
|
||||
}
|
||||
return syscall.Handle(hdc), nil
|
||||
}
|
||||
|
||||
func getDeviceCaps(hdc syscall.Handle, index int32) int {
|
||||
c, _, _ := _GetDeviceCaps.Call(uintptr(hdc), uintptr(index))
|
||||
return int(c)
|
||||
}
|
||||
|
||||
func getDpiForMonitor(hmonitor syscall.Handle, dpiType uint32) int {
|
||||
var dpiX, dpiY uintptr
|
||||
_GetDpiForMonitor.Call(uintptr(hmonitor), uintptr(dpiType), uintptr(unsafe.Pointer(&dpiX)), uintptr(unsafe.Pointer(&dpiY)))
|
||||
return int(dpiX)
|
||||
}
|
||||
|
||||
// GetSystemDPI returns the effective DPI of the system.
|
||||
func GetSystemDPI() int {
|
||||
// Check for getDpiForMonitor, introduced in Windows 8.1.
|
||||
if _GetDpiForMonitor.Find() == nil {
|
||||
hmon := monitorFromPoint(Point{}, MONITOR_DEFAULTTOPRIMARY)
|
||||
return getDpiForMonitor(hmon, MDT_EFFECTIVE_DPI)
|
||||
} else {
|
||||
// Fall back to the physical device DPI.
|
||||
screenDC, err := GetDC(0)
|
||||
if err != nil {
|
||||
return 96
|
||||
}
|
||||
defer ReleaseDC(screenDC)
|
||||
return getDeviceCaps(screenDC, LOGPIXELSX)
|
||||
}
|
||||
}
|
||||
|
||||
func GetKeyState(nVirtKey int32) int16 {
|
||||
c, _, _ := _GetKeyState.Call(uintptr(nVirtKey))
|
||||
return int16(c)
|
||||
}
|
||||
|
||||
func GetMessage(m *Msg, hwnd syscall.Handle, wMsgFilterMin, wMsgFilterMax uint32) int32 {
|
||||
r, _, _ := _GetMessage.Call(uintptr(unsafe.Pointer(m)),
|
||||
uintptr(hwnd),
|
||||
uintptr(wMsgFilterMin),
|
||||
uintptr(wMsgFilterMax))
|
||||
issue34474KeepAlive(m)
|
||||
return int32(r)
|
||||
}
|
||||
|
||||
func GetMessageTime() time.Duration {
|
||||
r, _, _ := _GetMessageTime.Call()
|
||||
return time.Duration(r) * time.Millisecond
|
||||
}
|
||||
|
||||
func KillTimer(hwnd syscall.Handle, nIDEvent uintptr) error {
|
||||
r, _, err := _SetTimer.Call(uintptr(hwnd), uintptr(nIDEvent), 0, 0)
|
||||
if r == 0 {
|
||||
return fmt.Errorf("KillTimer failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func LoadCursor(curID uint16) (syscall.Handle, error) {
|
||||
h, _, err := _LoadCursor.Call(0, uintptr(curID))
|
||||
if h == 0 {
|
||||
return 0, fmt.Errorf("LoadCursorW failed: %v", err)
|
||||
}
|
||||
return syscall.Handle(h), nil
|
||||
}
|
||||
|
||||
func monitorFromPoint(pt Point, flags uint32) syscall.Handle {
|
||||
r, _, _ := _MonitorFromPoint.Call(uintptr(pt.X), uintptr(pt.Y), uintptr(flags))
|
||||
return syscall.Handle(r)
|
||||
}
|
||||
|
||||
func MsgWaitForMultipleObjectsEx(nCount uint32, pHandles uintptr, millis, mask, flags uint32) (uint32, error) {
|
||||
r, _, err := _MsgWaitForMultipleObjectsEx.Call(uintptr(nCount), pHandles, uintptr(millis), uintptr(mask), uintptr(flags))
|
||||
res := uint32(r)
|
||||
if res == 0xFFFFFFFF {
|
||||
return 0, fmt.Errorf("MsgWaitForMultipleObjectsEx failed: %v", err)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func PeekMessage(m *Msg, hwnd syscall.Handle, wMsgFilterMin, wMsgFilterMax, wRemoveMsg uint32) bool {
|
||||
r, _, _ := _PeekMessage.Call(uintptr(unsafe.Pointer(m)), uintptr(hwnd), uintptr(wMsgFilterMin), uintptr(wMsgFilterMax), uintptr(wRemoveMsg))
|
||||
issue34474KeepAlive(m)
|
||||
return r != 0
|
||||
}
|
||||
|
||||
func PostQuitMessage(exitCode uintptr) {
|
||||
_PostQuitMessage.Call(exitCode)
|
||||
}
|
||||
|
||||
func PostMessage(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) error {
|
||||
r, _, err := _PostMessage.Call(uintptr(hwnd), uintptr(msg), wParam, lParam)
|
||||
if r == 0 {
|
||||
return fmt.Errorf("PostMessage failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ReleaseCapture() bool {
|
||||
r, _, _ := _ReleaseCapture.Call()
|
||||
return r != 0
|
||||
}
|
||||
|
||||
func RegisterClassEx(cls *WndClassEx) (uint16, error) {
|
||||
a, _, err := _RegisterClassExW.Call(uintptr(unsafe.Pointer(cls)))
|
||||
issue34474KeepAlive(cls)
|
||||
if a == 0 {
|
||||
return 0, fmt.Errorf("RegisterClassExW failed: %v", err)
|
||||
}
|
||||
return uint16(a), nil
|
||||
}
|
||||
|
||||
func ReleaseDC(hdc syscall.Handle) {
|
||||
_ReleaseDC.Call(uintptr(hdc))
|
||||
}
|
||||
|
||||
func SetForegroundWindow(hwnd syscall.Handle) {
|
||||
_SetForegroundWindow.Call(uintptr(hwnd))
|
||||
}
|
||||
|
||||
func SetFocus(hwnd syscall.Handle) {
|
||||
_SetFocus.Call(uintptr(hwnd))
|
||||
}
|
||||
|
||||
func SetProcessDPIAware() {
|
||||
_SetProcessDPIAware.Call()
|
||||
}
|
||||
|
||||
func SetCapture(hwnd syscall.Handle) syscall.Handle {
|
||||
r, _, _ := _SetCapture.Call(uintptr(hwnd))
|
||||
return syscall.Handle(r)
|
||||
}
|
||||
|
||||
func SetTimer(hwnd syscall.Handle, nIDEvent uintptr, uElapse uint32, timerProc uintptr) error {
|
||||
r, _, err := _SetTimer.Call(uintptr(hwnd), uintptr(nIDEvent), uintptr(uElapse), timerProc)
|
||||
if r == 0 {
|
||||
return fmt.Errorf("SetTimer failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ScreenToClient(hwnd syscall.Handle, p *Point) {
|
||||
_ScreenToClient.Call(uintptr(hwnd), uintptr(unsafe.Pointer(p)))
|
||||
issue34474KeepAlive(p)
|
||||
}
|
||||
|
||||
func ShowWindow(hwnd syscall.Handle, nCmdShow int32) {
|
||||
_ShowWindow.Call(uintptr(hwnd), uintptr(nCmdShow))
|
||||
}
|
||||
|
||||
func TranslateMessage(m *Msg) {
|
||||
_TranslateMessage.Call(uintptr(unsafe.Pointer(m)))
|
||||
issue34474KeepAlive(m)
|
||||
}
|
||||
|
||||
func UnregisterClass(cls uint16, hInst syscall.Handle) {
|
||||
_UnregisterClass.Call(uintptr(cls), uintptr(hInst))
|
||||
}
|
||||
|
||||
func UpdateWindow(hwnd syscall.Handle) {
|
||||
_UpdateWindow.Call(uintptr(hwnd))
|
||||
}
|
||||
|
||||
// issue34474KeepAlive calls runtime.KeepAlive as a
|
||||
// workaround for golang.org/issue/34474.
|
||||
func issue34474KeepAlive(v interface{}) {
|
||||
runtime.KeepAlive(v)
|
||||
}
|
||||
Reference in New Issue
Block a user