This commit is contained in:
Sasha Koshka 2023-07-21 23:22:03 -04:00
parent c193c25b15
commit a0fd8a694b
5 changed files with 274 additions and 7 deletions

23
box.go
View File

@ -261,6 +261,9 @@ func (this *box) doLayout () {
}
func (this *box) setParent (parent parent) {
if this.parent != parent && this.Focused() {
this.SetFocused(false)
}
this.parent = parent
}
@ -316,3 +319,23 @@ func (this *box) handleMouseUp (button input.Button) {
listener(button)
}
}
func (this *box) handleKeyDown (key input.Key, numberPad bool) {
for _, listener := range this.on.keyDown.Listeners() {
listener(key, numberPad)
}
}
func (this *box) handleKeyUp (key input.Key, numberPad bool) {
for _, listener := range this.on.keyUp.Listeners() {
listener(key, numberPad)
}
}
func (this *box) propagate (callback func (anyBox) bool) bool {
return callback(this)
}
func (this *box) propagateAlt (callback func (anyBox) bool) bool {
return callback(this)
}

View File

@ -227,3 +227,23 @@ func (this *containerBox) boxUnder (point image.Point) anyBox {
return this.box.boxUnder(point)
}
func (this *containerBox) propagate (callback func (anyBox) bool) bool {
for _, box := range this.children {
box := box.(anyBox)
if !box.propagate(callback) { return false }
}
return callback(this)
}
func (this *containerBox) propagateAlt (callback func (anyBox) bool) bool {
if !callback(this) { return false}
for _, box := range this.children {
box := box.(anyBox)
if !box.propagateAlt(callback) { return false }
}
return true
}

170
event.go
View File

