Skip to content

Commit

Permalink
X11 shell keyboard mapping (#1779)
Browse files Browse the repository at this point in the history
* x11 shell keyboard mapping

* allow deref_nullptr in tests

* [CI] install libxkbcommon for Docs

* More keys for x11

* More keys for gtk

* cache looked up mods names and avoid as *mut i8

* Apply suggestions from code review

* Move keycodes to a separate file

* allow non_upper_case_globals in keycodes.rs

* using cfg(target_os) in build scripts is *wrong*

see <rust-lang/cargo#4932>

* UnsafeCell is not needed

UnsafeCell is used to provide `*mut T` through `&T` but we already
have `*mut T`

* Update CHANGELOG
  • Loading branch information
maan2003 committed Aug 15, 2021
1 parent f053464 commit dfe8eed
Show file tree
Hide file tree
Showing 11 changed files with 747 additions and 279 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ jobs:
- name: install libgtk-dev
run: |
sudo apt update
sudo apt install libgtk-3-dev
sudo apt install libgtk-3-dev libxkbcommon-dev libxkbcommon-x11-dev
if: contains(matrix.os, 'ubuntu')

- name: install stable toolchain
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ You can find its changes [documented below](#070---2021-01-01).
- `Slider` widget now warns if max < min and swaps the values ([#1882] by [@Maan2003])
- Widget/Slider: Add stepping functionality ([#1875] by [@raymanfx])
- Add #[data(eq)] shorthand attribute for Data derive macro ([#1884] by [@Maan2003])
- X11: detect keyboard layout ([#1779] by [@Maan2003])

### Changed

Expand Down Expand Up @@ -750,6 +751,7 @@ Last release without a changelog :(
[#1761]: https://github.com/linebender/druid/pull/1761
[#1764]: https://github.com/linebender/druid/pull/1764
[#1772]: https://github.com/linebender/druid/pull/1772
[#1779]: https://github.com/linebender/druid/pull/1779
[#1787]: https://github.com/linebender/druid/pull/1787
[#1801]: https://github.com/linebender/druid/pull/1800
[#1802]: https://github.com/linebender/druid/pull/1802
Expand Down
8 changes: 6 additions & 2 deletions druid-shell/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ default-target = "x86_64-pc-windows-msvc"
[features]
default = ["gtk"]
gtk = ["gio", "gdk", "gdk-sys", "glib", "glib-sys", "gtk-sys", "gtk-rs", "gdk-pixbuf"]
x11 = ["x11rb", "nix", "cairo-sys-rs"]
x11 = ["x11rb", "nix", "cairo-sys-rs", "bindgen", "pkg-config"]
# Implement HasRawWindowHandle for WindowHandle
raw-win-handle = ["raw-window-handle"]

Expand Down Expand Up @@ -89,7 +89,7 @@ glib = { version = "0.10.1", optional = true }
glib-sys = { version = "0.10.0", optional = true }
gtk-sys = { version = "0.10.0", optional = true }
nix = { version = "0.18.0", optional = true }
x11rb = { version = "0.8.0", features = ["allow-unsafe-code", "present", "render", "randr", "xfixes", "resource_manager", "cursor"], optional = true }
x11rb = { version = "0.8.0", features = ["allow-unsafe-code", "present", "render", "randr", "xfixes", "xkb", "resource_manager", "cursor"], optional = true }

[target.'cfg(target_arch="wasm32")'.dependencies]
wasm-bindgen = "0.2.67"
Expand All @@ -105,3 +105,7 @@ static_assertions = "1.1.0"
test-env-log = { version = "0.2.5", features = ["trace"], default-features = false }
tracing-subscriber = "0.2.15"
unicode-segmentation = "1.7.0"

[build-dependencies]
bindgen = {version = "0.58", optional = true}
pkg-config = { version = "0.3", optional = true }
51 changes: 51 additions & 0 deletions druid-shell/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#[cfg(not(feature = "x11"))]
fn main() {}

#[cfg(feature = "x11")]
fn main() {
use pkg_config::probe_library;
use std::env;
use std::path::PathBuf;

if env::var("CARGO_CFG_TARGET_OS").unwrap() != "linux" {
return;
}

probe_library("xkbcommon").unwrap();
probe_library("xkbcommon-x11").unwrap();

let bindings = bindgen::Builder::default()
// The input header we would like to generate
// bindings for.
.header_contents(
"wrapper.h",
"\
#include <xkbcommon/xkbcommon-compose.h>
#include <xkbcommon/xkbcommon-names.h>
#include <xkbcommon/xkbcommon-x11.h>
#include <xkbcommon/xkbcommon.h>",
)
// Tell cargo to invalidate the built crate whenever any of the
// included header files changed.
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
.prepend_enum_name(false)
.size_t_is_usize(true)
.allowlist_function("xkb_.*")
.allowlist_type("xkb_.*")
.allowlist_var("XKB_.*")
.allowlist_type("xcb_connection_t")
// this needs var args
.blocklist_function("xkb_context_set_log_fn")
// we use FILE from libc
.blocklist_type("FILE")
.blocklist_type("va_list")
.blocklist_type("_.*")
.generate()
.expect("Unable to generate bindings");

// Write the bindings to the $OUT_DIR/xkbcommon.rs file.
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("xkbcommon_sys.rs"))
.expect("Couldn't write bindings!");
}
229 changes: 174 additions & 55 deletions druid-shell/src/backend/gtk/keycodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,65 @@ pub type RawKey = gdk::keys::Key;

#[allow(clippy::just_underscores_and_digits, non_upper_case_globals)]
pub fn raw_key_to_key(raw: RawKey) -> Option<Key> {
// changes from x11 backend keycodes:
// * XKB_KEY_ prefix removed
// * 3270 is replaced with _3270
// * XF86 prefix is removed
// * Sun* Keys are gone
Some(match raw {
Escape => Key::Escape,
BackSpace => Key::Backspace,
Tab | ISO_Left_Tab => Key::Tab,
Return => Key::Enter,
Control_L | Control_R => Key::Control,
Alt_L | Alt_R => Key::Alt,
Shift_L | Shift_R => Key::Shift,
// TODO: investigate mapping. Map Meta_[LR]?
Super_L | Super_R => Key::Meta,
Caps_Lock => Key::CapsLock,
F1 => Key::F1,
F2 => Key::F2,
F3 => Key::F3,
F4 => Key::F4,
Tab | KP_Tab | ISO_Left_Tab => Key::Tab,
Clear | KP_Begin => Key::Clear,
Return | KP_Enter => Key::Enter,
Linefeed => Key::Enter,
Pause => Key::Pause,
Scroll_Lock => Key::ScrollLock,
Escape => Key::Escape,
Multi_key => Key::Compose,
Kanji => Key::KanjiMode,
Muhenkan => Key::NonConvert,
Henkan_Mode => Key::Convert,
Romaji => Key::Romaji,
Hiragana => Key::Hiragana,
Katakana => Key::Katakana,
Hiragana_Katakana => Key::HiraganaKatakana,
Zenkaku => Key::Zenkaku,
Hankaku => Key::Hankaku,
Zenkaku_Hankaku => Key::ZenkakuHankaku,
Kana_Lock => Key::KanaMode,
Eisu_Shift | Eisu_toggle => Key::Alphanumeric,
Hangul => Key::HangulMode,
Hangul_Hanja => Key::HanjaMode,
Codeinput => Key::CodeInput,
SingleCandidate => Key::SingleCandidate,
MultipleCandidate => Key::AllCandidates,
PreviousCandidate => Key::PreviousCandidate,
Home | KP_Home => Key::Home,
Left | KP_Left => Key::ArrowLeft,
Up | KP_Up => Key::ArrowUp,
Right | KP_Right => Key::ArrowRight,
Down | KP_Down => Key::ArrowDown,
Prior | KP_Prior => Key::PageUp,
Next | KP_Next => Key::PageDown,
End | KP_End => Key::End,
Select => Key::Select,
// Treat Print/PrintScreen as PrintScreen https://crbug.com/683097.
Print | _3270_PrintScreen => Key::PrintScreen,
Execute => Key::Execute,
Insert | KP_Insert => Key::Insert,
Undo => Key::Undo,
Redo => Key::Redo,
Menu => Key::ContextMenu,
Find => Key::Find,
Cancel => Key::Cancel,
Help => Key::Help,
Break | _3270_Attn => Key::Attn,
Mode_switch => Key::ModeChange,
Num_Lock => Key::NumLock,
F1 | KP_F1 => Key::F1,
F2 | KP_F2 => Key::F2,
F3 | KP_F3 => Key::F3,
F4 | KP_F4 => Key::F4,
F5 => Key::F5,
F6 => Key::F6,
F7 => Key::F7,
Expand All @@ -46,51 +90,126 @@ pub fn raw_key_to_key(raw: RawKey) -> Option<Key> {
F10 => Key::F10,
F11 => Key::F11,
F12 => Key::F12,

Print => Key::PrintScreen,
Scroll_Lock => Key::ScrollLock,
// Pause/Break not audio.
Pause => Key::Pause,

Insert => Key::Insert,
// not available in keyboard-types
// Tools | F13 => Key::F13,
// F14 | Launch5 => Key::F14,
// F15 | Launch6 => Key::F15,
// F16 | Launch7 => Key::F16,
// F17 | Launch8 => Key::F17,
// F18 | Launch9 => Key::F18,
// F19 => Key::F19,
// F20 => Key::F20,
// F21 => Key::F21,
// F22 => Key::F22,
// F23 => Key::F23,
// F24 => Key::F24,
// Calculator => Key::LaunchCalculator,
// MyComputer | Explorer => Key::LaunchMyComputer,
// ISO_Level3_Latch => Key::AltGraphLatch,
// ISO_Level5_Shift => Key::ShiftLevel5,
Shift_L | Shift_R => Key::Shift,
Control_L | Control_R => Key::Control,
Caps_Lock => Key::CapsLock,
Meta_L | Meta_R => Key::Meta,
Alt_L | Alt_R => Key::Alt,
Super_L | Super_R => Key::Meta,
Hyper_L | Hyper_R => Key::Hyper,
Delete => Key::Delete,
Home => Key::Home,
End => Key::End,
Page_Up => Key::PageUp,
Page_Down => Key::PageDown,
Num_Lock => Key::NumLock,

Up => Key::ArrowUp,
Down => Key::ArrowDown,
Left => Key::ArrowLeft,
Right => Key::ArrowRight,
Clear => Key::Clear,

Menu => Key::ContextMenu,
Next_VMode => Key::VideoModeNext,
MonBrightnessUp => Key::BrightnessUp,
MonBrightnessDown => Key::BrightnessDown,
Standby | Sleep | Suspend => Key::Standby,
AudioLowerVolume => Key::AudioVolumeDown,
AudioMute => Key::AudioVolumeMute,
AudioRaiseVolume => Key::AudioVolumeUp,
AudioPlay => Key::MediaPlayPause,
AudioStop => Key::MediaStop,
AudioPrev => Key::MediaTrackPrevious,
AudioNext => Key::MediaTrackNext,
HomePage => Key::BrowserHome,
Mail => Key::LaunchMail,
Search => Key::BrowserSearch,
AudioRecord => Key::MediaRecord,
Calendar => Key::LaunchCalendar,
Back => Key::BrowserBack,
Forward => Key::BrowserForward,
Stop => Key::BrowserStop,
Refresh | Reload => Key::BrowserRefresh,
PowerOff => Key::PowerOff,
WakeUp => Key::WakeUp,
Launch0 => Key::LaunchApplication1,
Launch1 => Key::LaunchApplication2,
Eject => Key::Eject,
ScreenSaver => Key::LaunchScreenSaver,
WWW => Key::LaunchWebBrowser,
Favorites => Key::BrowserFavorites,
AudioPause => Key::MediaPause,
AudioMedia | Music => Key::LaunchMusicPlayer,
AudioRewind => Key::MediaRewind,
CD | Video => Key::LaunchMediaPlayer,
Close => Key::Close,
Copy => Key::Copy,
Cut => Key::Cut,
Display => Key::DisplaySwap,
Excel => Key::LaunchSpreadsheet,
LogOff => Key::LogOff,
New => Key::New,
Open => Key::Open,
Paste => Key::Paste,
Reply => Key::MailReply,
Save => Key::Save,
Send => Key::MailSend,
Spell => Key::SpellCheck,
SplitScreen => Key::SplitScreenToggle,
Word | OfficeHome => Key::LaunchWordProcessor,
ZoomIn => Key::ZoomIn,
ZoomOut => Key::ZoomOut,
WebCam => Key::LaunchWebCam,
MailForward => Key::MailForward,
AudioForward => Key::MediaFastForward,
AudioRandomPlay => Key::RandomToggle,
Subtitle => Key::Subtitle,
Hibernate => Key::Hibernate,
_3270_EraseEOF => Key::EraseEof,
_3270_Play => Key::Play,
_3270_ExSelect => Key::ExSel,
_3270_CursorSelect => Key::CrSel,
ISO_Level3_Shift => Key::AltGraph,

KP_Begin => Key::Clear,
KP_Delete => Key::Delete,
KP_Down => Key::ArrowDown,
KP_End => Key::End,
KP_Enter => Key::Enter,
KP_F1 => Key::F1,
KP_F2 => Key::F2,
KP_F3 => Key::F3,
KP_F4 => Key::F4,
KP_Home => Key::Home,
KP_Insert => Key::Insert,
KP_Left => Key::ArrowLeft,
KP_Page_Down => Key::PageDown,
KP_Page_Up => Key::PageUp,
KP_Right => Key::ArrowRight,
// KP_Separator? What does it map to?
KP_Tab => Key::Tab,
KP_Up => Key::ArrowUp,
// TODO: more mappings (media etc)
ISO_Next_Group => Key::GroupNext,
ISO_Prev_Group => Key::GroupPrevious,
ISO_First_Group => Key::GroupFirst,
ISO_Last_Group => Key::GroupLast,
dead_grave
| dead_acute
| dead_circumflex
| dead_tilde
| dead_macron
| dead_breve
| dead_abovedot
| dead_diaeresis
| dead_abovering
| dead_doubleacute
| dead_caron
| dead_cedilla
| dead_ogonek
| dead_iota
| dead_voiced_sound
| dead_semivoiced_sound
| dead_belowdot
| dead_hook
| dead_horn
| dead_stroke
| dead_abovecomma
| dead_abovereversedcomma
| dead_doublegrave
| dead_belowring
| dead_belowmacron
| dead_belowcircumflex
| dead_belowtilde
| dead_belowbreve
| dead_belowdiaeresis
| dead_invertedbreve
| dead_belowcomma
| dead_currency
| dead_greek => Key::Dead,
_ => return None,
})
}
Expand Down
Loading

0 comments on commit dfe8eed

Please sign in to comment.