Coverage for /home/antoine/projects/xpra-git/dist/python3/lib64/python/xpra/server/source/input_mixin.py : 63%
Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# -*- coding: utf-8 -*-
2# This file is part of Xpra.
3# Copyright (C) 2010-2020 Antoine Martin <antoine@xpra.org>
4# Copyright (C) 2008 Nathaniel Smith <njs@pobox.com>
5# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
6# later version. See the file COPYING for details.
8from xpra.server.source.stub_source_mixin import StubSourceMixin
9from xpra.keyboard.mask import DEFAULT_MODIFIER_MEANINGS
10from xpra.util import typedict
11from xpra.log import Logger
13log = Logger("keyboard")
16"""
17Manage input devices (keyboard, mouse, etc)
18"""
19class InputMixin(StubSourceMixin):
21 @classmethod
22 def is_needed(cls, caps : typedict) -> bool:
23 #the 'keyboard' and 'mouse' capability were only added in v4,
24 #so we have to enable the mixin by default:
25 return caps.boolget("keyboard", True) or caps.boolget("mouse", True)
27 def init_state(self):
28 self.pointer_relative = False
29 self.keyboard_config = None
30 self.double_click_time = -1
31 self.double_click_distance = -1, -1
32 # mouse echo:
33 self.mouse_show = False
34 self.mouse_last_position = None
35 self.mouse_last_relative_position = None
37 def cleanup(self):
38 self.keyboard_config = None
40 def parse_client_caps(self, c : typedict):
41 self.pointer_relative = c.boolget("pointer.relative")
42 self.double_click_time = c.intget("double_click.time")
43 self.double_click_distance = c.intpair("double_click.distance")
44 self.mouse_show = c.boolget("mouse.show")
45 self.mouse_last_position = c.intpair("mouse.initial-position")
48 def get_info(self) -> dict:
49 dc_info = {}
50 dct = self.double_click_time
51 if dct:
52 dc_info["time"] = dct
53 dcd = self.double_click_distance
54 if dcd:
55 dc_info["distance"] = dcd
56 info = {}
57 if dc_info:
58 info["double-click"] = dc_info
59 kc = self.keyboard_config
60 if kc:
61 info["keyboard"] = kc.get_info()
62 return info
64 def get_caps(self) -> dict:
65 #expose the "modifier_client_keycodes" defined in the X11 server keyboard config object,
66 #so clients can figure out which modifiers map to which keys:
67 kc = self.keyboard_config
68 if kc:
69 mck = getattr(kc, "modifier_client_keycodes", None)
70 if mck:
71 return {"modifier_keycodes" : mck}
72 return {}
75 def set_layout(self, layout, variant, options):
76 return self.keyboard_config.set_layout(layout, variant, options)
78 def keys_changed(self):
79 kc = self.keyboard_config
80 if kc:
81 kc.compute_modifier_map()
82 kc.compute_modifier_keynames()
83 log("keys_changed() updated keyboard config=%s", self.keyboard_config)
85 def make_keymask_match(self, modifier_list, ignored_modifier_keycode=None, ignored_modifier_keynames=None):
86 kc = self.keyboard_config
87 if kc and kc.enabled:
88 kc.make_keymask_match(modifier_list, ignored_modifier_keycode, ignored_modifier_keynames)
90 def set_default_keymap(self):
91 log("set_default_keymap() keyboard_config=%s", self.keyboard_config)
92 kc = self.keyboard_config
93 if kc:
94 kc.set_default_keymap()
95 return kc
98 def is_modifier(self, keyname, keycode) -> bool:
99 if keyname in DEFAULT_MODIFIER_MEANINGS.keys():
100 return True
101 #keyboard config should always exist if we are here?
102 kc = self.keyboard_config
103 if kc:
104 return kc.is_modifier(keycode)
105 return False
108 def set_keymap(self, current_keyboard_config, keys_pressed, force=False, translate_only=False):
109 kc = self.keyboard_config
110 log("set_keymap%s keyboard_config=%s", (current_keyboard_config, keys_pressed, force, translate_only), kc)
111 if kc and kc.enabled:
112 current_id = None
113 if current_keyboard_config and current_keyboard_config.enabled:
114 current_id = current_keyboard_config.get_hash()
115 keymap_id = kc.get_hash()
116 log("current keyboard id=%s, new keyboard id=%s", current_id, keymap_id)
117 if force or current_id is None or keymap_id!=current_id:
118 kc.keys_pressed = keys_pressed
119 kc.set_keymap(translate_only)
120 kc.owner = self.uuid
121 else:
122 log.info("keyboard mapping already configured (skipped)")
123 self.keyboard_config = current_keyboard_config
126 def get_keycode(self, client_keycode, keyname, pressed, modifiers, keyval, keystr, group) -> int:
127 kc = self.keyboard_config
128 if kc is None:
129 log.info("ignoring client key %s / %s since keyboard is not configured", client_keycode, keyname)
130 return -1
131 return kc.get_keycode(client_keycode, keyname, pressed, modifiers, keyval, keystr, group)
134 def update_mouse(self, wid, x, y, rx, ry):
135 log("update_mouse(%s, %i, %i, %i, %i) current=%s, client=%i, show=%s",
136 wid, x, y, rx, ry, self.mouse_last_position, self.counter, self.mouse_show)
137 if not self.mouse_show:
138 return
139 if self.mouse_last_position!=(x, y, rx, ry):
140 self.mouse_last_position = (x, y, rx, ry)
141 self.send_async("pointer-position", wid, x, y, rx, ry)