Need help writing an InputFilter to fix ALT-TAB (Twitcher) behaviour for GTK apps

It’s been years since I’ve been bothered by the fact that Firefox (or, at that time, GNOME Web, or any GTK app for that matter) won’t let you use Twitcher because it will capture the keys before Haiku could do anything, rendering Twitcher almost useless for me since almost always have a browser window open. Yesterday I did a search on the forums that pointed that this is apparently a bug on Haiku (Making sure you're not a bot!), that should handle this on the input_server

I wrote (or basically stole) a very simple input_server filter and to my surprise, it worked! Now I can change apps with ALT-TAB while on Firefox. The only downside is that Twitcher window doesn’t open: just the quick change feature works, and I can’t figure out why. I’m basically doing the same that BWindow::DispatchMessage does, but I’m obviously messing up somewhere. I checked that the code that “decides” between doing a quick change or opening a Twitcher windows is on Deskbar’s side, so this shouldn’t be the problem.

EDIT: for those of you who don’t know, if you release the TAB key quick enough, Twitcher will change apps without showing its window. If you leave the key pressed a little bit longer, it will show the window with all the open apps.

I’m sure it’s something easy and you can point me to the correct solution. Thanks!

1 Like
/*
 * Copyright 2009-2015 Haiku, Inc. All rights reserved
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *		Axel Dörfler, axeld@pinc-software.de
 *		John Scipione, jscipione@gmail.com
 */


#include "TwitcherInputFilter.h"

#include <string.h>

#include <new>

#include <InterfaceDefs.h>
#include <Message.h>
#include <Messenger.h>
#include <Roster.h>

#include <tracker_private.h>


#define _TWITCHER_	'_TWT'


extern "C" BInputServerFilter* instantiate_input_filter() {
	return new(std::nothrow) TwitcherInputFilter();
}


TwitcherInputFilter::TwitcherInputFilter()
{
}


filter_result
TwitcherInputFilter::Filter(BMessage* message, BList* _list)
{
	switch (message->what) {
		case B_KEY_DOWN:
		case B_UNMAPPED_KEY_DOWN:
		{
			const char* bytes;
			if (message->FindString("bytes", &bytes) != B_OK)
				break;
			
			uint32 rawKey;
			if (message->FindInt32("key", (int32*)&rawKey) != B_OK)
				rawKey = 0;
			
			int32 modifiers;
			if (message->FindInt32("modifiers", &modifiers) != B_OK)
				break;

			int32 modifiersHeld = modifiers & (B_COMMAND_KEY
				| B_CONTROL_KEY | B_OPTION_KEY | B_MENU_KEY | B_SHIFT_KEY);

			if ((modifiersHeld & B_CONTROL_KEY) != 0 && (bytes[0] == B_TAB || rawKey == 0x11)) {
				if (message->HasInt32("be:key_repeat"))
					return B_SKIP_MESSAGE;
				BMessenger deskbar(kDeskbarSignature);
				if (!deskbar.IsValid()) {
					// TODO: have some kind of fallback-handling in case the Deskbar is
					// not available?
					break;
				}
				
				app_info appInfo;
				be_roster->GetActiveAppInfo(&appInfo);
				team_id team = appInfo.team;

				BMessage message('TASK');
				message.AddInt32("key", bytes[0]);
				message.AddInt32("modifiers", modifiersHeld);
				message.AddInt64("when", system_time());
				message.AddInt32("team", team);
				deskbar.SendMessage(&message);
				
				return B_SKIP_MESSAGE;
			}
		}
	}

	return B_DISPATCH_MESSAGE;
}


status_t
TwitcherInputFilter::InitCheck()
{
	return B_OK;
}

This is a bug in the gtk port, Not Haiku. If you ignore keypressed in normal BAplication clients the same thing will happen. (and this makes sense if you consider for example implementing anything capturing keypresses to deal with then itself… like fullscreen webgl games might want to…)

1 Like

Well it’s been broken for years. And while you might be correct X512 seems to think different, and both of your opinions are very respectable to me. Obviously everyone’s use case is different but I find it strange that it doesn’t seem to bother anyone too much to fix it, specially now that Firefox is the main browser option for a lot of people.

I don’t really have the technical expertise to determine whose fault it is. If GTK really needs to be fixed, I’ll be happy to try and help, even considering that I can’t determine if it needs to be fixed haha. In the meantime, I was hoping this simple filter will be enough for my use case.

1 Like

Haikuports and Haiku are different projects, and quite frankly I already have my hands full with webkit development…

The main problem here is that gtk or wayland or whatever other layer is berween it does not handle specific messages from the system correctly. It could, since there are always the default implementations in BApplication you can call after having dealt with messages. But in reality for an applications as complex as a webrowser you really want to deal with this stuff yourself.

Yes, you can write an input filter, sure. This will break down in return every time you need the combination for something else, for example Haiku in a remote app_server or a vm or something. Or a webrowser app that uses ctrl-tab (to not interfere with alt-tab every OS uses…) :slight_smile:

I understand, it wasn’t a complain, actually the opposite. Since devs usually fix what’s bothering them before other stuff, I was surprised no one relied that much on ALT-TAB.

I understand what you say and it makes sense. For my use case the filter will be fine. Ideally this middle layer (GTK or Wayland) should dispatch the key presses it doesn’t need. A few years ago, on the bug report I posted X512 proposed a workaround in Wayland, but either it didn’t get merged or it’s not working for some reason.

EDIT: that solution seems to have been discarded at some point and now Wayland windows skips calling BWindow::DispatchMessage for all key presses.

Are we going this way, putting Haiku and Haikuports against each other now?

The reason I use and contribute to Haiku and Haikuports is precisely that I don’t have to deal with the Linux problem where every bug report always ends up being some other components’ fault, and thuis someone else’s fault, and no one ever fixes it (I have several 10+ year old bugs on my work machine and some I have no idea who to ask for help).

There is a problem, we can discuss it and find a solution that works for everyone.

In this case I think it makes sense that the system is always in control of the shortcut to switch between apps. There could be a specific API to block it, but it is not something that should happen by accident because someone forgot a call in their MessageReceived function (intentionally or not).

I do not want any application to be allowed to intercept such shortcuts. So I’d say handling it in input_server (hardcoded or as a filter) makes perfect sense here, and preciserly for that reason.

The web browser could then be patched, that seems like the right way to handle this.

(please do not start a debate about wether the shortcut in Haiku should be changed, that is an entirely different discussion).

I think there is a combination of:

  • Some devs not actually using Haiku and doing most things from Linux
  • Some devs not using Firefox (I don’t, I have other problems with it like the AltGr key not working, making it impossible to use a French keyboard pretty much)
  • Some devs not using alt-tab (I use workspaces to quickly switch between things, and inside workspaces I use the mouse to switch windows, so I don’t really need it)
  • Always having a very long list of bugs to get through
  • There are not that many devs in general

The chance of the bug getting fixed by someone else end up being quite slim :slight_smile:

4 Likes

It was a response to the question of why it isn’t fixed yet. I don’t contribute to haikuports at all. Among other things because I am blocked by it. The distinction might not be there for you but it certainly is for me. I don’t contribute to the website etc aswell anymore for the same reason.

In practice this does lead to different people working on such issues.

For this specific shortcut. Maybe. But in general, no. If you reimplement messagereceived at all completely you will have to deal with a lot more than one shortcut not firing. Depending on where you do this you will have a lot of issues in addition to this. Not calling the parent class is usually a bug. (And ideally we could use some code analysis tool to help us there…)

One possible way is to make inout_server forward these to deskbar (and later switcher), but that still has the same problems mentioned above, perhaps a window flag can then turn off that behaviour, but then you are stuck again with possible bugs in message functions…

The web browser could then be patched, that seems like the right way to handle this.

You can’t patch the webrowser against websites, you’d just screw it up for another site instead. Unless we use the webkit per site workarounds, but frankly I don’t think we have the ressources for that. (And similarily, it should not matter because websites already deal with MacOS that has basically the same shortcuts as we do, the ctrl-tab really i the only exception)

Thanks for taking your time to respond. I think there are valid arguments on both sides, but for this case I’m with @pulkomandy on the idea that no random application should be able to screw up core OS functionality, on the same idea that pressing CTRL-ALT-SUPR should always bring up TeamMonitor (or Task Manager in Windows) to be able to recover from a broken app.

In any case, the filter working as-is is a huge step in usability for me from yesterday. Having the Switcher window appear it would be perfect, however. The filter is doing basically the same as BWindow::_Switcher does, but there is obviosly a small mistake somewhere.

Ctrl-alt-del, and teamMonitor are actually implemented directly in input_server (in fact, the window even exists at all times, but is hidden)

2 Likes

That is a problem we should work to solve, not by putting the projects one against the other.

Also, as you mention yourself, the problem is not haikuports vs haiku, but hosted on github vs not hosted on github. And you can still email your patches to haikuports until people get so annoyed at the incoming flow of patches that eventually it’s easier to move off github (in the case of haikuports, I think it went from self hosted to bitbucket to github, so moving to a 4th place is not out of the question).

It used to be that keyboard messages were not handled through the normal message received path. That was also the case in BeOS.

Unfortunately, this was changed in Haiku, and my patch to revert that change was rejected.

Ideally we would not be writing MessageReceived by hand in C++.

However, whatever bugs you have in an app, this should, as much as possible, not interfere with the rest of the system, including system shortcuts. And here we have an easy way to solve at least that part. The bug should still be fixed, but at least it will break only the app where it exists.

I’m not sure what you mean. The system shortcut should be intercepted by the system, and if the web browser or a website tries to use it, it just should not work because the system shortcut takes precedence.

Even if that means fixing all the websites in the world, it sure will take some years, but it’s not impossible. We just need a lot more users complaining to these websites :smiley:

I had a quick look at the code in DeskBar and I think you should re-send the message on key repeat, but you are currently skipping it. But the code looks a bit messy so I’m not sure about that, and I don’t have time to dig deeper into it right now.

For those interested in decrypting the logic, it’s in src/apps/deskbar/Switcher.cpp

I can’t get to it is one major reason I would not patch this. It still eludes me why you think this is putting projects against each other.

I don’t even understand why you brought haikuports in this discussion, since until then, none of the discussed parts have any relation to haikuports. And so I understand even less why you had to mention, I quote:

Just after saying:

These statements are not really helpful, do not answer the initial question from jsteinaker, and saying “This is not a bug in Haiku” when the original posts links to the bug on Haiku bugtracker, it is a bold thing to say. I don’t see how I can interpret it otherwise than trying to shift the blame to other projects, which won’t help solving anything. So, if that’s not it, what was your reason for saying this?

1 Like

You’ve said yourself that you like beeing able to fix any bug in this space without having to be directed elsewhere, so why do you think this is assigning blame? That makes no sense to me. We are lucky in that we can fix stuff in the “right” place and not have layers of workarounds. And yes the bug is filed in the haiku bugtracker, I still disagree with that and I explained why. Is your point that all bugs in software shipped with haikuports belong on the haiku bugtracker? I think it wouldn’t be since Before you’ve held the oposite position, even closing a WonderBrush ticket I opened (which atleast was a software we had in every default install).

In any case I’ve not assigned blame to anything in the first place, I pointed out where I think/thought this should have been fixed, which is in the gtk port.

Even if a future Haiku version might decide to handle specific keypresses earlier that still does not solve the underlying issues in the gtk port. (The function in question of the ticket handles waay more than just shortcuts, so the superclass not beeing called would be a major issue)

In this specific case I agree with what X512 very clearly explained in the bugreport. The fact that an app can intercept system shortcuts at all is a bug, no app should be allowed to do that.

Wether the app did it intentioanlly or because it, itself, has a bug, is irrelevant here. Let’s fix the problem in Haiku side: applications should not be able to intercept system shortcuts, no matter if it’s because of a bug or even intentionally.

I think you did that too early, before we have discussed what the problem is. Maybe it is just a misunderstanding, but to me it looks like searching who is to blame, before understanding what the problem is, or, in this case, what the problems are, since there are two different problems:

  • There is one in Haiku: system shortcuts should not be blockable by an application
  • There is another in Haiku: we currently dispatch key events through the normal BMessageReceived flow, whereas BeOS explicitly did not do that (and documented that it did not do that)
  • There is a third bug in the Wayland compatibility wrapper: it exploits the second Haiku bug to intercept keystrokes from DispatchMessage (something that shouldn’t be possible precisely because it leads to lost key events too easily) and disables the default event dispatching

Now, how do we move forward from this. Either I watch you say “the bug is in Wayland, X512 should fix that” and X512 say “the bug clearly is in Haiku, I reported it 3 years ago and I am patiently waiting for Haiku devs to fix it” and nothing ever changes. Or, we try to find a solution together that works for everyone.

I would say we should fix the first bug in Haiku by moving the system shortcuts outside of BWindow. This seems uncontroversial.

The two other changes are more controversial: for the second one, I have submitted a patch but it was rejected, precisely because x512 wanted to intercept the keystrokes using the normal message dispatching system. I assume he has some reasons to do that in the Wayland code.

The good news is, if we fix the first bug, the issue from this forum topic disappears. So there is no need to fix the other two ppoblems right now.

3 Likes

So, why assume mallice instead and accuse me based on that?

I’ve only seen one problem here, which is incorrect handeling of events in gtk. You seem to want a different solution here than x512 wanted in that ticket. So if you want to change how Haiku works (which you considered the second problem here) That will still not fix GTK on the beta release, neither will intercepting shortcuts before they are send to the applications. The only way I see to fix this, for the current Haiku version, is to fix the gtk behaviour to behave like other applications here.

I’ve already outlined scenarios in which an application should be able to receive all keypresses, despite system shortcuts existing. Mainly for VMs or other remote system tools. So please take that into account if you want to catch shortcuts beforehand.

I fail to see where PulkoMandy accused you of “malice”. His critiques of what you have said are just that: critiques of what you have said (and remarks that he doesn’t understand why you say those things), not of whatever your motivations were or weren’t.

I agree with this. I think applications being able to override such system shortcuts makes sense. It isn’t easy to do (you have to override BWindow::DispatchMessage, not just MessageReceived on some random view), and most applications don’t touch that method at all.

Here’s how Xlibe handles this: xlibe/xlib/Drawables.cpp at master · waddlesplash/xlibe · GitHub

Probably the Wayland layer just needs the equivalent code.

1 Like

If I resend the message on key repeat I end up with applications changing super fast between each other, but the Switcher window never opens. In fact, I was doing that before I noticed that BWindow code checks precisely for key repeats to avoid sending them.

There’s code on Switcher.cpp (I think it’s on MainEntry) that checks if the keys are still pressed. If they aren’t and not enough time hasn’t passed, it does a QuickSwitch or whatever is called. Otherwise it just goes with the regular process. If I had to bet I somehow think that it’s failing to detect that both keys (modifier and TAB) are still down and so it’s doing a QuickSwitch everytime.

Can it still check that if your input server filter has consumed the key event?

Maybe try returning B_DISPATCH_MESSAGE instead of B_SKIP_MESSAGE in your filter, this way the switcher will receive the key events?

Also, probably doesn’t matter, but you are returning early if “bytes” isn’t found in the message. It will not be there in B_UNMAPPED_KEY_DOWN messages, so your attempts to fallback to the raw keycode is not going to work.

Returning B_DISPATCH_MESSAGE does the trick, thank you. And you’re also right about my attempt to fallback to the raw keycode not working (even when, as you correctly guessed, doesn’t matter in this specific case).

Now, the first “TAB” press works as expected. From the second one onwards, the Switcher moves two applications forward (I guess because the filter is sending the message, and then as it gets dispatched BWindow is doing the same). It shouldn’t be difficult to make a check for this in a quick and dirty way, until we can agree on the place all of this should be managed.

Thanks for your help, as always.