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 | use crate::{ | 1 | use crate::{ |
| 2 | Action, AnyView, AnyWindowHandle, App, AppCell, AppContext, AsyncApp, AvailableSpace, | 2 | Action, AnyView, AnyWindowHandle, App, AppCell, AppContext, AsyncApp, AvailableSpace, |
| 3 | BackgroundExecutor, BorrowAppContext, Bounds, ClipboardItem, DrawPhase, Drawable, Element, | 3 | BackgroundExecutor, BorrowAppContext, Bounds, Capslock, ClipboardItem, DrawPhase, Drawable, |
| 4 | Empty, EventEmitter, ForegroundExecutor, Global, InputEvent, Keystroke, Modifiers, | 4 | Element, Empty, EventEmitter, ForegroundExecutor, Global, InputEvent, Keystroke, Modifiers, |
| 5 | ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, | 5 | ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, |
| 6 | Platform, Point, Render, Result, Size, Task, TestDispatcher, TestPlatform, | 6 | Platform, Point, Render, Result, Size, Task, TestDispatcher, TestPlatform, |
| 7 | TestScreenCaptureSource, TestWindow, TextSystem, VisualContext, Window, WindowBounds, | 7 | TestScreenCaptureSource, TestWindow, TextSystem, VisualContext, Window, WindowBounds, |
| @@ -771,7 +771,18 @@ impl VisualTestContext { · 763 unmodified lines | |||
| 771 | 771 | ||
| 772 | /// Simulate a modifiers changed event | 772 | /// Simulate a modifiers changed event |
| 773 | pub fn simulate_modifiers_change(&mut self, modifiers: Modifiers) { | 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 | /// Simulates the user resizing the window to the new size. | 788 | /// Simulates the user resizing the window to the new size. |
| @@ -1,6 +1,6 @@ | |||
| 1 | use crate::{ | 1 | use crate::{ |
| 2 | Context, Empty, IntoElement, Keystroke, Modifiers, Pixels, Point, Render, Window, point, | 2 | Capslock, Context, Empty, IntoElement, Keystroke, Modifiers, Pixels, Point, Render, Window, |
| 3 | seal::Sealed, | 3 | point, seal::Sealed, |
| 4 | }; | 4 | }; |
| 5 | use smallvec::SmallVec; | 5 | use smallvec::SmallVec; |
| 6 | use std::{any::Any, fmt::Debug, ops::Deref, path::PathBuf}; | 6 | use std::{any::Any, fmt::Debug, ops::Deref, path::PathBuf}; |
| @@ -55,6 +55,8 @@ impl KeyEvent for KeyUpEvent {} · 48 unmodified lines | |||
| 55 | pub struct ModifiersChangedEvent { | 55 | pub struct ModifiersChangedEvent { |
| 56 | /// The new state of the modifier keys | 56 | /// The new state of the modifier keys |
| 57 | pub modifiers: Modifiers, | 57 | pub modifiers: Modifiers, |
| 58 | /// The new state of the capslock key | ||
| 59 | pub capslock: Capslock, | ||
| 58 | } | 60 | } |
| 59 | 61 | ||
| 60 | impl Sealed for ModifiersChangedEvent {} | 62 | impl Sealed for ModifiersChangedEvent {} |
| @@ -415,6 +415,7 @@ pub(crate) trait PlatformWindow: HasWindowHandle + HasDisplayHandle { · 414 unmodified lines | |||
| 415 | fn display(&self) -> Option<Rc<dyn PlatformDisplay>>; | 415 | fn display(&self) -> Option<Rc<dyn PlatformDisplay>>; |
| 416 | fn mouse_position(&self) -> Point<Pixels>; | 416 | fn mouse_position(&self) -> Point<Pixels>; |
| 417 | fn modifiers(&self) -> Modifiers; | 417 | fn modifiers(&self) -> Modifiers; |
| 418 | fn capslock(&self) -> Capslock; | ||
| 418 | fn set_input_handler(&mut self, input_handler: PlatformInputHandler); | 419 | fn set_input_handler(&mut self, input_handler: PlatformInputHandler); |
| 419 | fn take_input_handler(&mut self) -> Option<PlatformInputHandler>; | 420 | fn take_input_handler(&mut self) -> Option<PlatformInputHandler>; |
| 420 | fn prompt( | 421 | fn prompt( |
| @@ -538,3 +538,11 @@ impl Modifiers { · 537 unmodified lines | |||
| 538 | && (other.function || !self.function) | 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 | #[cfg(test)] | 884 | #[cfg(test)] |
| 877 | mod tests { | 885 | mod tests { |
| 878 | use super::*; | 886 | use super::*; |
| @@ -73,7 +73,7 @@ use super::{ · 72 unmodified lines | |||
| 73 | 73 | ||
| 74 | use crate::platform::{PlatformWindow, blade::BladeContext}; | 74 | use crate::platform::{PlatformWindow, blade::BladeContext}; |
| 75 | use crate::{ | 75 | use crate::{ |
| 76 | AnyWindowHandle, Bounds, CursorStyle, DOUBLE_CLICK_INTERVAL, DevicePixels, DisplayId, | 76 | AnyWindowHandle, Bounds, Capslock, CursorStyle, DOUBLE_CLICK_INTERVAL, DevicePixels, DisplayId, |
| 77 | FileDropEvent, ForegroundExecutor, KeyDownEvent, KeyUpEvent, Keystroke, LinuxCommon, | 77 | FileDropEvent, ForegroundExecutor, KeyDownEvent, KeyUpEvent, Keystroke, LinuxCommon, |
| 78 | LinuxKeyboardLayout, Modifiers, ModifiersChangedEvent, MouseButton, MouseDownEvent, | 78 | LinuxKeyboardLayout, Modifiers, ModifiersChangedEvent, MouseButton, MouseDownEvent, |
| 79 | MouseExitEvent, MouseMoveEvent, MouseUpEvent, NavigationDirection, Pixels, PlatformDisplay, | 79 | MouseExitEvent, MouseMoveEvent, MouseUpEvent, NavigationDirection, Pixels, PlatformDisplay, |
| @@ -217,6 +217,7 @@ pub(crate) struct WaylandClientState { · 137 unmodified lines | |||
| 217 | click: ClickState, | 217 | click: ClickState, |
| 218 | repeat: KeyRepeat, | 218 | repeat: KeyRepeat, |
| 219 | pub modifiers: Modifiers, | 219 | pub modifiers: Modifiers, |
| 220 | pub capslock: Capslock, | ||
| 220 | axis_source: AxisSource, | 221 | axis_source: AxisSource, |
| 221 | pub mouse_location: Option<Point<Pixels>>, | 222 | pub mouse_location: Option<Point<Pixels>>, |
| 222 | continuous_scroll_delta: Option<Point<Pixels>>, | 223 | continuous_scroll_delta: Option<Point<Pixels>>, |
| @@ -595,6 +596,7 @@ impl WaylandClient { · 372 unmodified lines | |||
| 595 | function: false, | 596 | function: false, |
| 596 | platform: false, | 597 | platform: false, |
| 597 | }, | 598 | }, |
| 599 | capslock: Capslock { on: false }, | ||
| 598 | scroll_event_received: false, | 600 | scroll_event_received: false, |
| 599 | axis_source: AxisSource::Wheel, | 601 | axis_source: AxisSource::Wheel, |
| 600 | mouse_location: None, | 602 | mouse_location: None, |
| @@ -1251,9 +1253,12 @@ impl Dispatch<wl_keyboard::WlKeyboard, ()> for WaylandClientStatePtr { · 650 unmodified lines | |||
| 1251 | keymap_state.serialize_layout(xkbcommon::xkb::STATE_LAYOUT_EFFECTIVE); | 1253 | keymap_state.serialize_layout(xkbcommon::xkb::STATE_LAYOUT_EFFECTIVE); |
| 1252 | keymap_state.update_mask(mods_depressed, mods_latched, mods_locked, 0, 0, group); | 1254 | keymap_state.update_mask(mods_depressed, mods_latched, mods_locked, 0, 0, group); |
| 1253 | state.modifiers = Modifiers::from_xkb(keymap_state); | 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 | let input = PlatformInput::ModifiersChanged(ModifiersChangedEvent { | 1259 | let input = PlatformInput::ModifiersChanged(ModifiersChangedEvent { |
| 1256 | modifiers: state.modifiers, | 1260 | modifiers: state.modifiers, |
| 1261 | capslock: state.capslock, | ||
| 1257 | }); | 1262 | }); |
| 1258 | drop(state); | 1263 | drop(state); |
| 1259 | 1264 | ||
| @@ -21,11 +21,6 @@ use wayland_protocols::xdg::shell::client::xdg_surface; · 20 unmodified lines | |||
| 21 | use wayland_protocols::xdg::shell::client::xdg_toplevel::{self}; | 21 | use wayland_protocols::xdg::shell::client::xdg_toplevel::{self}; |
| 22 | use wayland_protocols_plasma::blur::client::org_kde_kwin_blur; | 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 | use crate::scene::Scene; | 24 | use crate::scene::Scene; |
| 30 | use crate::{ | 25 | use crate::{ |
| 31 | AnyWindowHandle, Bounds, Decorations, Globals, GpuSpecs, Modifiers, Output, Pixels, | 26 | AnyWindowHandle, Bounds, Decorations, Globals, GpuSpecs, Modifiers, Output, Pixels, |
| @@ -34,6 +29,14 @@ use crate::{ · 2 unmodified lines | |||
| 34 | WindowBackgroundAppearance, WindowBounds, WindowControlArea, WindowControls, WindowDecorations, | 29 | WindowBackgroundAppearance, WindowBounds, WindowControlArea, WindowControls, WindowDecorations, |
| 35 | WindowParams, px, size, | 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 | #[derive(Default)] | 41 | #[derive(Default)] |
| 39 | pub(crate) struct Callbacks { | 42 | pub(crate) struct Callbacks { |
| @@ -861,6 +864,10 @@ impl PlatformWindow for WaylandWindow { · 821 unmodified lines | |||
| 861 | self.borrow().client.get_client().borrow().modifiers | 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 | fn set_input_handler(&mut self, input_handler: PlatformInputHandler) { | 871 | fn set_input_handler(&mut self, input_handler: PlatformInputHandler) { |
| 865 | self.borrow_mut().input_handler = Some(input_handler); | 872 | self.borrow_mut().input_handler = Some(input_handler); |
| 866 | } | 873 | } |
| @@ -1,3 +1,4 @@ | |||
| 1 | use crate::Capslock; | ||
| 1 | use core::str; | 2 | use core::str; |
| 2 | use std::{ | 3 | use std::{ |
| 3 | cell::RefCell, | 4 | cell::RefCell, |
| @@ -203,8 +204,11 @@ pub struct X11ClientState { · 199 unmodified lines | |||
| 203 | pub(crate) ximc: Option<X11rbClient<Rc<XCBConnection>>>, | 204 | pub(crate) ximc: Option<X11rbClient<Rc<XCBConnection>>>, |
| 204 | pub(crate) xim_handler: Option<XimHandler>, | 205 | pub(crate) xim_handler: Option<XimHandler>, |
| 205 | pub modifiers: Modifiers, | 206 | pub modifiers: Modifiers, |
| 207 | pub capslock: Capslock, | ||
| 206 | // TODO: Can the other updates to `modifiers` be removed so that this is unnecessary? | 208 | // TODO: Can the other updates to `modifiers` be removed so that this is unnecessary? |
| 209 | // capslock logic was done analog to modifiers | ||
| 207 | pub last_modifiers_changed_event: Modifiers, | 210 | pub last_modifiers_changed_event: Modifiers, |
| 211 | pub last_capslock_changed_event: Capslock, | ||
| 208 | 212 | ||
| 209 | pub(crate) compose_state: Option<xkbc::compose::State>, | 213 | pub(crate) compose_state: Option<xkbc::compose::State>, |
| 210 | pub(crate) pre_edit_text: Option<String>, | 214 | pub(crate) pre_edit_text: Option<String>, |
| @@ -473,7 +477,9 @@ impl X11Client { · 262 unmodified lines | |||
| 473 | 477 | ||
| 474 | X11Client(Rc::new(RefCell::new(X11ClientState { | 478 | X11Client(Rc::new(RefCell::new(X11ClientState { |
| 475 | modifiers: Modifiers::default(), | 479 | modifiers: Modifiers::default(), |
| 480 | capslock: Capslock::default(), | ||
| 476 | last_modifiers_changed_event: Modifiers::default(), | 481 | last_modifiers_changed_event: Modifiers::default(), |
| 482 | last_capslock_changed_event: Capslock::default(), | ||
| 477 | event_loop: Some(event_loop), | 483 | event_loop: Some(event_loop), |
| 478 | loop_handle: handle, | 484 | loop_handle: handle, |
| 479 | common, | 485 | common, |
| @@ -961,17 +967,25 @@ impl X11Client { · 481 unmodified lines | |||
| 961 | }; | 967 | }; |
| 962 | 968 | ||
| 963 | let modifiers = Modifiers::from_xkb(&state.xkb); | 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 | drop(state); | 974 | drop(state); |
| 966 | } else { | 975 | } else { |
| 967 | let focused_window_id = state.keyboard_focused_window?; | 976 | let focused_window_id = state.keyboard_focused_window?; |
| 968 | state.modifiers = modifiers; | 977 | state.modifiers = modifiers; |
| 969 | state.last_modifiers_changed_event = modifiers; | 978 | state.last_modifiers_changed_event = modifiers; |
| 979 | state.capslock = capslock; | ||
| 980 | state.last_capslock_changed_event = capslock; | ||
| 970 | drop(state); | 981 | drop(state); |
| 971 | 982 | ||
| 972 | let focused_window = self.get_window(focused_window_id)?; | 983 | let focused_window = self.get_window(focused_window_id)?; |
| 973 | focused_window.handle_input(PlatformInput::ModifiersChanged( | 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 | .unwrap_or_default() | 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 | fn set_input_handler(&mut self, input_handler: PlatformInputHandler) { | 1229 | fn set_input_handler(&mut self, input_handler: PlatformInputHandler) { |
| 1219 | self.0.state.borrow_mut().input_handler = Some(input_handler); | 1230 | self.0.state.borrow_mut().input_handler = Some(input_handler); |
| 1220 | } | 1231 | } |
| @@ -1,5 +1,5 @@ | |||
| 1 | use crate::{ | 1 | use crate::{ |
| 2 | KeyDownEvent, KeyUpEvent, Keystroke, Modifiers, ModifiersChangedEvent, MouseButton, | 2 | Capslock, KeyDownEvent, KeyUpEvent, Keystroke, Modifiers, ModifiersChangedEvent, MouseButton, |
| 3 | MouseDownEvent, MouseExitEvent, MouseMoveEvent, MouseUpEvent, NavigationDirection, Pixels, | 3 | MouseDownEvent, MouseExitEvent, MouseMoveEvent, MouseUpEvent, NavigationDirection, Pixels, |
| 4 | PlatformInput, ScrollDelta, ScrollWheelEvent, TouchPhase, | 4 | PlatformInput, ScrollDelta, ScrollWheelEvent, TouchPhase, |
| 5 | platform::mac::{ | 5 | platform::mac::{ |
| @@ -121,6 +121,11 @@ impl PlatformInput { · 115 unmodified lines | |||
| 121 | NSEventType::NSFlagsChanged => { | 121 | NSEventType::NSFlagsChanged => { |
| 122 | Some(Self::ModifiersChanged(ModifiersChangedEvent { | 122 | Some(Self::ModifiersChanged(ModifiersChangedEvent { |
| 123 | modifiers: read_modifiers(native_event), | 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 | NSEventType::NSKeyDown => Some(Self::KeyDown(KeyDownEvent { | 131 | NSEventType::NSKeyDown => Some(Self::KeyDown(KeyDownEvent { |
| @@ -1,11 +1,11 @@ | |||
| 1 | use super::{BoolExt, MacDisplay, NSRange, NSStringExt, ns_string, renderer}; | 1 | use super::{BoolExt, MacDisplay, NSRange, NSStringExt, ns_string, renderer}; |
| 2 | use crate::{ | 2 | use crate::{ |
| 3 | AnyWindowHandle, Bounds, DisplayLink, ExternalPaths, FileDropEvent, ForegroundExecutor, | 3 | AnyWindowHandle, Bounds, Capslock, DisplayLink, ExternalPaths, FileDropEvent, |
| 4 | KeyDownEvent, Keystroke, Modifiers, ModifiersChangedEvent, MouseButton, MouseDownEvent, | 4 | ForegroundExecutor, KeyDownEvent, Keystroke, Modifiers, ModifiersChangedEvent, MouseButton, |
| 5 | MouseMoveEvent, MouseUpEvent, Pixels, PlatformAtlas, PlatformDisplay, PlatformInput, | 5 | MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, PlatformAtlas, PlatformDisplay, |
| 6 | PlatformWindow, Point, PromptButton, PromptLevel, RequestFrameOptions, ScaledPixels, Size, | 6 | PlatformInput, PlatformWindow, Point, PromptButton, PromptLevel, RequestFrameOptions, |
| 7 | Timer, WindowAppearance, WindowBackgroundAppearance, WindowBounds, WindowControlArea, | 7 | ScaledPixels, Size, Timer, WindowAppearance, WindowBackgroundAppearance, WindowBounds, |
| 8 | WindowKind, WindowParams, platform::PlatformInputHandler, point, px, size, | 8 | WindowControlArea, WindowKind, WindowParams, platform::PlatformInputHandler, point, px, size, |
| 9 | }; | 9 | }; |
| 10 | use block::ConcreteBlock; | 10 | use block::ConcreteBlock; |
| 11 | use cocoa::{ | 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 | fn set_input_handler(&mut self, input_handler: PlatformInputHandler) { | 903 | fn set_input_handler(&mut self, input_handler: PlatformInputHandler) { |
| 894 | self.0.as_ref().lock().input_handler = Some(input_handler); | 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 | lock.synthetic_drag_counter += 1; | 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 | // Only raise modifiers changed event when they have actually changed | 1573 | // Only raise modifiers changed event when they have actually changed |
| 1561 | if let Some(PlatformInput::ModifiersChanged(ModifiersChangedEvent { | 1574 | if let Some(PlatformInput::ModifiersChanged(ModifiersChangedEvent { |
| 1562 | modifiers: prev_modifiers, | 1575 | modifiers: prev_modifiers, |
| 1576 | capslock: prev_capslock, | ||
| 1563 | })) = &lock.previous_modifiers_changed_event | 1577 | })) = &lock.previous_modifiers_changed_event |
| 1564 | { | 1578 | { |
| 1565 | if prev_modifiers == modifiers { | 1579 | if prev_modifiers == modifiers && prev_capslock == capslock { |
| 1566 | return; | 1580 | return; |
| 1567 | } | 1581 | } |
| 1568 | } | 1582 | } |
| @@ -153,6 +153,10 @@ impl PlatformWindow for TestWindow { · 152 unmodified lines | |||
| 153 | crate::Modifiers::default() | 153 | crate::Modifiers::default() |
| 154 | } | 154 | } |
| 155 | 155 | ||
| 156 | fn capslock(&self) -> crate::Capslock { | ||
| 157 | crate::Capslock::default() | ||
| 158 | } | ||
| 159 | |||
| 156 | fn set_input_handler(&mut self, input_handler: PlatformInputHandler) { | 160 | fn set_input_handler(&mut self, input_handler: PlatformInputHandler) { |
| 157 | self.0.lock().input_handler = Some(input_handler); | 161 | self.0.lock().input_handler = Some(input_handler); |
| 158 | } | 162 | } |
| @@ -1227,6 +1227,7 @@ where · 1226 unmodified lines | |||
| 1227 | { | 1227 | { |
| 1228 | let virtual_key = VIRTUAL_KEY(wparam.loword()); | 1228 | let virtual_key = VIRTUAL_KEY(wparam.loword()); |
| 1229 | let mut modifiers = current_modifiers(); | 1229 | let mut modifiers = current_modifiers(); |
| 1230 | let capslock = current_capslock(); | ||
| 1230 | 1231 | ||
| 1231 | match virtual_key { | 1232 | match virtual_key { |
| 1232 | VK_SHIFT | VK_CONTROL | VK_MENU | VK_LWIN | VK_RWIN => { | 1233 | VK_SHIFT | VK_CONTROL | VK_MENU | VK_LWIN | VK_RWIN => { |
| @@ -1239,6 +1240,7 @@ where · 6 unmodified lines | |||
| 1239 | state.last_reported_modifiers = Some(modifiers); | 1240 | state.last_reported_modifiers = Some(modifiers); |
| 1240 | Some(PlatformInput::ModifiersChanged(ModifiersChangedEvent { | 1241 | Some(PlatformInput::ModifiersChanged(ModifiersChangedEvent { |
| 1241 | modifiers, | 1242 | modifiers, |
| 1243 | capslock, | ||
| 1242 | })) | 1244 | })) |
| 1243 | } | 1245 | } |
| 1244 | vkey => { | 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 | fn get_client_area_insets( | 1382 | fn get_client_area_insets( |
| 1375 | handle: HWND, | 1383 | handle: HWND, |
| 1376 | is_maximized: bool, | 1384 | is_maximized: bool, |
| @@ -559,6 +559,10 @@ impl PlatformWindow for WindowsWindow { · 558 unmodified lines | |||
| 559 | current_modifiers() | 559 | current_modifiers() |
| 560 | } | 560 | } |
| 561 | 561 | ||
| 562 | fn capslock(&self) -> Capslock { | ||
| 563 | current_capslock() | ||
| 564 | } | ||
| 565 | |||
| 562 | fn set_input_handler(&mut self, input_handler: PlatformInputHandler) { | 566 | fn set_input_handler(&mut self, input_handler: PlatformInputHandler) { |
| 563 | self.0.state.borrow_mut().input_handler = Some(input_handler); | 567 | self.0.state.borrow_mut().input_handler = Some(input_handler); |
| 564 | } | 568 | } |
| @@ -2,15 +2,15 @@ · 1 unmodified line | |||
| 2 | use crate::Inspector; | 2 | use crate::Inspector; |
| 3 | use crate::{ | 3 | use crate::{ |
| 4 | Action, AnyDrag, AnyElement, AnyImageCache, AnyTooltip, AnyView, App, AppContext, Arena, Asset, | 4 | Action, AnyDrag, AnyElement, AnyImageCache, AnyTooltip, AnyView, App, AppContext, Arena, Asset, |
| 5 | AsyncWindowContext, AvailableSpace, Background, BorderStyle, Bounds, BoxShadow, Context, | 5 | AsyncWindowContext, AvailableSpace, Background, BorderStyle, Bounds, BoxShadow, Capslock, |
| 6 | Corners, CursorStyle, Decorations, DevicePixels, DispatchActionListener, DispatchNodeId, | 6 | Context, Corners, CursorStyle, Decorations, DevicePixels, DispatchActionListener, |
| 7 | DispatchTree, DisplayId, Edges, Effect, Entity, EntityId, EventEmitter, FileDropEvent, FontId, | 7 | DispatchNodeId, DispatchTree, DisplayId, Edges, Effect, Entity, EntityId, EventEmitter, |
| 8 | Global, GlobalElementId, GlyphId, GpuSpecs, Hsla, InputHandler, IsZero, KeyBinding, KeyContext, | 8 | FileDropEvent, FontId, Global, GlobalElementId, GlyphId, GpuSpecs, Hsla, InputHandler, IsZero, |
| 9 | KeyDownEvent, KeyEvent, Keystroke, KeystrokeEvent, LayoutId, LineLayoutIndex, Modifiers, | 9 | KeyBinding, KeyContext, KeyDownEvent, KeyEvent, Keystroke, KeystrokeEvent, LayoutId, |
| 10 | ModifiersChangedEvent, MonochromeSprite, MouseButton, MouseEvent, MouseMoveEvent, MouseUpEvent, | 10 | LineLayoutIndex, Modifiers, ModifiersChangedEvent, MonochromeSprite, MouseButton, MouseEvent, |
| 11 | Path, Pixels, PlatformAtlas, PlatformDisplay, PlatformInput, PlatformInputHandler, | 11 | MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas, PlatformDisplay, PlatformInput, |
| 12 | PlatformWindow, Point, PolychromeSprite, PromptButton, PromptLevel, Quad, Render, | 12 | PlatformInputHandler, PlatformWindow, Point, PolychromeSprite, PromptButton, PromptLevel, Quad, |
| 13 | RenderGlyphParams, RenderImage, RenderImageParams, RenderSvgParams, Replay, ResizeEdge, | 13 | Render, RenderGlyphParams, RenderImage, RenderImageParams, RenderSvgParams, Replay, ResizeEdge, |
| 14 | SMOOTH_SVG_SCALE_FACTOR, SUBPIXEL_VARIANTS, ScaledPixels, Scene, Shadow, SharedString, Size, | 14 | SMOOTH_SVG_SCALE_FACTOR, SUBPIXEL_VARIANTS, ScaledPixels, Scene, Shadow, SharedString, Size, |
| 15 | StrikethroughStyle, Style, SubscriberSet, Subscription, TaffyLayoutEngine, Task, TextStyle, | 15 | StrikethroughStyle, Style, SubscriberSet, Subscription, TaffyLayoutEngine, Task, TextStyle, |
| 16 | TextStyleRefinement, TransformationMatrix, Underline, UnderlineStyle, WindowAppearance, | 16 | TextStyleRefinement, TransformationMatrix, Underline, UnderlineStyle, WindowAppearance, |
| @@ -796,6 +796,7 @@ pub struct Window { · 779 unmodified lines | |||
| 796 | mouse_position: Point<Pixels>, | 796 | mouse_position: Point<Pixels>, |
| 797 | mouse_hit_test: HitTest, | 797 | mouse_hit_test: HitTest, |
| 798 | modifiers: Modifiers, | 798 | modifiers: Modifiers, |
| 799 | capslock: Capslock, | ||
| 799 | scale_factor: f32, | 800 | scale_factor: f32, |
| 800 | pub(crate) bounds_observers: SubscriberSet<(), AnyObserver>, | 801 | pub(crate) bounds_observers: SubscriberSet<(), AnyObserver>, |
| 801 | appearance: WindowAppearance, | 802 | appearance: WindowAppearance, |
| @@ -907,6 +908,7 @@ impl Window { · 105 unmodified lines | |||
| 907 | let sprite_atlas = platform_window.sprite_atlas(); | 908 | let sprite_atlas = platform_window.sprite_atlas(); |
| 908 | let mouse_position = platform_window.mouse_position(); | 909 | let mouse_position = platform_window.mouse_position(); |
| 909 | let modifiers = platform_window.modifiers(); | 910 | let modifiers = platform_window.modifiers(); |
| 911 | let capslock = platform_window.capslock(); | ||
| 910 | let content_size = platform_window.content_size(); | 912 | let content_size = platform_window.content_size(); |
| 911 | let scale_factor = platform_window.scale_factor(); | 913 | let scale_factor = platform_window.scale_factor(); |
| 912 | let appearance = platform_window.appearance(); | 914 | let appearance = platform_window.appearance(); |
| @@ -1015,6 +1017,7 @@ impl Window { · 102 unmodified lines | |||
| 1015 | .update(&mut cx, |_, window, cx| { | 1017 | .update(&mut cx, |_, window, cx| { |
| 1016 | window.active.set(active); | 1018 | window.active.set(active); |
| 1017 | window.modifiers = window.platform_window.modifiers(); | 1019 | window.modifiers = window.platform_window.modifiers(); |
| 1020 | window.capslock = window.platform_window.capslock(); | ||
| 1018 | window | 1021 | window |
| 1019 | .activation_observers | 1022 | .activation_observers |
| 1020 | .clone() | 1023 | .clone() |
| @@ -1100,6 +1103,7 @@ impl Window { · 79 unmodified lines | |||
| 1100 | mouse_position, | 1103 | mouse_position, |
| 1101 | mouse_hit_test: HitTest::default(), | 1104 | mouse_hit_test: HitTest::default(), |
| 1102 | modifiers, | 1105 | modifiers, |
| 1106 | capslock, | ||
| 1103 | scale_factor, | 1107 | scale_factor, |
| 1104 | bounds_observers: SubscriberSet::new(), | 1108 | bounds_observers: SubscriberSet::new(), |
| 1105 | appearance, | 1109 | appearance, |
| @@ -1728,6 +1732,11 @@ impl Window { · 622 unmodified lines | |||
| 1728 | self.modifiers | 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 | fn complete_frame(&self) { | 1740 | fn complete_frame(&self) { |
| 1732 | self.platform_window.completed_frame(); | 1741 | self.platform_window.completed_frame(); |
| 1733 | } | 1742 | } |
| @@ -3352,6 +3361,7 @@ impl Window { · 1618 unmodified lines | |||
| 3352 | } | 3361 | } |
| 3353 | PlatformInput::ModifiersChanged(modifiers_changed) => { | 3362 | PlatformInput::ModifiersChanged(modifiers_changed) => { |
| 3354 | self.modifiers = modifiers_changed.modifiers; | 3363 | self.modifiers = modifiers_changed.modifiers; |
| 3364 | self.capslock = modifiers_changed.capslock; | ||
| 3355 | PlatformInput::ModifiersChanged(modifiers_changed) | 3365 | PlatformInput::ModifiersChanged(modifiers_changed) |
| 3356 | } | 3366 | } |
| 3357 | PlatformInput::ScrollWheel(scroll_wheel) => { | 3367 | PlatformInput::ScrollWheel(scroll_wheel) => { |
| @@ -289,6 +289,9 @@ impl Render for SshPrompt { · 288 unmodified lines | |||
| 289 | .child(MarkdownElement::new(prompt.0.clone(), markdown_style)) | 289 | .child(MarkdownElement::new(prompt.0.clone(), markdown_style)) |
| 290 | .child(self.editor.clone()), | 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 | } |