mirror of
https://github.com/python/cpython.git
synced 2025-07-23 03:05:38 +00:00
Keybindings with the Shift modifier now work correctly. So do bindings
which use the Space key. Limit unmodified user keybindings to the function keys. Python Bug 775353, IDLEfork Bugs 755647, 761557 Improve error handling during startup if there's no Tkinter. M NEWS.txt M PyShell.py M config-keys.def M configHandler.py M keybindingDialog.py Backport candidate.
This commit is contained in:
parent
5f4e45d66f
commit
2303b1c19a
5 changed files with 83 additions and 74 deletions
|
@ -3,6 +3,10 @@ What's New in IDLE 1.0+?
|
||||||
|
|
||||||
*Release date: XX-XXX-2003*
|
*Release date: XX-XXX-2003*
|
||||||
|
|
||||||
|
- Keybindings with the Shift modifier now work correctly. So do bindings which
|
||||||
|
use the Space key. Limit unmodified user keybindings to the function keys.
|
||||||
|
Python Bug 775353, IDLEfork Bugs 755647, 761557
|
||||||
|
|
||||||
- After an exception, run.py was not setting the exception vector. Noam
|
- After an exception, run.py was not setting the exception vector. Noam
|
||||||
Raphael suggested correcting this so pdb's postmortem pm() would work.
|
Raphael suggested correcting this so pdb's postmortem pm() would work.
|
||||||
IDLEfork Patch 844675
|
IDLEfork Patch 844675
|
||||||
|
|
|
@ -16,7 +16,12 @@ import exceptions
|
||||||
import linecache
|
import linecache
|
||||||
from code import InteractiveInterpreter
|
from code import InteractiveInterpreter
|
||||||
|
|
||||||
from Tkinter import *
|
try:
|
||||||
|
from Tkinter import *
|
||||||
|
except ImportError:
|
||||||
|
print>>sys.__stderr__, "** IDLE can't import Tkinter. " \
|
||||||
|
"Your Python may not be configured for Tk. **"
|
||||||
|
sys.exit(1)
|
||||||
import tkMessageBox
|
import tkMessageBox
|
||||||
|
|
||||||
from EditorWindow import EditorWindow, fixwordbreaks
|
from EditorWindow import EditorWindow, fixwordbreaks
|
||||||
|
|
|
@ -30,10 +30,10 @@ open-new-window=<Control-Key-n>
|
||||||
open-window-from-file=<Control-Key-o>
|
open-window-from-file=<Control-Key-o>
|
||||||
plain-newline-and-indent=<Control-Key-j>
|
plain-newline-and-indent=<Control-Key-j>
|
||||||
print-window=<Control-Key-p>
|
print-window=<Control-Key-p>
|
||||||
redo=<Control-Shift-Key-z>
|
redo=<Control-Shift-Key-Z>
|
||||||
remove-selection=<Key-Escape>
|
remove-selection=<Key-Escape>
|
||||||
save-copy-of-window-as-file=<Alt-Shift-Key-s>
|
save-copy-of-window-as-file=<Alt-Shift-Key-S>
|
||||||
save-window-as-file=<Control-Shift-Key-s>
|
save-window-as-file=<Control-Shift-Key-S>
|
||||||
save-window=<Control-Key-s>
|
save-window=<Control-Key-s>
|
||||||
select-all=<Control-Key-a>
|
select-all=<Control-Key-a>
|
||||||
toggle-auto-coloring=<Control-Key-slash>
|
toggle-auto-coloring=<Control-Key-slash>
|
||||||
|
@ -78,7 +78,7 @@ open-window-from-file=<Control-Key-x><Control-Key-f>
|
||||||
plain-newline-and-indent=<Control-Key-j>
|
plain-newline-and-indent=<Control-Key-j>
|
||||||
print-window=<Control-x><Control-Key-p>
|
print-window=<Control-x><Control-Key-p>
|
||||||
python-docs=<Control-Key-h>
|
python-docs=<Control-Key-h>
|
||||||
python-context-help=<Control-Shift-Key-h>
|
python-context-help=<Control-Shift-Key-H>
|
||||||
redo=<Alt-Key-z> <Meta-Key-z>
|
redo=<Alt-Key-z> <Meta-Key-z>
|
||||||
remove-selection=<Key-Escape>
|
remove-selection=<Key-Escape>
|
||||||
save-copy-of-window-as-file=<Control-Key-x><Control-Key-y>
|
save-copy-of-window-as-file=<Control-Key-x><Control-Key-y>
|
||||||
|
@ -128,9 +128,9 @@ open-new-window=<Command-Key-n>
|
||||||
open-window-from-file=<Command-Key-o>
|
open-window-from-file=<Command-Key-o>
|
||||||
plain-newline-and-indent=<Control-Key-j>
|
plain-newline-and-indent=<Control-Key-j>
|
||||||
print-window=<Command-Key-p>
|
print-window=<Command-Key-p>
|
||||||
redo=<Shift-Command-Key-z>
|
redo=<Shift-Command-Key-Z>
|
||||||
remove-selection=<Key-Escape>
|
remove-selection=<Key-Escape>
|
||||||
save-window-as-file=<Shift-Command-Key-s>
|
save-window-as-file=<Shift-Command-Key-S>
|
||||||
save-window=<Command-Key-s>
|
save-window=<Command-Key-s>
|
||||||
save-copy-of-window-as-file=<Option-Command-Key-s>
|
save-copy-of-window-as-file=<Option-Command-Key-s>
|
||||||
select-all=<Command-Key-a>
|
select-all=<Command-Key-a>
|
||||||
|
|
|
@ -531,7 +531,7 @@ class IdleConf:
|
||||||
'<<print-window>>': ['<Control-p>'],
|
'<<print-window>>': ['<Control-p>'],
|
||||||
'<<redo>>': ['<Control-y>'],
|
'<<redo>>': ['<Control-y>'],
|
||||||
'<<remove-selection>>': ['<Escape>'],
|
'<<remove-selection>>': ['<Escape>'],
|
||||||
'<<save-copy-of-window-as-file>>': ['<Alt-Shift-s>'],
|
'<<save-copy-of-window-as-file>>': ['<Alt-Shift-S>'],
|
||||||
'<<save-window-as-file>>': ['<Alt-s>'],
|
'<<save-window-as-file>>': ['<Alt-s>'],
|
||||||
'<<save-window>>': ['<Control-s>'],
|
'<<save-window>>': ['<Control-s>'],
|
||||||
'<<select-all>>': ['<Alt-a>'],
|
'<<select-all>>': ['<Alt-a>'],
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
"""
|
"""
|
||||||
dialog for building tkinter accelerator key bindings
|
Dialog for building Tkinter accelerator key bindings
|
||||||
"""
|
"""
|
||||||
from Tkinter import *
|
from Tkinter import *
|
||||||
import tkMessageBox
|
import tkMessageBox
|
||||||
|
@ -49,9 +49,9 @@ class GetKeysDialog(Toplevel):
|
||||||
frameMain.pack(side=TOP,expand=TRUE,fill=BOTH)
|
frameMain.pack(side=TOP,expand=TRUE,fill=BOTH)
|
||||||
frameButtons=Frame(self)
|
frameButtons=Frame(self)
|
||||||
frameButtons.pack(side=BOTTOM,fill=X)
|
frameButtons.pack(side=BOTTOM,fill=X)
|
||||||
self.buttonOk = Button(frameButtons,text='Ok',
|
self.buttonOK = Button(frameButtons,text='OK',
|
||||||
width=8,command=self.Ok)
|
width=8,command=self.OK)
|
||||||
self.buttonOk.grid(row=0,column=0,padx=5,pady=5)
|
self.buttonOK.grid(row=0,column=0,padx=5,pady=5)
|
||||||
self.buttonCancel = Button(frameButtons,text='Cancel',
|
self.buttonCancel = Button(frameButtons,text='Cancel',
|
||||||
width=8,command=self.Cancel)
|
width=8,command=self.Cancel)
|
||||||
self.buttonCancel.grid(row=0,column=1,padx=5,pady=5)
|
self.buttonCancel.grid(row=0,column=1,padx=5,pady=5)
|
||||||
|
@ -85,9 +85,13 @@ class GetKeysDialog(Toplevel):
|
||||||
self.modifier_checkbuttons[modifier] = check
|
self.modifier_checkbuttons[modifier] = check
|
||||||
column += 1
|
column += 1
|
||||||
labelFnAdvice=Label(self.frameControlsBasic,justify=LEFT,
|
labelFnAdvice=Label(self.frameControlsBasic,justify=LEFT,
|
||||||
text="Select the desired modifier\n"+
|
text=\
|
||||||
"keys above, and final key\n"+
|
"Select the desired modifier keys\n"+
|
||||||
"from the list on the right.")
|
"above, and the final key from the\n"+
|
||||||
|
"list on the right.\n\n" +
|
||||||
|
"Use upper case Symbols when using\n" +
|
||||||
|
"the Shift modifier. (Letters will be\n" +
|
||||||
|
"converted automatically.)")
|
||||||
labelFnAdvice.grid(row=1,column=0,columnspan=4,padx=2,sticky=W)
|
labelFnAdvice.grid(row=1,column=0,columnspan=4,padx=2,sticky=W)
|
||||||
self.listKeysFinal=Listbox(self.frameControlsBasic,width=15,height=10,
|
self.listKeysFinal=Listbox(self.frameControlsBasic,width=15,height=10,
|
||||||
selectmode=SINGLE)
|
selectmode=SINGLE)
|
||||||
|
@ -102,17 +106,19 @@ class GetKeysDialog(Toplevel):
|
||||||
self.buttonClear.grid(row=2,column=0,columnspan=4)
|
self.buttonClear.grid(row=2,column=0,columnspan=4)
|
||||||
labelTitleAdvanced = Label(self.frameKeySeqAdvanced,justify=LEFT,
|
labelTitleAdvanced = Label(self.frameKeySeqAdvanced,justify=LEFT,
|
||||||
text="Enter new binding(s) for '"+self.action+"' :\n"+
|
text="Enter new binding(s) for '"+self.action+"' :\n"+
|
||||||
"(will not be checked for validity)")
|
"(These bindings will not be checked for validity!)")
|
||||||
labelTitleAdvanced.pack(anchor=W)
|
labelTitleAdvanced.pack(anchor=W)
|
||||||
self.entryKeysAdvanced=Entry(self.frameKeySeqAdvanced,
|
self.entryKeysAdvanced=Entry(self.frameKeySeqAdvanced,
|
||||||
textvariable=self.keyString)
|
textvariable=self.keyString)
|
||||||
self.entryKeysAdvanced.pack(fill=X)
|
self.entryKeysAdvanced.pack(fill=X)
|
||||||
labelHelpAdvanced=Label(self.frameHelpAdvanced,justify=LEFT,
|
labelHelpAdvanced=Label(self.frameHelpAdvanced,justify=LEFT,
|
||||||
text="Key bindings are specified using tkinter key id's as\n"+
|
text="Key bindings are specified using Tkinter keysyms as\n"+
|
||||||
"in these samples: <Control-f>, <Shift-F2>, <F12>,\n"
|
"in these samples: <Control-f>, <Shift-F2>, <F12>,\n"
|
||||||
"<Control-space>, <Meta-less>, <Control-Alt-Shift-x>.\n\n"+
|
"<Control-space>, <Meta-less>, <Control-Alt-Shift-X>.\n"
|
||||||
"'Emacs style' multi-keystroke bindings are specified as\n"+
|
"Upper case is used when the Shift modifier is present!\n\n" +
|
||||||
"follows: <Control-x><Control-y> or <Meta-f><Meta-g>.\n\n"+
|
"'Emacs style' multi-keystroke bindings are specified as\n" +
|
||||||
|
"follows: <Control-x><Control-y>, where the first key\n" +
|
||||||
|
"is the 'do-nothing' keybinding.\n\n" +
|
||||||
"Multiple separate bindings for one action should be\n"+
|
"Multiple separate bindings for one action should be\n"+
|
||||||
"separated by a space, eg., <Alt-v> <Meta-v>." )
|
"separated by a space, eg., <Alt-v> <Meta-v>." )
|
||||||
labelHelpAdvanced.grid(row=0,column=0,sticky=NSEW)
|
labelHelpAdvanced.grid(row=0,column=0,sticky=NSEW)
|
||||||
|
@ -149,20 +155,12 @@ class GetKeysDialog(Toplevel):
|
||||||
self.BuildKeyString()
|
self.BuildKeyString()
|
||||||
|
|
||||||
def BuildKeyString(self):
|
def BuildKeyString(self):
|
||||||
keyList=[]
|
keyList = modifiers = self.GetModifiers()
|
||||||
modifiers=self.GetModifiers()
|
finalKey = self.listKeysFinal.get(ANCHOR)
|
||||||
finalKey=self.listKeysFinal.get(ANCHOR)
|
|
||||||
if modifiers: modifiers[0]='<'+modifiers[0]
|
|
||||||
keyList=keyList+modifiers
|
|
||||||
if finalKey:
|
if finalKey:
|
||||||
if (not modifiers) and (finalKey not
|
finalKey = self.TranslateKey(finalKey, modifiers)
|
||||||
in self.alphanumKeys+self.punctuationKeys):
|
keyList.append(finalKey)
|
||||||
finalKey='<'+self.TranslateKey(finalKey)
|
self.keyString.set('<' + string.join(keyList,'-') + '>')
|
||||||
else:
|
|
||||||
finalKey=self.TranslateKey(finalKey)
|
|
||||||
keyList.append(finalKey+'>')
|
|
||||||
keyStr=string.join(keyList,'-')
|
|
||||||
self.keyString.set(keyStr)
|
|
||||||
|
|
||||||
def GetModifiers(self):
|
def GetModifiers(self):
|
||||||
modList = [variable.get() for variable in self.modifier_vars]
|
modList = [variable.get() for variable in self.modifier_vars]
|
||||||
|
@ -190,9 +188,10 @@ class GetKeysDialog(Toplevel):
|
||||||
self.whitespaceKeys+self.editKeys+self.moveKeys)
|
self.whitespaceKeys+self.editKeys+self.moveKeys)
|
||||||
self.listKeysFinal.insert(END, *keys)
|
self.listKeysFinal.insert(END, *keys)
|
||||||
|
|
||||||
def TranslateKey(self,key):
|
def TranslateKey(self, key, modifiers):
|
||||||
#translate from key list value to tkinter key-id
|
"Translate from keycap symbol to the Tkinter keysym"
|
||||||
translateDict={'~':'asciitilde','!':'exclam','@':'at','#':'numbersign',
|
translateDict = {'Space':'space',
|
||||||
|
'~':'asciitilde','!':'exclam','@':'at','#':'numbersign',
|
||||||
'%':'percent','^':'asciicircum','&':'ampersand','*':'asterisk',
|
'%':'percent','^':'asciicircum','&':'ampersand','*':'asterisk',
|
||||||
'(':'parenleft',')':'parenright','_':'underscore','-':'minus',
|
'(':'parenleft',')':'parenright','_':'underscore','-':'minus',
|
||||||
'+':'plus','=':'equal','{':'braceleft','}':'braceright',
|
'+':'plus','=':'equal','{':'braceleft','}':'braceright',
|
||||||
|
@ -200,14 +199,16 @@ class GetKeysDialog(Toplevel):
|
||||||
':':'colon',',':'comma','.':'period','<':'less','>':'greater',
|
':':'colon',',':'comma','.':'period','<':'less','>':'greater',
|
||||||
'/':'slash','?':'question','Page Up':'Prior','Page Down':'Next',
|
'/':'slash','?':'question','Page Up':'Prior','Page Down':'Next',
|
||||||
'Left Arrow':'Left','Right Arrow':'Right','Up Arrow':'Up',
|
'Left Arrow':'Left','Right Arrow':'Right','Up Arrow':'Up',
|
||||||
'Down Arrow': 'Down'}
|
'Down Arrow': 'Down', 'Tab':'tab'}
|
||||||
if key in translateDict.keys():
|
if key in translateDict.keys():
|
||||||
key=translateDict[key]
|
key = translateDict[key]
|
||||||
key='Key-'+key
|
if 'Shift' in modifiers and key in string.ascii_lowercase:
|
||||||
|
key = key.upper()
|
||||||
|
key = 'Key-' + key
|
||||||
return key
|
return key
|
||||||
|
|
||||||
def Ok(self, event=None):
|
def OK(self, event=None):
|
||||||
if self.KeysOk():
|
if self.KeysOK():
|
||||||
self.result=self.keyString.get()
|
self.result=self.keyString.get()
|
||||||
self.destroy()
|
self.destroy()
|
||||||
|
|
||||||
|
@ -215,40 +216,39 @@ class GetKeysDialog(Toplevel):
|
||||||
self.result=''
|
self.result=''
|
||||||
self.destroy()
|
self.destroy()
|
||||||
|
|
||||||
def KeysOk(self):
|
def KeysOK(self):
|
||||||
#simple validity check
|
"Validity check on user's keybinding selection"
|
||||||
keysOk=1
|
keys = self.keyString.get()
|
||||||
keys=self.keyString.get()
|
|
||||||
keys.strip()
|
keys.strip()
|
||||||
finalKey=self.listKeysFinal.get(ANCHOR)
|
finalKey = self.listKeysFinal.get(ANCHOR)
|
||||||
modifiers=self.GetModifiers()
|
modifiers = self.GetModifiers()
|
||||||
keySequence=keys.split()#make into a key sequence list for overlap check
|
# create a key sequence list for overlap check:
|
||||||
if not keys: #no keys specified
|
keySequence = keys.split()
|
||||||
tkMessageBox.showerror(title='Key Sequence Error',
|
keysOK = False
|
||||||
|
title = 'Key Sequence Error'
|
||||||
|
if not keys:
|
||||||
|
tkMessageBox.showerror(title=title, parent=self,
|
||||||
message='No keys specified.')
|
message='No keys specified.')
|
||||||
keysOk=0
|
elif not keys.endswith('>'):
|
||||||
elif not keys.endswith('>'): #no final key specified
|
tkMessageBox.showerror(title=title, parent=self,
|
||||||
tkMessageBox.showerror(title='Key Sequence Error',
|
message='Missing the final Key')
|
||||||
message='No final key specified.')
|
elif not modifiers and finalKey not in self.functionKeys:
|
||||||
keysOk=0
|
tkMessageBox.showerror(title=title, parent=self,
|
||||||
elif (not modifiers) and (finalKey in
|
|
||||||
self.alphanumKeys+self.punctuationKeys):
|
|
||||||
#modifier required
|
|
||||||
tkMessageBox.showerror(title='Key Sequence Error',
|
|
||||||
message='No modifier key(s) specified.')
|
message='No modifier key(s) specified.')
|
||||||
keysOk=0
|
elif (modifiers == ['Shift']) \
|
||||||
elif (modifiers==['Shift']) and (finalKey not
|
and (finalKey not in
|
||||||
in self.functionKeys+('Tab',)):
|
self.functionKeys + ('Tab', 'Space')):
|
||||||
#shift alone is only a useful modifier with a function key
|
msg = 'The shift modifier by itself may not be used with' \
|
||||||
tkMessageBox.showerror(title='Key Sequence Error',
|
' this key symbol; only with F1-F12, Tab, or Space'
|
||||||
message='Shift alone is not a useful modifier '+
|
tkMessageBox.showerror(title=title, parent=self,
|
||||||
'when used with this final key key.')
|
message=msg)
|
||||||
keysOk=0
|
elif keySequence in self.currentKeySequences:
|
||||||
elif keySequence in self.currentKeySequences: #keys combo already in use
|
msg = 'This key combination is already in use.'
|
||||||
tkMessageBox.showerror(title='Key Sequence Error',
|
tkMessageBox.showerror(title=title, parent=self,
|
||||||
message='This key combination is already in use.')
|
message=msg)
|
||||||
keysOk=0
|
else:
|
||||||
return keysOk
|
keysOK = True
|
||||||
|
return keysOK
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
#test the dialog
|
#test the dialog
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue