fix(cef): enable IMContext for dead key compose support
Re-enable the GtkIMContextSimple integration that was disabled during debugging. The previous crash was caused by stale bindings, not the IMContext itself. Dead key sequences (e.g. '+e → é) now work correctly on US International and other compose-capable keyboard layouts.
- commit
- a5e0073b7a24e65eccab42d51c3059e91429c664
- author
- brice · · 2026-03-20 19:16 UTC
- committer
- brice · · 2026-03-28 04:37 UTC
- parent
- 2f401f2
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
1 file · +13 -19
M internal/infrastructure/cef/input_bridge.go +13 -19
| @@ -139,25 +139,19 @@ func (ib *inputBridge) attachFocusAndKeyboard(glArea *gtk.GLArea) { | |||
| 139 | 139 | // Keyboard + IMContext for dead key / compose support. | |
| 140 | 140 | key := gtk.NewEventControllerKey() | |
| 141 | 141 | ||
| 142 | - | // Set up IMContext: when set on the controller, GTK calls | |
| 143 | - | // FilterKeypress on every key event. If the IM absorbs the key | |
| 144 | - | // (dead key, compose in-progress), key-pressed is NOT emitted; | |
| 145 | - | // instead the IM emits "commit" with the composed string. | |
| 146 | - | // TODO: re-enable once ConnectCommit callback crash is resolved. | |
| 147 | - | // The IMContext integration causes a stack corruption crash at startup, | |
| 148 | - | // likely due to a purego callback ABI mismatch in the generated signal | |
| 149 | - | // bindings. The VK code fixes and gdk.KeyvalToUnicode() still work | |
| 150 | - | // without IMContext — XKB handles dead key composition at the layout level. | |
| 151 | - | // | |
| 152 | - | // ib.imContext = gtk.NewIMContextSimple() | |
| 153 | - | // if ib.imContext != nil { | |
| 154 | - | // ib.commitCb = func(_ gtk.IMContext, text string) { | |
| 155 | - | // ib.onIMCommit(text) | |
| 156 | - | // } | |
| 157 | - | // ib.imContext.ConnectCommit(&ib.commitCb) | |
| 158 | - | // key.SetImContext(&ib.imContext.IMContext) | |
| 159 | - | // ib.imContext.SetClientWidget(&glArea.Widget) | |
| 160 | - | // } | |
| 142 | + | // Set up IMContext for dead key / compose support. | |
| 143 | + | // When set on the controller, GTK calls FilterKeypress on every key | |
| 144 | + | // event. If the IM absorbs the key (dead key, compose in-progress), | |
| 145 | + | // key-pressed is NOT emitted; the IM emits "commit" with the result. | |
| 146 | + | ib.imContext = gtk.NewIMContextSimple() | |
| 147 | + | if ib.imContext != nil { | |
| 148 | + | ib.commitCb = func(_ gtk.IMContext, text string) { | |
| 149 | + | ib.onIMCommit(text) | |
| 150 | + | } | |
| 151 | + | ib.imContext.ConnectCommit(&ib.commitCb) | |
| 152 | + | key.SetImContext(&ib.imContext.IMContext) | |
| 153 | + | ib.imContext.SetClientWidget(&glArea.Widget) | |
| 154 | + | } | |
| 161 | 155 | ||
| 162 | 156 | keyPressCb := func(_ gtk.EventControllerKey, keyval, keycode uint, state gdk.ModifierType) bool { | |
| 163 | 157 | ib.onKeyPress(keyval, keycode, uint(state)) | |
| @@ -139,25 +139,19 @@ func (ib *inputBridge) attachFocusAndKeyboard(glArea *gtk.GLArea) { | |||||
| 139 | // Keyboard + IMContext for dead key / compose support. | 139 | // Keyboard + IMContext for dead key / compose support. | ||
| 140 | key := gtk.NewEventControllerKey() | 140 | key := gtk.NewEventControllerKey() | ||
| 141 | 141 | ||||
| 142 | - | // Set up IMContext: when set on the controller, GTK calls | 142 | + | // Set up IMContext for dead key / compose support. |
| 143 | - | // FilterKeypress on every key event. If the IM absorbs the key | 143 | + | // When set on the controller, GTK calls FilterKeypress on every key |
| 144 | - | // (dead key, compose in-progress), key-pressed is NOT emitted; | 144 | + | // event. If the IM absorbs the key (dead key, compose in-progress), |
| 145 | - | // instead the IM emits "commit" with the composed string. | 145 | + | // key-pressed is NOT emitted; the IM emits "commit" with the result. |
| 146 | - | // TODO: re-enable once ConnectCommit callback crash is resolved. | 146 | + | ib.imContext = gtk.NewIMContextSimple() |
| 147 | - | // The IMContext integration causes a stack corruption crash at startup, | 147 | + | if ib.imContext != nil { |
| 148 | - | // likely due to a purego callback ABI mismatch in the generated signal | 148 | + | ib.commitCb = func(_ gtk.IMContext, text string) { |
| 149 | - | // bindings. The VK code fixes and gdk.KeyvalToUnicode() still work | 149 | + | ib.onIMCommit(text) |
| 150 | - | // without IMContext — XKB handles dead key composition at the layout level. | 150 | + | } |
| 151 | - | // | 151 | + | ib.imContext.ConnectCommit(&ib.commitCb) |
| 152 | - | // ib.imContext = gtk.NewIMContextSimple() | 152 | + | key.SetImContext(&ib.imContext.IMContext) |
| 153 | - | // if ib.imContext != nil { | 153 | + | ib.imContext.SetClientWidget(&glArea.Widget) |
| 154 | - | // ib.commitCb = func(_ gtk.IMContext, text string) { | 154 | + | } |
| 155 | - | // ib.onIMCommit(text) | |||
| 156 | - | // } | |||
| 157 | - | // ib.imContext.ConnectCommit(&ib.commitCb) | |||
| 158 | - | // key.SetImContext(&ib.imContext.IMContext) | |||
| 159 | - | // ib.imContext.SetClientWidget(&glArea.Widget) | |||
| 160 | - | // } | |||
| 161 | 155 | ||||
| 162 | keyPressCb := func(_ gtk.EventControllerKey, keyval, keycode uint, state gdk.ModifierType) bool { | 156 | keyPressCb := func(_ gtk.EventControllerKey, keyval, keycode uint, state gdk.ModifierType) bool { | ||
| 163 | ib.onKeyPress(keyval, keycode, uint(state)) | 157 | ib.onKeyPress(keyval, keycode, uint(state)) | ||