Skip to content

Feature/keyboard layout support #57

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

Merged
merged 12 commits into from
Jan 22, 2019
3 changes: 3 additions & 0 deletions example/simpleDemo/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ func main() {
gutter.OptionPixelRatio(1.2),
gutter.OptionVMArguments([]string{"--dart-non-checked-mode", "--observatory-port=50300"}),
gutter.OptionAddPluginReceiver(ownPlugin, "plugin_demo"),
// Default keyboard is Qwerty, if you want to change it, you can check keyboard.go in gutter package.
// Otherwise you can create your own by usinng `KeyboardShortcuts` struct.
//gutter.OptionKeyboardLayout(gutter.KeyboardAzertyLayout),
}

if err = gutter.Run(options...); err != nil {
Expand Down
112 changes: 60 additions & 52 deletions gutter.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,73 +93,74 @@ func glfwMouseButtonCallback(window *glfw.Window, key glfw.MouseButton, action g

var state = textModel{}

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

if key == glfw.KeyEscape && action == glfw.Press {
w.SetShouldClose(true)
}
return func(w *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) {
if key == glfw.KeyEscape && action == glfw.Press {
w.SetShouldClose(true)
}

if action == glfw.Repeat || action == glfw.Press {
if state.clientID != 0 {
if action == glfw.Repeat || action == glfw.Press {
if state.clientID != 0 {

switch key {
case glfw.KeyEnter:
if mods == glfw.ModControl {
performAction(w, "done")
} else {
state.addChar([]rune{'\n'})
performAction(w, "newline")
}
switch key {
case glfw.KeyEnter:
if mods == glfw.ModControl {
performAction(w, "done")
} else {
state.addChar([]rune{'\n'})
performAction(w, "newline")
}

case glfw.KeyHome:
state.MoveCursorHome(int(mods))
case glfw.KeyHome:
state.MoveCursorHome(int(mods))

case glfw.KeyEnd:
state.MoveCursorEnd(int(mods))
case glfw.KeyEnd:
state.MoveCursorEnd(int(mods))

case glfw.KeyLeft:
state.MoveCursorLeft(int(mods))
case glfw.KeyLeft:
state.MoveCursorLeft(int(mods))

case glfw.KeyRight:
state.MoveCursorRight(int(mods))
case glfw.KeyRight:
state.MoveCursorRight(int(mods))

case glfw.KeyDelete:
state.Delete(int(mods))
case glfw.KeyDelete:
state.Delete(int(mods))

case glfw.KeyBackspace:
state.Backspace(int(mods))
case glfw.KeyBackspace:
state.Backspace(int(mods))

case glfw.KeyA:
if mods == glfw.ModControl {
state.SelectAll()
}
case keyboardLayout.SelectAll:
if mods == glfw.ModControl {
state.SelectAll()
}

case glfw.KeyC:
if mods == glfw.ModControl && state.isSelected() {
_, _, selectedContent := state.GetSelectedText()
w.SetClipboardString(selectedContent)
}
case keyboardLayout.Copy:
if mods == glfw.ModControl && state.isSelected() {
_, _, selectedContent := state.GetSelectedText()
w.SetClipboardString(selectedContent)
}

case glfw.KeyX:
if mods == glfw.ModControl && state.isSelected() {
_, _, selectedContent := state.GetSelectedText()
w.SetClipboardString(selectedContent)
state.RemoveSelectedText()
}
case keyboardLayout.Cut:
if mods == glfw.ModControl && state.isSelected() {
_, _, selectedContent := state.GetSelectedText()
w.SetClipboardString(selectedContent)
state.RemoveSelectedText()
}

case glfw.KeyV:
if mods == glfw.ModControl {
var clpString, err = w.GetClipboardString()
if err != nil {
log.Printf("unable to get the clipboard content: %v\n", err)
} else {
state.addChar([]rune(clpString))
case keyboardLayout.Paste:
if mods == glfw.ModControl {
var clpString, err = w.GetClipboardString()
if err != nil {
log.Printf("unable to get the clipboard content: %v\n", err)
} else {
state.addChar([]rune(clpString))
}
}
}
}
}
}

}

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

width, height := window.GetFramebufferSize()
glfwWindowSizeCallback(window, width, height)
var glfwKeyCallback func(w *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey)

if c.KeyboardLayout != nil {
glfwKeyCallback = glfwKey(*c.KeyboardLayout)
} else {
glfwKeyCallback = glfwKey(KeyboardQwertyLayout)
}

window.SetKeyCallback(glfwKeyCallback)
window.SetFramebufferSizeCallback(glfwWindowSizeCallback)
Expand Down Expand Up @@ -286,11 +294,11 @@ func performAction(window *glfw.Window, action string) {
"TextInputAction." + action,
})
message := flutter.Message{
Args: actionArgs,
Method:"TextInputClient.performAction",
Args: actionArgs,
Method: "TextInputClient.performAction",
}
var mess = &flutter.PlatformMessage{
Channel:textInputChannel,
Channel: textInputChannel,
Message: message,
}
flutterOGL := flutter.SelectEngine(0)
Expand Down
19 changes: 19 additions & 0 deletions keyboard.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package gutter

import "github.com/go-gl/glfw/v3.2/glfw"

// KeyboardQwertyLayout is the default key for shortcuts (US-layout)
var KeyboardQwertyLayout = KeyboardShortcuts{
Cut: glfw.KeyX,
Copy: glfw.KeyC,
Paste: glfw.KeyV,
SelectAll: glfw.KeyA,
}

// KeyboardAzertyLayout gives an Azerty layout (french)
var KeyboardAzertyLayout = KeyboardShortcuts{
Cut: glfw.KeyX,
Copy: glfw.KeyC,
Paste: glfw.KeyV,
SelectAll: glfw.KeyQ,
}
18 changes: 18 additions & 0 deletions option.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,14 @@ func OptionAddPluginReceiver(handler PluginReceivers, channelName string) Option
}
}

// OptionKeyboardLayout allow application to support keyboard that have a different layout
// when the FlutterEngine send a PlatformMessage to the Embedder
func OptionKeyboardLayout(keyboardLayout KeyboardShortcuts) Option {
return func(c *config) {
c.KeyboardLayout = &keyboardLayout
}
}

type config struct {
WindowDimension struct {
x int
Expand All @@ -97,6 +105,16 @@ type config struct {
PixelRatio float64
VMArguments []string
PlatformMessageReceivers map[string][]PluginReceivers // The Key is the Channel name.
KeyboardLayout *KeyboardShortcuts
}

// KeyboardShortcuts Struct where user can define his own keyboard shortcut.
// This will allow application to support keyboard layout different from US layout
type KeyboardShortcuts struct {
Cut glfw.Key
Copy glfw.Key
Paste glfw.Key
SelectAll glfw.Key
}

func (t config) merge(options ...Option) config {
Expand Down