Initial public release of Warp.

Repo-Sync-Origin: warpdotdev/warp-internal@12af1d983b
This commit is contained in:
David Stern
2026-04-28 08:43:33 -05:00
commit 0dbd3d567a
4982 changed files with 1431549 additions and 0 deletions
@@ -0,0 +1,155 @@
//! Keyboard input handling for Wayland via the RemoteDesktop portal.
use std::collections::HashSet;
use ashpd::desktop::Session;
use ashpd::desktop::remote_desktop::{KeyState, RemoteDesktop};
use super::super::keysym::{XK_SHIFT_L, char_to_keysym, keysym_needs_shift};
use crate::Key;
/// Keyboard state for tracking auto-shifted keys.
pub struct Keyboard {
/// Keysyms currently held that required auto-shift.
/// When non-empty, shift is being held by us.
auto_shift_keys: HashSet<i32>,
}
impl Keyboard {
pub fn new() -> Self {
Self {
auto_shift_keys: HashSet::new(),
}
}
/// Types a string of text by sending keysym events.
pub async fn type_text<'a>(
&mut self,
remote_desktop: &RemoteDesktop<'a>,
session: &Session<'a, RemoteDesktop<'a>>,
text: &str,
) -> Result<(), String> {
for ch in text.chars() {
self.type_char(remote_desktop, session, ch).await?;
}
Ok(())
}
/// Sends a key down event for the given key.
///
/// For `Key::Char`, this will automatically press shift if needed.
pub async fn key_down<'a>(
&mut self,
remote_desktop: &RemoteDesktop<'a>,
session: &Session<'a, RemoteDesktop<'a>>,
key: &Key,
) -> Result<(), String> {
let (keysym, needs_shift) = self.resolve_key(key);
if needs_shift {
// Press shift only if this is the first auto-shifted key.
if self.auto_shift_keys.is_empty() {
self.press_shift(remote_desktop, session).await?;
}
self.auto_shift_keys.insert(keysym);
}
remote_desktop
.notify_keyboard_keysym(session, keysym, KeyState::Pressed)
.await
.map_err(|e| format!("Failed to send key down: {e}"))
}
/// Sends a key up event for the given key.
///
/// For `Key::Char`, this will automatically release shift if it was auto-pressed
/// and this is the last auto-shifted key being released.
pub async fn key_up<'a>(
&mut self,
remote_desktop: &RemoteDesktop<'a>,
session: &Session<'a, RemoteDesktop<'a>>,
key: &Key,
) -> Result<(), String> {
let (keysym, _) = self.resolve_key(key);
remote_desktop
.notify_keyboard_keysym(session, keysym, KeyState::Released)
.await
.map_err(|e| format!("Failed to send key up: {e}"))?;
// Release shift only if this key was auto-shifted and it's the last one.
if self.auto_shift_keys.remove(&keysym) && self.auto_shift_keys.is_empty() {
self.release_shift(remote_desktop, session).await?;
}
Ok(())
}
async fn type_char<'a>(
&mut self,
remote_desktop: &RemoteDesktop<'a>,
session: &Session<'a, RemoteDesktop<'a>>,
ch: char,
) -> Result<(), String> {
let keysym = char_to_keysym(ch) as i32;
let needs_shift = keysym_needs_shift(keysym as u32);
// Press shift if needed, then press and release the key, then release shift.
if needs_shift {
self.press_shift(remote_desktop, session).await?;
}
remote_desktop
.notify_keyboard_keysym(session, keysym, KeyState::Pressed)
.await
.map_err(|e| format!("Failed to send key press: {e}"))?;
remote_desktop
.notify_keyboard_keysym(session, keysym, KeyState::Released)
.await
.map_err(|e| format!("Failed to send key release: {e}"))?;
if needs_shift {
self.release_shift(remote_desktop, session).await?;
}
Ok(())
}
/// Resolves a `Key` to a keysym and shift requirement.
fn resolve_key(&self, key: &Key) -> (i32, bool) {
match key {
Key::Keycode(keysym) => {
// Key::Keycode uses X11 keysyms, which we can use directly.
(*keysym, false)
}
Key::Char(ch) => {
let keysym = char_to_keysym(*ch) as i32;
let needs_shift = keysym_needs_shift(keysym as u32);
(keysym, needs_shift)
}
}
}
async fn press_shift<'a>(
&self,
remote_desktop: &RemoteDesktop<'a>,
session: &Session<'a, RemoteDesktop<'a>>,
) -> Result<(), String> {
remote_desktop
.notify_keyboard_keysym(session, XK_SHIFT_L as i32, KeyState::Pressed)
.await
.map_err(|e| format!("Failed to press shift: {e}"))
}
async fn release_shift<'a>(
&self,
remote_desktop: &RemoteDesktop<'a>,
session: &Session<'a, RemoteDesktop<'a>>,
) -> Result<(), String> {
remote_desktop
.notify_keyboard_keysym(session, XK_SHIFT_L as i32, KeyState::Released)
.await
.map_err(|e| format!("Failed to release shift: {e}"))
}
}