Index: src/org/openstreetmap/josm/actions/PreferencesAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/PreferencesAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/PreferencesAction.java	(working copy)
@@ -14,6 +14,7 @@
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.gui.preferences.PreferenceDialog;
 import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.ShortCut;
 
 /**
  * Open the Preferences dialog.
@@ -26,7 +27,8 @@
 	 * Create the preference action with "&Preferences" as label.
 	 */
 	public PreferencesAction() {
-		super(tr("Preferences ..."), "preference", tr("Open a preferences page for global settings."), KeyEvent.VK_F12, 0, true);
+		super(tr("Preferences ..."), "preference", tr("Open a preferences page for global settings."),
+		ShortCut.registerShortCut("system:preferences", tr("Preferences"), KeyEvent.VK_F12, ShortCut.GROUP_DIRECT), true);
 	}
 
 	/**
Index: src/org/openstreetmap/josm/actions/OpenAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/OpenAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/OpenAction.java	(working copy)
@@ -24,6 +24,7 @@
 import org.openstreetmap.josm.io.NmeaReader;
 import org.openstreetmap.josm.io.OsmReader;
 import org.xml.sax.SAXException;
+import org.openstreetmap.josm.tools.ShortCut;
 
 /**
  * Open a file chooser dialog and select an file to import. Then call the gpx-import
@@ -37,7 +38,8 @@
 	 * Create an open action. The name is "Open a file".
 	 */
 	public OpenAction() {
-		super(tr("Open ..."), "open", tr("Open a file."), KeyEvent.VK_O, InputEvent.CTRL_DOWN_MASK);
+		super(tr("Open ..."), "open", tr("Open a file."),
+		ShortCut.registerShortCut("system:open", tr("File: Open..."), KeyEvent.VK_O, ShortCut.GROUP_MENU));
 	}
 
 	public void actionPerformed(ActionEvent e) {
Index: src/org/openstreetmap/josm/actions/AlignInCircleAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/AlignInCircleAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/AlignInCircleAction.java	(working copy)
@@ -19,6 +19,7 @@
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.tools.ShortCut;
 
 /**
  * Aligns all selected nodes within a circle. (Useful for roundabouts)
@@ -28,7 +29,8 @@
 public final class AlignInCircleAction extends JosmAction {
 
 	public AlignInCircleAction() {
-		super(tr("Align Nodes in Circle"), "aligncircle", tr("Move the selected nodes into a circle."), KeyEvent.VK_O, 0, true);
+		super(tr("Align Nodes in Circle"), "aligncircle", tr("Move the selected nodes into a circle."),
+		ShortCut.registerShortCut("tools:aligncircle", tr("Tool: Align in circle"), KeyEvent.VK_O, ShortCut.GROUP_EDIT), true);
 	}
 
 	public void actionPerformed(ActionEvent e) {
Index: src/org/openstreetmap/josm/actions/MoveAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/MoveAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/MoveAction.java	(working copy)
@@ -16,6 +16,7 @@
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.visitor.AllNodesVisitor;
+import org.openstreetmap.josm.tools.ShortCut;
 
 /**
  * Moves the selection
@@ -27,12 +28,34 @@
 	public enum Direction { UP, LEFT, RIGHT, DOWN }
 	private Direction myDirection;
 	
+	// any better idea?
+	private static Object calltosupermustbefirststatementinconstructor(Direction dir, boolean text) {
+		ShortCut sc;
+		String directiontext;
+		if        (dir == Direction.UP)   {
+			directiontext = tr("up");
+			sc = ShortCut.registerShortCut("core:moveup",    tr("Move objects {0}", directiontext), KeyEvent.VK_UP,    ShortCut.GROUPS_ALT1+ShortCut.GROUP_DIRECT);
+		} else if (dir == Direction.DOWN)  {
+			directiontext = tr("down");
+			sc = ShortCut.registerShortCut("core:movedown",  tr("Move objects {0}", directiontext), KeyEvent.VK_DOWN,  ShortCut.GROUPS_ALT1+ShortCut.GROUP_DIRECT);
+		} else if (dir == Direction.LEFT)  {
+			directiontext = tr("left");
+			sc = ShortCut.registerShortCut("core:moveleft",  tr("Move objects {0}", directiontext), KeyEvent.VK_LEFT,  ShortCut.GROUPS_ALT1+ShortCut.GROUP_DIRECT);
+		} else { //dir == Direction.RIGHT) {
+			directiontext = tr("right");
+			sc = ShortCut.registerShortCut("core:moveright", tr("Move objects {0}", directiontext), KeyEvent.VK_RIGHT, ShortCut.GROUPS_ALT1+ShortCut.GROUP_DIRECT);
+		}
+		if (text) {
+			return directiontext;
+		} else {
+			return sc;
+		}
+	}
+
 	public MoveAction(Direction dir) {
-		super(tr("Move"), null, tr("Moves Objects"), 
-		(dir == Direction.UP) ? KeyEvent.VK_UP : 
-		(dir == Direction.DOWN) ? KeyEvent.VK_DOWN :
-		(dir == Direction.LEFT) ? KeyEvent.VK_LEFT :
-		KeyEvent.VK_RIGHT, 0, true);
+		super(tr("Move {0}", calltosupermustbefirststatementinconstructor(dir, true)), null,
+		      tr("Moves Objects {0}", calltosupermustbefirststatementinconstructor(dir, true)),
+		      (ShortCut)calltosupermustbefirststatementinconstructor(dir, false), true);
 		myDirection = dir;
 	}
 
Index: src/org/openstreetmap/josm/actions/JosmAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/JosmAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/JosmAction.java	(working copy)
@@ -1,6 +1,7 @@
 // License: GPL. Copyright 2007 by Immanuel Scholz and others
 package org.openstreetmap.josm.actions;
 
+import java.awt.event.InputEvent;
 
 import javax.swing.AbstractAction;
 import javax.swing.JComponent;
@@ -10,7 +11,7 @@
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.tools.Destroyable;
 import org.openstreetmap.josm.tools.ImageProvider;
-import org.openstreetmap.josm.tools.ShortCutLabel;
+import org.openstreetmap.josm.tools.ShortCut;
 
 /**
  * Base class helper for all Actions in JOSM. Just to make the life easier.
@@ -23,27 +24,75 @@
  */
 abstract public class JosmAction extends AbstractAction implements Destroyable {
 
+	@Deprecated
 	public KeyStroke shortCut;
+	protected ShortCut sc;
 
+	public ShortCut getShortCut() {
+		if (sc == null) {
+			sc = ShortCut.registerShortCut("core:none", "No Shortcut", 0, ShortCut.GROUP_NONE);
+			sc.setAutomatic(); // as this shortcut is shared by all action that don't want to have a shortcut,
+			                   // we shouldn't allow the user to change it...
+		}
+		return sc;
+	}
+
+	@Deprecated
 	public JosmAction(String name, String iconName, String tooltip, int shortCut, int modifier, boolean register) {
 		super(name, iconName == null ? null : ImageProvider.get(iconName));
 		setHelpId();
-		String scl = ShortCutLabel.name(shortCut, modifier);
-		putValue(SHORT_DESCRIPTION, "<html>"+tooltip+" <font size='-2'>"+scl+"</font>"+(scl.equals("")?"":"&nbsp;")+"</html>");
 		if (shortCut != 0) {
-			this.shortCut = KeyStroke.getKeyStroke(shortCut, modifier);
-			Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(this.shortCut, name);
+			int group = ShortCut.GROUP_LAYER; //GROUP_NONE;
+			if (((modifier & InputEvent.CTRL_MASK) != 0) || ((modifier & InputEvent.CTRL_DOWN_MASK) != 0)) {
+				group = ShortCut.GROUP_MENU;
+			} else if (modifier == 0) {
+				group = ShortCut.GROUP_EDIT;
+			}
+			sc = ShortCut.registerShortCut("auto:"+name, name, shortCut, group);
+			this.shortCut = sc.getKeyStroke();
+			Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(sc.getKeyStroke(), name);
 			Main.contentPane.getActionMap().put(name, this);
 		}
+		putValue(SHORT_DESCRIPTION, Main.platform.makeTooltip(tooltip, sc));
         putValue("toolbar", iconName);
         if (register)
         	Main.toolbar.register(this);
 	}
 
+	/**
+	 * The new super for all actions.
+	 *
+	 * Use this super constructor to setup your action. It takes 5 parameters:
+	 *
+	 * name - the action's text as displayed on the menu (if it is added to a menu)
+	 * iconName - the filename of the icon to use
+	 * tooltip - a longer description of the action that will be displayed in the tooltip. Please note
+	 *           that html is not supported for menu action on some platforms
+	 * shortCut - a ready-created shortcut object or null if you don't want a shortcut. But you always
+	 *            do want a shortcut, remember you can alway register it with group=none, so you
+	 *            won't be assigned a shurtcut unless the user configures one. If you pass null here,
+	 *            the user CANNOT configure a shortcut for your action.
+	 * register - register this action for the toolbar preferences?
+	 */
+	public JosmAction(String name, String iconName, String tooltip, ShortCut shortCut, boolean register) {
+		super(name, iconName == null ? null : ImageProvider.get(iconName));
+		setHelpId();
+		sc = shortCut;
+		if (sc != null) {
+			this.shortCut = sc.getKeyStroke();
+			Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(sc.getKeyStroke(), name);
+			Main.contentPane.getActionMap().put(name, this);
+		}
+		putValue(SHORT_DESCRIPTION, Main.platform.makeTooltip(tooltip, sc));
+		putValue("toolbar", iconName);
+    if (register)
+    	Main.toolbar.register(this);
+	}
+
 	public void destroy() {
 		if (shortCut != null) {
-			Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).remove(shortCut);
-			Main.contentPane.getActionMap().remove(shortCut);
+			Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).remove(sc.getKeyStroke());
+			Main.contentPane.getActionMap().remove(sc.getKeyStroke());
 		}
 	}
 	
