github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/exp/shiny/driver/internal/win32/win32.go (about)

     1  // Copyright 2015 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // +build windows
     6  
     7  // Package win32 implements a partial shiny screen driver using the Win32 API.
     8  // It provides window, lifecycle, key, and mouse management, but no drawing.
     9  // That is left to windriver (using GDI) or gldriver (using DirectX via ANGLE).
    10  package win32
    11  
    12  import (
    13  	"fmt"
    14  	"runtime"
    15  	"syscall"
    16  	"unsafe"
    17  
    18  	"golang.org/x/exp/shiny/screen"
    19  	"golang.org/x/mobile/event/key"
    20  	"golang.org/x/mobile/event/lifecycle"
    21  	"golang.org/x/mobile/event/mouse"
    22  	"golang.org/x/mobile/event/paint"
    23  	"golang.org/x/mobile/event/size"
    24  	"golang.org/x/mobile/geom"
    25  )
    26  
    27  // screenHWND is the handle to the "Screen window".
    28  // The Screen window encapsulates all screen.Screen operations
    29  // in an actual Windows window so they all run on the main thread.
    30  // Since any messages sent to a window will be executed on the
    31  // main thread, we can safely use the messages below.
    32  var screenHWND HWND
    33  
    34  const (
    35  	msgCreateWindow = _WM_USER + iota
    36  	msgMainCallback
    37  	msgShow
    38  	msgQuit
    39  	msgLast
    40  )
    41  
    42  var nextWM uint32 = msgLast
    43  
    44  func newWindow(opts *screen.NewWindowOptions) (HWND, error) {
    45  	// TODO(brainman): convert windowClass to *uint16 once (in initWindowClass)
    46  	wcname, err := syscall.UTF16PtrFromString(windowClass)
    47  	if err != nil {
    48  		return 0, err
    49  	}
    50  	title, err := syscall.UTF16PtrFromString("Shiny Window")
    51  	if err != nil {
    52  		return 0, err
    53  	}
    54  	hwnd, err := _CreateWindowEx(0,
    55  		wcname, title,
    56  		_WS_OVERLAPPEDWINDOW,
    57  		_CW_USEDEFAULT, _CW_USEDEFAULT,
    58  		_CW_USEDEFAULT, _CW_USEDEFAULT,
    59  		0, 0, hThisInstance, 0)
    60  	if err != nil {
    61  		return 0, err
    62  	}
    63  	// TODO(andlabs): use proper nCmdShow
    64  	// TODO(andlabs): call UpdateWindow()
    65  
    66  	return hwnd, nil
    67  }
    68  
    69  // Show shows a newly created window.
    70  // It sends the appropriate lifecycle events, makes the window appear
    71  // on the screen, and sends an initial size event.
    72  //
    73  // This is a separate step from NewWindow to give the driver a chance
    74  // to setup its internal state for a window before events start being
    75  // delivered.
    76  func Show(hwnd HWND) {
    77  	SendMessage(hwnd, msgShow, 0, 0)
    78  }
    79  
    80  func Release(hwnd HWND) {
    81  	// TODO(andlabs): check for errors from this?
    82  	// TODO(andlabs): remove unsafe
    83  	_DestroyWindow(hwnd)
    84  	// TODO(andlabs): what happens if we're still painting?
    85  }
    86  
    87  func sendFocus(hwnd HWND, uMsg uint32, wParam, lParam uintptr) (lResult uintptr) {
    88  	switch uMsg {
    89  	case _WM_SETFOCUS:
    90  		LifecycleEvent(hwnd, lifecycle.StageFocused)
    91  	case _WM_KILLFOCUS:
    92  		LifecycleEvent(hwnd, lifecycle.StageVisible)
    93  	default:
    94  		panic(fmt.Sprintf("unexpected focus message: %d", uMsg))
    95  	}
    96  	return _DefWindowProc(hwnd, uMsg, wParam, lParam)
    97  }
    98  
    99  func sendShow(hwnd HWND, uMsg uint32, wParam, lParam uintptr) (lResult uintptr) {
   100  	LifecycleEvent(hwnd, lifecycle.StageVisible)
   101  	_ShowWindow(hwnd, _SW_SHOWDEFAULT)
   102  	sendSize(hwnd)
   103  	return 0
   104  }
   105  
   106  func sendSizeEvent(hwnd HWND, uMsg uint32, wParam, lParam uintptr) (lResult uintptr) {
   107  	wp := (*_WINDOWPOS)(unsafe.Pointer(lParam))
   108  	if wp.Flags&_SWP_NOSIZE != 0 {
   109  		return 0
   110  	}
   111  	sendSize(hwnd)
   112  	return 0
   113  }
   114  
   115  func sendSize(hwnd HWND) {
   116  	var r _RECT
   117  	if err := _GetClientRect(hwnd, &r); err != nil {
   118  		panic(err) // TODO(andlabs)
   119  	}
   120  
   121  	width := int(r.Right - r.Left)
   122  	height := int(r.Bottom - r.Top)
   123  
   124  	// TODO(andlabs): don't assume that PixelsPerPt == 1
   125  	SizeEvent(hwnd, size.Event{
   126  		WidthPx:     width,
   127  		HeightPx:    height,
   128  		WidthPt:     geom.Pt(width),
   129  		HeightPt:    geom.Pt(height),
   130  		PixelsPerPt: 1,
   131  	})
   132  }
   133  
   134  func sendMouseEvent(hwnd HWND, uMsg uint32, wParam, lParam uintptr) (lResult uintptr) {
   135  	e := mouse.Event{
   136  		X:         float32(_GET_X_LPARAM(lParam)),
   137  		Y:         float32(_GET_Y_LPARAM(lParam)),
   138  		Modifiers: keyModifiers(),
   139  	}
   140  
   141  	switch uMsg {
   142  	case _WM_MOUSEMOVE, _WM_MOUSEWHEEL:
   143  		e.Direction = mouse.DirNone
   144  	case _WM_LBUTTONDOWN, _WM_MBUTTONDOWN, _WM_RBUTTONDOWN:
   145  		e.Direction = mouse.DirPress
   146  	case _WM_LBUTTONUP, _WM_MBUTTONUP, _WM_RBUTTONUP:
   147  		e.Direction = mouse.DirRelease
   148  	default:
   149  		panic("sendMouseEvent() called on non-mouse message")
   150  	}
   151  
   152  	switch uMsg {
   153  	case _WM_MOUSEMOVE:
   154  		switch {
   155  		case wParam&_MK_LBUTTON == _MK_LBUTTON:
   156  			e.Button = mouse.ButtonLeft
   157  		case wParam&_MK_MBUTTON == _MK_MBUTTON:
   158  			e.Button = mouse.ButtonMiddle
   159  		case wParam&_MK_RBUTTON == _MK_RBUTTON:
   160  			e.Button = mouse.ButtonRight
   161  		default:
   162  			// TODO: send move events when no buttons are held down?
   163  			return 0
   164  		}
   165  	case _WM_LBUTTONDOWN, _WM_LBUTTONUP:
   166  		e.Button = mouse.ButtonLeft
   167  	case _WM_MBUTTONDOWN, _WM_MBUTTONUP:
   168  		e.Button = mouse.ButtonMiddle
   169  	case _WM_RBUTTONDOWN, _WM_RBUTTONUP:
   170  		e.Button = mouse.ButtonRight
   171  	case _WM_MOUSEWHEEL:
   172  		delta := _GET_WHEEL_DELTA_WPARAM(wParam) / _WHEEL_DELTA
   173  		switch {
   174  		case delta > 0:
   175  			e.Button = mouse.ButtonWheelUp
   176  		case delta < 0:
   177  			e.Button = mouse.ButtonWheelDown
   178  			delta = -delta
   179  		default:
   180  			return
   181  		}
   182  		for delta > 0 {
   183  			MouseEvent(hwnd, e)
   184  			delta--
   185  		}
   186  		return
   187  	}
   188  
   189  	MouseEvent(hwnd, e)
   190  
   191  	return 0
   192  }
   193  
   194  // Precondition: this is called in immediate response to the message that triggered the event (so not after w.Send).
   195  func keyModifiers() (m key.Modifiers) {
   196  	down := func(x int32) bool {
   197  		// GetKeyState gets the key state at the time of the message, so this is what we want.
   198  		return _GetKeyState(x)&0x80 != 0
   199  	}
   200  
   201  	if down(_VK_CONTROL) {
   202  		m |= key.ModControl
   203  	}
   204  	if down(_VK_MENU) {
   205  		m |= key.ModAlt
   206  	}
   207  	if down(_VK_SHIFT) {
   208  		m |= key.ModShift
   209  	}
   210  	if down(_VK_LWIN) || down(_VK_RWIN) {
   211  		m |= key.ModMeta
   212  	}
   213  	return m
   214  }
   215  
   216  var (
   217  	MouseEvent     func(hwnd HWND, e mouse.Event)
   218  	PaintEvent     func(hwnd HWND, e paint.Event)
   219  	SizeEvent      func(hwnd HWND, e size.Event)
   220  	KeyEvent       func(hwnd HWND, e key.Event)
   221  	LifecycleEvent func(hwnd HWND, e lifecycle.Stage)
   222  )
   223  
   224  func sendPaint(hwnd HWND, uMsg uint32, wParam, lParam uintptr) (lResult uintptr) {
   225  	PaintEvent(hwnd, paint.Event{})
   226  	return _DefWindowProc(hwnd, uMsg, wParam, lParam)
   227  }
   228  
   229  func screenWindowWndProc(hwnd HWND, uMsg uint32, wParam uintptr, lParam uintptr) (lResult uintptr) {
   230  	switch uMsg {
   231  	case msgCreateWindow:
   232  		p := (*newWindowParams)(unsafe.Pointer(lParam))
   233  		p.w, p.err = newWindow(p.opts)
   234  	case msgMainCallback:
   235  		go func() {
   236  			mainCallback()
   237  			SendMessage(screenHWND, msgQuit, 0, 0)
   238  		}()
   239  	case msgQuit:
   240  		_PostQuitMessage(0)
   241  	default:
   242  		return _DefWindowProc(hwnd, uMsg, wParam, lParam)
   243  	}
   244  	return 0
   245  }
   246  
   247  var windowMsgs = map[uint32]func(hwnd HWND, uMsg uint32, wParam, lParam uintptr) (lResult uintptr){
   248  	_WM_SETFOCUS:         sendFocus,
   249  	_WM_KILLFOCUS:        sendFocus,
   250  	_WM_PAINT:            sendPaint,
   251  	msgShow:              sendShow,
   252  	_WM_WINDOWPOSCHANGED: sendSizeEvent,
   253  
   254  	_WM_LBUTTONDOWN: sendMouseEvent,
   255  	_WM_LBUTTONUP:   sendMouseEvent,
   256  	_WM_MBUTTONDOWN: sendMouseEvent,
   257  	_WM_MBUTTONUP:   sendMouseEvent,
   258  	_WM_RBUTTONDOWN: sendMouseEvent,
   259  	_WM_RBUTTONUP:   sendMouseEvent,
   260  	_WM_MOUSEMOVE:   sendMouseEvent,
   261  	_WM_MOUSEWHEEL:  sendMouseEvent,
   262  
   263  	_WM_KEYDOWN: sendKeyEvent,
   264  	_WM_KEYUP:   sendKeyEvent,
   265  	// TODO case _WM_SYSKEYDOWN, _WM_SYSKEYUP:
   266  }
   267  
   268  func AddWindowMsg(fn func(hwnd HWND, uMsg uint32, wParam, lParam uintptr)) uint32 {
   269  	uMsg := nextWM
   270  	nextWM++
   271  	windowMsgs[uMsg] = func(hwnd HWND, uMsg uint32, wParam, lParam uintptr) uintptr {
   272  		fn(hwnd, uMsg, wParam, lParam)
   273  		return 0
   274  	}
   275  	return uMsg
   276  }
   277  
   278  func windowWndProc(hwnd HWND, uMsg uint32, wParam uintptr, lParam uintptr) (lResult uintptr) {
   279  	fn := windowMsgs[uMsg]
   280  	if fn != nil {
   281  		return fn(hwnd, uMsg, wParam, lParam)
   282  	}
   283  	return _DefWindowProc(hwnd, uMsg, wParam, lParam)
   284  }
   285  
   286  type newWindowParams struct {
   287  	opts *screen.NewWindowOptions
   288  	w    HWND
   289  	err  error
   290  }
   291  
   292  func NewWindow(opts *screen.NewWindowOptions) (HWND, error) {
   293  	var p newWindowParams
   294  	p.opts = opts
   295  	SendMessage(screenHWND, msgCreateWindow, 0, uintptr(unsafe.Pointer(&p)))
   296  	return p.w, p.err
   297  }
   298  
   299  const windowClass = "shiny_Window"
   300  
   301  func initWindowClass() (err error) {
   302  	wcname, err := syscall.UTF16PtrFromString(windowClass)
   303  	if err != nil {
   304  		return err
   305  	}
   306  	_, err = _RegisterClass(&_WNDCLASS{
   307  		LpszClassName: wcname,
   308  		LpfnWndProc:   syscall.NewCallback(windowWndProc),
   309  		HIcon:         hDefaultIcon,
   310  		HCursor:       hDefaultCursor,
   311  		HInstance:     hThisInstance,
   312  		// TODO(andlabs): change this to something else? NULL? the hollow brush?
   313  		HbrBackground: syscall.Handle(_COLOR_BTNFACE + 1),
   314  	})
   315  	return err
   316  }
   317  
   318  func initScreenWindow() (err error) {
   319  	const screenWindowClass = "shiny_ScreenWindow"
   320  	swc, err := syscall.UTF16PtrFromString(screenWindowClass)
   321  	if err != nil {
   322  		return err
   323  	}
   324  	emptyString, err := syscall.UTF16PtrFromString("")
   325  	if err != nil {
   326  		return err
   327  	}
   328  	wc := _WNDCLASS{
   329  		LpszClassName: swc,
   330  		LpfnWndProc:   syscall.NewCallback(screenWindowWndProc),
   331  		HIcon:         hDefaultIcon,
   332  		HCursor:       hDefaultCursor,
   333  		HInstance:     hThisInstance,
   334  		HbrBackground: syscall.Handle(_COLOR_BTNFACE + 1),
   335  	}
   336  	_, err = _RegisterClass(&wc)
   337  	if err != nil {
   338  		return err
   339  	}
   340  	screenHWND, err = _CreateWindowEx(0,
   341  		swc, emptyString,
   342  		_WS_OVERLAPPEDWINDOW,
   343  		_CW_USEDEFAULT, _CW_USEDEFAULT,
   344  		_CW_USEDEFAULT, _CW_USEDEFAULT,
   345  		_HWND_MESSAGE, 0, hThisInstance, 0)
   346  	if err != nil {
   347  		return err
   348  	}
   349  	return nil
   350  }
   351  
   352  var (
   353  	hDefaultIcon   syscall.Handle
   354  	hDefaultCursor syscall.Handle
   355  	hThisInstance  syscall.Handle
   356  )
   357  
   358  func initCommon() (err error) {
   359  	hDefaultIcon, err = _LoadIcon(0, _IDI_APPLICATION)
   360  	if err != nil {
   361  		return err
   362  	}
   363  	hDefaultCursor, err = _LoadCursor(0, _IDC_ARROW)
   364  	if err != nil {
   365  		return err
   366  	}
   367  	// TODO(andlabs) hThisInstance
   368  	return nil
   369  }
   370  
   371  var mainCallback func()
   372  
   373  func Main(f func()) (retErr error) {
   374  	// It does not matter which OS thread we are on.
   375  	// All that matters is that we confine all UI operations
   376  	// to the thread that created the respective window.
   377  	runtime.LockOSThread()
   378  
   379  	if err := initCommon(); err != nil {
   380  		return err
   381  	}
   382  
   383  	if err := initScreenWindow(); err != nil {
   384  		return err
   385  	}
   386  	defer func() {
   387  		// TODO(andlabs): log an error if this fails?
   388  		_DestroyWindow(screenHWND)
   389  		// TODO(andlabs): unregister window class
   390  	}()
   391  
   392  	if err := initWindowClass(); err != nil {
   393  		return err
   394  	}
   395  
   396  	// Prime the pump.
   397  	mainCallback = f
   398  	_PostMessage(screenHWND, msgMainCallback, 0, 0)
   399  
   400  	// Main message pump.
   401  	var m _MSG
   402  	for {
   403  		done, err := _GetMessage(&m, 0, 0, 0)
   404  		if err != nil {
   405  			return fmt.Errorf("win32 GetMessage failed: %v", err)
   406  		}
   407  		if done == 0 { // WM_QUIT
   408  			break
   409  		}
   410  		_TranslateMessage(&m)
   411  		_DispatchMessage(&m)
   412  	}
   413  
   414  	return nil
   415  }