diff --git a/klembord/__init__.py b/klembord/__init__.py index 2c09545..618ea3d 100755 --- a/klembord/__init__.py +++ b/klembord/__init__.py @@ -16,9 +16,11 @@ """ import sys -from collections import OrderedDict, Mapping, ByteString, Sequence +from collections import OrderedDict +from collections.abc import Mapping, Sequence if sys.platform.startswith('win32'): from .winclipboard import WinClipboard + from .winclipboard import parse_description WINDOWS = True LINUX = False else: @@ -199,7 +201,7 @@ def set_with_rich_text(self, text, html): else: raise TypeError('text or html is not str') - def get_with_rich_text(self): + def get_with_rich_text(self, include_win_description=False): """Get the contents of the selection in plaintext and HTML formats. Returns: @@ -209,11 +211,13 @@ def get_with_rich_text(self): """ if WINDOWS: + description = OrderedDict() content = self.get((W_HTML, W_UNICODE)) html = content[W_HTML] if html: # Strip HTML Format additions and return just the fragment. - html = html.decode(UTF8)[131:-38] + description = parse_description(html.decode(UTF8)) + html = html[ description['StartFragment']: description['EndFragment']].decode(UTF8) # Must decode after slicing text = content[W_UNICODE] if text: text = text.decode(UTF16) @@ -235,7 +239,11 @@ def get_with_rich_text(self): html = html.decode(UTF16) except UnicodeDecodeError: html = html.decode(UTF8, 'ignore') - return (text, html) + + if WINDOWS and include_win_description: + return (text, html, description) + else: + return (text, html) def clear(self): """Empty selection. @@ -365,7 +373,7 @@ def set_with_rich_text(text, html): SELECTION.set_with_rich_text(text, html) -def get_with_rich_text(): +def get_with_rich_text(include_win_description=False): """Get the contents of the selection in plaintext and HTML formats. Returns: @@ -377,7 +385,7 @@ def get_with_rich_text(): global SELECTION if SELECTION is None: SELECTION = Selection() - return SELECTION.get_with_rich_text() + return SELECTION.get_with_rich_text(include_win_description) def clear(): diff --git a/klembord/winclipboard.py b/klembord/winclipboard.py index 1648d8b..6c7e42b 100755 --- a/klembord/winclipboard.py +++ b/klembord/winclipboard.py @@ -1,8 +1,10 @@ #!/usr/bin/env python3 -from collections import OrderedDict, ByteString +from collections import OrderedDict +from collections.abc import ByteString from ctypes import windll, create_unicode_buffer, memmove, c_uint, c_wchar from ctypes import c_void_p, c_bool, c_int, c_byte +import re UNSUPPORTED = { @@ -230,3 +232,31 @@ def wrap_html(self, fragment_str): return wrapped + + +start_html_RE = re.compile(r'(StartHTML):(-?\d+)') +start_fragment_RE = re.compile(r'(StartFragment):(\d+)') +end_fragment_RE = re.compile(r'(EndFragment):(\d+)') + +def parse_description(text): + ''' Returns a dictionary of the description info. + Only StartFragment and EndFragment are guaranteed to exist and be integers. + ''' + start_html = start_html_RE.search(text) + start_fragment = start_fragment_RE.search(text) + end_fragment = end_fragment_RE.search(text) + + description = OrderedDict() + + if start_html: + start_index = int(start_html.group(2)) + + if start_index > 0: + description_blob = text[:start_index] + + description = OrderedDict( line.split(':', 1) for line in description_blob.splitlines() ) + + description[ start_fragment.group(1) ] = int(start_fragment.group(2)) + description[ end_fragment.group(1) ] = int(end_fragment.group(2)) + + return description \ No newline at end of file diff --git a/klembord/xclipboard.py b/klembord/xclipboard.py index db7b5d2..1660c2f 100644 --- a/klembord/xclipboard.py +++ b/klembord/xclipboard.py @@ -4,7 +4,7 @@ import sys from threading import Thread from queue import Queue, Empty -from collections import ByteString +from collections.abc import ByteString from traceback import print_exception from Xlib import X, display, Xatom from Xlib.protocol import event