Index: src/org/openstreetmap/josm/actions/SelectAllAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/SelectAllAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/SelectAllAction.java	(working copy)
@@ -7,11 +7,13 @@
 import java.awt.event.KeyEvent;
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.tools.ShortCut;
 
 public class SelectAllAction extends JosmAction {
 
 	public SelectAllAction() {
-		super(tr("Select All"),"selectall", tr("Select all undeleted objects in the data layer. This selects incomplete objects too."), KeyEvent.VK_A, KeyEvent.CTRL_DOWN_MASK, true);
+		super(tr("Select All"),"selectall", tr("Select all undeleted objects in the data layer. This selects incomplete objects too."),
+		ShortCut.registerShortCut("system:selectall", tr("Edit: Select all"), KeyEvent.VK_A, ShortCut.GROUP_MENU), true);
     }
 
 	public void actionPerformed(ActionEvent e) {
Index: src/org/openstreetmap/josm/actions/ExitAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/ExitAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/ExitAction.java	(working copy)
@@ -7,6 +7,7 @@
 import java.awt.event.KeyEvent;
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.tools.ShortCut;
 
 /**
  * Exit the application. May ask for permission first (if something has changed).
@@ -18,7 +19,8 @@
 	 * Construct the action with "Exit" as label
 	 */
 	public ExitAction() {
-		super(tr("Exit"), "exit", tr("Exit the application."), KeyEvent.VK_Q, KeyEvent.CTRL_DOWN_MASK, true);
+		super(tr("Exit"), "exit", tr("Exit the application."),
+		ShortCut.registerShortCut("system:menuexit", tr("Quit JOSM"), KeyEvent.VK_Q, ShortCut.GROUP_MENU), true);
 	}
 
 	public void actionPerformed(ActionEvent e) {
Index: src/org/openstreetmap/josm/actions/CopyAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/CopyAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/CopyAction.java	(working copy)
@@ -23,6 +23,7 @@
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.data.osm.visitor.Visitor;
+import org.openstreetmap.josm.tools.ShortCut;
 
 public final class CopyAction extends JosmAction implements SelectionChangedListener {
 
@@ -31,7 +32,7 @@
 	public CopyAction() {
 		super(tr("Copy"), "copy",
 				tr("Copy selected objects to paste buffer."),
-				KeyEvent.VK_C, KeyEvent.CTRL_MASK, true);
+				ShortCut.registerShortCut("system:copy", tr("Edit: Copy"), KeyEvent.VK_C, ShortCut.GROUP_MENU), true);
 		setEnabled(false);
 		DataSet.selListeners.add(this);
 		listeners = new LinkedList<JosmAction>();
Index: src/org/openstreetmap/josm/actions/UnselectAllAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/UnselectAllAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/UnselectAllAction.java	(working copy)
@@ -9,17 +9,20 @@
 import javax.swing.JComponent;
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.tools.ShortCut;
 
 public class UnselectAllAction extends JosmAction {
 
 	public UnselectAllAction() {
 		super(tr("Unselect All"), "unselectall", tr("Unselect all objects."),
-		        KeyEvent.VK_U, 0, true);
+		ShortCut.registerShortCut("edit:unselectall", tr("Edit: Unselect all"), KeyEvent.VK_U, ShortCut.GROUP_EDIT), true);
+		// this is not really GROUP_EDIT, but users really would complain if the yhad to reconfigure because we put
+		// the correct group in
 
 		// Add extra shortcut C-S-a
 		Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
-		        KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.CTRL_DOWN_MASK
-		                | KeyEvent.SHIFT_DOWN_MASK), tr("Unselect All"));
+		ShortCut.registerShortCut("edit:unselectall2", tr("Edit: Unselect all (2)"), KeyEvent.VK_A, ShortCut.GROUP_MENU).getKeyStroke(),
+		tr("Unselect All"));
 
 		// Add extra shortcut ESCAPE
 		/*
@@ -28,7 +31,7 @@
 		 * for now this is a reasonable approximation.
 		 */
 		Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
-		        KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0),
+		ShortCut.registerShortCut("edit:unselectall3", tr("Edit: Unselect all (3)"), KeyEvent.VK_ESCAPE, ShortCut.GROUP_DIRECT).getKeyStroke(),
 		        tr("Unselect All"));
 	}
 
Index: src/org/openstreetmap/josm/actions/ZoomInAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/ZoomInAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/ZoomInAction.java	(working copy)
@@ -7,12 +7,13 @@
 import java.awt.event.KeyEvent;
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.tools.ShortCut;
 
 public final class ZoomInAction extends JosmAction {
 
 	public ZoomInAction() {
 		super(tr("Zoom in"), "dialogs/zoomin", tr("Zoom in"),
-		        KeyEvent.VK_PLUS, 0, true);
+		ShortCut.registerShortCut("view:zoomin", tr("View: Zoom in"), KeyEvent.VK_PLUS, ShortCut.GROUP_DIRECT), true);
 		setEnabled(true);
 	}
 
Index: src/org/openstreetmap/josm/actions/SplitWayAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/SplitWayAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/SplitWayAction.java	(working copy)
@@ -32,6 +32,7 @@
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.data.osm.visitor.NameVisitor;
 import org.openstreetmap.josm.data.osm.visitor.Visitor;
+import org.openstreetmap.josm.tools.ShortCut;
 
 /**
  * Splits a way into multiple ways (all identical except for their node list).
@@ -49,7 +50,8 @@
 	 * Create a new SplitWayAction.
 	 */
 	public SplitWayAction() {
-		super(tr("Split Way"), "splitway", tr("Split a way at the selected node."), KeyEvent.VK_P, 0, true);
+		super(tr("Split Way"), "splitway", tr("Split a way at the selected node."),
+		ShortCut.registerShortCut("tools:splitway", tr("Tool: Split way"), KeyEvent.VK_P, ShortCut.GROUP_EDIT), true);
 		DataSet.selListeners.add(this);
 	}
 
Index: src/org/openstreetmap/josm/actions/ZoomOutAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/ZoomOutAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/ZoomOutAction.java	(working copy)
@@ -7,12 +7,13 @@
 import java.awt.event.KeyEvent;
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.tools.ShortCut;
 
 public final class ZoomOutAction extends JosmAction {
 
 	public ZoomOutAction() {
 		super(tr("Zoom out"), "dialogs/zoomout", tr("Zoom out"),
-		        KeyEvent.VK_MINUS, 0, true);
+		ShortCut.registerShortCut("view:zoomout", tr("View: Zoom out"), KeyEvent.VK_MINUS, ShortCut.GROUP_DIRECT), true);
 		setEnabled(true);
 	}
 
