aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNigel Tao <nigeltao@golang.org>2010-06-29 10:54:41 +1000
committerNigel Tao <nigeltao@golang.org>2010-06-29 10:54:41 +1000
commit715425bf6f6e82fd6e6c84c920be651e98c3be2e (patch)
treed734a66d91eed3e9ad7f243f7c3f1e735b30996c
parent807605d0fc8a4c4ca46458773bf5ca2263d2c1d9 (diff)
downloadgo-715425bf6f6e82fd6e6c84c920be651e98c3be2e.tar.gz
go-715425bf6f6e82fd6e6c84c920be651e98c3be2e.zip
exp/draw/x11: implement the mapping from keycodes to keysyms.
R=rsc CC=golang-dev, rog https://golang.org/cl/1739042
-rw-r--r--src/pkg/exp/draw/x11/conn.go109
1 files changed, 78 insertions, 31 deletions
diff --git a/src/pkg/exp/draw/x11/conn.go b/src/pkg/exp/draw/x11/conn.go
index 3579a24c38..979ce2b7d9 100644
--- a/src/pkg/exp/draw/x11/conn.go
+++ b/src/pkg/exp/draw/x11/conn.go
@@ -29,6 +29,11 @@ const (
windowWidth = 800
)
+const (
+ keymapLo = 8
+ keymapHi = 255
+)
+
type conn struct {
// TODO(nigeltao): Figure out which goroutine should be responsible for closing c,
// or if there is a race condition if one goroutine calls c.Close whilst another one
@@ -136,6 +141,13 @@ func (c *conn) QuitChan() <-chan bool { return c.quit }
// pumper runs in its own goroutine, reading X events and demuxing them over the kbd / mouse / resize / quit chans.
func (c *conn) pumper() {
+ var (
+ keymap [256][]int
+ keysymsPerKeycode int
+ )
+ defer close(c.flush)
+ // TODO(nigeltao): Is this the right place for defer c.c.Close()?
+ // TODO(nigeltao): Should we explicitly defer close our kbd/mouse/resize/quit chans?
for {
// X events are always 32 bytes long.
_, err := io.ReadFull(c.r, c.buf[0:32])
@@ -144,15 +156,49 @@ func (c *conn) pumper() {
// TODO(nigeltao): should we do c.quit<-true? Should c.quit be a buffered channel?
// Or is c.quit only for non-exceptional closing (e.g. when the window manager destroys
// our window), and not for e.g. an I/O error?
- break
+ os.Stderr.Write([]byte(err.String()))
+ return
}
switch c.buf[0] {
+ case 0x01: // Reply from a request (e.g. GetKeyboardMapping).
+ cookie := int(c.buf[3])<<8 | int(c.buf[2])
+ if cookie != 1 {
+ // We issued only one request (GetKeyboardMapping) with a cookie of 1,
+ // so we shouldn't get any other reply from the X server.
+ os.Stderr.Write([]byte("exp/draw/x11: unexpected cookie\n"))
+ return
+ }
+ keysymsPerKeycode = int(c.buf[1])
+ b := make([]int, 256*keysymsPerKeycode)
+ for i := range keymap {
+ keymap[i] = b[i*keysymsPerKeycode : (i+1)*keysymsPerKeycode]
+ }
+ for i := keymapLo; i <= keymapHi; i++ {
+ m := keymap[i]
+ for j := range m {
+ u, err := readU32LE(c.r, c.buf[0:4])
+ if err != nil {
+ os.Stderr.Write([]byte(err.String()))
+ return
+ }
+ m[j] = int(u)
+ }
+ }
case 0x02, 0x03: // Key press, key release.
- // BUG(nigeltao): Keycode to keysym mapping is not implemented.
-
- // The keycode is in c.buf[1], but as keymaps aren't implemented yet, we'll use the
- // space character as a placeholder.
- keysym := int(' ')
+ // X Keyboard Encoding is documented at http://tronche.com/gui/x/xlib/input/keyboard-encoding.html
+ // TODO(nigeltao): Do we need to implement the "MODE SWITCH / group modifier" feature
+ // or is that some no-longer-used X construct?
+ if keysymsPerKeycode < 2 {
+ // Either we haven't yet received the GetKeyboardMapping reply or
+ // the X server has sent one that's too short.
+ continue
+ }
+ keycode := int(c.buf[1])
+ shift := int(c.buf[28]) & 0x01
+ keysym := keymap[keycode][shift]
+ if keysym == 0 {
+ keysym = keymap[keycode][0]
+ }
// TODO(nigeltao): Should we send KeyboardChan ints for Shift/Ctrl/Alt? Should Shift-A send
// the same int down the channel as the sent on just the A key?
// TODO(nigeltao): How should IME events (e.g. key presses that should generate CJK text) work? Or
@@ -194,9 +240,6 @@ func (c *conn) pumper() {
// What about EnterNotify (0x07) and LeaveNotify (0x08)?
}
}
- close(c.flush)
- // TODO(nigeltao): Is this the right place for c.c.Close()?
- // TODO(nigeltao): Should we explicitly close our kbd/mouse/resize/quit chans?
}
// connect connects to the X server given by the full X11 display name (e.g.
@@ -537,29 +580,33 @@ func NewWindowDisplay(display string) (draw.Context, os.Error) {
}
// Now that we're connected, show a window, via three X protocol messages.
- // First, create a graphics context (GC).
- setU32LE(c.buf[0:4], 0x00060037) // 0x37 is the CreateGC opcode, and the message is 6 x 4 bytes long.
- setU32LE(c.buf[4:8], uint32(c.gc))
- setU32LE(c.buf[8:12], uint32(c.root))
- setU32LE(c.buf[12:16], 0x00010004) // Bit 2 is XCB_GC_FOREGROUND, bit 16 is XCB_GC_GRAPHICS_EXPOSURES.
- setU32LE(c.buf[16:20], 0x00000000) // The Foreground is black.
- setU32LE(c.buf[20:24], 0x00000000) // GraphicsExposures' value is unused.
- // Second, create the window.
- setU32LE(c.buf[24:28], 0x000a0001) // 0x01 is the CreateWindow opcode, and the message is 10 x 4 bytes long.
- setU32LE(c.buf[28:32], uint32(c.window))
- setU32LE(c.buf[32:36], uint32(c.root))
- setU32LE(c.buf[36:40], 0x00000000) // Initial (x, y) is (0, 0).
- setU32LE(c.buf[40:44], windowHeight<<16|windowWidth)
- setU32LE(c.buf[44:48], 0x00010000) // Border width is 0, XCB_WINDOW_CLASS_INPUT_OUTPUT is 1.
- setU32LE(c.buf[48:52], uint32(c.visual))
- setU32LE(c.buf[52:56], 0x00000802) // Bit 1 is XCB_CW_BACK_PIXEL, bit 11 is XCB_CW_EVENT_MASK.
- setU32LE(c.buf[56:60], 0x00000000) // The Back-Pixel is black.
- setU32LE(c.buf[60:64], 0x0000804f) // Key/button press and release, pointer motion, and expose event masks.
- // Third, map the window.
- setU32LE(c.buf[64:68], 0x00020008) // 0x08 is the MapWindow opcode, and the message is 2 x 4 bytes long.
- setU32LE(c.buf[68:72], uint32(c.window))
+ // First, issue a GetKeyboardMapping request. This is the first request, and
+ // will be associated with a cookie of 1.
+ setU32LE(c.buf[0:4], 0x00020065) // 0x65 is the GetKeyboardMapping opcode, and the message is 2 x 4 bytes long.
+ setU32LE(c.buf[4:8], uint32((keymapHi-keymapLo+1)<<8|keymapLo))
+ // Second, create a graphics context (GC).
+ setU32LE(c.buf[8:12], 0x00060037) // 0x37 is the CreateGC opcode, and the message is 6 x 4 bytes long.
+ setU32LE(c.buf[12:16], uint32(c.gc))
+ setU32LE(c.buf[16:20], uint32(c.root))
+ setU32LE(c.buf[20:24], 0x00010004) // Bit 2 is XCB_GC_FOREGROUND, bit 16 is XCB_GC_GRAPHICS_EXPOSURES.
+ setU32LE(c.buf[24:28], 0x00000000) // The Foreground is black.
+ setU32LE(c.buf[28:32], 0x00000000) // GraphicsExposures' value is unused.
+ // Third, create the window.
+ setU32LE(c.buf[32:36], 0x000a0001) // 0x01 is the CreateWindow opcode, and the message is 10 x 4 bytes long.
+ setU32LE(c.buf[36:40], uint32(c.window))
+ setU32LE(c.buf[40:44], uint32(c.root))
+ setU32LE(c.buf[44:48], 0x00000000) // Initial (x, y) is (0, 0).
+ setU32LE(c.buf[48:52], windowHeight<<16|windowWidth)
+ setU32LE(c.buf[52:56], 0x00010000) // Border width is 0, XCB_WINDOW_CLASS_INPUT_OUTPUT is 1.
+ setU32LE(c.buf[56:60], uint32(c.visual))
+ setU32LE(c.buf[60:64], 0x00000802) // Bit 1 is XCB_CW_BACK_PIXEL, bit 11 is XCB_CW_EVENT_MASK.
+ setU32LE(c.buf[64:68], 0x00000000) // The Back-Pixel is black.
+ setU32LE(c.buf[68:72], 0x0000804f) // Key/button press and release, pointer motion, and expose event masks.
+ // Fourth, map the window.
+ setU32LE(c.buf[72:76], 0x00020008) // 0x08 is the MapWindow opcode, and the message is 2 x 4 bytes long.
+ setU32LE(c.buf[76:80], uint32(c.window))
// Write the bytes.
- _, err = c.w.Write(c.buf[0:72])
+ _, err = c.w.Write(c.buf[0:80])
if err != nil {
return nil, err
}