Reputation: 11
This is my first Kivy app, surprisingly there wasn't the usual amount of documentation on copy/paste button text with the clipboard which I assume because it is simple, however I get a traceback saying ValueError embedded null character.
I thought that it was because the button produces text of recently hashed text and it still was contained in a byte string, but when decoding it acts if its already decoded and states string doesn't have a decode attribute. I apologize in advance for any "playing" in my code and if the answer has been staring at me
kivy clipboard doc: https://kivy.org/docs/api-kivy.core.clipboard.html#
** Update I believe I found the issue, regardless of the data type that is passed to the clipboard function there is a Value error, I took a look at the kivy file for the clipboard "clipboard_winctypes.py" and under the put() function the function msvcrt.wcscpy_s() is called. When this is commented out the clipboard will copy the button text however, I receive weird things like ⫐ᵄƅ
also under the put() function where text is set to text += u'x00', if this is commented out and msvcrt.wscpy_s() is left uncommented to be called it executes without error but nothing is copied to the clipboard however msvcrt is an object of ctypes.cdll.msvcrt and I don't where to go from here
clipboard_winctypes.py:
'''
Clipboard windows: an implementation of the Clipboard using ctypes.
'''
__all__ = ('ClipboardWindows', )
from kivy.utils import platform
from kivy.core.clipboard import ClipboardBase
if platform != 'win':
raise SystemError('unsupported platform for Windows clipboard')
import ctypes
from ctypes import wintypes
user32 = ctypes.windll.user32
kernel32 = ctypes.windll.kernel32
msvcrt = ctypes.cdll.msvcrt
c_char_p = ctypes.c_char_p
c_wchar_p = ctypes.c_wchar_p
class ClipboardWindows(ClipboardBase):
def get(self, mimetype='text/plain'):
GetClipboardData = user32.GetClipboardData
GetClipboardData.argtypes = [wintypes.UINT]
GetClipboardData.restype = wintypes.HANDLE
user32.OpenClipboard(user32.GetActiveWindow())
# 1 is CF_TEXT
pcontents = GetClipboardData(13)
if not pcontents:
return ''
data = c_wchar_p(pcontents).value.encode(self._encoding)
user32.CloseClipboard()
return data
def put(self, text, mimetype='text/plain'):
text = text.decode(self._encoding) # auto converted later
text += u'\x00'
SetClipboardData = user32.SetClipboardData
SetClipboardData.argtypes = [wintypes.UINT, wintypes.HANDLE]
SetClipboardData.restype = wintypes.HANDLE
GlobalAlloc = kernel32.GlobalAlloc
GlobalAlloc.argtypes = [wintypes.UINT, ctypes.c_size_t]
GlobalAlloc.restype = wintypes.HGLOBAL
CF_UNICODETEXT = 13
user32.OpenClipboard(user32.GetActiveWindow())
user32.EmptyClipboard()
hCd = GlobalAlloc(0, len(text) * ctypes.sizeof(ctypes.c_wchar))
msvcrt.wcscpy_s(c_wchar_p(hCd), len(text), c_wchar_p(text))
SetClipboardData(CF_UNICODETEXT, hCd)
user32.CloseClipboard()
def get_types(self):
return ['text/plain']
cry_hash.py
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.togglebutton import ToggleButton
from kivy.uix.label import Label
import hashlib
class Hasher:
def __init__(self, to_hash, hash_alg, hash_length):
if to_hash != type(bytes):
self.to_hash = bytes(to_hash, encoding='utf-8')
else:
self.to_hash = to_hash
self.hash_alg = hash_alg
self.hash_length = int(hash_length)
def create_hash(self):
hash_object = hashlib.new(self.hash_alg)
hash_object.update(self.to_hash)
result = hash_object.hexdigest()[:self.hash_length]
del hash_object
return result
class LabelBackground(Label):
pass
class CryHashWidgetBoxLayout(BoxLayout):
def get_hash(self, user_hash, hash_length):
tb = next((t for t in ToggleButton.get_widgets('hash_type') if t.state == 'down'), None)
hash_alg = tb.text if tb else None
krypt_tool = Hasher(user_hash, hash_alg, hash_length)
hashed_input = krypt_tool.create_hash()
self.ids.hash_return.text = hashed_input
def reset(self, text_reset):
incoming = text_reset
del incoming
incoming = ''
self.ids.hash_return.text = incoming
class CryHashApp(App):
def build(self):
return CryHashWidgetBoxLayout()
if __name__ == '__main__':
CryHashApp().run()
KV file: cryhash.kv
#File name: cry_hash.py
#:import utils kivy.utils
#:import Clipboard kivy.core.clipboard.Clipboard
<ToggleButton>:
background_color: utils.get_color_from_hex('#E00000')
<TextInput>:
background_color: utils.get_color_from_hex('#5F9B9F')
<Label>
font_name: 'fonts/arialbd.ttf'
<CryHashWidgetBoxLayout>:
orientation: 'vertical'
Label:
font_name: 'fonts/welga.ttf'
color: utils.get_color_from_hex('#E00000')
text: 'Welcome to Cry Hash!'
font_size: 80
Button:
id: hash_return
background_color: utils.get_color_from_hex('#F15E92')
font_size: 40
text: ''
on_release:
Clipboard.copy(hash_return.text)
BoxLayout:
orientation: 'horizontal'
BoxLayout:
orientation: 'vertical'
Label:
id: bg_hash
color: utils.get_color_from_hex('#E00000')
text: 'Enter text to hash'
TextInput:
id: user_hash
multiline: False
text: ''
Label:
id: bg_length
color: utils.get_color_from_hex('#E00000')
text: 'Enter length'
TextInput:
id: get_hash_length
multiline: False
text: '10'
Button:
id: get_data
background_color: utils.get_color_from_hex('#1900FF')
text: 'get hash!'
on_release: root.get_hash(user_hash.text, get_hash_length.text)
BoxLayout:
orientation: 'vertical'
ToggleButton:
id: SHA256
text: 'SHA256'
state: 'down'
group: 'hash_type'
ToggleButton:
id: SHA512
text: 'SHA512'
group: 'hash_type'
ToggleButton:
id: SHA1
text: 'SHA1'
group: 'hash_type'
ToggleButton:
id: MD5
text: 'MD5'
group: 'hash_type'
Upvotes: 1
Views: 2052
Reputation: 11
To summarize other answers:
Issue:
"ValueError: embedded null character" when using copy to clipboard (Kivy)
Solution:
pyperclip.copy('text that you want into clipboard')
Upvotes: 1
Reputation: 11
I have found a work around, I believe that is just simply a bug in the Kivy framework, if someone can find a true solution in the kivy code please let me know, otherwise I simply imported pyperclip, created a pyperclip copy function in the .py file and called to the function in the .kv file. Works flawlessly!
cry_hash.py:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.togglebutton import ToggleButton
from kivy.uix.label import Label
import hashlib
import pyperclip
class Hasher:
def __init__(self, to_hash, hash_alg, hash_length):
if to_hash != type(bytes):
self.to_hash = bytes(to_hash, encoding='utf-8')
else:
self.to_hash = to_hash
self.hash_alg = hash_alg
self.hash_length = int(hash_length)
def create_hash(self):
hash_object = hashlib.new(self.hash_alg)
hash_object.update(self.to_hash)
result = hash_object.hexdigest()[:self.hash_length]
del hash_object
return result
class LabelBackground(Label):
pass
class CryHashWidgetBoxLayout(BoxLayout):
def get_hash(self, user_hash, hash_length):
tb = next((t for t in ToggleButton.get_widgets('hash_type') if t.state == 'down'), None)
hash_alg = tb.text if tb else None
krypt_tool = Hasher(user_hash, hash_alg, hash_length)
hashed_input = krypt_tool.create_hash()
self.ids.hash_return.text = str(hashed_input)
def reset(self, text_reset):
incoming = text_reset
del incoming
incoming = ''
self.ids.hash_return.text = incoming
def copy_text(self, text):
pyperclip.copy(text)
class CryHashApp(App):
def build(self):
return CryHashWidgetBoxLayout()
if __name__ == '__main__':
CryHashApp().run()
cryhash.kv:
#File name: cry_hash.py
#:import utils kivy.utils
#:import Clipboard kivy.core.clipboard.Clipboard
<ToggleButton>:
background_color: utils.get_color_from_hex('#E00000')
<TextInput>:
background_color: utils.get_color_from_hex('#5F9B9F')
<Label>
font_name: 'fonts/arialbd.ttf'
<CryHashWidgetBoxLayout>:
orientation: 'vertical'
Label:
font_name: 'fonts/welga.ttf'
color: utils.get_color_from_hex('#E00000')
text: 'Welcome to Cry Hash!'
font_size: 80
Button:
id: hash_return
background_color: utils.get_color_from_hex('#F15E92')
font_size: 40
text: ''
on_release: root.copy_text(hash_return.text)
BoxLayout:
orientation: 'horizontal'
BoxLayout:
orientation: 'vertical'
Label:
id: bg_hash
color: utils.get_color_from_hex('#E00000')
text: 'Enter text to hash'
TextInput:
id: user_hash
multiline: False
text: ''
Label:
id: bg_length
color: utils.get_color_from_hex('#E00000')
text: 'Enter length'
TextInput:
id: get_hash_length
multiline: False
text: '10'
Button:
id: get_data
background_color: utils.get_color_from_hex('#1900FF')
text: 'get hash!'
on_release: root.get_hash(user_hash.text, get_hash_length.text)
BoxLayout:
orientation: 'vertical'
ToggleButton:
id: SHA256
text: 'SHA256'
state: 'down'
group: 'hash_type'
ToggleButton:
id: SHA512
text: 'SHA512'
group: 'hash_type'
ToggleButton:
id: SHA1
text: 'SHA1'
group: 'hash_type'
ToggleButton:
id: MD5
text: 'MD5'
group: 'hash_type'
Upvotes: 0