Event handling of modifier keys

From TDN

(This code discussion is based on TGE1.5.2 source.)

One of the handy things you can do in Torquescript is bind the modifier keys (shift, control, alt) to the moveMap. For example in my client/scripts/default.bind.cs I toggle the display of certain hud elements when the shift key is pressed;

$is_left_shift_down = 0;
function toggleLeftShift(%val)
{
   echo ("toggleLeftShift(" @ %val @ ")");
   $is_left_shift_down = %val;
   updateSymbolEntryDisplay();
}
moveMap.bind(keyboard, "lshift", toggleLeftShift );

Which works fine in a Windows build. It didn't work for my Mac build however until I made the following substitution in platformMacCarb/macCarbEvents.cc replacing the existing _OnRawModifiers() function with this;

//-----------------------------------------------------------------------------
static OSStatus _OnRawModifiers(EventRef theEvent)
{
   static U32 oldModState = 0L;
   U32 mods;
   GetEventParameter(theEvent, kEventParamKeyModifiers, 
                     typeUInt32, NULL, sizeof(UInt32), NULL, &mods);

   // slesh ---
   // want to notify app of modifier press alone, not just in conjunction with other keys
   // what changed in modifier keys since last modifier notification...
   U32 makeMods = ~oldModState & mods;
   U32 breakMods = oldModState & ~mods;
   
   UInt32   keyCode = 0;
   U32 action = 0;
   if (makeMods & shiftKey) {
      keyCode = KEY_LSHIFT;
      action = SI_MAKE;
   } else if (breakMods & shiftKey) {
      keyCode = KEY_LSHIFT;
      action = SI_BREAK;
   }
   /*if (makeMods & rightShiftKey) {
      keyCode = KEY_RSHIFT;
      if (mods & rightShiftKey)
         action = SI_MAKE;
      else
         action = SI_BREAK;
   }*/
   if (makeMods & cmdKey) {
      keyCode = KEY_LALT;
      action = SI_MAKE;
   } else if (breakMods & cmdKey) {
      keyCode = KEY_LALT;
      action = SI_BREAK;
   }
   if (makeMods & optionKey) {
      keyCode = KEY_LALT; //KEY_MAC_OPT;
      action = SI_MAKE;
   } else if (breakMods & optionKey) {
      keyCode = KEY_LALT; //KEY_MAC_OPT;
      action = SI_BREAK;
   }
   //if (changedMods & rightOptionKey)    keyCode = SI_MAC_ROPT;
   if (makeMods & controlKey) {
      keyCode = KEY_LCONTROL; //SI_LCTRL;
      action = SI_MAKE;
   } else if (breakMods & controlKey) {
      keyCode = KEY_LCONTROL; //SI_LCTRL;
      action = SI_BREAK;
   }
   //if (changedMods & rightControlKey)   keyCode = SI_RCTRL;
   
   InputEvent torqueEvent;
   torqueEvent.deviceType  = KeyboardDeviceType;
   torqueEvent.deviceInst  = 0;
   torqueEvent.objType     = SI_KEY;
   torqueEvent.objInst     = keyCode;
   torqueEvent.modifier    = 0;
   torqueEvent.ascii       = 0;
   torqueEvent.action      = action;
   torqueEvent.fValue      = (action == SI_BREAK) ? 0.0f : 1.0f;
   
   Game->postEvent(torqueEvent);

   // --- end slesh

   oldModState = mods;

   return noErr;  
}

Or something to that effect.

Here is a modified version by Alex Stone which accomodates multiple key-state changes per event.

static OSStatus _OnRawModifiers(EventRef theEvent)
{
   static U32 oldModState = 0L;
   U32 mods;
   GetEventParameter(theEvent, kEventParamKeyModifiers, 
                     typeUInt32, NULL, sizeof(UInt32), NULL, &mods);


   InputEvent evt;
   U32 makeMods = ~oldModState & mods;
   U32 breakMods = oldModState & ~mods;
   
   evt.deviceType  = KeyboardDeviceType;
   evt.deviceInst  = 0;
   evt.objType     = SI_KEY;
   evt.modifier    = 0;
   evt.ascii       = 0;
   //evt.action      = action;
   //evt.fValue      = fvalue;
   
   //Figure out which keys are now up (Break), which ones are now down (Make)
	if(breakMods & shiftKey)
	{
		evt.objInst = KEY_LSHIFT;
		evt.action = SI_BREAK;
		evt.fValue = 0.0f;
		Game->postEvent(evt);
	}
	else if(makeMods & shiftKey)
	{
		evt.objInst = KEY_LSHIFT;
		evt.action = SI_MAKE;
		evt.fValue = 1.0f;
		Game->postEvent(evt);
	}
	
	if(breakMods & rightShiftKey)
	{
		evt.objInst = KEY_RSHIFT;
		evt.action = SI_BREAK;
		evt.fValue = 0.0f;
		Game->postEvent(evt);
	}
	else if(makeMods & rightShiftKey)
	{
		evt.objInst = KEY_RSHIFT;
		evt.action = SI_MAKE;
		evt.fValue = 1.0f;
		Game->postEvent(evt);
	}
	
	if(breakMods & controlKey)
	{
		evt.objInst = KEY_LCONTROL;
		evt.action = SI_BREAK;
		evt.fValue = 0.0f;
		Game->postEvent(evt);
	}
	else if(makeMods & controlKey)
	{
		evt.objInst = KEY_LCONTROL;
		evt.action = SI_MAKE;
		evt.fValue = 1.0f;
		Game->postEvent(evt);
	}
	
	if(breakMods & rightControlKey)
	{
		evt.objInst = KEY_RCONTROL;
		evt.action = SI_BREAK;
		evt.fValue = 0.0f;
		Game->postEvent(evt);
	}
	else if(makeMods & rightControlKey)
	{
		evt.objInst = KEY_RCONTROL;
		evt.action = SI_MAKE;
		evt.fValue = 1.0f;
		Game->postEvent(evt);
	}
	
	if(breakMods & (optionKey | cmdKey))
	{
		evt.objInst = KEY_LALT;
		evt.action = SI_BREAK;
		evt.fValue = 0.0f;
		Game->postEvent(evt);
	}
	else if(makeMods & (optionKey | cmdKey))
	{
		evt.objInst = KEY_LALT;
		evt.action = SI_MAKE;
		evt.fValue = 1.0f;
		Game->postEvent(evt);
	}
	
	if(breakMods & rightOptionKey)
	{
		evt.objInst = KEY_RALT;
		evt.action = SI_BREAK;
		evt.fValue = 0.0f;
		Game->postEvent(evt);
	}
	else if(makeMods & rightOptionKey)
	{
		evt.objInst = KEY_RALT;
		evt.action = SI_MAKE;
		evt.fValue = 1.0f;
		Game->postEvent(evt);
	}
   
   oldModState = mods;

   return noErr;  
}