Archived
2
0
This repository has been archived on 2024-06-24. You can view files and clone it, but cannot push or open issues or pull requests.
neko-custom/server/internal/desktop/xorg/xorg.go

321 lines
5.7 KiB
Go
Raw Permalink Normal View History

2020-02-11 18:15:59 +13:00
package xorg
2020-01-19 12:30:09 +13:00
/*
2022-09-14 07:40:40 +12:00
#cgo LDFLAGS: -lX11 -lXrandr -lXtst -lXfixes
2020-01-19 12:30:09 +13:00
2020-02-11 18:15:59 +13:00
#include "xorg.h"
2020-01-19 12:30:09 +13:00
*/
import "C"
import (
"fmt"
2022-09-14 07:40:40 +12:00
"image"
"image/color"
"sync"
2020-01-19 12:30:09 +13:00
"time"
2020-02-11 18:15:59 +13:00
"unsafe"
2020-01-19 12:30:09 +13:00
2021-10-06 09:38:24 +13:00
"m1k1o/neko/internal/types"
2020-01-19 12:30:09 +13:00
)
2022-09-14 07:40:40 +12:00
//go:generate ./keysymdef.sh
type KbdMod uint8
const (
KbdModCapsLock KbdMod = 2
KbdModNumLock KbdMod = 16
)
2020-02-11 18:15:59 +13:00
var ScreenConfigurations = make(map[int]types.ScreenConfiguration)
2022-09-14 07:40:40 +12:00
var debounce_button = make(map[uint32]time.Time)
var debounce_key = make(map[uint32]time.Time)
var mu = sync.Mutex{}
2020-01-19 12:30:09 +13:00
2022-09-14 07:40:40 +12:00
func GetScreenConfigurations() {
mu.Lock()
defer mu.Unlock()
2020-02-11 18:15:59 +13:00
C.XGetScreenConfigurations()
2020-01-19 12:30:09 +13:00
}
2022-09-14 07:40:40 +12:00
func DisplayOpen(display string) bool {
mu.Lock()
defer mu.Unlock()
2020-02-11 18:15:59 +13:00
displayUnsafe := C.CString(display)
defer C.free(unsafe.Pointer(displayUnsafe))
2022-09-14 07:40:40 +12:00
ok := C.XDisplayOpen(displayUnsafe)
return int(ok) == 1
}
func DisplayClose() {
mu.Lock()
defer mu.Unlock()
C.XDisplayClose()
2020-01-19 12:30:09 +13:00
}
func Move(x, y int) {
mu.Lock()
defer mu.Unlock()
2020-01-26 03:29:52 +13:00
C.XMove(C.int(x), C.int(y))
2020-01-19 12:30:09 +13:00
}
2022-09-14 07:40:40 +12:00
func GetCursorPosition() (int, int) {
mu.Lock()
defer mu.Unlock()
var x C.int
var y C.int
C.XCursorPosition(&x, &y)
return int(x), int(y)
}
2020-01-19 12:30:09 +13:00
func Scroll(x, y int) {
mu.Lock()
defer mu.Unlock()
2020-01-26 03:29:52 +13:00
C.XScroll(C.int(x), C.int(y))
2020-01-19 12:30:09 +13:00
}
2022-09-14 07:40:40 +12:00
func ButtonDown(code uint32) error {
mu.Lock()
defer mu.Unlock()
2020-06-16 04:57:28 +12:00
if _, ok := debounce_button[code]; ok {
2020-06-14 02:21:11 +12:00
return fmt.Errorf("debounced button %v", code)
2020-01-19 12:30:09 +13:00
}
2020-06-16 04:57:28 +12:00
debounce_button[code] = time.Now()
2020-01-19 12:30:09 +13:00
2020-06-14 02:21:11 +12:00
C.XButton(C.uint(code), C.int(1))
return nil
2020-01-19 12:30:09 +13:00
}
2022-09-14 07:40:40 +12:00
func KeyDown(code uint32) error {
mu.Lock()
defer mu.Unlock()
2020-06-16 04:57:28 +12:00
if _, ok := debounce_key[code]; ok {
2020-06-14 02:21:11 +12:00
return fmt.Errorf("debounced key %v", code)
2020-01-19 12:30:09 +13:00
}
2020-06-16 04:57:28 +12:00
debounce_key[code] = time.Now()
2020-01-26 03:29:52 +13:00
2021-04-13 05:22:59 +12:00
C.XKey(C.KeySym(code), C.int(1))
2020-06-14 02:21:11 +12:00
return nil
2020-01-19 12:30:09 +13:00
}
2022-09-14 07:40:40 +12:00
func ButtonUp(code uint32) error {
mu.Lock()
defer mu.Unlock()
2020-06-16 04:57:28 +12:00
if _, ok := debounce_button[code]; !ok {
2020-06-14 02:21:11 +12:00
return fmt.Errorf("debounced button %v", code)
2020-01-19 12:30:09 +13:00
}
2020-06-16 04:57:28 +12:00
delete(debounce_button, code)
2020-01-19 12:30:09 +13:00
2020-06-14 02:21:11 +12:00
C.XButton(C.uint(code), C.int(0))
return nil
2020-01-19 12:30:09 +13:00
}
2022-09-14 07:40:40 +12:00
func KeyUp(code uint32) error {
mu.Lock()
defer mu.Unlock()
2020-06-16 04:57:28 +12:00
if _, ok := debounce_key[code]; !ok {
2020-06-14 02:21:11 +12:00
return fmt.Errorf("debounced key %v", code)
2020-01-19 12:30:09 +13:00
}
2020-06-16 04:57:28 +12:00
delete(debounce_key, code)
2020-01-19 12:30:09 +13:00
2021-04-13 05:22:59 +12:00
C.XKey(C.KeySym(code), C.int(0))
2020-06-14 02:21:11 +12:00
return nil
2020-01-19 12:30:09 +13:00
}
2020-02-11 18:15:59 +13:00
func ResetKeys() {
2022-09-14 07:40:40 +12:00
mu.Lock()
defer mu.Unlock()
2020-06-16 04:57:28 +12:00
2022-09-14 07:40:40 +12:00
for code := range debounce_button {
C.XButton(C.uint(code), C.int(0))
2020-06-16 04:57:28 +12:00
delete(debounce_button, code)
}
2020-01-19 12:30:09 +13:00
2022-09-14 07:40:40 +12:00
for code := range debounce_key {
C.XKey(C.KeySym(code), C.int(0))
2020-06-16 04:57:28 +12:00
delete(debounce_key, code)
2020-01-19 12:30:09 +13:00
}
}
2020-02-11 18:15:59 +13:00
func CheckKeys(duration time.Duration) {
2022-09-14 07:40:40 +12:00
mu.Lock()
defer mu.Unlock()
2020-01-19 12:30:09 +13:00
t := time.Now()
2020-06-16 04:57:28 +12:00
for code, start := range debounce_button {
2020-01-19 12:30:09 +13:00
if t.Sub(start) < duration {
continue
}
2022-09-14 07:40:40 +12:00
C.XButton(C.uint(code), C.int(0))
2020-06-16 04:57:28 +12:00
delete(debounce_button, code)
}
2022-09-14 07:40:40 +12:00
2020-06-16 04:57:28 +12:00
for code, start := range debounce_key {
if t.Sub(start) < duration {
continue
2020-01-19 12:30:09 +13:00
}
2022-09-14 07:40:40 +12:00
C.XKey(C.KeySym(code), C.int(0))
2020-06-16 04:57:28 +12:00
delete(debounce_key, code)
2020-01-19 12:30:09 +13:00
}
}
2020-02-11 18:15:59 +13:00
2022-09-14 07:40:40 +12:00
func ChangeScreenSize(width int, height int, rate int16) error {
2020-02-11 18:15:59 +13:00
mu.Lock()
defer mu.Unlock()
for index, size := range ScreenConfigurations {
if size.Width == width && size.Height == height {
2020-02-11 19:10:36 +13:00
for _, fps := range size.Rates {
2022-09-14 07:40:40 +12:00
if rate == fps {
2020-02-11 19:10:36 +13:00
C.XSetScreenConfiguration(C.int(index), C.short(fps))
2020-02-11 18:15:59 +13:00
return nil
}
}
}
}
2022-09-14 07:40:40 +12:00
return fmt.Errorf("unknown screen configuration %dx%d@%d", width, height, rate)
2020-02-11 18:15:59 +13:00
}
func GetScreenSize() *types.ScreenSize {
mu.Lock()
defer mu.Unlock()
index := int(C.XGetScreenSize())
rate := int16(C.XGetScreenRate())
if conf, ok := ScreenConfigurations[index]; ok {
return &types.ScreenSize{
Width: conf.Width,
Height: conf.Height,
Rate: rate,
}
}
return nil
}
2022-09-14 07:40:40 +12:00
func SetKeyboardModifier(mod KbdMod, active bool) {
mu.Lock()
defer mu.Unlock()
num := C.int(0)
if active {
num = C.int(1)
}
C.XSetKeyboardModifier(C.int(mod), num)
}
func GetKeyboardModifiers() KbdMod {
mu.Lock()
defer mu.Unlock()
return KbdMod(C.XGetKeyboardModifiers())
}
func GetCursorImage() *types.CursorImage {
mu.Lock()
defer mu.Unlock()
cur := C.XGetCursorImage()
defer C.XFree(unsafe.Pointer(cur))
width := int(cur.width)
height := int(cur.height)
// Xlib stores 32-bit data in longs, even if longs are 64-bits long.
pixels := C.GoBytes(unsafe.Pointer(cur.pixels), C.int(width*height*8))
img := image.NewRGBA(image.Rect(0, 0, width, height))
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
pos := ((y * width) + x) * 8
img.SetRGBA(x, y, color.RGBA{
A: pixels[pos+3],
R: pixels[pos+2],
G: pixels[pos+1],
B: pixels[pos+0],
})
}
}
return &types.CursorImage{
Width: uint16(width),
Height: uint16(height),
Xhot: uint16(cur.xhot),
Yhot: uint16(cur.yhot),
Serial: uint64(cur.cursor_serial),
Image: img,
}
}
func GetScreenshotImage() *image.RGBA {
2020-06-20 12:15:38 +12:00
mu.Lock()
defer mu.Unlock()
2022-09-14 07:40:40 +12:00
var w, h C.int
pixelsUnsafe := C.XGetScreenshot(&w, &h)
pixels := C.GoBytes(unsafe.Pointer(pixelsUnsafe), w*h*3)
defer C.free(unsafe.Pointer(pixelsUnsafe))
width := int(w)
height := int(h)
img := image.NewRGBA(image.Rect(0, 0, width, height))
for row := 0; row < height; row++ {
for col := 0; col < width; col++ {
pos := ((row * width) + col) * 3
img.SetRGBA(col, row, color.RGBA{
R: uint8(pixels[pos]),
G: uint8(pixels[pos+1]),
B: uint8(pixels[pos+2]),
A: 0xFF,
})
}
}
return img
2020-06-20 12:15:38 +12:00
}
2020-02-11 18:15:59 +13:00
//export goCreateScreenSize
func goCreateScreenSize(index C.int, width C.int, height C.int, mwidth C.int, mheight C.int) {
ScreenConfigurations[int(index)] = types.ScreenConfiguration{
Width: int(width),
Height: int(height),
Rates: make(map[int]int16),
}
}
//export goSetScreenRates
2022-09-14 07:40:40 +12:00
func goSetScreenRates(index C.int, rate_index C.int, rateC C.short) {
rate := int16(rateC)
// filter out all irrelevant rates
if rate > 60 || (rate > 30 && rate%10 != 0) {
return
}
ScreenConfigurations[int(index)].Rates[int(rate_index)] = rate
2020-02-11 18:15:59 +13:00
}