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

feat: language provider (windows only) #85

Open
wants to merge 15 commits into
base: main
Choose a base branch
from

Conversation

jawee
Copy link

@jawee jawee commented Aug 18, 2024

Provider for getting current OS language and keyboard language.

Only Windows support, developed the same thing for the c# version of glazewm.

Haven't been able to run it, pnpm dev fails with the error below. So it's untested.

 ERR_PNPM_RECURSIVE_RUN_FIRST_FAIL  @zebar/desktop@0.0.0 dev: `npm run -s monitors -- --print0 | xargs -0 -P 99 
-I % sh -c 'npm run tauri dev -- -- -- open bar --args %'`
Exit status 255
 ELIFECYCLE  Command failed with exit code 255.

@lars-berger
Copy link
Collaborator

Ay this is awesome, thank you 🙏

A big improvement that could be made is removing the interval altogether and instead listening to WM_INPUTLANGCHANGE. This way we wouldn't have delays in showing the current language. If you're ok with making the change, create_message_window and run_message_loop can be copied 1:1 from GlazeWM. You'd need to spawn a thread for the window like so and have an event_hook_proc that listens for WM_INPUTLANGCHANGE

Re. pnpm dev failing - are you able to run main without the pr changes?

@jawee
Copy link
Author

jawee commented Aug 19, 2024

Ay this is awesome, thank you 🙏

A big improvement that could be made is removing the interval altogether and instead listening to WM_INPUTLANGCHANGE. This way we wouldn't have delays in showing the current language. If you're ok with making the change, create_message_window and run_message_loop can be copied 1:1 from GlazeWM. You'd need to spawn a thread for the window like so and have an event_hook_proc that listens for WM_INPUTLANGCHANGE

Re. pnpm dev failing - are you able to run main without the pr changes?

I'll give it a try when I find some more time, hopefully this weekend :)

Re pnpm dev, it was a bit of a user error (guess I can't read above headlines :) ), just noticed that git bash or wsl was required, and I was using powershell. Now it kind of works, although no providers seems to work, getting the error below for all of them (I assume all of them at least), can't get any of the default providers in "group/right" to work. This also happens if I try to run it from main.
WARN zebar::providers::provider_manager: Error refreshing provider: channel closed

Want me to move the "problem discussion" to an issue, to not clutter the PR further? :)

fixed cfg(windows) in variables
fixed copy paste typos in create-language-provider
@lars-berger
Copy link
Collaborator

Re pnpm dev, it was a bit of a user error (guess I can't read above headlines :) ), just noticed that git bash or wsl was required, and I was using powershell. Now it kind of works, although no providers seems to work, getting the error below for all of them (I assume all of them at least), can't get any of the default providers in "group/right" to work. This also happens if I try to run it from main. WARN zebar::providers::provider_manager: Error refreshing provider: channel closed

Want me to move the "problem discussion" to an issue, to not clutter the PR further? :)

Ah thanks for catching this - was a regression introduced by a recent refactor. There's a fix in main for it now 👍

@jawee
Copy link
Author

jawee commented Aug 25, 2024

It does seem like the WM_INPUTLANGCHANGE only is being sent to the focused window and then it's being swallowed. If I create a visible window and do a language change, the message is received. But regardless of what I seem to do, I can't get it to be sent to a background window. So not sure how to proceed, other than cleaning up my polling version or wait for someone that might know the windows api intricacies better than me to figure it out.

I tried to listen for the WM_INPUTLANGCHANGE in the glzr code base as well with the same result.

@lars-berger
Copy link
Collaborator

It does seem like the WM_INPUTLANGCHANGE only is being sent to the focused window and then it's being swallowed. If I create a visible window and do a language change, the message is received. But regardless of what I seem to do, I can't get it to be sent to a background window. So not sure how to proceed, other than cleaning up my polling version or wait for someone that might know the windows api intricacies better than me to figure it out.

I tried to listen for the WM_INPUTLANGCHANGE in the glzr code base as well with the same result.

Damn, that sucks. Most WM_** notification messages work totally fine with background windows, so it's unfortunate this particular one only works with visible windows.

From an SO post, there's a more reliable alternative via COM:

The better solution, then, is to implement the ITfLanguageProfileNotifySink interface, whose OnLanguageChanged method is called whenever the input language changes, regardless of the way that it was changed.

However, I see that your question is tagged with both the C and C++ tags. You can use COM from C, but it's a real pain in the neck. Far simpler if you're using C++. If I needed to do this work in a C program, I'd probably just find a way to make WM_INPUTLANGCHANGE work for me. Maybe I'm just lazy.

There's actually one example of using ITfLanguageProfileNotifySink in Rust here. They have some state on the ITfLanguageProfileNotifySink instance but I think it'd work to just remove all that and instead emit/listen to an mspc channel like so:

#[implement(
  Windows::Win32::UI::TextServices::ITfLanguageProfileNotifySink
)]
struct LanguageProfileNotifySink {
  lang_change_tx: mpsc::Sender<u16>,
}

#[allow(non_snake_case)]
impl LanguageProfileNotifySink {
  fn new() -> (Self, mpsc::Receiver<u16>) {
    let (lang_change_tx, lang_change_rx) = mpsc::channel::<u16>(1);

    (Self { lang_change_tx }, lang_change_rx) // listen to the returned `lang_change_rx` in the provider
  }

  fn OnLanguageChange(&self, _langid: u16) -> windows::core::Result<BOOL> {
    Ok(true.into())
  }

  fn OnLanguageChanged(&self) -> ::windows::core::Result<()> {
    self.lang_change_tx.send(0).unwrap();
    Ok(())
  }
}

COM is used extensively within Tauri, so it should be totally fine to use in this case

@jawee
Copy link
Author

jawee commented Sep 1, 2024

I've tried implementing it using the ITfLanguageProfileNotifySink, but haven't been able to get it to work with zebar, I did make a small application where I've gotten it to work, but it seems to have the same issue as the WM_INPUTLANGCHANGE event, it's only sent to the application in focus.

According to this, it seems like that's how it's supposed to be. https://stackoverflow.com/questions/74468291/itflanguageprofilenotifysinkonlanguagechange-only-reporting-when-the-window-is

Doesn't seem like this feature can be done in a nice way unfortunately.

@lars-berger
Copy link
Collaborator

I've tried implementing it using the ITfLanguageProfileNotifySink, but haven't been able to get it to work with zebar, I did make a small application where I've gotten it to work, but it seems to have the same issue as the WM_INPUTLANGCHANGE event, it's only sent to the application in focus.

According to this, it seems like that's how it's supposed to be. https://stackoverflow.com/questions/74468291/itflanguageprofilenotifysinkonlanguagechange-only-reporting-when-the-window-is

Doesn't seem like this feature can be done in a nice way unfortunately.

That's super unfortunate that ITfLanguageProfileNotifySink has the same issue. Thanks for giving it a shot at least 🙏

Just a heads up, I'm working on a v2 rework of Zebar currently. There'll be a bunch of merge conflicts once it's merged (#99) - you cool with me committing to your branch directly to fix these up afterwards? One other thing is I'm keen to rename the provider + variable from language.language -> keyboard.layout - I can make that change while fixing up the conflicts if you're fine with that

@jawee
Copy link
Author

jawee commented Sep 12, 2024

You can modify and change it however you like. :)

I should have fixed the compilation error for arm64-windows (the workflow that failed)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: 📬 Needs triage
Development

Successfully merging this pull request may close these issues.

2 participants