Merge pull request #92 from m1k1o/guacamole-kbd

Guacamole Keyboard support + choose layout
This commit is contained in:
Nurdism
2020-07-11 16:17:32 -04:00
committed by GitHub
25 changed files with 1865 additions and 995 deletions

View File

@ -181,19 +181,19 @@ func (manager *RemoteManager) Scroll(x, y int) {
xorg.Scroll(x, y)
}
func (manager *RemoteManager) ButtonDown(code int) (*types.Button, error) {
func (manager *RemoteManager) ButtonDown(code int) error {
return xorg.ButtonDown(code)
}
func (manager *RemoteManager) KeyDown(code int) (*types.Key, error) {
func (manager *RemoteManager) KeyDown(code uint64) error {
return xorg.KeyDown(code)
}
func (manager *RemoteManager) ButtonUp(code int) (*types.Button, error) {
func (manager *RemoteManager) ButtonUp(code int) error {
return xorg.ButtonUp(code)
}
func (manager *RemoteManager) KeyUp(code int) (*types.Key, error) {
func (manager *RemoteManager) KeyUp(code uint64) error {
return xorg.KeyUp(code)
}
@ -216,3 +216,7 @@ func (manager *RemoteManager) ScreenConfigurations() map[int]types.ScreenConfigu
func (manager *RemoteManager) GetScreenSize() *types.ScreenSize {
return xorg.GetScreenSize()
}
func (manager *RemoteManager) SetKeyboardLayout(layout string) {
xorg.SetKeyboardLayout(layout)
}

View File

@ -22,6 +22,7 @@ const (
CONTROL_REQUESTING = "control/requesting"
CONTROL_GIVE = "control/give"
CONTROL_CLIPBOARD = "control/clipboard"
CONTROL_KEYBOARD = "control/keyboard"
)
const (

View File

@ -46,6 +46,11 @@ type Clipboard struct {
Text string `json:"text"`
}
type Keyboard struct {
Event string `json:"event"`
Layout string `json:"layout"`
}
type Control struct {
Event string `json:"event"`
ID string `json:"id"`

View File

@ -15,11 +15,12 @@ type RemoteManager interface {
ScreenConfigurations() map[int]ScreenConfiguration
Move(x, y int)
Scroll(x, y int)
ButtonDown(code int) (*Button, error)
KeyDown(code int) (*Key, error)
ButtonUp(code int) (*Button, error)
KeyUp(code int) (*Key, error)
ButtonDown(code int) error
KeyDown(code uint64) error
ButtonUp(code int) error
KeyUp(code uint64) error
ReadClipboard() string
WriteClipboard(data string)
ResetKeys()
SetKeyboardLayout(layout string)
}

View File

@ -33,7 +33,7 @@ type PayloadScroll struct {
type PayloadKey struct {
PayloadHeader
Key uint16
Key uint64
}
func (manager *WebRTCManager) handle(id string, msg webrtc.DataChannelMessage) error {
@ -85,21 +85,21 @@ func (manager *WebRTCManager) handle(id string, msg webrtc.DataChannelMessage) e
}
if payload.Key < 8 {
button, err := manager.remote.ButtonDown(int(payload.Key))
err := manager.remote.ButtonDown(int(payload.Key))
if err != nil {
manager.logger.Warn().Err(err).Msg("key down failed")
manager.logger.Warn().Err(err).Msg("button down failed")
return nil
}
manager.logger.Debug().Msgf("button down %s(%d)", button.Name, payload.Key)
manager.logger.Debug().Msgf("button down %d", payload.Key)
} else {
key, err := manager.remote.KeyDown(int(payload.Key))
err := manager.remote.KeyDown(uint64(payload.Key))
if err != nil {
manager.logger.Warn().Err(err).Msg("key down failed")
return nil
}
manager.logger.Debug().Msgf("key down %s(%d)", key.Name, payload.Key)
manager.logger.Debug().Msgf("key down %d", payload.Key)
}
break
@ -111,21 +111,21 @@ func (manager *WebRTCManager) handle(id string, msg webrtc.DataChannelMessage) e
}
if payload.Key < 8 {
button, err := manager.remote.ButtonUp(int(payload.Key))
err := manager.remote.ButtonUp(int(payload.Key))
if err != nil {
manager.logger.Warn().Err(err).Msg("button up failed")
return nil
}
manager.logger.Debug().Msgf("button up %s(%d)", button.Name, payload.Key)
manager.logger.Debug().Msgf("button up %d", payload.Key)
} else {
key, err := manager.remote.KeyUp(int(payload.Key))
err := manager.remote.KeyUp(uint64(payload.Key))
if err != nil {
manager.logger.Warn().Err(err).Msg("keyup failed")
manager.logger.Warn().Err(err).Msg("key up failed")
return nil
}
manager.logger.Debug().Msgf("key up %s(%d)", key.Name, payload.Key)
manager.logger.Debug().Msgf("key up %d", payload.Key)
}
break
case OP_KEY_CLK:

View File

@ -115,3 +115,14 @@ func (h *MessageHandler) controlClipboard(id string, session types.Session, payl
h.remote.WriteClipboard(payload.Text)
return nil
}
func (h *MessageHandler) controlKeyboard(id string, session types.Session, payload *message.Keyboard) error {
// check if session is host
if !h.sessions.IsHost(id) {
h.logger.Debug().Str("id", id).Msg("is not the host")
return nil
}
h.remote.SetKeyboardLayout(payload.Layout)
return nil
}

View File

@ -89,6 +89,13 @@ func (h *MessageHandler) Message(id string, raw []byte) error {
utils.Unmarshal(payload, raw, func() error {
return h.controlClipboard(id, session, payload)
}), "%s failed", header.Event)
case event.CONTROL_KEYBOARD:
payload := &message.Keyboard{}
return errors.Wrapf(
utils.Unmarshal(payload, raw, func() error {
return h.controlKeyboard(id, session, payload)
}), "%s failed", header.Event)
// Chat Events
case event.CHAT_MESSAGE:

View File

@ -1,45 +0,0 @@
package keycode
import "n.eko.moe/neko/internal/types"
var LEFT_BUTTON = types.Button{
Name: "LEFT",
Code: 0,
Keysym: 1,
}
var CENTER_BUTTON = types.Button{
Name: "CENTER",
Code: 1,
Keysym: 2,
}
var RIGHT_BUTTON = types.Button{
Name: "RIGHT",
Code: 2,
Keysym: 3,
}
var SCROLL_UP_BUTTON = types.Button{
Name: "SCROLL_UP",
Code: 3,
Keysym: 4,
}
var SCROLL_DOWN_BUTTON = types.Button{
Name: "SCROLL_DOWN",
Code: 4,
Keysym: 5,
}
var SCROLL_LEFT_BUTTON = types.Button{
Name: "SCROLL_LEFT",
Code: 5,
Keysym: 6,
}
var SCROLL_RIGHT_BUTTON = types.Button{
Name: "SCROLL_RIGHT",
Code: 6,
Keysym: 7,
}

View File

@ -1,696 +0,0 @@
package keycode
import "n.eko.moe/neko/internal/types"
var BACKSPACE = types.Key{
Name: "BACKSPACE",
Value: "BackSpace",
Code: 8,
Keysym: int(0xff08),
}
var TAB = types.Key{
Name: "TAB",
Value: "Tab",
Code: 9,
Keysym: int(0xFF09),
}
var CLEAR = types.Key{
Name: "CLEAR",
Value: "Clear",
Code: 12,
Keysym: int(0xFF0B),
}
var ENTER = types.Key{
Name: "ENTER",
Value: "Enter",
Code: 13,
Keysym: int(0xFF0D),
}
var SHIFT = types.Key{
Name: "SHIFT",
Value: "Shift",
Code: 16,
Keysym: int(0xFFE1),
}
var CTRL = types.Key{
Name: "CTRL",
Value: "Ctrl",
Code: 17,
Keysym: int(0xFFE3),
}
var ALT = types.Key{
Name: "ALT",
Value: "Alt",
Code: 18,
Keysym: int(0xFFE9),
}
var PAUSE = types.Key{
Name: "PAUSE",
Value: "Pause",
Code: 19,
Keysym: int(0xFF13),
}
var CAPS_LOCK = types.Key{
Name: "CAPS_LOCK",
Value: "Caps Lock",
Code: 20,
Keysym: int(0xFFE5),
}
var ESCAPE = types.Key{
Name: "ESCAPE",
Value: "Escape",
Code: 27,
Keysym: int(0xFF1B),
}
var SPACE = types.Key{
Name: "SPACE",
Value: " ",
Code: 32,
Keysym: int(0x0020),
}
var PAGE_UP = types.Key{
Name: "PAGE_UP",
Value: "Page Up",
Code: 33,
Keysym: int(0xFF55),
}
var PAGE_DOWN = types.Key{
Name: "PAGE_DOWN",
Value: "Page Down",
Code: 34,
Keysym: int(0xFF56),
}
var END = types.Key{
Name: "END",
Value: "End",
Code: 35,
Keysym: int(0xFF57),
}
var HOME = types.Key{
Name: "HOME",
Value: "Home",
Code: 36,
Keysym: int(0xFF50),
}
var LEFT_ARROW = types.Key{
Name: "LEFT_ARROW",
Value: "Left Arrow",
Code: 37,
Keysym: int(0xFF51),
}
var UP_ARROW = types.Key{
Name: "UP_ARROW",
Value: "Up Arrow",
Code: 38,
Keysym: int(0xFF52),
}
var RIGHT_ARROW = types.Key{
Name: "RIGHT_ARROW",
Value: "Right Arrow",
Code: 39,
Keysym: int(0xFF53),
}
var DOWN_ARROW = types.Key{
Name: "DOWN_ARROW",
Value: "Down Arrow",
Code: 40,
Keysym: int(0xFF54),
}
var INSERT = types.Key{
Name: "INSERT",
Value: "Insert",
Code: 45,
Keysym: int(0xFF63),
}
var DELETE = types.Key{
Name: "DELETE",
Value: "Delete",
Code: 46,
Keysym: int(0xFFFF),
}
var KEY_0 = types.Key{
Name: "KEY_0",
Value: "0",
Code: 48,
Keysym: int(0x0030),
}
var KEY_1 = types.Key{
Name: "KEY_1",
Value: "1",
Code: 49,
Keysym: int(0x0031),
}
var KEY_2 = types.Key{
Name: "KEY_2",
Value: "2",
Code: 50,
Keysym: int(0x0032),
}
var KEY_3 = types.Key{
Name: "KEY_3",
Value: "3",
Code: 51,
Keysym: int(0x0033),
}
var KEY_4 = types.Key{
Name: "KEY_4",
Value: "4",
Code: 52,
Keysym: int(0x0034),
}
var KEY_5 = types.Key{
Name: "KEY_5",
Value: "5",
Code: 53,
Keysym: int(0x0035),
}
var KEY_6 = types.Key{
Name: "KEY_6",
Value: "6",
Code: 54,
Keysym: int(0x0036),
}
var KEY_7 = types.Key{
Name: "KEY_7",
Value: "7",
Code: 55,
Keysym: int(0x0037),
}
var KEY_8 = types.Key{
Name: "KEY_8",
Value: "8",
Code: 56,
Keysym: int(0x0038),
}
var KEY_9 = types.Key{
Name: "KEY_9",
Value: "9",
Code: 57,
Keysym: int(0x0039),
}
var KEY_A = types.Key{
Name: "KEY_A",
Value: "a",
Code: 65,
Keysym: int(0x0061),
}
var KEY_B = types.Key{
Name: "KEY_B",
Value: "b",
Code: 66,
Keysym: int(0x0062),
}
var KEY_C = types.Key{
Name: "KEY_C",
Value: "c",
Code: 67,
Keysym: int(0x0063),
}
var KEY_D = types.Key{
Name: "KEY_D",
Value: "d",
Code: 68,
Keysym: int(0x0064),
}
var KEY_E = types.Key{
Name: "KEY_E",
Value: "e",
Code: 69,
Keysym: int(0x0065),
}
var KEY_F = types.Key{
Name: "KEY_F",
Value: "f",
Code: 70,
Keysym: int(0x0066),
}
var KEY_G = types.Key{
Name: "KEY_G",
Value: "g",
Code: 71,
Keysym: int(0x0067),
}
var KEY_H = types.Key{
Name: "KEY_H",
Value: "h",
Code: 72,
Keysym: int(0x0068),
}
var KEY_I = types.Key{
Name: "KEY_I",
Value: "i",
Code: 73,
Keysym: int(0x0069),
}
var KEY_J = types.Key{
Name: "KEY_J",
Value: "j",
Code: 74,
Keysym: int(0x006a),
}
var KEY_K = types.Key{
Name: "KEY_K",
Value: "k",
Code: 75,
Keysym: int(0x006b),
}
var KEY_L = types.Key{
Name: "KEY_L",
Value: "l",
Code: 76,
Keysym: int(0x006c),
}
var KEY_M = types.Key{
Name: "KEY_M",
Value: "m",
Code: 77,
Keysym: int(0x006d),
}
var KEY_N = types.Key{
Name: "KEY_N",
Value: "n",
Code: 78,
Keysym: int(0x006e),
}
var KEY_O = types.Key{
Name: "KEY_O",
Value: "o",
Code: 79,
Keysym: int(0x006f),
}
var KEY_P = types.Key{
Name: "KEY_P",
Value: "p",
Code: 80,
Keysym: int(0x0070),
}
var KEY_Q = types.Key{
Name: "KEY_Q",
Value: "q",
Code: 81,
Keysym: int(0x0071),
}
var KEY_R = types.Key{
Name: "KEY_R",
Value: "r",
Code: 82,
Keysym: int(0x0072),
}
var KEY_S = types.Key{
Name: "KEY_S",
Value: "s",
Code: 83,
Keysym: int(0x0073),
}
var KEY_T = types.Key{
Name: "KEY_T",
Value: "t",
Code: 84,
Keysym: int(0x0074),
}
var KEY_U = types.Key{
Name: "KEY_U",
Value: "u",
Code: 85,
Keysym: int(0x0075),
}
var KEY_V = types.Key{
Name: "KEY_V",
Value: "v",
Code: 86,
Keysym: int(0x0076),
}
var KEY_W = types.Key{
Name: "KEY_W",
Value: "w",
Code: 87,
Keysym: int(0x0077),
}
var KEY_X = types.Key{
Name: "KEY_X",
Value: "x",
Code: 88,
Keysym: int(0x0078),
}
var KEY_Y = types.Key{
Name: "KEY_Y",
Value: "y",
Code: 89,
Keysym: int(0x0079),
}
var KEY_Z = types.Key{
Name: "KEY_Z",
Value: "z",
Code: 90,
Keysym: int(0x007a),
}
var WIN_LEFT = types.Key{
Name: "WIN_LEFT",
Value: "Win Left",
Code: 91,
Keysym: int(0xFFEB),
}
var WIN_RIGHT = types.Key{
Name: "WIN_RIGHT",
Value: "Win Right",
Code: 92,
Keysym: int(0xFF67),
}
var PAD_0 = types.Key{
Name: "PAD_0",
Value: "Num Pad 0",
Code: 96,
Keysym: int(0xFFB0),
}
var PAD_1 = types.Key{
Name: "PAD_1",
Value: "Num Pad 1",
Code: 97,
Keysym: int(0xFFB1),
}
var PAD_2 = types.Key{
Name: "PAD_2",
Value: "Num Pad 2",
Code: 98,
Keysym: int(0xFFB2),
}
var PAD_3 = types.Key{
Name: "PAD_3",
Value: "Num Pad 3",
Code: 99,
Keysym: int(0xFFB3),
}
var PAD_4 = types.Key{
Name: "PAD_4",
Value: "Num Pad 4",
Code: 100,
Keysym: int(0xFFB4),
}
var PAD_5 = types.Key{
Name: "PAD_5",
Value: "Num Pad 5",
Code: 101,
Keysym: int(0xFFB5),
}
var PAD_6 = types.Key{
Name: "PAD_6",
Value: "Num Pad 6",
Code: 102,
Keysym: int(0xFFB6),
}
var PAD_7 = types.Key{
Name: "PAD_7",
Value: "Num Pad 7",
Code: 103,
Keysym: int(0xFFB7),
}
var PAD_8 = types.Key{
Name: "PAD_8",
Value: "Num Pad 8",
Code: 104,
Keysym: int(0xFFB8),
}
var PAD_9 = types.Key{
Name: "PAD_9",
Value: "Num Pad 9",
Code: 105,
Keysym: int(0xFFB9),
}
var MULTIPLY = types.Key{
Name: "MULTIPLY",
Value: "*",
Code: 106,
Keysym: int(0xFFAA),
}
var ADD = types.Key{
Name: "ADD",
Value: "+",
Code: 107,
Keysym: int(0xFFAB),
}
var SUBTRACT = types.Key{
Name: "SUBTRACT",
Value: "-",
Code: 109,
Keysym: int(0xFFAD),
}
var DECIMAL = types.Key{
Name: "DECIMAL",
Value: ".",
Code: 110,
Keysym: int(0xFFAE),
}
var DIVIDE = types.Key{
Name: "DIVIDE",
Value: "/",
Code: 111,
Keysym: int(0xFFAF),
}
var KEY_F1 = types.Key{
Name: "KEY_F1",
Value: "f1",
Code: 112,
Keysym: int(0xFFBE),
}
var KEY_F2 = types.Key{
Name: "KEY_F2",
Value: "f2",
Code: 113,
Keysym: int(0xFFBF),
}
var KEY_F3 = types.Key{
Name: "KEY_F3",
Value: "f3",
Code: 114,
Keysym: int(0xFFC0),
}
var KEY_F4 = types.Key{
Name: "KEY_F4",
Value: "f4",
Code: 115,
Keysym: int(0xFFC1),
}
var KEY_F5 = types.Key{
Name: "KEY_F5",
Value: "f5",
Code: 116,
Keysym: int(0xFFC2),
}
var KEY_F6 = types.Key{
Name: "KEY_F6",
Value: "f6",
Code: 117,
Keysym: int(0xFFC3),
}
var KEY_F7 = types.Key{
Name: "KEY_F7",
Value: "f7",
Code: 118,
Keysym: int(0xFFC4),
}
var KEY_F8 = types.Key{
Name: "KEY_F8",
Value: "f8",
Code: 119,
Keysym: int(0xFFC5),
}
var KEY_F9 = types.Key{
Name: "KEY_F9",
Value: "f9",
Code: 120,
Keysym: int(0xFFC6),
}
var KEY_F10 = types.Key{
Name: "KEY_F10",
Value: "f10",
Code: 121,
Keysym: int(0xFFC7),
}
var KEY_F11 = types.Key{
Name: "KEY_F11",
Value: "f11",
Code: 122,
Keysym: int(0xFFC8),
}
var KEY_F12 = types.Key{
Name: "KEY_F12",
Value: "f12",
Code: 123,
Keysym: int(0xFFC9),
}
var NUM_LOCK = types.Key{
Name: "NUM_LOCK",
Value: "Num Lock",
Code: 144,
Keysym: int(0xFF7F),
}
var SCROLL_LOCK = types.Key{
Name: "SCROLL_LOCK",
Value: "Scroll Lock",
Code: 145,
Keysym: int(0xFF14),
}
var SEMI_COLON = types.Key{
Name: "SEMI_COLON",
Value: ";",
Code: 186,
Keysym: int(0x003b),
}
var EQUAL = types.Key{
Name: "EQUAL",
Value: "=",
Code: 187,
Keysym: int(0x003d),
}
var COMMA = types.Key{
Name: "COMMA",
Value: ",",
Code: 188,
Keysym: int(0x002c),
}
var DASH = types.Key{
Name: "DASH",
Value: "-",
Code: 189,
Keysym: int(0x002d),
}
var PERIOD = types.Key{
Name: "PERIOD",
Value: ".",
Code: 190,
Keysym: int(0x002e),
}
var FORWARD_SLASH = types.Key{
Name: "FORWARD_SLASH",
Value: "/",
Code: 191,
Keysym: int(0x002f),
}
var GRAVE = types.Key{
Name: "GRAVE",
Value: "`",
Code: 192,
Keysym: int(0x0060),
}
var OPEN_BRACKET = types.Key{
Name: "OPEN_BRACKET",
Value: "[",
Code: 219,
Keysym: int(0x005b),
}
var BACK_SLASH = types.Key{
Name: "BACK_SLASH",
Value: "\\",
Code: 220,
Keysym: int(0x005c),
}
var CLOSE_BRAKET = types.Key{
Name: "CLOSE_BRAKET",
Value: "]",
Code: 221,
Keysym: int(0x005d),
}
var SINGLE_QUOTE = types.Key{
Name: "SINGLE_QUOTE",
Value: "'",
Code: 222,
Keysym: int(0x0022),
}

View File

@ -89,16 +89,30 @@ void XScroll(int x, int y) {
}
void XButton(unsigned int button, int down) {
Display *display = getXDisplay();
XTestFakeButtonEvent(display, button, down, CurrentTime);
XSync(display, 0);
if (button != 0) {
Display *display = getXDisplay();
XTestFakeButtonEvent(display, button, down, CurrentTime);
XSync(display, 0);
}
}
void XKey(unsigned long key, int down) {
Display *display = getXDisplay();
KeyCode code = XKeysymToKeycode(display, key);
if (key != 0) {
Display *display = getXDisplay();
KeyCode code = XKeysymToKeycode(display, key);
// Map non-existing keysyms to new keycodes
if(code == 0) {
int min, max, numcodes;
XDisplayKeycodes(display, &min, &max);
XGetKeyboardMapping(display, min, max-min, &numcodes);
code = (max-min+1)*numcodes;
KeySym keysym_list[numcodes];
for(int i=0;i<numcodes;i++) keysym_list[i] = key;
XChangeKeyboardMapping(display, code, numcodes, keysym_list, 1);
}
if (code != 0) {
XTestFakeKeyEvent(display, code, down, CurrentTime);
XSync(display, 0);
}
@ -151,3 +165,10 @@ short XGetScreenRate() {
XRRScreenConfiguration *conf = XRRGetScreenInfo(display, RootWindow(display, 0));
return XRRConfigCurrentRate(conf);
}
void SetKeyboardLayout(char *layout) {
// TOOD: refactor, use native API.
char cmd[13] = "setxkbmap ";
strncat(cmd, layout, 2);
system(cmd);
}

View File

@ -1,9 +1,3 @@
// NOTE: I have no fucking clue what I'm doing with this,
// it works, but I am positive I'm doing this very wrong...
// should I be freeing these strings? does go gc them?
// pretty sure this *isn't* thread safe either.... /shrug
// if you know a better way to get this done *please* make a pr <3
package xorg
/*
@ -19,127 +13,18 @@ import (
"sync"
"time"
"unsafe"
"regexp"
"n.eko.moe/neko/internal/types"
"n.eko.moe/neko/internal/xorg/keycode"
)
var ScreenConfigurations = make(map[int]types.ScreenConfiguration)
var debounce = make(map[int]time.Time)
var buttons = make(map[int]types.Button)
var keys = make(map[int]types.Key)
var debounce_button = make(map[int]time.Time)
var debounce_key = make(map[uint64]time.Time)
var mu = sync.Mutex{}
func init() {
keys[keycode.BACKSPACE.Code] = keycode.BACKSPACE
keys[keycode.TAB.Code] = keycode.TAB
keys[keycode.CLEAR.Code] = keycode.CLEAR
keys[keycode.ENTER.Code] = keycode.ENTER
keys[keycode.SHIFT.Code] = keycode.SHIFT
keys[keycode.CTRL.Code] = keycode.CTRL
keys[keycode.ALT.Code] = keycode.ALT
keys[keycode.PAUSE.Code] = keycode.PAUSE
keys[keycode.CAPS_LOCK.Code] = keycode.CAPS_LOCK
keys[keycode.ESCAPE.Code] = keycode.ESCAPE
keys[keycode.SPACE.Code] = keycode.SPACE
keys[keycode.PAGE_UP.Code] = keycode.PAGE_UP
keys[keycode.PAGE_DOWN.Code] = keycode.PAGE_DOWN
keys[keycode.END.Code] = keycode.END
keys[keycode.HOME.Code] = keycode.HOME
keys[keycode.LEFT_ARROW.Code] = keycode.LEFT_ARROW
keys[keycode.UP_ARROW.Code] = keycode.UP_ARROW
keys[keycode.RIGHT_ARROW.Code] = keycode.RIGHT_ARROW
keys[keycode.DOWN_ARROW.Code] = keycode.DOWN_ARROW
keys[keycode.INSERT.Code] = keycode.INSERT
keys[keycode.DELETE.Code] = keycode.DELETE
keys[keycode.KEY_0.Code] = keycode.KEY_0
keys[keycode.KEY_1.Code] = keycode.KEY_1
keys[keycode.KEY_2.Code] = keycode.KEY_2
keys[keycode.KEY_3.Code] = keycode.KEY_3
keys[keycode.KEY_4.Code] = keycode.KEY_4
keys[keycode.KEY_5.Code] = keycode.KEY_5
keys[keycode.KEY_6.Code] = keycode.KEY_6
keys[keycode.KEY_7.Code] = keycode.KEY_7
keys[keycode.KEY_8.Code] = keycode.KEY_8
keys[keycode.KEY_9.Code] = keycode.KEY_9
keys[keycode.KEY_A.Code] = keycode.KEY_A
keys[keycode.KEY_B.Code] = keycode.KEY_B
keys[keycode.KEY_C.Code] = keycode.KEY_C
keys[keycode.KEY_D.Code] = keycode.KEY_D
keys[keycode.KEY_E.Code] = keycode.KEY_E
keys[keycode.KEY_F.Code] = keycode.KEY_F
keys[keycode.KEY_G.Code] = keycode.KEY_G
keys[keycode.KEY_H.Code] = keycode.KEY_H
keys[keycode.KEY_I.Code] = keycode.KEY_I
keys[keycode.KEY_J.Code] = keycode.KEY_J
keys[keycode.KEY_K.Code] = keycode.KEY_K
keys[keycode.KEY_L.Code] = keycode.KEY_L
keys[keycode.KEY_M.Code] = keycode.KEY_M
keys[keycode.KEY_N.Code] = keycode.KEY_N
keys[keycode.KEY_O.Code] = keycode.KEY_O
keys[keycode.KEY_P.Code] = keycode.KEY_P
keys[keycode.KEY_Q.Code] = keycode.KEY_Q
keys[keycode.KEY_R.Code] = keycode.KEY_R
keys[keycode.KEY_S.Code] = keycode.KEY_S
keys[keycode.KEY_T.Code] = keycode.KEY_T
keys[keycode.KEY_U.Code] = keycode.KEY_U
keys[keycode.KEY_V.Code] = keycode.KEY_V
keys[keycode.KEY_W.Code] = keycode.KEY_W
keys[keycode.KEY_X.Code] = keycode.KEY_X
keys[keycode.KEY_Y.Code] = keycode.KEY_Y
keys[keycode.KEY_Z.Code] = keycode.KEY_Z
keys[keycode.WIN_LEFT.Code] = keycode.WIN_LEFT
keys[keycode.WIN_RIGHT.Code] = keycode.WIN_RIGHT
keys[keycode.PAD_0.Code] = keycode.PAD_0
keys[keycode.PAD_1.Code] = keycode.PAD_1
keys[keycode.PAD_2.Code] = keycode.PAD_2
keys[keycode.PAD_3.Code] = keycode.PAD_3
keys[keycode.PAD_4.Code] = keycode.PAD_4
keys[keycode.PAD_5.Code] = keycode.PAD_5
keys[keycode.PAD_6.Code] = keycode.PAD_6
keys[keycode.PAD_7.Code] = keycode.PAD_7
keys[keycode.PAD_8.Code] = keycode.PAD_8
keys[keycode.PAD_9.Code] = keycode.PAD_9
keys[keycode.MULTIPLY.Code] = keycode.MULTIPLY
keys[keycode.ADD.Code] = keycode.ADD
keys[keycode.SUBTRACT.Code] = keycode.SUBTRACT
keys[keycode.DECIMAL.Code] = keycode.DECIMAL
keys[keycode.DIVIDE.Code] = keycode.DIVIDE
keys[keycode.KEY_F1.Code] = keycode.KEY_F1
keys[keycode.KEY_F2.Code] = keycode.KEY_F2
keys[keycode.KEY_F3.Code] = keycode.KEY_F3
keys[keycode.KEY_F4.Code] = keycode.KEY_F4
keys[keycode.KEY_F5.Code] = keycode.KEY_F5
keys[keycode.KEY_F6.Code] = keycode.KEY_F6
keys[keycode.KEY_F7.Code] = keycode.KEY_F7
keys[keycode.KEY_F8.Code] = keycode.KEY_F8
keys[keycode.KEY_F9.Code] = keycode.KEY_F9
keys[keycode.KEY_F10.Code] = keycode.KEY_F10
keys[keycode.KEY_F11.Code] = keycode.KEY_F11
keys[keycode.KEY_F12.Code] = keycode.KEY_F12
keys[keycode.NUM_LOCK.Code] = keycode.NUM_LOCK
keys[keycode.SCROLL_LOCK.Code] = keycode.SCROLL_LOCK
keys[keycode.SEMI_COLON.Code] = keycode.SEMI_COLON
keys[keycode.EQUAL.Code] = keycode.EQUAL
keys[keycode.COMMA.Code] = keycode.COMMA
keys[keycode.DASH.Code] = keycode.DASH
keys[keycode.PERIOD.Code] = keycode.PERIOD
keys[keycode.FORWARD_SLASH.Code] = keycode.FORWARD_SLASH
keys[keycode.GRAVE.Code] = keycode.GRAVE
keys[keycode.OPEN_BRACKET.Code] = keycode.OPEN_BRACKET
keys[keycode.BACK_SLASH.Code] = keycode.BACK_SLASH
keys[keycode.CLOSE_BRAKET.Code] = keycode.CLOSE_BRAKET
keys[keycode.SINGLE_QUOTE.Code] = keycode.SINGLE_QUOTE
buttons[keycode.LEFT_BUTTON.Code] = keycode.LEFT_BUTTON
buttons[keycode.CENTER_BUTTON.Code] = keycode.CENTER_BUTTON
buttons[keycode.RIGHT_BUTTON.Code] = keycode.RIGHT_BUTTON
buttons[keycode.SCROLL_UP_BUTTON.Code] = keycode.SCROLL_UP_BUTTON
buttons[keycode.SCROLL_DOWN_BUTTON.Code] = keycode.SCROLL_DOWN_BUTTON
buttons[keycode.SCROLL_LEFT_BUTTON.Code] = keycode.SCROLL_LEFT_BUTTON
buttons[keycode.SCROLL_RIGHT_BUTTON.Code] = keycode.SCROLL_RIGHT_BUTTON
C.XGetScreenConfigurations()
}
@ -167,80 +52,60 @@ func Scroll(x, y int) {
C.XScroll(C.int(x), C.int(y))
}
func ButtonDown(code int) (*types.Button, error) {
func ButtonDown(code int) error {
mu.Lock()
defer mu.Unlock()
button, ok := buttons[code]
if !ok {
return nil, fmt.Errorf("invalid button %v", code)
if _, ok := debounce_button[code]; ok {
return fmt.Errorf("debounced button %v", code)
}
if _, ok := debounce[code]; ok {
return nil, fmt.Errorf("debounced button %v(%v)", button.Name, code)
}
debounce_button[code] = time.Now()
debounce[code] = time.Now()
C.XButton(C.uint(button.Keysym), C.int(1))
return &button, nil
C.XButton(C.uint(code), C.int(1))
return nil
}
func KeyDown(code int) (*types.Key, error) {
func KeyDown(code uint64) error {
mu.Lock()
defer mu.Unlock()
key, ok := keys[code]
if !ok {
return nil, fmt.Errorf("invalid key %v", code)
if _, ok := debounce_key[code]; ok {
return fmt.Errorf("debounced key %v", code)
}
if _, ok := debounce[code]; ok {
return nil, fmt.Errorf("debounced key %v(%v)", key.Name, code)
}
debounce_key[code] = time.Now()
debounce[code] = time.Now()
C.XKey(C.ulong(key.Keysym), C.int(1))
return &key, nil
C.XKey(C.ulong(code), C.int(1))
return nil
}
func ButtonUp(code int) (*types.Button, error) {
func ButtonUp(code int) error {
mu.Lock()
defer mu.Unlock()
button, ok := buttons[code]
if !ok {
return nil, fmt.Errorf("invalid button %v", code)
if _, ok := debounce_button[code]; !ok {
return fmt.Errorf("debounced button %v", code)
}
if _, ok := debounce[code]; !ok {
return nil, fmt.Errorf("debounced button %v(%v)", button.Name, code)
}
delete(debounce_button, code)
delete(debounce, code)
C.XButton(C.uint(button.Keysym), C.int(0))
return &button, nil
C.XButton(C.uint(code), C.int(0))
return nil
}
func KeyUp(code int) (*types.Key, error) {
func KeyUp(code uint64) error {
mu.Lock()
defer mu.Unlock()
key, ok := keys[code]
if !ok {
return nil, fmt.Errorf("invalid key %v", code)
if _, ok := debounce_key[code]; !ok {
return fmt.Errorf("debounced key %v", code)
}
if _, ok := debounce[code]; !ok {
return nil, fmt.Errorf("debounced key %v(%v)", key.Name, code)
}
delete(debounce_key, code)
delete(debounce, code)
C.XKey(C.ulong(key.Keysym), C.int(0))
return &key, nil
C.XKey(C.ulong(code), C.int(0))
return nil
}
func ReadClipboard() string {
@ -264,31 +129,35 @@ func WriteClipboard(data string) {
}
func ResetKeys() {
for key := range debounce {
if key < 8 {
ButtonUp(key)
} else {
KeyUp(key)
}
for code := range debounce_button {
ButtonUp(code)
delete(debounce, key)
delete(debounce_button, code)
}
for code := range debounce_key {
KeyUp(code)
delete(debounce_key, code)
}
}
func CheckKeys(duration time.Duration) {
t := time.Now()
for key, start := range debounce {
for code, start := range debounce_button {
if t.Sub(start) < duration {
continue
}
ButtonUp(code)
if key < 8 {
ButtonUp(key)
} else {
KeyUp(key)
delete(debounce_button, code)
}
for code, start := range debounce_key {
if t.Sub(start) < duration {
continue
}
KeyUp(code)
delete(debounce, key)
delete(debounce_key, code)
}
}
@ -342,6 +211,20 @@ func GetScreenSize() *types.ScreenSize {
return nil
}
func SetKeyboardLayout(layout string) {
mu.Lock()
defer mu.Unlock()
if !regexp.MustCompile(`^[a-zA-Z]+$`).MatchString(layout) {
return
}
layoutUnsafe := C.CString(layout)
defer C.free(unsafe.Pointer(layoutUnsafe))
C.SetKeyboardLayout(layoutUnsafe)
}
//export goCreateScreenSize
func goCreateScreenSize(index C.int, width C.int, height C.int, mwidth C.int, mheight C.int) {
ScreenConfigurations[int(index)] = types.ScreenConfiguration{

View File

@ -38,5 +38,7 @@
void XDisplayClose(void);
void XDisplaySet(char *input);
void SetKeyboardLayout(char *layout);
#endif