Closes #21700 Release Notes: - Added caps lock support and show a warning if the user is entering an SSH password with Caps Lock enabled ---------
Unified · Split
| @@ -1,7 +1,7 @@ | ||
| 1 | 1 | use crate::{ |
| 2 | 2 | Action, AnyView, AnyWindowHandle, App, AppCell, AppContext, AsyncApp, AvailableSpace, |
| 3 | − BackgroundExecutor, BorrowAppContext, Bounds, ClipboardItem, DrawPhase, Drawable, Element, | |
| 4 | − Empty, EventEmitter, ForegroundExecutor, Global, InputEvent, Keystroke, Modifiers, | |
| 3 | + BackgroundExecutor, BorrowAppContext, Bounds, Capslock, ClipboardItem, DrawPhase, Drawable, | |
| 4 | + Element, Empty, EventEmitter, ForegroundExecutor, Global, InputEvent, Keystroke, Modifiers, | |
| 5 | 5 | ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, |
| 6 | 6 | Platform, Point, Render, Result, Size, Task, TestDispatcher, TestPlatform, |
| 7 | 7 | TestScreenCaptureSource, TestWindow, TextSystem, VisualContext, Window, WindowBounds, |
| @@ -771,7 +771,18 @@ impl VisualTestContext { · 763 unmodified lines | ||
| 771 | 771 | |
| 772 | 772 | /// Simulate a modifiers changed event |
| 773 | 773 | pub fn simulate_modifiers_change(&mut self, modifiers: Modifiers) { |
| 774 | − self.simulate_event(ModifiersChangedEvent { modifiers }) | |
| 774 | + self.simulate_event(ModifiersChangedEvent { | |
| 775 | + modifiers, | |
| 776 | + capslock: Capslock { on: false }, | |
| 777 | + }) | |
| 778 | + } | |
| 779 | + | |
| 780 | + /// Simulate a capslock changed event | |
| 781 | + pub fn simulate_capslock_change(&mut self, on: bool) { | |
| 782 | + self.simulate_event(ModifiersChangedEvent { | |
| 783 | + modifiers: Modifiers::none(), | |
| 784 | + capslock: Capslock { on }, | |
| 785 | + }) | |
| 775 | 786 | } |
| 776 | 787 | |
| 777 | 788 | /// Simulates the user resizing the window to the new size. |
| @@ -1,6 +1,6 @@ | ||
| 1 | 1 | use crate::{ |
| 2 | − Context, Empty, IntoElement, Keystroke, Modifiers, Pixels, Point, Render, Window, point, | |
| 3 | − seal::Sealed, | |
| 2 | + Capslock, Context, Empty, IntoElement, Keystroke, Modifiers, Pixels, Point, Render, Window, | |
| 3 | + point, seal::Sealed, | |
| 4 | 4 | }; |
| 5 | 5 | use smallvec::SmallVec; |
| 6 | 6 | use std::{any::Any, fmt::Debug, ops::Deref, path::PathBuf}; |
| @@ -55,6 +55,8 @@ impl KeyEvent for KeyUpEvent {} · 48 unmodified lines | ||
| 55 | 55 | pub struct ModifiersChangedEvent { |
| 56 | 56 | /// The new state of the modifier keys |
| 57 | 57 | pub modifiers: Modifiers, |
| 58 | + /// The new state of the capslock key | |
| 59 | + pub capslock: Capslock, | |
| 58 | 60 | } |
| 59 | 61 | |
| 60 | 62 | impl Sealed for ModifiersChangedEvent {} |
| @@ -415,6 +415,7 @@ pub(crate) trait PlatformWindow: HasWindowHandle + HasDisplayHandle { · 414 unmodified lines | ||
| 415 | 415 | fn display(&self) -> Option<Rc<dyn PlatformDisplay>>; |
| 416 | 416 | fn mouse_position(&self) -> Point<Pixels>; |
| 417 | 417 | fn modifiers(&self) -> Modifiers; |
| 418 | + fn capslock(&self) -> Capslock; | |
| 418 | 419 | fn set_input_handler(&mut self, input_handler: PlatformInputHandler); |
| 419 | 420 | fn take_input_handler(&mut self) -> Option<PlatformInputHandler>; |
| 420 | 421 | fn prompt( |
| @@ -538,3 +538,11 @@ impl Modifiers { · 537 unmodified lines | ||
| 538 | 538 | && (other.function || !self.function) |
| 539 | 539 | } |
| 540 | 540 | } |
| 541 | + | |
| 542 | +/// The state of the capslock key at some point in time | |
| 543 | +#[derive(Copy, Clone, Debug, Eq, PartialEq, Default, Serialize, Deserialize, Hash, JsonSchema)] | |
| 544 | +pub struct Capslock { | |
| 545 | + /// The capslock key is on | |
| 546 | + #[serde(default)] | |
| 547 | + pub on: bool, | |
| 548 | +} | |
| @@ -873,6 +873,14 @@ impl crate::Modifiers { · 872 unmodified lines | ||
| 873 | 873 | } |
| 874 | 874 | } |
| 875 | 875 | |
| 876 | +#[cfg(any(feature = "wayland", feature = "x11"))] | |
| 877 | +impl crate::Capslock { | |
| 878 | + pub(super) fn from_xkb(keymap_state: &State) -> Self { | |
| 879 | + let on = keymap_state.mod_name_is_active(xkb::MOD_NAME_CAPS, xkb::STATE_MODS_EFFECTIVE); | |
| 880 | + Self { on } | |
| 881 | + } | |
| 882 | +} | |
| 883 | + | |
| 876 | 884 | #[cfg(test)] |
| 877 | 885 | mod tests { |
| 878 | 886 | use super::*; |
| @@ -73,7 +73,7 @@ use super::{ · 72 unmodified lines | ||
| 73 | 73 | |
| 74 | 74 | use crate::platform::{PlatformWindow, blade::BladeContext}; |
| 75 | 75 | use crate::{ |
| 76 | − AnyWindowHandle, Bounds, CursorStyle, DOUBLE_CLICK_INTERVAL, DevicePixels, DisplayId, | |
| 76 | + AnyWindowHandle, Bounds, Capslock, CursorStyle, DOUBLE_CLICK_INTERVAL, DevicePixels, DisplayId, | |
| 77 | 77 | FileDropEvent, ForegroundExecutor, KeyDownEvent, KeyUpEvent, Keystroke, LinuxCommon, |
| 78 | 78 | LinuxKeyboardLayout, Modifiers, ModifiersChangedEvent, MouseButton, MouseDownEvent, |
| 79 | 79 | MouseExitEvent, MouseMoveEvent, MouseUpEvent, NavigationDirection, Pixels, PlatformDisplay, |
| @@ -217,6 +217,7 @@ pub(crate) struct WaylandClientState { · 137 unmodified lines | ||
| 217 | 217 | click: ClickState, |
| 218 | 218 | repeat: KeyRepeat, |
| 219 | 219 | pub modifiers: Modifiers, |
| 220 | + pub capslock: Capslock, | |
| 220 | 221 | axis_source: AxisSource, |
| 221 | 222 | pub mouse_location: Option<Point<Pixels>>, |
| 222 | 223 | continuous_scroll_delta: Option<Point<Pixels>>, |
| @@ -595,6 +596,7 @@ impl WaylandClient { · 372 unmodified lines | ||
| 595 | 596 | function: false, |
| 596 | 597 | platform: false, |
| 597 | 598 | }, |
| 599 | + capslock: Capslock { on: false }, | |
| 598 | 600 | scroll_event_received: false, |
| 599 | 601 | axis_source: AxisSource::Wheel, |
| 600 | 602 | mouse_location: None, |
| @@ -1251,9 +1253,12 @@ impl Dispatch<wl_keyboard::WlKeyboard, ()> for WaylandClientStatePtr { · 650 unmodified lines | ||
| 1251 | 1253 | keymap_state.serialize_layout(xkbcommon::xkb::STATE_LAYOUT_EFFECTIVE); |
| 1252 | 1254 | keymap_state.update_mask(mods_depressed, mods_latched, mods_locked, 0, 0, group); |
| 1253 | 1255 | state.modifiers = Modifiers::from_xkb(keymap_state); |
| 1256 | + let keymap_state = state.keymap_state.as_mut().unwrap(); | |
| 1257 | + state.capslock = Capslock::from_xkb(keymap_state); | |
| 1254 | 1258 | |
| 1255 | 1259 | let input = PlatformInput::ModifiersChanged(ModifiersChangedEvent { |
| 1256 | 1260 | modifiers: state.modifiers, |
| 1261 | + capslock: state.capslock, | |
| 1257 | 1262 | }); |
| 1258 | 1263 | drop(state); |
| 1259 | 1264 | |
| @@ -21,11 +21,6 @@ use wayland_protocols::xdg::shell::client::xdg_surface; · 20 unmodified lines | ||
| 21 | 21 | use wayland_protocols::xdg::shell::client::xdg_toplevel::{self}; |
| 22 | 22 | use wayland_protocols_plasma::blur::client::org_kde_kwin_blur; |
| 23 | 23 | |
| 24 | −use crate::platform::{ | |
| 25 | − PlatformAtlas, PlatformInputHandler, PlatformWindow, | |
| 26 | − blade::{BladeContext, BladeRenderer, BladeSurfaceConfig}, | |
| 27 | − linux::wayland::{display::WaylandDisplay, serial::SerialKind}, | |
| 28 | −}; | |
| 29 | 24 | use crate::scene::Scene; |
| 30 | 25 | use crate::{ |
| 31 | 26 | AnyWindowHandle, Bounds, Decorations, Globals, GpuSpecs, Modifiers, Output, Pixels, |
| @@ -34,6 +29,14 @@ use crate::{ · 2 unmodified lines | ||
| 34 | 29 | WindowBackgroundAppearance, WindowBounds, WindowControlArea, WindowControls, WindowDecorations, |
| 35 | 30 | WindowParams, px, size, |
| 36 | 31 | }; |
| 32 | +use crate::{ | |
| 33 | + Capslock, | |
| 34 | + platform::{ | |
| 35 | + PlatformAtlas, PlatformInputHandler, PlatformWindow, | |
| 36 | + blade::{BladeContext, BladeRenderer, BladeSurfaceConfig}, | |
| 37 | + linux::wayland::{display::WaylandDisplay, serial::SerialKind}, | |
| 38 | + }, | |
| 39 | +}; | |
| 37 | 40 | |
| 38 | 41 | #[derive(Default)] |
| 39 | 42 | pub(crate) struct Callbacks { |
| @@ -861,6 +864,10 @@ impl PlatformWindow for WaylandWindow { · 821 unmodified lines | ||
| 861 | 864 | self.borrow().client.get_client().borrow().modifiers |
| 862 | 865 | } |
| 863 | 866 | |
| 867 | + fn capslock(&self) -> Capslock { | |
| 868 | + self.borrow().client.get_client().borrow().capslock | |
| 869 | + } | |
| 870 | + | |
| 864 | 871 | fn set_input_handler(&mut self, input_handler: PlatformInputHandler) { |
| 865 | 872 | self.borrow_mut().input_handler = Some(input_handler); |
| 866 | 873 | } |
| @@ -1,3 +1,4 @@ | ||
| 1 | +use crate::Capslock; | |
| 1 | 2 | use core::str; |
| 2 | 3 | use std::{ |
| 3 | 4 | cell::RefCell, |
| @@ -203,8 +204,11 @@ pub struct X11ClientState { · 199 unmodified lines | ||
| 203 | 204 | pub(crate) ximc: Option<X11rbClient<Rc<XCBConnection>>>, |
| 204 | 205 | pub(crate) xim_handler: Option<XimHandler>, |
| 205 | 206 | pub modifiers: Modifiers, |
| 207 | + pub capslock: Capslock, | |
| 206 | 208 | // TODO: Can the other updates to `modifiers` be removed so that this is unnecessary? |
| 209 | + // capslock logic was done analog to modifiers | |
| 207 | 210 | pub last_modifiers_changed_event: Modifiers, |
| 211 | + pub last_capslock_changed_event: Capslock, | |
| 208 | 212 | |
| 209 | 213 | pub(crate) compose_state: Option<xkbc::compose::State>, |
| 210 | 214 | pub(crate) pre_edit_text: Option<String>, |
| @@ -473,7 +477,9 @@ impl X11Client { · 262 unmodified lines | ||
| 473 | 477 | |
| 474 | 478 | X11Client(Rc::new(RefCell::new(X11ClientState { |
| 475 | 479 | modifiers: Modifiers::default(), |
| 480 | + capslock: Capslock::default(), | |
| 476 | 481 | last_modifiers_changed_event: Modifiers::default(), |
| 482 | + last_capslock_changed_event: Capslock::default(), | |
| 477 | 483 | event_loop: Some(event_loop), |
| 478 | 484 | loop_handle: handle, |
| 479 | 485 | common, |
| @@ -961,17 +967,25 @@ impl X11Client { · 481 unmodified lines | ||
| 961 | 967 | }; |
| 962 | 968 | |
| 963 | 969 | let modifiers = Modifiers::from_xkb(&state.xkb); |
| 964 | − if state.last_modifiers_changed_event == modifiers { | |
| 970 | + let capslock = Capslock::from_xkb(&state.xkb); | |
| 971 | + if state.last_modifiers_changed_event == modifiers | |
| 972 | + && state.last_capslock_changed_event == capslock | |
| 973 | + { | |
| 965 | 974 | drop(state); |
| 966 | 975 | } else { |
| 967 | 976 | let focused_window_id = state.keyboard_focused_window?; |
| 968 | 977 | state.modifiers = modifiers; |
| 969 | 978 | state.last_modifiers_changed_event = modifiers; |
| 979 | + state.capslock = capslock; | |
| 980 | + state.last_capslock_changed_event = capslock; | |
| 970 | 981 | drop(state); |
| 971 | 982 | |
| 972 | 983 | let focused_window = self.get_window(focused_window_id)?; |
| 973 | 984 | focused_window.handle_input(PlatformInput::ModifiersChanged( |
| 974 | − ModifiersChangedEvent { modifiers }, | |
| 985 | + ModifiersChangedEvent { | |
| 986 | + modifiers, | |
| 987 | + capslock, | |
| 988 | + }, | |
| 975 | 989 | )); |
| 976 | 990 | } |
| 977 | 991 | |
| @@ -1215,6 +1215,17 @@ impl PlatformWindow for X11Window { · 1214 unmodified lines | ||
| 1215 | 1215 | .unwrap_or_default() |
| 1216 | 1216 | } |
| 1217 | 1217 | |
| 1218 | + fn capslock(&self) -> crate::Capslock { | |
| 1219 | + self.0 | |
| 1220 | + .state | |
| 1221 | + .borrow() | |
| 1222 | + .client | |
| 1223 | + .0 | |
| 1224 | + .upgrade() | |
| 1225 | + .map(|ref_cell| ref_cell.borrow().capslock) | |
| 1226 | + .unwrap_or_default() | |
| 1227 | + } | |
| 1228 | + | |
| 1218 | 1229 | fn set_input_handler(&mut self, input_handler: PlatformInputHandler) { |
| 1219 | 1230 | self.0.state.borrow_mut().input_handler = Some(input_handler); |
| 1220 | 1231 | } |
| @@ -1,5 +1,5 @@ | ||
| 1 | 1 | use crate::{ |
| 2 | − KeyDownEvent, KeyUpEvent, Keystroke, Modifiers, ModifiersChangedEvent, MouseButton, | |
| 2 | + Capslock, KeyDownEvent, KeyUpEvent, Keystroke, Modifiers, ModifiersChangedEvent, MouseButton, | |
| 3 | 3 | MouseDownEvent, MouseExitEvent, MouseMoveEvent, MouseUpEvent, NavigationDirection, Pixels, |
| 4 | 4 | PlatformInput, ScrollDelta, ScrollWheelEvent, TouchPhase, |
| 5 | 5 | platform::mac::{ |
| @@ -121,6 +121,11 @@ impl PlatformInput { · 115 unmodified lines | ||
| 121 | 121 | NSEventType::NSFlagsChanged => { |
| 122 | 122 | Some(Self::ModifiersChanged(ModifiersChangedEvent { |
| 123 | 123 | modifiers: read_modifiers(native_event), |
| 124 | + capslock: Capslock { | |
| 125 | + on: native_event | |
| 126 | + .modifierFlags() | |
| 127 | + .contains(NSEventModifierFlags::NSAlphaShiftKeyMask), | |
| 128 | + }, | |
| 124 | 129 | })) |
| 125 | 130 | } |
| 126 | 131 | NSEventType::NSKeyDown => Some(Self::KeyDown(KeyDownEvent { |
| @@ -1,11 +1,11 @@ | ||
| 1 | 1 | use super::{BoolExt, MacDisplay, NSRange, NSStringExt, ns_string, renderer}; |
| 2 | 2 | use crate::{ |
| 3 | − AnyWindowHandle, Bounds, DisplayLink, ExternalPaths, FileDropEvent, ForegroundExecutor, | |
| 4 | − KeyDownEvent, Keystroke, Modifiers, ModifiersChangedEvent, MouseButton, MouseDownEvent, | |
| 5 | − MouseMoveEvent, MouseUpEvent, Pixels, PlatformAtlas, PlatformDisplay, PlatformInput, | |
| 6 | − PlatformWindow, Point, PromptButton, PromptLevel, RequestFrameOptions, ScaledPixels, Size, | |
| 7 | − Timer, WindowAppearance, WindowBackgroundAppearance, WindowBounds, WindowControlArea, | |
| 8 | − WindowKind, WindowParams, platform::PlatformInputHandler, point, px, size, | |
| 3 | + AnyWindowHandle, Bounds, Capslock, DisplayLink, ExternalPaths, FileDropEvent, | |
| 4 | + ForegroundExecutor, KeyDownEvent, Keystroke, Modifiers, ModifiersChangedEvent, MouseButton, | |
| 5 | + MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, PlatformAtlas, PlatformDisplay, | |
| 6 | + PlatformInput, PlatformWindow, Point, PromptButton, PromptLevel, RequestFrameOptions, | |
| 7 | + ScaledPixels, Size, Timer, WindowAppearance, WindowBackgroundAppearance, WindowBounds, | |
| 8 | + WindowControlArea, WindowKind, WindowParams, platform::PlatformInputHandler, point, px, size, | |
| 9 | 9 | }; |
| 10 | 10 | use block::ConcreteBlock; |
| 11 | 11 | use cocoa::{ |
| @@ -890,6 +890,16 @@ impl PlatformWindow for MacWindow { · 878 unmodified lines | ||
| 890 | 890 | } |
| 891 | 891 | } |
| 892 | 892 | |
| 893 | + fn capslock(&self) -> Capslock { | |
| 894 | + unsafe { | |
| 895 | + let modifiers: NSEventModifierFlags = msg_send![class!(NSEvent), modifierFlags]; | |
| 896 | + | |
| 897 | + Capslock { | |
| 898 | + on: modifiers.contains(NSEventModifierFlags::NSAlphaShiftKeyMask), | |
| 899 | + } | |
| 900 | + } | |
| 901 | + } | |
| 902 | + | |
| 893 | 903 | fn set_input_handler(&mut self, input_handler: PlatformInputHandler) { |
| 894 | 904 | self.0.as_ref().lock().input_handler = Some(input_handler); |
| 895 | 905 | } |
| @@ -1556,13 +1566,17 @@ extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) { · 660 unmodified lines | ||
| 1556 | 1566 | lock.synthetic_drag_counter += 1; |
| 1557 | 1567 | } |
| 1558 | 1568 | |
| 1559 | − PlatformInput::ModifiersChanged(ModifiersChangedEvent { modifiers }) => { | |
| 1569 | + PlatformInput::ModifiersChanged(ModifiersChangedEvent { | |
| 1570 | + modifiers, | |
| 1571 | + capslock, | |
| 1572 | + }) => { | |
| 1560 | 1573 | // Only raise modifiers changed event when they have actually changed |
| 1561 | 1574 | if let Some(PlatformInput::ModifiersChanged(ModifiersChangedEvent { |
| 1562 | 1575 | modifiers: prev_modifiers, |
| 1576 | + capslock: prev_capslock, | |
| 1563 | 1577 | })) = &lock.previous_modifiers_changed_event |
| 1564 | 1578 | { |
| 1565 | − if prev_modifiers == modifiers { | |
| 1579 | + if prev_modifiers == modifiers && prev_capslock == capslock { | |
| 1566 | 1580 | return; |
| 1567 | 1581 | } |
| 1568 | 1582 | } |
| @@ -153,6 +153,10 @@ impl PlatformWindow for TestWindow { · 152 unmodified lines | ||
| 153 | 153 | crate::Modifiers::default() |
| 154 | 154 | } |
| 155 | 155 | |
| 156 | + fn capslock(&self) -> crate::Capslock { | |
| 157 | + crate::Capslock::default() | |
| 158 | + } | |
| 159 | + | |
| 156 | 160 | fn set_input_handler(&mut self, input_handler: PlatformInputHandler) { |
| 157 | 161 | self.0.lock().input_handler = Some(input_handler); |
| 158 | 162 | } |
| @@ -1227,6 +1227,7 @@ where · 1226 unmodified lines | ||
| 1227 | 1227 | { |
| 1228 | 1228 | let virtual_key = VIRTUAL_KEY(wparam.loword()); |
| 1229 | 1229 | let mut modifiers = current_modifiers(); |
| 1230 | + let capslock = current_capslock(); | |
| 1230 | 1231 | |
| 1231 | 1232 | match virtual_key { |
| 1232 | 1233 | VK_SHIFT | VK_CONTROL | VK_MENU | VK_LWIN | VK_RWIN => { |
| @@ -1239,6 +1240,7 @@ where · 6 unmodified lines | ||
| 1239 | 1240 | state.last_reported_modifiers = Some(modifiers); |
| 1240 | 1241 | Some(PlatformInput::ModifiersChanged(ModifiersChangedEvent { |
| 1241 | 1242 | modifiers, |
| 1243 | + capslock, | |
| 1242 | 1244 | })) |
| 1243 | 1245 | } |
| 1244 | 1246 | vkey => { |
| @@ -1371,6 +1373,12 @@ pub(crate) fn current_modifiers() -> Modifiers { · 126 unmodified lines | ||
| 1371 | 1373 | } |
| 1372 | 1374 | } |
| 1373 | 1375 | |
| 1376 | +#[inline] | |
| 1377 | +pub(crate) fn current_capslock() -> Capslock { | |
| 1378 | + let on = unsafe { GetKeyState(VK_CAPITAL.0 as i32) & 1 } > 0; | |
| 1379 | + Capslock { on: on } | |
| 1380 | +} | |
| 1381 | + | |
| 1374 | 1382 | fn get_client_area_insets( |
| 1375 | 1383 | handle: HWND, |
| 1376 | 1384 | is_maximized: bool, |
| @@ -559,6 +559,10 @@ impl PlatformWindow for WindowsWindow { · 558 unmodified lines | ||
| 559 | 559 | current_modifiers() |
| 560 | 560 | } |
| 561 | 561 | |
| 562 | + fn capslock(&self) -> Capslock { | |
| 563 | + current_capslock() | |
| 564 | + } | |
| 565 | + | |
| 562 | 566 | fn set_input_handler(&mut self, input_handler: PlatformInputHandler) { |
| 563 | 567 | self.0.state.borrow_mut().input_handler = Some(input_handler); |
| 564 | 568 | } |
| @@ -2,15 +2,15 @@ · 1 unmodified line | ||
| 2 | 2 | use crate::Inspector; |
| 3 | 3 | use crate::{ |
| 4 | 4 | Action, AnyDrag, AnyElement, AnyImageCache, AnyTooltip, AnyView, App, AppContext, Arena, Asset, |
| 5 | − AsyncWindowContext, AvailableSpace, Background, BorderStyle, Bounds, BoxShadow, Context, | |
| 6 | − Corners, CursorStyle, Decorations, DevicePixels, DispatchActionListener, DispatchNodeId, | |
| 7 | − DispatchTree, DisplayId, Edges, Effect, Entity, EntityId, EventEmitter, FileDropEvent, FontId, | |
| 8 | − Global, GlobalElementId, GlyphId, GpuSpecs, Hsla, InputHandler, IsZero, KeyBinding, KeyContext, | |
| 9 | − KeyDownEvent, KeyEvent, Keystroke, KeystrokeEvent, LayoutId, LineLayoutIndex, Modifiers, | |
| 10 | − ModifiersChangedEvent, MonochromeSprite, MouseButton, MouseEvent, MouseMoveEvent, MouseUpEvent, | |
| 11 | − Path, Pixels, PlatformAtlas, PlatformDisplay, PlatformInput, PlatformInputHandler, | |
| 12 | − PlatformWindow, Point, PolychromeSprite, PromptButton, PromptLevel, Quad, Render, | |
| 13 | − RenderGlyphParams, RenderImage, RenderImageParams, RenderSvgParams, Replay, ResizeEdge, | |
| 5 | + AsyncWindowContext, AvailableSpace, Background, BorderStyle, Bounds, BoxShadow, Capslock, | |
| 6 | + Context, Corners, CursorStyle, Decorations, DevicePixels, DispatchActionListener, | |
| 7 | + DispatchNodeId, DispatchTree, DisplayId, Edges, Effect, Entity, EntityId, EventEmitter, | |
| 8 | + FileDropEvent, FontId, Global, GlobalElementId, GlyphId, GpuSpecs, Hsla, InputHandler, IsZero, | |
| 9 | + KeyBinding, KeyContext, KeyDownEvent, KeyEvent, Keystroke, KeystrokeEvent, LayoutId, | |
| 10 | + LineLayoutIndex, Modifiers, ModifiersChangedEvent, MonochromeSprite, MouseButton, MouseEvent, | |
| 11 | + MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas, PlatformDisplay, PlatformInput, | |
| 12 | + PlatformInputHandler, PlatformWindow, Point, PolychromeSprite, PromptButton, PromptLevel, Quad, | |
| 13 | + Render, RenderGlyphParams, RenderImage, RenderImageParams, RenderSvgParams, Replay, ResizeEdge, | |
| 14 | 14 | SMOOTH_SVG_SCALE_FACTOR, SUBPIXEL_VARIANTS, ScaledPixels, Scene, Shadow, SharedString, Size, |
| 15 | 15 | StrikethroughStyle, Style, SubscriberSet, Subscription, TaffyLayoutEngine, Task, TextStyle, |
| 16 | 16 | TextStyleRefinement, TransformationMatrix, Underline, UnderlineStyle, WindowAppearance, |
| @@ -796,6 +796,7 @@ pub struct Window { · 779 unmodified lines | ||
| 796 | 796 | mouse_position: Point<Pixels>, |
| 797 | 797 | mouse_hit_test: HitTest, |
| 798 | 798 | modifiers: Modifiers, |
| 799 | + capslock: Capslock, | |
| 799 | 800 | scale_factor: f32, |
| 800 | 801 | pub(crate) bounds_observers: SubscriberSet<(), AnyObserver>, |
| 801 | 802 | appearance: WindowAppearance, |
| @@ -907,6 +908,7 @@ impl Window { · 105 unmodified lines | ||
| 907 | 908 | let sprite_atlas = platform_window.sprite_atlas(); |
| 908 | 909 | let mouse_position = platform_window.mouse_position(); |
| 909 | 910 | let modifiers = platform_window.modifiers(); |
| 911 | + let capslock = platform_window.capslock(); | |
| 910 | 912 | let content_size = platform_window.content_size(); |
| 911 | 913 | let scale_factor = platform_window.scale_factor(); |
| 912 | 914 | let appearance = platform_window.appearance(); |
| @@ -1015,6 +1017,7 @@ impl Window { · 102 unmodified lines | ||
| 1015 | 1017 | .update(&mut cx, |_, window, cx| { |
| 1016 | 1018 | window.active.set(active); |
| 1017 | 1019 | window.modifiers = window.platform_window.modifiers(); |
| 1020 | + window.capslock = window.platform_window.capslock(); | |
| 1018 | 1021 | window |
| 1019 | 1022 | .activation_observers |
| 1020 | 1023 | .clone() |
| @@ -1100,6 +1103,7 @@ impl Window { · 79 unmodified lines | ||
| 1100 | 1103 | mouse_position, |
| 1101 | 1104 | mouse_hit_test: HitTest::default(), |
| 1102 | 1105 | modifiers, |
| 1106 | + capslock, | |
| 1103 | 1107 | scale_factor, |
| 1104 | 1108 | bounds_observers: SubscriberSet::new(), |
| 1105 | 1109 | appearance, |
| @@ -1728,6 +1732,11 @@ impl Window { · 622 unmodified lines | ||
| 1728 | 1732 | self.modifiers |
| 1729 | 1733 | } |
| 1730 | 1734 | |
| 1735 | + /// The current state of the keyboard's capslock | |
| 1736 | + pub fn capslock(&self) -> Capslock { | |
| 1737 | + self.capslock | |
| 1738 | + } | |
| 1739 | + | |
| 1731 | 1740 | fn complete_frame(&self) { |
| 1732 | 1741 | self.platform_window.completed_frame(); |
| 1733 | 1742 | } |
| @@ -3352,6 +3361,7 @@ impl Window { · 1618 unmodified lines | ||
| 3352 | 3361 | } |
| 3353 | 3362 | PlatformInput::ModifiersChanged(modifiers_changed) => { |
| 3354 | 3363 | self.modifiers = modifiers_changed.modifiers; |
| 3364 | + self.capslock = modifiers_changed.capslock; | |
| 3355 | 3365 | PlatformInput::ModifiersChanged(modifiers_changed) |
| 3356 | 3366 | } |
| 3357 | 3367 | PlatformInput::ScrollWheel(scroll_wheel) => { |
| @@ -289,6 +289,9 @@ impl Render for SshPrompt { · 288 unmodified lines | ||
| 289 | 289 | .child(MarkdownElement::new(prompt.0.clone(), markdown_style)) |
| 290 | 290 | .child(self.editor.clone()), |
| 291 | 291 | ) |
| 292 | + .when(window.capslock().on, |el| { | |
| 293 | + el.child(Label::new("⚠️ ⇪ is on")) | |
| 294 | + }) | |
| 292 | 295 | }) |
| 293 | 296 | } |
| 294 | 297 | } |