Skip to content

Commit

Permalink
#817: detect win32 keyboard layout changes and forward the new layout…
Browse files Browse the repository at this point in the history
… to the server (once for all windows for now..)

git-svn-id: https://xpra.org/svn/Xpra/trunk@11099 3bb7dfac-3a0b-4e04-842a-767bc560f471
  • Loading branch information
totaam committed Oct 30, 2015
1 parent a8e7997 commit 5d8e8f1
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 11 deletions.
7 changes: 7 additions & 0 deletions src/xpra/client/client_window_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
focuslog = Logger("focus")
mouselog = Logger("mouse")
workspacelog = Logger("workspace")
keylog = Logger("keyboard")
metalog = Logger("metadata")


Expand Down Expand Up @@ -580,6 +581,12 @@ def log(self, message=""):
log.info(message)


def keyboard_layout_changed(self, *args):
#used by win32 hooks to tell us about keyboard layout changes for this window
keylog("keyboard_layout_changed%s", args)
self._client.window_keyboard_layout_changed(self)


def dbus_call(self, *args, **kwargs):
#alias for rpc_call using dbus as rpc_type, see UIXpraClient.dbus_call
if not self._client.server_dbus_proxy:
Expand Down
9 changes: 5 additions & 4 deletions src/xpra/client/gtk_base/gtk_keyboard_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,21 @@ def __init__(self, net_send, keyboard_sync, key_shortcuts):
self._keymap = None
self.update()
if self._keymap:
self._keymap_change_handler_id = self._keymap.connect("keys-changed", self._keys_changed)
self._keymap_change_handler_id = self._keymap.connect("keys-changed", self.keymap_changed)

def _keys_changed(self, *args):
log("keys_changed")
def keymap_changed(self, *args):
log("keymap_changed%s", args)
if self._keymap_change_handler_id:
self._keymap.disconnect(self._keymap_change_handler_id)
self._keymap_change_handler_id = None
self._keymap = gdk.keymap_get_default()
self._keymap_change_handler_id = self._keymap.connect("keys-changed", self._keys_changed)
if self._keymap_changing:
#timer due already
return
self._keymap_changing = True
def do_keys_changed():
#re-register the change handler:
self._keymap_change_handler_id = self._keymap.connect("keys-changed", self.keymap_changed)
self._keymap_changing = False
if self.locked:
#automatic changes not allowed!
Expand Down
3 changes: 3 additions & 0 deletions src/xpra/client/keyboard_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ def nosend(*args):
pass
self.send = nosend

def keymap_changed(self, *args):
pass


def parse_shortcuts(self, strs):
#TODO: maybe parse with re instead?
Expand Down
6 changes: 6 additions & 0 deletions src/xpra/client/ui_client_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -1011,6 +1011,12 @@ def send_button(state):
send_button(pressed)


def window_keyboard_layout_changed(self, window):
#win32 can change the keyboard mapping per window...
keylog("window_keyboard_layout_changed(%s)", window)
if self.keyboard_helper:
self.keyboard_helper.keymap_changed()

def get_keymap_properties(self):
props = self.keyboard_helper.get_keymap_properties()
props["modifiers"] = self.get_current_modifiers()
Expand Down
23 changes: 18 additions & 5 deletions src/xpra/platform/win32/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
DEFAULT_MAX_SIZE_HINT = sys.version_info[0]<3
MAX_SIZE_HINT = WINDOW_HOOKS and os.environ.get("XPRA_WIN32_MAX_SIZE_HINT", str(int(DEFAULT_MAX_SIZE_HINT)))=="1"
GEOMETRY = WINDOW_HOOKS and os.environ.get("XPRA_WIN32_GEOMETRY", "1")=="1"
LANGCHANGE = WINDOW_HOOKS and os.environ.get("XPRA_WIN32_LANGCHANGE", "1")=="1"

DPI_AWARE = os.environ.get("XPRA_DPI_AWARE", "1")=="1"
DPI_AWARENESS = int(os.environ.get("XPRA_DPI_AWARENESS", "1"))
Expand Down Expand Up @@ -307,7 +308,7 @@ def add_window_hooks(window):
#call it at least once:
window.fixup_window_style()

