mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-04 00:45:35 +00:00
app/internal/xkb: extra XKB interface to internal package
Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
@@ -2,7 +2,10 @@
|
|||||||
|
|
||||||
// +build !android
|
// +build !android
|
||||||
|
|
||||||
package app
|
// Package xkb implements a Go interface for the X Keyboard Extension library.
|
||||||
|
package xkb
|
||||||
|
|
||||||
|
import "gioui.org/io/event"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#cgo LDFLAGS: -lxkbcommon
|
#cgo LDFLAGS: -lxkbcommon
|
||||||
@@ -25,7 +28,7 @@ import (
|
|||||||
"gioui.org/io/key"
|
"gioui.org/io/key"
|
||||||
)
|
)
|
||||||
|
|
||||||
type xkb struct {
|
type Context struct {
|
||||||
ctx *C.struct_xkb_context
|
ctx *C.struct_xkb_context
|
||||||
keyMap *C.struct_xkb_keymap
|
keyMap *C.struct_xkb_keymap
|
||||||
state *C.struct_xkb_state
|
state *C.struct_xkb_state
|
||||||
@@ -39,7 +42,7 @@ var (
|
|||||||
_XKB_MOD_NAME_SHIFT = []byte("Shift\x00")
|
_XKB_MOD_NAME_SHIFT = []byte("Shift\x00")
|
||||||
)
|
)
|
||||||
|
|
||||||
func (x *xkb) Destroy() {
|
func (x *Context) Destroy() {
|
||||||
if x.state != nil {
|
if x.state != nil {
|
||||||
C.xkb_compose_state_unref(x.compState)
|
C.xkb_compose_state_unref(x.compState)
|
||||||
x.compState = nil
|
x.compState = nil
|
||||||
@@ -62,11 +65,11 @@ func (x *xkb) Destroy() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newXKB(format C.uint32_t, fd C.int32_t, size C.uint32_t) (*xkb, error) {
|
func New(format int, fd int, size int) (*Context, error) {
|
||||||
xkb := &xkb{
|
ctx := &Context{
|
||||||
ctx: C.xkb_context_new(C.XKB_CONTEXT_NO_FLAGS),
|
ctx: C.xkb_context_new(C.XKB_CONTEXT_NO_FLAGS),
|
||||||
}
|
}
|
||||||
if xkb.ctx == nil {
|
if ctx.ctx == nil {
|
||||||
return nil, errors.New("newXKB: xkb_context_new failed")
|
return nil, errors.New("newXKB: xkb_context_new failed")
|
||||||
}
|
}
|
||||||
locale := os.Getenv("LC_ALL")
|
locale := os.Getenv("LC_ALL")
|
||||||
@@ -81,36 +84,36 @@ func newXKB(format C.uint32_t, fd C.int32_t, size C.uint32_t) (*xkb, error) {
|
|||||||
}
|
}
|
||||||
cloc := C.CString(locale)
|
cloc := C.CString(locale)
|
||||||
defer C.free(unsafe.Pointer(cloc))
|
defer C.free(unsafe.Pointer(cloc))
|
||||||
xkb.compTable = C.xkb_compose_table_new_from_locale(xkb.ctx, cloc, C.XKB_COMPOSE_COMPILE_NO_FLAGS)
|
ctx.compTable = C.xkb_compose_table_new_from_locale(ctx.ctx, cloc, C.XKB_COMPOSE_COMPILE_NO_FLAGS)
|
||||||
if xkb.compTable == nil {
|
if ctx.compTable == nil {
|
||||||
xkb.Destroy()
|
ctx.Destroy()
|
||||||
return nil, errors.New("newXKB: xkb_compose_table_new_from_locale failed")
|
return nil, errors.New("newXKB: xkb_compose_table_new_from_locale failed")
|
||||||
}
|
}
|
||||||
xkb.compState = C.xkb_compose_state_new(xkb.compTable, C.XKB_COMPOSE_STATE_NO_FLAGS)
|
ctx.compState = C.xkb_compose_state_new(ctx.compTable, C.XKB_COMPOSE_STATE_NO_FLAGS)
|
||||||
if xkb.compState == nil {
|
if ctx.compState == nil {
|
||||||
xkb.Destroy()
|
ctx.Destroy()
|
||||||
return nil, errors.New("newXKB: xkb_compose_state_new failed")
|
return nil, errors.New("newXKB: xkb_compose_state_new failed")
|
||||||
}
|
}
|
||||||
mapData, err := syscall.Mmap(int(fd), 0, int(size), syscall.PROT_READ, syscall.MAP_SHARED)
|
mapData, err := syscall.Mmap(int(fd), 0, int(size), syscall.PROT_READ, syscall.MAP_SHARED)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
xkb.Destroy()
|
ctx.Destroy()
|
||||||
return nil, fmt.Errorf("newXKB: mmap of keymap failed: %v", err)
|
return nil, fmt.Errorf("newXKB: mmap of keymap failed: %v", err)
|
||||||
}
|
}
|
||||||
defer syscall.Munmap(mapData)
|
defer syscall.Munmap(mapData)
|
||||||
xkb.keyMap = C.xkb_keymap_new_from_buffer(xkb.ctx, (*C.char)(unsafe.Pointer(&mapData[0])), C.size_t(size-1), C.XKB_KEYMAP_FORMAT_TEXT_V1, C.XKB_KEYMAP_COMPILE_NO_FLAGS)
|
ctx.keyMap = C.xkb_keymap_new_from_buffer(ctx.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 xkb.keyMap == nil {
|
if ctx.keyMap == nil {
|
||||||
xkb.Destroy()
|
ctx.Destroy()
|
||||||
return nil, errors.New("newXKB: xkb_keymap_new_from_buffer failed")
|
return nil, errors.New("newXKB: xkb_keymap_new_from_buffer failed")
|
||||||
}
|
}
|
||||||
xkb.state = C.xkb_state_new(xkb.keyMap)
|
ctx.state = C.xkb_state_new(ctx.keyMap)
|
||||||
if xkb.state == nil {
|
if ctx.state == nil {
|
||||||
xkb.Destroy()
|
ctx.Destroy()
|
||||||
return nil, errors.New("newXKB: xkb_state_new failed")
|
return nil, errors.New("newXKB: xkb_state_new failed")
|
||||||
}
|
}
|
||||||
return xkb, nil
|
return ctx, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *xkb) dispatchKey(w *Window, keyCode C.uint32_t) {
|
func (x *Context) DispatchKey(keyCode uint32) (events []event.Event) {
|
||||||
keyCode = mapXKBKeyCode(keyCode)
|
keyCode = mapXKBKeyCode(keyCode)
|
||||||
if len(x.utf8Buf) == 0 {
|
if len(x.utf8Buf) == 0 {
|
||||||
x.utf8Buf = make([]byte, 1)
|
x.utf8Buf = make([]byte, 1)
|
||||||
@@ -124,7 +127,7 @@ func (x *xkb) dispatchKey(w *Window, keyCode C.uint32_t) {
|
|||||||
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 {
|
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 {
|
||||||
cmd.Modifiers |= key.ModShift
|
cmd.Modifiers |= key.ModShift
|
||||||
}
|
}
|
||||||
w.event(cmd)
|
events = append(events, cmd)
|
||||||
}
|
}
|
||||||
C.xkb_compose_state_feed(x.compState, sym)
|
C.xkb_compose_state_feed(x.compState, sym)
|
||||||
var size C.int
|
var size C.int
|
||||||
@@ -158,21 +161,22 @@ func (x *xkb) dispatchKey(w *Window, keyCode C.uint32_t) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(str) > 0 {
|
if len(str) > 0 {
|
||||||
w.event(key.EditEvent{Text: string(str)})
|
events = append(events, key.EditEvent{Text: string(str)})
|
||||||
}
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *xkb) isRepeatKey(keyCode C.uint32_t) bool {
|
func (x *Context) IsRepeatKey(keyCode uint32) bool {
|
||||||
keyCode = mapXKBKeyCode(keyCode)
|
keyCode = mapXKBKeyCode(keyCode)
|
||||||
return C.xkb_keymap_key_repeats(x.keyMap, C.xkb_keycode_t(keyCode)) == 1
|
return C.xkb_keymap_key_repeats(x.keyMap, C.xkb_keycode_t(keyCode)) == 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *xkb) updateMask(depressed, latched, locked, group C.uint32_t) {
|
func (x *Context) UpdateMask(depressed, latched, locked, group uint32) {
|
||||||
xkbGrp := C.xkb_layout_index_t(group)
|
xkbGrp := C.xkb_layout_index_t(group)
|
||||||
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), xkbGrp, xkbGrp, xkbGrp)
|
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), xkbGrp, xkbGrp, xkbGrp)
|
||||||
}
|
}
|
||||||
|
|
||||||
func mapXKBKeyCode(keyCode C.uint32_t) C.uint32_t {
|
func mapXKBKeyCode(keyCode uint32) uint32 {
|
||||||
// According to the xkb_v1 spec: "to determine the xkb keycode, clients must add 8 to the key event keycode."
|
// According to the xkb_v1 spec: "to determine the xkb keycode, clients must add 8 to the key event keycode."
|
||||||
return keyCode + 8
|
return keyCode + 8
|
||||||
}
|
}
|
||||||
+15
-9
@@ -16,6 +16,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"gioui.org/app/internal/xkb"
|
||||||
"gioui.org/f32"
|
"gioui.org/f32"
|
||||||
"gioui.org/internal/fling"
|
"gioui.org/internal/fling"
|
||||||
"gioui.org/io/key"
|
"gioui.org/io/key"
|
||||||
@@ -68,7 +69,7 @@ type wlConn struct {
|
|||||||
pointer *C.struct_wl_pointer
|
pointer *C.struct_wl_pointer
|
||||||
touch *C.struct_wl_touch
|
touch *C.struct_wl_touch
|
||||||
keyboard *C.struct_wl_keyboard
|
keyboard *C.struct_wl_keyboard
|
||||||
xkb *xkb
|
xkb *xkb.Context
|
||||||
|
|
||||||
repeat repeatState
|
repeat repeatState
|
||||||
}
|
}
|
||||||
@@ -77,7 +78,7 @@ type repeatState struct {
|
|||||||
rate int
|
rate int
|
||||||
delay time.Duration
|
delay time.Duration
|
||||||
|
|
||||||
key C.uint32_t
|
key uint32
|
||||||
win *Window
|
win *Window
|
||||||
stopC chan struct{}
|
stopC chan struct{}
|
||||||
|
|
||||||
@@ -630,7 +631,7 @@ func gio_onKeyboardKeymap(data unsafe.Pointer, keyboard *C.struct_wl_keyboard, f
|
|||||||
if format != C.WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 {
|
if format != C.WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
xkb, err := newXKB(format, fd, size)
|
xkb, err := xkb.New(int(format), int(fd), int(size))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// TODO: Do better.
|
// TODO: Do better.
|
||||||
panic(err)
|
panic(err)
|
||||||
@@ -662,13 +663,16 @@ func gio_onKeyboardKey(data unsafe.Pointer, keyboard *C.struct_wl_keyboard, seri
|
|||||||
if state != C.WL_KEYBOARD_KEY_STATE_PRESSED || conn.xkb == nil {
|
if state != C.WL_KEYBOARD_KEY_STATE_PRESSED || conn.xkb == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
conn.xkb.dispatchKey(w.w, keyCode)
|
kc := uint32(keyCode)
|
||||||
if conn.xkb.isRepeatKey(keyCode) {
|
for _, e := range conn.xkb.DispatchKey(kc) {
|
||||||
conn.repeat.Start(w, keyCode, t)
|
w.w.event(e)
|
||||||
|
}
|
||||||
|
if conn.xkb.IsRepeatKey(kc) {
|
||||||
|
conn.repeat.Start(w, kc, t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *repeatState) Start(w *window, keyCode C.uint32_t, t time.Duration) {
|
func (r *repeatState) Start(w *window, keyCode uint32, t time.Duration) {
|
||||||
if r.rate <= 0 {
|
if r.rate <= 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -733,7 +737,9 @@ func (r *repeatState) Repeat() {
|
|||||||
if r.last+delay > now {
|
if r.last+delay > now {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
conn.xkb.dispatchKey(r.win, r.key)
|
for _, e := range conn.xkb.DispatchKey(r.key) {
|
||||||
|
r.win.event(e)
|
||||||
|
}
|
||||||
r.last += delay
|
r.last += delay
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -852,7 +858,7 @@ func gio_onKeyboardModifiers(data unsafe.Pointer, keyboard *C.struct_wl_keyboard
|
|||||||
if conn.xkb == nil {
|
if conn.xkb == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
conn.xkb.updateMask(depressed, latched, locked, group)
|
conn.xkb.UpdateMask(uint32(depressed), uint32(latched), uint32(locked), uint32(group))
|
||||||
}
|
}
|
||||||
|
|
||||||
//export gio_onKeyboardRepeatInfo
|
//export gio_onKeyboardRepeatInfo
|
||||||
|
|||||||
Reference in New Issue
Block a user