Hide keyboard shortcuts

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. 

7 

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 

12 

13log = Logger("keyboard") 

14 

15 

16""" 

17Manage input devices (keyboard, mouse, etc) 

18""" 

19class InputMixin(StubSourceMixin): 

20 

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) 

26 

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 

36 

37 def cleanup(self): 

38 self.keyboard_config = None 

39 

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") 

46 

47 

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 

63 

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 {} 

73 

74 

75 def set_layout(self, layout, variant, options): 

76 return self.keyboard_config.set_layout(layout, variant, options) 

77 

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) 

84 

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) 

89 

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 

96 

97 

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 

106 

107 

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 

124 

125 

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) 

132 

133 

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)