Index: typo3/sysext/rtehtmlarea/extensions/CopyPaste/class.tx_rtehtmlarea_copypaste.php
===================================================================
--- typo3/sysext/rtehtmlarea/extensions/CopyPaste/class.tx_rtehtmlarea_copypaste.php	(révision 4939)
+++ typo3/sysext/rtehtmlarea/extensions/CopyPaste/class.tx_rtehtmlarea_copypaste.php	(copie de travail)
@@ -42,26 +42,29 @@
 	protected $thisConfig;						// Reference to RTE PageTSConfig
 	protected $toolbar;						// Reference to RTE toolbar array
 	protected $LOCAL_LANG; 						// Frontend language array
-	
 	protected $pluginButtons = 'copy, cut, paste';
 	protected $convertToolbarForHtmlAreaArray = array (
 		'copy'	=> 'Copy',
 		'cut'	=> 'Cut',
 		'paste'	=> 'Paste',
 		);
-	protected $hideButtonsFromClient = array (			// Hide buttons not implemented in client browsers
+		// Hide buttons not implemented in client browsers
+	protected $hideButtonsFromClient = array (
 		'safari'	=>	array('paste'),
+		'opera'		=>	array('copy', 'cut', 'paste'),
  		);
-	
+
 	public function main($parentObject) {
-		$enabled = parent::main($parentObject) && $this->htmlAreaRTE->client['BROWSER'] != 'opera';
+		$enabled = parent::main($parentObject);
 			// Hiding some buttons
 		if ($enabled && is_array($this->hideButtonsFromClient[$this->htmlAreaRTE->client['BROWSER']])) {
 			$this->pluginButtons = implode(',', array_diff(t3lib_div::trimExplode(',', $this->pluginButtons, 1), $this->hideButtonsFromClient[$this->htmlAreaRTE->client['BROWSER']]));
 		}
+			// Force enabling the plugin even if no button remains in the tool bar, so that hot keys still are enabled
+		$this->pluginAddsButtons = false;
 		return $enabled;
 	}
-	
+
 	/**
 	 * Return JS configuration of the htmlArea plugins registered by the extension
 	 *
@@ -80,10 +83,24 @@
 		return $registerRTEinJavascriptString;
 	}
 
-} // end of class
+	/**
+	 * Return an updated array of toolbar enabled buttons
+	 *
+	 * @param	array		$show: array of toolbar elements that will be enabled, unless modified here
+	 *
+	 * @return 	array		toolbar button array, possibly updated
+	 */
+	public function applyToolbarConstraints($show) {
+			// Remove some buttons
+		if (is_array($this->hideButtonsFromClient[$this->htmlAreaRTE->client['BROWSER']])) {
+			return array_diff($show, $this->hideButtonsFromClient[$this->htmlAreaRTE->client['BROWSER']]);
+		} else {
+			return $show;
+		}
+	}
+}
 
 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/rtehtmlarea/extensions/CopyPaste/class.tx_rtehtmlarea_copypaste.php']) {
 	include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/rtehtmlarea/extensions/CopyPaste/class.tx_rtehtmlarea_copypaste.php']);
 }
-
 ?>
\ No newline at end of file
Index: typo3/sysext/rtehtmlarea/htmlarea/htmlarea.js
===================================================================
--- typo3/sysext/rtehtmlarea/htmlarea/htmlarea.js	(révision 4939)
+++ typo3/sysext/rtehtmlarea/htmlarea/htmlarea.js	(copie de travail)
@@ -1875,6 +1875,7 @@
 							}
 						}
 				}
+				return true;
 			}
 		} else if (ev.altKey) {
 				// check if context menu is already handling this event
@@ -1891,6 +1892,7 @@
 					}
 				}
 			}
