Skip to content

Commit 91996e7

Browse files
zephylacPierre Champion
authored and
Pierre Champion
committed
Feature/keyboard layout support (#57)
* Support different layout * Exported struct, user can use it in main * Renaming function (matchin new format) * Added default value for shortcuts * Removed local import (testing) * Added keyboard config * Check for optionnal keyboard * Fixed renaming * Fixed regression * new example for keyboard * Added explaination
1 parent a939e6b commit 91996e7

File tree

4 files changed

+100
-52
lines changed

4 files changed

+100
-52
lines changed

example/simpleDemo/main.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ func main() {
3939
gutter.OptionPixelRatio(1.2),
4040
gutter.OptionVMArguments([]string{"--dart-non-checked-mode", "--observatory-port=50300"}),
4141
gutter.OptionAddPluginReceiver(ownPlugin, "plugin_demo"),
42+
// Default keyboard is Qwerty, if you want to change it, you can check keyboard.go in gutter package.
43+
// Otherwise you can create your own by usinng `KeyboardShortcuts` struct.
44+
//gutter.OptionKeyboardLayout(gutter.KeyboardAzertyLayout),
4245
}
4346

4447
if err = gutter.Run(options...); err != nil {

gutter.go

Lines changed: 60 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -93,73 +93,74 @@ func glfwMouseButtonCallback(window *glfw.Window, key glfw.MouseButton, action g
9393

9494
var state = textModel{}
9595

96-
func glfwKeyCallback(w *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) {
96+
func glfwKey(keyboardLayout KeyboardShortcuts) func(w *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) {
9797

98-
if key == glfw.KeyEscape && action == glfw.Press {
99-
w.SetShouldClose(true)
100-
}
98+
return func(w *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) {
99+
if key == glfw.KeyEscape && action == glfw.Press {
100+
w.SetShouldClose(true)
101+
}
101102

102-
if action == glfw.Repeat || action == glfw.Press {
103-
if state.clientID != 0 {
103+
if action == glfw.Repeat || action == glfw.Press {
104+
if state.clientID != 0 {
104105

105-
switch key {
106-
case glfw.KeyEnter:
107-
if mods == glfw.ModControl {
108-
performAction(w, "done")
109-
} else {
110-
state.addChar([]rune{'\n'})
111-
performAction(w, "newline")
112-
}
106+
switch key {
107+
case glfw.KeyEnter:
108+
if mods == glfw.ModControl {
109+
performAction(w, "done")
110+
} else {
111+
state.addChar([]rune{'\n'})
112+
performAction(w, "newline")
113+
}
113114

114-
case glfw.KeyHome:
115-
state.MoveCursorHome(int(mods))
115+
case glfw.KeyHome:
116+
state.MoveCursorHome(int(mods))
116117

117-
case glfw.KeyEnd:
118-
state.MoveCursorEnd(int(mods))
118+
case glfw.KeyEnd:
119+
state.MoveCursorEnd(int(mods))
119120

120-
case glfw.KeyLeft:
121-
state.MoveCursorLeft(int(mods))
121+
case glfw.KeyLeft:
122+
state.MoveCursorLeft(int(mods))
122123

123-
case glfw.KeyRight:
124-
state.MoveCursorRight(int(mods))
124+
case glfw.KeyRight:
125+
state.MoveCursorRight(int(mods))
125126

126-
case glfw.KeyDelete:
127-
state.Delete(int(mods))
127+
case glfw.KeyDelete:
128+
state.Delete(int(mods))
128129

129-
case glfw.KeyBackspace:
130-
state.Backspace(int(mods))
130+
case glfw.KeyBackspace:
131+
state.Backspace(int(mods))
131132

132-
case glfw.KeyA:
133-
if mods == glfw.ModControl {
134-
state.SelectAll()
135-
}
133+
case keyboardLayout.SelectAll:
134+
if mods == glfw.ModControl {
135+
state.SelectAll()
136+
}
136137

137-
case glfw.KeyC:
138-
if mods == glfw.ModControl && state.isSelected() {
139-
_, _, selectedContent := state.GetSelectedText()
140-
w.SetClipboardString(selectedContent)
141-
}
138+
case keyboardLayout.Copy:
139+
if mods == glfw.ModControl && state.isSelected() {
140+
_, _, selectedContent := state.GetSelectedText()
141+
w.SetClipboardString(selectedContent)
142+
}
142143

143-
case glfw.KeyX:
144-
if mods == glfw.ModControl && state.isSelected() {
145-
_, _, selectedContent := state.GetSelectedText()
146-
w.SetClipboardString(selectedContent)
147-
state.RemoveSelectedText()
148-
}
144+
case keyboardLayout.Cut:
145+
if mods == glfw.ModControl && state.isSelected() {
146+
_, _, selectedContent := state.GetSelectedText()
147+
w.SetClipboardString(selectedContent)
148+
state.RemoveSelectedText()
149+
}
149150

150-
case glfw.KeyV:
151-
if mods == glfw.ModControl {
152-
var clpString, err = w.GetClipboardString()
153-
if err != nil {
154-
log.Printf("unable to get the clipboard content: %v\n", err)
155-
} else {
156-
state.addChar([]rune(clpString))
151+
case keyboardLayout.Paste:
152+
if mods == glfw.ModControl {
153+
var clpString, err = w.GetClipboardString()
154+
if err != nil {
155+
log.Printf("unable to get the clipboard content: %v\n", err)
156+
} else {
157+
state.addChar([]rune(clpString))
158+
}
157159
}
158160
}
159161
}
160162
}
161163
}
162-
163164
}
164165

165166
func glfwWindowSizeCallback(window *glfw.Window, width int, height int) {
@@ -242,6 +243,13 @@ func runFlutter(window *glfw.Window, c config) *flutter.EngineOpenGL {
242243

243244
width, height := window.GetFramebufferSize()
244245
glfwWindowSizeCallback(window, width, height)
246+
var glfwKeyCallback func(w *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey)
247+
248+
if c.KeyboardLayout != nil {
249+
glfwKeyCallback = glfwKey(*c.KeyboardLayout)
250+
} else {
251+
glfwKeyCallback = glfwKey(KeyboardQwertyLayout)
252+
}
245253

246254
window.SetKeyCallback(glfwKeyCallback)
247255
window.SetFramebufferSizeCallback(glfwWindowSizeCallback)
@@ -286,11 +294,11 @@ func performAction(window *glfw.Window, action string) {
286294
"TextInputAction." + action,
287295
})
288296
message := flutter.Message{
289-
Args: actionArgs,
290-
Method:"TextInputClient.performAction",
297+
Args: actionArgs,
298+
Method: "TextInputClient.performAction",
291299
}
292300
var mess = &flutter.PlatformMessage{
293-
Channel:textInputChannel,
301+
Channel: textInputChannel,
294302
Message: message,
295303
}
296304
flutterOGL := flutter.SelectEngine(0)

keyboard.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package gutter
2+
3+
import "github.com/go-gl/glfw/v3.2/glfw"
4+
5+
// KeyboardQwertyLayout is the default key for shortcuts (US-layout)
6+
var KeyboardQwertyLayout = KeyboardShortcuts{
7+
Cut: glfw.KeyX,
8+
Copy: glfw.KeyC,
9+
Paste: glfw.KeyV,
10+
SelectAll: glfw.KeyA,
11+
}
12+
13+
// KeyboardAzertyLayout gives an Azerty layout (french)
14+
var KeyboardAzertyLayout = KeyboardShortcuts{
15+
Cut: glfw.KeyX,
16+
Copy: glfw.KeyC,
17+
Paste: glfw.KeyV,
18+
SelectAll: glfw.KeyQ,
19+
}

option.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,14 @@ func OptionAddPluginReceiver(handler PluginReceivers, channelName string) Option
8686
}
8787
}
8888

89+
// OptionKeyboardLayout allow application to support keyboard that have a different layout
90+
// when the FlutterEngine send a PlatformMessage to the Embedder
91+
func OptionKeyboardLayout(keyboardLayout KeyboardShortcuts) Option {
92+
return func(c *config) {
93+
c.KeyboardLayout = &keyboardLayout
94+
}
95+
}
96+
8997
type config struct {
9098
WindowDimension struct {
9199
x int
@@ -97,6 +105,16 @@ type config struct {
97105
PixelRatio float64
98106
VMArguments []string
99107
PlatformMessageReceivers map[string][]PluginReceivers // The Key is the Channel name.
108+
KeyboardLayout *KeyboardShortcuts
109+
}
110+
111+
// KeyboardShortcuts Struct where user can define his own keyboard shortcut.
112+
// This will allow application to support keyboard layout different from US layout
113+
type KeyboardShortcuts struct {
114+
Cut glfw.Key
115+
Copy glfw.Key
116+
Paste glfw.Key
117+
SelectAll glfw.Key
100118
}
101119

102120
func (t config) merge(options ...Option) config {

0 commit comments

Comments
 (0)