protected override void Initialize() { _xkbContext = XkbCommon.xkb_context_new(); if (_xkbContext == null) { throw new OpenWindowException("Failed to create xkbcommon context."); } LogDebug("Connecting to display..."); _wlDisplay = WlDisplay.Connect(); if (_wlDisplay.IsNull) { var error = WaylandClient.wl_display_get_error(null); throw new OpenWindowException($"Failed to connect to Wayland display ({error})."); } _wlDisplay.SetListener(DisplayErrorCallback, null); LogDebug("Connected to display."); WaylandBindings.Load(); XdgShellBindings.Load(); XdgDecorationUnstableV1Bindings.Load(); ViewporterBindings.Load(); _wlRegistry = _wlDisplay.GetRegistry(); if (_wlRegistry.IsNull) { throw new OpenWindowException("Failed to get Wayland registry."); } LogDebug("Got registry."); _wlRegistry.SetListener(RegistryGlobalCallback, RegistryGlobalRemoveCallback); LogDebug("Initiating first display roundtrip."); _wlDisplay.Roundtrip(); LogDebug("Initiating second display roundtrip."); _wlDisplay.Roundtrip(); if (_wlCompositor.IsNull) { throw new OpenWindowException("Server did not advertise a compositor."); } if (_xdgWmBase.IsNull) { if (_wlShellAvailable) { LogError("Server did not advertise xdg_wm_base, but it advertised a wl_shell. wl_shell is deprecated and not supported by OpenWindow."); } throw new OpenWindowException("Server did not advertise xdg_wm_base."); } }
private void KeymapCallback(void *data, wl_keyboard *proxy, wl_keyboard_keymap_format format, int fd, uint size) { if (format != wl_keyboard_keymap_format.XkbV1) { Libc.close(fd); throw new NotImplementedException("Only xkbcommon compatible keymaps are currently supported."); } var kbdStr = Libc.mmap(null, size, Libc.PROT_READ, Libc.MAP_PRIVATE, fd, 0); if (kbdStr == null) { Libc.close(fd); return; } var newKeymap = XkbCommon.xkb_keymap_new_from_string(_xkbContext, kbdStr, XkbCommon.XKB_KEYMAP_FORMAT_TEXT_V1); Libc.munmap(kbdStr, size); Libc.close(fd); if (newKeymap == null) { throw new OpenWindowException("Failed to create xkb keymap."); } var newState = XkbCommon.xkb_state_new(newKeymap); if (newState == null) { XkbCommon.xkb_keymap_unref(newKeymap); throw new OpenWindowException("Failed to create xkb state."); } if (_xkbKeymap != null) { XkbCommon.xkb_keymap_unref(_xkbKeymap); } if (_xkbState != null) { XkbCommon.xkb_state_unref(_xkbState); } _xkbKeymap = newKeymap; _xkbState = newState; UpdateKeymap(); }
private void KeyboardKeyCallback(void *data, wl_keyboard *proxy, uint serial, uint time, uint lsc, wl_keyboard_key_state state) { if (lsc >= WaylandKeyMaps.LinuxToOwScanCode.Length) { return; } var osc = WaylandKeyMaps.LinuxToOwScanCode[lsc]; SetKey(osc, state == wl_keyboard_key_state.Pressed); if (state == wl_keyboard_key_state.Released) { return; } // this returns zero if the key press generates more than 1 character in UTF32 var utf32 = XkbCommon.xkb_state_key_get_utf32(_xkbState, lsc + 8); if (utf32 != 0) { SendCharacter(utf32); } else { var strBufSize = XkbCommon.xkb_state_key_get_utf8(_xkbState, lsc + 8, null, 0); if (strBufSize == 0) { return; } byte *strBuf = stackalloc byte[strBufSize]; XkbCommon.xkb_state_key_get_utf8(_xkbState, lsc + 8, strBuf, strBufSize); // We send text in UTF-32 i.e. no more than 32 bits at a time var offset = 0; while (ReadUtf32FromUtf8(strBuf, ref offset, out utf32)) { SendCharacter(utf32); } } }
private void UpdateKeymap() { for (var lsc = 0; lsc < WaylandKeyMaps.LinuxToOwScanCode.Length; lsc++) { var osc = WaylandKeyMaps.LinuxToOwScanCode[lsc]; if (osc == ScanCode.Unknown) { continue; } var sym = XkbCommon.xkb_state_key_get_one_sym(_xkbState, (uint)(lsc + 8)); var owk = WaylandKeyMaps.XkbToOwKey(sym); if (owk == Key.Unknown) { continue; } _keyboardState.Set(osc, owk); } _keyboardState.Set(ScanCode.PrintScreen, Key.PrintScreen); }