Index: src/org/openstreetmap/josm/actions/SaveAsAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/SaveAsAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/SaveAsAction.java	(working copy)
@@ -8,6 +8,7 @@
 import java.io.File;
 
 import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.tools.ShortCut;
 
 /**
  * Export the data.
@@ -21,7 +22,8 @@
 	 * @param layer Save this layer.
 	 */
 	public SaveAsAction(Layer layer) {
-		super(tr("Save as ..."), "save_as", tr("Save the current data to a new file."), KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK, layer);
+		super(tr("Save as ..."), "save_as", tr("Save the current data to a new file."),
+		ShortCut.registerShortCut("system:saveas", tr("File: Save as..."), KeyEvent.VK_S, ShortCut.GROUP_MENU), layer);
 	}
 	
 	@Override protected File getFile(Layer layer) {
Index: src/org/openstreetmap/josm/actions/audio/AudioBackAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/audio/AudioBackAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/audio/AudioBackAction.java	(working copy)
@@ -10,13 +10,15 @@
 import org.openstreetmap.josm.actions.JosmAction;
 import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer;
 import org.openstreetmap.josm.tools.AudioPlayer;
+import org.openstreetmap.josm.tools.ShortCut;
 
 public class AudioBackAction extends JosmAction {
 
 	private double amount; // note, normally negative, i.e. jump backwards in time
 	
 	public AudioBackAction() {
-		super(tr("Back"), "audio-back", tr("Jump back."), KeyEvent.VK_F6, 0, true);
+		super(tr("Back"), "audio-back", tr("Jump back."),
+		ShortCut.registerShortCut("audio:back", tr("Audio: Back"), KeyEvent.VK_F6, ShortCut.GROUP_DIRECT), true);
 		try {
 			amount = - Double.parseDouble(Main.pref.get("audio.forwardbackamount","10.0"));
 		} catch (NumberFormatException e) {
Index: src/org/openstreetmap/josm/actions/audio/AudioFwdAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/audio/AudioFwdAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/audio/AudioFwdAction.java	(working copy)
@@ -10,13 +10,15 @@
 import org.openstreetmap.josm.actions.JosmAction;
 import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer;
 import org.openstreetmap.josm.tools.AudioPlayer;
+import org.openstreetmap.josm.tools.ShortCut;
 
 public class AudioFwdAction extends JosmAction {
 
 	private double amount;
 	
 	public AudioFwdAction() {
-		super(tr("Forward"), "audio-fwd", tr("Jump forward"), KeyEvent.VK_F7, 0, true);
+		super(tr("Forward"), "audio-fwd", tr("Jump forward"),
+		ShortCut.registerShortCut("audio:forward", tr("Audio: Forward"), KeyEvent.VK_F7, ShortCut.GROUP_DIRECT), true);
 		try {
 			amount = Double.parseDouble(Main.pref.get("audio.forwardbackamount","10.0"));
 		} catch (NumberFormatException e) {
Index: src/org/openstreetmap/josm/actions/audio/AudioFastSlowAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/audio/AudioFastSlowAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/audio/AudioFastSlowAction.java	(working copy)
@@ -6,11 +6,24 @@
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.actions.JosmAction;
 import org.openstreetmap.josm.tools.AudioPlayer;
+import org.openstreetmap.josm.tools.ShortCut;
 
 abstract public class AudioFastSlowAction extends JosmAction {
 
 	private double multiplier;
 	
+	public AudioFastSlowAction(String name, String iconName, String tooltip, ShortCut shortcut, boolean fast) {
+		super(name, iconName, tooltip, shortcut, true);
+		try {
+			multiplier = Double.parseDouble(Main.pref.get("audio.fastfwdmultiplier","1.3"));
+		} catch (NumberFormatException e) {
+			multiplier = 1.3;
+		}
+		if (! fast)
+			multiplier = 1.0 / multiplier;
+	}
+
+	@Deprecated
 	public AudioFastSlowAction(String name, String iconName, String tooltip, int shortcut, int modifier, boolean fast) {
 		super(name, iconName, tooltip, shortcut, modifier, true);
 		try {
Index: src/org/openstreetmap/josm/actions/audio/AudioPlayPauseAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/audio/AudioPlayPauseAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/audio/AudioPlayPauseAction.java	(working copy)
@@ -10,11 +10,13 @@
 import org.openstreetmap.josm.actions.JosmAction;
 import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer;
 import org.openstreetmap.josm.tools.AudioPlayer;
+import org.openstreetmap.josm.tools.ShortCut;
 
 public class AudioPlayPauseAction extends JosmAction {
 
 	public AudioPlayPauseAction() {
-		super(tr("Play/pause"), "audio-playpause", tr("Play/pause audio."), KeyEvent.VK_PERIOD, 0, true);
+		super(tr("Play/pause"), "audio-playpause", tr("Play/pause audio."),
+		ShortCut.registerShortCut("audio:pause", tr("Audio: Play/Pause"), KeyEvent.VK_PERIOD, ShortCut.GROUP_DIRECT), true);
 	}
 
 	public void actionPerformed(ActionEvent e) {
Index: src/org/openstreetmap/josm/actions/audio/AudioFasterAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/audio/AudioFasterAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/audio/AudioFasterAction.java	(working copy)
@@ -2,12 +2,14 @@
 package org.openstreetmap.josm.actions.audio;
 
 import static org.openstreetmap.josm.tools.I18n.tr;
+import org.openstreetmap.josm.tools.ShortCut;
 
 import java.awt.event.KeyEvent;
 
 public class AudioFasterAction extends AudioFastSlowAction {
 	
 	public AudioFasterAction() {
-		super(tr("Faster"), "audio-faster", tr("Faster Forward"), KeyEvent.VK_F9, 0, true);
+		super(tr("Faster"), "audio-faster", tr("Faster Forward"),
+		ShortCut.registerShortCut("audio:faster", tr("Audio: Faster"), KeyEvent.VK_F9, ShortCut.GROUP_DIRECT), true);
 	}
 }
Index: src/org/openstreetmap/josm/actions/audio/AudioSlowerAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/audio/AudioSlowerAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/audio/AudioSlowerAction.java	(working copy)
@@ -4,10 +4,12 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
 import java.awt.event.KeyEvent;
+import org.openstreetmap.josm.tools.ShortCut;
 
 public class AudioSlowerAction extends AudioFastSlowAction {
 	
 	public AudioSlowerAction() {
-		super(tr("Slower"), "audio-slower", tr("Slower Forward"), KeyEvent.VK_F9, KeyEvent.SHIFT_MASK, false);
+		super(tr("Slower"), "audio-slower", tr("Slower Forward"),
+		ShortCut.registerShortCut("audio:slower", tr("Audio: Slower"), KeyEvent.VK_F9, ShortCut.GROUP_DIRECT), true);
 	}
 }
Index: src/org/openstreetmap/josm/actions/audio/AudioPrevAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/audio/AudioPrevAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/audio/AudioPrevAction.java	(working copy)
@@ -8,11 +8,13 @@
 
 import org.openstreetmap.josm.actions.JosmAction;
 import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer;
+import org.openstreetmap.josm.tools.ShortCut;
 
 public class AudioPrevAction extends JosmAction {
 
 	public AudioPrevAction() {
-		super(tr("Previous Marker"), "audio-prev", tr("Play previous marker."), KeyEvent.VK_F5, 0, true);
+		super(tr("Previous Marker"), "audio-prev", tr("Play previous marker."),
+		ShortCut.registerShortCut("audio:prev", tr("Audio: Previous"), KeyEvent.VK_F5, ShortCut.GROUP_DIRECT), true);
 	}
 
 	public void actionPerformed(ActionEvent e) {
Index: src/org/openstreetmap/josm/actions/audio/AudioNextAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/audio/AudioNextAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/audio/AudioNextAction.java	(working copy)
@@ -8,11 +8,13 @@
 
 import org.openstreetmap.josm.actions.JosmAction;
 import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer;
+import org.openstreetmap.josm.tools.ShortCut;
 
 public class AudioNextAction extends JosmAction {
 
 	public AudioNextAction() {
-		super(tr("Next Marker"), "audio-next", tr("Play next marker."), KeyEvent.VK_F8, 0, true);
+		super(tr("Next Marker"), "audio-next", tr("Play next marker."),
+		ShortCut.registerShortCut("audio:next", tr("Audio: Next"), KeyEvent.VK_F8, ShortCut.GROUP_DIRECT), true);
 	}
 
 	public void actionPerformed(ActionEvent e) {
Index: src/org/openstreetmap/josm/actions/JoinNodeWayAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/JoinNodeWayAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/JoinNodeWayAction.java	(working copy)
@@ -22,11 +22,12 @@
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.data.osm.WaySegment;
+import org.openstreetmap.josm.tools.ShortCut;
 
 public class JoinNodeWayAction extends JosmAction {
 	public JoinNodeWayAction() {
-	    super(tr("Join node to way"), "joinnodeway",
-			tr("Join a node into the nearest way segments"), KeyEvent.VK_J, 0, true);
+	    super(tr("Join node to way"), "joinnodeway", tr("Join a node into the nearest way segments"),
+			ShortCut.registerShortCut("tools:joinnodeway", tr("Tool: Join node to way"), KeyEvent.VK_J, ShortCut.GROUP_EDIT), true);
 	}
 
 	public void actionPerformed(ActionEvent e) {
Index: src/org/openstreetmap/josm/actions/search/SearchAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/search/SearchAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/search/SearchAction.java	(working copy)
@@ -21,6 +21,7 @@
 import org.openstreetmap.josm.actions.JosmAction;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.ShortCut;
 
 public class SearchAction extends JosmAction {
 
@@ -35,8 +36,8 @@
     private static SearchSetting lastSearch = null;
 
     public SearchAction() {
-        super(tr("Search ..."), "dialogs/search", tr("Search for objects."), KeyEvent.VK_F, KeyEvent.CTRL_DOWN_MASK,
-                true);
+        super(tr("Search ..."), "dialogs/search", tr("Search for objects."),
+        ShortCut.registerShortCut("system:find", tr("Search..."), KeyEvent.VK_F, ShortCut.GROUP_HOTKEY), true);
     }
 
     public void actionPerformed(ActionEvent e) {
Index: src/org/openstreetmap/josm/actions/AlignInLineAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/AlignInLineAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/AlignInLineAction.java	(working copy)
@@ -17,6 +17,7 @@
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.tools.ShortCut;
 
 /**
  * Aligns all selected nodes into a straight line (useful for
@@ -28,7 +29,8 @@
 public final class AlignInLineAction extends JosmAction {
 
 	public AlignInLineAction() {
-		super(tr("Align Nodes in Line"), "alignline", tr("Move the selected nodes onto a line."), KeyEvent.VK_L, 0, true);
+		super(tr("Align Nodes in Line"), "alignline", tr("Move the selected nodes onto a line."),
+		ShortCut.registerShortCut("tools:alignline", tr("Tool: Align in line"), KeyEvent.VK_L, ShortCut.GROUP_EDIT), true);
 	}
 
 	/**
Index: src/org/openstreetmap/josm/actions/ReverseWayAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/ReverseWayAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/ReverseWayAction.java	(working copy)
@@ -24,13 +24,13 @@
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.data.osm.visitor.Visitor;
+import org.openstreetmap.josm.tools.ShortCut;
 
 public final class ReverseWayAction extends JosmAction {
 
 	public ReverseWayAction() {
-		super(tr("Reverse ways"), "wayflip",
-		        tr("Reverse the direction of all selected ways."),
-		        KeyEvent.VK_R, 0, true);
+		super(tr("Reverse ways"), "wayflip", tr("Reverse the direction of all selected ways."),
+		ShortCut.registerShortCut("tools:reverse", tr("Tool: Reverse way"), KeyEvent.VK_R, ShortCut.GROUP_EDIT), true);
 	}
 
 	public void actionPerformed(ActionEvent e) {
Index: src/org/openstreetmap/josm/actions/UnGlueAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/UnGlueAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/UnGlueAction.java	(working copy)
@@ -25,6 +25,7 @@
 import org.openstreetmap.josm.data.osm.Relation;
 import org.openstreetmap.josm.data.osm.RelationMember;
 import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.tools.ShortCut;
 
 /**
  * Dupe a node that is used my multiple ways, so each way has its own node.
@@ -43,7 +44,8 @@
 	 * Create a new SplitWayAction.
 	 */
 	public UnGlueAction() {
-		super(tr("UnGlue Ways"), "unglueways", tr("Duplicate the selected node so each way using it has its own copy."), KeyEvent.VK_G, 0, true);
+		super(tr("UnGlue Ways"), "unglueways", tr("Duplicate the selected node so each way using it has its own copy."),
+		ShortCut.registerShortCut("tools:unglue", tr("Tool: Unglue"), KeyEvent.VK_G, ShortCut.GROUP_EDIT), true);
 		DataSet.selListeners.add(this);
 	}
 
Index: src/org/openstreetmap/josm/actions/GpxExportAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/GpxExportAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/GpxExportAction.java	(working copy)
@@ -33,6 +33,7 @@
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.io.GpxWriter;
 import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.ShortCut;
 
 /**
  * Exports data to gpx.
@@ -44,7 +45,8 @@
 	private final Layer layer;
 
 	public GpxExportAction(Layer layer) {
-		super(tr("Export to GPX ..."), "exportgpx", tr("Export the data to GPX file."), KeyEvent.VK_E, InputEvent.CTRL_DOWN_MASK);
+		super(tr("Export to GPX ..."), "exportgpx", tr("Export the data to GPX file."),
+		ShortCut.registerShortCut("file:exportgpx", tr("Export to GPX"), KeyEvent.VK_E, ShortCut.GROUP_MENU));
 		this.layer = layer;
 	}
 
Index: src/org/openstreetmap/josm/actions/DeleteAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/DeleteAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/DeleteAction.java	(working copy)
@@ -7,12 +7,13 @@
 import java.awt.event.KeyEvent;
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.tools.ShortCut;
 
 public final class DeleteAction extends JosmAction {
 
 	public DeleteAction() {
 		super(tr("Delete"), "dialogs/delete", tr("Delete selected objects."),
-		        KeyEvent.VK_DELETE, 0, true);
+		ShortCut.registerShortCut("system:delete", tr("Edit: Delete"), KeyEvent.VK_DELETE, ShortCut.GROUP_DIRECT), true);
 		setEnabled(true);
 	}
 
Index: src/org/openstreetmap/josm/actions/mapmode/DeleteAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/mapmode/DeleteAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/mapmode/DeleteAction.java	(working copy)
@@ -15,6 +15,7 @@
 import org.openstreetmap.josm.data.osm.WaySegment;
 import org.openstreetmap.josm.gui.MapFrame;
 import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.tools.ShortCut;
 
 /**
  * An action that enables the user to delete nodes and other objects.
@@ -42,7 +43,7 @@
 		super(tr("Delete Mode"),
 				"delete", 
 				tr("Delete nodes or ways."), 
-				KeyEvent.VK_D, 
+				ShortCut.registerShortCut("mapmode:delete", tr("Delete mode"), KeyEvent.VK_D, ShortCut.GROUP_EDIT),
 				mapFrame, 
 				ImageProvider.getCursor("normal", "delete"));
 	}
Index: src/org/openstreetmap/josm/actions/mapmode/MapMode.java
===================================================================
--- src/org/openstreetmap/josm/actions/mapmode/MapMode.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/mapmode/MapMode.java	(working copy)
@@ -11,6 +11,7 @@
 import org.openstreetmap.josm.actions.JosmAction;
 import org.openstreetmap.josm.gui.MapFrame;
 import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.tools.ShortCut;
 
 /**
  * A class implementing MapMode is able to be selected as an mode for map editing.
@@ -27,6 +28,16 @@
 	/**
 	 * Constructor for mapmodes without an menu
 	 */
+	public MapMode(String name, String iconName, String tooltip, ShortCut shortCut, MapFrame mapFrame, Cursor cursor) {
+		super(name, "mapmode/"+iconName, tooltip, shortCut, false);
+		this.cursor = cursor;
+		putValue("active", false);
+	}
+
+	/**
+	 * Constructor for mapmodes without an menu
+	 */
+	 @Deprecated
 	public MapMode(String name, String iconName, String tooltip, int keystroke, MapFrame mapFrame, Cursor cursor) {
 		super(name, "mapmode/"+iconName, tooltip, keystroke, 0, false);
 		this.cursor = cursor;
Index: src/org/openstreetmap/josm/actions/mapmode/ZoomAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/mapmode/ZoomAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/mapmode/ZoomAction.java	(working copy)
@@ -12,6 +12,7 @@
 import org.openstreetmap.josm.gui.SelectionManager;
 import org.openstreetmap.josm.gui.SelectionManager.SelectionEnded;
 import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.tools.ShortCut;
 
 /**
  * Enable the zoom mode within the MapFrame. 
@@ -44,7 +45,9 @@
 	 * @param mapFrame The MapFrame, whose zoom mode should be enabled.
 	 */
 	public ZoomAction(MapFrame mapFrame) {
-		super(tr("Zoom"), "zoom", tr("Zoom and move map"), KeyEvent.VK_Z, mapFrame, ImageProvider.getCursor("normal", "zoom"));
+		super(tr("Zoom"), "zoom", tr("Zoom and move map"),
+		ShortCut.registerShortCut("mapmode:zoom", tr("Zoom mode"), KeyEvent.VK_Z, ShortCut.GROUP_EDIT),
+		mapFrame, ImageProvider.getCursor("normal", "zoom"));
 		mv = mapFrame.mapView;
 		selectionManager = new SelectionManager(this, true, mv);
 	}
Index: src/org/openstreetmap/josm/actions/mapmode/PlayHeadDragMode.java
===================================================================
--- src/org/openstreetmap/josm/actions/mapmode/PlayHeadDragMode.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/mapmode/PlayHeadDragMode.java	(working copy)
@@ -11,6 +11,7 @@
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.coor.EastNorth;
 import org.openstreetmap.josm.gui.layer.markerlayer.PlayHeadMarker;
+import org.openstreetmap.josm.tools.ShortCut;
 
 /**
  * Singleton marker class to track position of audio.
@@ -26,7 +27,8 @@
 	private PlayHeadMarker playHeadMarker = null;
 	
 	public PlayHeadDragMode(PlayHeadMarker m) {
-		super("play head drag", "playheaddrag", "play head trag", 0, Main.map, Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
+		super("play head drag", "playheaddrag", "play head drag", null,
+		Main.map, Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
 		playHeadMarker = m;
 	}
 	
Index: src/org/openstreetmap/josm/actions/mapmode/DrawAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/mapmode/DrawAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/mapmode/DrawAction.java	(working copy)
@@ -51,6 +51,7 @@
 import org.openstreetmap.josm.gui.layer.MapViewPaintable;
 import org.openstreetmap.josm.tools.ImageProvider;
 import org.openstreetmap.josm.tools.Pair;
+import org.openstreetmap.josm.tools.ShortCut;
 
 /**
  *
@@ -73,11 +74,12 @@
 	
 	public DrawAction(MapFrame mapFrame) {
 		super(tr("Draw"), "node/autonode", tr("Draw nodes"),
-			KeyEvent.VK_A, mapFrame, getCursor());
+				ShortCut.registerShortCut("mapmode:draw", tr("Draw mode"), KeyEvent.VK_A, ShortCut.GROUP_EDIT),
+				mapFrame, getCursor());
 
 		// Add extra shortcut N
 		Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
-			KeyStroke.getKeyStroke(KeyEvent.VK_N, 0), tr("Draw"));
+			ShortCut.registerShortCut("mapmode:draw2", tr("Draw mode (2)"), KeyEvent.VK_N, ShortCut.GROUP_EDIT).getKeyStroke(), tr("Draw"));
 		
 		//putValue("help", "Action/AddNode/Autnode");
 		selectedColor = Main.pref.getColor(marktr("selected"), Color.YELLOW);
Index: src/org/openstreetmap/josm/actions/mapmode/SelectAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/mapmode/SelectAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/mapmode/SelectAction.java	(working copy)
@@ -35,6 +35,8 @@
 import org.openstreetmap.josm.gui.SelectionManager;
 import org.openstreetmap.josm.gui.SelectionManager.SelectionEnded;
 import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.tools.ShortCut;
+
 /**
  * Move is an action that can move all kind of OsmPrimitives (except keys for now).
  *
@@ -83,7 +85,8 @@
 	 */
 	public SelectAction(MapFrame mapFrame) {
 		super(tr("Select"), "move/move", tr("Select, move and rotate objects"),
-			KeyEvent.VK_S, mapFrame,
+			ShortCut.registerShortCut("mapmode:select", tr("Select mode"), KeyEvent.VK_S, ShortCut.GROUP_EDIT),
+			mapFrame,
 			getCursor("normal", "selection", Cursor.DEFAULT_CURSOR));
 		putValue("help", "Action/Move/Move");
 		selectionManager = new SelectionManager(this, false, mapFrame.mapView);		
Index: src/org/openstreetmap/josm/actions/mapmode/ExtrudeAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/mapmode/ExtrudeAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/mapmode/ExtrudeAction.java	(working copy)
@@ -29,6 +29,8 @@
 import org.openstreetmap.josm.gui.MapView;
 import org.openstreetmap.josm.gui.layer.MapViewPaintable;
 import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.tools.ShortCut;
+
 /**
  * Makes a rectangle from a line, or modifies a rectangle.
  * 
@@ -71,7 +73,8 @@
 	 */
 	public ExtrudeAction(MapFrame mapFrame) {
 		super(tr("Extrude"), "extrude/extrude", tr("Create areas"),
-			KeyEvent.VK_X, mapFrame,
+				ShortCut.registerShortCut("mapmode:extrude", tr("Extrude mode"), KeyEvent.VK_X, ShortCut.GROUP_EDIT),
+			mapFrame,
 			getCursor("normal", "selection", Cursor.DEFAULT_CURSOR));
 		putValue("help", "Action/Extrude/Extrude");
 		initialMoveDelay = Main.pref.getInteger("edit.initial-move-delay",200);
Index: src/org/openstreetmap/josm/actions/UndoAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/UndoAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/UndoAction.java	(working copy)
@@ -8,8 +8,8 @@
 import java.awt.event.KeyEvent;
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.tools.ShortCut;
 
-
 /**
  * Undoes the last command.
  * 
@@ -21,7 +21,8 @@
 	 * Construct the action with "Undo" as label.
 	 */
 	public UndoAction() {
-		super(tr("Undo"), "undo", tr("Undo the last action."), KeyEvent.VK_Z, InputEvent.CTRL_DOWN_MASK, true);
+		super(tr("Undo"), "undo", tr("Undo the last action."),
+		ShortCut.registerShortCut("system:undo", tr("Edit: Undo"), KeyEvent.VK_Z, ShortCut.GROUP_MENU), true);
 		setEnabled(false);
 	}
 
Index: src/org/openstreetmap/josm/actions/AlignInRectangleAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/AlignInRectangleAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/AlignInRectangleAction.java	(working copy)
@@ -19,6 +19,7 @@
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.tools.ShortCut;
 
 /**
  * Aligns all selected nodes within a rectangle. 
@@ -39,7 +40,8 @@
 public final class AlignInRectangleAction extends JosmAction {
 
 	public AlignInRectangleAction() {
-		super(tr("Align Nodes in Rectangle"), "alignrect", tr("Move the selected nodes into a rectangle."), KeyEvent.VK_Q, 0, true);
+		super(tr("Align Nodes in Rectangle"), "alignrect", tr("Move the selected nodes into a rectangle."),
+		ShortCut.registerShortCut("tools:alignrect", tr("Tool: Align in rectangle"), KeyEvent.VK_Q, ShortCut.GROUP_EDIT), true);
 	}
 
 	public void actionPerformed(ActionEvent e) {
Index: src/org/openstreetmap/josm/actions/DownloadAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/DownloadAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/DownloadAction.java	(working copy)
@@ -16,6 +16,7 @@
 import org.openstreetmap.josm.gui.download.DownloadDialog;
 import org.openstreetmap.josm.gui.download.DownloadDialog.DownloadTask;
 import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.ShortCut;
 
 /**
  * Action that opens a connection to the osm server and downloads map data.
@@ -30,7 +31,8 @@
 	public DownloadDialog dialog;
 	
 	public DownloadAction() {
-		super(tr("Download from OSM ..."), "download", tr("Download map data from the OSM server."), KeyEvent.VK_D, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK, true);
+		super(tr("Download from OSM ..."), "download", tr("Download map data from the OSM server."),
+		ShortCut.registerShortCut("file:download", tr("File: Download"), KeyEvent.VK_D, ShortCut.GROUPS_ALT1+ShortCut.GROUP_HOTKEY), true);
 	}
 
 	public void actionPerformed(ActionEvent e) {
Index: src/org/openstreetmap/josm/actions/DuplicateAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/DuplicateAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/DuplicateAction.java	(working copy)
@@ -12,13 +12,14 @@
 import org.openstreetmap.josm.data.SelectionChangedListener;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.tools.ShortCut;
 
 public final class DuplicateAction extends JosmAction implements SelectionChangedListener {
 
     public DuplicateAction() {
     	super(tr("Duplicate"), "duplicate",
 			tr("Duplicate selection by copy and immediate paste."),
-			KeyEvent.VK_D, KeyEvent.CTRL_MASK, true);
+			ShortCut.registerShortCut("system:duplicate", tr("Edit: Duplicate selection"), KeyEvent.VK_D, ShortCut.GROUP_MENU), true);
     	setEnabled(false);
 		DataSet.selListeners.add(this);
     }
Index: src/org/openstreetmap/josm/actions/AboutAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/AboutAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/AboutAction.java	(working copy)
@@ -33,6 +33,7 @@
 import org.openstreetmap.josm.tools.GBC;
 import org.openstreetmap.josm.tools.ImageProvider;
 import org.openstreetmap.josm.tools.UrlLabel;
+import org.openstreetmap.josm.tools.ShortCut;
 
 /**
  * Nice about screen. I guess every application need one these days.. *sigh*
@@ -66,7 +67,7 @@
 	}
 	
 	public AboutAction() {
-		super(tr("About"), "about",tr("Display the about screen."), KeyEvent.VK_F1, KeyEvent.SHIFT_DOWN_MASK, true);
+		super(tr("About"), "about", tr("Display the about screen."), ShortCut.registerShortCut("system:about", tr("About..."), KeyEvent.VK_F1, ShortCut.GROUP_DIRECT), true);
 	}
 
 	public void actionPerformed(ActionEvent e) {
Index: src/org/openstreetmap/josm/actions/PasteAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/PasteAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/PasteAction.java	(working copy)
@@ -23,13 +23,13 @@
 import org.openstreetmap.josm.data.osm.RelationMember;
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.tools.ShortCut;
 
 public final class PasteAction extends JosmAction {
 
     public PasteAction() {
-    	super(tr("Paste"), "paste",
-			tr("Paste contents of paste buffer."),
-			KeyEvent.VK_V, KeyEvent.CTRL_MASK, true);
+    	super(tr("Paste"), "paste", tr("Paste contents of paste buffer."),
+			ShortCut.registerShortCut("system:paste", tr("Edit: Paste"), KeyEvent.VK_V, ShortCut.GROUP_MENU), true);
 		setEnabled(false);
     }
 
Index: src/org/openstreetmap/josm/actions/DiskAccessAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/DiskAccessAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/DiskAccessAction.java	(working copy)
@@ -9,12 +9,18 @@
 import javax.swing.JOptionPane;
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.tools.ShortCut;
 
 /**
  * Helper class for all actions that access the disk
  */
 abstract public class DiskAccessAction extends JosmAction {
 
+	public DiskAccessAction(String name, String iconName, String tooltip, ShortCut shortCut) {
+		super(name, iconName, tooltip, shortCut, true);
+	}
+
+	@Deprecated
 	public DiskAccessAction(String name, String iconName, String tooltip, int shortCut, int modifiers) {
 		super(name, iconName, tooltip, shortCut, modifiers, true);
 	}
Index: src/org/openstreetmap/josm/actions/HistoryInfoAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/HistoryInfoAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/HistoryInfoAction.java	(working copy)
@@ -13,11 +13,13 @@
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.data.osm.visitor.Visitor;
 import org.openstreetmap.josm.tools.OpenBrowser;
+import org.openstreetmap.josm.tools.ShortCut;
 
 public class HistoryInfoAction extends JosmAction {
 
 	public HistoryInfoAction() {
-		super(tr("OSM History Information"), "about",tr("Display history information about OSM ways or nodes."), KeyEvent.VK_H, KeyEvent.SHIFT_DOWN_MASK, true);
+		super(tr("OSM History Information"), "about",tr("Display history information about OSM ways or nodes."),
+		ShortCut.registerShortCut("core:history", tr("Display history"), KeyEvent.VK_H, ShortCut.GROUP_HOTKEY), true);
 	}
 
 	public void actionPerformed(ActionEvent e) {
Index: src/org/openstreetmap/josm/actions/AutoScaleAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/AutoScaleAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/AutoScaleAction.java	(working copy)
@@ -14,6 +14,7 @@
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
 import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.tools.ShortCut;
 
 /**
  * Toggles the autoScale feature of the mapView
@@ -45,7 +46,7 @@
 
     public AutoScaleAction(String mode) {
         super(tr("Zoom to {0}", tr(mode)), "dialogs/autoscale/" + mode, tr("Zoom the view to {0}.", tr(mode)),
-                AutoScaleAction.getModeShortcut(mode), 0, true);
+				ShortCut.registerShortCut("view:zoom"+mode, tr("View: Zoom to {0}", tr(mode)), getModeShortcut(mode), ShortCut.GROUP_EDIT), true);
         String modeHelp = Character.toUpperCase(mode.charAt(0)) + mode.substring(1);
         putValue("help", "Action/AutoScale/" + modeHelp);
         this.mode = mode;
Index: src/org/openstreetmap/josm/actions/UploadAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/UploadAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/UploadAction.java	(working copy)
@@ -23,6 +23,7 @@
 import org.openstreetmap.josm.io.OsmServerWriter;
 import org.openstreetmap.josm.tools.GBC;
 import org.xml.sax.SAXException;
+import org.openstreetmap.josm.tools.ShortCut;
 
 /**
  * Action that opens a connection to the osm server and uploads all changes.
@@ -59,7 +60,8 @@
 	public final LinkedList<UploadHook> uploadHooks = new LinkedList<UploadHook>();
 
 	public UploadAction() {
-		super(tr("Upload to OSM ..."), "upload", tr("Upload all changes to the OSM server."), KeyEvent.VK_U, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK, true);
+		super(tr("Upload to OSM ..."), "upload", tr("Upload all changes to the OSM server."),
+		ShortCut.registerShortCut("file:upload", tr("File: Upload"), KeyEvent.VK_U, ShortCut.GROUPS_ALT1+ShortCut.GROUP_HOTKEY), true);
 
 		/**
 		 * Displays a screen where the actions that would be taken are displayed and
Index: src/org/openstreetmap/josm/actions/CreateCircleAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/CreateCircleAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/CreateCircleAction.java	(working copy)
@@ -19,11 +19,14 @@
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.tools.ShortCut;
 
 /**
  * Create a new circle from three selected nodes--or a way with 3 nodes. (Useful for roundabouts)
+ *
  * Note: If a way is selected, it is changed. If nodes are selected a new way is created.
  *       So if you've got a way with 3 nodes it makes a difference between running this on the way or the nodes!
+ *
  * BTW: Someone might want to implement projection corrections for this...
  *
  * @author Henry Loenwind, based on much copy&Paste from other Actions.
@@ -31,7 +34,8 @@
 public final class CreateCircleAction extends JosmAction {
 
 	public CreateCircleAction() {
-		super(tr("Create Circle"), "createcircle", tr("Create a circle from three selected nodes."), KeyEvent.VK_O, KeyEvent.CTRL_MASK, true);
+		super(tr("Create Circle"), "createcircle", tr("Create a circle from three selected nodes."),
+		ShortCut.registerShortCut("tools:createcircle", tr("Tool: Create circle"), KeyEvent.VK_O, ShortCut.GROUP_EDIT), true);
 	}
 
 	private double calcang(double xc, double yc, double x, double y) {
Index: src/org/openstreetmap/josm/actions/MergeNodesAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/MergeNodesAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/MergeNodesAction.java	(working copy)
@@ -39,6 +39,7 @@
 import org.openstreetmap.josm.data.osm.visitor.CollectBackReferencesVisitor;
 import org.openstreetmap.josm.tools.GBC;
 import org.openstreetmap.josm.tools.Pair;
+import org.openstreetmap.josm.tools.ShortCut;
 
 
 /**
@@ -51,7 +52,8 @@
 public class MergeNodesAction extends JosmAction implements SelectionChangedListener {
 
 	public MergeNodesAction() {
-		super(tr("Merge Nodes"), "mergenodes", tr("Merge nodes into one."), KeyEvent.VK_M, 0, true);
+		super(tr("Merge Nodes"), "mergenodes", tr("Merge nodes into the oldest one."),
+		ShortCut.registerShortCut("tools:mergenodes", tr("Tool: Merge nodes"), KeyEvent.VK_M, ShortCut.GROUP_EDIT), true);
 		DataSet.selListeners.add(this);
 	}
 
Index: src/org/openstreetmap/josm/actions/SaveActionBase.java
===================================================================
--- src/org/openstreetmap/josm/actions/SaveActionBase.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/SaveActionBase.java	(working copy)
@@ -21,11 +21,18 @@
 import org.openstreetmap.josm.gui.layer.GpxLayer;
 import org.openstreetmap.josm.io.OsmWriter;
 import org.openstreetmap.josm.io.GpxWriter;
+import org.openstreetmap.josm.tools.ShortCut;
 
 public abstract class SaveActionBase extends DiskAccessAction {
 
 	private Layer layer;
 
+	public SaveActionBase(String name, String iconName, String tooltip, ShortCut shortCut, Layer layer) {
+		super(name, iconName, tooltip, shortCut);
+		this.layer = layer;
+	}
+
+	@Deprecated
 	public SaveActionBase(String name, String iconName, String tooltip, int shortCut, int modifiers, Layer layer) {
 		super(name, iconName, tooltip, shortCut, modifiers);
 		this.layer = layer;
Index: src/org/openstreetmap/josm/actions/RedoAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/RedoAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/RedoAction.java	(working copy)
@@ -8,8 +8,8 @@
 import java.awt.event.KeyEvent;
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.tools.ShortCut;
 
-
 /**
  * Redoes the last command.
  * 
@@ -21,7 +21,8 @@
 	 * Construct the action with "Redo" as label.
 	 */
 	public RedoAction() {
-		super(tr("Redo"), "redo", tr("Redo the last undone action."), KeyEvent.VK_Y, InputEvent.CTRL_DOWN_MASK, true);
+		super(tr("Redo"), "redo", tr("Redo the last undone action."),
+		ShortCut.registerShortCut("system:redo", tr("Edit: Redo"), KeyEvent.VK_Y, ShortCut.GROUP_MENU), true);
 		setEnabled(false);
 	}
 
Index: src/org/openstreetmap/josm/actions/NewAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/NewAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/NewAction.java	(working copy)
@@ -10,11 +10,13 @@
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.tools.ShortCut;
 
 public class NewAction extends JosmAction {
 
 	public NewAction() {
-		super(tr("New"), "new", tr("Create a new map."), KeyEvent.VK_N, InputEvent.CTRL_DOWN_MASK, true);
+		super(tr("New"), "new", tr("Create a new map."),
+		ShortCut.registerShortCut("system:new", tr("File: New"), KeyEvent.VK_N, ShortCut.GROUP_MENU), true);
 	}
 
 	public void actionPerformed(ActionEvent e) {
Index: src/org/openstreetmap/josm/actions/PasteTagsAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/PasteTagsAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/PasteTagsAction.java	(working copy)
@@ -19,13 +19,14 @@
 import org.openstreetmap.josm.data.SelectionChangedListener;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.tools.ShortCut;
 
 public final class PasteTagsAction extends JosmAction implements SelectionChangedListener {
 
 	public PasteTagsAction(JosmAction copyAction) {
 		super(tr("Paste Tags"), "pastetags",
 			tr("Apply tags of contents of paste buffer to all selected items."),
-			KeyEvent.VK_V, KeyEvent.CTRL_MASK | KeyEvent.SHIFT_MASK, true);
+			ShortCut.registerShortCut("system:pastestyle", tr("Edit: Paste tags"), KeyEvent.VK_V, ShortCut.GROUP_MENU), true);
 		DataSet.selListeners.add(this);
 		copyAction.addListener(this);
 		setEnabled(false);
Index: src/org/openstreetmap/josm/actions/CombineWayAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/CombineWayAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/CombineWayAction.java	(working copy)
@@ -39,6 +39,7 @@
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.tools.GBC;
 import org.openstreetmap.josm.tools.Pair;
+import org.openstreetmap.josm.tools.ShortCut;
 
 /**
  * Combines multiple ways into one.
@@ -48,7 +49,8 @@
 public class CombineWayAction extends JosmAction implements SelectionChangedListener {
 
 	public CombineWayAction() {
-		super(tr("Combine Way"), "combineway", tr("Combine several ways into one."), KeyEvent.VK_C, 0, true);
+		super(tr("Combine Way"), "combineway", tr("Combine several ways into one."),
+		ShortCut.registerShortCut("tools:combineway", tr("Tool: Combine ways"), KeyEvent.VK_C, ShortCut.GROUP_EDIT), true);
 		DataSet.selListeners.add(this);
 	}
 
Index: src/org/openstreetmap/josm/actions/SaveAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/SaveAction.java	(revision 1010)
+++ src/org/openstreetmap/josm/actions/SaveAction.java	(working copy)
@@ -10,6 +10,7 @@
 import org.openstreetmap.josm.gui.layer.Layer;
 import org.openstreetmap.josm.gui.layer.GpxLayer;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.tools.ShortCut;
 
 /**
  * Export the data as an OSM xml file.
@@ -23,7 +24,8 @@
 	 * @param layer Save this layer.
 	 */
 	public SaveAction(Layer layer) {
-		super(tr("Save"), "save", tr("Save the current data."), KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK, layer);
+		super(tr("Save"), "save", tr("Save the current data."),
+		ShortCut.registerShortCut("system:save", tr("File: Save"), KeyEvent.VK_S, ShortCut.GROUP_MENU), layer);
 	}
 	
 	@Override public File getFile(Layer layer) {
Index: src/org/openstreetmap/josm/tools/OpenBrowser.java
===================================================================
--- src/org/openstreetmap/josm/tools/OpenBrowser.java	(revision 1010)
+++ src/org/openstreetmap/josm/tools/OpenBrowser.java	(working copy)
@@ -11,6 +11,9 @@
 
 /**
  * Helper to open platform web browser on different platforms
+ *
+ * This now delegates the real work to a platform specific class.
+ *
  * @author Imi
  */
 public class OpenBrowser {
@@ -29,40 +32,12 @@
 			}
 		}
 
-		String os = System.getProperty("os.name");
-		if (os == null)
-			return "unknown operating system";
 		try {
-			if (os != null && os.startsWith("Windows"))
-				windows(url);
-			else if (os.equals("Linux") || os.equals("Solaris") || os.equals("SunOS") || os.equals("AIX") || os.equals("FreeBSD"))
-				linux(url);
-			else if (os.equals("Mac OS") || os.equals("Mac OS X"))
-				mac(url);
-			else
-				return "unknown operating system";
+			Main.platform.openUrl(url);
 		} catch (IOException e) {
 			return e.getMessage();
 		}
 		return null;
 	}
 
-	private static void windows(String url) throws IOException {
-		Runtime.getRuntime().exec("rundll32 url.dll,FileProtocolHandler " + url);
 	}
-
-	private static void linux(String url) {
-		String[] programs = {"gnome-open", "kfmclient openURL", "firefox"};
-		for (String program : programs) {
-			try {
-				Runtime.getRuntime().exec(program+" "+url);
-				return;
-			} catch (IOException e) {
-            }
-		}
-	}
-
-	private static void mac(String url) throws IOException {
-		Runtime.getRuntime().exec("open " + url);
-	}
-}
Index: src/org/openstreetmap/josm/tools/ShortCutLabel.java
===================================================================
--- src/org/openstreetmap/josm/tools/ShortCutLabel.java	(revision 1010)
+++ src/org/openstreetmap/josm/tools/ShortCutLabel.java	(working copy)
@@ -5,8 +5,9 @@
 
 import java.awt.event.KeyEvent;
 
-
+@Deprecated
 public class ShortCutLabel {
+	@Deprecated
 	public static String name(int shortCut, int modifiers) {
 		if (shortCut == 0 && modifiers == 0)
 			return "";
Index: src/org/openstreetmap/josm/gui/dialogs/ConflictDialog.java
===================================================================
--- src/org/openstreetmap/josm/gui/dialogs/ConflictDialog.java	(revision 1010)
+++ src/org/openstreetmap/josm/gui/dialogs/ConflictDialog.java	(working copy)
@@ -42,6 +42,7 @@
 import org.openstreetmap.josm.gui.NavigatableComponent;
 import org.openstreetmap.josm.gui.OsmPrimitivRenderer;
 import org.openstreetmap.josm.gui.SideButton;
+import org.openstreetmap.josm.tools.ShortCut;
 
 public final class ConflictDialog extends ToggleDialog {
 
@@ -50,7 +51,8 @@
 	private final JList displaylist = new JList(model);
 
 	public ConflictDialog() {
-		super(tr("Conflict"), "conflict", tr("Merging conflicts."), KeyEvent.VK_C, 100);
+		super(tr("Conflict"), "conflict", tr("Merging conflicts."),
+		ShortCut.registerShortCut("subwindow:conflict", tr("Toggle conflict window"), KeyEvent.VK_C, ShortCut.GROUP_LAYER), 100);
 		displaylist.setCellRenderer(new OsmPrimitivRenderer());
 		displaylist.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
 		displaylist.addMouseListener(new MouseAdapter(){
Index: src/org/openstreetmap/josm/gui/dialogs/HistoryDialog.java
===================================================================
--- src/org/openstreetmap/josm/gui/dialogs/HistoryDialog.java	(revision 1010)
+++ src/org/openstreetmap/josm/gui/dialogs/HistoryDialog.java	(working copy)
@@ -37,6 +37,7 @@
 import org.openstreetmap.josm.gui.SideButton;
 import org.openstreetmap.josm.tools.GBC;
 import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.tools.ShortCut;
 
 /**
  * History dialog works like follows:
@@ -86,7 +87,8 @@
 	private JLabel notLoaded = new JLabel("<html><i>"+tr("Click Reload to refresh list")+"</i></html>");
 
 	public HistoryDialog() {
-		super(tr("History"), "history", tr("Display the history of all selected items."), KeyEvent.VK_H, 150);
+		super(tr("History"), "history", tr("Display the history of all selected items."),
+		ShortCut.registerShortCut("subwindow:history", tr("Toggle history window"), KeyEvent.VK_H, ShortCut.GROUP_LAYER), 150);
 		historyPane.setVisible(false);
 		notLoaded.setVisible(true);
 		notLoaded.setHorizontalAlignment(JLabel.CENTER);
Index: src/org/openstreetmap/josm/gui/dialogs/SelectionListDialog.java
===================================================================
--- src/org/openstreetmap/josm/gui/dialogs/SelectionListDialog.java	(revision 1010)
+++ src/org/openstreetmap/josm/gui/dialogs/SelectionListDialog.java	(working copy)
@@ -40,6 +40,7 @@
 import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
 import org.openstreetmap.josm.gui.OsmPrimitivRenderer;
 import org.openstreetmap.josm.gui.SideButton;
+import org.openstreetmap.josm.tools.ShortCut;
 
 /**
  * A small tool dialog for displaying the current selection. The selection manager
@@ -75,7 +76,8 @@
     private Collection<? extends OsmPrimitive> historyIgnoreSelection = null;
 
     public SelectionListDialog() {
-        super(tr("Current Selection"), "selectionlist", tr("Open a selection list window."), KeyEvent.VK_T, 150);
+        super(tr("Current Selection"), "selectionlist", tr("Open a selection list window."),
+        ShortCut.registerShortCut("subwindow:selection", tr("Toggle selection window"), KeyEvent.VK_T, ShortCut.GROUP_LAYER), 150);
 
         selectionHistory = new LinkedList<Collection<? extends OsmPrimitive>>();
         popupMenu = new JPopupMenu();
Index: src/org/openstreetmap/josm/gui/dialogs/ToggleDialog.java
===================================================================
--- src/org/openstreetmap/josm/gui/dialogs/ToggleDialog.java	(revision 1010)
+++ src/org/openstreetmap/josm/gui/dialogs/ToggleDialog.java	(working copy)
@@ -26,6 +26,7 @@
 import org.openstreetmap.josm.actions.HelpAction.Helpful;
 import org.openstreetmap.josm.tools.GBC;
 import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.tools.ShortCut;
 
 /**
  * This class is a toggle dialog that can be turned on and off. It is attached
@@ -39,8 +40,8 @@
 		public final String prefname;
 		public AbstractButton button;
 
-		private ToggleDialogAction(String name, String iconName, String tooltip, int shortCut, int modifier, String prefname) {
-			super(name, iconName, tooltip, shortCut, modifier, false);
+		private ToggleDialogAction(String name, String iconName, String tooltip, ShortCut shortCut, String prefname) {
+			super(name, iconName, tooltip, shortCut, false);
 			this.prefname = prefname;
 		}
 
@@ -61,11 +62,22 @@
 	public JPanel parent;
 	private final JPanel titleBar = new JPanel(new GridBagLayout());
 
+	@Deprecated
 	public ToggleDialog(final String name, String iconName, String tooltip, int shortCut, int preferredHeight) {
 		super(new BorderLayout());
 		this.prefName = iconName;
+		ToggleDialogInit(name, iconName, tooltip, ShortCut.registerShortCut("auto:"+name, tooltip, shortCut, ShortCut.GROUP_LAYER), preferredHeight);
+	}
+
+	public ToggleDialog(final String name, String iconName, String tooltip, ShortCut shortCut, int preferredHeight) {
+		super(new BorderLayout());
+		this.prefName = iconName;
+		ToggleDialogInit(name, iconName, tooltip, shortCut, preferredHeight);
+	}
+
+	private void ToggleDialogInit(final String name, String iconName, String tooltip, ShortCut shortCut, int preferredHeight) {
 		setPreferredSize(new Dimension(330,preferredHeight));
-		action = new ToggleDialogAction(name, "dialogs/"+iconName, tooltip, shortCut, KeyEvent.ALT_MASK, iconName);
+		action = new ToggleDialogAction(name, "dialogs/"+iconName, tooltip, shortCut, iconName);
 		String helpId = "Dialog/"+getClass().getName().substring(getClass().getName().lastIndexOf('.')+1);
 		action.putValue("help", helpId.substring(0, helpId.length()-6));
 		setLayout(new BorderLayout());
Index: src/org/openstreetmap/josm/gui/dialogs/CommandStackDialog.java
===================================================================
--- src/org/openstreetmap/josm/gui/dialogs/CommandStackDialog.java	(revision 1010)
+++ src/org/openstreetmap/josm/gui/dialogs/CommandStackDialog.java	(working copy)
@@ -19,6 +19,7 @@
 import org.openstreetmap.josm.command.Command;
 import org.openstreetmap.josm.gui.MapFrame;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer.CommandQueueListener;
+import org.openstreetmap.josm.tools.ShortCut;
 
 public class CommandStackDialog extends ToggleDialog implements CommandQueueListener {
 
@@ -26,7 +27,8 @@
     private JTree tree = new JTree(treeModel);
 
 	public CommandStackDialog(final MapFrame mapFrame) {
-		super(tr("Command Stack"), "commandstack", tr("Open a list of all commands (undo buffer)."), KeyEvent.VK_O, 100);
+		super(tr("Command Stack"), "commandstack", tr("Open a list of all commands (undo buffer)."),
+		ShortCut.registerShortCut("subwindow:commandstack", tr("Toggle command stack"), KeyEvent.VK_O, ShortCut.GROUP_LAYER), 100);
 		Main.main.undoRedo.listenerCommands.add(this);
 			
 		tree.setRootVisible(false);
Index: src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java
===================================================================
--- src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java	(revision 1010)
+++ src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java	(working copy)
@@ -39,6 +39,7 @@
 import org.openstreetmap.josm.tools.DontShowAgainInfo;
 import org.openstreetmap.josm.tools.ImageProvider;
 import org.openstreetmap.josm.tools.ImageProvider.OverlayPosition;
+import org.openstreetmap.josm.tools.ShortCut;
 
 /**
  * A component that manages the list of all layers and react to selection changes
@@ -157,7 +158,8 @@
 	 * Create an layerlist and attach it to the given mapView.
 	 */
 	public LayerListDialog(MapFrame mapFrame) {
-		super(tr("Layers"), "layerlist", tr("Open a list of all loaded layers."), KeyEvent.VK_L, 100);
+		super(tr("Layers"), "layerlist", tr("Open a list of all loaded layers."),
+		ShortCut.registerShortCut("subwindow:layers", tr("Toggle layer window"), KeyEvent.VK_L, ShortCut.GROUP_LAYER), 100);
 		instance = new JList(model);
 		listScrollPane = new JScrollPane(instance);
 		add(listScrollPane, BorderLayout.CENTER);
Index: src/org/openstreetmap/josm/gui/dialogs/RelationListDialog.java
===================================================================
--- src/org/openstreetmap/josm/gui/dialogs/RelationListDialog.java	(revision 1010)
+++ src/org/openstreetmap/josm/gui/dialogs/RelationListDialog.java	(working copy)
@@ -31,6 +31,7 @@
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.gui.layer.Layer.LayerChangeListener;
 import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.ShortCut;
 
 /**
  * A dialog showing all known relations, with buttons to add, edit, and
@@ -54,7 +55,8 @@
 	private JList displaylist = new JList(list);
 
 	public RelationListDialog() {
-		super(tr("Relations"), "relationlist", tr("Open a list of all relations."), KeyEvent.VK_R, 150);
+		super(tr("Relations"), "relationlist", tr("Open a list of all relations."),
+		ShortCut.registerShortCut("subwindow:relations", tr("Toggle relations window"), KeyEvent.VK_R, ShortCut.GROUP_LAYER), 150);
 		displaylist.setCellRenderer(new OsmPrimitivRenderer());
 		displaylist.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
 		displaylist.addMouseListener(new MouseAdapter(){
Index: src/org/openstreetmap/josm/gui/dialogs/UserListDialog.java
===================================================================
--- src/org/openstreetmap/josm/gui/dialogs/UserListDialog.java	(revision 1010)
+++ src/org/openstreetmap/josm/gui/dialogs/UserListDialog.java	(working copy)
@@ -20,6 +20,7 @@
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.User;
+import org.openstreetmap.josm.tools.ShortCut;
 
 /**
  * Displays a dialog with all users who have last edited something in the 
@@ -46,7 +47,8 @@
     private static User anonymousUser = User.get("(anonymous users)");
 			
 	public UserListDialog() {
-		super(tr("Authors"), "userlist", tr("Open a list of people working on the selected objects."), KeyEvent.VK_A, 150);
+		super(tr("Authors"), "userlist", tr("Open a list of people working on the selected objects."),
+		ShortCut.registerShortCut("subwindow:authors", tr("Toggle authors window"), KeyEvent.VK_A, ShortCut.GROUP_LAYER), 150);
 		
 		data.setColumnIdentifiers(new String[]{tr("Author"),tr("# Objects"),"%"});
 		userTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
Index: src/org/openstreetmap/josm/gui/dialogs/PropertiesDialog.java
===================================================================
--- src/org/openstreetmap/josm/gui/dialogs/PropertiesDialog.java	(revision 1010)
+++ src/org/openstreetmap/josm/gui/dialogs/PropertiesDialog.java	(working copy)
@@ -63,6 +63,7 @@
 import org.openstreetmap.josm.gui.tagging.TaggingPreset;
 import org.openstreetmap.josm.tools.AutoCompleteComboBox;
 import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.ShortCut;
 
 /**
  * This dialog displays the properties of the current selected primitives.
@@ -416,7 +417,8 @@
 	 * Create a new PropertiesDialog
 	 */
 	public PropertiesDialog(MapFrame mapFrame) {
-		super(tr("Properties/Memberships"), "propertiesdialog", tr("Properties for selected objects."), KeyEvent.VK_P, 150);
+		super(tr("Properties/Memberships"), "propertiesdialog", tr("Properties for selected objects."),
+		ShortCut.registerShortCut("subwindow:properies", tr("Toggle properties window"), KeyEvent.VK_P, ShortCut.GROUP_LAYER), 150);
 
 		// ---------------------------------------
 		// This drop-down is really deprecated but we offer people a chance to 
Index: src/org/openstreetmap/josm/gui/MainApplication.java
===================================================================
--- src/org/openstreetmap/josm/gui/MainApplication.java	(revision 1010)
+++ src/org/openstreetmap/josm/gui/MainApplication.java	(working copy)
@@ -30,6 +30,11 @@
  */
 public class MainApplication extends Main {
 	/**
+	 * Allow subclassing (see JOSM.java)
+	 */
+	public MainApplication() {}
+
+	/**
 	 * Construct an main frame, ready sized and operating. Does not
 	 * display the frame.
 	 */
@@ -65,6 +70,11 @@
 
 		Thread.setDefaultUncaughtExceptionHandler(new BugReportExceptionHandler());
 
+		// initialize the plaform hook, and
+		Main.determinePlatformHook();
+		// call the really early hook before we anything else
+		Main.platform.preStartupHook();
+
 		// construct argument table
 		List<String> argList = Arrays.asList(argArray);
 		final Map<String, Collection<String>> args = new HashMap<String, Collection<String>>();
@@ -143,6 +153,7 @@
 		Main.loadPlugins(true, language);
 
 		if (argList.contains("--help") || argList.contains("-?") || argList.contains("-h")) {
+			// TODO: put in a platformHook for system that have no console by default
 			System.out.println(tr("Java OpenStreetMap Editor")+"\n\n"+
 					tr("usage")+":\n"+
 					"\tjava -jar josm.jar <option> <option> <option>...\n\n"+
@@ -191,4 +202,5 @@
 			}
 		});
 	}
+
 }
Index: src/org/openstreetmap/josm/gui/MapView.java
===================================================================
--- src/org/openstreetmap/josm/gui/MapView.java	(revision 1010)
+++ src/org/openstreetmap/josm/gui/MapView.java	(working copy)
@@ -25,6 +25,7 @@
 
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.actions.AutoScaleAction;
+import org.openstreetmap.josm.actions.JosmAction;
 import org.openstreetmap.josm.actions.MoveAction;
 import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.data.SelectionChangedListener;
@@ -106,17 +107,28 @@
 				new AutoScaleAction("data").actionPerformed(null);
 
 				new MapMover(MapView.this, Main.contentPane);
-				Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, java.awt.event.InputEvent.SHIFT_MASK), "UP");
-				Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, java.awt.event.InputEvent.SHIFT_MASK), "DOWN");
-				Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, java.awt.event.InputEvent.SHIFT_MASK), "LEFT");
-				Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, java.awt.event.InputEvent.SHIFT_MASK), "RIGHT");
+				JosmAction mv;
+				mv = new MoveAction(MoveAction.Direction.UP);
+				if (mv.getShortCut() != null) {
+					Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(mv.getShortCut().getKeyStroke(), "UP");
+					Main.contentPane.getActionMap().put("UP", mv);
+				}
+				mv = new MoveAction(MoveAction.Direction.DOWN);
+				if (mv.getShortCut() != null) {
+					Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(mv.getShortCut().getKeyStroke(), "DOWN");
+					Main.contentPane.getActionMap().put("DOWN", mv);
+				}
+				mv = new MoveAction(MoveAction.Direction.LEFT);
+				if (mv.getShortCut() != null) {
+					Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(mv.getShortCut().getKeyStroke(), "LEFT");
+					Main.contentPane.getActionMap().put("LEFT", mv);
+				}
+				mv = new MoveAction(MoveAction.Direction.RIGHT);
+				if (mv.getShortCut() != null) {
+					Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(mv.getShortCut().getKeyStroke(), "RIGHT");
+					Main.contentPane.getActionMap().put("RIGHT", mv);
+				}
 
-				Main.contentPane.getActionMap().put("UP", new MoveAction(MoveAction.Direction.UP));
-				Main.contentPane.getActionMap().put("DOWN", new MoveAction(MoveAction.Direction.DOWN));
-				Main.contentPane.getActionMap().put("LEFT", new MoveAction(MoveAction.Direction.LEFT));
-				Main.contentPane.getActionMap().put("RIGHT", new MoveAction(MoveAction.Direction.RIGHT));
-				
-
 				MapSlider zoomSlider = new MapSlider(MapView.this);
 				add(zoomSlider);
 				zoomSlider.setBounds(3, 0, 114, 30);
Index: src/org/openstreetmap/josm/gui/MainMenu.java
===================================================================
--- src/org/openstreetmap/josm/gui/MainMenu.java	(revision 1010)
+++ src/org/openstreetmap/josm/gui/MainMenu.java	(working copy)
@@ -12,6 +12,7 @@
 import javax.swing.JMenuBar;
 import javax.swing.JMenuItem;
 import javax.swing.KeyStroke;
+import java.awt.event.KeyEvent;
 
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.actions.AboutAction;
@@ -58,6 +59,7 @@
 import org.openstreetmap.josm.actions.audio.AudioSlowerAction;
 import org.openstreetmap.josm.actions.search.SearchAction;
 import org.openstreetmap.josm.data.DataSetChecker;
+import org.openstreetmap.josm.tools.ShortCut;
 
 /**
  * This is the JOSM main menu bar. It is overwritten to initialize itself and provide
@@ -129,79 +131,77 @@
 	public final JMenu presetsMenu = new JMenu(tr("Presets"));
 	public final JMenu helpMenu = new JMenu(tr("Help"));
         
+	/**
+	 * Add a JosmAction to a menu.
+	 *
+	 * This method handles all the shortcut handling.
+	 * It also makes sure that actions that are handled by the
+	 * OS are not duplicated on the menu.
+	 */
+	public static void add(JMenu menu, JosmAction action) {
+		if (!action.getShortCut().getAutomatic()) {
+			JMenuItem menuitem = menu.add(action);
+			KeyStroke ks = action.getShortCut().getKeyStroke();
+			if (ks != null) {
+				menuitem.setAccelerator(ks);
+			}
+		}
+	}
 
+	/**
+	 * Add a menu to the main menu.
+	 *
+	 * This method handles all the shortcut handling.
+	 */
+	public void add(JMenu menu, int mnemonicKey, String shortName) {
+		ShortCut.registerShortCut("menu:"+shortName, shortName+" menu", mnemonicKey, ShortCut.GROUP_MNEMONIC).setMnemonic(menu);
+		add(menu);
+	}
+
 	public MainMenu() {
         JMenuItem current;
         
-		fileMenu.setMnemonic('F');
-		current = fileMenu.add(newAction);
-		current.setAccelerator(newAction.shortCut);
-		current = fileMenu.add(open);
-		current.setAccelerator(open.shortCut);
+		add(fileMenu, newAction);
+		add(fileMenu, open);
 		fileMenu.addSeparator();
-		current = fileMenu.add(save);
-		current.setAccelerator(save.shortCut);
-		current = fileMenu.add(saveAs);
-		current.setAccelerator(saveAs.shortCut);
-		current = fileMenu.add(gpxExport);
-		current.setAccelerator(gpxExport.shortCut);
+		add(fileMenu, save);
+		add(fileMenu, saveAs);
+		add(fileMenu, gpxExport);
 		fileMenu.addSeparator();
-		current = fileMenu.add(download);
-		current.setAccelerator(download.shortCut);
-		current = fileMenu.add(upload);
-		current.setAccelerator(upload.shortCut);
-		fileMenu.addSeparator();
-		current = fileMenu.add(exit);
-		current.setAccelerator(exit.shortCut);
-		add(fileMenu);
+		add(fileMenu, download);
+		add(fileMenu, upload);
+		add(fileMenu, exit);
+		add(fileMenu, KeyEvent.VK_F, "file");
 
-		editMenu.setMnemonic('E');
-		current = editMenu.add(undo);
-		current.setAccelerator(undo.shortCut);
-		current = editMenu.add(redo);
-		current.setAccelerator(redo.shortCut);
+		add(editMenu, undo);
+		add(editMenu, redo);
 		editMenu.addSeparator();
-		current = editMenu.add(copy);
-		current.setAccelerator(copy.shortCut);
-		current = editMenu.add(delete);
-		current.setAccelerator(delete.shortCut);
-		current = editMenu.add(paste);
-		current.setAccelerator(paste.shortCut);
-		current = editMenu.add(pasteTags);
-		current.setAccelerator(pasteTags.shortCut);
-		current = editMenu.add(duplicate);
-		current.setAccelerator(duplicate.shortCut);
+		add(editMenu, copy);
+		add(editMenu, delete);
+		add(editMenu, paste);
+		add(editMenu, pasteTags);
+		add(editMenu, duplicate);
 		editMenu.addSeparator();
-		current = editMenu.add(selectAll);
-		current.setAccelerator(selectAll.shortCut);
-		current = editMenu.add(unselectAll);
-		current.setAccelerator(unselectAll.shortCut);
+		add(editMenu, selectAll);
+		add(editMenu, unselectAll);
 		editMenu.addSeparator();
-		current = editMenu.add(search);
-		current.setAccelerator(search.shortCut);
+		add(editMenu, search);
 		editMenu.addSeparator();
-		current = editMenu.add(preferences);
-		current.setAccelerator(preferences.shortCut);
-		add(editMenu);
+		add(editMenu, preferences);
+		add(editMenu, KeyEvent.VK_E, "edit");
 		
-		viewMenu.setMnemonic('V');
         for (String mode : AutoScaleAction.modes) {
             JosmAction autoScaleAction = new AutoScaleAction(mode);
-			current = viewMenu.add(autoScaleAction);
-		    current.setAccelerator(autoScaleAction.shortCut);
+			add(viewMenu, autoScaleAction);
         }
         viewMenu.addSeparator();
-        JosmAction a = new ZoomOutAction();
-		viewMenu.add(a).setAccelerator(a.shortCut);
-		a = new ZoomInAction();
-		viewMenu.add(a).setAccelerator(a.shortCut);
-
+		add(viewMenu, new ZoomOutAction());
+		add(viewMenu, new ZoomInAction());
 		viewMenu.addSeparator();
-
 		// TODO move code to an "action" like the others?
         final JCheckBoxMenuItem wireframe = new JCheckBoxMenuItem(tr("Wireframe view"));
 		wireframe.setSelected(Main.pref.getBoolean("draw.wireframe", false));
-        wireframe.setAccelerator(KeyStroke.getKeyStroke("ctrl W"));
+		wireframe.setAccelerator(ShortCut.registerShortCut("menu:view:wireframe", "Toggle Wireframe view", KeyEvent.VK_W, ShortCut.GROUP_MENU).getKeyStroke());
         wireframe.addActionListener(new ActionListener() {
         	public void actionPerformed(ActionEvent ev) {
         		Main.pref.put("draw.wireframe", wireframe.isSelected());
@@ -211,72 +211,48 @@
         	}
         });
         viewMenu.add(wireframe);
+		add(viewMenu, KeyEvent.VK_V, "view");
         
-		add(viewMenu);
-
-		toolsMenu.setMnemonic('T');
-		current = toolsMenu.add(splitWay);
-		current.setAccelerator(splitWay.shortCut);
-		current = toolsMenu.add(combineWay);
-		current.setAccelerator(combineWay.shortCut);
+		add(toolsMenu, splitWay);
+		add(toolsMenu, combineWay);
 		toolsMenu.addSeparator();
-		current = toolsMenu.add(reverseWay);
-		current.setAccelerator(reverseWay.shortCut);
+		add(toolsMenu, reverseWay);
 		toolsMenu.addSeparator();
-		current = toolsMenu.add(alignInCircle);
-		current.setAccelerator(alignInCircle.shortCut);
-		current = toolsMenu.add(alignInLine);
-		current.setAccelerator(alignInLine.shortCut);
-		current = toolsMenu.add(alignInRect);
-		current.setAccelerator(alignInRect.shortCut);
+		add(toolsMenu, alignInCircle);
+		add(toolsMenu, alignInLine);
+		add(toolsMenu, alignInRect);
 		toolsMenu.addSeparator();
-		current = toolsMenu.add(createCircle);
-		current.setAccelerator(createCircle.shortCut);
+		add(toolsMenu, createCircle);
 		toolsMenu.addSeparator();
-		current = toolsMenu.add(mergeNodes);
-		current.setAccelerator(mergeNodes.shortCut);
-		current = toolsMenu.add(joinNodeWay);
-		current.setAccelerator(joinNodeWay.shortCut);
-		current = toolsMenu.add(unglueNodes);
-		current.setAccelerator(unglueNodes.shortCut);
-		add(toolsMenu);
+		add(toolsMenu, mergeNodes);
+		add(toolsMenu, joinNodeWay);
+		add(toolsMenu, unglueNodes);
+		add(toolsMenu, KeyEvent.VK_T, "tools");
 
 		if (! Main.pref.getBoolean("audio.menuinvisible")) {
-			audioMenu.setMnemonic('A');
-			current = audioMenu.add(audioPlayPause);
-			current.setAccelerator(audioPlayPause.shortCut);
-			current = audioMenu.add(audioNext);
-			current.setAccelerator(audioNext.shortCut);
-			current = audioMenu.add(audioPrev);
-			current.setAccelerator(audioPrev.shortCut);
-			current = audioMenu.add(audioFwd);
-			current.setAccelerator(audioFwd.shortCut);
-			current = audioMenu.add(audioBack);
-			current.setAccelerator(audioBack.shortCut);
-			current = audioMenu.add(audioSlower);
-			current.setAccelerator(audioSlower.shortCut);
-			current = audioMenu.add(audioFaster);
-			current.setAccelerator(audioFaster.shortCut);
-			add(audioMenu);
+			add(audioMenu, audioPlayPause);
+			add(audioMenu, audioNext);
+			add(audioMenu, audioPrev);
+			add(audioMenu, audioFwd);
+			add(audioMenu, audioBack);
+			add(audioMenu, audioSlower);
+			add(audioMenu, audioFaster);
+			add(audioMenu, KeyEvent.VK_A, "audio");
 		}
 
-		add(presetsMenu);
-		presetsMenu.setMnemonic('P');
+		add(presetsMenu, KeyEvent.VK_P, "presets");
 		
-		helpMenu.setMnemonic('H');
 		JMenuItem check = new JMenuItem("DEBUG: Check Dataset");
 		check.addActionListener(new ActionListener(){
 			public void actionPerformed(ActionEvent e) {
 				DataSetChecker.check();
             }
 		});
-		current = helpMenu.add(check);
-		current = helpMenu.add(help);
-		//current.setAccelerator(help.shortCut);
-		current = helpMenu.add(about);
-		current.setAccelerator(about.shortCut);
-		current = helpMenu.add(historyinfo);
-		current.setAccelerator(historyinfo.shortCut);
-		add(helpMenu);
+		helpMenu.add(check);
+		current = helpMenu.add(help); // why is help not a JosmAction?
+		current.setAccelerator(ShortCut.registerShortCut("system:help", tr("Help"), KeyEvent.VK_F1, ShortCut.GROUP_DIRECT).getKeyStroke());
+		add(helpMenu, about);
+		add(helpMenu, historyinfo);
+		add(helpMenu, KeyEvent.VK_H, "help");
     }
 }
Index: src/org/openstreetmap/josm/gui/preferences/LafPreference.java
===================================================================
--- src/org/openstreetmap/josm/gui/preferences/LafPreference.java	(revision 1010)
+++ src/org/openstreetmap/josm/gui/preferences/LafPreference.java	(working copy)
@@ -4,6 +4,7 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
 import java.awt.Component;
+import java.lang.reflect.*;
 
 import javax.swing.DefaultListCellRenderer;
 import javax.swing.JComboBox;
@@ -26,6 +27,19 @@
 	public void addGui(PreferenceDialog gui) {
 		lafCombo = new JComboBox(UIManager.getInstalledLookAndFeels());
 		
+		// let's try to load additional LookAndFeels and put them into the list
+		try {
+			Class Cquaqua = Class.forName("ch.randelshofer.quaqua.QuaquaLookAndFeel");
+			Object Oquaqua = Cquaqua.getConstructor((Class[])null).newInstance((Object[])null);
+			// no exception? Then Go!
+			lafCombo.addItem(
+				new UIManager.LookAndFeelInfo(((javax.swing.LookAndFeel)Oquaqua).getName(), "ch.randelshofer.quaqua.QuaquaLookAndFeel")
+			);
+		} catch (Exception ex) {
+			// just ignore, Quaqua may not even be installed...
+			//System.out.println("Failed to load Quaqua: " + ex);
+		}
+
 		String laf = Main.pref.get("laf");
 		for (int i = 0; i < lafCombo.getItemCount(); ++i) {
 			if (((LookAndFeelInfo)lafCombo.getItemAt(i)).getClassName().equals(laf)) {
Index: src/org/openstreetmap/josm/gui/preferences/PreferenceDialog.java
===================================================================
--- src/org/openstreetmap/josm/gui/preferences/PreferenceDialog.java	(revision 1010)
+++ src/org/openstreetmap/josm/gui/preferences/PreferenceDialog.java	(working copy)
@@ -110,6 +110,7 @@
 		settings.add(new PluginPreference());
 		settings.add(Main.toolbar);
 		settings.add(new AudioPreference());
+		settings.add(new ShortcutPreference());
 		
 		for (PluginProxy plugin : Main.plugins) {
 			PreferenceSetting p = plugin.getPreferenceSetting();
Index: src/org/openstreetmap/josm/gui/MapMover.java
===================================================================
--- src/org/openstreetmap/josm/gui/MapMover.java	(revision 1010)
+++ src/org/openstreetmap/josm/gui/MapMover.java	(working copy)
@@ -15,6 +15,8 @@
 import javax.swing.JComponent;
 import javax.swing.JPanel;
 import javax.swing.KeyStroke;
+import org.openstreetmap.josm.tools.ShortCut;
+import static org.openstreetmap.josm.tools.I18n.tr;
 
 import org.openstreetmap.josm.data.coor.EastNorth;
 
@@ -78,16 +80,38 @@
 		nc.addMouseMotionListener(this);
 		nc.addMouseWheelListener(this);
 		
-		String[] n = {",",".","up","right","down","left"};
-		int[] k = {KeyEvent.VK_COMMA, KeyEvent.VK_PERIOD, KeyEvent.VK_UP, KeyEvent.VK_RIGHT, KeyEvent.VK_DOWN, KeyEvent.VK_LEFT};
+		if (contentPane != null) {
+			contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
+				ShortCut.registerShortCut("system:movefocusright", tr("Map: Move right"), KeyEvent.VK_RIGHT, ShortCut.GROUP_HOTKEY).getKeyStroke(),
+				"MapMover.Zoomer.right");
+			contentPane.getActionMap().put("MapMover.Zoomer.right", new ZoomerAction("right"));
 
-		if (contentPane != null) {
-			for (int i = 0; i < n.length; ++i) {
-				contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(k[i], KeyEvent.CTRL_DOWN_MASK), "MapMover.Zoomer."+n[i]);
-				contentPane.getActionMap().put("MapMover.Zoomer."+n[i], new ZoomerAction(n[i]));
+			contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
+				ShortCut.registerShortCut("system:movefocusleft", tr("Map: Move left"), KeyEvent.VK_LEFT, ShortCut.GROUP_HOTKEY).getKeyStroke(),
+				"MapMover.Zoomer.left");
+			contentPane.getActionMap().put("MapMover.Zoomer.left", new ZoomerAction("left"));
+
+			contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
+				ShortCut.registerShortCut("system:movefocusup", tr("Map: Move up"), KeyEvent.VK_UP, ShortCut.GROUP_HOTKEY).getKeyStroke(),
+				"MapMover.Zoomer.up");
+			contentPane.getActionMap().put("MapMover.Zoomer.up", new ZoomerAction("up"));
+
+			contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
+				ShortCut.registerShortCut("system:movefocusdown", tr("Map: Move down"), KeyEvent.VK_DOWN, ShortCut.GROUP_HOTKEY).getKeyStroke(),
+				"MapMover.Zoomer.down");
+			contentPane.getActionMap().put("MapMover.Zoomer.down", new ZoomerAction("down"));
+
+			contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
+				ShortCut.registerShortCut("view:zoominalternate", tr("Map: Zoom in"), KeyEvent.VK_COMMA, ShortCut.GROUP_HOTKEY).getKeyStroke(),
+				"MapMover.Zoomer.in");
+			contentPane.getActionMap().put("MapMover.Zoomer.in", new ZoomerAction(","));
+
+			contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
+				ShortCut.registerShortCut("view:zoomoutalternate", tr("Map: Zoom out"), KeyEvent.VK_PERIOD, ShortCut.GROUP_HOTKEY).getKeyStroke(),
+				"MapMover.Zoomer.out");
+			contentPane.getActionMap().put("MapMover.Zoomer.out", new ZoomerAction("."));
 			}
 		}
-	}
 
 	/**
 	 * If the right (and only the right) mouse button is pressed, move the map
Index: src/org/openstreetmap/josm/gui/MainApplet.java
===================================================================
--- src/org/openstreetmap/josm/gui/MainApplet.java	(revision 1010)
+++ src/org/openstreetmap/josm/gui/MainApplet.java	(working copy)
@@ -28,12 +28,14 @@
 import org.openstreetmap.josm.actions.JosmAction;
 import org.openstreetmap.josm.data.ServerSidePreferences;
 import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.ShortCut;
 
 public class MainApplet extends JApplet {
 
 	public static final class UploadPreferencesAction extends JosmAction {
 		public UploadPreferencesAction() {
-			super(tr("Upload Preferences"), "upload-preferences", tr("Upload the current preferences to the server"), KeyEvent.VK_U, KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK, true);
+			super(tr("Upload Preferences"), "upload-preferences", tr("Upload the current preferences to the server"),
+			ShortCut.registerShortCut("applet:uploadprefs", tr("Upload preferences"), KeyEvent.VK_U, ShortCut.GROUP_HOTKEY), true);
         }
 	    public void actionPerformed(ActionEvent e) {
 	    	((ServerSidePreferences)Main.pref).upload();
Index: src/org/openstreetmap/josm/Main.java
===================================================================
--- src/org/openstreetmap/josm/Main.java	(revision 1010)
+++ src/org/openstreetmap/josm/Main.java	(working copy)
@@ -58,6 +58,11 @@
 import org.openstreetmap.josm.plugins.PluginInformation;
 import org.openstreetmap.josm.plugins.PluginProxy;
 import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.tools.PlatformHook;
+import org.openstreetmap.josm.tools.PlatformHookUnixoid;
+import org.openstreetmap.josm.tools.PlatformHookWindows;
+import org.openstreetmap.josm.tools.PlatformHookOsx;
+import org.openstreetmap.josm.tools.ShortCut;
 
 abstract public class Main {
 	/**
@@ -132,6 +137,14 @@
 	}
 
 	/**
+	 * Platform specific code goes in here.
+	 * Plugins may replace it, however, some hooks will be called before any plugins have been loeaded.
+	 * So if you need to hook into those early ones, split your class and send the one with the early hooks
+	 * to the JOSM team for inclusion.
+	 */
+	public static PlatformHook platform;
+
+	/**
 	 * Set or clear (if passed <code>null</code>) the map.
 	 */
 	public final void setMapFrame(final MapFrame map) {
@@ -177,9 +190,10 @@
 			setMapFrame(null);
 	}
 
-
 	public Main() {
 		main = this;
+//		platform = determinePlatformHook();
+		platform.startupHook();
 		contentPane.add(panel, BorderLayout.CENTER);
 		panel.add(new GettingStarted(), BorderLayout.CENTER);
 		menu = new MainMenu();
@@ -189,7 +203,7 @@
 		// creating toolbar
 		contentPane.add(toolbar.control, BorderLayout.NORTH);
 
-		contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0), "Help");
+		contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(ShortCut.registerShortCut("system:help", tr("Help"), KeyEvent.VK_F1, ShortCut.GROUP_DIRECT).getKeyStroke(), "Help");
 		contentPane.getActionMap().put("Help", menu.help);
 
 		TaggingPresetPreference.initialize();
@@ -414,6 +428,7 @@
 	}
 
 	public static boolean breakBecauseUnsavedChanges() {
+		ShortCut.savePrefs();
 		if (map != null) {
 			boolean modified = false;
 			boolean uploadedModified = false;
@@ -470,4 +485,22 @@
 
 		main.menu.open.openFile(new File(s));
 	}
+
+	protected static void determinePlatformHook() {
+		String os = System.getProperty("os.name");
+		if (os == null) {
+			System.err.println("Your operating system has no name, so I'm guessing its some kind of *nix.");
+			platform = new PlatformHookUnixoid();
+		} else if (os.toLowerCase().startsWith("windows")) {
+			platform = new PlatformHookWindows();
+		} else if (os.equals("Linux") || os.equals("Solaris") || os.equals("SunOS") || os.equals("AIX") || os.equals("FreeBSD")) {
+			platform = new PlatformHookUnixoid();
+		} else if (os.toLowerCase().startsWith("mac os x")) {
+			platform = new PlatformHookOsx();
+		} else {
+			System.err.println("I don't know your operating system '"+os+"', so I'm guessing its some kind of *nix.");
+			platform = new PlatformHookUnixoid();
 }
+	}
+
+}
Index: build.xml
===================================================================
--- build.xml	(revision 1010)
+++ build.xml	(working copy)
@@ -36,7 +36,7 @@
 		<delete file="dist/josm-custom.jar"/>
 		<jar destfile="dist/josm-custom.jar" basedir="build">
 			<manifest>
-				<attribute name="Main-class" value="org.openstreetmap.josm.gui.MainApplication" />
+				<attribute name="Main-class" value="JOSM" />
 			</manifest>
 		</jar>
 	</target>
