iDevGames Forums

Full Version: [For David, aarku] Carbon Events
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
This is a source file from an old project of mine showing how to use Carbon events for game input. Make of it what you can...

Code:
#include <Carbon/Carbon.h>

#include "EventHandler.hpp"

#include "MacKeyCodes.hpp"

namespace COSI {

int shiftLevel = 0;

ScreenDimension EventHandler::getScreenResolution() {
    ScreenDimension result;
    return result;
}


#define CARBON_ERROR(err) if (err != noErr) { fatalError("Carbon error `%d'\n", err); }

static const EventTypeSpec KEY_EVENTS[] = {
  { kEventClassKeyboard, kEventRawKeyDown },
  { kEventClassKeyboard, kEventRawKeyUp },
  { kEventClassKeyboard, kEventRawKeyModifiersChanged }
};

static const EventTypeSpec MOUSE_EVENTS[] = {
  { kEventClassMouse, kEventMouseDown },
  { kEventClassMouse, kEventMouseUp },
  { kEventClassMouse, kEventMouseMoved },
  { kEventClassMouse, kEventMouseDragged }
};

static const EventTypeSpec WINDOW_EVENTS[] = {
  { kEventClassWindow, kEventWindowBoundsChanged },
    { kEventClassWindow, kEventWindowFocusAcquired },
  { kEventClassWindow, kEventWindowFocusRelinquish },
  { kEventClassWindow, kEventWindowCollapsed },
  { kEventClassWindow, kEventWindowExpanded }
};


Key macToCOSIKeyCode(UInt32 macKeyCode);

Key macToCOSIKeyCode(UInt32 macKeyCode) {
  if (macKeyCode >= NUM_KEY_CODES) {
    return KEY_UNKNOWN;
  }
  Key result = KEY_CODES[macKeyCode];
  
  //debugMessage("Translating %lx to %s\n", macKeyCode, keyName(result).c_str());
  
  return result;
}

OSStatus keyHandler(EventHandlerCallRef hcr, EventRef event, void* p);
OSStatus mouseHandler(EventHandlerCallRef hcr, EventRef event, void* p);
OSStatus appWindowHandler(EventHandlerCallRef hcr, EventRef event, void* p);

void idleTimer(EventLoopTimerRef timer, void *p);

OSStatus keyHandler(EventHandlerCallRef hcr, EventRef event, void* p) {
  EventHandler* handler = (EventHandler*)(p);

  if (GetEventClass(event) != kEventClassKeyboard) {
    fatalError("Carbon error: wrong event class given to handler\n");
  }
  switch(GetEventKind(event)) {
  case kEventRawKeyDown: {
    UInt32 keyCode;
    
    OSStatus error = GetEventParameter(event,
                                       kEventParamKeyCode,
                                       typeUInt32,
                                       NULL,
                                       sizeof(UInt32),
                                       NULL,
                                       &keyCode);
    CARBON_ERROR(error);
    handler->keyPressed(macToCOSIKeyCode(keyCode));
  } break;
  case kEventRawKeyUp: {
    UInt32 keyCode;
    
    OSStatus error = GetEventParameter(event,
                                       kEventParamKeyCode,
                                       typeUInt32,
                                       NULL,
                                       sizeof(UInt32),
                                       NULL,
                                       &keyCode);
    CARBON_ERROR(error);
    handler->keyReleased(macToCOSIKeyCode(keyCode));
  } break;
  case kEventRawKeyModifiersChanged: {
    static UInt32 modifiers = 0;
    UInt32 newModifiers;
    
    OSStatus error = GetEventParameter(event,
                                       kEventParamKeyModifiers,
                                       typeUInt32,
                                       NULL,
                                       sizeof(UInt32),
                                       NULL,
                                       &newModifiers);
    CARBON_ERROR(error);
    
    UInt32 changed = modifiers ^ newModifiers;
      
    if ((changed & cmdKey) != 0) {
      if ((modifiers & cmdKey) != 0) {
        handler->keyReleased(KEY_COMMAND);
      } else {
        handler->keyPressed(KEY_COMMAND);
      }
    }
    if ((changed & (shiftKey | rightShiftKey)) != 0) {
      if ((modifiers & (shiftKey | rightShiftKey)) != 0) {
        handler->keyReleased(KEY_SHIFT);
      } else {
        handler->keyPressed(KEY_SHIFT);
      }
    }
    if ((changed & (optionKey | rightOptionKey)) != 0) {
      if ((modifiers & (optionKey | rightOptionKey)) != 0) {
        handler->keyReleased(KEY_OPTION);
      } else {
        handler->keyPressed(KEY_OPTION);
      }
    }
    if ((changed & (controlKey | rightControlKey)) != 0) {
      if ((modifiers & (controlKey | rightControlKey)) != 0) {
        handler->keyReleased(KEY_CTRL);
      } else {
        handler->keyPressed(KEY_CTRL);
      }
    }
    if ((changed & alphaLock) != 0) {
      if ((modifiers & alphaLock) != 0) {
        handler->keyReleased(KEY_CAPS_LOCK);
      } else {
        handler->keyPressed(KEY_CAPS_LOCK);
      }
    }
    
    modifiers = newModifiers;
    
  } break;
  default:
    fatalError("Carbon error: wrong event kind given to handler\n");
  }
  
  return noErr;
}

OSStatus mouseHandler(EventHandlerCallRef hcr, EventRef event, void* p) {
  static ButtonMask currentButtons = 0;

  EventHandler* handler = (EventHandler*)(p);

  if (GetEventClass(event) != kEventClassMouse) {
    fatalError("Carbon error: wrong event class given to handler\n");
  }
  switch(GetEventKind(event)) {
  case kEventMouseDown: {
    Point where;
    OSStatus error;
    error = GetEventParameter(event,
                              kEventParamMouseLocation,
                              typeQDPoint,
                              NULL,
                              sizeof(where),
                              NULL,
                              &where);
    CARBON_ERROR(error);
    GlobalToLocal(&where);
    
    EventMouseButton button;
    error = GetEventParameter(event,
                              kEventParamMouseButton,
                              typeMouseButton,
                              NULL,
                              sizeof(button),
                              NULL,
                              &button);
    CARBON_ERROR(error);
    
    //debugMessage("Mouse button %d pressed\n", button);
    
    currentButtons |= nthMouseButton(button);
    
    handler->mousePressed(MouseLocation(where.h, where.v),
                          currentButtons,
                          nthMouseButton(button));
  } break;
  case kEventMouseUp: {
    Point where;
    OSStatus error;
    error = GetEventParameter(event,
                              kEventParamMouseLocation,
                              typeQDPoint,
                              NULL,
                              sizeof(where),
                              NULL,
                              &where);
    CARBON_ERROR(error);
    GlobalToLocal(&where);
    
    EventMouseButton button;
    error = GetEventParameter(event,
                              kEventParamMouseButton,
                              typeMouseButton,
                              NULL,
                              sizeof(button),
                              NULL,
                              &button);
    CARBON_ERROR(error);
    
    //debugMessage("Mouse button %d released\n", button);
    
    currentButtons &= ~nthMouseButton(button);
    
    handler->mouseReleased(MouseLocation(where.h, where.v),
                           currentButtons,
                           nthMouseButton(button));
  } break;
  case kEventMouseMoved: case kEventMouseDragged: {
    Point location, delta;
    OSStatus error;
    
    error = GetEventParameter(event,
                              kEventParamMouseLocation,
                              typeQDPoint,
                              NULL,
                              sizeof(location),
                              NULL,
                              &location);
    CARBON_ERROR(error);
    GlobalToLocal(&location);
    
    // kEventParamMouseDelta doesn't work on MacOS < X, so this code
    // will need to be replaced if Carbon COSI is to work on 8.6 or 9.x
    error = GetEventParameter(event,
                              kEventParamMouseDelta,
                              typeQDPoint,
                              NULL,
                              sizeof(delta),
                              NULL,
                              &delta);
    CARBON_ERROR(error);
    
    handler->mouseMoved(MouseLocation(location.h, location.v),
                        MouseDelta(delta.h, delta.v),
                        currentButtons);
  } break;
  default:
    fatalError("Carbon error: wrong event kind given to handler\n");
  }
  
  return noErr;
}

OSStatus appWindowHandler(EventHandlerCallRef hcr, EventRef event, void* p) {
  EventHandler* handler = (EventHandler*)(p);

  if (GetEventClass(event) != kEventClassWindow) {
    fatalError("Carbon error: wrong event class given to handler\n");
  }
  switch(GetEventKind(event)) {
  case kEventWindowBoundsChanged: {
    Rect bounds;
    OSStatus error;
    error = GetEventParameter(event,
                              kEventParamCurrentBounds,
                              typeQDRectangle,
                              NULL,
                              sizeof(bounds),
                              NULL,
                              &bounds);
    CARBON_ERROR(error);
  
    handler->windowResized(ScreenDimension(bounds.right - bounds.left, bounds.bottom - bounds.top));
  } break;
    case kEventWindowFocusAcquired: {
    handler->windowFocus(ACQUIRED);
  } break;
  case kEventWindowFocusRelinquish: {
    handler->windowFocus(LOST);
  } break;
  case kEventWindowCollapsed: {
    handler->windowStatus(MINIMIZED);
  } break;
  case kEventWindowExpanded: {
    handler->windowStatus(UNMINIMIZED);
  } break;
  default:
    fatalError("Carbon error: wrong event kind given to handler\n");
  }
  
  return noErr;
}

void idleTimer(EventLoopTimerRef timer, void *p) {
  EventHandler* handler = (EventHandler*)(p);
  handler->idle();
}
  
EventHandler::EventHandler() {
  OSStatus error;
  error = InstallApplicationEventHandler(NewEventHandlerUPP(keyHandler),
                                         GetEventTypeCount(KEY_EVENTS),
                                         KEY_EVENTS,
                                         this,
                                         NULL);
  CARBON_ERROR(error);
  
  error = InstallApplicationEventHandler(NewEventHandlerUPP(mouseHandler),
                                         GetEventTypeCount(MOUSE_EVENTS),
                                         MOUSE_EVENTS,
                                         this,
                                         NULL);
  CARBON_ERROR(error);
  
  error = InstallApplicationEventHandler(NewEventHandlerUPP(appWindowHandler),
                                         GetEventTypeCount(WINDOW_EVENTS),
                                         WINDOW_EVENTS,
                                         this,
                                         NULL);
  CARBON_ERROR(error);
  
  error = InstallEventLoopTimer(GetMainEventLoop(),              //inEventLoop
                                0,                               //inFireDelay
                                5 * kEventDurationMillisecond,   //inInterval (200 Hz)
                                NewEventLoopTimerUPP(idleTimer), //inTimerProc
                                this,                            //inTimerData,
                                NULL                             //outTimer
                               );
  CARBON_ERROR(error);
}

EventHandler::~EventHandler() {
}

void EventHandler::handleEvents() {
  RunApplicationEventLoop();
}

}
Great post Keith! I was going through an old Carbon project.. and someone had a question about using IME input to enter non-english characters, like é. Can this carbon approach be used with IME?

(No one give me crap about resurrecting an old thread. I'm on topic!)
They might give you crap about resurrecting Carbon though. Wink
This is all deprecated these days... and had nothing to do with input methods in the first place.

For a modern equivalent of this code, see https://github.com/elmindreda/glfw/blob/...a_window.m (but it still doesn't deal with input methods).
Someone give this man a trophy for the oldest thread revival ever. LOL
Reference URL's