-
Notifications
You must be signed in to change notification settings - Fork 15
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
(DRAFT) Wayland+GNOME via DBus support #136
Conversation
Update the string and Unicode processor functions to adapt to the state of the CapsLock LED.
Provide the context object to commands, so that functions like `unicode_keystrokes` can access it. Don't provide context if the target function can't accept it.
One big PR is not what we need... I'd recommend you learn to keep the separate features you're working on in different branches and have a PR for each. This PR should focus on just the swappable DBus support... not any of the other input timing fixes (or other things). |
Are these per-user environmental variables accessible if keyszer is running as an isolated user? Are you impinging someone would manually create these environment vars when running keyszer that way? I would have guessed those variables are set by the WM at runtime and wouldn't be accessible when keyszer starts as a system service. |
That is an annoyingly good question. Since I'm always working in the There is such a thing as user-level service files, that get run from the user's home. I know that I got one running in the past, while I was messing with trying to use the since-removed When running
As mentioned in the Wayland thread, I was just about to put in an API function to allow the environment info to be injected from the config, for the exact reason of the environment possibly not being accessible (or something being misidentified due to some customized environment). But I really feel like if the program can get access to the user's display server, to the point where it can read the window attributes of windows your user is interacting with, it seems like the rest of the needed environment information should theoretically be available to it before it even attempts to do that. And there is a backup for the DE detection that checks for things like "gnome-shell" or "sway" in the process list. Although if multiple users are logged in simultaneously, operating independent graphical environments that show up in the process list, that would probably not produce reliable results. But that's really an edge case, I would hope. I'll have to try to do a system service and test without my user being in the |
I've been thinking about this a lot and I'm afraid the direction this is heading has all just become a bit too much. This is WAY more code than I imagined to support Weyland... just reading thru the I also don't think I'm interested in supporting live WM/DE auto-switching directly... so here are my current thoughts: Simply have a config knob/method for context provider class:
That reference must refer to a class that can be instantiated that handles context with a We could perhaps ship a few popular options (IF they don't increase the requirements terribly), or they all might be made available as modules you just install into your config once... If someone wanted to "switch" DE/WM they'd need to write a small script to kill/restart the key mapper in-between - OR write a So to reboot this I think we'd need to:
For the key context perhaps it's no different, just another context provider. add_context_provider("kb", "builtin/key_context")
add_context_provider("wm", "builtin/x11")
# later
ctx.kb.capslock_on
ctx.wm.name Or perhaps key context is simply a given and your other providers inherit from it... keeping the space flat. So most importantly we'd need to flesh out the context provider API/architecture first... then (if you're still interested) you'd port this work (each provider) over to simply being a single, self-container plug-in provider class. After those worked and we had a few people testing them we could circle back to whether to publish as external modules or part of the core app. Of course you'd be free to keep exploring the MultiProvider idea if you wanted, but right now I'm pretty sure I don't want to become the owner of all that complexity. |
Other than the complexity of Although it's kind of sad to me that keyszer would remain a very manual thing and make users replicate what I'm doing just to have some auto-adaptation, I can understand not wanting to take on so much intelligence in what is just supposed to be a utility that remaps keys. 👍🏽 If you're willing to work with me a bit to get to the form of what you're talking about with the classes, I'm fine with pulling I'm about 95% of the way to having a Kinto config that automatically treats all different keyboard types correctly without manual intervention, and adapts to the distro/DE as well as using globals for choices like "Want to use Sublime shortcuts in VSCode?" (and toggling multi-language modmap variations), so they can be flipped anytime the user wants, rather than rewriting so many lines of the config with Once you pull out And without What about the part that automatically works with either of the two GNOME extensions, and adapts if you turn one off and turn another one on, without needing a restart? Seems a real shame to take that part out. It isn't really even checking anything in the environment, just trying what it knows how to try until one extension succeeds, similar to how Let me know your thoughts on each of these points. This was all just an experiment that went better than I had hoped, since it's all working now that the timing delay is in place. |
Would this be vaguely like what you're thinking about? With the module changing to just be Just spitballing to try and get an idea of which direction to go. This is based on the current mainline from .logger import debug
from ..models.key import Key
class KeyContext:
def __init__(self, device):
self._device = device
@property
def device_name(self):
return self._device.name
@property
def capslock_on(self):
return Key.LED_CAPSL in self._device.leds()
@property
def numlock_on(self):
return Key.LED_NUML in self._device.leds()
class WindowContext(KeyContext):
def __init__(self, device):
super().__init__(device)
self._X_ctx = None
def _query_window_context(self):
# cache this, think it might be expensive
if self._X_ctx is None:
self._X_ctx = get_xorg_context()
@property
def wm_class(self):
self._query_window_context()
return self._X_ctx["wm_class"]
@property
def wm_name(self):
self._query_window_context()
return self._X_ctx["wm_name"]
# generic context error, covering both X11 and Wayland
@property
def context_error(self):
self._query_window_context()
return self._X_ctx["context_error"] |
I don't think it's needed (as a concept)... in my world it would just be another ContextProvider... one that wrapped a bunch of others.... and I do think that a slightly more generic ContextProvider is a good abstraction... it allows one to build both simple things (small modules) AND complex things (huge auto-detection systems).
Well, I'd like to see it first, but we can probably include a few simple context providers... I do have some concerns about supporting a bunch of configs no one is actually using though... and it's weird for someone on a simple X11 system to have to install DBus libraries if they aren't using a complex DE... so that's one consideration. But maybe we don't actually have to specify them all as dependencies if they are optional configuration pieces?
I'm not sure I understand exactly what we're talking about here. I'd say lets first trim off all the extraneous stuff and then see what we're left with and have another look. |
I'm not sure - I feel like I need to noodle on the architecture here... in some ways the WM and keyboard context are entirely separate, yet in others it's all just part of the large pool of what one could call "context" surrounding the keypress. I think the simplest thing (fewest changes) to do to get the ball rolling would be to let KeyContext compose WMContext within in... such that when creating a new KeyContext you'd inject your instance of the WMContext... KeyContext.new(keyboard, wm_context_instance) Very similar to what we have now but that wm_class and wm_name would defer to the WM context provider instance that was passed in... rather than a hard coded lib. |
Yeah, might be a good point. Another detail to leave to the parent project trying to use keyszer as a tool.
In that vein, here's an iteration I talked the AI into that makes some sense to me: from .logger import debug
from ..models.key import Key
class KeyContext:
def __init__(self):
super().__init__()
@property
def capslock_on(self, device):
return Key.LED_CAPSL in device.leds()
@property
def numlock_on(self, device):
return Key.LED_NUML in device.leds()
class WindowContext:
def __init__(self):
super().__init__()
self._X_ctx = None
def _query_window_context(self):
# cache this, think it might be expensive
if self._X_ctx is None:
self._X_ctx = get_xorg_context()
@property
def wm_class(self):
self._query_window_context()
return self._X_ctx["wm_class"]
@property
def wm_name(self):
self._query_window_context()
return self._X_ctx["wm_name"]
# generic context error, covering both X11 and Wayland
@property
def context_error(self):
self._query_window_context()
return self._X_ctx["context_error"]
class Context(KeyContext, WindowContext):
def __init__(self, device):
super().__init__()
self.device = device I don't feel like the nomenclature of "wm" entirely does justice to the context for the window, or should I say doesn't abstract it quite enough. Since it depends on session type, window manager (in some cases) or the full-fledged desktop environment (which in the case of GNOME is not just about the Mutter window manager, the extensions have to talk to the GNOME Shell). I like referring to it more generally as "window context". And the providers (the window context "getters") will worry about what exactly that means for each provider's intended environment. |
Yeah, the idea of the code sample above would be that you'd just do I think I'm still missing a step, which is the turning of the Or actually, if that's necessary, rather than the "connector" becoming a class and talking to the appropriate module? |
Trying to think about how the theoretical "custom" provider coming from config might work, but my mind is a big gray fog on that front. On the other hand, setting up an API to tell keyser "use the X11/Xorg window context provider" seems like a pretty straightforward idea. And could be automated from config, at least at startup, if config has |
Merge Adapt to capslock branch into Wayland+GNOME+DBus dev branch
Closing in favor of the cleaner class-based approach in PR #157 |
DRAFT - Work in Progress (but functioning)
Changes
Many changes, including the prep work for allowing new environments besides X11 to be supported with independent modules that link to
KeyContext
via a "connector" module that checks the environment (display/session type and desktop environment/window manager) to decide which window context "getter" module to use.Requires
Needs one of the GNOME shell extensions mentioned below, and the
dbus
module, among other things.Related issue
Should partially resolve issue #27, within the limited context of a Wayland+GNOME environment, with the GNOME shell extension "Window Calls Extended" or "Xremap" installed and enabled to provide the DBus interface to acquire the window attributes.
Window Calls Extended extension:
https://extensions.gnome.org/extension/4974/window-calls-extended/
https://github.com/hseliger/window-calls-extended
Xremap extension:
https://extensions.gnome.org/extension/5060/xremap/
https://github.com/xremap/xremap-gnome
These GNOME extensions don't provide a D-Bus "signal" to attach a window focus handler to. Another extension might be able to fulfill that need at some point.
Checklist