chore(v2): vendor dependencies for offline/China builds
go mod vendor pins onnxruntime_go v1.12.1, Gio and the rest into v2/vendor so go run/build work without hitting proxy.golang.org (blocked/slow in China). Verified: CGO_ENABLED=1 go build -mod=vendor ./internal/spike and GOOS=windows go build -mod=vendor ./internal/ui both pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+375
@@ -0,0 +1,375 @@
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
//go:build (linux && !android) || freebsd || openbsd
|
||||
// +build linux,!android freebsd openbsd
|
||||
|
||||
// Package xkb implements a Go interface for the X Keyboard Extension library.
|
||||
package xkb
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
"unsafe"
|
||||
|
||||
"gioui.org/io/event"
|
||||
"gioui.org/io/key"
|
||||
)
|
||||
|
||||
/*
|
||||
#cgo linux pkg-config: xkbcommon
|
||||
#cgo freebsd openbsd CFLAGS: -I/usr/local/include
|
||||
#cgo freebsd openbsd LDFLAGS: -L/usr/local/lib -lxkbcommon
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <xkbcommon/xkbcommon-compose.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
type Context struct {
|
||||
Ctx *C.struct_xkb_context
|
||||
keyMap *C.struct_xkb_keymap
|
||||
state *C.struct_xkb_state
|
||||
compTable *C.struct_xkb_compose_table
|
||||
compState *C.struct_xkb_compose_state
|
||||
utf8Buf []byte
|
||||
}
|
||||
|
||||
var (
|
||||
_XKB_MOD_NAME_CTRL = []byte("Control\x00")
|
||||
_XKB_MOD_NAME_SHIFT = []byte("Shift\x00")
|
||||
_XKB_MOD_NAME_ALT = []byte("Mod1\x00")
|
||||
_XKB_MOD_NAME_LOGO = []byte("Mod4\x00")
|
||||
)
|
||||
|
||||
func (x *Context) Destroy() {
|
||||
if x.compState != nil {
|
||||
C.xkb_compose_state_unref(x.compState)
|
||||
x.compState = nil
|
||||
}
|
||||
if x.compTable != nil {
|
||||
C.xkb_compose_table_unref(x.compTable)
|
||||
x.compTable = nil
|
||||
}
|
||||
x.DestroyKeymapState()
|
||||
if x.Ctx != nil {
|
||||
C.xkb_context_unref(x.Ctx)
|
||||
x.Ctx = nil
|
||||
}
|
||||
}
|
||||
|
||||
func New() (*Context, error) {
|
||||
ctx := &Context{
|
||||
Ctx: C.xkb_context_new(C.XKB_CONTEXT_NO_FLAGS),
|
||||
}
|
||||
if ctx.Ctx == nil {
|
||||
return nil, errors.New("newXKB: xkb_context_new failed")
|
||||
}
|
||||
locale := os.Getenv("LC_ALL")
|
||||
if locale == "" {
|
||||
locale = os.Getenv("LC_CTYPE")
|
||||
}
|
||||
if locale == "" {
|
||||
locale = os.Getenv("LANG")
|
||||
}
|
||||
if locale == "" {
|
||||
locale = "C"
|
||||
}
|
||||
cloc := C.CString(locale)
|
||||
defer C.free(unsafe.Pointer(cloc))
|
||||
ctx.compTable = C.xkb_compose_table_new_from_locale(ctx.Ctx, cloc, C.XKB_COMPOSE_COMPILE_NO_FLAGS)
|
||||
if ctx.compTable == nil {
|
||||
ctx.Destroy()
|
||||
return nil, errors.New("newXKB: xkb_compose_table_new_from_locale failed")
|
||||
}
|
||||
ctx.compState = C.xkb_compose_state_new(ctx.compTable, C.XKB_COMPOSE_STATE_NO_FLAGS)
|
||||
if ctx.compState == nil {
|
||||
ctx.Destroy()
|
||||
return nil, errors.New("newXKB: xkb_compose_state_new failed")
|
||||
}
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
func (x *Context) DestroyKeymapState() {
|
||||
if x.state != nil {
|
||||
C.xkb_state_unref(x.state)
|
||||
x.state = nil
|
||||
}
|
||||
if x.keyMap != nil {
|
||||
C.xkb_keymap_unref(x.keyMap)
|
||||
x.keyMap = nil
|
||||
}
|
||||
}
|
||||
|
||||
// SetKeymap sets the keymap and state. The context takes ownership of the
|
||||
// keymap and state and frees them in Destroy.
|
||||
func (x *Context) SetKeymap(xkbKeyMap, xkbState unsafe.Pointer) {
|
||||
x.DestroyKeymapState()
|
||||
x.keyMap = (*C.struct_xkb_keymap)(xkbKeyMap)
|
||||
x.state = (*C.struct_xkb_state)(xkbState)
|
||||
}
|
||||
|
||||
func (x *Context) LoadKeymap(format int, fd int, size int) error {
|
||||
x.DestroyKeymapState()
|
||||
mapData, err := syscall.Mmap(int(fd), 0, int(size), syscall.PROT_READ, syscall.MAP_SHARED)
|
||||
if err != nil {
|
||||
return fmt.Errorf("newXKB: mmap of keymap failed: %v", err)
|
||||
}
|
||||
defer syscall.Munmap(mapData)
|
||||
keyMap := C.xkb_keymap_new_from_buffer(x.Ctx, (*C.char)(unsafe.Pointer(&mapData[0])), C.size_t(size-1), C.XKB_KEYMAP_FORMAT_TEXT_V1, C.XKB_KEYMAP_COMPILE_NO_FLAGS)
|
||||
if keyMap == nil {
|
||||
return errors.New("newXKB: xkb_keymap_new_from_buffer failed")
|
||||
}
|
||||
state := C.xkb_state_new(keyMap)
|
||||
if state == nil {
|
||||
C.xkb_keymap_unref(keyMap)
|
||||
return errors.New("newXKB: xkb_state_new failed")
|
||||
}
|
||||
x.keyMap = keyMap
|
||||
x.state = state
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Context) Modifiers() key.Modifiers {
|
||||
var mods key.Modifiers
|
||||
if x.state == nil {
|
||||
return mods
|
||||
}
|
||||
|
||||
if C.xkb_state_mod_name_is_active(x.state, (*C.char)(unsafe.Pointer(&_XKB_MOD_NAME_CTRL[0])), C.XKB_STATE_MODS_EFFECTIVE) == 1 {
|
||||
mods |= key.ModCtrl
|
||||
}
|
||||
if C.xkb_state_mod_name_is_active(x.state, (*C.char)(unsafe.Pointer(&_XKB_MOD_NAME_SHIFT[0])), C.XKB_STATE_MODS_EFFECTIVE) == 1 {
|
||||
mods |= key.ModShift
|
||||
}
|
||||
if C.xkb_state_mod_name_is_active(x.state, (*C.char)(unsafe.Pointer(&_XKB_MOD_NAME_ALT[0])), C.XKB_STATE_MODS_EFFECTIVE) == 1 {
|
||||
mods |= key.ModAlt
|
||||
}
|
||||
if C.xkb_state_mod_name_is_active(x.state, (*C.char)(unsafe.Pointer(&_XKB_MOD_NAME_LOGO[0])), C.XKB_STATE_MODS_EFFECTIVE) == 1 {
|
||||
mods |= key.ModSuper
|
||||
}
|
||||
return mods
|
||||
}
|
||||
|
||||
func (x *Context) DispatchKey(keyCode uint32, state key.State) (events []event.Event) {
|
||||
if x.state == nil {
|
||||
return
|
||||
}
|
||||
kc := C.xkb_keycode_t(keyCode)
|
||||
if len(x.utf8Buf) == 0 {
|
||||
x.utf8Buf = make([]byte, 1)
|
||||
}
|
||||
sym := C.xkb_state_key_get_one_sym(x.state, kc)
|
||||
if name, ok := convertKeysym(sym); ok {
|
||||
cmd := key.Event{
|
||||
Name: name,
|
||||
Modifiers: x.Modifiers(),
|
||||
State: state,
|
||||
}
|
||||
// Ensure that a physical backtab key is translated to
|
||||
// Shift-Tab.
|
||||
if sym == C.XKB_KEY_ISO_Left_Tab {
|
||||
cmd.Modifiers |= key.ModShift
|
||||
}
|
||||
events = append(events, cmd)
|
||||
}
|
||||
C.xkb_compose_state_feed(x.compState, sym)
|
||||
var str []byte
|
||||
switch C.xkb_compose_state_get_status(x.compState) {
|
||||
case C.XKB_COMPOSE_CANCELLED, C.XKB_COMPOSE_COMPOSING:
|
||||
return
|
||||
case C.XKB_COMPOSE_COMPOSED:
|
||||
size := C.xkb_compose_state_get_utf8(x.compState, (*C.char)(unsafe.Pointer(&x.utf8Buf[0])), C.size_t(len(x.utf8Buf)))
|
||||
if int(size) >= len(x.utf8Buf) {
|
||||
x.utf8Buf = make([]byte, size+1)
|
||||
size = C.xkb_compose_state_get_utf8(x.compState, (*C.char)(unsafe.Pointer(&x.utf8Buf[0])), C.size_t(len(x.utf8Buf)))
|
||||
}
|
||||
C.xkb_compose_state_reset(x.compState)
|
||||
str = x.utf8Buf[:size]
|
||||
case C.XKB_COMPOSE_NOTHING:
|
||||
mod := x.Modifiers()
|
||||
if mod&(key.ModCtrl|key.ModAlt|key.ModSuper) == 0 {
|
||||
str = x.charsForKeycode(kc)
|
||||
}
|
||||
}
|
||||
// Report only printable runes.
|
||||
var n int
|
||||
for n < len(str) {
|
||||
r, s := utf8.DecodeRune(str)
|
||||
if unicode.IsPrint(r) {
|
||||
n += s
|
||||
} else {
|
||||
copy(str[n:], str[n+s:])
|
||||
str = str[:len(str)-s]
|
||||
}
|
||||
}
|
||||
if state == key.Press && len(str) > 0 {
|
||||
events = append(events, key.EditEvent{Text: string(str)})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (x *Context) charsForKeycode(keyCode C.xkb_keycode_t) []byte {
|
||||
size := C.xkb_state_key_get_utf8(x.state, keyCode, (*C.char)(unsafe.Pointer(&x.utf8Buf[0])), C.size_t(len(x.utf8Buf)))
|
||||
if int(size) >= len(x.utf8Buf) {
|
||||
x.utf8Buf = make([]byte, size+1)
|
||||
size = C.xkb_state_key_get_utf8(x.state, keyCode, (*C.char)(unsafe.Pointer(&x.utf8Buf[0])), C.size_t(len(x.utf8Buf)))
|
||||
}
|
||||
return x.utf8Buf[:size]
|
||||
}
|
||||
|
||||
func (x *Context) IsRepeatKey(keyCode uint32) bool {
|
||||
if x.state == nil {
|
||||
return false
|
||||
}
|
||||
kc := C.xkb_keycode_t(keyCode)
|
||||
return C.xkb_keymap_key_repeats(x.keyMap, kc) == 1
|
||||
}
|
||||
|
||||
func (x *Context) UpdateMask(depressed, latched, locked, depressedGroup, latchedGroup, lockedGroup uint32) {
|
||||
if x.state == nil {
|
||||
return
|
||||
}
|
||||
C.xkb_state_update_mask(x.state, C.xkb_mod_mask_t(depressed), C.xkb_mod_mask_t(latched), C.xkb_mod_mask_t(locked),
|
||||
C.xkb_layout_index_t(depressedGroup), C.xkb_layout_index_t(latchedGroup), C.xkb_layout_index_t(lockedGroup))
|
||||
}
|
||||
|
||||
func convertKeysym(s C.xkb_keysym_t) (key.Name, bool) {
|
||||
if 'a' <= s && s <= 'z' {
|
||||
return key.Name(rune(s - 'a' + 'A')), true
|
||||
}
|
||||
if C.XKB_KEY_KP_0 <= s && s <= C.XKB_KEY_KP_9 {
|
||||
return key.Name(rune(s - C.XKB_KEY_KP_0 + '0')), true
|
||||
}
|
||||
if ' ' < s && s <= '~' {
|
||||
return key.Name(rune(s)), true
|
||||
}
|
||||
var n key.Name
|
||||
switch s {
|
||||
case C.XKB_KEY_Escape:
|
||||
n = key.NameEscape
|
||||
case C.XKB_KEY_Left:
|
||||
n = key.NameLeftArrow
|
||||
case C.XKB_KEY_Right:
|
||||
n = key.NameRightArrow
|
||||
case C.XKB_KEY_Return:
|
||||
n = key.NameReturn
|
||||
case C.XKB_KEY_Up:
|
||||
n = key.NameUpArrow
|
||||
case C.XKB_KEY_Down:
|
||||
n = key.NameDownArrow
|
||||
case C.XKB_KEY_Home:
|
||||
n = key.NameHome
|
||||
case C.XKB_KEY_End:
|
||||
n = key.NameEnd
|
||||
case C.XKB_KEY_BackSpace:
|
||||
n = key.NameDeleteBackward
|
||||
case C.XKB_KEY_Delete:
|
||||
n = key.NameDeleteForward
|
||||
case C.XKB_KEY_Page_Up:
|
||||
n = key.NamePageUp
|
||||
case C.XKB_KEY_Page_Down:
|
||||
n = key.NamePageDown
|
||||
case C.XKB_KEY_F1:
|
||||
n = key.NameF1
|
||||
case C.XKB_KEY_F2:
|
||||
n = key.NameF2
|
||||
case C.XKB_KEY_F3:
|
||||
n = key.NameF3
|
||||
case C.XKB_KEY_F4:
|
||||
n = key.NameF4
|
||||
case C.XKB_KEY_F5:
|
||||
n = key.NameF5
|
||||
case C.XKB_KEY_F6:
|
||||
n = key.NameF6
|
||||
case C.XKB_KEY_F7:
|
||||
n = key.NameF7
|
||||
case C.XKB_KEY_F8:
|
||||
n = key.NameF8
|
||||
case C.XKB_KEY_F9:
|
||||
n = key.NameF9
|
||||
case C.XKB_KEY_F10:
|
||||
n = key.NameF10
|
||||
case C.XKB_KEY_F11:
|
||||
n = key.NameF11
|
||||
case C.XKB_KEY_F12:
|
||||
n = key.NameF12
|
||||
case C.XKB_KEY_Tab, C.XKB_KEY_ISO_Left_Tab:
|
||||
n = key.NameTab
|
||||
case 0x20:
|
||||
n = key.NameSpace
|
||||
case C.XKB_KEY_Control_L, C.XKB_KEY_Control_R:
|
||||
n = key.NameCtrl
|
||||
case C.XKB_KEY_Shift_L, C.XKB_KEY_Shift_R:
|
||||
n = key.NameShift
|
||||
case C.XKB_KEY_Alt_L, C.XKB_KEY_Alt_R:
|
||||
n = key.NameAlt
|
||||
case C.XKB_KEY_Super_L, C.XKB_KEY_Super_R:
|
||||
n = key.NameSuper
|
||||
|
||||
case C.XKB_KEY_KP_Space:
|
||||
n = key.NameSpace
|
||||
case C.XKB_KEY_KP_Tab:
|
||||
n = key.NameTab
|
||||
case C.XKB_KEY_KP_Enter:
|
||||
n = key.NameEnter
|
||||
case C.XKB_KEY_KP_F1:
|
||||
n = key.NameF1
|
||||
case C.XKB_KEY_KP_F2:
|
||||
n = key.NameF2
|
||||
case C.XKB_KEY_KP_F3:
|
||||
n = key.NameF3
|
||||
case C.XKB_KEY_KP_F4:
|
||||
n = key.NameF4
|
||||
case C.XKB_KEY_KP_Home:
|
||||
n = key.NameHome
|
||||
case C.XKB_KEY_KP_Left:
|
||||
n = key.NameLeftArrow
|
||||
case C.XKB_KEY_KP_Up:
|
||||
n = key.NameUpArrow
|
||||
case C.XKB_KEY_KP_Right:
|
||||
n = key.NameRightArrow
|
||||
case C.XKB_KEY_KP_Down:
|
||||
n = key.NameDownArrow
|
||||
case C.XKB_KEY_KP_Prior:
|
||||
// not supported
|
||||
return "", false
|
||||
case C.XKB_KEY_KP_Next:
|
||||
// not supported
|
||||
return "", false
|
||||
case C.XKB_KEY_KP_End:
|
||||
n = key.NameEnd
|
||||
case C.XKB_KEY_KP_Begin:
|
||||
n = key.NameHome
|
||||
case C.XKB_KEY_KP_Insert:
|
||||
// not supported
|
||||
return "", false
|
||||
case C.XKB_KEY_KP_Delete:
|
||||
n = key.NameDeleteForward
|
||||
case C.XKB_KEY_KP_Multiply:
|
||||
n = "*"
|
||||
case C.XKB_KEY_KP_Add:
|
||||
n = "+"
|
||||
case C.XKB_KEY_KP_Separator:
|
||||
// not supported
|
||||
return "", false
|
||||
case C.XKB_KEY_KP_Subtract:
|
||||
n = "-"
|
||||
case C.XKB_KEY_KP_Decimal:
|
||||
// TODO(dh): does a German keyboard layout also translate the numpad key to XKB_KEY_KP_DECIMAL? Because in
|
||||
// German, the decimal is a comma, not a period.
|
||||
n = "."
|
||||
case C.XKB_KEY_KP_Divide:
|
||||
n = "/"
|
||||
case C.XKB_KEY_KP_Equal:
|
||||
n = "="
|
||||
|
||||
default:
|
||||
return "", false
|
||||
}
|
||||
return n, true
|
||||
}
|
||||
Reference in New Issue
Block a user