Skip to content

Commit

Permalink
Merge pull request #2602 from m32/master
Browse files Browse the repository at this point in the history
python clipboard - wx winport version
  • Loading branch information
elfmz authored Dec 29, 2024
2 parents 7fb26f4 + 993515c commit f7cf7f2
Show file tree
Hide file tree
Showing 4 changed files with 245 additions and 47 deletions.
20 changes: 20 additions & 0 deletions python/configs/plug/plugins/tool-show-clipboard.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import gi

gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk

clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
for mime in (
"text/plain",
"text/plain;charset=utf-8",
"text/html",
"text/uri-list",
"image/png",
'x-special/gnome-copied-files',
'SAVE_TARGETS',
'TIMESTAMP',
'TARGETS',
):
text = clipboard.wait_for_contents(Gdk.Atom.intern(mime, True))
if text:
print(mime, text.get_data())
136 changes: 89 additions & 47 deletions python/configs/plug/plugins/ucharmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from far2l.plugin import PluginBase
from far2l.fardialogbuilder import (
TEXT,
EDIT,
BUTTON,
USERCONTROL,
HLine,
Expand Down Expand Up @@ -38,34 +39,24 @@ def _OpenPlugin(self, OpenFrom):
import debugpy
debugpy.breakpoint()

self.max_col = 32
symbols = ''.join([chr(i) for i in range(256)])+(
'ЂЃ‚ѓ„…†‡€‰Љ‹ЊЌЋЏ'
'ђ‘’“”•–—˜™љ›њќћџ'
' ЎўЈ¤Ґ¦§Ё©Є«¬"®Ї'
'°±Ііґµ¶·ё№є»јЅѕї'
'АБВГДЕЖЗИЙКЛМНОП'
'РСТУФХЦЧШЩЪЫЬЭЮЯ'
'абвгдежзийклмноп'
'рстуфхцчшщъыьэюя'
'░▒▓│┤╡╢╖╕╣║╗╝╜╛┐'
'└┴┬├─┼╞╟╚╔╩╦╠═╬╧'
'╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀'
'∙√■⌠≈≤≥⌡²÷ąćęłńó'
'śżźĄĆĘŁŃÓŚŻŹ'
)
n = len(symbols) % self.max_col
if n:
symbols += ' '*(self.max_col-n)
self.max_row = len(symbols) // self.max_col
self.offset = 0
self.max_col = 64
self.max_row = 20
self.text = ''
self.charbuf = self.ffi.new("CHAR_INFO []", len(symbols))
self.charbuf = self.ffi.new("CHAR_INFO []", self.max_col*self.max_row)
attrNormal = 0x170
attrSelected = 0x1c
for i in range(len(symbols)):
cb = self.charbuf[i]
cb.Attributes = attrNormal
cb.Char.UnicodeChar = ord(symbols[i])

def setVBuf(hDlg):
self.info.SendDlgMessage(hDlg, self.ffic.DM_ENABLEREDRAW, 0, 0)
for i in range(self.max_col*self.max_row):
cb = self.charbuf[i]
cb.Attributes = attrNormal
if self.offset+i <= 0xffff:
cb.Char.UnicodeChar = self.offset+i
else:
cb.Char.UnicodeChar = 0x20
self.info.SendDlgMessage(hDlg, self.ffic.DM_ENABLEREDRAW, 1, 0)

def xy2lin(col, row):
return row * self.max_col + col
Expand All @@ -74,31 +65,68 @@ def setColor(col, row, attr):
self.charbuf[xy2lin(col, row)].Attributes = attr

def updateOffset(offset):
char = symbols[offset]
dlg.SetText(dlg.ID_voffset, f"{offset}")
dlg.SetText(dlg.ID_vchar, f'{char}/{ord(char):4x}')
dlg.SetText(dlg.ID_voffset, f"{offset:5d}/0x{offset:04x}")

@self.ffi.callback("FARWINDOWPROC")
def DialogProc(hDlg, Msg, Param1, Param2):
def _DialogProc(hDlg, Msg, Param1, Param2):
if Msg == self.ffic.DN_INITDIALOG:
setVBuf(hDlg)
self.SetCursorPos(hDlg, dlg.ID_hex, 0, 0)
setColor(0, 0, attrSelected)
updateOffset(0)
self.info.SendDlgMessage(hDlg, self.ffic.DM_SETCURSORSIZE, dlg.ID_hex, 1|(100<<32))
dlg.SetFocus(dlg.ID_hex)
return self.info.DefDlgProc(hDlg, Msg, Param1, Param2)
elif Msg == self.ffic.DN_BTNCLICK:
#log.debug(f"btn DialogProc({Param1}, {Param2})")
col, row = self.GetCursorPos(hDlg, dlg.ID_hex)
offset = xy2lin(col, row)
self.text = symbols[offset]
updateOffset(offset)
#log.debug(f"enter:{offset} row:{row} col:{col}, ch:{self.text} cb={self.charbuf[offset].Attributes:x}")
return self.info.DefDlgProc(hDlg, Msg, Param1, Param2)
if Param1 == dlg.ID_vgoto:
v = dlg.GetText(dlg.ID_vgotovalue).strip()
if not v:
v = '0'
try:
offset = int(v, 16 if v[:2] == '0x' else 10)
self.offset = offset
setVBuf(hDlg)
except:
if len(v) == 1:
self.offset = ord(v)
setVBuf(hDlg)
else:
log.exception('goto')
dlg.SetFocus(dlg.ID_hex)
self.SetCursorPos(hDlg, dlg.ID_hex, 0, 0)
updateOffset(self.offset)
return 1
elif Param1 == dlg.ID_vok:
col, row = self.GetCursorPos(hDlg, dlg.ID_hex)
offset = self.offset + xy2lin(col, row)
if offset <= 0xffff:
try:
self.text = chr(offset)
except:
log.exception(f'OK click {offset}')
return 0
elif Msg == self.ffic.DN_KEY and Param1 == dlg.ID_hex:
col, row = self.GetCursorPos(hDlg, dlg.ID_hex)
setColor(col, row, attrNormal)
#log.debug(f"key DialogProc({Param1}, {Param2:x}), col={col} row={row})")
if Param2 == self.ffic.KEY_LEFT:
if Param2 == self.ffic.KEY_PGUP:
self.offset -= self.max_row * self.max_col
if self.offset < 0:
self.offset = 0
setVBuf(hDlg)
offset = self.offset + xy2lin(col, row)
updateOffset(offset)
elif Param2 == self.ffic.KEY_HOME:
row = 0
col = 0
elif Param2 == self.ffic.KEY_PGDN:
self.offset += self.max_row * self.max_col
if self.offset > 0xffff:
self.offset = 0x10000 - self.max_row * self.max_col
setVBuf(hDlg)
offset = self.offset + xy2lin(col, row)
updateOffset(offset)
elif Param2 == self.ffic.KEY_LEFT:
col -= 1
elif Param2 == self.ffic.KEY_UP:
row -= 1
Expand All @@ -107,9 +135,13 @@ def DialogProc(hDlg, Msg, Param1, Param2):
elif Param2 == self.ffic.KEY_DOWN:
row += 1
elif Param2 == self.ffic.KEY_ENTER:
offset = xy2lin(col, row)
self.text = symbols[offset]
#log.debug(f"enter:{offset} row:{row} col:{col}, ch:{self.text} cb={self.charbuf[offset].Attributes:x}")
#log.debug(f"enter at offset:{self.offset} row:{row} col:{col}")
offset = self.offset + xy2lin(col, row)
if offset <= 0xffff:
try:
self.text = chr(offset)
except:
log.exception(f'enter at {offset}')
return 0
elif Param2 == self.ffic.KEY_ESC:
return 0
Expand All @@ -124,7 +156,7 @@ def DialogProc(hDlg, Msg, Param1, Param2):
elif row == -1:
row = self.max_row - 1
setColor(col, row, attrSelected)
offset = xy2lin(col, row)
offset = self.offset + xy2lin(col, row)
updateOffset(offset)
#log.debug(f"col={col}/{self.max_col} row={row}/{self.max_row}")
self.SetCursorPos(hDlg, dlg.ID_hex, col, row)
Expand All @@ -138,11 +170,19 @@ def DialogProc(hDlg, Msg, Param1, Param2):
setColor(col, row, attrSelected)
self.SetCursorPos(hDlg, dlg.ID_hex, col, row)
#log.debug(f"mou DialogProc(col={col} row={row})")
offset = xy2lin(col, row)
self.text = self.symbols[offset]
offset = self.offset + xy2lin(col, row)
#self.text = self.symbols[offset]
updateOffset(offset)
return self.info.DefDlgProc(hDlg, Msg, Param1, Param2)

@self.ffi.callback("FARWINDOWPROC")
def DialogProc(hDlg, Msg, Param1, Param2):
try:
return _DialogProc(hDlg, Msg, Param1, Param2)
except:
log.exception('dialogproc')
return 1

b = DialogBuilder(
self,
DialogProc,
Expand All @@ -152,9 +192,10 @@ def DialogProc(hDlg, Msg, Param1, Param2):
VSizer(
HSizer(
TEXT(None, "Offset:"),
TEXT("voffset", " "*8),
TEXT(None, "Char:"),
TEXT("vchar", " "*6),
TEXT("voffset", " "*12),
TEXT(None, "&Goto:"),
EDIT("vgotovalue", width=7),
BUTTON("vgoto", "GOTO"),
),
HLine(),
USERCONTROL('hex', self.max_col, self.max_row, param={'VBuf':self.ffi.cast("CHAR_INFO *", self.ffi.addressof(self.charbuf))}),
Expand All @@ -168,6 +209,7 @@ def DialogProc(hDlg, Msg, Param1, Param2):
dlg = b.build(-1, -1)

res = self.info.DialogRun(dlg.hDlg)
if res in (1, dlg.ID_vok):
#log.debug(f'res={res} text=***{self.text}***')
if res in (dlg.ID_hex, dlg.ID_vok):
self.info.FSF.CopyToClipboard(self.s2f(self.text))
self.info.DialogFree(dlg.hDlg)
65 changes: 65 additions & 0 deletions python/configs/plug/plugins/uclipget.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import os
import sys
import logging

import ctypes as ct
import far2lc
from far2l.plugin import PluginBase
from yfar import FarPlugin

log = logging.getLogger(__name__)

class Plugin(FarPlugin):
label = "Python Clip GET"
openFrom = ["PLUGINSMENU", 'FILEPANEL']

def CopyFiles(self, data):
pwd = self.get_panel().directory
data = data.decode('utf8')
log.debug(f'copyfiles: {data}')
prefix = 'file://'
for uri in data.split('\n'):
if uri[:len(prefix)] != prefix:
continue
fqname = uri[len(prefix):]
fname = fqname.split('/')[-1]
dqname = os.path.join(pwd, fname)
log.debug(f'CopyFile: {fqname} -> {dqname}')
with open(dqname, 'wb') as fo:
with open(fqname, 'rb') as fi:
rec = fi.read(4096)
if not rec:
break
fo.write(rec)

def OpenPlugin(self, OpenFrom):
winport = self.ffi.cast("struct WINPORTDECL *", far2lc.WINPORT())
clipurifmt = winport.RegisterClipboardFormat("text/uri-list")
if not clipurifmt:
log.error('uclipset.ClipboardRegisterFormat.1')
return
clipgnofmt = winport.RegisterClipboardFormat("x-special/gnome-copied-files")
if not clipgnofmt:
log.error('uclipset.ClipboardRegisterFormat.2')
return
if not winport.OpenClipboard(self.ffi.NULL):
log.error('uclipset.OpenClipboard')
return
try:
data = winport.GetClipboardData(clipurifmt)
if data is not None:
nb = winport.ClipboardSize(data)
result = self.ffi.buffer(data, nb-1)
self.CopyFiles(bytes(result))
else:
data = winport.GetClipboardData(clipgnofmt)
if data is not None:
nb = winport.ClipboardSize(data)
result = self.ffi.buffer(data, nb-1)
self.CopyFiles(bytes(result))
except:
log.exception('uclipset.GetClipboardData')
finally:
if not winport.CloseClipboard():
log.error('uclipset.CloseClipboard')
return
71 changes: 71 additions & 0 deletions python/configs/plug/plugins/uclipset.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import sys
import logging

import ctypes as ct
import far2lc
from far2l.plugin import PluginBase
from yfar import FarPlugin

log = logging.getLogger(__name__)

CAH_ALLOCATED_MAGIC = 0x0610ba10A110CED0
CAH_FREED_MAGIC = 0x0610ba10F4EED000
class ClipboardAllocHeader(ct.Structure):
_fields_ = [
('size', ct.c_uint32),
('padding', ct.c_uint32),
('magic', ct.c_uint64),
]

class Plugin(FarPlugin):
label = "Python Clip SET"
openFrom = ["PLUGINSMENU", 'FILEPANEL']

def SetClipboard(self, winport, fmt, fqname):
fqname = fqname.encode('utf8')
#log.debug(f'clip.{fmt} set: {fqname} {len(fqname)}')
ptr = winport.ClipboardAlloc(len(fqname))
if ptr is None:
log.debug('clipboard alloc failed')
else:
if 0:
m = int(self.ffi.cast('DWORD64', ptr))
log.debug(f'ptr={ptr} m={m:x}')
m -= ct.sizeof(ClipboardAllocHeader)
log.debug(f'm={m:x}')
mp = ClipboardAllocHeader.from_address(m)
log.debug(f'mp.size={mp.size} mp.padding={mp.padding} mp.magic={mp.magic:x} CAH_ALLOCATED_MAGIC={CAH_ALLOCATED_MAGIC:x}')
self.ffi.memmove(ptr, fqname, len(fqname))
res = winport.SetClipboardData(fmt, ptr)

def OpenPlugin(self, OpenFrom):
winport = self.ffi.cast("struct WINPORTDECL *", far2lc.WINPORT())
clipurifmt = winport.RegisterClipboardFormat("text/uri-list")
if not clipurifmt:
log.error('uclipset.ClipboardRegisterFormat.1')
return
clipgnofmt = winport.RegisterClipboardFormat("x-special/gnome-copied-files")
if not clipgnofmt:
log.error('uclipset.ClipboardRegisterFormat.2')
return
if not winport.OpenClipboard(self.ffi.NULL):
log.error('uclipset.OpenClipboard')
return
try:
files = []
panel = self.get_panel()
for f in panel.selected:
fqname = f.full_file_name
files.append("file://"+fqname)
#self.SetClipboard(winport, 1, fqname)
self.SetClipboard(winport, clipurifmt, "\n".join(files))
self.SetClipboard(winport, clipgnofmt, "copy\n"+"\n".join(files))
except:
log.exception('uclipset.SetClipboard')
finally:
if not winport.CloseClipboard():
log.error('uclipset.CloseClipboard')
return
# typedef BOOL (*WINPORT_IsClipboardFormatAvailable) (UINT format);
# typedef PVOID (*WINPORT_GetClipboardData) (UINT format);
# typedef SIZE_T (*WINPORT_ClipboardSize) (PVOID mem);

0 comments on commit f7cf7f2

Please sign in to comment.