not-fl3/egui-miniquad

Key modifier state after a modifier is pressed or released

Opened this issue · 2 comments

The modifier key state changes are only reaching egui on the next key event. For example, if you press and hold Ctrl and don't press any other key, egui will not know about it. If you then release it, egui will now think it is being held down, until some future key event.

As I understand it, miniquad is passing through (from X11) key up/down events whose modifier state does not include the effect of that event itself. Next, egui-miniquad stores that pre-event modifier state and discards the key event since egui doesn't care about those. It then sends that incorrect state to egui for new frames and with events where miniquad doesn't include the modifier state (e.g. mouse events).

Test program (using egui-miniquad v0.12.0 and miniquad v0.3.13)
use {egui_miniquad as egui_mq, miniquad as mq};

struct Stage {
    egui_mq: egui_mq::EguiMq,
}

impl Stage {
    pub fn new(ctx: &mut mq::Context) -> Stage {
        Stage {
            egui_mq: egui_mq::EguiMq::new(ctx),
        }
    }
}

impl mq::EventHandler for Stage {
    fn update(&mut self, _ctx: &mut mq::Context) {}

    fn draw(&mut self, ctx: &mut mq::Context) {
        self.egui_mq.run(ctx, |mq_ctx, egui_ctx| {
            egui::CentralPanel::default().show(&egui_ctx, |ui| {
                ui.label(format!("{:#?}",ui.input().modifiers));
            });
        });
        self.egui_mq.draw(ctx);
        ctx.commit_frame();
    }

    fn mouse_motion_event(&mut self, _: &mut mq::Context, x: f32, y: f32) {
        self.egui_mq.mouse_motion_event(x, y);
    }

    fn mouse_wheel_event(&mut self, _: &mut mq::Context, dx: f32, dy: f32) {
        self.egui_mq.mouse_wheel_event(dx, dy);
    }

    fn mouse_button_down_event(
        &mut self,
        ctx: &mut mq::Context,
        mb: mq::MouseButton,
        x: f32,
        y: f32,
    ) {
        self.egui_mq.mouse_button_down_event(ctx, mb, x, y);
    }

    fn mouse_button_up_event(
        &mut self,
        ctx: &mut mq::Context,
        mb: mq::MouseButton,
        x: f32,
        y: f32,
    ) {
        self.egui_mq.mouse_button_up_event(ctx, mb, x, y);
    }

    fn char_event(
        &mut self,
        _ctx: &mut mq::Context,
        character: char,
        _keymods: mq::KeyMods,
        _repeat: bool,
    ) {
        self.egui_mq.char_event(character);
    }

    fn key_down_event(
        &mut self,
        ctx: &mut mq::Context,
        keycode: mq::KeyCode,
        keymods: mq::KeyMods,
        _repeat: bool,
    ) {
        if keycode == mq::KeyCode::Q {
            std::process::exit(0);
        }
        println!("---KEY DOWN---");
        dbg!(keycode);
        dbg!(keymods);
        println!("calling egui_mq.key_down_event");
        self.egui_mq.key_down_event(ctx, keycode, keymods);
        println!("---END---");
    }

    fn key_up_event(&mut self, _ctx: &mut mq::Context, keycode: mq::KeyCode, keymods: mq::KeyMods) {
        println!("---KEY UP---");
        dbg!(keycode);
        dbg!(keymods);
        println!("calling egui_mq.key_up_event");
        self.egui_mq.key_up_event(keycode, keymods);
        println!("---END---");
    }
}

fn main() {
    mq::start(Default::default(), |mut ctx| Box::new(Stage::new(&mut ctx)));
}

This similar issue in glfw has some informative discussion: glfw/glfw#1630

I've realized I can easily work around it by changing the keymods in my event handlers, but it's not a general solution since it doesn't properly account for keymaps and likely a bunch of other cases. It now seems that this will need changes in miniquad instead.

Workaround
    fn key_down_event(
        &mut self,
        ctx: &mut mq::Context,
        keycode: mq::KeyCode,
        mut keymods: mq::KeyMods,
        _repeat: bool,
    ) {
        match keycode {
            mq::KeyCode::LeftShift | mq::KeyCode::RightShift => keymods.shift = true,
            mq::KeyCode::LeftControl | mq::KeyCode::RightControl => keymods.ctrl = true,
            mq::KeyCode::LeftAlt /*| mq::KeyCode::RightAlt*/ => keymods.alt = true,
            mq::KeyCode::LeftSuper | mq::KeyCode::RightSuper => keymods.logo = true,
            _ => (),
        }
        self.egui_mq.key_down_event(ctx, keycode, keymods);

    }

    fn key_up_event(&mut self, _ctx: &mut mq::Context, keycode: mq::KeyCode, mut keymods: mq::KeyMods) {
        match keycode {
            mq::KeyCode::LeftShift | mq::KeyCode::RightShift => keymods.shift = false,
            mq::KeyCode::LeftControl | mq::KeyCode::RightControl => keymods.ctrl = false,
            mq::KeyCode::LeftAlt /*| mq::KeyCode::RightAlt*/ => keymods.alt = false,
            mq::KeyCode::LeftSuper | mq::KeyCode::RightSuper => keymods.logo = false,
            _ => (),
        }
        self.egui_mq.key_up_event(keycode, keymods);
    }

use this PR not-fl3/miniquad#313
you can capture the key modifer,
@quaternic