mirror of
https://github.com/mirkobrombin/raven.git
synced 2026-11-03 21:46:32 +00:00
137 lines
3.4 KiB
Go
137 lines
3.4 KiB
Go
package win32k
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/mirkobrombin/Raven/pkg/mmu"
|
|
)
|
|
|
|
// MessageQueue translates host input events into Windows messages.
|
|
// In the future, Wayland events (wl_pointer, wl_keyboard) will feed this queue
|
|
// and be translated into WM_* messages for the guest application.
|
|
type MessageQueue struct {
|
|
mu sync.Mutex
|
|
mem *mmu.MMU
|
|
win32k *Win32kSubsystem
|
|
pending []WinMessage
|
|
shutdown bool
|
|
}
|
|
|
|
// NewMessageQueue creates a message queue bridge.
|
|
func NewMessageQueue(mem *mmu.MMU, w *Win32kSubsystem) *MessageQueue {
|
|
return &MessageQueue{
|
|
mem: mem,
|
|
win32k: w,
|
|
}
|
|
}
|
|
|
|
// Windows message constants.
|
|
const (
|
|
WM_NULL = 0x0000
|
|
WM_CREATE = 0x0001
|
|
WM_DESTROY = 0x0002
|
|
WM_MOVE = 0x0003
|
|
WM_SIZE = 0x0005
|
|
WM_ACTIVATE = 0x0006
|
|
WM_SETFOCUS = 0x0007
|
|
WM_KILLFOCUS = 0x0008
|
|
WM_CLOSE = 0x0010
|
|
WM_QUIT = 0x0012
|
|
WM_PAINT = 0x000F
|
|
WM_ERASEBKGND = 0x0014
|
|
WM_SHOWWINDOW = 0x0018
|
|
WM_KEYDOWN = 0x0100
|
|
WM_KEYUP = 0x0101
|
|
WM_CHAR = 0x0102
|
|
WM_SYSKEYDOWN = 0x0104
|
|
WM_SYSKEYUP = 0x0105
|
|
WM_MOUSEMOVE = 0x0200
|
|
WM_LBUTTONDOWN = 0x0201
|
|
WM_LBUTTONUP = 0x0202
|
|
WM_RBUTTONDOWN = 0x0204
|
|
WM_RBUTTONUP = 0x0205
|
|
WM_MBUTTONDOWN = 0x0207
|
|
WM_MBUTTONUP = 0x0208
|
|
WM_MOUSEWHEEL = 0x020A
|
|
WM_TIMER = 0x0113
|
|
WM_NCCREATE = 0x0081
|
|
WM_NCDESTROY = 0x0082
|
|
WM_NCHITTEST = 0x0084
|
|
WM_NCPAINT = 0x0085
|
|
WM_GETMINMAXINFO = 0x0024
|
|
WM_WINDOWPOSCHANGING = 0x0046
|
|
WM_WINDOWPOSCHANGED = 0x0047
|
|
)
|
|
|
|
// InjectKeyDown injects a key-down event from Wayland into the guest.
|
|
func (mq *MessageQueue) InjectKeyDown(hwnd uint64, vkCode uint32, scanCode uint32) {
|
|
mq.win32k.PostMessage(hwnd, WM_KEYDOWN, uint64(vkCode), uint64(scanCode)<<16|1)
|
|
}
|
|
|
|
// InjectKeyUp injects a key-up event.
|
|
func (mq *MessageQueue) InjectKeyUp(hwnd uint64, vkCode uint32, scanCode uint32) {
|
|
mq.win32k.PostMessage(hwnd, WM_KEYUP, uint64(vkCode), uint64(scanCode)<<16|0xC0000001)
|
|
}
|
|
|
|
// InjectChar injects a WM_CHAR event (translated character).
|
|
func (mq *MessageQueue) InjectChar(hwnd uint64, char rune) {
|
|
mq.win32k.PostMessage(hwnd, WM_CHAR, uint64(char), 1)
|
|
}
|
|
|
|
// InjectMouseMove injects a mouse movement event.
|
|
func (mq *MessageQueue) InjectMouseMove(hwnd uint64, x, y int32) {
|
|
lParam := uint64(uint32(y))<<16 | uint64(uint32(x)&0xFFFF)
|
|
mq.win32k.PostMessage(hwnd, WM_MOUSEMOVE, 0, lParam)
|
|
}
|
|
|
|
// InjectMouseButton injects a mouse button press/release.
|
|
func (mq *MessageQueue) InjectMouseButton(hwnd uint64, button int, down bool, x, y int32) {
|
|
lParam := uint64(uint32(y))<<16 | uint64(uint32(x)&0xFFFF)
|
|
var msg uint32
|
|
switch button {
|
|
case 0: // left
|
|
if down {
|
|
msg = WM_LBUTTONDOWN
|
|
} else {
|
|
msg = WM_LBUTTONUP
|
|
}
|
|
case 1: // right
|
|
if down {
|
|
msg = WM_RBUTTONDOWN
|
|
} else {
|
|
msg = WM_RBUTTONUP
|
|
}
|
|
case 2: // middle
|
|
if down {
|
|
msg = WM_MBUTTONDOWN
|
|
} else {
|
|
msg = WM_MBUTTONUP
|
|
}
|
|
}
|
|
mq.win32k.PostMessage(hwnd, msg, 0, lParam)
|
|
}
|
|
|
|
// Run starts the message queue pump. In the future, this reads from a Wayland
|
|
// connection and translates events. For now it generates periodic WM_TIMER.
|
|
func (mq *MessageQueue) Run() {
|
|
ticker := time.NewTicker(16 * time.Millisecond) // ~60fps
|
|
defer ticker.Stop()
|
|
|
|
for range ticker.C {
|
|
mq.mu.Lock()
|
|
if mq.shutdown {
|
|
mq.mu.Unlock()
|
|
return
|
|
}
|
|
mq.mu.Unlock()
|
|
}
|
|
}
|
|
|
|
// Stop shuts down the message queue.
|
|
func (mq *MessageQueue) Stop() {
|
|
mq.mu.Lock()
|
|
mq.shutdown = true
|
|
mq.mu.Unlock()
|
|
}
|