--- event-carbon.c.old	Sun Feb 27 18:58:11 2005
+++ event-carbon.c	Sun Feb 27 18:43:11 2005
@@ -17,6 +17,8 @@
 
 #include "console-carbon-impl.h"
 
+EXFUN (Funicode_to_char, 2);  /* In unicode.c.  */
+
 extern Lisp_Object Qcarbon_unicode;  /* From intl-carbon.c.  */
 
 extern SELECT_TYPE process_only_mask;  /* From event-unixoid.c.  */
@@ -35,7 +37,7 @@
 
 static EventLoopTimerUPP timer_proc_UPP;
 
-static debug_carbon_events = 0;
+static int debug_carbon_events = 0;
 
 /* Used in frame-carbon.c.  */
 void carbon_enqueue_user_event (Lisp_Object);
@@ -263,48 +265,145 @@
 }
 
 static void
-handle_keyboard_event (EventRef event)
+enqueue_one_input_event (Lisp_Object keysym, int emacs_modifiers)
+{
+  Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
+  
+  XSET_EVENT_TYPE (emacs_event, key_press_event);
+  XSET_EVENT_CHANNEL (emacs_event, Vselected_console);
+  XSET_EVENT_KEY_KEYSYM (emacs_event, keysym);
+  XSET_EVENT_KEY_MODIFIERS (emacs_event, emacs_modifiers);
+  
+  carbon_enqueue_user_event (emacs_event);
+}
+
+static void
+enqueue_input (UniChar *text, UInt32 text_length, UInt32 modifiers)
 {
-  UInt32 event_kind = GetEventKind (event);
+  int emacs_modifiers = carbon_modifiers_to_emacs_modifiers (modifiers & ~shiftKey);
   
-  if (event_kind == kEventRawKeyDown || event_kind == kEventRawKeyRepeat)
+  for (unsigned int i = 0; i < text_length; i++)
     {
-      UInt32 modifiers;
-      GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(typeUInt32), NULL, &modifiers);
-      int emacs_modifiers = carbon_modifiers_to_emacs_modifiers (modifiers);
+      Lisp_Object emacs_char = Funicode_to_char (make_int (text[i]), Qnil);
+      enqueue_one_input_event (emacs_char, emacs_modifiers);
+    }
+}
+
+/* When the control or command key is down, Carbon doesn't return
+   character codes exactly as expected by XEmacs (e.g., on a
+   U.S. keyboard, C-: is returned as control-shift-';').  Therefore we
+   "reinterpret" the event by calling KeyTranslate or UCKeyTranslate
+   with these modifier keys masked out.  */
+static void
+retranslate_keycode (EventRef keyboard_event, UInt32 modifiers)
+{
+  UInt32 new_modifiers = modifiers & ~controlKey & ~cmdKey;
+  
+  UInt32 keycode;
+  GetEventParameter (keyboard_event, kEventParamKeyCode, typeUInt32, NULL, sizeof (keycode), NULL, &keycode);
+  
+  KeyboardLayoutRef layoutRef;
+  if (KLGetCurrentKeyboardLayout (&layoutRef) != noErr)
+    invalid_operation ("Can't get keyboard layout ref", Qunbound);
+  
+  KeyboardLayoutKind layout_kind;
+  if (KLGetKeyboardLayoutProperty (layoutRef, kKLKind, (const void **)&layout_kind) != noErr)
+    invalid_operation ("Can't get keyboard layout kind", Qunbound);
+
+  /* Depending on whether KCHR or uchr keyboard layout data is
+     available, call KeyTranslate or UCKeyTranslate to determine the
+     actual character code that should be enqueued.  */
+  if (layout_kind == kKLKCHRKind)
+    {
+      void *kchr_ptr;
+      if (KLGetKeyboardLayoutProperty (layoutRef, kKLKCHRData, (const void **)&kchr_ptr) != noErr)
+	invalid_operation ("Can't get KCHR keyboard layout", Qunbound);
     
-      UInt32 keycode;
-      GetEventParameter(event, kEventParamKeyCode, typeUInt32, NULL, sizeof(typeUInt32), NULL, &keycode);
-      
-      Lisp_Object keysym;
-      char *keysymstr = keycode_to_keysymstr_table[keycode & 0x7f];
-      if (keysymstr)
-	keysym = KEYSYM (keysymstr);
-      else
-	{
-	  char charcode;
-	  if (modifiers & (controlKey | optionKey | cmdKey))
-	    {
-	      UInt32 new_keycode = keycode | (modifiers & ~controlKey & ~optionKey & ~cmdKey);
-	      Ptr kchr_ptr = (Ptr) GetScriptManagerVariable (smKCHRCache);
-	      unsigned long some_state = 0;
-	      charcode = KeyTranslate (kchr_ptr, new_keycode, &some_state) & 0xff;
-	    }
-	  else
-	    GetEventParameter(event, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(typeChar), NULL, &charcode);
+      UInt16 new_keycode = new_modifiers & 0xff00;
 
-	  keysym = make_char ((unsigned char)charcode);
-	}
+      if (GetEventKind (keyboard_event) == kEventRawKeyUp)
+	new_keycode |= (1 << 7);
+      
+      new_keycode |= (keycode & 0x7f);
+      
+      static UInt32 deadKeyState = 0;
+      UniChar char_code = KeyTranslate (kchr_ptr, new_keycode, &deadKeyState);
       
-      Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
+      enqueue_input (&char_code, 1, modifiers);
+    }
+  else /* layout_kind == kKLuchrKind || layout_kind == kKLKCHRuchrKind */
+    {
+      UCKeyboardLayout *layout;
+      if (KLGetKeyboardLayoutProperty (layoutRef, kKLuchrData, (const void**)&layout) != noErr)
+	invalid_operation ("Can't get uchr keyboard layout", Qunbound);
       
-      XSET_EVENT_TYPE (emacs_event, key_press_event);
-      XSET_EVENT_CHANNEL (emacs_event, Vselected_console);
-      XSET_EVENT_KEY_KEYSYM (emacs_event, keysym);
-      XSET_EVENT_KEY_MODIFIERS (emacs_event, emacs_modifiers);
+      static UInt32 deadKeyState = 0;
+      UniChar output[16];
+      UniCharCount output_length;
+      if (UCKeyTranslate (layout, keycode, kUCKeyActionDown, new_modifiers >> 8, LMGetKbdType (), 0, &deadKeyState, 16, &output_length, output) != noErr)
+	invalid_operation ("Can't translate key using uchr", Qunbound);
       
-      carbon_enqueue_user_event (emacs_event);
+      enqueue_input (output, output_length, modifiers);
+    }
+}
+
+static OSStatus
+text_input_event_handler (EventHandlerCallRef UNUSED (next_handler), EventRef event, void * UNUSED (data))
+{
+  EventRef keyboard_event;
+  if (GetEventParameter (event, kEventParamTextInputSendKeyboardEvent, typeEventRef, NULL, sizeof (keyboard_event), NULL, &keyboard_event) != noErr)
+    invalid_operation ("Can't get keyboard event", Qunbound);
+  
+  UInt32 modifiers;
+  if (GetEventParameter (keyboard_event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof (modifiers), NULL, &modifiers) != noErr)
+    invalid_operation ("Can't get key modifiers", Qunbound);
+
+  UInt32 keycode;
+  if (GetEventParameter (keyboard_event, kEventParamKeyCode, typeUInt32, NULL, sizeof (typeUInt32), NULL, &keycode) != noErr)
+    invalid_operation ("Can't get key code", Qunbound);
+  
+  char *keysymstr = keycode_to_keysymstr_table[keycode & 0x7f];
+  if (keysymstr)
+    {
+      enqueue_one_input_event (KEYSYM (keysymstr), carbon_modifiers_to_emacs_modifiers (modifiers));
     }
+  else
+    {
+      if (modifiers & (controlKey | cmdKey))
+	{
+	  retranslate_keycode (keyboard_event, modifiers);
+	}
+      else
+	{
+	  UInt32 text_size;
+	  if (GetEventParameter (event, kEventParamTextInputSendText, typeUnicodeText, NULL, 0, &text_size, NULL) != noErr)
+	    invalid_operation ("Can't get input text size", Qunbound);
+    
+	  Extbyte *text = alloca_extbytes (text_size);
+	  if (GetEventParameter (event, kEventParamTextInputSendText, typeUnicodeText, NULL, text_size, NULL, text) != noErr)
+	    invalid_operation ("Can't get input text", Qunbound);
+	  
+	  enqueue_input ((UniChar *)text, text_size / 2, modifiers);
+	}
+    }
+
+  return noErr;
+}
+
+static void
+install_text_input_event_handler (void)
+{
+  EventHandlerUPP ti_handler = NewEventHandlerUPP (text_input_event_handler);
+  
+  EventTypeSpec ti_types[] =
+    {
+      { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent }
+    };
+  
+  if (InstallApplicationEventHandler (ti_handler, sizeof (ti_types) / sizeof (ti_types[0]), ti_types, NULL, NULL) != noErr)
+    invalid_operation ("Can't install text input event handler", Qunbound);
+  
+  DisposeEventHandlerUPP (ti_handler);
 }
 
 static int
@@ -382,8 +481,9 @@
       EventClass event_class = GetEventClass (event);
       UInt32 event_kind = GetEventKind (event);
     
-      if (event_class == kEventClassKeyboard)
-	handle_keyboard_event (event);
+      if (event_class == kEventClassKeyboard || event_class == kEventClassTextInput)
+	/* handle_keyboard_event (event); */
+	generic_send_event_to_target (event);
       else if (event_class == kEventClassMouse && event_kind == kEventMouseMoved)
 	; /* Too many, just ignore it. */
       else if (event_class == kEventClassMouse && event_kind == kEventMouseDown)
@@ -749,6 +849,8 @@
   carbon_process_event_queue_tail = Qnil;
   
   install_apple_event_handlers ();
+
+  install_text_input_event_handler ();
 }
 
 void