+			return true;
 		} else if (keyEvent) {
 			if (HTMLArea.is_gecko) editor._detectURL(ev);
 			switch (ev.keyCode) {
@@ -3044,7 +3046,7 @@
 	makeFunctionReference : function (functionName) {
 		var self = this;
 		return (function(arg1, arg2) {
-			self[functionName](arg1, arg2);});
+			return (self[functionName](arg1, arg2));});
 	},
 
 	/**
Index: typo3/sysext/rtehtmlarea/htmlarea/plugins/CopyPaste/copy-paste.js
===================================================================
--- typo3/sysext/rtehtmlarea/htmlarea/plugins/CopyPaste/copy-paste.js	(révision 4939)
+++ typo3/sysext/rtehtmlarea/htmlarea/plugins/CopyPaste/copy-paste.js	(copie de travail)
@@ -1,7 +1,7 @@
 /***************************************************************
 *  Copyright notice
 *
-*  (c) 2008 Stanislas Rolland <typo3(arobas)sjbr.ca>
+*  (c) 2008-2009 Stanislas Rolland <typo3(arobas)sjbr.ca>
 *  All rights reserved
 *
 *  This script is part of the TYPO3 project. The TYPO3 project is
@@ -73,9 +73,16 @@
 					hotKey		: (this.buttonsConfiguration[button[2]] ? this.buttonsConfiguration[button[2]].hotKey : (button[1] ? button[1] : null))
 				};
 				this.registerButton(buttonConfiguration);
+				if (!this.isButtonInToolbar(buttonId)) {
+					var hotKeyConfiguration = {
+						id	: buttonConfiguration.hotKey,
+						cmd	: buttonConfiguration.id,
+						action	: buttonConfiguration.action
+					};
+					this.registerHotKey(hotKeyConfiguration);
+				}
 			}
 		}
-		
 		return true;
 	 },
 	 
@@ -103,28 +110,36 @@
 		buttonId = buttonId ? buttonId : id;
 		this.editor.focusEditor();
 		if (!this.applyToTable(buttonId, target)) {
+				// If we are not handling table cells
 			switch (buttonId) {
 				case "Copy":
 				case "Cut" :
-					this.applyBrowserCommand(buttonId);
+					if (buttonId == id) {
+							// If we are handling a button, not a hotkey
+						this.applyBrowserCommand(buttonId);
+					}
 					break;
 				case "Paste":
-					if (!HTMLArea.is_opera) {
-						this.applyBrowserCommand(buttonId, (buttonId != id));
+					if (buttonId == id) {
+							// If we are handling a button, not a hotkey
+						this.applyBrowserCommand(buttonId, true);
 					}
-						// In FF3, the paste operation will indeed trigger the paste event
+						// In FF3, the paste operation will indeed trigger the onPaste even; not in FF2; nor in Opera
 					if (HTMLArea.is_opera || (HTMLArea.is_gecko && navigator.productSub < 2008020514)) {
-						if (this.editor._toolbarObjects.CleanWord) {
-							var cleanLaterFunctRef = this.editor.plugins.DefaultClean ? this.editor.plugins.DefaultClean.instance.cleanLaterFunctRef : (this.editor.plugins.TYPO3HtmlParser ? this.editor.plugins.TYPO3HtmlParser.instance.cleanLaterFunctRef : null);
-							if (cleanLaterFunctRef) {
-								window.setTimeout(cleanLaterFunctRef, 50);
-							}
+						var cleanLaterFunctRef = this.editor.getPluginInstance("DefaultClean") ? this.editor.getPluginInstance("DefaultClean").cleanLaterFunctRef : (this.editor.getPluginInstance("TYPO3HtmlParser") ? this.editor.getPluginInstance("TYPO3HtmlParser").cleanLaterFunctRef : null);
+						if (cleanLaterFunctRef) {
+							window.setTimeout(cleanLaterFunctRef, 50);
 						}
 					}
 					break;
+				default:
+					break;
 			}
+			return (buttonId != id);
+		} else {
+				// We handled the table case
+			return false;
 		}
-		return false;
 	},
 	
 	applyBrowserCommand : function (buttonId, buttonPress) {
