From 3f68f9a9ccfa4e836c7179960e0bd1855e0aed0f Mon Sep 17 00:00:00 2001 From: jstenar <> Date: Tue, 4 Jul 2006 18:45:28 +0000 Subject: [PATCH] pyreadline-refactor: First commit on ironpython functionality (very basic, typing text but no editing, requires patched ironpython) --- doc/ChangeLog | 4 + pyreadline/__init__.py | 2 +- pyreadline/clipboard/__init__.py | 17 + pyreadline/{ => clipboard}/clipboard.py | 58 +-- pyreadline/clipboard/common.py | 58 +++ pyreadline/clipboard/ironpython_clipboard.py | 28 ++ pyreadline/console/__init__.py | 19 + pyreadline/{ => console}/console.py | 30 +- .../{ => console}/console_attributes.py | 0 pyreadline/console/consolebase.py | 52 +++ pyreadline/console/event.py | 21 ++ pyreadline/console/ironpython_console.py | 335 ++++++++++++++++++ pyreadline/keysyms/__init__.py | 17 + pyreadline/keysyms/ironpython_keysyms.py | 186 ++++++++++ pyreadline/{ => keysyms}/keysyms.py | 2 +- pyreadline/{ => keysyms}/winconstants.py | 0 pyreadline/modes/emacs.py | 2 +- 17 files changed, 747 insertions(+), 84 deletions(-) create mode 100644 pyreadline/clipboard/__init__.py rename pyreadline/{ => clipboard}/clipboard.py (66%) create mode 100644 pyreadline/clipboard/common.py create mode 100644 pyreadline/clipboard/ironpython_clipboard.py create mode 100644 pyreadline/console/__init__.py rename pyreadline/{ => console}/console.py (93%) rename pyreadline/{ => console}/console_attributes.py (100%) create mode 100644 pyreadline/console/consolebase.py create mode 100644 pyreadline/console/event.py create mode 100644 pyreadline/console/ironpython_console.py create mode 100644 pyreadline/keysyms/__init__.py create mode 100644 pyreadline/keysyms/ironpython_keysyms.py rename pyreadline/{ => keysyms}/keysyms.py (98%) rename pyreadline/{ => keysyms}/winconstants.py (100%) diff --git a/doc/ChangeLog b/doc/ChangeLog index bb582a2..4436200 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,7 @@ +2006-07-04 Jörgen Stenarson + * First commit for ironpython. Typing in alphabet works but no special keys. + + 2006-04-18 Jörgen Stenarson * Added more tests for emacsmode * Made changes in lineeditor diff --git a/pyreadline/__init__.py b/pyreadline/__init__.py index 2a42456..2c8bb25 100644 --- a/pyreadline/__init__.py +++ b/pyreadline/__init__.py @@ -7,7 +7,7 @@ # the file COPYING, distributed as part of this software. #***************************************************************************** -import lineeditor,modes +import logger,clipboard,lineeditor,modes from rlmain import * __all__ = [ 'parse_and_bind', 'get_line_buffer', diff --git a/pyreadline/clipboard/__init__.py b/pyreadline/clipboard/__init__.py new file mode 100644 index 0000000..582adf3 --- /dev/null +++ b/pyreadline/clipboard/__init__.py @@ -0,0 +1,17 @@ +from common import * +success=False +try: + from clipboard import GetClipboardText,SetClipboardText + success=True +except ImportError: + pass + +try: + from ironpython_clipboard import GetClipboardText,SetClipboardText + success=True +except ImportError: + pass + + + + diff --git a/pyreadline/clipboard.py b/pyreadline/clipboard/clipboard.py similarity index 66% rename from pyreadline/clipboard.py rename to pyreadline/clipboard/clipboard.py index 6a597d3..17c45d2 100644 --- a/pyreadline/clipboard.py +++ b/pyreadline/clipboard/clipboard.py @@ -34,7 +34,7 @@ ################################################################################### from ctypes import * -from winconstants import CF_TEXT, GHND +from keysyms.winconstants import CF_TEXT, GHND OpenClipboard = windll.user32.OpenClipboard EmptyClipboard = windll.user32.EmptyClipboard @@ -84,20 +84,6 @@ def GetClipboardText(): CloseClipboard() return text -def make_tab(lists): - if hasattr(lists,"tolist"): - lists=lists.tolist() - ut=[] - for rad in lists: - if type(rad) in [list,tuple]: - ut.append("\t".join(["%s"%x for x in rad])) - else: - ut.append("%s"%rad) - return "\n".join(ut) - -def send_data(lists): - SetClipboardText(make_tab(lists)) - def SetClipboardText(text): buffer = c_buffer(text) bufferSize = sizeof(buffer) @@ -111,48 +97,6 @@ def SetClipboardText(text): SetClipboardData(c_int(CF_TEXT), c_int(hGlobalMem)) CloseClipboard() - -def set_clipboard_text(toclipboard): - SetClipboardText(str(toclipboard)) - -def make_list_of_list(txt): - def make_num(x): - try: - return int(x) - except ValueError: - try: - return float(x) - except ValueError: - try: - return complex(x) - except ValueError: - return x - return x - ut=[] - flag=False - for rad in [x for x in txt.split("\r\n") if x!=""]: - raden=[make_num(x) for x in rad.split("\t")] - if str in map(type,raden): - flag=True - ut.append(raden) - return ut,flag - - -def get_clipboard_text_and_convert(paste_list=False): - """Get txt from clipboard. if paste_list==True the convert tab separated - data to list of lists. Enclose list of list in array() if all elements are - numeric""" - txt=GetClipboardText() - if txt: - if paste_list and "\t" in txt: - array,flag=make_list_of_list(txt) - if flag: - txt=repr(array) - else: - txt="array(%s)"%repr(array) - txt="".join([c for c in txt if c not in " \t\r\n"]) - return txt - if __name__ == '__main__': txt=GetClipboardText() # display last text clipped print txt diff --git a/pyreadline/clipboard/common.py b/pyreadline/clipboard/common.py new file mode 100644 index 0000000..03722e8 --- /dev/null +++ b/pyreadline/clipboard/common.py @@ -0,0 +1,58 @@ + + +def send_data(lists): + SetClipboardText(make_tab(lists)) + + +def set_clipboard_text(toclipboard): + SetClipboardText(str(toclipboard)) + +def make_tab(lists): + if hasattr(lists,"tolist"): + lists=lists.tolist() + ut=[] + for rad in lists: + if type(rad) in [list,tuple]: + ut.append("\t".join(["%s"%x for x in rad])) + else: + ut.append("%s"%rad) + return "\n".join(ut) + +def make_list_of_list(txt): + def make_num(x): + try: + return int(x) + except ValueError: + try: + return float(x) + except ValueError: + try: + return complex(x) + except ValueError: + return x + return x + ut=[] + flag=False + for rad in [x for x in txt.split("\r\n") if x!=""]: + raden=[make_num(x) for x in rad.split("\t")] + if str in map(type,raden): + flag=True + ut.append(raden) + return ut,flag + + +def get_clipboard_text_and_convert(paste_list=False): + """Get txt from clipboard. if paste_list==True the convert tab separated + data to list of lists. Enclose list of list in array() if all elements are + numeric""" + txt=GetClipboardText() + if txt: + if paste_list and "\t" in txt: + array,flag=make_list_of_list(txt) + if flag: + txt=repr(array) + else: + txt="array(%s)"%repr(array) + txt="".join([c for c in txt if c not in " \t\r\n"]) + return txt + diff --git a/pyreadline/clipboard/ironpython_clipboard.py b/pyreadline/clipboard/ironpython_clipboard.py new file mode 100644 index 0000000..f91e099 --- /dev/null +++ b/pyreadline/clipboard/ironpython_clipboard.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +#***************************************************************************** +# Copyright (C) 2006 Jorgen Stenarson. +# +# Distributed under the terms of the BSD License. The full license is in +# the file COPYING, distributed as part of this software. +#***************************************************************************** +import clr +clr.AddReferenceByPartialName("System.Windows.Forms") +import System.Windows.Forms.Clipboard as cb + +def GetClipboardText(): + text="" + if cb.ContainsText(): + text=cb.GetText() + + return text + +def SetClipboardText(text): + cb.SetText(text) + +if __name__ == '__main__': + txt=GetClipboardText() # display last text clipped + print txt + + + + \ No newline at end of file diff --git a/pyreadline/console/__init__.py b/pyreadline/console/__init__.py new file mode 100644 index 0000000..8602b69 --- /dev/null +++ b/pyreadline/console/__init__.py @@ -0,0 +1,19 @@ +import glob + +success=False + +try: + from console import * + success=True +except ImportError: + pass + +try: + from ironpython_console import * + success=True +except ImportError: + pass + + +if not success: + raise ImportError("Could not find a console implementation for your platform") diff --git a/pyreadline/console.py b/pyreadline/console/console.py similarity index 93% rename from pyreadline/console.py rename to pyreadline/console/console.py index 11df2d8..1cab1b4 100644 --- a/pyreadline/console.py +++ b/pyreadline/console/console.py @@ -16,19 +16,17 @@ This was modeled after the C extension of the same name by Fredrik Lundh. import sys import traceback import re -from logger import log +from pyreadline.logger import log try: # I developed this with ctypes 0.6 from ctypes import * from _ctypes import call_function except ImportError: - print 'you need the ctypes module to run this code' - print 'http://starship.python.net/crew/theller/ctypes/' - raise + raise ImportError("You need ctypes to run this code") # my code -from keysyms import make_keysym, make_keyinfo +from pyreadline.keysyms import make_keysym, make_keyinfo # some constants we need STD_INPUT_HANDLE = -10 @@ -544,7 +542,9 @@ class Console(object): for func in funcs: setattr(Console, func, getattr(windll.kernel32, func)) -class event(object): +from event import Event + +class event(Event): '''Represent events from the console.''' def __init__(self, console, input): '''Initialize an event from the Windows input structure.''' @@ -591,24 +591,6 @@ class event(object): self.type = "Menu" self.state = input.Event.MenuEvent.dwCommandId - def __repr__(self): - '''Display an event for debugging.''' - if self.type in ['KeyPress', 'KeyRelease']: - s = "%s char='%s'%d keysym='%s' keycode=%d:%x state=%x keyinfo=%s" % \ - (self.type, self.char, ord(self.char), self.keysym, self.keycode, self.keycode, - self.state, self.keyinfo) - elif self.type in ['Motion', 'Button']: - s = '%s x=%d y=%d state=%x' % (self.type, self.x, self.y, self.state) - elif self.type == 'Configure': - s = '%s w=%d h=%d' % (self.type, self.width, self.height) - elif self.type in ['FocusIn', 'FocusOut']: - s = self.type - elif self.type == 'Menu': - s = '%s state=%x' % (self.type, self.state) - else: - s = 'unknown event type' - return s - def getconsole(buffer=1): """Get a console handle. diff --git a/pyreadline/console_attributes.py b/pyreadline/console/console_attributes.py similarity index 100% rename from pyreadline/console_attributes.py rename to pyreadline/console/console_attributes.py diff --git a/pyreadline/console/consolebase.py b/pyreadline/console/consolebase.py new file mode 100644 index 0000000..3409ced --- /dev/null +++ b/pyreadline/console/consolebase.py @@ -0,0 +1,52 @@ +class baseconsole: + def __init__(self): + pass + + def bell(self): + raise NotImplementedError + + def pos(self, x=None, y=None): + '''Move or query the window cursor.''' + raise NotImplementedError + + def size(self): + raise NotImplementedError + + def rectangle(self, rect, attr=None, fill=' '): + '''Fill Rectangle.''' + raise NotImplementedError + + def write_scrolling(self, text, attr=None): + '''write text at current cursor position while watching for scrolling. + + If the window scrolls because you are at the bottom of the screen + buffer, all positions that you are storing will be shifted by the + scroll amount. For example, I remember the cursor position of the + prompt so that I can redraw the line but if the window scrolls, + the remembered position is off. + + This variant of write tries to keep track of the cursor position + so that it will know when the screen buffer is scrolled. It + returns the number of lines that the buffer scrolled. + + ''' + raise NotImplementedError + + def getkeypress(self): + '''Return next key press event from the queue, ignoring others.''' + raise NotImplementedError + + def write(self, text): + raise NotImplementedError + + def page(self, attr=None, fill=' '): + '''Fill the entire screen.''' + raise NotImplementedError + + def isatty(self): + return True + + def flush(self): + pass + + \ No newline at end of file diff --git a/pyreadline/console/event.py b/pyreadline/console/event.py new file mode 100644 index 0000000..599ff73 --- /dev/null +++ b/pyreadline/console/event.py @@ -0,0 +1,21 @@ +class Event(object): + '''Represent events from the console.''' + def __init__(self, console, input): + pass + def __repr__(self): + '''Display an event for debugging.''' + if self.type in ['KeyPress', 'KeyRelease']: + s = "%s char='%s'%d keysym='%s' keycode=%d:%x state=%x keyinfo=%s" % \ + (self.type, self.char, ord(self.char), self.keysym, self.keycode, self.keycode, + self.state, self.keyinfo) + elif self.type in ['Motion', 'Button']: + s = '%s x=%d y=%d state=%x' % (self.type, self.x, self.y, self.state) + elif self.type == 'Configure': + s = '%s w=%d h=%d' % (self.type, self.width, self.height) + elif self.type in ['FocusIn', 'FocusOut']: + s = self.type + elif self.type == 'Menu': + s = '%s state=%x' % (self.type, self.state) + else: + s = 'unknown event type' + return s diff --git a/pyreadline/console/ironpython_console.py b/pyreadline/console/ironpython_console.py new file mode 100644 index 0000000..de59eff --- /dev/null +++ b/pyreadline/console/ironpython_console.py @@ -0,0 +1,335 @@ +# -*- coding: utf-8 -*- +#***************************************************************************** +# Copyright (C) 2003-2006 Gary Bishop. +# Copyright (C) 2006 Jorgen Stenarson. +# +# Distributed under the terms of the BSD License. The full license is in +# the file COPYING, distributed as part of this software. +#***************************************************************************** +'''Cursor control and color for the .NET console. +''' + +# primitive debug printing that won't interfere with the screen + +import clr +clr.AddReference("IronPythonConsole.exe") +import IronPythonConsole + +import sys +import traceback +import re +import os + +import System + +from event import Event +from pyreadline.logger import log + +print "Codepage",System.Console.InputEncoding.CodePage +from pyreadline.keysyms import make_keysym, make_keyinfo + +color=System.ConsoleColor + +ansicolor={ + "0;31": color.DarkRed, + "0;32": color.DarkGreen, + "0;33": color.DarkYellow, + "0;34": color.DarkBlue, + "0;35": color.DarkMagenta, + "0;36": color.DarkCyan, + "0;37": color.DarkGray, + "1;31": color.Red, + "1;32": color.Green, + "1;33": color.Yellow, + "1;34": color.Blue, + "1;35": color.Magenta, + "1;36": color.Cyan, + "1;37": color.White + } + +class Console(object): + '''Console driver for Windows. + + ''' + + def __init__(self, newbuffer=0): + '''Initialize the Console object. + + newbuffer=1 will allocate a new buffer so the old content will be restored + on exit. + ''' + self.serial=0 + self.attr = System.Console.ForegroundColor + self.saveattr = System.Console.ForegroundColor + log('initial attr=%x' % self.attr) + + def __del__(self): + '''Cleanup the console when finished.''' + # I don't think this ever gets called + self.SetConsoleTextAttribute(self.hout, self.saveattr) + self.SetConsoleMode(self.hin, self.inmode) + self.FreeConsole() + + def pos(self, x=None, y=None): + '''Move or query the window cursor.''' + if x is not None: + System.Console.CursorLeft=x + else: + x=System.Console.CursorLeft + if y is not None: + System.Console.CursorTop=y + else: + y=System.Console.CursorTop + return x,y + + def home(self): + '''Move to home.''' + self.pos(0,0) + +# Map ANSI color escape sequences into Windows Console Attributes + + terminal_escape = re.compile('(\001?\033\\[[0-9;]*m\002?)') + escape_parts = re.compile('\001?\033\\[([0-9;]*)m\002?') + + # This pattern should match all characters that change the cursor position differently + # than a normal character. + motion_char_re = re.compile('([\n\r\t\010\007])') + + def write_scrolling(self, text, attr=None): + '''write text at current cursor position while watching for scrolling. + + If the window scrolls because you are at the bottom of the screen + buffer, all positions that you are storing will be shifted by the + scroll amount. For example, I remember the cursor position of the + prompt so that I can redraw the line but if the window scrolls, + the remembered position is off. + + This variant of write tries to keep track of the cursor position + so that it will know when the screen buffer is scrolled. It + returns the number of lines that the buffer scrolled. + + ''' + x, y = self.pos() + w, h = self.size() + scroll = 0 # the result + + # split the string into ordinary characters and funny characters + chunks = self.motion_char_re.split(text) + for chunk in chunks: + log('C:'+chunk) + n = self.write_color(chunk, attr) + if len(chunk) == 1: # the funny characters will be alone + if chunk[0] == '\n': # newline + x = 0 + y += 1 + elif chunk[0] == '\r': # carriage return + x = 0 + elif chunk[0] == '\t': # tab + x = 8*(int(x/8)+1) + if x > w: # newline + x -= w + y += 1 + elif chunk[0] == '\007': # bell + pass + elif chunk[0] == '\010': + x -= 1 + if x < 0: + y -= 1 # backed up 1 line + else: # ordinary character + x += 1 + if x == w: # wrap + x = 0 + y += 1 + if y == h: # scroll + scroll += 1 + y = h - 1 + else: # chunk of ordinary characters + x += n + l = int(x / w) # lines we advanced + x = x % w # new x value + y += l + if y >= h: # scroll + scroll += y - h + 1 + y = h - 1 + return scroll + + def write_color(self, text, attr=None): + '''write text at current cursor position and interpret color escapes. + + return the number of characters written. + ''' + log('write_color("%s", %s)' % (text, attr)) + chunks = self.terminal_escape.split(text) + log('chunks=%s' % repr(chunks)) + n = 0 # count the characters we actually write, omitting the escapes + if attr is None:#use attribute from initial console + attr = self.attr + for chunk in chunks: + m = self.escape_parts.match(chunk) + if m: + log(m.group(1)) + attr=ansicolor.get(m.group(1),self.attr) + n += len(chunk) + log('attr=%s' % attr) + System.Console.ForegroundColor=attr + #self.WriteConsoleA(self.hout, chunk, len(chunk), byref(junk), None) + System.Console.Write(chunk) + return n + + def write_plain(self, text, attr=None): + '''write text at current cursor position.''' + log('write("%s", %s)' %(text,attr)) + if attr is None: + attr = self.attr + n = c_int(0) + self.SetConsoleTextAttribute(self.hout, attr) + self.WriteConsoleA(self.hout, text, len(text), byref(n), None) + return len(text) + + if os.environ.has_key("EMACS"): + def write_color(self, text, attr=None): + junk = c_int(0) + self.WriteFile(self.hout, text, len(text), byref(junk), None) + return len(text) + write_plain = write_color + + # make this class look like a file object + def write(self, text): + log('write("%s")' % text) + return self.write_color(text) + + #write = write_scrolling + + def isatty(self): + return True + + def flush(self): + pass + + def page(self, attr=None, fill=' '): + '''Fill the entire screen.''' + System.Console.Clear() + + def text(self, x, y, text, attr=None): + '''Write text at the given position.''' + self.pos(x,y) + self.write_color(text,attr) + + def rectangle(self, rect, attr=None, fill=' '): + '''Fill Rectangle.''' + pass + #raise NotImplementedError + + def scroll(self, rect, dx, dy, attr=None, fill=' '): + '''Scroll a rectangle.''' + pass + raise NotImplementedError + + def scroll_window(self, lines): + '''Scroll the window by the indicated number of lines.''' + top=System.Console.WindowTop+lines + if top<0: + top=0 + if top+System.Console.WindowHeight>System.Console.BufferHeight: + top=System.Console.BufferHeight + System.Console.WindowTop=top + + def getkeypress(self): + '''Return next key press event from the queue, ignoring others.''' + ck=System.ConsoleKey + while 1: + e = System.Console.ReadKey(True) + if e.Key == System.ConsoleKey.PageDown: #PageDown + self.scroll_window(12) + elif e.Key == System.ConsoleKey.PageUp:#PageUp + self.scroll_window(-12) + elif str(e.KeyChar)=="\000":#Drop deadkeys + pass + else: + return event(self,e) + + def title(self, txt=None): + '''Set/get title.''' + if txt: + System.Console.Title=txt + else: + return System.Console.Title + + def size(self, width=None, height=None): + '''Set/get window size.''' + sc=System.Console + if width is not None and height is not None: + sc.WindowWidth,sc.WindowHeight=width,height + else: + return sc.WindowWidth,sc.WindowHeight + + def cursor(self, visible=None, size=None): + '''Set cursor on or off.''' + System.Console.CursorVisible=visible + + def bell(self): + System.Console.Beep() + + def next_serial(self): + '''Get next event serial number.''' + self.serial += 1 + return self.serial + +class event(Event): + '''Represent events from the console.''' + def __init__(self, console, input): + '''Initialize an event from the Windows input structure.''' + self.type = '??' + self.serial = console.next_serial() + self.width = 0 + self.height = 0 + self.x = 0 + self.y = 0 + self.char = chr(input.KeyChar) + self.keycode = input.Key + self.state = input.Modifiers + + self.type="KeyRelease" + + self.keysym = make_keysym(self.keycode) + self.keyinfo = make_keyinfo(self.keycode, self.state) + + +def install_readline(hook): + class IronPythonWrapper(IronPythonConsole.IConsole): + def ReadLine(self,autoIndentSize): + return hook() + def Write(self,text, style): + System.Console.Write(text) + def WriteLine(self,text, style): + System.Console.WriteLine(text) + IronPythonConsole.PythonCommandLine.MyConsole = IronPythonWrapper() + + +def getconsole(buffer=1): + """Get a console handle. + + If buffer is non-zero, a new console buffer is allocated and + installed. Otherwise, this returns a handle to the current + console buffer""" + c = Console(buffer) + return c + +if __name__ == '_zx_main__': + import time, sys + c = Console(0) + sys.stdout = c + sys.stderr = c + c.page() + c.pos(5, 10) + c.write('hi there') + c.title("Testing console") +# c.bell() + print + print "size",c.size() + print ' some printed output' + for i in range(10): + e=c.getkeypress() + print e.Key,chr(e.KeyChar),ord(e.KeyChar),e.Modifiers + del c + diff --git a/pyreadline/keysyms/__init__.py b/pyreadline/keysyms/__init__.py new file mode 100644 index 0000000..795e9e9 --- /dev/null +++ b/pyreadline/keysyms/__init__.py @@ -0,0 +1,17 @@ +import glob + +success=False +try: + from keysyms import * + success=True +except ImportError,x: + pass + +try: + from ironpython_keysyms import * + success=True +except ImportError,x: + pass + +if not success: + raise ImportError("Could not import keysym for local pythonversion",x) \ No newline at end of file diff --git a/pyreadline/keysyms/ironpython_keysyms.py b/pyreadline/keysyms/ironpython_keysyms.py new file mode 100644 index 0000000..e9a9169 --- /dev/null +++ b/pyreadline/keysyms/ironpython_keysyms.py @@ -0,0 +1,186 @@ +# -*- coding: utf-8 -*- +#***************************************************************************** +# Copyright (C) 2003-2006 Gary Bishop. +# Copyright (C) 2006 Jorgen Stenarson. +# +# Distributed under the terms of the BSD License. The full license is in +# the file COPYING, distributed as part of this software. +#***************************************************************************** +import System + +c32=System.ConsoleKey +# table for translating virtual keys to X windows key symbols +code2sym_map = {#c32.CANCEL: 'Cancel', + c32.Backspace: 'BackSpace', + c32.Tab: 'Tab', + c32.Clear: 'Clear', + c32.Enter: 'Return', +# c32.Shift: 'Shift_L', +# c32.Control: 'Control_L', +# c32.Menu: 'Alt_L', + c32.Pause: 'Pause', +# c32.Capital: 'Caps_Lock', + c32.Escape: 'Escape', +# c32.Space: 'space', + c32.PageUp: 'Prior', + c32.PageDown: 'Next', + c32.End: 'End', + c32.Home: 'Home', + c32.LeftArrow: 'Left', + c32.UpArrow: 'Up', + c32.RightArrow: 'Right', + c32.DownArrow: 'Down', + c32.Select: 'Select', + c32.Print: 'Print', + c32.Execute: 'Execute', +# c32.Snapshot: 'Snapshot', + c32.Insert: 'Insert', + c32.Delete: 'Delete', + c32.Help: 'Help', + c32.F1: 'F1', + c32.F2: 'F2', + c32.F3: 'F3', + c32.F4: 'F4', + c32.F5: 'F5', + c32.F6: 'F6', + c32.F7: 'F7', + c32.F8: 'F8', + c32.F9: 'F9', + c32.F10: 'F10', + c32.F11: 'F11', + c32.F12: 'F12', + c32.F13: 'F13', + c32.F14: 'F14', + c32.F15: 'F15', + c32.F16: 'F16', + c32.F17: 'F17', + c32.F18: 'F18', + c32.F19: 'F19', + c32.F20: 'F20', + c32.F21: 'F21', + c32.F22: 'F22', + c32.F23: 'F23', + c32.F24: 'F24', +# c32.Numlock: 'Num_Lock,', +# c32.Scroll: 'Scroll_Lock', +# c32.Apps: 'VK_APPS', +# c32.ProcesskeY: 'VK_PROCESSKEY', +# c32.Attn: 'VK_ATTN', +# c32.Crsel: 'VK_CRSEL', +# c32.Exsel: 'VK_EXSEL', +# c32.Ereof: 'VK_EREOF', +# c32.Play: 'VK_PLAY', +# c32.Zoom: 'VK_ZOOM', +# c32.Noname: 'VK_NONAME', +# c32.Pa1: 'VK_PA1', + c32.OemClear: 'VK_OEM_CLEAR', + c32.NumPad0: 'NUMPAD0', + c32.NumPad1: 'NUMPAD1', + c32.NumPad2: 'NUMPAD2', + c32.NumPad3: 'NUMPAD3', + c32.NumPad4: 'NUMPAD4', + c32.NumPad5: 'NUMPAD5', + c32.NumPad6: 'NUMPAD6', + c32.NumPad7: 'NUMPAD7', + c32.NumPad8: 'NUMPAD8', + c32.NumPad9: 'NUMPAD9', + c32.Divide: 'Divide', + c32.Multiply: 'Multiply', + c32.Add: 'Add', + c32.Subtract: 'Subtract', + c32.Decimal: 'VK_DECIMAL' + } + +# function to handle the mapping +def make_keysym(keycode): + try: + sym = code2sym_map[keycode] + except KeyError: + sym = '' + return sym + +sym2code_map = {} +for code,sym in code2sym_map.iteritems(): + sym2code_map[sym.lower()] = code + +def key_text_to_keyinfo(keytext): + '''Convert a GNU readline style textual description of a key to keycode with modifiers''' + if keytext.startswith('"'): # " + return keyseq_to_keyinfo(keytext[1:-1]) + else: + return keyname_to_keyinfo(keytext) + + +def char_to_keyinfo(char, control=False, meta=False, shift=False): + vk = (ord(char)) + if vk & 0xffff == 0xffff: + print 'VkKeyScan("%s") = %x' % (char, vk) + raise ValueError, 'bad key' + if vk & 0x100: + shift = True + if vk & 0x200: + control = True + if vk & 0x400: + meta = True + return (control, meta, shift, vk & 0xff) + +def keyname_to_keyinfo(keyname): + control = False + meta = False + shift = False + + while 1: + lkeyname = keyname.lower() + if lkeyname.startswith('control-'): + control = True + keyname = keyname[8:] + elif lkeyname.startswith('ctrl-'): + control = True + keyname = keyname[5:] + elif lkeyname.startswith('meta-'): + meta = True + keyname = keyname[5:] + elif lkeyname.startswith('alt-'): + meta = True + keyname = keyname[4:] + elif lkeyname.startswith('shift-'): + shift = True + keyname = keyname[6:] + else: + if len(keyname) > 1: + return (control, meta, shift, sym2code_map.get(keyname.lower()," ")) + else: + return char_to_keyinfo(keyname, control, meta, shift) + +def keyseq_to_keyinfo(keyseq): + res = [] + control = False + meta = False + shift = False + + while 1: + if keyseq.startswith('\\C-'): + control = True + keyseq = keyseq[3:] + elif keyseq.startswith('\\M-'): + meta = True + keyseq = keyseq[3:] + elif keyseq.startswith('\\e'): + res.append(char_to_keyinfo('\033', control, meta, shift)) + control = meta = shift = False + keyseq = keyseq[2:] + elif len(keyseq) >= 1: + res.append(char_to_keyinfo(keyseq[0], control, meta, shift)) + control = meta = shift = False + keyseq = keyseq[1:] + else: + return res[0] + +def make_keyinfo(keycode, state): +# control = (state & (4+8)) != 0 +# meta = (state & (1+2)) != 0 +# shift = (state & 0x10) != 0 + control=False + meta=False + shift=False + return (control, meta, shift, keycode) diff --git a/pyreadline/keysyms.py b/pyreadline/keysyms/keysyms.py similarity index 98% rename from pyreadline/keysyms.py rename to pyreadline/keysyms/keysyms.py index ef298ac..6ad9d10 100644 --- a/pyreadline/keysyms.py +++ b/pyreadline/keysyms/keysyms.py @@ -149,7 +149,7 @@ def keyname_to_keyinfo(keyname): keyname = keyname[6:] else: if len(keyname) > 1: - return (control, meta, shift, sym2code_map[keyname.lower()]) + return (control, meta, shift, sym2code_map.get(keyname.lower()," ")) else: return char_to_keyinfo(keyname, control, meta, shift) diff --git a/pyreadline/winconstants.py b/pyreadline/keysyms/winconstants.py similarity index 100% rename from pyreadline/winconstants.py rename to pyreadline/keysyms/winconstants.py diff --git a/pyreadline/modes/emacs.py b/pyreadline/modes/emacs.py index 2b79812..5f1fdef 100644 --- a/pyreadline/modes/emacs.py +++ b/pyreadline/modes/emacs.py @@ -22,7 +22,7 @@ class EmacsMode(basemode.BaseMode): super(EmacsMode,self).__init__(rlobj) self._keylog=(lambda x,y: None) self.previous_func=None - + self.prompt="" def __repr__(self): return ""