Index: /FCKeditor/trunk/editor/_source/commandclasses/fck_othercommands.js
===================================================================
--- /FCKeditor/trunk/editor/_source/commandclasses/fck_othercommands.js	(revision 392)
+++ /FCKeditor/trunk/editor/_source/commandclasses/fck_othercommands.js	(revision 393)
@@ -231,16 +231,10 @@
 FCKUndoCommand.prototype.Execute = function()
 {
-	if ( FCKBrowserInfo.IsIE )
-		FCKUndo.Undo() ;
-	else
-		FCK.ExecuteNamedCommand( 'Undo' ) ;
+	FCKUndo.Undo() ;
 }
 
 FCKUndoCommand.prototype.GetState = function()
 {
-	if ( FCKBrowserInfo.IsIE )
-		return ( FCKUndo.CheckUndoState() ? FCK_TRISTATE_OFF : FCK_TRISTATE_DISABLED ) ;
-	else
-		return FCK.GetNamedCommandState( 'Undo' ) ;
+	return ( FCKUndo.CheckUndoState() ? FCK_TRISTATE_OFF : FCK_TRISTATE_DISABLED ) ;
 }
 
@@ -253,16 +247,10 @@
 FCKRedoCommand.prototype.Execute = function()
 {
-	if ( FCKBrowserInfo.IsIE )
-		FCKUndo.Redo() ;
-	else
-		FCK.ExecuteNamedCommand( 'Redo' ) ;
+	FCKUndo.Redo() ;
 }
 
 FCKRedoCommand.prototype.GetState = function()
 {
-	if ( FCKBrowserInfo.IsIE )
-		return ( FCKUndo.CheckRedoState() ? FCK_TRISTATE_OFF : FCK_TRISTATE_DISABLED ) ;
-	else
-		return FCK.GetNamedCommandState( 'Redo' ) ;
+	return ( FCKUndo.CheckRedoState() ? FCK_TRISTATE_OFF : FCK_TRISTATE_DISABLED ) ;
 }
 
Index: /FCKeditor/trunk/editor/_source/internals/fck_gecko.js
===================================================================
--- /FCKeditor/trunk/editor/_source/internals/fck_gecko.js	(revision 392)
+++ /FCKeditor/trunk/editor/_source/internals/fck_gecko.js	(revision 393)
@@ -26,4 +26,32 @@
 FCK.Description = "FCKeditor for Gecko Browsers" ;
 
+FCK._KeyDownUndo = function()
+{
+	if ( !FCKUndo.Typing )
+	{
+		FCKUndo.SaveUndoStep() ;
+		FCKUndo.Typing = true ;
+		FCK.Events.FireEvent( "OnSelectionChange" ) ;
+	}
+
+	FCKUndo.TypesCount++ ;
+
+	if ( FCKUndo.TypesCount > FCKUndo.MaxTypes )
+	{
+		FCKUndo.TypesCount = 0 ;
+		FCKUndo.SaveUndoStep() ;
+	}
+}
+
+FCK._KeyDownListener = function( evt )
+{
+	if ( FCK.EditorWindow )
+	{
+		if ( !( evt.keyCode >= 16 && evt.keyCode <= 18 ) )
+			FCK._KeyDownUndo();
+	}
+	return true;
+}
+
 FCK.InitializeBehaviors = function()
 {
@@ -59,4 +87,7 @@
 	}
 	this.EditorDocument.addEventListener( 'dblclick', this._DblClickListener, true ) ;
+
+	// Record changes for the undo system when there are key down events.
+	this.EditorDocument.addEventListener( 'keydown', this._KeyDownListener, false ) ;
 
 	// Reset the context menu.
Index: /FCKeditor/trunk/editor/_source/internals/fckundo_gecko.js
===================================================================
--- /FCKeditor/trunk/editor/_source/internals/fckundo_gecko.js	(revision 392)
+++ /FCKeditor/trunk/editor/_source/internals/fckundo_gecko.js	(revision 393)
@@ -24,4 +24,92 @@
 var FCKUndo = new Object() ;
 
+FCKUndo.SavedData = new Array() ;
+FCKUndo.CurrentIndex = -1 ;
+FCKUndo.TypesCount = FCKUndo.MaxTypes = 25 ;
+FCKUndo.Typing = false;
+
 FCKUndo.SaveUndoStep = function()
-{}
+{
+	if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG )
+		return ;
+
+	// Shrink the array to the current level.
+	FCKUndo.SavedData = FCKUndo.SavedData.slice( 0, FCKUndo.CurrentIndex + 1 ) ;
+
+	// Get the Actual HTML.
+	var sHtml = FCK.EditorDocument.body.innerHTML ;
+
+	// Cancel operation if the new step is identical to the previous one.
+	if ( FCKUndo.CurrentIndex >= 0 && sHtml == FCKUndo.SavedData[ FCKUndo.CurrentIndex ][0] )
+		return ;
+
+	// If we reach the Maximun number of undo levels, we must remove the first
+	// entry of the list shifting all elements.
+	if ( FCKUndo.CurrentIndex + 1 >= FCKConfig.MaxUndoLevels )
+		FCKUndo.SavedData.shift() ;
+	else
+		FCKUndo.CurrentIndex++ ;
+
+	// Get the actual selection.
+	// TODO: How to handle this in Gecko?
+
+	// Save the new level in front of the actual position.
+	FCKUndo.SavedData[ FCKUndo.CurrentIndex ] = [ sHtml, null ] ;
+
+	FCK.Events.FireEvent( "OnSelectionChange" ) ;
+}
+
+FCKUndo.CheckUndoState = function()
+{
+	return ( FCKUndo.Typing || FCKUndo.CurrentIndex > 0 ) ;
+}
+
+FCKUndo.CheckRedoState = function()
+{
+	return ( !FCKUndo.Typing && FCKUndo.CurrentIndex < ( FCKUndo.SavedData.length - 1 ) ) ;
+}
+
+FCKUndo.Undo = function()
+{
+	if ( FCKUndo.CheckUndoState() )
+	{
+		// If it is the first step.
+		if ( FCKUndo.CurrentIndex == ( FCKUndo.SavedData.length - 1 ) )
+		{
+			// Save the actual state for a possible "Redo" call.
+			FCKUndo.SaveUndoStep() ;
+		}
+
+		// Go a step back.
+		FCKUndo._ApplyUndoLevel( --FCKUndo.CurrentIndex ) ;
+
+		FCK.Events.FireEvent( "OnSelectionChange" ) ;
+	}
+}
+
+FCKUndo.Redo = function()
+{
+	if ( FCKUndo.CheckRedoState() )
+	{
+		// Go a step forward.
+		FCKUndo._ApplyUndoLevel( ++FCKUndo.CurrentIndex ) ;
+
+		FCK.Events.FireEvent( "OnSelectionChange" ) ;
+	}
+}
+
+FCKUndo._ApplyUndoLevel = function(level)
+{
+	var oData = FCKUndo.SavedData[ level ] ;
+
+	if ( !oData )
+		return ;
+
+	// Update the editor contents with that step data.
+	FCK.EditorDocument.body.innerHTML = oData[0] ;
+
+	// TODO: Restore selection in Gecko
+
+	FCKUndo.TypesCount = 0 ;
+	FCKUndo.Typing = false ;
+}
Index: /FCKeditor/trunk/editor/_source/internals/fckundo_ie.js
===================================================================
--- /FCKeditor/trunk/editor/_source/internals/fckundo_ie.js	(revision 392)
+++ /FCKeditor/trunk/editor/_source/internals/fckundo_ie.js	(revision 393)
