-
-
Notifications
You must be signed in to change notification settings - Fork 74
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added dynamic X keyboard event monitoring to qvm_start_daemon.py
Update keyboard_layout property whenever guivm's layout changes, instead of only at the start. requires QubesOS/qubes-core-admin#350 references QubesOS/qubes-issues#1396 references QubesOS/qubes-issues#4294
- Loading branch information
Showing
3 changed files
with
236 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
# -*- encoding: utf8 -*- | ||
# | ||
# The Qubes OS Project, http://www.qubes-os.org | ||
# | ||
# Copyright (C) 2020 Marek Marczykowski-Górecki | ||
# <[email protected]> | ||
# | ||
# This program is free software; you can redistribute it and/or modify | ||
# it under the terms of the GNU Lesser General Public License as published by | ||
# the Free Software Foundation; either version 2.1 of the License, or | ||
# (at your option) any later version. | ||
# | ||
# This program is distributed in the hope that it will be useful, | ||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
# GNU Lesser General Public License for more details. | ||
# | ||
# You should have received a copy of the GNU Lesser General Public License along | ||
# with this program; if not, see <http://www.gnu.org/licenses/>. | ||
""" | ||
This is a set of helper classes, designed to facilitate importing an X extension | ||
that's not supported by default by xcffib. | ||
""" | ||
import io | ||
import struct | ||
import xcffib | ||
|
||
|
||
|
||
class XkbUseExtensionReply(xcffib.Reply): | ||
"""Helper class to parse XkbUseExtensionReply | ||
Contains hardcoded values based on X11/XKBproto.h""" | ||
# pylint: disable=too-few-public-methods | ||
def __init__(self, unpacker): | ||
if isinstance(unpacker, xcffib.Protobj): | ||
unpacker = xcffib.MemoryUnpacker(unpacker.pack()) | ||
xcffib.Reply.__init__(self, unpacker) | ||
base = unpacker.offset | ||
self.major_version, self.minor_version = unpacker.unpack( | ||
"xx2x4xHH4x4x4x4x") | ||
self.bufsize = unpacker.offset - base | ||
|
||
|
||
class XkbUseExtensionCookie(xcffib.Cookie): | ||
"""Helper class for use in loading Xkb extension""" | ||
reply_type = XkbUseExtensionReply | ||
|
||
|
||
class XkbGetStateReply(xcffib.Reply): | ||
"""Helper class to parse XkbGetState; copy&paste from X11/XKBproto.h""" | ||
# pylint: disable=too-few-public-methods | ||
_typedef = """ | ||
BYTE type; | ||
BYTE deviceID; | ||
CARD16 sequenceNumber B16; | ||
CARD32 length B32; | ||
CARD8 mods; | ||
CARD8 baseMods; | ||
CARD8 latchedMods; | ||
CARD8 lockedMods; | ||
CARD8 group; | ||
CARD8 lockedGroup; | ||
INT16 baseGroup B16; | ||
INT16 latchedGroup B16; | ||
CARD8 compatState; | ||
CARD8 grabMods; | ||
CARD8 compatGrabMods; | ||
CARD8 lookupMods; | ||
CARD8 compatLookupMods; | ||
CARD8 pad1; | ||
CARD16 ptrBtnState B16; | ||
CARD16 pad2 B16; | ||
CARD32 pad3 B32;""" | ||
_type_mapping = { | ||
"BYTE": "B", | ||
"CARD16": "H", | ||
"CARD8": "B", | ||
"CARD32": "I", | ||
"INT16": "h", | ||
} | ||
|
||
def __init__(self, unpacker): | ||
if isinstance(unpacker, xcffib.Protobj): | ||
unpacker = xcffib.MemoryUnpacker(unpacker.pack()) | ||
xcffib.Reply.__init__(self, unpacker) | ||
base = unpacker.offset | ||
|
||
# dynamic parse of copy&pasted struct content, for easy re-usability | ||
for line in self._typedef.splitlines(): | ||
line = line.strip() | ||
line = line.rstrip(';') | ||
if not line: | ||
continue | ||
typename, name = line.split()[:2] # ignore optional third part | ||
setattr(self, name, unpacker.unpack(self._type_mapping[typename])) | ||
|
||
self.bufsize = unpacker.offset - base | ||
|
||
|
||
class XkbGetStateCookie(xcffib.Cookie): | ||
"""Helper class for use in parsing Xkb GetState""" | ||
reply_type = XkbGetStateReply | ||
|
||
|
||
class XkbExtension(xcffib.Extension): | ||
"""Helper class to load and use Xkb xcffib extension; needed | ||
because there is not XKB support in xcffib.""" | ||
# pylint: disable=invalid-name,missing-function-docstring | ||
def UseExtension(self, is_checked=True): | ||
buf = io.BytesIO() | ||
buf.write(struct.pack("=xx2xHH", 1, 0)) | ||
return self.send_request(0, buf, XkbGetStateCookie, | ||
is_checked=is_checked) | ||
|
||
def GetState(self, deviceSpec=0x100, is_checked=True): | ||
buf = io.BytesIO() | ||
buf.write(struct.pack("=xx2xHxx", deviceSpec)) | ||
return self.send_request(4, buf, XkbGetStateCookie, | ||
is_checked=is_checked) | ||
|
||
|
||
key = xcffib.ExtensionKey("XKEYBOARD") | ||
# this is a lie: there are events and errors types | ||
_events = {} | ||
_errors = {} | ||
|
||
# pylint: disable=protected-access | ||
xcffib._add_ext(key, XkbExtension, _events, _errors) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters