Exemple #1
0
func (app *DemoApp) WndProc(hwnd w32.HWND, msg uint, wParam, lParam uintptr) uintptr {
	if hwnd != app.hwnd {
		return w32.DefWindowProc(hwnd, msg, wParam, lParam)
	}
	switch msg {
	case w32.WM_SIZE:
		width := w32.LOWORD(uint(lParam))
		height := w32.HIWORD(uint(lParam))
		app.OnResize(width, height)
		return 0
	case w32.WM_DISPLAYCHANGE:
		w32.InvalidateRect(app.hwnd, nil, false)
		return 0
	case w32.WM_PAINT:
		app.OnRender()
		w32.ValidateRect(app.hwnd, nil)
		return 0
	case w32.WM_DESTROY:
		w32.PostQuitMessage(0)
		return 1
	}

	return w32.DefWindowProc(hwnd, msg, wParam, lParam)
}
Exemple #2
0
func (this *Form) WndProc(msg uint, wparam, lparam uintptr) uintptr {
	switch msg {
	case w32.WM_LBUTTONDOWN:
		if this.isDragMove {
			w32.ReleaseCapture()
			w32.SendMessage(this.hwnd, w32.WM_NCLBUTTONDOWN, w32.HTCAPTION, 0)
		}
	case w32.WM_CLOSE:
		w32.DestroyWindow(this.hwnd)
	case w32.WM_DESTROY:
		w32.PostQuitMessage(0)
	}

	return w32.DefWindowProc(this.hwnd, msg, wparam, lparam)
}
Exemple #3
0
func (this *Form) WndProc(msg uint, wparam, lparam uintptr) uintptr {
	switch msg {
	case w32.WM_LBUTTONDOWN:
		if this.isDragMove {
			w32.ReleaseCapture()
			w32.SendMessage(this.hwnd, w32.WM_NCLBUTTONDOWN, w32.HTCAPTION, 0)
		}
	case w32.WM_CLOSE:
		this.onClose.Fire(NewEventArg(this, nil))
		return 0
	case w32.WM_DESTROY:
		w32.PostQuitMessage(0)
		return 0
	}
	return w32.DefWindowProc(this.hwnd, uint32(msg), wparam, lparam)
}
Exemple #4
0
// WndProc of the notify icon
func (t *_NotifyIcon) iconCallback(hwnd w32.HWND, msg uint32, wparam w32.WPARAM, lparam w32.LPARAM) w32.LRESULT {
	if msg == niCallbackMessage {
		switch lparam {
		case w32.WM_LBUTTONUP:
			select {
			case t.onClick <- LeftMouseButton:
			default:
			}
		case w32.WM_RBUTTONUP:
			select {
			case t.onClick <- RightMouseButton:
			default:
			}
		}
	}
	return w32.LRESULT(w32.DefWindowProc(hwnd, msg, uintptr(wparam), uintptr(lparam)))
}
Exemple #5
0
func (this *CustomControl) WndProc(msg uint, wparam, lparam uintptr) uintptr {
	sender := GetMsgHandler(this.hwnd)
	switch msg {
	case w32.WM_CREATE:
		internalTrackMouseEvent(this.hwnd)
		this.onCreate.Fire(NewEventArg(sender, nil))
	case w32.WM_CLOSE:
		this.onClose.Fire(NewEventArg(sender, nil))
	case w32.WM_MOUSEMOVE:
		if this.isMouseLeft {
			this.onMouseHover.Fire(NewEventArg(sender, nil))
			internalTrackMouseEvent(this.hwnd)
			this.isMouseLeft = false
		}
	case w32.WM_MOUSELEAVE:
		this.onMouseLeave.Fire(NewEventArg(sender, nil))
		this.isMouseLeft = true
	}
	return w32.DefWindowProc(this.hwnd, uint32(msg), wparam, lparam)
}
Exemple #6
0
func generalWndProc(hwnd w32.HWND, msg uint, wparam, lparam uintptr) uintptr {
	if msg == w32.WM_INITDIALOG && gDialogWaiting != nil {
		gDialogWaiting.hwnd = hwnd
		RegMsgHandler(gDialogWaiting)
	}

	if controller := GetMsgHandler(hwnd); controller != nil {
		ret := controller.WndProc(msg, wparam, lparam)
		switch msg {
		case w32.WM_NOTIFY: //Reflect notification to control
			nm := (*w32.NMHDR)(unsafe.Pointer(lparam))
			if controller := GetMsgHandler(nm.HwndFrom); controller != nil {
				ret := controller.WndProc(msg, wparam, lparam)
				if ret != 0 {
					w32.SetWindowLong(hwnd, w32.DWL_MSGRESULT, uint32(ret))
					return w32.TRUE
				}
			}
		case w32.WM_COMMAND:
			if lparam != 0 { //Reflect message to control
				h := w32.HWND(lparam)
				if controller := GetMsgHandler(h); controller != nil {
					ret := controller.WndProc(msg, wparam, lparam)
					if ret != 0 {
						w32.SetWindowLong(hwnd, w32.DWL_MSGRESULT, uint32(ret))
						return w32.TRUE
					}
				}
			}
		case w32.WM_CLOSE:
			controller.OnClose().Fire(NewEventArg(controller, nil))
		case w32.WM_KILLFOCUS:
			controller.OnKillFocus().Fire(NewEventArg(controller, nil))
		case w32.WM_SETFOCUS:
			controller.OnSetFocus().Fire(NewEventArg(controller, nil))
		case w32.WM_DROPFILES:
			controller.OnDropFiles().Fire(NewEventArg(controller, genDropFilesEventArg(wparam)))
		case w32.WM_LBUTTONDOWN:
			controller.OnLBDown().Fire(NewEventArg(controller, genMouseEventArg(wparam, lparam)))
		case w32.WM_LBUTTONUP:
			controller.OnLBUp().Fire(NewEventArg(controller, genMouseEventArg(wparam, lparam)))
		case w32.WM_MBUTTONDOWN:
			controller.OnMBDown().Fire(NewEventArg(controller, genMouseEventArg(wparam, lparam)))
		case w32.WM_MBUTTONUP:
			controller.OnMBUp().Fire(NewEventArg(controller, genMouseEventArg(wparam, lparam)))
		case w32.WM_RBUTTONDOWN:
			controller.OnRBDown().Fire(NewEventArg(controller, genMouseEventArg(wparam, lparam)))
		case w32.WM_RBUTTONUP:
			controller.OnRBUp().Fire(NewEventArg(controller, genMouseEventArg(wparam, lparam)))
		case w32.WM_PAINT:
			canvas := NewCanvasFromHwnd(hwnd)
			defer canvas.Dispose()
			controller.OnPaint().Fire(NewEventArg(controller, &PaintEventData{Canvas: canvas}))
		case w32.WM_KEYUP:
			controller.OnKeyUp().Fire(NewEventArg(controller, &KeyUpEventData{int(wparam), int(lparam)}))
		case w32.WM_SIZE:
			x, y := genPoint(lparam)
			controller.OnSize().Fire(NewEventArg(controller, &SizeEventData{uint(wparam), x, y}))
		}

		//Trigger msg handler registered via "Bind".
		if handler, ok := controller.BindedHandler(msg); ok {
			handler(NewEventArg(controller, &RawMsg{hwnd, msg, wparam, lparam}))
		}

		return ret
	}

	return w32.DefWindowProc(hwnd, uint32(msg), wparam, lparam)
}
Exemple #7
0
func WndProc(hwnd w32.HWND, msg uint, wparam, lparam uintptr) uintptr {
	wnd := GetMsgHandler(hwnd)
	if wnd == nil {
		return uintptr(w32.DefWindowProc(hwnd, msg, wparam, lparam))
	}

	var rc uintptr
	switch msg {
	case w32.WM_LBUTTONDOWN, w32.WM_RBUTTONDOWN, w32.WM_MBUTTONDOWN:
		wnd.button = wnd.button | buttonForDetail(msg)
		var bpe wde.MouseDownEvent
		bpe.Which = buttonForDetail(msg)
		bpe.Where.X = int(lparam) & 0xFFFF
		bpe.Where.Y = int(lparam>>16) & 0xFFFF
		wnd.lastX = bpe.Where.X
		wnd.lastY = bpe.Where.Y
		wnd.events <- bpe

	case w32.WM_LBUTTONUP, w32.WM_RBUTTONUP, w32.WM_MBUTTONUP:
		wnd.button = wnd.button & ^buttonForDetail(msg)
		var bpe wde.MouseUpEvent
		bpe.Which = buttonForDetail(msg)
		bpe.Where.X = int(lparam) & 0xFFFF
		bpe.Where.Y = int(lparam>>16) & 0xFFFF
		wnd.lastX = bpe.Where.X
		wnd.lastY = bpe.Where.Y
		wnd.events <- bpe

	case w32.WM_MOUSEMOVE:
		var mme wde.MouseMovedEvent
		mme.Where.X = int(lparam) & 0xFFFF
		mme.Where.Y = int(lparam>>16) & 0xFFFF
		if wnd.lastX != wnd.noX {
			mme.From.X = int(wnd.lastX)
			mme.From.Y = int(wnd.lastY)
		} else {
			mme.From.X = mme.Where.X
			mme.From.Y = mme.Where.Y
		}
		wnd.lastX = mme.Where.X
		wnd.lastY = mme.Where.Y

		if !wnd.trackMouse {
			var tme w32.TRACKMOUSEEVENT
			tme.CbSize = uint(unsafe.Sizeof(tme))
			tme.DwFlags = w32.TME_LEAVE
			tme.HwndTrack = hwnd
			tme.DwHoverTime = w32.HOVER_DEFAULT
			w32.TrackMouseEvent(&tme)
			wnd.trackMouse = true
			wnd.events <- wde.MouseEnteredEvent(mme)
		} else {
			if wnd.button == 0 {
				wnd.events <- mme
			} else {
				var mde wde.MouseDraggedEvent
				mde.MouseMovedEvent = mme
				mde.Which = wnd.button
				wnd.events <- mde
			}
		}

	case w32.WM_MOUSELEAVE:
		wnd.trackMouse = false

		var wee wde.MouseExitedEvent
		// TODO: get real position
		wee.Where.Y = wnd.lastX
		wee.Where.X = wnd.lastY
		wnd.events <- wee

	case w32.WM_KEYDOWN:
		// TODO: letter
		ke := wde.KeyEvent{
			fmt.Sprintf("%d", wparam),
		}
		wnd.events <- wde.KeyDownEvent(ke)
		kpe := wde.KeyTypedEvent{
			KeyEvent: ke,
		}
		wnd.events <- kpe

	case w32.WM_KEYUP:
		// TODO: letter
		wnd.events <- wde.KeyUpEvent{
			fmt.Sprintf("%d", wparam),
		}

	case w32.WM_SIZE:
		width := int(lparam) & 0xFFFF
		height := int(lparam>>16) & 0xFFFF
		wnd.buffer = NewDIB(image.Rect(0, 0, width, height))
		wnd.events <- wde.ResizeEvent{width, height}
		rc = w32.DefWindowProc(hwnd, msg, wparam, lparam)

	case w32.WM_PAINT:
		var paint w32.PAINTSTRUCT
		hdc := w32.BeginPaint(hwnd, &paint)
		wnd.blitImage(hdc)
		w32.EndPaint(hwnd, &paint)
		rc = w32.DefWindowProc(hwnd, msg, wparam, lparam)

	case w32.WM_CLOSE:
		UnRegMsgHandler(hwnd)
		w32.DestroyWindow(hwnd)
		wnd.events <- wde.CloseEvent{}

	case w32.WM_DESTROY:
		w32.PostQuitMessage(0)

	default:
		rc = w32.DefWindowProc(hwnd, msg, wparam, lparam)
	}

	return rc
}
Exemple #8
0
// WinEvent proccess a win32 event.
func winEvent(id w32.HWND, event uint32, wParam, lParam uintptr) uintptr {
	w, ok := widgetTable[id]
	if !ok {
		return w32.DefWindowProc(id, event, wParam, lParam)
	}
	switch event {
	case w32.WM_CHAR:
		r := utf16.Decode([]uint16{uint16(loWord(uint32(wParam)))})
		if len(r) == 0 {
			break
		}
		key := r[0]
		if key == 0 {
			break
		}
		if (key == '\b') || (key == '\t') || (key == '\n') || (key == '\r') {
			break
		}
		ev := sparta.KeyEvent{
			Key:   sparta.Key(key),
			State: getState(),
		}
		x, y, _ := w32.GetCursorPos()
		ev.Loc.X, ev.Loc.Y, _ = w32.ScreenToClient(id, x, y)
		w.OnEvent(ev)
	case w32.WM_CLOSE:
		if w.Property(sparta.Parent) != nil {
			break
		}
		w.OnEvent(sparta.CloseEvent{})
	case w32.WM_KEYDOWN:
		key := getKeyValue(wParam)
		if key == 0 {
			break
		}
		if (key & sparta.KeyNoChar) == 0 {
			break
		}
		ev := sparta.KeyEvent{
			Key:   key,
			State: getState(),
		}
		x, y, _ := w32.GetCursorPos()
		ev.Loc.X, ev.Loc.Y, _ = w32.ScreenToClient(id, x, y)
		w.OnEvent(ev)
	case w32.WM_KEYUP:
		key := getKeyValue(wParam)
		if key == 0 {
			break
		}
		ev := sparta.KeyEvent{
			Key:   -key,
			State: getState(),
		}
		x, y, _ := w32.GetCursorPos()
		ev.Loc.X, ev.Loc.Y, _ = w32.ScreenToClient(id, x, y)
		w.OnEvent(ev)
	case w32.WM_LBUTTONDOWN, w32.WM_RBUTTONDOWN, w32.WM_MBUTTONDOWN:
		ev := sparta.MouseEvent{
			Button: getButton(event),
			State:  getState(),
			Loc:    image.Pt(getXLParam(lParam), getYLParam(lParam)),
		}
		w.OnEvent(ev)
		w.Focus()
	case w32.WM_LBUTTONUP, w32.WM_RBUTTONUP, w32.WM_MBUTTONUP:
		ev := sparta.MouseEvent{
			Button: -getButton(event),
			State:  getState(),
			Loc:    image.Pt(getXLParam(lParam), getYLParam(lParam)),
		}
		w.OnEvent(ev)
	case w32.WM_MOUSEMOVE:
		ev := sparta.MouseEvent{
			Loc: image.Pt(getXLParam(lParam), getYLParam(lParam)),
		}
		w.OnEvent(ev)
	case w32.WM_MOUSEWHEEL:
		ev := sparta.MouseEvent{
			Button: sparta.MouseWheel,
		}
		if getWheelDeltaWParam(wParam) < 0 {
			ev.Button = -sparta.MouseWheel
		}
		ev.Loc.X, ev.Loc.Y, _ = w32.ScreenToClient(id, getXLParam(lParam), getYLParam(lParam))
		w = propagateWheel(w, ev.Loc)
		w.OnEvent(ev)
	case w32.WM_MOVE:
		win := w.Window().(*window)
		win.pos.X, win.pos.Y = int(loWord(uint32(lParam))), int(hiWord(uint32(lParam)))
	case w32.WM_PAINT:
		win := w.Window().(*window)
		ps := &w32.PAINTSTRUCT{}
		win.dc = w32.BeginPaint(id, ps)
		win.isPaint = true

		w32.SetBkMode(win.dc, w32.TRANSPARENT)
		w32.SetBkColor(win.dc, win.back.color)

		// "clear" the area
		w32.SelectObject(win.dc, w32.HGDIOBJ(win.back.brush))
		w32.SelectObject(win.dc, w32.HGDIOBJ(win.back.pen))
		w32.Rectangle(win.dc, int(ps.RcPaint.Left), int(ps.RcPaint.Top), int(ps.RcPaint.Right), int(ps.RcPaint.Bottom))

		w32.SelectObject(win.dc, w32.HGDIOBJ(win.fore.brush))
		w32.SelectObject(win.dc, w32.HGDIOBJ(win.fore.pen))
		w32.SelectObject(win.dc, w32.HGDIOBJ(winFont))
		w32.SetTextColor(win.dc, win.fore.color)
		win.curr = win.fore

		ev := sparta.ExposeEvent{image.Rect(int(ps.RcPaint.Left), int(ps.RcPaint.Top), int(ps.RcPaint.Right), int(ps.RcPaint.Bottom))}
		w.OnEvent(ev)
		w32.EndPaint(id, ps)
		win.isPaint = false
		win.dc = 0
	case w32.WM_SIZE:
		win := w.Window().(*window)
		ev := sparta.ConfigureEvent{image.Rect(win.pos.X, win.pos.Y, win.pos.X+int(loWord(uint32(lParam))), win.pos.Y+int(hiWord(uint32(lParam))))}
		w.OnEvent(ev)
	case w32.WM_USER:
		src, ok := widgetTable[w32.HWND(wParam)]
		if !ok {
			src = nil
		}
		ev := sparta.CommandEvent{
			Source: src,
			Value:  int(int32(lParam)),
		}
		w.OnEvent(ev)
	default:
		return w32.DefWindowProc(id, event, wParam, lParam)
	}
	return 0
}
Exemple #9
0
func WndProc(hwnd w32.HWND, msg uint32, wparam, lparam uintptr) uintptr {
	wnd := GetMsgHandler(hwnd)
	if wnd == nil {
		return uintptr(w32.DefWindowProc(hwnd, msg, wparam, lparam))
	}

	var rc uintptr
	switch msg {
	case w32.WM_ACTIVATE:
		if wparam&0xffff != 0 {
			/* This window has just been granted focus, so flag our internal
			** key state as stale. We can't simply refresh our state because
			** win32's GetKeyboardState isn't always accurate at this point
			** in the event stream. */
			wnd.keysStale = true
		}
		rc = w32.DefWindowProc(hwnd, msg, wparam, lparam)

	case w32.WM_SHOWWINDOW:
		w32.SetFocus(hwnd)
		wnd.restoreCursor()

	case w32.WM_LBUTTONDOWN, w32.WM_RBUTTONDOWN, w32.WM_MBUTTONDOWN:
		wnd.button = wnd.button | buttonForDetail(msg)
		var bpe wde.MouseDownEvent
		bpe.Which = buttonForDetail(msg)
		bpe.Where.X = int(lparam) & 0xFFFF
		bpe.Where.Y = int(lparam>>16) & 0xFFFF
		wnd.lastX = bpe.Where.X
		wnd.lastY = bpe.Where.Y
		wnd.events <- bpe

	case w32.WM_LBUTTONUP, w32.WM_RBUTTONUP, w32.WM_MBUTTONUP:
		wnd.button = wnd.button & ^buttonForDetail(msg)
		var bpe wde.MouseUpEvent
		bpe.Which = buttonForDetail(msg)
		bpe.Where.X = int(lparam) & 0xFFFF
		bpe.Where.Y = int(lparam>>16) & 0xFFFF
		wnd.lastX = bpe.Where.X
		wnd.lastY = bpe.Where.Y
		wnd.events <- bpe

	case w32.WM_MOUSEWHEEL:
		var me wde.MouseEvent
		screenX := int(lparam) & 0xFFFF
		screenY := int(lparam>>16) & 0xFFFF
		me.Where.X, me.Where.Y, _ = w32.ScreenToClient(wnd.hwnd, screenX, screenY)
		button := wde.WheelDownButton
		delta := int16((wparam >> 16) & 0xFFFF)
		if delta > 0 {
			button = wde.WheelUpButton
		}
		wnd.lastX = me.Where.X
		wnd.lastX = me.Where.Y
		wnd.events <- wde.MouseDownEvent{me, button}
		wnd.events <- wde.MouseUpEvent{me, button}

	case w32.WM_MOUSEMOVE:
		var mme wde.MouseMovedEvent
		mme.Where.X = int(lparam) & 0xFFFF
		mme.Where.Y = int(lparam>>16) & 0xFFFF
		if wnd.lastX != wnd.noX {
			mme.From.X = int(wnd.lastX)
			mme.From.Y = int(wnd.lastY)
		} else {
			mme.From.X = mme.Where.X
			mme.From.Y = mme.Where.Y
		}
		wnd.lastX = mme.Where.X
		wnd.lastY = mme.Where.Y

		if !wnd.trackMouse {
			var tme w32.TRACKMOUSEEVENT
			tme.CbSize = uint32(unsafe.Sizeof(tme))
			tme.DwFlags = w32.TME_LEAVE
			tme.HwndTrack = hwnd
			tme.DwHoverTime = w32.HOVER_DEFAULT
			w32.TrackMouseEvent(&tme)
			wnd.trackMouse = true
			wnd.restoreCursor()
			wnd.events <- wde.MouseEnteredEvent(mme)
		} else {
			if wnd.button == 0 {
				wnd.events <- mme
			} else {
				var mde wde.MouseDraggedEvent
				mde.MouseMovedEvent = mme
				mde.Which = wnd.button
				wnd.events <- mde
			}
		}

	case w32.WM_MOUSELEAVE:
		wnd.trackMouse = false

		var wee wde.MouseExitedEvent
		// TODO: get real position
		wee.Where.Y = wnd.lastX
		wee.Where.X = wnd.lastY
		wnd.events <- wee

	case w32.WM_SYSKEYDOWN, w32.WM_KEYDOWN:
		translatable := w32.MapVirtualKeyEx(uint(wparam), w32.MAPVK_VK_TO_CHAR, w32.HKL(0))
		wnd.keyDown = keyFromVirtualKeyCode(wparam)
		wnd.keysDown[wnd.keyDown] = true
		wnd.checkKeyState()
		wnd.events <- wde.KeyDownEvent{wnd.keyDown}
		if translatable == 0 {
			kpe := wde.KeyTypedEvent{
				wde.KeyEvent{wnd.keyDown},
				"",
				wnd.constructChord(),
			}
			wnd.events <- kpe
		}
	case w32.WM_SYSCHAR, w32.WM_CHAR:
		glyph := syscall.UTF16ToString([]uint16{uint16(wparam)})
		kpe := wde.KeyTypedEvent{
			wde.KeyEvent{wnd.keyDown},
			glyph,
			wnd.constructChord(),
		}
		wnd.events <- kpe
	case w32.WM_SYSKEYUP, w32.WM_KEYUP:
		keyUp := keyFromVirtualKeyCode(wparam)
		delete(wnd.keysDown, keyUp)
		wnd.checkKeyState()
		wnd.events <- wde.KeyUpEvent{
			keyUp,
		}

	case w32.WM_SIZE:
		width := int(lparam) & 0xFFFF
		height := int(lparam>>16) & 0xFFFF
		wnd.buffer = NewDIB(image.Rect(0, 0, width, height))
		wnd.events <- wde.ResizeEvent{width, height}
		rc = w32.DefWindowProc(hwnd, msg, wparam, lparam)

	case w32.WM_PAINT:
		wnd.Repaint()
		rc = w32.DefWindowProc(hwnd, msg, wparam, lparam)

	case WDEM_UI_THREAD:
		f := <-wnd.uiTasks
		f()

	case w32.WM_CLOSE:
		wnd.events <- wde.CloseEvent{}

	case w32.WM_DESTROY:
		w32.PostQuitMessage(0)

	default:
		rc = w32.DefWindowProc(hwnd, msg, wparam, lparam)
	}

	return rc
}
Exemple #10
0
func WndProc(hwnd w32.HWND, msg uint, wparam, lparam uintptr) uintptr {
	wnd := GetMsgHandler(hwnd)
	if wnd == nil {
		return uintptr(w32.DefWindowProc(hwnd, msg, wparam, lparam))
	}

	var rc uintptr
	switch msg {
	case w32.WM_SHOWWINDOW:
		w32.SetFocus(hwnd)
	case w32.WM_LBUTTONDOWN, w32.WM_RBUTTONDOWN, w32.WM_MBUTTONDOWN:
		wnd.button = wnd.button | buttonForDetail(msg)
		var bpe wde.MouseDownEvent
		bpe.Which = buttonForDetail(msg)
		bpe.Where.X = int(lparam) & 0xFFFF
		bpe.Where.Y = int(lparam>>16) & 0xFFFF
		wnd.lastX = bpe.Where.X
		wnd.lastY = bpe.Where.Y
		wnd.events <- bpe

	case w32.WM_LBUTTONUP, w32.WM_RBUTTONUP, w32.WM_MBUTTONUP:
		wnd.button = wnd.button & ^buttonForDetail(msg)
		var bpe wde.MouseUpEvent
		bpe.Which = buttonForDetail(msg)
		bpe.Where.X = int(lparam) & 0xFFFF
		bpe.Where.Y = int(lparam>>16) & 0xFFFF
		wnd.lastX = bpe.Where.X
		wnd.lastY = bpe.Where.Y
		wnd.events <- bpe

	case w32.WM_MOUSEMOVE:
		var mme wde.MouseMovedEvent
		mme.Where.X = int(lparam) & 0xFFFF
		mme.Where.Y = int(lparam>>16) & 0xFFFF
		if wnd.lastX != wnd.noX {
			mme.From.X = int(wnd.lastX)
			mme.From.Y = int(wnd.lastY)
		} else {
			mme.From.X = mme.Where.X
			mme.From.Y = mme.Where.Y
		}
		wnd.lastX = mme.Where.X
		wnd.lastY = mme.Where.Y

		if !wnd.trackMouse {
			var tme w32.TRACKMOUSEEVENT
			tme.CbSize = uint(unsafe.Sizeof(tme))
			tme.DwFlags = w32.TME_LEAVE
			tme.HwndTrack = hwnd
			tme.DwHoverTime = w32.HOVER_DEFAULT
			w32.TrackMouseEvent(&tme)
			wnd.trackMouse = true
			wnd.events <- wde.MouseEnteredEvent(mme)
		} else {
			if wnd.button == 0 {
				wnd.events <- mme
			} else {
				var mde wde.MouseDraggedEvent
				mde.MouseMovedEvent = mme
				mde.Which = wnd.button
				wnd.events <- mde
			}
		}

	case w32.WM_MOUSELEAVE:
		wnd.trackMouse = false

		var wee wde.MouseExitedEvent
		// TODO: get real position
		wee.Where.Y = wnd.lastX
		wee.Where.X = wnd.lastY
		wnd.events <- wee

	case w32.WM_SYSKEYDOWN:
		keyDown = keyFromVirtualKeyCode(wparam)
		keysDown[wde.KeyLeftAlt] = true
		keysDown[keyDown] = true
		ke := wde.KeyEvent{
			keyDown,
		}
		wnd.events <- wde.KeyDownEvent(ke)
	case w32.WM_KEYDOWN:
		keyDown = keyFromVirtualKeyCode(wparam)
		keysDown[keyDown] = true
		ke := wde.KeyEvent{
			keyDown,
		}
		wnd.events <- wde.KeyDownEvent(ke)
	case w32.WM_SYSCHAR:
		glyph := syscall.UTF16ToString([]uint16{uint16(wparam)})
		ke := wde.KeyEvent{
			keyDown,
		}
		kpe := wde.KeyTypedEvent{
			ke,
			glyph,
			wde.ConstructChord(keysDown),
		}
		wnd.events <- kpe
	case w32.WM_CHAR:
		glyph := syscall.UTF16ToString([]uint16{uint16(wparam)})
		ke := wde.KeyEvent{
			keyDown,
		}
		kpe := wde.KeyTypedEvent{
			ke,
			glyph,
			wde.ConstructChord(keysDown),
		}
		wnd.events <- kpe
	case w32.WM_SYSKEYUP:
		keyUp := keyFromVirtualKeyCode(wparam)
		delete(keysDown, wde.KeyLeftAlt)
		delete(keysDown, keyUp)
		wnd.events <- wde.KeyUpEvent{
			keyUp,
		}
	case w32.WM_KEYUP:
		keyUp := keyFromVirtualKeyCode(wparam)
		delete(keysDown, keyUp)
		wnd.events <- wde.KeyUpEvent{
			keyUp,
		}

	case w32.WM_SIZE:
		width := int(lparam) & 0xFFFF
		height := int(lparam>>16) & 0xFFFF
		wnd.buffer = NewDIB(image.Rect(0, 0, width, height))
		wnd.events <- wde.ResizeEvent{width, height}
		rc = w32.DefWindowProc(hwnd, msg, wparam, lparam)

	case w32.WM_PAINT:
		rc = w32.DefWindowProc(hwnd, msg, wparam, lparam)

	case w32.WM_CLOSE:
		UnRegMsgHandler(hwnd)
		w32.DestroyWindow(hwnd)
		wnd.events <- wde.CloseEvent{}

	case w32.WM_DESTROY:
		w32.PostQuitMessage(0)

	default:
		rc = w32.DefWindowProc(hwnd, msg, wparam, lparam)
	}

	return rc
}