2222# THE SOFTWARE.
2323#
2424
25+ # Modified by Brandon Navra
26+ # Notes for Windows
27+ # Prerequsites
28+ # - Curses
29+ # - pyreadline
30+ #
31+ # Added
32+ #
33+ # - Support for running on windows command prompt
34+ # - input from numpad keys
35+ #
36+ # Issues
37+ #
38+ # - Suspend doesn't work nor does detection of resizing of screen
39+ # - Instead the suspend key exits the program
40+ # - View source doesn't work on windows unless you install the less program (From GnuUtils or Cygwin)
41+
2542from __future__ import division , with_statement
2643
44+ import platform
2745import os
2846import sys
2947import curses
3048import math
3149import re
3250import time
33- import signal
51+
3452import struct
35- import termios
36- import fcntl
53+ if platform .system () != 'Windows' :
54+ import signal #Windows does not have job control
55+ import termios #Windows uses curses
56+ import fcntl #Windows uses curses
3757import unicodedata
3858import errno
3959
7696DO_RESIZE = False
7797# ---
7898
99+
79100def getpreferredencoding ():
80101 return locale .getpreferredencoding () or sys .getdefaultencoding ()
81102
@@ -136,7 +157,7 @@ def readline(self, size=-1):
136157
137158 curses .raw (True )
138159 try :
139- while not buffer .endswith ('\n ' ):
160+ while not ( buffer .endswith ('\n ' ) or buffer . endswith ( ' \r ' ) ):
140161 key = self .interface .get_key ()
141162 if key in [curses .erasechar (), 'KEY_BACKSPACE' ]:
142163 y , x = self .interface .scr .getyx ()
@@ -147,7 +168,7 @@ def readline(self, size=-1):
147168 elif key == chr (4 ) and not buffer :
148169 # C-d
149170 return ''
150- elif (key != '\n ' and
171+ elif (key not in ( '\n ' , ' \r ' ) and
151172 (len (key ) > 1 or unicodedata .category (key ) == 'Cc' )):
152173 continue
153174 sys .stdout .write (key )
@@ -224,6 +245,21 @@ def make_colors(config):
224245 'w' : 7 ,
225246 'd' : - 1 ,
226247 }
248+
249+ if platform .system () == 'Windows' :
250+ c = dict (c .items () +
251+ [
252+ ('K' , 8 ),
253+ ('R' , 9 ),
254+ ('G' , 10 ),
255+ ('Y' , 11 ),
256+ ('B' , 12 ),
257+ ('M' , 13 ),
258+ ('C' , 14 ),
259+ ('W' , 15 ),
260+ ]
261+ )
262+
227263 for i in range (63 ):
228264 if i > 7 :
229265 j = i // 8
@@ -773,14 +809,22 @@ def p_key(self, key):
773809
774810 config = self .config
775811
776- if key == chr (8 ): # C-Backspace (on my computer anyway!)
812+ if platform .system () == 'Windows' :
813+ C_BACK = chr (127 )
814+ BACKSP = chr (8 )
815+ else :
816+ C_BACK = chr (8 )
817+ BACKSP = chr (127 )
818+
819+ if key == C_BACK : # C-Backspace (on my computer anyway!)
777820 self .clrtobol ()
778821 key = '\n '
779822 # Don't return; let it get handled
780- if key == chr (27 ):
823+
824+ if key == chr (27 ): #Escape Key
781825 return ''
782826
783- if key in (chr ( 127 ) , 'KEY_BACKSPACE' ):
827+ if key in (BACKSP , 'KEY_BACKSPACE' ):
784828 self .bs ()
785829 self .complete ()
786830 return ''
@@ -893,7 +937,7 @@ def p_key(self, key):
893937 self .statusbar .message (_ ('Cannot show source.' ))
894938 return ''
895939
896- elif key == '\n ' :
940+ elif key in ( '\n ' , ' \r ' , 'PADENTER' ) :
897941 self .lf ()
898942 return None
899943
@@ -904,9 +948,25 @@ def p_key(self, key):
904948 return self .tab (back = True )
905949
906950 elif key in key_dispatch [config .suspend_key ]:
907- self .suspend ()
908- return ''
951+ if platform .system () != 'Windows' :
952+ self .suspend ()
953+ return ''
954+ else :
955+ self .do_exit = True
956+ return None
909957
958+ elif key [0 :3 ] == 'PAD' and not key in ('PAD0' , 'PADSTOP' ):
959+ pad_keys = {
960+ 'PADMINUS' : '-' ,
961+ 'PADPLUS' : '+' ,
962+ 'PADSLASH' : '/' ,
963+ 'PADSTAR' : '*' ,
964+ }
965+ try :
966+ self .addstr (pad_keys [key ])
967+ self .print_line (self .s )
968+ except KeyError :
969+ return ''
910970 elif len (key ) == 1 and not unicodedata .category (key ) == 'Cc' :
911971 self .addstr (key )
912972 self .print_line (self .s )
@@ -1296,8 +1356,9 @@ def size(self):
12961356
12971357 def suspend (self ):
12981358 """Suspend the current process for shell job control."""
1299- curses .endwin ()
1300- os .kill (os .getpid (), signal .SIGSTOP )
1359+ if platform .system () != 'Windows' :
1360+ curses .endwin ()
1361+ os .kill (os .getpid (), signal .SIGSTOP )
13011362
13021363 def tab (self , back = False ):
13031364 """Process the tab key being hit. If there's only whitespace
@@ -1575,9 +1636,32 @@ def gethw():
15751636 So I'm not going to ask any questions.
15761637
15771638 """
1578- h , w = struct .unpack (
1579- "hhhh" ,
1580- fcntl .ioctl (sys .__stdout__ , termios .TIOCGWINSZ , "\000 " * 8 ))[0 :2 ]
1639+
1640+ if platform .system () != 'Windows' :
1641+ h , w = struct .unpack (
1642+ "hhhh" ,
1643+ fcntl .ioctl (sys .__stdout__ , termios .TIOCGWINSZ , "\000 " * 8 ))[0 :2 ]
1644+ else :
1645+ from ctypes import windll , create_string_buffer
1646+
1647+ # stdin handle is -10
1648+ # stdout handle is -11
1649+ # stderr handle is -12
1650+
1651+ h = windll .kernel32 .GetStdHandle (- 12 )
1652+ csbi = create_string_buffer (22 )
1653+ res = windll .kernel32 .GetConsoleScreenBufferInfo (h , csbi )
1654+
1655+ if res :
1656+ import struct
1657+ (bufx , bufy , curx , cury , wattr ,
1658+ left , top , right , bottom , maxx , maxy ) = struct .unpack ("hhhhHhhhhhh" , csbi .raw )
1659+ sizex = right - left + 1
1660+ sizey = bottom - top + 1
1661+ else :
1662+ sizex , sizey = stdscr .getmaxyx ()# can't determine actual size - return default values
1663+
1664+ h , w = sizey , sizex
15811665 return h , w
15821666
15831667
@@ -1679,10 +1763,11 @@ def main_curses(scr, args, config, interactive=True, locals_=None,
16791763 global colors
16801764 DO_RESIZE = False
16811765
1682- old_sigwinch_handler = signal .signal (signal .SIGWINCH ,
1683- lambda * _ : sigwinch (scr ))
1684- # redraw window after being suspended
1685- old_sigcont_handler = signal .signal (signal .SIGCONT , lambda * _ : sigcont (scr ))
1766+ if platform .system () != 'Windows' :
1767+ old_sigwinch_handler = signal .signal (signal .SIGWINCH ,
1768+ lambda * _ : sigwinch (scr ))
1769+ # redraw window after being suspended
1770+ old_sigcont_handler = signal .signal (signal .SIGCONT , lambda * _ : sigcont (scr ))
16861771
16871772 stdscr = scr
16881773 try :
@@ -1733,8 +1818,9 @@ def main_curses(scr, args, config, interactive=True, locals_=None,
17331818 curses .raw (False )
17341819
17351820 # Restore signal handlers
1736- signal .signal (signal .SIGWINCH , old_sigwinch_handler )
1737- signal .signal (signal .SIGCONT , old_sigcont_handler )
1821+ if platform .system () != 'Windows' :
1822+ signal .signal (signal .SIGWINCH , old_sigwinch_handler )
1823+ signal .signal (signal .SIGCONT , old_sigcont_handler )
17381824
17391825 return clirepl .getstdout ()
17401826
@@ -1743,6 +1829,7 @@ def main(args=None, locals_=None, banner=None):
17431829 locale .setlocale (locale .LC_ALL , "" )
17441830 translations .init ()
17451831
1832+
17461833 config , options , exec_args = bpython .args .parse (args )
17471834
17481835 # Save stdin, stdout and stderr for later restoration
0 commit comments