cchat-gtk/internal/ui/messages/input/keydown.go

123 lines
2.8 KiB
Go

package input
import (
"time"
"github.com/diamondburned/cchat-gtk/internal/gts"
"github.com/diamondburned/cchat-gtk/internal/log"
"github.com/gotk3/gotk3/gdk"
"github.com/gotk3/gotk3/gtk"
"github.com/pkg/errors"
)
const shiftMask = uint(gdk.SHIFT_MASK)
const cntrlMask = uint(gdk.CONTROL_MASK)
func bithas(bit, has uint) bool {
return bit&has == has
}
func convEvent(ev *gdk.Event) (key, mask uint) {
var keyEvent = gdk.EventKeyNewFromEvent(ev)
return keyEvent.KeyVal(), keyEvent.State()
}
// connects to key-press-event
func (f *Field) keyDown(tv *gtk.TextView, ev *gdk.Event) bool {
var key, mask = convEvent(ev)
switch {
// If Enter is pressed.
case key == gdk.KEY_Return:
// If Shift is being held, insert a new line.
if bithas(mask, shiftMask) {
f.buffer.InsertAtCursor("\n")
return true
}
// Else, send the message.
f.sendInput()
return true
// If Arrow Up is pressed, then we might want to edit the latest message if
// any.
case key == gdk.KEY_Up:
// Do we have input? If we do, then we shouldn't touch it.
if f.textLen() > 0 {
return false
}
// Try and find the latest message ID that is ours.
msgr := f.ctrl.LatestMessageFrom(f.UserID)
if msgr == nil {
// No messages found, so we can passthrough normally.
return false
}
id := msgr.Unwrap().ID
// If we don't support message editing, then passthrough events.
if !f.Editable(id) {
return false
}
// Start editing.
f.StartEditing(id)
// TODO: add a visible indicator to indicate a message being edited.
// Take the event.
return true
// Clear text when the Escape key is pressed.
case key == gdk.KEY_Escape:
f.clearText()
// Ctrl+V is paste.
case key == gdk.KEY_v && bithas(mask, cntrlMask):
// As this pasting is for image attachments, don't accept it if iwe
// don't allow attachments.
if !f.upload {
return false
}
// TODO: make this asynchronous.
// Is there an image in the clipboard?
if !gts.Clipboard.WaitIsImageAvailable() {
return false
}
gts.Async(func() (func(), error) {
p, err := gts.Clipboard.WaitForImage()
if err != nil {
return nil, errors.Wrap(err, "Failed to get image from clipboard")
}
return func() { f.Attachments.AddPixbuf(p) }, nil
})
return true
}
// If the server supports typing indication, then announce that we are
// typing with a proper rate limit.
if f.typing != nil {
// Get the current time; if the next timestamp is before now, then that
// means it's time for us to update it and send a typing indication.
if now := time.Now(); f.lastTyped.Add(f.typerDura).Before(now) {
// Update.
f.lastTyped = now
// Send asynchronously.
go func() {
if err := f.typing.Typing(); err != nil {
log.Error(errors.Wrap(err, "Failed to announce typing"))
}
}()
}
}
// Passthrough.
return false
}