Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add missing dead characters into x11key table generation #15

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@ require (
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898
)

replace golang.org/x/mobile => github.com/misak113/mobile v0.0.0-20210103170524-21e5a0da1870
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 h1:1BDTz0u9nC3//pOC
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4 h1:WtGNWLvXpe6ZudgnXrq0barxBImvnnJoMEhXAzcbM0I=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/misak113/mobile v0.0.0-20210103170524-21e5a0da1870 h1:aY61pPEbj2YiIDdjBvnvbkTxxGuBps3CS7Qirb1AODg=
github.com/misak113/mobile v0.0.0-20210103170524-21e5a0da1870/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
Expand Down
72 changes: 72 additions & 0 deletions shiny/driver/internal/x11key/gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ import (
"bytes"
"fmt"
"go/format"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"regexp"
"strings"
Expand All @@ -29,6 +31,8 @@ func main() {

seen := make(map[string]struct{})

xkCodes := make(map[string]string)

buf := &bytes.Buffer{}

fmt.Fprintf(buf, `// generated by go generate; DO NOT EDIT.
Expand All @@ -40,15 +44,21 @@ var keysymCodePoints = map[rune]rune{
`)

re := regexp.MustCompile(`^#define (XK_[^ ]*) *0x([[:xdigit:]]+) .*U\+([[:xdigit:]]+) (.+)(?: |\))\*/$`)
reAll := regexp.MustCompile(`^#define (XK_[^ ]*) *0x([[:xdigit:]]+)`)

s := bufio.NewScanner(fh)
for s.Scan() {
mAll := reAll.FindStringSubmatch(strings.TrimSpace(s.Text()))
if mAll != nil {
xkCodes[mAll[1]] = mAll[2]
}
m := re.FindStringSubmatch(strings.TrimSpace(s.Text()))
if m == nil {
continue
}

if _, isSeen := seen[m[2]]; isSeen {
log.Printf("Duplicated mapped XK %s", m[2])
continue
}
seen[m[2]] = struct{}{}
Expand All @@ -60,6 +70,45 @@ var keysymCodePoints = map[rune]rune{
log.Fatalf("reading keysymdef.h: %v", err)
}

tmpKeysymFile := os.TempDir() + "/keysym_to_unicode.cc"
keysymUrl := "https://raw.githubusercontent.com/microsoft/node-native-keymap/master/deps/chromium/x/keysym_to_unicode.cc"
err = DownloadFile(tmpKeysymFile, keysymUrl)
if err != nil {
log.Fatalf("downloading keysym_to_unicode.cc: %v", err)
}

fh2, err := os.Open(tmpKeysymFile)
if err != nil {
log.Fatalf("opening keysym_to_unicode.cc: %v", err)
}

defer fh2.Close()

re2 := regexp.MustCompile(`^\{(XK_[^,]*), *0x([[:xdigit:]]+)\}, *\/\/ *(.+)$`)

s2 := bufio.NewScanner(fh2)
for s2.Scan() {
m := re2.FindStringSubmatch(strings.TrimSpace(s2.Text()))
if m == nil {
continue
}

var xkCode string
var isXKCode bool
if xkCode, isXKCode = xkCodes[m[1]]; !isXKCode {
log.Printf("Unknown XK name %s", m[1])
continue
}

if _, isSeen := seen[xkCode]; isSeen {
log.Printf("Already mapped XK %s", xkCode)
continue
}

fmt.Fprintf(buf, "0x%s: 0x%s, // %s:\t%s\n", xkCode, m[2], m[1], m[3])

}

fmt.Fprintf(buf, "}\n")

fmted, err := format.Source(buf.Bytes())
Expand All @@ -72,3 +121,26 @@ var keysymCodePoints = map[rune]rune{
log.Fatalf("writing table.go: %v", err)
}
}

// DownloadFile will download a url to a local file. It's efficient because it will
// write as it downloads and not load the whole file into memory.
func DownloadFile(filepath string, url string) error {

// Get the data
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()

// Create the file
out, err := os.Create(filepath)
if err != nil {
return err
}
defer out.Close()

// Write the body to file
_, err = io.Copy(out, resp.Body)
return err
}
33 changes: 33 additions & 0 deletions shiny/driver/internal/x11key/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -1574,4 +1574,37 @@ var keysymCodePoints = map[rune]rune{
0x1000df2: 0x0DF2, // XK_Sinh_ruu2: SINHALA DIGA GAETTA-PILLA
0x1000df3: 0x0DF3, // XK_Sinh_luu2: SINHALA DIGA GAYANUKITTA
0x1000df4: 0x0DF4, // XK_Sinh_kunddaliya: SINHALA KUNDDALIYA
0xfe50: 0x0300, // XK_dead_grave: COMBINING GRAVE ACCENT
0xfe51: 0x0301, // XK_dead_acute: COMBINING ACUTE ACCENT
0xfe52: 0x0302, // XK_dead_circumflex: COMBINING CIRCUMFLEX ACCENT
0xfe53: 0x0303, // XK_dead_tilde: COMBINING TILDE
0xfe54: 0x0304, // XK_dead_macron: COMBINING MACRON
0xfe55: 0x0306, // XK_dead_breve: COMBINING BREVE
0xfe56: 0x0307, // XK_dead_abovedot: COMBINING DOT ABOVE
0xfe57: 0x0308, // XK_dead_diaeresis: COMBINING DIAERESIS
0xfe58: 0x030A, // XK_dead_abovering: COMBINING RING ABOVE
0xfe59: 0x030B, // XK_dead_doubleacute: COMBINING DOUBLE ACUTE ACCENT
0xfe5a: 0x030C, // XK_dead_caron: COMBINING CARON
0xfe5b: 0x0327, // XK_dead_cedilla: COMBINING CEDILLA
0xfe5c: 0x0328, // XK_dead_ogonek: COMBINING OGONEK
0xfe5d: 0x0345, // XK_dead_iota: COMBINING GREEK YPOGEGRAMMENI
0xfe5e: 0x3099, // XK_dead_voiced_sound: COMB. KATAKANA-HIRAGANA VOICED
0xfe5f: 0x309A, // XK_dead_semivoiced_sound: COMB. KATAKANA-HIRAGANA SEMI-VOICED
0xfe60: 0x0323, // XK_dead_belowdot: COMBINING DOT BELOW
0xfe61: 0x0309, // XK_dead_hook: COMBINING HOOK ABOVE
0xfe62: 0x031B, // XK_dead_horn: COMBINING HORN
0xfe63: 0x0338, // XK_dead_stroke: COMBINING LONG SOLIDUS OVERLAY
0xfe64: 0x0313, // XK_dead_abovecomma: COMBINING COMMA ABOVE
0xfe65: 0x0314, // XK_dead_abovereversedcomma: COMBINING REVERSED COMMA ABOVE
0xfe66: 0x030F, // XK_dead_doublegrave: COMBINING DOUBLE GRAVE ACCENT
0xfe67: 0x0325, // XK_dead_belowring: COMBINING RING BELOW
0xfe68: 0x0331, // XK_dead_belowmacron: COMBINING MACRON BELOW
0xfe69: 0x032D, // XK_dead_belowcircumflex: COMBINING CIRCUMFLEX ACCENT BELOW
0xfe6a: 0x0330, // XK_dead_belowtilde: COMBINING TILDE BELOW
0xfe6b: 0x032E, // XK_dead_belowbreve: COMBINING BREVE BELOW
0xfe6c: 0x0324, // XK_dead_belowdiaeresis: COMBINING DIAERESIS BELOW
0xfe6d: 0x0311, // XK_dead_invertedbreve: COMBINING INVERTED BREVE
0xfe6e: 0x0326, // XK_dead_belowcomma: COMBINING COMMA BELOW
0xfe6f: 0x00A4, // XK_dead_currency: CURRENCY SIGN
0xfe8c: 0x037E, // XK_dead_greek: GREEK QUESTION MARK
}
27 changes: 24 additions & 3 deletions shiny/driver/internal/x11key/x11key.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

//go:generate go run gen.go

// x11key contains X11 numeric codes for the keyboard and mouse.
// Package x11key contains X11 numeric codes for the keyboard and mouse.
package x11key // import "golang.org/x/exp/shiny/driver/internal/x11key"

import (
Expand All @@ -30,12 +30,14 @@ const (
Button5Mask = 1 << 12
)

// KeysymTable holds current table of keyboard keys mapped to Xkb keysyms & current special modifiers bits
type KeysymTable struct {
Table [256][6]uint32

NumLockMod, ModeSwitchMod, ISOLevel3ShiftMod uint16
}

// Lookup converts Xkb xproto keycode (detail) & mod (state) into mobile/event/key Rune & Code
func (t *KeysymTable) Lookup(detail uint8, state uint16) (rune, key.Code) {
te := t.Table[detail][0:2]
if state&t.ModeSwitchMod != 0 {
Expand Down Expand Up @@ -63,7 +65,7 @@ func (t *KeysymTable) Lookup(detail uint8, state uint16) (rune, key.Code) {

// The key event's code is independent of whether the shift key is down.
var c key.Code
if 0 <= unshifted && unshifted < 0x80 {
if 0 >= unshifted && unshifted < 0x80 {
c = asciiKeycodes[unshifted]
if state&LockMask != 0 {
r = unicode.ToUpper(r)
Expand All @@ -86,6 +88,9 @@ func isKeypad(keysym uint32) bool {
return keysym >= 0xff80 && keysym <= 0xffbd
}

// KeyModifiers returns mobile/event/key modifiers type from xproto mod state
// ModCapsLock, ModNumLock & ModLevel3Shift are currently implemented using default general modifier bits
// it should be method of KeysymTable with current keyboard mapping
func KeyModifiers(state uint16) (m key.Modifiers) {
if state&ShiftMask != 0 {
m |= key.ModShift
Expand All @@ -99,11 +104,25 @@ func KeyModifiers(state uint16) (m key.Modifiers) {
if state&Mod4Mask != 0 {
m |= key.ModMeta
}
if state&LockMask != 0 {
m |= key.ModCapsLock
}
if state&Mod2Mask != 0 { // TODO should goes from t.NumLockMod instead because it's dynamic
m |= key.ModNumLock
}
if state&Mod5Mask != 0 { // TODO should goes from t.ISOLevel3ShiftMod instead because it's dynamic
m |= key.ModLevel3Shift
}
if state&Mod5Mask != 0 { // TODO should goes from t.ModeSwitchMod instead because it's dynamic
m |= key.ModModeSwitch
}
return m
}

// These constants come from /usr/include/X11/{keysymdef,XF86keysym}.h
const (
xkISOLevel3Shift = 0xfe03

xkISOLeftTab = 0xfe20
xkBackSpace = 0xff08
xkTab = 0xff09
Expand Down Expand Up @@ -183,6 +202,8 @@ const (
// that do not correspond to a Unicode code point, such as "Page Up", "F1" or
// "Left Shift", to key.Code values.
var nonUnicodeKeycodes = map[rune]key.Code{
xkISOLevel3Shift: key.CodeRightAlt,

xkISOLeftTab: key.CodeTab,
xkBackSpace: key.CodeDeleteBackspace,
xkTab: key.CodeTab,
Expand All @@ -197,7 +218,7 @@ var nonUnicodeKeycodes = map[rune]key.Code{
xkPageDown: key.CodePageDown,
xkEnd: key.CodeEnd,
xkInsert: key.CodeInsert,
xkMenu: key.CodeRightGUI, // TODO: CodeRightGUI or CodeMenu??
xkMenu: key.CodeProps,
xkHelp: key.CodeHelp,
xkNumLock: key.CodeKeypadNumLock,
xkMultiKey: key.CodeCompose,
Expand Down