diff -urN sketch.orig/ChangeLog sketch/ChangeLog
--- sketch.orig/ChangeLog	2005-10-06 11:57:29.000000000 +0300
+++ sketch/ChangeLog	2005-10-06 11:57:29.000000000 +0300
@@ -1,3 +1,58 @@
+2005-10-06
+
+	New mechanism for keypress handling.
+	Key presses are dispatched to the app context.
+	The app context tries to retrieve a command for a given key by looking
+	at the keymap of the active ToolInstance. If it doesn't find one it
+	looks in its own keymap. If a command is found it is executed.
+
+	* Sketch/UI/canvas.py (SketchCanvas): Move some parts of kepyress
+	handling to other components.
+	(SketchCanvas.translate_event): New. Extract the useful values from a
+	gtk keypress event.
+	(SketchCanvas.keypress): Move execution of command to context.
+	(SketchCanvas.lookup_key): Removed. Keys are looked up by
+	the app context now.
+	(SketchCanvas.is_normal_char): Removed. Now this is handled by
+	TextToolInstance.
+
+	* Sketch/UI/skapp.py (keymap, text_keymap, align_keymap): Removed.
+
+	* Sketch/UI/__init__.py: New. Make available the gtk.keysyms as a
+	dictionary without importing gtk and thus whitout opening a display.
+	This makes it possible to run headless tests.
+
+	* Sketch/Editor/__init__.py (standard_keystrokes, align_keystrokes,
+	text_keystrokes): Removed. They are now in Sketch/Editor/keystrokes.py
+
+	* Sketch/Editor/keystrokes.py: New. The default keystrokes.
+	Also added a separated list with the keystrokes of the EditTool.
+
+	* Sketch/Editor/context.py (Context.keymap): New class attribute:
+	keymap. This is the default keymap, holding the commands that don't
+	depend on a tool (e.g. loading a file).
+	(Context.ExecuteKey): New. Executes the command corresponding to the
+	pressed key.
+
+	* Sketch/Editor/registry.py (Keymap): Default value for the
+	special_keys argument is now the Sketch.UI.keysyms dictionary.
+
+	* Sketch/Editor/tools.py (ToolInstance.keymap): New class attribute.
+	(ToolInstance.LookupKey): New. Return the command corresponding to a
+	key.
+
+	* Sketch/Editor/textool.pt (TextToolInstance.keymap): New. The default
+	text keymap.
+	(TextToolInstance.LookupKey): New. Override ToolInstance.LookupKey
+	because the text tool actually has a use for the event string
+	argument.
+
+	* Sketch/Editor/edittool.py (EditToolInstance.keymap): New. The
+	default edit tool keymap.
+
+	* Sketch/Editor/aligntool.py (AlignToolInstance.keymap): New. The
+	default align tool keymap.
+
 2005-10-03  Bernhard Herzog  <bh@intevation.de>
 
 	* Sketch/UI/fillpanel.py (GradientPatternFrame.__init__): Replace
diff -urN sketch.orig/Sketch/Editor/aligntool.py sketch/Sketch/Editor/aligntool.py
--- sketch.orig/Sketch/Editor/aligntool.py	2005-10-06 11:57:29.000000000 +0300
+++ sketch/Sketch/Editor/aligntool.py	2005-10-06 11:57:29.000000000 +0300
@@ -26,6 +26,8 @@
 from tools import ToolInstance, ToolInfo
 from handle import Handle
 from builtins import align_selected
+from registry import Keymap
+from keystrokes import align_keystrokes
 
 class AlignRectangle(SelectionRectangle):
 
