fix: Bildschirmtastatur unter GNOME/Wayland (Issue #21)
GNOME blendet die Bildschirmtastatur erst ein, wenn ein bereits aktives Textfeld zwp_text_input_v3.enable erneut meldet (wie GTK beim Antippen). winit meldet enable nur einmal. Ein eigenes text-input-Objekt auf derselben Wayland-Verbindung schickt das zweite enable, wenn ein Textfeld den Fokus bekommt oder erneut angetippt wird. - Zeichen der Bildschirmtastatur kommen als IME-Text ohne Vorschau; egui 0.27 fügte davon nur das erste ein. Sie werden jetzt als normaler Text übergeben. - Die Rücktaste löscht über delete_surrounding_text; dafür meldet das eigene Objekt einen Platzhalter-Umgebungstext und übersetzt das Löschen in Tastendrücke. - Ein Fingertipp ging verloren, wenn GNOME beim Antippen den Mauszeiger ausblendet (CursorLeft bei aufliegendem Finger); das Ereignis erreicht egui in dem Fall nicht mehr. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1148851585
commit
6fb190cf79
5 files changed
+355
-2
No files matched your search
+52
-2
@@ -12,6 +12,7 @@ use winit::{
|
||||
event_loop::{ControlFlow, EventLoopBuilder},
|
||||
keyboard::{Key, ModifiersState, NamedKey},
|
||||
platform::{wayland::EventLoopBuilderExtWayland, x11::EventLoopBuilderExtX11},
|
||||
raw_window_handle::{HasDisplayHandle, RawDisplayHandle},
|
||||
window::{Window, WindowBuilder},
|
||||
};
|
||||
|
||||
@@ -25,6 +26,7 @@ use ink_notes::export::{self, export_notebook_to_pdf, ExportStrategy};
|
||||
use ink_notes::geometry::{self, RecognizedShape};
|
||||
use ink_notes::image_layer::TextureSource;
|
||||
use ink_notes::library::Library;
|
||||
use ink_notes::osk::{self, KeyboardRequester};
|
||||
use ink_notes::pdf_doc::PdfRenderService;
|
||||
use ink_notes::platform::{self, DisplayBackend};
|
||||
use ink_notes::selection::{
|
||||
@@ -1148,6 +1150,17 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
}
|
||||
};
|
||||
|
||||
// Bildschirmtastatur (nur Wayland): eigenes text-input-Objekt, siehe osk.rs
|
||||
let mut keyboard_requester = match window.display_handle().map(|handle| handle.as_raw()) {
|
||||
// Safety: `window` lebt bis zum Ende von main, die Event-Schleife besitzt beide
|
||||
Ok(RawDisplayHandle::Wayland(handle)) => {
|
||||
Some(unsafe { KeyboardRequester::new(handle.display.as_ptr()) })
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
let mut ime_was_active = false;
|
||||
let mut ime_composing = false;
|
||||
|
||||
// 1. Notizbuch aus Storage laden oder initialisieren (Session-Wiederherstellung)
|
||||
let storage_base_dir = storage::default_storage_dir();
|
||||
let _ = storage::cleanup_trash(
|
||||
@@ -1307,6 +1320,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut pinch_prev_distance: Option<f32> = None;
|
||||
// Berührungen, die auf der UI begonnen haben, gehören bis zum Abheben egui
|
||||
let mut ui_touch_ids: std::collections::HashSet<u64> = std::collections::HashSet::new();
|
||||
// Alle aufliegenden Finger (auch auf der UI), unabhängig von der Gestenauswertung
|
||||
let mut touches_down: std::collections::HashSet<u64> = std::collections::HashSet::new();
|
||||
let mut pinch_prev_center: Option<(f32, f32)> = None;
|
||||
let mut is_pinch_gesturing = false;
|
||||
let mut is_touch_drawing = false;
|
||||
@@ -1869,7 +1884,30 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
||||
Event::WindowEvent { event, window_id } if window_id == window.id() => {
|
||||
// 1. Window-Event zuerst an egui übergeben
|
||||
let egui_response = egui_winit_state.on_window_event(&window, &event);
|
||||
if let WindowEvent::Touch(touch) = &event {
|
||||
match touch.phase {
|
||||
TouchPhase::Started => {
|
||||
touches_down.insert(touch.id);
|
||||
}
|
||||
TouchPhase::Ended | TouchPhase::Cancelled => {
|
||||
touches_down.remove(&touch.id);
|
||||
}
|
||||
TouchPhase::Moved => {}
|
||||
}
|
||||
}
|
||||
// Beim Antippen blendet GNOME den Mauszeiger aus und meldet CursorLeft, während der
|
||||
// Finger noch aufliegt. egui-winit verwirft dabei die Zeigerposition und meldet das
|
||||
// Abheben nicht mehr, der Tipp ginge verloren – daher erfährt egui davon nichts.
|
||||
let egui_response = if matches!(event, WindowEvent::CursorLeft { .. })
|
||||
&& !touches_down.is_empty()
|
||||
{
|
||||
egui_winit::EventResponse {
|
||||
repaint: true,
|
||||
consumed: false,
|
||||
}
|
||||
} else {
|
||||
egui_winit_state.on_window_event(&window, &event)
|
||||
};
|
||||
if egui_response.repaint {
|
||||
window.request_redraw();
|
||||
}
|
||||
@@ -2938,7 +2976,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
}
|
||||
|
||||
// 1. egui Eingabe erfassen und Frame starten
|
||||
let raw_input = egui_winit_state.take_egui_input(&window);
|
||||
let mut raw_input = egui_winit_state.take_egui_input(&window);
|
||||
osk::plain_ime_commits_to_text(&mut raw_input.events, &mut ime_composing);
|
||||
if let Some(requester) = keyboard_requester.as_mut() {
|
||||
raw_input.events.extend(requester.take_deletions());
|
||||
}
|
||||
egui_ctx.begin_frame(raw_input);
|
||||
|
||||
// 2. Auswahl-Overlay rendern (Bounding Box, Griffe, Lasso)
|
||||
@@ -3702,7 +3744,15 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
||||
// 4. egui Frame beenden & Primitives tessellieren
|
||||
let full_output = egui_ctx.end_frame();
|
||||
let ime_active = full_output.platform_output.ime.is_some();
|
||||
egui_winit_state.handle_platform_output(&window, full_output.platform_output);
|
||||
if let Some(requester) = keyboard_requester.as_mut() {
|
||||
let pressed = egui_ctx.input(|i| i.pointer.any_pressed());
|
||||
if osk::should_request(ime_was_active, ime_active, pressed) {
|
||||
requester.request();
|
||||
}
|
||||
}
|
||||
ime_was_active = ime_active;
|
||||
|
||||
// egui braucht Folge-Frames, z. B. um neu angeordnete Bereiche zu vermessen
|
||||
// (die Werkzeugleiste wird erst im 2.–3. Frame korrekt zentriert)
|
||||
|
||||
Reference in new issue
Block a user