diff --git a/.changes/expose-keyboard-inputs.md b/.changes/expose-keyboard-inputs.md
new file mode 100644
index 000000000000..209bc4582d72
--- /dev/null
+++ b/.changes/expose-keyboard-inputs.md
@@ -0,0 +1,5 @@
+---
+tauri: 'minor:feat'
+---
+
+Expose window keyboard events from `tao`, as `WindowEvent::KeyboardInput`.
diff --git a/Cargo.lock b/Cargo.lock
index 28031d69f68f..32a2e03dc9a1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -9395,6 +9395,7 @@ dependencies = [
"gtk",
"http 1.2.0",
"jni",
+ "keyboard-types",
"raw-window-handle",
"serde",
"serde_json",
diff --git a/crates/tauri-runtime-wry/src/keyboard.rs b/crates/tauri-runtime-wry/src/keyboard.rs
new file mode 100644
index 000000000000..2ba533b81601
--- /dev/null
+++ b/crates/tauri-runtime-wry/src/keyboard.rs
@@ -0,0 +1,559 @@
+use tao::{
+ event::{ElementState as TaoElementState, KeyEvent as TaoKeyEvent},
+ keyboard::{Key as TaoKey, KeyCode as TaoKeyCode, KeyLocation as TaoKeyLocation},
+};
+use tauri_runtime::keyboard::{Code, Key, KeyState, KeyboardEvent, Location};
+
+pub(crate) fn convert_key_event(event: &TaoKeyEvent) -> KeyboardEvent {
+ let state = convert_key_state(&event.state).expect("Unsupported key state");
+ let key = convert_key(&event.logical_key);
+ let code = convert_key_code(&event.physical_key);
+ let location = convert_location(&event.location).expect("Unsupported key location");
+
+ KeyboardEvent {
+ state,
+ key,
+ code,
+ location,
+ repeat: event.repeat,
+ }
+}
+
+fn convert_key(key: &TaoKey<'_>) -> Key {
+ match key {
+ TaoKey::Character(c) => Key::Character(c.to_string()),
+ TaoKey::Unidentified(_) => Key::Unidentified,
+ TaoKey::Dead(_) => Key::Dead,
+ TaoKey::Alt => Key::Alt,
+ TaoKey::AltGraph => Key::AltGraph,
+ TaoKey::CapsLock => Key::CapsLock,
+ TaoKey::Control => Key::Control,
+ TaoKey::Fn => Key::Fn,
+ TaoKey::FnLock => Key::FnLock,
+ TaoKey::NumLock => Key::NumLock,
+ TaoKey::ScrollLock => Key::ScrollLock,
+ TaoKey::Shift => Key::Shift,
+ TaoKey::Symbol => Key::Symbol,
+ TaoKey::SymbolLock => Key::SymbolLock,
+ TaoKey::Hyper => Key::Hyper,
+ // What Tao calls super, the web at calls meta.
+ // It's the key that represents the Windows logo on Windows, and the Command key (⌘) on Mac.
+ TaoKey::Super => Key::Meta,
+ TaoKey::Enter => Key::Enter,
+ TaoKey::Tab => Key::Tab,
+ // TaoKey has space, but Key does not.
+ // According to whitespace is encoded as regular
+ // strings, and so we convert to Key::Character here with a space value.
+ TaoKey::Space => Key::Character(String::from("\u{0020}")),
+ TaoKey::ArrowDown => Key::ArrowDown,
+ TaoKey::ArrowLeft => Key::ArrowLeft,
+ TaoKey::ArrowRight => Key::ArrowRight,
+ TaoKey::ArrowUp => Key::ArrowUp,
+ TaoKey::End => Key::End,
+ TaoKey::Home => Key::Home,
+ TaoKey::PageDown => Key::PageDown,
+ TaoKey::PageUp => Key::PageUp,
+ TaoKey::Backspace => Key::Backspace,
+ TaoKey::Clear => Key::Clear,
+ TaoKey::Copy => Key::Copy,
+ TaoKey::Cut => Key::Cut,
+ TaoKey::Delete => Key::Delete,
+ TaoKey::EraseEof => Key::EraseEof,
+ TaoKey::ExSel => Key::ExSel,
+ TaoKey::Insert => Key::Insert,
+ TaoKey::Paste => Key::Paste,
+ TaoKey::Redo => Key::Redo,
+ TaoKey::Undo => Key::Undo,
+ TaoKey::Accept => Key::Accept,
+ TaoKey::Again => Key::Again,
+ TaoKey::Attn => Key::Attn,
+ TaoKey::Cancel => Key::Cancel,
+ TaoKey::ContextMenu => Key::ContextMenu,
+ TaoKey::Escape => Key::Escape,
+ TaoKey::Execute => Key::Execute,
+ TaoKey::Find => Key::Find,
+ TaoKey::Help => Key::Help,
+ TaoKey::Pause => Key::Pause,
+ TaoKey::Play => Key::Play,
+ TaoKey::Props => Key::Props,
+ TaoKey::Select => Key::Select,
+ TaoKey::ZoomIn => Key::ZoomIn,
+ TaoKey::ZoomOut => Key::ZoomOut,
+ TaoKey::BrightnessDown => Key::BrightnessDown,
+ TaoKey::BrightnessUp => Key::BrightnessUp,
+ TaoKey::Eject => Key::Eject,
+ TaoKey::LogOff => Key::LogOff,
+ TaoKey::Power => Key::Power,
+ TaoKey::PowerOff => Key::PowerOff,
+ TaoKey::PrintScreen => Key::PrintScreen,
+ TaoKey::Hibernate => Key::Hibernate,
+ TaoKey::Standby => Key::Standby,
+ TaoKey::WakeUp => Key::WakeUp,
+ TaoKey::AllCandidates => Key::AllCandidates,
+ TaoKey::Alphanumeric => Key::Alphanumeric,
+ TaoKey::CodeInput => Key::CodeInput,
+ TaoKey::Compose => Key::Compose,
+ TaoKey::Convert => Key::Convert,
+ TaoKey::FinalMode => Key::FinalMode,
+ TaoKey::GroupFirst => Key::GroupFirst,
+ TaoKey::GroupLast => Key::GroupLast,
+ TaoKey::GroupNext => Key::GroupNext,
+ TaoKey::GroupPrevious => Key::GroupPrevious,
+ TaoKey::ModeChange => Key::ModeChange,
+ TaoKey::NextCandidate => Key::NextCandidate,
+ TaoKey::NonConvert => Key::NonConvert,
+ TaoKey::PreviousCandidate => Key::PreviousCandidate,
+ TaoKey::Process => Key::Process,
+ TaoKey::SingleCandidate => Key::SingleCandidate,
+ TaoKey::HangulMode => Key::HangulMode,
+ TaoKey::HanjaMode => Key::HanjaMode,
+ TaoKey::JunjaMode => Key::JunjaMode,
+ TaoKey::Eisu => Key::Eisu,
+ TaoKey::Hankaku => Key::Hankaku,
+ TaoKey::Hiragana => Key::Hiragana,
+ TaoKey::HiraganaKatakana => Key::HiraganaKatakana,
+ TaoKey::KanaMode => Key::KanaMode,
+ TaoKey::KanjiMode => Key::KanjiMode,
+ TaoKey::Katakana => Key::Katakana,
+ TaoKey::Romaji => Key::Romaji,
+ TaoKey::Zenkaku => Key::Zenkaku,
+ TaoKey::ZenkakuHankaku => Key::ZenkakuHankaku,
+ TaoKey::Soft1 => Key::Soft1,
+ TaoKey::Soft2 => Key::Soft2,
+ TaoKey::Soft3 => Key::Soft3,
+ TaoKey::Soft4 => Key::Soft4,
+ TaoKey::ChannelDown => Key::ChannelDown,
+ TaoKey::ChannelUp => Key::ChannelUp,
+ TaoKey::Close => Key::Close,
+ TaoKey::MailForward => Key::MailForward,
+ TaoKey::MailReply => Key::MailReply,
+ TaoKey::MailSend => Key::MailSend,
+ TaoKey::MediaClose => Key::MediaClose,
+ TaoKey::MediaFastForward => Key::MediaFastForward,
+ TaoKey::MediaPause => Key::MediaPause,
+ TaoKey::MediaPlay => Key::MediaPlay,
+ TaoKey::MediaPlayPause => Key::MediaPlayPause,
+ TaoKey::MediaRecord => Key::MediaRecord,
+ TaoKey::MediaRewind => Key::MediaRewind,
+ TaoKey::MediaStop => Key::MediaStop,
+ TaoKey::MediaTrackNext => Key::MediaTrackNext,
+ TaoKey::MediaTrackPrevious => Key::MediaTrackPrevious,
+ TaoKey::New => Key::New,
+ TaoKey::Open => Key::Open,
+ TaoKey::Print => Key::Print,
+ TaoKey::Save => Key::Save,
+ TaoKey::SpellCheck => Key::SpellCheck,
+ TaoKey::Key11 => Key::Key11,
+ TaoKey::Key12 => Key::Key12,
+ TaoKey::AudioBalanceLeft => Key::AudioBalanceLeft,
+ TaoKey::AudioBalanceRight => Key::AudioBalanceRight,
+ TaoKey::AudioBassBoostDown => Key::AudioBassBoostDown,
+ TaoKey::AudioBassBoostToggle => Key::AudioBassBoostToggle,
+ TaoKey::AudioBassBoostUp => Key::AudioBassBoostUp,
+ TaoKey::AudioFaderFront => Key::AudioFaderFront,
+ TaoKey::AudioFaderRear => Key::AudioFaderRear,
+ TaoKey::AudioSurroundModeNext => Key::AudioSurroundModeNext,
+ TaoKey::AudioTrebleDown => Key::AudioTrebleDown,
+ TaoKey::AudioTrebleUp => Key::AudioTrebleUp,
+ TaoKey::AudioVolumeDown => Key::AudioVolumeDown,
+ TaoKey::AudioVolumeUp => Key::AudioVolumeUp,
+ TaoKey::AudioVolumeMute => Key::AudioVolumeMute,
+ TaoKey::MicrophoneToggle => Key::MicrophoneToggle,
+ TaoKey::MicrophoneVolumeDown => Key::MicrophoneVolumeDown,
+ TaoKey::MicrophoneVolumeUp => Key::MicrophoneVolumeUp,
+ TaoKey::MicrophoneVolumeMute => Key::MicrophoneVolumeMute,
+ TaoKey::SpeechCorrectionList => Key::SpeechCorrectionList,
+ TaoKey::SpeechInputToggle => Key::SpeechInputToggle,
+ TaoKey::LaunchApplication1 => Key::LaunchApplication1,
+ TaoKey::LaunchApplication2 => Key::LaunchApplication2,
+ TaoKey::LaunchCalendar => Key::LaunchCalendar,
+ TaoKey::LaunchContacts => Key::LaunchContacts,
+ TaoKey::LaunchMail => Key::LaunchMail,
+ TaoKey::LaunchMediaPlayer => Key::LaunchMediaPlayer,
+ TaoKey::LaunchMusicPlayer => Key::LaunchMusicPlayer,
+ TaoKey::LaunchPhone => Key::LaunchPhone,
+ TaoKey::LaunchScreenSaver => Key::LaunchScreenSaver,
+ TaoKey::LaunchSpreadsheet => Key::LaunchSpreadsheet,
+ TaoKey::LaunchWebBrowser => Key::LaunchWebBrowser,
+ TaoKey::LaunchWebCam => Key::LaunchWebCam,
+ TaoKey::LaunchWordProcessor => Key::LaunchWordProcessor,
+ TaoKey::BrowserBack => Key::BrowserBack,
+ TaoKey::BrowserFavorites => Key::BrowserFavorites,
+ TaoKey::BrowserForward => Key::BrowserForward,
+ TaoKey::BrowserHome => Key::BrowserHome,
+ TaoKey::BrowserRefresh => Key::BrowserRefresh,
+ TaoKey::BrowserSearch => Key::BrowserSearch,
+ TaoKey::BrowserStop => Key::BrowserStop,
+ TaoKey::AppSwitch => Key::AppSwitch,
+ TaoKey::Call => Key::Call,
+ TaoKey::Camera => Key::Camera,
+ TaoKey::CameraFocus => Key::CameraFocus,
+ TaoKey::EndCall => Key::EndCall,
+ TaoKey::GoBack => Key::GoBack,
+ TaoKey::GoHome => Key::GoHome,
+ TaoKey::HeadsetHook => Key::HeadsetHook,
+ TaoKey::LastNumberRedial => Key::LastNumberRedial,
+ TaoKey::Notification => Key::Notification,
+ TaoKey::MannerMode => Key::MannerMode,
+ TaoKey::VoiceDial => Key::VoiceDial,
+ TaoKey::TV => Key::TV,
+ TaoKey::TV3DMode => Key::TV3DMode,
+ TaoKey::TVAntennaCable => Key::TVAntennaCable,
+ TaoKey::TVAudioDescription => Key::TVAudioDescription,
+ TaoKey::TVAudioDescriptionMixDown => Key::TVAudioDescriptionMixDown,
+ TaoKey::TVAudioDescriptionMixUp => Key::TVAudioDescriptionMixUp,
+ TaoKey::TVContentsMenu => Key::TVContentsMenu,
+ TaoKey::TVDataService => Key::TVDataService,
+ TaoKey::TVInput => Key::TVInput,
+ TaoKey::TVInputComponent1 => Key::TVInputComponent1,
+ TaoKey::TVInputComponent2 => Key::TVInputComponent2,
+ TaoKey::TVInputComposite1 => Key::TVInputComposite1,
+ TaoKey::TVInputComposite2 => Key::TVInputComposite2,
+ TaoKey::TVInputHDMI1 => Key::TVInputHDMI1,
+ TaoKey::TVInputHDMI2 => Key::TVInputHDMI2,
+ TaoKey::TVInputHDMI3 => Key::TVInputHDMI3,
+ TaoKey::TVInputHDMI4 => Key::TVInputHDMI4,
+ TaoKey::TVInputVGA1 => Key::TVInputVGA1,
+ TaoKey::TVMediaContext => Key::TVMediaContext,
+ TaoKey::TVNetwork => Key::TVNetwork,
+ TaoKey::TVNumberEntry => Key::TVNumberEntry,
+ TaoKey::TVPower => Key::TVPower,
+ TaoKey::TVRadioService => Key::TVRadioService,
+ TaoKey::TVSatellite => Key::TVSatellite,
+ TaoKey::TVSatelliteBS => Key::TVSatelliteBS,
+ TaoKey::TVSatelliteCS => Key::TVSatelliteCS,
+ TaoKey::TVSatelliteToggle => Key::TVSatelliteToggle,
+ TaoKey::TVTerrestrialAnalog => Key::TVTerrestrialAnalog,
+ TaoKey::TVTerrestrialDigital => Key::TVTerrestrialDigital,
+ TaoKey::TVTimer => Key::TVTimer,
+ TaoKey::AVRInput => Key::AVRInput,
+ TaoKey::AVRPower => Key::AVRPower,
+ TaoKey::ColorF0Red => Key::ColorF0Red,
+ TaoKey::ColorF1Green => Key::ColorF1Green,
+ TaoKey::ColorF2Yellow => Key::ColorF2Yellow,
+ TaoKey::ColorF3Blue => Key::ColorF3Blue,
+ TaoKey::ColorF4Grey => Key::ColorF4Grey,
+ TaoKey::ColorF5Brown => Key::ColorF5Brown,
+ TaoKey::ClosedCaptionToggle => Key::ClosedCaptionToggle,
+ TaoKey::Dimmer => Key::Dimmer,
+ TaoKey::DisplaySwap => Key::DisplaySwap,
+ TaoKey::DVR => Key::DVR,
+ TaoKey::Exit => Key::Exit,
+ TaoKey::FavoriteClear0 => Key::FavoriteClear0,
+ TaoKey::FavoriteClear1 => Key::FavoriteClear1,
+ TaoKey::FavoriteClear2 => Key::FavoriteClear2,
+ TaoKey::FavoriteClear3 => Key::FavoriteClear3,
+ TaoKey::FavoriteRecall0 => Key::FavoriteRecall0,
+ TaoKey::FavoriteRecall1 => Key::FavoriteRecall1,
+ TaoKey::FavoriteRecall2 => Key::FavoriteRecall2,
+ TaoKey::FavoriteRecall3 => Key::FavoriteRecall3,
+ TaoKey::FavoriteStore0 => Key::FavoriteStore0,
+ TaoKey::FavoriteStore1 => Key::FavoriteStore1,
+ TaoKey::FavoriteStore2 => Key::FavoriteStore2,
+ TaoKey::FavoriteStore3 => Key::FavoriteStore3,
+ TaoKey::Guide => Key::Guide,
+ TaoKey::GuideNextDay => Key::GuideNextDay,
+ TaoKey::GuidePreviousDay => Key::GuidePreviousDay,
+ TaoKey::Info => Key::Info,
+ TaoKey::InstantReplay => Key::InstantReplay,
+ TaoKey::Link => Key::Link,
+ TaoKey::ListProgram => Key::ListProgram,
+ TaoKey::LiveContent => Key::LiveContent,
+ TaoKey::Lock => Key::Lock,
+ TaoKey::MediaApps => Key::MediaApps,
+ TaoKey::MediaAudioTrack => Key::MediaAudioTrack,
+ TaoKey::MediaLast => Key::MediaLast,
+ TaoKey::MediaSkipBackward => Key::MediaSkipBackward,
+ TaoKey::MediaSkipForward => Key::MediaSkipForward,
+ TaoKey::MediaStepBackward => Key::MediaStepBackward,
+ TaoKey::MediaStepForward => Key::MediaStepForward,
+ TaoKey::MediaTopMenu => Key::MediaTopMenu,
+ TaoKey::NavigateIn => Key::NavigateIn,
+ TaoKey::NavigateNext => Key::NavigateNext,
+ TaoKey::NavigateOut => Key::NavigateOut,
+ TaoKey::NavigatePrevious => Key::NavigatePrevious,
+ TaoKey::NextFavoriteChannel => Key::NextFavoriteChannel,
+ TaoKey::NextUserProfile => Key::NextUserProfile,
+ TaoKey::OnDemand => Key::OnDemand,
+ TaoKey::Pairing => Key::Pairing,
+ TaoKey::PinPDown => Key::PinPDown,
+ TaoKey::PinPMove => Key::PinPMove,
+ TaoKey::PinPToggle => Key::PinPToggle,
+ TaoKey::PinPUp => Key::PinPUp,
+ TaoKey::PlaySpeedDown => Key::PlaySpeedDown,
+ TaoKey::PlaySpeedReset => Key::PlaySpeedReset,
+ TaoKey::PlaySpeedUp => Key::PlaySpeedUp,
+ TaoKey::RandomToggle => Key::RandomToggle,
+ TaoKey::RcLowBattery => Key::RcLowBattery,
+ TaoKey::RecordSpeedNext => Key::RecordSpeedNext,
+ TaoKey::RfBypass => Key::RfBypass,
+ TaoKey::ScanChannelsToggle => Key::ScanChannelsToggle,
+ TaoKey::ScreenModeNext => Key::ScreenModeNext,
+ TaoKey::Settings => Key::Settings,
+ TaoKey::SplitScreenToggle => Key::SplitScreenToggle,
+ TaoKey::STBInput => Key::STBInput,
+ TaoKey::STBPower => Key::STBPower,
+ TaoKey::Subtitle => Key::Subtitle,
+ TaoKey::Teletext => Key::Teletext,
+ TaoKey::VideoModeNext => Key::VideoModeNext,
+ TaoKey::Wink => Key::Wink,
+ TaoKey::ZoomToggle => Key::ZoomToggle,
+ TaoKey::F1 => Key::F1,
+ TaoKey::F2 => Key::F2,
+ TaoKey::F3 => Key::F3,
+ TaoKey::F4 => Key::F4,
+ TaoKey::F5 => Key::F5,
+ TaoKey::F6 => Key::F6,
+ TaoKey::F7 => Key::F7,
+ TaoKey::F8 => Key::F8,
+ TaoKey::F9 => Key::F9,
+ TaoKey::F10 => Key::F10,
+ TaoKey::F11 => Key::F11,
+ TaoKey::F12 => Key::F12,
+ TaoKey::F13 => Key::F13,
+ TaoKey::F14 => Key::F14,
+ TaoKey::F15 => Key::F15,
+ TaoKey::F16 => Key::F16,
+ TaoKey::F17 => Key::F17,
+ TaoKey::F18 => Key::F18,
+ TaoKey::F19 => Key::F19,
+ TaoKey::F20 => Key::F20,
+ TaoKey::F21 => Key::F21,
+ TaoKey::F22 => Key::F22,
+ TaoKey::F23 => Key::F23,
+ TaoKey::F24 => Key::F24,
+ TaoKey::F25 => Key::F25,
+ TaoKey::F26 => Key::F26,
+ TaoKey::F27 => Key::F27,
+ TaoKey::F28 => Key::F28,
+ TaoKey::F29 => Key::F29,
+ TaoKey::F30 => Key::F30,
+ TaoKey::F31 => Key::F31,
+ TaoKey::F32 => Key::F32,
+ TaoKey::F33 => Key::F33,
+ TaoKey::F34 => Key::F34,
+ TaoKey::F35 => Key::F35,
+ _ => Key::Unidentified,
+ }
+}
+
+fn convert_key_code(code: &TaoKeyCode) -> Code {
+ match code {
+ TaoKeyCode::Backquote => Code::Backquote,
+ TaoKeyCode::Backslash => Code::Backslash,
+ TaoKeyCode::BracketLeft => Code::BracketLeft,
+ TaoKeyCode::BracketRight => Code::BracketRight,
+ TaoKeyCode::Comma => Code::Comma,
+ TaoKeyCode::Digit0 => Code::Digit0,
+ TaoKeyCode::Digit1 => Code::Digit1,
+ TaoKeyCode::Digit2 => Code::Digit2,
+ TaoKeyCode::Digit3 => Code::Digit3,
+ TaoKeyCode::Digit4 => Code::Digit4,
+ TaoKeyCode::Digit5 => Code::Digit5,
+ TaoKeyCode::Digit6 => Code::Digit6,
+ TaoKeyCode::Digit7 => Code::Digit7,
+ TaoKeyCode::Digit8 => Code::Digit8,
+ TaoKeyCode::Digit9 => Code::Digit9,
+ TaoKeyCode::Equal => Code::Equal,
+ TaoKeyCode::IntlBackslash => Code::IntlBackslash,
+ TaoKeyCode::IntlRo => Code::IntlRo,
+ TaoKeyCode::IntlYen => Code::IntlYen,
+ TaoKeyCode::KeyA => Code::KeyA,
+ TaoKeyCode::KeyB => Code::KeyB,
+ TaoKeyCode::KeyC => Code::KeyC,
+ TaoKeyCode::KeyD => Code::KeyD,
+ TaoKeyCode::KeyE => Code::KeyE,
+ TaoKeyCode::KeyF => Code::KeyF,
+ TaoKeyCode::KeyG => Code::KeyG,
+ TaoKeyCode::KeyH => Code::KeyH,
+ TaoKeyCode::KeyI => Code::KeyI,
+ TaoKeyCode::KeyJ => Code::KeyJ,
+ TaoKeyCode::KeyK => Code::KeyK,
+ TaoKeyCode::KeyL => Code::KeyL,
+ TaoKeyCode::KeyM => Code::KeyM,
+ TaoKeyCode::KeyN => Code::KeyN,
+ TaoKeyCode::KeyO => Code::KeyO,
+ TaoKeyCode::KeyP => Code::KeyP,
+ TaoKeyCode::KeyQ => Code::KeyQ,
+ TaoKeyCode::KeyR => Code::KeyR,
+ TaoKeyCode::KeyS => Code::KeyS,
+ TaoKeyCode::KeyT => Code::KeyT,
+ TaoKeyCode::KeyU => Code::KeyU,
+ TaoKeyCode::KeyV => Code::KeyV,
+ TaoKeyCode::KeyW => Code::KeyW,
+ TaoKeyCode::KeyX => Code::KeyX,
+ TaoKeyCode::KeyY => Code::KeyY,
+ TaoKeyCode::KeyZ => Code::KeyZ,
+ TaoKeyCode::Minus => Code::Minus,
+ // The web at does not have Plus,
+ // but Equal means the key that represents =+ on the US keyboard.
+ TaoKeyCode::Plus => Code::Equal,
+ TaoKeyCode::Period => Code::Period,
+ TaoKeyCode::Quote => Code::Quote,
+ TaoKeyCode::Semicolon => Code::Semicolon,
+ TaoKeyCode::Slash => Code::Slash,
+ TaoKeyCode::AltLeft => Code::AltLeft,
+ TaoKeyCode::AltRight => Code::AltRight,
+ TaoKeyCode::Backspace => Code::Backspace,
+ TaoKeyCode::CapsLock => Code::CapsLock,
+ TaoKeyCode::ContextMenu => Code::ContextMenu,
+ TaoKeyCode::ControlLeft => Code::ControlLeft,
+ TaoKeyCode::ControlRight => Code::ControlRight,
+ TaoKeyCode::Enter => Code::Enter,
+ // What Tao calls super, the web at calls meta.
+ // It's the key that represents the Windows logo on Windows, and the Command key (⌘) on Mac.
+ TaoKeyCode::SuperLeft => Code::MetaLeft,
+ TaoKeyCode::SuperRight => Code::MetaRight,
+ TaoKeyCode::ShiftLeft => Code::ShiftLeft,
+ TaoKeyCode::ShiftRight => Code::ShiftRight,
+ TaoKeyCode::Space => Code::Space,
+ TaoKeyCode::Tab => Code::Tab,
+ TaoKeyCode::Convert => Code::Convert,
+ TaoKeyCode::KanaMode => Code::KanaMode,
+ TaoKeyCode::Lang1 => Code::Lang1,
+ TaoKeyCode::Lang2 => Code::Lang2,
+ TaoKeyCode::Lang3 => Code::Lang3,
+ TaoKeyCode::Lang4 => Code::Lang4,
+ TaoKeyCode::NonConvert => Code::NonConvert,
+ TaoKeyCode::Delete => Code::Delete,
+ TaoKeyCode::End => Code::End,
+ TaoKeyCode::Help => Code::Help,
+ TaoKeyCode::Home => Code::Home,
+ TaoKeyCode::Insert => Code::Insert,
+ TaoKeyCode::PageDown => Code::PageDown,
+ TaoKeyCode::PageUp => Code::PageUp,
+ TaoKeyCode::ArrowDown => Code::ArrowDown,
+ TaoKeyCode::ArrowLeft => Code::ArrowLeft,
+ TaoKeyCode::ArrowRight => Code::ArrowRight,
+ TaoKeyCode::ArrowUp => Code::ArrowUp,
+ TaoKeyCode::NumLock => Code::NumLock,
+ TaoKeyCode::Numpad0 => Code::Numpad0,
+ TaoKeyCode::Numpad1 => Code::Numpad1,
+ TaoKeyCode::Numpad2 => Code::Numpad2,
+ TaoKeyCode::Numpad3 => Code::Numpad3,
+ TaoKeyCode::Numpad4 => Code::Numpad4,
+ TaoKeyCode::Numpad5 => Code::Numpad5,
+ TaoKeyCode::Numpad6 => Code::Numpad6,
+ TaoKeyCode::Numpad7 => Code::Numpad7,
+ TaoKeyCode::Numpad8 => Code::Numpad8,
+ TaoKeyCode::Numpad9 => Code::Numpad9,
+ TaoKeyCode::NumpadAdd => Code::NumpadAdd,
+ TaoKeyCode::NumpadBackspace => Code::NumpadBackspace,
+ TaoKeyCode::NumpadClear => Code::NumpadClear,
+ TaoKeyCode::NumpadClearEntry => Code::NumpadClearEntry,
+ TaoKeyCode::NumpadComma => Code::NumpadComma,
+ TaoKeyCode::NumpadDecimal => Code::NumpadDecimal,
+ TaoKeyCode::NumpadDivide => Code::NumpadDivide,
+ TaoKeyCode::NumpadEnter => Code::NumpadEnter,
+ TaoKeyCode::NumpadEqual => Code::NumpadEqual,
+ TaoKeyCode::NumpadHash => Code::NumpadHash,
+ TaoKeyCode::NumpadMemoryAdd => Code::NumpadMemoryAdd,
+ TaoKeyCode::NumpadMemoryClear => Code::NumpadMemoryClear,
+ TaoKeyCode::NumpadMemoryRecall => Code::NumpadMemoryRecall,
+ TaoKeyCode::NumpadMemoryStore => Code::NumpadMemoryStore,
+ TaoKeyCode::NumpadMemorySubtract => Code::NumpadMemorySubtract,
+ TaoKeyCode::NumpadMultiply => Code::NumpadMultiply,
+ TaoKeyCode::NumpadParenLeft => Code::NumpadParenLeft,
+ TaoKeyCode::NumpadParenRight => Code::NumpadParenRight,
+ TaoKeyCode::NumpadStar => Code::NumpadStar,
+ TaoKeyCode::NumpadSubtract => Code::NumpadSubtract,
+ TaoKeyCode::Escape => Code::Escape,
+ TaoKeyCode::Fn => Code::Fn,
+ TaoKeyCode::FnLock => Code::FnLock,
+ TaoKeyCode::PrintScreen => Code::PrintScreen,
+ TaoKeyCode::ScrollLock => Code::ScrollLock,
+ TaoKeyCode::Pause => Code::Pause,
+ TaoKeyCode::BrowserBack => Code::BrowserBack,
+ TaoKeyCode::BrowserFavorites => Code::BrowserFavorites,
+ TaoKeyCode::BrowserForward => Code::BrowserForward,
+ TaoKeyCode::BrowserHome => Code::BrowserHome,
+ TaoKeyCode::BrowserRefresh => Code::BrowserRefresh,
+ TaoKeyCode::BrowserSearch => Code::BrowserSearch,
+ TaoKeyCode::BrowserStop => Code::BrowserStop,
+ TaoKeyCode::Eject => Code::Eject,
+ TaoKeyCode::LaunchApp1 => Code::LaunchApp1,
+ TaoKeyCode::LaunchApp2 => Code::LaunchApp2,
+ TaoKeyCode::LaunchMail => Code::LaunchMail,
+ TaoKeyCode::MediaPlayPause => Code::MediaPlayPause,
+ TaoKeyCode::MediaSelect => Code::MediaSelect,
+ TaoKeyCode::MediaStop => Code::MediaStop,
+ TaoKeyCode::MediaTrackNext => Code::MediaTrackNext,
+ TaoKeyCode::MediaTrackPrevious => Code::MediaTrackPrevious,
+ TaoKeyCode::Power => Code::Power,
+ TaoKeyCode::Sleep => Code::Sleep,
+ TaoKeyCode::AudioVolumeDown => Code::AudioVolumeDown,
+ TaoKeyCode::AudioVolumeMute => Code::AudioVolumeMute,
+ TaoKeyCode::AudioVolumeUp => Code::AudioVolumeUp,
+ TaoKeyCode::WakeUp => Code::WakeUp,
+ TaoKeyCode::Hyper => Code::Hyper,
+ TaoKeyCode::Turbo => Code::Turbo,
+ TaoKeyCode::Abort => Code::Abort,
+ TaoKeyCode::Resume => Code::Resume,
+ TaoKeyCode::Suspend => Code::Suspend,
+ TaoKeyCode::Again => Code::Again,
+ TaoKeyCode::Copy => Code::Copy,
+ TaoKeyCode::Cut => Code::Cut,
+ TaoKeyCode::Find => Code::Find,
+ TaoKeyCode::Open => Code::Open,
+ TaoKeyCode::Paste => Code::Paste,
+ TaoKeyCode::Props => Code::Props,
+ TaoKeyCode::Select => Code::Select,
+ TaoKeyCode::Undo => Code::Undo,
+ TaoKeyCode::Hiragana => Code::Hiragana,
+ TaoKeyCode::Katakana => Code::Katakana,
+ TaoKeyCode::F1 => Code::F1,
+ TaoKeyCode::F2 => Code::F2,
+ TaoKeyCode::F3 => Code::F3,
+ TaoKeyCode::F4 => Code::F4,
+ TaoKeyCode::F5 => Code::F5,
+ TaoKeyCode::F6 => Code::F6,
+ TaoKeyCode::F7 => Code::F7,
+ TaoKeyCode::F8 => Code::F8,
+ TaoKeyCode::F9 => Code::F9,
+ TaoKeyCode::F10 => Code::F10,
+ TaoKeyCode::F11 => Code::F11,
+ TaoKeyCode::F12 => Code::F12,
+ TaoKeyCode::F13 => Code::F13,
+ TaoKeyCode::F14 => Code::F14,
+ TaoKeyCode::F15 => Code::F15,
+ TaoKeyCode::F16 => Code::F16,
+ TaoKeyCode::F17 => Code::F17,
+ TaoKeyCode::F18 => Code::F18,
+ TaoKeyCode::F19 => Code::F19,
+ TaoKeyCode::F20 => Code::F20,
+ TaoKeyCode::F21 => Code::F21,
+ TaoKeyCode::F22 => Code::F22,
+ TaoKeyCode::F23 => Code::F23,
+ TaoKeyCode::F24 => Code::F24,
+ TaoKeyCode::F25 => Code::F25,
+ TaoKeyCode::F26 => Code::F26,
+ TaoKeyCode::F27 => Code::F27,
+ TaoKeyCode::F28 => Code::F28,
+ TaoKeyCode::F29 => Code::F29,
+ TaoKeyCode::F30 => Code::F30,
+ TaoKeyCode::F31 => Code::F31,
+ TaoKeyCode::F32 => Code::F32,
+ TaoKeyCode::F33 => Code::F33,
+ TaoKeyCode::F34 => Code::F34,
+ TaoKeyCode::F35 => Code::F35,
+ _ => Code::Unidentified,
+ }
+}
+
+fn convert_key_state(state: &TaoElementState) -> Option {
+ match state {
+ TaoElementState::Pressed => Some(KeyState::Down),
+ TaoElementState::Released => Some(KeyState::Up),
+ _ => None,
+ }
+}
+
+fn convert_location(location: &TaoKeyLocation) -> Option {
+ match location {
+ TaoKeyLocation::Standard => Some(Location::Standard),
+ TaoKeyLocation::Left => Some(Location::Left),
+ TaoKeyLocation::Right => Some(Location::Right),
+ TaoKeyLocation::Numpad => Some(Location::Numpad),
+ _ => None,
+ }
+}
diff --git a/crates/tauri-runtime-wry/src/lib.rs b/crates/tauri-runtime-wry/src/lib.rs
index 7e8013d6a743..03a1c2ea88a4 100644
--- a/crates/tauri-runtime-wry/src/lib.rs
+++ b/crates/tauri-runtime-wry/src/lib.rs
@@ -125,6 +125,7 @@ use std::{
pub type WebviewId = u32;
type IpcHandler = dyn Fn(Request) + 'static;
+mod keyboard;
#[cfg(any(
windows,
target_os = "linux",
@@ -532,6 +533,11 @@ impl<'a> From<&TaoWindowEvent<'a>> for WindowEventWrapper {
},
#[cfg(any(target_os = "linux", target_os = "macos"))]
TaoWindowEvent::Focused(focused) => WindowEvent::Focused(*focused),
+ TaoWindowEvent::KeyboardInput { event, .. } => {
+ let event = keyboard::convert_key_event(event);
+
+ WindowEvent::KeyboardInput { event }
+ }
TaoWindowEvent::ThemeChanged(theme) => WindowEvent::ThemeChanged(map_theme(theme)),
_ => return Self(None),
};
diff --git a/crates/tauri-runtime/Cargo.toml b/crates/tauri-runtime/Cargo.toml
index 0e2171b9c574..b8afec178368 100644
--- a/crates/tauri-runtime/Cargo.toml
+++ b/crates/tauri-runtime/Cargo.toml
@@ -34,6 +34,7 @@ http = "1"
raw-window-handle = "0.6"
url = { version = "2" }
dpi = { version = "0.1", features = ["serde"] }
+keyboard-types = "0.7.0"
[target."cfg(windows)".dependencies.windows]
version = "0.58"
diff --git a/crates/tauri-runtime/src/keyboard.rs b/crates/tauri-runtime/src/keyboard.rs
new file mode 100644
index 000000000000..dfbe7d3569ee
--- /dev/null
+++ b/crates/tauri-runtime/src/keyboard.rs
@@ -0,0 +1,28 @@
+use serde::{Deserialize, Serialize};
+
+pub use keyboard_types::{Code, Key, KeyState, Location, Modifiers};
+
+/// Keyboard events are issued for all pressed and released keys.
+#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
+pub struct KeyboardEvent {
+ /// Whether the key is pressed or released.
+ pub state: KeyState,
+ /// Logical key value.
+ pub key: Key,
+ /// Physical key position.
+ pub code: Code,
+ /// Location for keys with multiple instances on common keyboards.
+ pub location: Location,
+ /// True if the key is currently auto-repeated.
+ pub repeat: bool,
+}
+
+impl KeyboardEvent {
+ pub fn is_down(&self) -> bool {
+ self.state == KeyState::Down
+ }
+
+ pub fn is_up(&self) -> bool {
+ self.state == KeyState::Up
+ }
+}
diff --git a/crates/tauri-runtime/src/lib.rs b/crates/tauri-runtime/src/lib.rs
index 8c93a19a0907..bdd221536afc 100644
--- a/crates/tauri-runtime/src/lib.rs
+++ b/crates/tauri-runtime/src/lib.rs
@@ -21,6 +21,7 @@ use tauri_utils::Theme;
use url::Url;
use webview::{DetachedWebview, PendingWebview};
+pub mod keyboard;
/// Types useful for interacting with a user's monitors.
pub mod monitor;
pub mod webview;
diff --git a/crates/tauri-runtime/src/window.rs b/crates/tauri-runtime/src/window.rs
index dc843100da98..c7ffed6b5f76 100644
--- a/crates/tauri-runtime/src/window.rs
+++ b/crates/tauri-runtime/src/window.rs
@@ -5,6 +5,7 @@
//! A layer between raw [`Runtime`] windows and Tauri.
use crate::{
+ keyboard::KeyboardEvent,
webview::{DetachedWebview, PendingWebview},
Icon, Runtime, UserEvent, WindowDispatch,
};
@@ -43,6 +44,10 @@ pub enum WindowEvent {
///
/// The parameter is true if the window has gained focus, and false if it has lost focus.
Focused(bool),
+
+ /// An event from the keyboard has been received.
+ KeyboardInput { event: KeyboardEvent },
+
/// The window's scale factor has changed.
///
/// The following user actions can cause DPI changes:
diff --git a/crates/tauri/src/app.rs b/crates/tauri/src/app.rs
index 57fc7a00ac56..95f6db5ff4ed 100644
--- a/crates/tauri/src/app.rs
+++ b/crates/tauri/src/app.rs
@@ -8,6 +8,7 @@ use crate::{
channel::ChannelDataIpcQueue, CallbackFn, CommandArg, CommandItem, Invoke, InvokeError,
InvokeHandler, InvokeResponseBody,
},
+ keyboard::KeyboardEvent,
manager::{webview::UriSchemeProtocol, AppManager, Asset},
plugin::{Plugin, PluginStore},
resources::ResourceTable,
@@ -115,6 +116,8 @@ pub enum WindowEvent {
///
/// The parameter is true if the window has gained focus, and false if it has lost focus.
Focused(bool),
+ /// An event from the keyboard has been received.
+ KeyboardInput(KeyboardEvent),
/// The window's scale factor has changed.
///
/// The following user actions can cause DPI changes:
@@ -151,6 +154,7 @@ impl From for WindowEvent {
},
RuntimeWindowEvent::Destroyed => Self::Destroyed,
RuntimeWindowEvent::Focused(flag) => Self::Focused(flag),
+ RuntimeWindowEvent::KeyboardInput { event } => Self::KeyboardInput(event),
RuntimeWindowEvent::ScaleFactorChanged {
scale_factor,
new_inner_size,
diff --git a/crates/tauri/src/keyboard/mod.rs b/crates/tauri/src/keyboard/mod.rs
new file mode 100644
index 000000000000..6a8560c70181
--- /dev/null
+++ b/crates/tauri/src/keyboard/mod.rs
@@ -0,0 +1,5 @@
+// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-License-Identifier: MIT
+
+pub use tauri_runtime::keyboard::{Code, Key, KeyState, KeyboardEvent, Location, Modifiers};
diff --git a/crates/tauri/src/lib.rs b/crates/tauri/src/lib.rs
index caf81748e45e..661ebe7700e8 100644
--- a/crates/tauri/src/lib.rs
+++ b/crates/tauri/src/lib.rs
@@ -82,6 +82,7 @@ pub mod async_runtime;
mod error;
mod event;
pub mod ipc;
+pub mod keyboard;
mod manager;
mod pattern;
pub mod plugin;
diff --git a/crates/tauri/src/manager/window.rs b/crates/tauri/src/manager/window.rs
index f56f40a26c23..d3a828589ac9 100644
--- a/crates/tauri/src/manager/window.rs
+++ b/crates/tauri/src/manager/window.rs
@@ -28,6 +28,7 @@ const WINDOW_MOVED_EVENT: EventName<&str> = EventName::from_str("tauri://move");
const WINDOW_CLOSE_REQUESTED_EVENT: EventName<&str> =
EventName::from_str("tauri://close-requested");
const WINDOW_DESTROYED_EVENT: EventName<&str> = EventName::from_str("tauri://destroyed");
+const WINDOW_KEYBOARD_INPUT_EVENT: EventName<&str> = EventName::from_str("tauri://keyboard-input");
const WINDOW_FOCUS_EVENT: EventName<&str> = EventName::from_str("tauri://focus");
const WINDOW_BLUR_EVENT: EventName<&str> = EventName::from_str("tauri://blur");
const WINDOW_SCALE_FACTOR_CHANGED_EVENT: EventName<&str> =
@@ -180,6 +181,9 @@ fn on_window_event(window: &Window, event: &WindowEvent) -> crate
},
&(),
)?,
+ WindowEvent::KeyboardInput(event) => {
+ window.emit_to_window(WINDOW_KEYBOARD_INPUT_EVENT, event)?;
+ }
WindowEvent::ScaleFactorChanged {
scale_factor,
new_inner_size,