github.com/rajveermalviya/gamen@v0.1.2-0.20220930195403-9be15877c1aa/internal/wayland/keyboard.go (about)

     1  //go:build linux && !android
     2  
     3  package wayland
     4  
     5  /*
     6  
     7  #include <stdlib.h>
     8  #include "wayland-client-protocol.h"
     9  
    10  */
    11  import "C"
    12  
    13  import (
    14  	"log"
    15  	"runtime/cgo"
    16  	"time"
    17  	"unsafe"
    18  
    19  	"github.com/rajveermalviya/gamen/events"
    20  	"github.com/rajveermalviya/gamen/internal/xkbcommon"
    21  	"golang.org/x/sys/unix"
    22  )
    23  
    24  type Keyboard struct {
    25  	d        *Display
    26  	keyboard *C.struct_wl_keyboard
    27  
    28  	// from repeat_info event
    29  	haveServerRepeat  bool
    30  	serverRepeatRate  uint32
    31  	serverRepeatDelay time.Duration
    32  
    33  	// some state to handle key repeats
    34  	// key that was pressed
    35  	repeatKey uint32
    36  	// time when key was first pressed
    37  	repeatKeyStartTime time.Time
    38  	// time when we sent the last synthetic key press event
    39  	repeatKeyLastSendTime time.Time
    40  
    41  	// which surface has keyboard focus
    42  	focus *C.struct_wl_surface
    43  
    44  	modifiers events.ModifiersState
    45  }
    46  
    47  func (k *Keyboard) destroy() {
    48  	if k.keyboard != nil {
    49  		k.d.l.wl_keyboard_destroy(k.keyboard)
    50  		k.keyboard = nil
    51  	}
    52  }
    53  
    54  //export keyboardHandleKeymap
    55  func keyboardHandleKeymap(data unsafe.Pointer, wl_keyboard *C.struct_wl_keyboard, format C.uint32_t, fd C.int32_t, size C.uint32_t) {
    56  	defer unix.Close(int(fd))
    57  
    58  	ev, ok := (*cgo.Handle)(data).Value().(*Display)
    59  	if !ok {
    60  		return
    61  	}
    62  
    63  	if ev.xkb == nil {
    64  		return
    65  	}
    66  
    67  	buf, err := unix.Mmap(int(fd), 0, int(size), unix.PROT_READ, unix.MAP_SHARED)
    68  	if err != nil {
    69  		log.Printf("failed to mmap keymap: %v\n", err)
    70  		return
    71  	}
    72  	defer unix.Munmap(buf)
    73  
    74  	err = ev.xkb.KeymapFromBuffer(buf)
    75  	if err != nil {
    76  		log.Printf("failed to create keymap from buffer: %v\n", err)
    77  		return
    78  	}
    79  }
    80  
    81  //export keyboardHandleEnter
    82  func keyboardHandleEnter(data unsafe.Pointer, wl_keyboard *C.struct_wl_keyboard, serial C.uint32_t, surface *C.struct_wl_surface, keys *C.struct_wl_array) {
    83  	d, ok := (*cgo.Handle)(data).Value().(*Display)
    84  	if !ok {
    85  		return
    86  	}
    87  	k := d.keyboard
    88  
    89  	k.focus = surface
    90  
    91  	w, ok := d.windows[surface]
    92  	if !ok {
    93  		return
    94  	}
    95  
    96  	if cb := w.focusedCb.Load(); cb != nil {
    97  		if cb := (*cb); cb != nil {
    98  			cb()
    99  		}
   100  	}
   101  
   102  	// send modifiers that are already pressed
   103  	if k.modifiers != 0 {
   104  		if cb := w.modifiersChangedCb.Load(); cb != nil {
   105  			if cb := (*cb); cb != nil {
   106  				cb(k.modifiers)
   107  			}
   108  		}
   109  	}
   110  }
   111  
   112  //export keyboardHandleLeave
   113  func keyboardHandleLeave(data unsafe.Pointer, wl_keyboard *C.struct_wl_keyboard, serial C.uint32_t, surface *C.struct_wl_surface) {
   114  	d, ok := (*cgo.Handle)(data).Value().(*Display)
   115  	if !ok {
   116  		return
   117  	}
   118  	k := d.keyboard
   119  
   120  	w, ok := d.windows[surface]
   121  	if !ok {
   122  		return
   123  	}
   124  
   125  	// remove modifiers if pressed
   126  	if k.modifiers != 0 {
   127  		if cb := w.modifiersChangedCb.Load(); cb != nil {
   128  			if cb := (*cb); cb != nil {
   129  				cb(0)
   130  			}
   131  		}
   132  	}
   133  
   134  	if cb := w.unfocusedCb.Load(); cb != nil {
   135  		if cb := (*cb); cb != nil {
   136  			cb()
   137  		}
   138  	}
   139  
   140  	k.repeatKey = 0
   141  	k.focus = nil
   142  }
   143  
   144  //export keyboardHandleKey
   145  func keyboardHandleKey(data unsafe.Pointer, wl_keyboard *C.struct_wl_keyboard, serial C.uint32_t, _time C.uint32_t, key C.uint32_t, state enum_wl_keyboard_key_state) {
   146  	d, ok := (*cgo.Handle)(data).Value().(*Display)
   147  	if !ok {
   148  		return
   149  	}
   150  
   151  	xkb := d.xkb
   152  	if xkb == nil {
   153  		return
   154  	}
   155  
   156  	k := d.keyboard
   157  	if k.focus == nil {
   158  		return
   159  	}
   160  
   161  	now := time.Now()
   162  	k.repeatKeyStartTime = now
   163  	k.repeatKeyLastSendTime = now
   164  	if state == WL_KEYBOARD_KEY_STATE_RELEASED && k.repeatKey == uint32(key) {
   165  		k.repeatKey = 0
   166  	}
   167  
   168  	k.handleKeyEvent(key, state)
   169  
   170  	if state == WL_KEYBOARD_KEY_STATE_PRESSED && xkb.KeyRepeats(xkbcommon.KeyCode(key+8)) {
   171  		k.repeatKey = uint32(key)
   172  		k.repeatKeyStartTime = time.Now()
   173  		k.repeatKeyLastSendTime = k.repeatKeyStartTime
   174  	}
   175  }
   176  
   177  func (k *Keyboard) handleKeyEvent(key C.uint32_t, state enum_wl_keyboard_key_state) {
   178  	xkb := k.d.xkb
   179  	w, ok := k.d.windows[k.focus]
   180  	if !ok {
   181  		return
   182  	}
   183  
   184  	key += 8
   185  	sym := xkb.GetOneSym(xkbcommon.KeyCode(key))
   186  
   187  	if cb := w.keyboardInputCb.Load(); cb != nil {
   188  		if cb := (*cb); cb != nil {
   189  			var buttonState events.ButtonState
   190  			switch state {
   191  			case WL_KEYBOARD_KEY_STATE_PRESSED:
   192  				buttonState = events.ButtonStatePressed
   193  			case WL_KEYBOARD_KEY_STATE_RELEASED:
   194  				buttonState = events.ButtonStateReleased
   195  			}
   196  
   197  			cb(
   198  				buttonState,
   199  				events.ScanCode(key),
   200  				xkbcommon.KeySymToVirtualKey(sym),
   201  			)
   202  		}
   203  	}
   204  
   205  	if state == WL_KEYBOARD_KEY_STATE_PRESSED {
   206  		if cb := w.receivedCharacterCb.Load(); cb != nil {
   207  			if cb := (*cb); cb != nil {
   208  				utf8 := xkb.GetUtf8(xkbcommon.KeyCode(key), xkbcommon.KeySym(sym))
   209  				for _, char := range utf8 {
   210  					cb(char)
   211  				}
   212  			}
   213  		}
   214  	}
   215  }
   216  
   217  //export keyboardHandleModifiers
   218  func keyboardHandleModifiers(data unsafe.Pointer, wl_keyboard *C.struct_wl_keyboard, serial C.uint32_t, mods_depressed C.uint32_t, mods_latched C.uint32_t, mods_locked C.uint32_t, group C.uint32_t) {
   219  	d, ok := (*cgo.Handle)(data).Value().(*Display)
   220  	if !ok {
   221  		return
   222  	}
   223  	k := d.keyboard
   224  
   225  	if d.xkb == nil {
   226  		return
   227  	}
   228  
   229  	if d.xkb.UpdateMask(
   230  		xkbcommon.ModMask(mods_depressed),
   231  		xkbcommon.ModMask(mods_latched),
   232  		xkbcommon.ModMask(mods_locked),
   233  		0,
   234  		0,
   235  		xkbcommon.LayoutIndex(group),
   236  	) {
   237  		return
   238  	}
   239  
   240  	var m events.ModifiersState
   241  
   242  	if d.xkb.ModIsShift() {
   243  		m |= events.ModifiersStateShift
   244  	}
   245  	if d.xkb.ModIsCtrl() {
   246  		m |= events.ModifiersStateCtrl
   247  	}
   248  	if d.xkb.ModIsAlt() {
   249  		m |= events.ModifiersStateAlt
   250  	}
   251  	if d.xkb.ModIsLogo() {
   252  		m |= events.ModifiersStateLogo
   253  	}
   254  
   255  	k.modifiers = m
   256  
   257  	if k.focus == nil {
   258  		return
   259  	}
   260  
   261  	w, ok := d.windows[k.focus]
   262  	if !ok {
   263  		return
   264  	}
   265  
   266  	if cb := w.modifiersChangedCb.Load(); cb != nil {
   267  		if cb := (*cb); cb != nil {
   268  			cb(m)
   269  		}
   270  	}
   271  }
   272  
   273  //export keyboardHandleRepeatInfo
   274  func keyboardHandleRepeatInfo(data unsafe.Pointer, wl_keyboard *C.struct_wl_keyboard, rate C.int32_t, delay C.int32_t) {
   275  	d, ok := (*cgo.Handle)(data).Value().(*Display)
   276  	if !ok {
   277  		return
   278  	}
   279  
   280  	k := d.keyboard
   281  
   282  	k.haveServerRepeat = true
   283  	k.serverRepeatRate = uint32(rate)
   284  	k.serverRepeatDelay = time.Duration(delay) * time.Millisecond
   285  }