Assuming you're running Emacs directly under a windowing system (Cocoa, MS-DOS, Windows, X, ...) and not inside a text terminal (gnome-terminal, konsole, rxvt, xterm, ...), it's possible.
(define-key key-translation-map [?\C-\ [(control left_bracket)])
(define-key key-translation-map [escape] [?\e])
(define-key function-key-map [escape] nil)
(define-key function-key-map [?\e] nil)
(when (boundp 'local-function-key-map)
;;(define-key local-function-key-map [escape] nil)
(defun remove-escape-from-local-function-key-map ()
(define-key local-function-key-map [?\e] nil)
(define-key local-function-key-map [escape] nil))
(add-hook 'term-setup-hook 'remove-escape-from-local-function-key-map))
There are three different input events at play here:
Ctrl+[, i.e., the
control modifier together with a key that sends the character
[. Emacs would normally show this as
C-[ accepted by
kbd), if it didn't have a special case for this, as explained below.
Character number 27, which is sent by the Esc key on some systems. Emacs shows this as
ESC when displaying key sequences, and
\e in strings.
The Esc key itself (in X Window, this means the
Escape keysym). Emacs shows this as
escape unless translated (see below).
Emacs normally translates
ESC, but this is done at a relatively high level, in
function-key-map, so it can be overridden by modifying
function-key-map or by defining a binding for
escape in the global keymap or a local keymap. GNU Emacs 23 introduces
local-function-key-map which applies per terminal type.
Emacs always translates
ESC, at a very low level (in
keyboard.c). This is not configurable.
However Emacs provides a way to translate keys at a relatively low level:
key-translation-map. This applies before any global or local binding, but only for keys that are not in
function-key-map. So the trick is to exchange
escape at that point.
These mechanisms are described in the Emacs Lisp manual under the heading "Translation keymaps".
By the way, similar principles apply to