shiny: handle changes to x11 keyboard mapping

Handle MappingNotifyEvent and reload the keyboard configuration as
needed. This will keep the x11 driver updated when the user changes the
keyboard layout (for example with setxkbmap).

Change-Id: I466d9c221f8e742b813634be429df710cb46aaac
Reviewed-on: https://go-review.googlesource.com/c/exp/+/192777
Reviewed-by: Nigel Tao <nigeltao@golang.org>
diff --git a/shiny/driver/x11driver/screen.go b/shiny/driver/x11driver/screen.go
index 336d73f..c734797 100644
--- a/shiny/driver/x11driver/screen.go
+++ b/shiny/driver/x11driver/screen.go
@@ -115,6 +115,7 @@
 }
 
 func (s *screenImpl) run() {
+	keyboardChanged := false
 	for {
 		ev, err := s.xc.WaitForEvent()
 		if err != nil {
@@ -190,6 +191,10 @@
 			}
 
 		case xproto.KeyPressEvent:
+			if keyboardChanged {
+				keyboardChanged = false
+				s.initKeyboardMapping()
+			}
 			if w := s.findWindow(ev.Event); w != nil {
 				w.handleKey(ev.Detail, ev.State, key.DirPress)
 			} else {
@@ -197,6 +202,10 @@
 			}
 
 		case xproto.KeyReleaseEvent:
+			if keyboardChanged {
+				keyboardChanged = false
+				s.initKeyboardMapping()
+			}
 			if w := s.findWindow(ev.Event); w != nil {
 				w.handleKey(ev.Detail, ev.State, key.DirRelease)
 			} else {
@@ -223,6 +232,11 @@
 			} else {
 				noWindowFound = true
 			}
+
+		case xproto.MappingNotifyEvent:
+			if ev.Request == xproto.MappingModifier || ev.Request == xproto.MappingKeyboard {
+				keyboardChanged = true
+			}
 		}
 
 		if noWindowFound {