Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(#620) Enabling keyboard LEDs when the modifier state changes #3441

Merged
merged 1 commit into from
Jul 11, 2024

Conversation

mattkae
Copy link
Contributor

@mattkae mattkae commented Jun 24, 2024

fixes #620

What's new?

  • XkbMapper takes a callback for when the leds need to be updated for a device
  • Whenever a modifier is changed for a device, XkbMapper notifies the corresponding device of a possible change to its LEDs using Device::set_leds
  • In the case if a libinput device,LibInputDevice::set_leds calls libinput_device_led_update to update the LEDs

@mattkae mattkae changed the title Feature/620 WIP: Do not review! (#620) Enabling keyboard LEDs when the modifier state changes Jun 24, 2024
Copy link

codecov bot commented Jun 24, 2024

Codecov Report

Attention: Patch coverage is 73.53760% with 95 lines in your changes missing coverage. Please review.

Project coverage is 77.14%. Comparing base (317060e) to head (de5f7f5).

Files Patch % Lines
src/server/input/xkb_mapper_registrar.cpp 75.26% 71 Missing ⚠️
src/platforms/evdev/libinput_device.cpp 30.76% 18 Missing ⚠️
...ude/mir/test/doubles/mock_led_observer_registrar.h 0.00% 2 Missing ⚠️
tests/mir_test_doubles/mock_libinput.cpp 0.00% 2 Missing ⚠️
src/server/input/default_configuration.cpp 90.00% 1 Missing ⚠️
tests/include/mir/test/doubles/mock_libinput.h 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3441      +/-   ##
==========================================
- Coverage   77.45%   77.14%   -0.32%     
==========================================
  Files        1073     1076       +3     
  Lines       68782    69118     +336     
==========================================
+ Hits        53278    53323      +45     
- Misses      15504    15795     +291     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@mattkae mattkae changed the title WIP: Do not review! (#620) Enabling keyboard LEDs when the modifier state changes (#620) Enabling keyboard LEDs when the modifier state changes Jun 24, 2024
@mattkae mattkae requested a review from RAOF June 25, 2024 13:10
@mattkae mattkae marked this pull request as ready for review June 25, 2024 13:10
@mattkae mattkae requested a review from a team as a code owner June 25, 2024 13:10
Comment on lines 70 to 71

virtual void set_leds(KeyboardLeds leds) = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just noting that this is a platform ABI break

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this change, and the ABI break are now unnecessary

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think this is unnecessary here (as is the ABI break)

Copy link
Contributor

@AlanGriffiths AlanGriffiths left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My first thought is that this should be more explicit.

  • Keyboard devices register for modifier state updates
  • Modifier updates are passed through that registrar

The only question then is whether the register is a new object or just a new interface supported by XKBMapper

(Maybe you can shoot this idea down though?)

src/platforms/evdev/libinput_device.cpp Outdated Show resolved Hide resolved
Comment on lines 333 to 339
{
the_default_input_device_hub()->for_each_mutable_input_device([&](mir::input::Device& device)
{
if (device.id() == device_id)
device.set_leds(leds);
});
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably capture the_default_input_device_hub(), not call it every time the mapping state changes.

And, surely, there could be a more direct way from XKBMapper to the corresponding device than scanning everything registered on the device hub? (E.g. a map MirInputDeviceId -> callback)

Copy link
Contributor Author

@mattkae mattkae Jun 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is that the_default_input_device_hub() also relies on the the_key_mapper(), so it's a circular dependency. I will see if there is some other way around this, perhaps with the "registration" idea that you said earlier.

@mattkae mattkae force-pushed the feature/620 branch 3 times, most recently from 49b787c to b361733 Compare June 27, 2024 17:27
Copy link
Contributor

@AlanGriffiths AlanGriffiths left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After we spoke I thought you were going to propose a solution that preserved ABI. This isn't that

#include "mir/input/xkb_mapper.h"
#include "mir/input/xkb_mapper_deprecated.h"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would we rename the file and break downstreams that use it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the tricky part is that the import will be the same when we include mir/input/xkb_mapper.h. So one of them has to be named differently, and I chose the old one.

Would it be a better idea to rename the new one to something slightly different? Or is there a better solution?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, I thought "we don't change old stuff, just deprecate it". New stuff can be called by new names, old stuff cannot

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see why KeyMapper is being changed. Especially when there are now two different definitions

Comment on lines 70 to 71

virtual void set_leds(KeyboardLeds leds) = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this change, and the ABI break are now unnecessary

Comment on lines 35 to 41
class KeyMapperObserver
{
public:
virtual ~KeyMapperObserver() = default;
virtual void leds_set(MirInputDeviceId id, KeyboardLeds leds) = 0;
};

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't a KeyMapper observer. It is a LED state observer.

We should be keeping the KeyMapper interface unchanged. The ObserverRegister can be part of another interface implemented by XkbMapper.

Also, wouldn't it be better to register with the device id and only send notifications to the corresponding device. (And not notify all devices most of which drop the notification.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup I agree 👍

@@ -39,6 +40,26 @@

namespace mi = mir::input;

namespace
{
class DefaultInputDeviceHubKeyMapperObserver : public mi::KeyMapperObserver
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the DefaultInputDeviceHub should be registering. Only devices that support LEDs

@mattkae mattkae force-pushed the feature/620 branch 2 times, most recently from 4ac484a to 24e5e33 Compare June 28, 2024 20:14
Comment on lines 28 to 33
class LedObserver
{
public:
virtual ~LedObserver() = default;
virtual void leds_set(MirInputDeviceId id, KeyboardLeds leds) = 0;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is our practice to disable CopyAssign for interfaces

Copy link
Contributor

@AlanGriffiths AlanGriffiths left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems unfinished

Comment on lines 35 to 40
class LedObserverRegistrar : public ObserverRegistrar<LedObserver>
{
public:
virtual ~LedObserverRegistrar() = default;
};
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As previously discussed I think we should be registering with a device id, which isn't supported by ObserverRegistrar<>

Comment on lines 70 to 71

virtual void set_leds(KeyboardLeds leds) = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think this is unnecessary here (as is the ABI break)

Comment on lines 64 to 67
void register_interest(std::weak_ptr<LedObserver> const& observer) override;
void register_interest(
std::weak_ptr<LedObserver> const& observer,
Executor& executor) override;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see this implemented or used?

@mattkae
Copy link
Contributor Author

mattkae commented Jul 1, 2024

This seems unfinished

I have updated it 👍

Copy link
Contributor

@AlanGriffiths AlanGriffiths left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we could simplify further and reduce change

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this file need to move?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this file need to move?

Comment on lines 100 to 102
std::shared_ptr<InputReport> const& report);
std::shared_ptr<InputReport> const& report,
std::shared_ptr<LedObserverRegistrar> const& led_observer_registrar);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an ABI break - I still don't think that is needed

Comment on lines 728 to 734
void mie::LibInputDevice::associate_to_id(MirInputDeviceId id)
{
try_stop_observing_leds();
led_observer = std::make_shared<LibInputDeviceLedObserver>(this);
led_observer_registrar->register_interest(led_observer, id);
device_id = id;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code looks like initialization, but is not in a constructor. Is there a good reason it is here? (And not, say, in mi::DefaultDevice?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason it is here is to not break the input ABI, but perhaps I'm not seeing something ;)

Comment on lines 437 to 440
auto weak_device = input_device_registry->add_device(devices.back());

if (auto device = weak_device.lock())
new_device->associate_to_id(device->id());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh!

So we're making mi::Device visible and passing LedObserverRegistrar around so that we can do two-phase initialization here?

Can we simplify things by registering the callback from DefaultInputDeviceHub/DefaultDevice?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would require InputDevice to have set_leds defined on it, which would break the input ABI again 😄 That's how I had it before.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But I guess we broke it anyway my change the create_platform signature 😂

@mattkae
Copy link
Contributor Author

mattkae commented Jul 2, 2024

@AlanGriffiths For your AM tomorrow, here's a summary what I have right now:

  • We have a new interface called LedObserverRegistrar that gets passed to the input Platform
  • Every platform except evdev ignores that argument. The evdev platform uses it to register on Led events in LibinputDevice
  • XkbMapperRegistrar will then notify LibInputDevice when an LED changes

In this way, only the evdev platform needs to concern itself with the LEDs, because it is the only one that cares about it.

@AlanGriffiths
Copy link
Contributor

@mattkae I've had a quick pass at the approach I prefer with #3471 - it is still a bit rough, but you are allowed to look

Copy link
Contributor

@AlanGriffiths AlanGriffiths left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have the hardware to test, but this all looks sensible

@AlanGriffiths
Copy link
Contributor

This branch has conflicts that must be resolved

Looks like a rebase is in order

@mattkae mattkae added this pull request to the merge queue Jul 11, 2024
Merged via the queue into main with commit 873fea3 Jul 11, 2024
33 of 36 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Numlock LED does not change
2 participants