if MAX_SIZE_HINT:
if MAX_SIZE_HINT or LANGCHANGE:
#glue code for gtk to win32 APIs:
#add event hook class:
win32hooks = Win32Hooks(handle)
Expand All @@ -324,6 +325,13 @@ def add_window_hooks(window):
if window.geometry_hints:
apply_maxsize_hints(window, window.geometry_hints)

if LANGCHANGE:
def inputlangchange(hwnd, event, wParam, lParam):
log("WM_INPUTLANGCHANGE: character set: %i, input locale identifier: %i", wParam, lParam)
window.keyboard_layout_changed("WM_INPUTLANGCHANGE", wParam, lParam)
win32hooks.add_window_event_handler(win32con.WM_INPUTLANGCHANGE, inputlangchange)


def remove_window_hooks(window):
try:
win32hooks = getattr(window, "win32hooks", None)
Expand Down Expand Up @@ -601,10 +609,11 @@ def __init__(self, client, opts):
import win32con #@Reimport @UnresolvedImport
el = get_win32_event_listener(True)
if el:
el.add_event_callback(win32con.WM_ACTIVATEAPP, self.activateapp)
el.add_event_callback(win32con.WM_POWERBROADCAST, self.power_broadcast_event)
el.add_event_callback(win32con.WM_MOVE, self.wm_move)
el.add_event_callback(WM_WTSSESSION_CHANGE, self.session_change_event)
el.add_event_callback(win32con.WM_ACTIVATEAPP, self.activateapp)
el.add_event_callback(win32con.WM_POWERBROADCAST, self.power_broadcast_event)
el.add_event_callback(win32con.WM_MOVE, self.wm_move)
el.add_event_callback(WM_WTSSESSION_CHANGE, self.session_change_event)
el.add_event_callback(win32con.WM_INPUTLANGCHANGE, self.inputlangchange)
except Exception as e:
log.error("cannot register focus and power callbacks: %s", e)

Expand Down Expand Up @@ -636,6 +645,10 @@ def session_change_event(self, event, session):
c.freeze()


def inputlangchange(self, wParam, lParam):
log("WM_INPUTLANGCHANGE: %i, %i", wParam, lParam)


def activateapp(self, wParam, lParam):
c = self.client
log("WM_ACTIVATEAPP: %s/%s client=%s", wParam, lParam, c)
Expand Down
1 change: 1 addition & 0 deletions src/xpra/platform/win32/win32_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
LOG_EVENTS = {
win32con.WM_POWERBROADCAST : "WM_POWERBROADCAST: power management event",
win32con.WM_TIMECHANGE : "WM_TIMECHANGE: time change event",
win32con.WM_INPUTLANGCHANGE : "WM_INPUTLANGCHANGE: input language changed",
WM_DWMCOMPOSITIONCHANGED : "WM_DWMCOMPOSITIONCHANGED: Desktop Window Manager composition has been enabled or disabled",
}
KNOWN_WM_EVENTS = IGNORE_EVENTS.copy()
Expand Down
7 changes: 5 additions & 2 deletions src/xpra/platform/win32/window_hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ class Win32Hooks(object):
def __init__(self, hwnd):
self._hwnd = hwnd
self._message_map = {}
if HOOK_MINMAXINFO:
self._message_map[win32con.WM_GETMINMAXINFO] = self.on_getminmaxinfo
self.max_size = None
if HOOK_MINMAXINFO:
self.add_window_event_handler(win32con.WM_GETMINMAXINFO, self.on_getminmaxinfo)
try:
#we only use this code for resizable windows, so use SM_C?SIZEFRAME:
self.frame_width = win32api.GetSystemMetrics(win32con.SM_CXSIZEFRAME)
Expand All @@ -64,6 +64,9 @@ def __init__(self, hwnd):
log("Win32Hooks: message_map=%s", self._message_map)
self._oldwndproc = None

def add_window_event_handler(self, event, handler):
self._message_map[event] = handler

def setup(self):
assert self._oldwndproc is None
self._newwndproc = WndProcType(self._wndproc)
Expand Down

0 comments on commit 5d8e8f1

Please sign in to comment.