@ -8,6 +8,102 @@ import "git.tebibyte.media/tomo/xgbkb"
import "github.com/jezek/xgbutil/xevent"
import "git.tebibyte.media/tomo/tomo/input"
var buttonCodeTable = map[xproto.Keysym] input.Key {
0xFFFFFF: input.KeyNone,
0xFF63: input.KeyInsert,
0xFF67: input.KeyMenu,
0xFF61: input.KeyPrintScreen,
0xFF6B: input.KeyPause,
0xFFE5: input.KeyCapsLock,
0xFF14: input.KeyScrollLock,
0xFF7F: input.KeyNumLock,
0xFF08: input.KeyBackspace,
0xFF09: input.KeyTab,
0xFE20: input.KeyTab,
0xFF0D: input.KeyEnter,
0xFF1B: input.KeyEscape,
0xFF52: input.KeyUp,
0xFF54: input.KeyDown,
0xFF51: input.KeyLeft,
0xFF53: input.KeyRight,
0xFF55: input.KeyPageUp,
0xFF56: input.KeyPageDown,
0xFF50: input.KeyHome,
0xFF57: input.KeyEnd,
0xFFE1: input.KeyLeftShift,
0xFFE2: input.KeyRightShift,
0xFFE3: input.KeyLeftControl,
0xFFE4: input.KeyRightControl,
0xFFE7: input.KeyLeftMeta,
0xFFE8: input.KeyRightMeta,
0xFFE9: input.KeyLeftAlt,
0xFFEA: input.KeyRightAlt,
0xFFEB: input.KeyLeftSuper,
0xFFEC: input.KeyRightSuper,
0xFFED: input.KeyLeftHyper,
0xFFEE: input.KeyRightHyper,
0xFFFF: input.KeyDelete,
0xFFBE: input.KeyF1,
0xFFBF: input.KeyF2,
0xFFC0: input.KeyF3,
0xFFC1: input.KeyF4,
0xFFC2: input.KeyF5,
0xFFC3: input.KeyF6,
0xFFC4: input.KeyF7,
0xFFC5: input.KeyF8,
0xFFC6: input.KeyF9,
0xFFC7: input.KeyF10,
0xFFC8: input.KeyF11,
0xFFC9: input.KeyF12,
0xFF20: input.KeyDead,
}
var keypadCodeTable = map[xproto.Keysym] input.Key {
0xff80: input.Key(' '),
0xff89: input.KeyTab,
0xff8d: input.KeyEnter,
0xff91: input.KeyF1,
0xff92: input.KeyF2,
0xff93: input.KeyF3,
0xff94: input.KeyF4,
0xff95: input.KeyHome,
0xff96: input.KeyLeft,
0xff97: input.KeyUp,
0xff98: input.KeyRight,
0xff99: input.KeyDown,
0xff9a: input.KeyPageUp,
0xff9b: input.KeyPageDown,
0xff9c: input.KeyEnd,
0xff9d: input.KeyHome,
0xff9e: input.KeyInsert,
0xff9f: input.KeyDelete,
0xffbd: input.Key('='),
0xffaa: input.Key('*'),
0xffab: input.Key('+'),
0xffac: input.Key(','),
0xffad: input.Key('-'),
0xffae: input.Key('.'),
0xffaf: input.Key('/'),
0xffb0: input.Key('0'),
0xffb1: input.Key('1'),
0xffb2: input.Key('2'),
0xffb3: input.Key('3'),
0xffb4: input.Key('4'),
0xffb5: input.Key('5'),
0xffb6: input.Key('6'),
0xffb7: input.Key('7'),
0xffb8: input.Key('8'),
0xffb9: input.Key('9'),
}
func (window *window) handleExpose (
connection *xgbutil.XUtil,
event xevent.ExposeEvent,
@ -74,6 +170,80 @@ func (window *window) exposeEventFollows (event xproto.ConfigureNotifyEvent) (fo
return false
}
func keycodeToKey (keycode xproto.Keycode, state uint16) (input.Key, bool) {
keysym, char := xgbkb.KeycodeToKeysym(keycode, state)
if xgbkb.IsOnNumpad(keysym) {
// look up in keypad table
key := keypadCodeTable[keysym]
return key, true
} else {
// look up in control code table
key, isControl := buttonCodeTable[keysym]
if isControl {
return key, false
} else {
// return as rune
return input.Key(char), false
}
}
}
func (window *window) handleKeyPress (
connection *xgbutil.XUtil,
event xevent.KeyPressEvent,
) {
if window.hasModal { return }
keyEvent := *event.KeyPressEvent
key, numberPad := keycodeToKey(keyEvent.Detail, keyEvent.State)
window.updateModifiers(keyEvent.State)
if key == input.KeyTab && window.modifiers.Alt {
if window.modifiers.Shift {
window.focusPrevious()
} else {
window.focusNext()
}
} else if key == input.KeyEscape && window.shy {
window.Close()
} else if window.focused != nil {
window.focused.handleKeyDown(key, numberPad)
}
}
func (window *window) handleKeyRelease (
connection *xgbutil.XUtil,
event xevent.KeyReleaseEvent,
) {
if window.hasModal { return }
keyEvent := *event.KeyReleaseEvent
// do not process this event if it was generated from a key repeat
nextEvents := xevent.Peek(window.backend.x)
if len(nextEvents) > 0 {
untypedEvent := nextEvents[0]
if untypedEvent.Err == nil {
typedEvent, ok :=
untypedEvent.Event.(xproto.KeyPressEvent)
if ok && typedEvent.Detail == keyEvent.Detail &&
typedEvent.Event == keyEvent.Event &&
typedEvent.State == keyEvent.State {
return
}
}
}
key, numberPad := keycodeToKey(keyEvent.Detail, keyEvent.State)
window.updateModifiers(keyEvent.State)
if window.focused != nil {
window.focused.handleKeyUp(key, numberPad)
}
}
func (window *window) handleButtonPress (
connection *xgbutil.XUtil,

View File

@ -48,6 +48,9 @@ type anyBox interface {
boxUnder (image.Point) anyBox
recalculateMinimumSize ()
propagate (func (anyBox) bool) bool
propagateAlt (func (anyBox) bool) bool
handleFocusEnter ()
handleFocusLeave ()
// handleDndEnter ()
@ -59,8 +62,8 @@ type anyBox interface {
handleMouseDown (input.Button)
handleMouseUp (input.Button)
// handleScroll (float64, float64)
// handleKeyDown (input.Key, bool)
// handleKeyUp (input.Key, bool)
handleKeyDown (input.Key, bool)
handleKeyUp (input.Key, bool)
}
func assertAnyBox (unknown tomo.Box) anyBox {
@ -119,17 +122,68 @@ func (window *window) focus (box anyBox) {
window.invalidateDraw(previous)
previous.handleFocusLeave()
}
if box != nil {
if box != nil && box.canBeFocused() {
window.invalidateDraw(box)
box.handleFocusEnter()
}
}
func (window *window) anyFocused () bool {
return window.focused != nil
}
func (this *window) boxUnder (point image.Point) anyBox {
if this.root == nil { return nil }
return this.root.boxUnder(point)
}
func (this *window) focusNext () {
found := !this.anyFocused()
focused := false
this.propagateAlt (func (box anyBox) bool {
if found {
// looking for the next box to select
if box.canBeFocused() {
// found it
this.focus(box)
focused = true
return false
}
} else {
// looking for the current focused element
if box == this.focused {
// found it
found = true
}
}
return true
})
if !focused { this.focus(nil) }
}
func (this *window) focusPrevious () {
var behind anyBox
this.propagate (func (box anyBox) bool {
if box == this.focused {
return false
}
if box.canBeFocused() { behind = box }
return true
})
this.focus(behind)
}
func (this *window) propagate (callback func (box anyBox) bool) {
if this.root == nil { return }
this.root.propagate(callback)
}
func (this *window) propagateAlt (callback func (box anyBox) bool) {
if this.root == nil { return }
this.root.propagateAlt(callback)
}
func (window *window) afterEvent () {
if window.xCanvas == nil { return }

View File

@ -109,10 +109,10 @@ func (backend *Backend) newWindow (
Connect(backend.x, window.xWindow.Id)
xevent.ConfigureNotifyFun(window.handleConfigureNotify).
Connect(backend.x, window.xWindow.Id)
// xevent.KeyPressFun(window.handleKeyPress).
// Connect(backend.x, window.xWindow.Id)
// xevent.KeyReleaseFun(window.handleKeyRelease).
// Connect(backend.x, window.xWindow.Id)
xevent.KeyPressFun(window.handleKeyPress).
Connect(backend.x, window.xWindow.Id)
xevent.KeyReleaseFun(window.handleKeyRelease).
Connect(backend.x, window.xWindow.Id)
xevent.ButtonPressFun(window.handleButtonPress).
Connect(backend.x, window.xWindow.Id)
xevent.ButtonReleaseFun(window.handleButtonRelease).