@@ -74,6 +76,7 @@
     """
 
     title = ''"Align"
+    keymap = Keymap(align_keystrokes)
 
     def __init__(self, editor):
         ToolInstance.__init__(self, editor)
diff -urN sketch.orig/Sketch/Editor/context.py sketch/Sketch/Editor/context.py
--- sketch.orig/Sketch/Editor/context.py	2005-10-06 11:57:29.000000000 +0300
+++ sketch/Sketch/Editor/context.py	2005-10-06 11:57:29.000000000 +0300
@@ -23,10 +23,15 @@
      LAYER, LAYER_ORDER, LAYER_ACTIVE, STATE, STYLE, OBJECT_CHANGED, \
      TRANSACTION_START, TRANSACTION_END, HANDLES
 
+from registry import Keymap
+from command import Command
+from keystrokes import standard_keystrokes
+
 main_tools = ('SelectionTool', 'EditTool')
 
 class Context(Sketch.Base.Publisher):
 
+    keymap = Keymap(standard_keystrokes)
     editor_channels = (SELECTION, STATE, HANDLES)
     document_channels = (UNDO, STYLE, LAYER, LAYER_ORDER, LAYER_ACTIVE,
                          OBJECT_CHANGED, TRANSACTION_START, TRANSACTION_END)
@@ -94,6 +99,27 @@
     def MainTool(self):
         return self.main_tool
 
+    def ExecuteKey(self, keyval, state, evstr):
+        """Find and execute the command corresponding to keyval.
+
+        The command is searched in the keymap of the active tool (if there
+        is one) then in self's keymap.
+        """
+        command_name = None
+        # First check if we have a tool that can handle the keypress
+        if self.HasEditor() and self.editor.tool is not None:
+            command_name = self.editor.tool.LookupKey(keyval, state, evstr)
+        if command_name is None:
+            command_name = self.keymap.Command((keyval, state))
+
+        command = Sketch.Editor.Registry.Command(command_name)
+        if command is not None:
+            if command.Sensitive(self):
+                if command.PassKey():
+                    command.Execute(self, evstr)
+                else:
+                    command.Execute(self)
+
 
 def switch_tool(context):
     if context.tool in main_tools:
diff -urN sketch.orig/Sketch/Editor/edittool.py sketch/Sketch/Editor/edittool.py
--- sketch.orig/Sketch/Editor/edittool.py	2005-10-06 11:57:29.000000000 +0300
+++ sketch/Sketch/Editor/edittool.py	2005-10-06 11:57:29.000000000 +0300
@@ -27,6 +27,8 @@
 import const
 import tools
 from selectiontool import SelectionRectangle
+from registry import Keymap
+from keystrokes import edit_keystrokes
 
 class MultiEditor:
 
@@ -144,6 +146,7 @@
 class EditToolInstance(tools.ToolInstance):
 
     title = ''"Edit"
+    keymap = Keymap(edit_keystrokes)
 
     def __init__(self, editor):
         tools.ToolInstance.__init__(self, editor)
diff -urN sketch.orig/Sketch/Editor/__init__.py sketch/Sketch/Editor/__init__.py
--- sketch.orig/Sketch/Editor/__init__.py	2005-10-06 11:57:29.000000000 +0300
+++ sketch/Sketch/Editor/__init__.py	2005-10-06 11:57:29.000000000 +0300
@@ -23,7 +23,7 @@
 from registry import ScriptRegistry, Menu, BuildMenuTree, Keymap
 from command import Command, SafeScript, AdvancedScript, BuiltinCommand, \
      BuiltinEditorCommand
-
+from keystrokes import *
 Registry = ScriptRegistry()
 
 #AddFunction = Registry.AddFunction
@@ -217,79 +217,6 @@
     ]
 
 
-standard_keystrokes = [
-    ('file_open', 'C-o'),
-    ('file_save', 'C-s'),
-    ('exit', 'C-q'),
-    ('close_window', 'C-w'),
-
-    ('delete', 'Delete'),
-    ('undo', 'C-z'),
-    ('redo', 'C-r'),
-    ('duplicate', 'C-d'),
-
-    ('group', 'C-g'),
-    ('ungroup', 'C-u'),
-
-    ('selection_tool', 's'),
-    ('edit_tool', 'e'),
-    ('align_tool', 'a'),
-    ('rectangle_tool', 'r'),
-    ('ellipse_tool', 'c'),      # c = circle
-    ('curve_tool', 'b'),        # b = bezier
-    ('line_tool', 'l'),
-    ('freehand_tool', 'f'),
-    ('zoom_tool', 'z'),
-    ('text_tool', 't'),
-
-    ('switch_tool', 'space'),
-
-    ('zoom_100', '1'),
-    ('zoom_in', '>'),
-    ('zoom_out', '<'),
-
-    ('view_fit_window', 'S-F4'),
-    ('view_fit_selection_to_window', 'C-F4'),
-    ('view_fit_page_to_window', 'F4'),
-
-    #('cont_angle', 'a'),
-    ('cont_smooth', 's'),
-    ('cont_symmetrical', 'y'),
-    ('segments_to_lines', 'l'),
-    ('segments_to_curve', 'b'),
-    ]
-
-
-text_keystrokes = [
-    ('move_char_forward', 'Right'),
-    ('move_char_forward', 'C-f'),
-    ('move_char_backward', 'Left'),
-    ('move_char_backward', 'C-b'),
-    ('move_to_beginning_of_line', 'C-a'),
-    ('move_to_beginning_of_line', 'Home'),
-    ('move_to_end_of_line', 'C-e'),
-    ('move_to_end_of_line', 'End'),
-
-    ('delete_char_forward', 'Delete'),
-    ('delete_char_forward', 'C-d'),
-    ('delete_char_backward', 'BackSpace'),
-    ]
-
-align_keystrokes = [
-    ('align_left', 'l'),
-    ('align_top', 't'),
-    ('align_right', 'r'),
-    ('align_bottom', 'b'),
-    ('align_center_x', 'v'),
-    ('align_center_y', 'h'),
-    ('align_center', 'c'),
-    ('set_align_reference_page', 'p'),
-    ('set_align_reference_last', 'z'),
-    ('set_align_reference_selection', 's'),
-    ]
-
-# text command not listed: insert_char
-
 toolmap = {'SelectionTool': selectiontool.SelectionTool,
            'EditTool': edittool.EditTool,
            'AlignTool': aligntool.AlignTool,
diff -urN sketch.orig/Sketch/Editor/keystrokes.py sketch/Sketch/Editor/keystrokes.py
--- sketch.orig/Sketch/Editor/keystrokes.py	1970-01-01 02:00:00.000000000 +0200
+++ sketch/Sketch/Editor/keystrokes.py	2005-10-06 11:57:29.000000000 +0300
@@ -0,0 +1,92 @@
+# Sketch - A Python-based interactive drawing program
+# Copyright (C) 2005 by Bernhard Herzog
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the GNU
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307	USA
+
+
+standard_keystrokes = [
+    ('file_open', 'C-o'),
+    ('file_save', 'C-s'),
+    ('exit', 'C-q'),
+    ('close_window', 'C-w'),
+
+    ('delete', 'Delete'),
+    ('undo', 'C-z'),
+    ('redo', 'C-r'),
+    ('duplicate', 'C-d'),
+
+    ('group', 'C-g'),
+    ('ungroup', 'C-u'),
+
+    ('selection_tool', 's'),
+    ('edit_tool', 'e'),
+    ('align_tool', 'a'),
+    ('rectangle_tool', 'r'),
+    ('ellipse_tool', 'c'),      # c = circle
+    ('curve_tool', 'b'),        # b = bezier
+    ('line_tool', 'l'),
+    ('freehand_tool', 'f'),
+    ('zoom_tool', 'z'),
+    ('text_tool', 't'),
+
+    ('switch_tool', 'space'),
+
+    ('zoom_100', '1'),
+    ('zoom_in', '>'),
+    ('zoom_out', '<'),
+
+    ('view_fit_window', 'S-F4'),
+    ('view_fit_selection_to_window', 'C-F4'),
+    ('view_fit_page_to_window', 'F4'),
+    ]
+
+
+text_keystrokes = [
+    ('move_char_forward', 'Right'),
+    ('move_char_forward', 'C-f'),
+    ('move_char_backward', 'Left'),
+    ('move_char_backward', 'C-b'),
+    ('move_to_beginning_of_line', 'C-a'),
+    ('move_to_beginning_of_line', 'Home'),
+    ('move_to_end_of_line', 'C-e'),
+    ('move_to_end_of_line', 'End'),
+
+    ('delete_char_forward', 'Delete'),
+    ('delete_char_forward', 'C-d'),
+    ('delete_char_backward', 'BackSpace'),
+    ]
+# text command not listed: insert_char
+
+align_keystrokes = [
+    ('align_left', 'l'),
+    ('align_top', 't'),
+    ('align_right', 'r'),
+    ('align_bottom', 'b'),
+    ('align_center_x', 'v'),
+    ('align_center_y', 'h'),
+    ('align_center', 'c'),
+    ('set_align_reference_page', 'p'),
+    ('set_align_reference_last', 'z'),
+    ('set_align_reference_selection', 's'),
+    ]
+
+edit_keystrokes = [
+    ('select_all_nodes', 'C-a'),
+    ('cont_angle', 'a'),
+    ('cont_smooth', 's'),
+    ('cont_symmetrical', 'y'),
+    ('segments_to_lines', 'l'),
+    ('segments_to_curve', 'b'),
+    ]
diff -urN sketch.orig/Sketch/Editor/registry.py sketch/Sketch/Editor/registry.py
--- sketch.orig/Sketch/Editor/registry.py	2005-10-06 11:57:29.000000000 +0300
+++ sketch/Sketch/Editor/registry.py	2005-10-06 11:57:29.000000000 +0300
@@ -24,7 +24,7 @@
 from Sketch.Base.warn import warn, USER
 from Sketch.Base import Publisher
 from Sketch.Base.const import CHANGED
-
+from Sketch.UI import keysyms
 from command import SafeScript
 import const
 
@@ -108,7 +108,7 @@
     
 class Keymap:
 
-    def __init__(self, map = None, special_keys = None):
+    def __init__(self, map = None, special_keys = keysyms):
         self.map = {}
         self.inverse = {}
         if special_keys is None:
diff -urN sketch.orig/Sketch/Editor/texttool.py sketch/Sketch/Editor/texttool.py
--- sketch.orig/Sketch/Editor/texttool.py	2005-10-06 11:57:29.000000000 +0300
+++ sketch/Sketch/Editor/texttool.py	2005-10-06 11:57:29.000000000 +0300
@@ -28,6 +28,8 @@
 from Sketch.Editor import Creator, Editor, AddEditorBuiltin
 
 import handle, tools
+from registry import Keymap
+from keystrokes import text_keystrokes
 
 
 class SimpleTextCreator(Creator):
@@ -334,6 +336,7 @@
 class TextToolInstance(tools.ToolInstance):
 
     title = ''"Text"
+    keymap = Keymap(text_keystrokes)
 
     def __init__(self, editor):
         tools.ToolInstance.__init__(self, editor)
@@ -421,6 +424,15 @@
         else:
             self.editor.update_handles()
 
+    def LookupKey(self, keyval, state, evstr):
+        cmd = tools.ToolInstance.LookupKey(self, keyval, state, evstr)
+        if cmd is not None:
+            return cmd
+        if len(evstr) == 1 and state & ~Sketch.Editor.ShiftMask == 0:
+            return 'insert_char'
+        else:
+            return None
+
     def CallObjectEditorMethod(self, aclass, methodname, args = ()):
         if type(args) != TupleType:
             args = (args,)
diff -urN sketch.orig/Sketch/Editor/tools.py sketch/Sketch/Editor/tools.py
--- sketch.orig/Sketch/Editor/tools.py	2005-10-06 11:57:29.000000000 +0300
+++ sketch/Sketch/Editor/tools.py	2005-10-06 11:57:29.000000000 +0300
@@ -24,6 +24,7 @@
 import const
 from selrect import SelectionRectangle
 
+from registry import Keymap
 
 #
 # Tools
@@ -46,6 +47,8 @@
 
 class ToolInstance:
 
+    keymap = Keymap()
+
     def __init__(self, editor):
         self.editor = editor
         self.document = editor.Document()
@@ -118,6 +121,10 @@
     def ButtonClick(self, context, p, snapped, button, state, handle = None):
         self.canvas = context
 
+    def LookupKey(self, keyval, state, evstr):
+        """Return the command corresponding to key."""
+        return self.keymap.Command((keyval, state))
+
     def Cancel(self, context):
         self.stop_edit(context)
         #if self.current is not None:
diff -urN sketch.orig/Sketch/UI/canvas.py sketch/Sketch/UI/canvas.py
--- sketch.orig/Sketch/UI/canvas.py	2005-10-06 11:57:30.000000000 +0300
+++ sketch/Sketch/UI/canvas.py	2005-10-06 11:57:29.000000000 +0300
@@ -112,6 +112,19 @@
     # ported to a different toolkit.
     return state
 
+def translate_event(event):
+    # extract the useful values from a gtk keypress event.
+    state = translate_state(event.state)
+    state = state & Sketch.Editor.AllowedModifierMask
+    if len(event.string) == 1 and state & Sketch.Editor.ShiftMask:
+        keyval = ord(event.string)
+        state = state & ~Sketch.Editor.ShiftMask
+    else:
+        keyval = event.keyval
+    if 0x041 <= keyval <= 0x05a:
+        keyval = keyval + 32
+    return keyval, state, event.string
+
 class SketchCanvas(SketchView):
 
     def __init__(self, application, main_window, document, editor, **kw):
@@ -278,28 +291,7 @@
         elif event.keyval == gtk.keysyms.Escape:
             self.cancel()
         else:
-            #print event.keyval, event.state
-            state = translate_state(event.state)
-            state = state & Sketch.Editor.AllowedModifierMask
-            if len(event.string) == 1 and state & Sketch.Editor.ShiftMask:
-                keyval = ord(event.string)
-                state = state & ~Sketch.Editor.ShiftMask
-            else:
-                keyval = event.keyval
-            if 0x041 <= keyval <= 0x05a:
-                keyval = keyval + 32
-            #print keyval, event.string, state
-            command = self.lookup_key(keyval, state, event.string)
-            #print command
-            if command is not None:
-                command = Sketch.Editor.Registry.Command(command)
-                if command is not None:
-                    context = self.application.context
-                    if command.Sensitive(context):
-                        if command.PassKey():
-                            command.Execute(context, event.string)
-                        else:
-                            command.Execute(context)
+            self.application.context.ExecuteKey(*translate_event(event))
         return 1
 
     def key_release(self, widget, event):
@@ -308,28 +300,6 @@
             self.fake_motion_event(event)
         return 1
 
-    def lookup_key(self, keyval, state, str):
-        tool = self.application.context.tool
-        # XXX implement a better mechanism for context dependent keymaps
-        if tool == 'TextTool':
-            #obj = self.editor.SelectedObjects()
-            #if obj:
-            #    obj = obj[0]
-            #    if obj.is_Text:
-            command = skapp.text_keymap.Command((keyval, state))
-            if command is not None:
-                return command
-            if self.is_normal_char(keyval, state, str):
-                return 'insert_char'
-        elif tool == 'AlignTool':
-            command = skapp.align_keymap.Command((keyval, state))
-            if command is not None:
-                return command
-        return skapp.keymap.Command((keyval, state))
-
-    def is_normal_char(self, keyval, state, str):
-        return len(str) == 1 and state & ~Sketch.Editor.ShiftMask == 0
-
     #
 
     def cancel(self):
diff -urN sketch.orig/Sketch/UI/__init__.py sketch/Sketch/UI/__init__.py
--- sketch.orig/Sketch/UI/__init__.py	2005-10-06 11:57:30.000000000 +0300
+++ sketch/Sketch/UI/__init__.py	2005-10-06 11:57:29.000000000 +0300
@@ -16,9 +16,22 @@
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307	USA
 
 import sys
+from imp import find_module
 
 import Sketch
 
+# Make available the gtk.keysyms as a dictionary without importing gtk and
+# thus whitout opening a display.  This makes it possible to run headless
+# tests.
+gtkpath = find_module('gtk')[1]
+# make it the first item in sys.path
+sys.path.insert(0, gtkpath)
+import keysyms as gsym
+keysyms = dict([(a,b) for (a,b) in gsym.__dict__.iteritems() if '__' not in a])
+sys.path.remove(gtkpath)
+del gtkpath, gsym
+
+
 
 class UIPreferences(Sketch.Base.Preferences):
 
diff -urN sketch.orig/test/ChangeLog sketch/test/ChangeLog
--- sketch.orig/test/ChangeLog	2005-10-06 11:57:30.000000000 +0300
+++ sketch/test/ChangeLog	2005-10-06 11:57:29.000000000 +0300
@@ -1,3 +1,7 @@
+2005-10-06
+
+	* test_shortcuts.py: New. Tests for the new shortcut mechanism.
+
 2005-09-25  Bernhard Herzog  <bh@intevation.de>
 
 	Patch by Valentin Ungureanu (savannah patch #4396):
diff -urN sketch.orig/test/test_shortcuts.py sketch/test/test_shortcuts.py
--- sketch.orig/test/test_shortcuts.py	1970-01-01 02:00:00.000000000 +0200
+++ sketch/test/test_shortcuts.py	2005-10-06 11:57:29.000000000 +0300
@@ -0,0 +1,106 @@
+# Skencil - A Python-based interactive drawing program
+# Copyright (C) 2005 by Bernhard Herzog
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""
+Tests for keyboard shortcuts.
+
+The tests verifiy that the app context activates the proper command,
+taking into account the active tool.
+
+"""
+
+import unittest
+
+import support
+support.add_sketch_dir_to_path()
+
+import Sketch
+from Sketch import Rectangle, Trafo
+from Sketch.Editor import EditorWithSelection, InteractiveDocument, Context, \
+     ShiftMask, ControlMask, Registry
+from Sketch.Editor import Add, AdvancedScript, toolmap
+from Sketch.Editor.tools import ToolInstance, ToolInfo
+from Sketch.Editor.registry import Keymap
+
+class SimpleToolInstance(ToolInstance):
+
+    keymap = Keymap([('insert_tool_rect', 'C-S-a')])
+
+
+class TestShortcuts(unittest.TestCase):
+
+    """Test shortcut overriding.
+
+       The test is done by creating a context and a tool that bind
+       different commands to the same shortcut. The result of context
+       "executing" the shortcut should depend on whether the tool is
+       active or not.
+
+       Each command inserts a rectangle, so verifying if the proper
+       command was executed is done by looking at what rectangle was
+       inserted.
+    """
+
+    def setUp(self):
+        document = InteractiveDocument(create_layer = 1)
+        self.layer = document.AppendLayer("test")
+        document.SetActiveLayer(document.LayerIndex(self.layer))
+        self.editor = EditorWithSelection(document)
+        # Set up a context with no application
+        self.context = Context(None)
+        self.context.set_editor(self.editor)
+
+        # Create two commands that insert a rectangle
+        self.tool_rect = Rectangle(Trafo(100, 0, 0, 100, 10, 10))
+        self.app_rect = Rectangle(Trafo(50, 0, 0, 50, 50, 50))
+
+        Add(AdvancedScript("insert_app_rect", "Insert app rectangle",
+                           lambda ctx: ctx.editor.Insert(self.app_rect)))
+        self.context.keymap.AddItem('insert_app_rect',
+                                    (ord('a'), ControlMask | ShiftMask))
+
+        Add(AdvancedScript("insert_tool_rect", "Insert tool rectangle",
+                           lambda ctx: ctx.editor.Insert(self.tool_rect)))
+
+        # Create a simple tool
+        SimpleTool = ToolInfo("SimpleTool", SimpleToolInstance)
+        # Make the tool available to the editor
+        toolmap["SimpleTool"] = SimpleTool
+
+    def tearDown(self):
+        if self.editor is not None:
+            self.editor.Destroy()
+        self.editor = self.layer = self.context = None
+
+    def test_app_shortcut(self):
+        """Test that a global shortcut activates the proper command"""
+        self.editor.SetTool("SelectionTool")
+        # Simulate pressing Ctrl+Shift+A
+        self.context.ExecuteKey(ord('a'), ShiftMask | ControlMask, 'a')
+        # Check if the app_rect was inserted
+        self.assertEquals(self.layer.GetObjects(), [self.app_rect])
+
+    def test_tool_shortcut(self):
+        """Test that a tool shortcut overrides the global one"""
+        self.editor.SetTool("SimpleTool")
+        self.context.ExecuteKey(ord('a'), ShiftMask | ControlMask, 'a')
+        # Check if the tool_rect was inserted
+        self.assertEquals(self.layer.GetObjects(), [self.tool_rect])
+
+if __name__ == "__main__":
+    unittest.main()
+
