예제 #1
0
void HIDGamepad::valueChanged(IOHIDValueRef value)
{
    IOHIDElementCookie cookie = IOHIDElementGetCookie(IOHIDValueGetElement(value));
    HIDGamepadElement* element = m_elementMap.get(cookie);

    // This might be an element we don't currently handle as input so we can skip it.
    if (!element)
        return;

    element->rawValue = IOHIDValueGetScaledValue(value, kIOHIDValueScaleTypePhysical);

    if (element->isButton()) {
        for (unsigned i = 0; i < m_buttons.size(); ++i) {
            if (m_buttons[i].get() == element)
                m_buttonValues[i] = element->normalizedValue();
        }
    } else if (element->isAxis()) {
        for (unsigned i = 0; i < m_axes.size(); ++i) {
            if (m_axes[i].get() == element)
                m_axisValues[i] = element->normalizedValue();
        }
    } else
        ASSERT_NOT_REACHED();

    m_lastUpdateTime = monotonicallyIncreasingTime();
}
예제 #2
0
static void input_callback(void *ctx, IOReturn result, void *sender, IOHIDValueRef value)
{
	struct osx_mouse_data *mdata = static_cast<struct osx_mouse_data *>(ctx);
	IOHIDElementRef elem = IOHIDValueGetElement(value);
	uint32_t page = IOHIDElementGetUsagePage(elem);
	uint32_t usage = IOHIDElementGetUsage(elem);
	uint32_t val = IOHIDValueGetIntegerValue(value);

	if (page == kHIDPage_GenericDesktop) {
		switch (usage) {
			case kHIDUsage_GD_X:
				SDL_LockMutex(mdata->mouse_mutex);
				mdata->mouse_x += val;
				SDL_UnlockMutex(mdata->mouse_mutex);
				break;
			case kHIDUsage_GD_Y:
				SDL_LockMutex(mdata->mouse_mutex);
				mdata->mouse_y += val;
				SDL_UnlockMutex(mdata->mouse_mutex);
				break;
			default:
				break;
		}
	}
}
예제 #3
0
// NOTE: I pieced this together through trial and error, any corrections are welcome
static void hid_device_input_callback(void* context, IOReturn result, void* sender, IOHIDValueRef value)
{
   struct apple_pad_connection* connection = (struct apple_pad_connection*)context;

   IOHIDElementRef element = IOHIDValueGetElement(value);
   uint32_t type = IOHIDElementGetType(element);
   uint32_t page = IOHIDElementGetUsagePage(element);
   uint32_t use = IOHIDElementGetUsage(element);

   // Joystick handler: TODO: Can GamePad work the same?
   if (type == kIOHIDElementTypeInput_Button && page == kHIDPage_Button)
   {
      CFIndex state = IOHIDValueGetIntegerValue(value);

      if (state)  g_current_input_data.pad_buttons[connection->slot] |= (1 << (use - 1));
      else        g_current_input_data.pad_buttons[connection->slot] &= ~(1 << (use - 1));
   }
   else if (type == kIOHIDElementTypeInput_Misc && page == kHIDPage_GenericDesktop)
   {
      static const uint32_t axis_use_ids[4] = { 48, 49, 50, 53 };
      for (int i = 0; i < 4; i ++)
      {
         if (use == axis_use_ids[i])
         {
            CFIndex min = IOHIDElementGetPhysicalMin(element);
            CFIndex max = IOHIDElementGetPhysicalMax(element) - min;
            CFIndex state = IOHIDValueGetIntegerValue(value) - min;
         
            float val = (float)state / (float)max;
            g_current_input_data.pad_axis[connection->slot][i] = ((val * 2.0f) - 1.0f) * 32767.0f;
         }
      }
   }
}
  void
  osxHIDPointingDevice::hidQueueCallback(void *context, IOReturn /*result*/, void *sender) {
    // std::cerr << "osxHIDPointingDevice::hidQueueCallback" << std::endl ;
    
    osxHIDPointingDevice *self = (osxHIDPointingDevice*)context ;
    IOHIDQueueRef queue = (IOHIDQueueRef)sender ;

    while (true) {

      IOHIDValueRef hidvalue = IOHIDQueueCopyNextValueWithTimeout(queue, 0.) ;
      if (!hidvalue) break ;

#if 1
      TimeStamp::inttime uptime = AbsoluteTimeInNanoseconds(IOHIDValueGetTimeStamp(hidvalue)) ;
      TimeStamp::inttime timestamp = self->epoch + (uptime - self->epoch_mach)*TimeStamp::one_nanosecond ;
#else

      TimeStamp::inttime timestamp = TimeStamp::createAsInt() ;
#endif

      if (self->qreport.isOlderThan(timestamp)) {
	// Flush the old qreport before creating a new one
	self->report(self->qreport) ;
	self->qreport.clear() ;
      }

      IOHIDElementRef element = IOHIDValueGetElement(hidvalue) ;
      uint32_t usagepage = IOHIDElementGetUsagePage(element) ;
      uint32_t usage = IOHIDElementGetUsage(element) ;
      //std::cout << usagepage << std::endl;
      //std::cout << usage << std::endl;
      if (usagepage==kHIDPage_GenericDesktop) {
	if (usage==kHIDUsage_GD_X || usage==kHIDUsage_GD_Y) {
      // Could use IOHIDValueGetScaledValue(hidvalue, kIOHIDValueScaleTypePhysical)
      CFIndex d = IOHIDValueGetIntegerValue(hidvalue) ;

      //std::cout << IOHIDValueGetBytePtr(hidvalue) << std::endl;
      //std::cout << IOHIDValueGetLength(hidvalue) << std::endl;
      if (d) {
	    if (usage==kHIDUsage_GD_X) self->qreport.dx = (int32_t)d ; else self->qreport.dy = (int32_t)d ;
	    self->qreport.t = timestamp ;
	  }
	}
	// FIXME: GD_Z, GD_Wheel, etc.
      } else if (usagepage==kHIDPage_Button) {
	// kHIDUsage_Button_1 is 1
	self->qreport.setButton(usage-1, (uint32_t)IOHIDValueGetIntegerValue(hidvalue)) ;
	self->qreport.t = timestamp ;
      }

      CFRelease(hidvalue) ;
    }

    // Flush the qreport we were constructing, if any
    if (self->qreport.t!=TimeStamp::undef)
      self->report(self->qreport) ;
    self->qreport.clear() ;
  }
예제 #5
0
void CPH_HidMacOSX::InputValueCallback(IOHIDValueRef valueRef)
{
	IOHIDElementRef elementRef = IOHIDValueGetElement(valueRef);
	uint32 usage = IOHIDElementGetUsage(elementRef);
	uint32 usagePage = IOHIDElementGetUsagePage(elementRef);
	CFIndex state = IOHIDValueGetIntegerValue(valueRef);
	if(usagePage != kHIDPage_KeyboardOrKeypad) return;
	for(auto bindingIterator(std::begin(m_bindings));
	    bindingIterator != std::end(m_bindings); bindingIterator++)
	{
		const auto& binding = (*bindingIterator);
		if(!binding) continue;
		binding->ProcessEvent(usage, state);
	}
}
예제 #6
0
void HIDGamepadProvider::valuesChanged(IOHIDValueRef value)
{
    IOHIDDeviceRef device = IOHIDElementGetDevice(IOHIDValueGetElement(value));

    HIDGamepad* gamepad = m_gamepadMap.get(device);

    // When starting monitoring we might get a value changed callback before we even know the device is connected.
    if (!gamepad)
        return;

    gamepad->valueChanged(value);

    // This isActive check is necessary as we want to delay input notifications from the time of the first input,
    // and not push the notification out on every subsequent input.
    if (!m_inputNotificationTimer.isActive())
        m_inputNotificationTimer.startOneShot(InputNotificationDelay);
}
예제 #7
0
HIDInputType HIDGamepad::valueChanged(IOHIDValueRef value)
{
    IOHIDElementCookie cookie = IOHIDElementGetCookie(IOHIDValueGetElement(value));
    HIDGamepadElement* element = m_elementMap.get(cookie);

    // This might be an element we don't currently handle as input so we can skip it.
    if (!element)
        return HIDInputType::NotAButtonPress;

    element->rawValue = IOHIDValueGetScaledValue(value, kIOHIDValueScaleTypePhysical);

    if (element->isButton()) {
        for (unsigned i = 0; i < m_buttons.size(); ++i) {
            if (&m_buttons[i].get() == element) {
                m_buttonValues[i] = element->normalizedValue();
                break;
            }
        }
    } else if (element->isAxis()) {
        for (unsigned i = 0; i < m_axes.size(); ++i) {
            if (&m_axes[i].get() == element) {
                m_axisValues[i] = element->normalizedValue();
                break;
            }
        }
    } else if (element->isDPad()) {
        int intValue = IOHIDValueGetIntegerValue(value) - element->min;
        for (unsigned i = 0; i < m_dPads.size(); ++i) {
            if (&m_dPads[i].get() != element)
                continue;

            // Each DPad represents 4 button values which are tacked on to the end of the values from non-DPad buttons.
            unsigned firstButtonValue = m_buttons.size() + i * 4;

            ASSERT(m_buttonValues.size() > firstButtonValue + 3);

            fillInButtonValues(intValue, m_buttonValues[firstButtonValue], m_buttonValues[firstButtonValue + 1], m_buttonValues[firstButtonValue + 2], m_buttonValues[firstButtonValue + 3]);
        }
    } else
        ASSERT_NOT_REACHED();

    m_lastUpdateTime = monotonicallyIncreasingTime();

    return element->isButton() ? HIDInputType::ButtonPress : HIDInputType::NotAButtonPress;
}
예제 #8
0
 static void hid_event(void* userdata, IOReturn result, void* sender, IOHIDValueRef value) {
     EventBridge* self = reinterpret_cast<EventBridge*>(userdata);
     IOHIDElementRef element = IOHIDValueGetElement(value);
     uint32_t usage_page = IOHIDElementGetUsagePage(element);
     switch (usage_page) {
       case kHIDPage_KeyboardOrKeypad:
         self->key_event(result, element, value);
         break;
       case kHIDPage_GenericDesktop:
         self->analog_event(result, element, value);
         break;
       case kHIDPage_Button:
         self->button_event(result, element, value);
         break;
       default:
         sfz::print(sfz::io::err, sfz::format("{0}\n", usage_page));
         break;
     }
 }
예제 #9
0
void CInputProviderMacOsHid::InputValueCallback(DEVICE_INFO* deviceInfo, IOReturn result, void* sender, IOHIDValueRef valueRef)
{
	if(!OnInput) return;

	IOHIDElementRef elementRef = IOHIDValueGetElement(valueRef);
	uint32 usagePage = IOHIDElementGetUsagePage(elementRef);
	if(
	    (usagePage != kHIDPage_GenericDesktop) &&
	    (usagePage != kHIDPage_Button))
	{
		return;
	}
	uint32 usage = IOHIDElementGetUsage(elementRef);
	CFIndex value = IOHIDValueGetIntegerValue(valueRef);
	IOHIDElementType type = IOHIDElementGetType(elementRef);
	BINDINGTARGET tgt;
	tgt.providerId = PROVIDER_ID;
	tgt.deviceId = deviceInfo->deviceId;
	tgt.keyId = usage;
	tgt.keyType = GetKeyType(usage, type);
	OnInput(tgt, value);
}
예제 #10
0
static void onDeviceValueChanged(void * context, IOReturn result, void * sender, IOHIDValueRef value) {
  struct Gamepad_device * deviceRecord;
  struct Gamepad_devicePrivate * hidDeviceRecord;
  IOHIDElementRef element;
  IOHIDElementCookie cookie;
  unsigned int axisIndex, buttonIndex;
  static mach_timebase_info_data_t timebaseInfo;
	
  if (timebaseInfo.denom == 0) {
    mach_timebase_info(&timebaseInfo);
  }
	
  deviceRecord = context;
  hidDeviceRecord = deviceRecord->privateData;
  element = IOHIDValueGetElement(value);
  cookie = IOHIDElementGetCookie(element);
	
  for (axisIndex = 0; axisIndex < deviceRecord->numAxes; axisIndex++) {
    if (!hidDeviceRecord->axisElements[axisIndex].isHatSwitchSecondAxis &&
        hidDeviceRecord->axisElements[axisIndex].cookie == cookie) {
      CFIndex integerValue;
			
      if (IOHIDValueGetLength(value) > 4) {
        // Workaround for a strange crash that occurs with PS3 controller; was getting lengths of 39 (!)
        continue;
      }
      integerValue = IOHIDValueGetIntegerValue(value);
			
      if (hidDeviceRecord->axisElements[axisIndex].isHatSwitch) {
        int x, y;
				
        // Fix for Saitek X52
        if (!hidDeviceRecord->axisElements[axisIndex].hasNullState) {
          if (integerValue < hidDeviceRecord->axisElements[axisIndex].logicalMin) {
            integerValue = hidDeviceRecord->axisElements[axisIndex].logicalMax - hidDeviceRecord->axisElements[axisIndex].logicalMin + 1;
          } else {
            integerValue--;
          }
        }
				
        hatValueToXY(integerValue, hidDeviceRecord->axisElements[axisIndex].logicalMax - hidDeviceRecord->axisElements[axisIndex].logicalMin + 1, &x, &y);
				
        if (x != deviceRecord->axisStates[axisIndex]) {
          queueAxisEvent(deviceRecord,
                         IOHIDValueGetTimeStamp(value) * timebaseInfo.numer / timebaseInfo.denom * 0.000000001,
                         axisIndex,
                         x,
                         deviceRecord->axisStates[axisIndex]);
					
          deviceRecord->axisStates[axisIndex] = x;
        }
				
        if (y != deviceRecord->axisStates[axisIndex + 1]) {
          queueAxisEvent(deviceRecord,
                         IOHIDValueGetTimeStamp(value) * timebaseInfo.numer / timebaseInfo.denom * 0.000000001,
                         axisIndex + 1,
                         y,
                         deviceRecord->axisStates[axisIndex + 1]);
					
          deviceRecord->axisStates[axisIndex + 1] = y;
        }
				
      } else {
        float floatValue;
				
        if (integerValue < hidDeviceRecord->axisElements[axisIndex].logicalMin) {
          hidDeviceRecord->axisElements[axisIndex].logicalMin = integerValue;
        }
        if (integerValue > hidDeviceRecord->axisElements[axisIndex].logicalMax) {
          hidDeviceRecord->axisElements[axisIndex].logicalMax = integerValue;
        }
        floatValue = (integerValue - hidDeviceRecord->axisElements[axisIndex].logicalMin) / (float) (hidDeviceRecord->axisElements[axisIndex].logicalMax - hidDeviceRecord->axisElements[axisIndex].logicalMin) * 2.0f - 1.0f;
				
        queueAxisEvent(deviceRecord,
                       IOHIDValueGetTimeStamp(value) * timebaseInfo.numer / timebaseInfo.denom * 0.000000001,
                       axisIndex,
                       floatValue,
                       deviceRecord->axisStates[axisIndex]);
				
        deviceRecord->axisStates[axisIndex] = floatValue;
      }
			
      return;
    }
  }
	
  for (buttonIndex = 0; buttonIndex < deviceRecord->numButtons; buttonIndex++) {
    if (hidDeviceRecord->buttonElements[buttonIndex].cookie == cookie) {
      bool down;
			
      down = IOHIDValueGetIntegerValue(value);
      queueButtonEvent(deviceRecord,
                       IOHIDValueGetTimeStamp(value) * timebaseInfo.numer / timebaseInfo.denom * 0.000000001,
                       buttonIndex,
                       down);
			
      deviceRecord->buttonStates[buttonIndex] = down;
			
      return;
    }
  }
}
예제 #11
0
static void input_callback(void *context, IOReturn result, void *sender, IOHIDValueRef value)
{
	struct input_data *input = (struct input_data*)context;
	IOHIDElementRef elem = IOHIDValueGetElement(value);
	uint32_t page = IOHIDElementGetUsagePage(elem);
	uint32_t usage = IOHIDElementGetUsage(elem);
	uint32_t val = IOHIDValueGetIntegerValue(value);

	if (page == kHIDPage_GenericDesktop)
	{
		if (input->ignore_mouse)
		{
			return;
		}

		switch (usage)
		{
			case kHIDUsage_GD_X:
				pthread_mutex_lock(&input->mouse_mutex);
				input->mouse_x += val;
				pthread_mutex_unlock(&input->mouse_mutex);
				break;
			case kHIDUsage_GD_Y:
				pthread_mutex_lock(&input->mouse_mutex);
				input->mouse_y += val;
				pthread_mutex_unlock(&input->mouse_mutex);
				break;
			case kHIDUsage_GD_Wheel:
				if ((int32_t)val > 0)
				{
					add_to_event_queue(input, K_MWHEELUP, true);
					add_to_event_queue(input, K_MWHEELUP, false);
				}
				else if ((int32_t)val < 0)
				{
					add_to_event_queue(input, K_MWHEELDOWN, true);
					add_to_event_queue(input, K_MWHEELDOWN, false);
				}
				break;
			default:
				break;
		}
	}
	else if (page == kHIDPage_Button)
	{
		if (input->ignore_mouse)
		{
			return;
		}

		if (usage < 1 || usage > 10)
		{
			usage = 10;
		}

		add_to_event_queue(input, K_MOUSE1 + usage - 1, val ? true : false);
	}
	else if (page == kHIDPage_KeyboardOrKeypad)
	{
		if (usage == kHIDUsage_KeyboardLeftGUI)
		{
			input->left_cmd_key_active = val ? true : false;
		}
		else if (usage == kHIDUsage_KeyboardRightGUI)
		{
			input->right_cmd_key_active = val ? true : false;
		}

		if (usage < sizeof(keytable) && (input->left_cmd_key_active || input->right_cmd_key_active))
		{
			if (keytable[usage] == 'c' && val)
			{
				add_to_event_queue(input, K_COPY, true);
				add_to_event_queue(input, K_COPY, false);
			}
			else if (keytable[usage] == 'v' && val)
			{
				add_to_event_queue(input, K_PASTE, true);
				add_to_event_queue(input, K_PASTE, false);
			}

			return;
		}

		if (usage < sizeof(keytable))
		{
			add_to_event_queue(input, keytable[usage], val ? true : false);

			pthread_mutex_lock(&input->key_mutex);

			if (val)
			{
				input->repeatkey = keytable[usage];
				input->nextrepeattime = Sys_IntTime() + input->key_repeat_initial_delay;
			}
			else
			{
				input->repeatkey = 0;
				input->nextrepeattime = 0;
			}

			pthread_mutex_unlock(&input->key_mutex);
		}
	}
	else if (page == 0xFF)
	{
		if (usage == kHIDUsage_KeyboardErrorUndefined)
		{
			input->fn_key_active = val ? true : false;
		}
	}
}
예제 #12
0
static void iohidmanager_hid_device_input_callback(void *data, IOReturn result,
      void* sender, IOHIDValueRef value)
{
   iohidmanager_hid_t *hid                  = (iohidmanager_hid_t*)hid_driver_get_data();
   struct iohidmanager_hid_adapter *adapter = (struct iohidmanager_hid_adapter*)data;
   IOHIDElementRef element                  = IOHIDValueGetElement(value);
   uint32_t type                            = (uint32_t)IOHIDElementGetType(element);
   uint32_t page                            = (uint32_t)IOHIDElementGetUsagePage(element);
   uint32_t use                             = (uint32_t)IOHIDElementGetUsage(element);
   uint32_t cookie                          = (uint32_t)IOHIDElementGetCookie(element);
   apple_input_rec_t *tmp                   = NULL;

   if (type != kIOHIDElementTypeInput_Misc)
      if (type != kIOHIDElementTypeInput_Button)
         if (type != kIOHIDElementTypeInput_Axis)
            return;

   /* Joystick handler.
    * TODO: Can GamePad work the same? */

   int pushed_button = 0;

   switch (page)
   {
      case kHIDPage_GenericDesktop:
         switch (type)
         {
            case kIOHIDElementTypeInput_Misc:
               switch (use)
               {
                  case kHIDUsage_GD_Hatswitch:
                     {
                        tmp = adapter->hats;

                        while(tmp && tmp->cookie != (IOHIDElementCookie)cookie)
                           tmp = tmp->next;

                        if(tmp->cookie == (IOHIDElementCookie)cookie)
                        {
                           CFIndex range = IOHIDElementGetLogicalMax(element) - IOHIDElementGetLogicalMin(element);
                           CFIndex val   = IOHIDValueGetIntegerValue(value);

                           if(range == 3)
                              val *= 2;

                           switch(val)
                           {
                              case 0:
                                 /* pos = up */
                                 hid->hats[adapter->slot][0] = 0;
                                 hid->hats[adapter->slot][1] = -1;
                                 break;
                              case 1:
                                 /* pos = up+right */
                                 hid->hats[adapter->slot][0] = 1;
                                 hid->hats[adapter->slot][1] = -1;
                                 break;
                              case 2:
                                 /* pos = right */
                                 hid->hats[adapter->slot][0] = 1;
                                 hid->hats[adapter->slot][1] = 0;
                                 break;
                              case 3:
                                 /* pos = down+right */
                                 hid->hats[adapter->slot][0] = 1;
                                 hid->hats[adapter->slot][1] = 1;
                                 break;
                              case 4:
                                 /* pos = down */
                                 hid->hats[adapter->slot][0] = 0;
                                 hid->hats[adapter->slot][1] = 1;
                                 break;
                              case 5:
                                 /* pos = down+left */
                                 hid->hats[adapter->slot][0] = -1;
                                 hid->hats[adapter->slot][1] = 1;
                                 break;
                              case 6:
                                 /* pos = left */
                                 hid->hats[adapter->slot][0] = -1;
                                 hid->hats[adapter->slot][1] = 0;
                                 break;
                              case 7:
                                 /* pos = up_left */
                                 hid->hats[adapter->slot][0] = -1;
                                 hid->hats[adapter->slot][1] = -1;
                                 break;
                              default:
                                 /* pos = centered */
                                 hid->hats[adapter->slot][0] = 0;
                                 hid->hats[adapter->slot][1] = 0;
                                 break;
                           }
                        }
                     }
                     break;
                  default:
                     tmp = adapter->axes;

                     while(tmp && tmp->cookie != (IOHIDElementCookie)cookie)
                        tmp = tmp->next;

                     if (tmp)
                     {
                        if(tmp->cookie == (IOHIDElementCookie)cookie)
                        {
                           CFIndex min   = IOHIDElementGetPhysicalMin(element);
                           CFIndex state = IOHIDValueGetIntegerValue(value) - min;
                           CFIndex max   = IOHIDElementGetPhysicalMax(element) - min;
                           float val     = (float)state / (float)max;

                           hid->axes[adapter->slot][tmp->id] =
                              ((val * 2.0f) - 1.0f) * 32767.0f;
                        }
                     }
                     else
                        pushed_button = 1;
                     break;
               }
               break;
         }
         break;
      case kHIDPage_Consumer:
      case kHIDPage_Button:
         switch (type)
         {
            case kIOHIDElementTypeInput_Misc:
            case kIOHIDElementTypeInput_Button:
               pushed_button = 1;
               break;
         }
         break;
   }

   if (pushed_button)
   {
      tmp = adapter->buttons;

      uint8_t bit = 0;
      while(tmp && tmp->cookie != (IOHIDElementCookie)cookie)
      {
         bit++;
         tmp = tmp->next;
      }

      if(tmp && tmp->cookie == (IOHIDElementCookie)cookie)
      {
         CFIndex state = IOHIDValueGetIntegerValue(value);
         if (state)
            BIT64_SET(hid->buttons[adapter->slot], bit);
         else
            BIT64_CLEAR(hid->buttons[adapter->slot], bit);
      }
   }
}
예제 #13
0
void __deviceValueCallback (void * context, IOReturn result, void * sender, IOHIDValueRef value)
{
    IOHIDElementRef element = IOHIDValueGetElement(value);
    
    printf("IOHIDDeviceRef[%p]: value=%p timestamp=%lld cookie=%d usagePage=0x%02X usage=0x%02X intValue=%ld\n", sender, value, IOHIDValueGetTimeStamp(value), (uint32_t)IOHIDElementGetCookie(element), IOHIDElementGetUsagePage(element), IOHIDElementGetUsage(element), IOHIDValueGetIntegerValue(value));
}
예제 #14
0
void GamepadManager::onDeviceValueChanged(IOHIDValueRef value)
{
    
    IOHIDElementRef element = IOHIDValueGetElement(value);
    IOHIDDeviceRef device = IOHIDElementGetDevice(element);

    int vendorID = getIntDeviceProperty(device, CFSTR(kIOHIDVendorIDKey));
    int productID = getIntDeviceProperty(device, CFSTR(kIOHIDProductIDKey));
    
    uint32_t usagePage = IOHIDElementGetUsagePage(element);
    uint32_t usage = IOHIDElementGetUsage(element);

    // The following controller mapping is based on the Logitech F710, however we use it for
    // all Logitech devices on the assumption that they're likely to share the same mapping.
    if (vendorID == Logitech_F710_VendorID)
    {
        // Logitech F710 mapping.
        if (usagePage == kHIDPage_Button)
        {
            bool buttonState = IOHIDValueGetIntegerValue(value);

            switch(usage)
            {
                case kHIDUsage_Button_1:
                    manipulateBitField(State.Buttons, Gamepad_X, buttonState);
                    break;
                case kHIDUsage_Button_2:
                    manipulateBitField(State.Buttons, Gamepad_A, buttonState);
                    break;
                case kHIDUsage_Button_3:
                    manipulateBitField(State.Buttons, Gamepad_B, buttonState);
                    break;
                case kHIDUsage_Button_4:
                    manipulateBitField(State.Buttons, Gamepad_Y, buttonState);
                    break;
                case 0x05:
                    manipulateBitField(State.Buttons, Gamepad_L1, buttonState);
                    break;
                case 0x06:
                    manipulateBitField(State.Buttons, Gamepad_R1, buttonState);
                    break;
                case 0x07:
                    State.LT = buttonState ? 1.0f:0.0f;
                    break;
                case 0x08:
                    State.RT = buttonState ? 1.0f:0.0f;
                    break;
                case 0x09:
                    manipulateBitField(State.Buttons, Gamepad_Back, buttonState);
                    break;
                case 0x0A:
                    manipulateBitField(State.Buttons, Gamepad_Start, buttonState);
                    break;
                case 0x0B:
                    manipulateBitField(State.Buttons, Gamepad_LStick, buttonState);
                    break;
                case 0x0C:
                    manipulateBitField(State.Buttons, Gamepad_RStick, buttonState);
                    break;
                default:
                    return;
            }
        }
        else if (usagePage == kHIDPage_GenericDesktop)
        {
            float v;
            switch(usage)
            {
                case kHIDUsage_GD_X:
                    v = mapAnalogAxis(value, element);
                    if (!setStateIfDifferent(State.LX, v))
                        return;
                    break;
                case kHIDUsage_GD_Y:
                    v = mapAnalogAxis(value, element);
                    if (!setStateIfDifferent(State.LY, -v))
                        return;
                    break;
                case kHIDUsage_GD_Z:
                    v = mapAnalogAxis(value, element);
                    if (!setStateIfDifferent(State.RX, v))
                        return;
                    break;
                case kHIDUsage_GD_Rz:
                    v = mapAnalogAxis(value, element);
                    if (!setStateIfDifferent(State.RY, -v))
                        return;
                    break;
                case kHIDUsage_GD_Hatswitch:
                    {
                        CFIndex integerValue = IOHIDValueGetIntegerValue(value);
                 
                        manipulateBitField(State.Buttons,
                                           Gamepad_Up,
                                           integerValue == 7 || integerValue == 0 || integerValue == 1);
                        manipulateBitField(State.Buttons,
                                           Gamepad_Down,
                                           integerValue == 3 || integerValue == 4 || integerValue == 5);
                        manipulateBitField(State.Buttons,
                                           Gamepad_Left,
                                           integerValue == 5 || integerValue == 6 || integerValue == 7);
                        manipulateBitField(State.Buttons,
                                           Gamepad_Right,
                                           integerValue == 1 || integerValue == 2 || integerValue == 3);
                    }
                    break;
                default:
                    return;
            }
        }
    }
    // The following controller mapping is based on the Sony DualShock3, however we use it for
    // all Sony devices on the assumption that they're likely to share the same mapping.
    else if (vendorID == Sony_DualShock3_VendorID)
    {
        // PS3 Controller.
        if (usagePage == kHIDPage_Button)
        {
            bool buttonState = IOHIDValueGetIntegerValue(value);
            
            switch(usage)
            {
                case kHIDUsage_Button_1:
                    manipulateBitField(State.Buttons, Gamepad_Back, buttonState);
                    break;
                case kHIDUsage_Button_2:
                    manipulateBitField(State.Buttons, Gamepad_LStick, buttonState);
                    break;
                case kHIDUsage_Button_3:
                    manipulateBitField(State.Buttons, Gamepad_RStick, buttonState);
                    break;
                case kHIDUsage_Button_4:
                    manipulateBitField(State.Buttons, Gamepad_Start, buttonState);
                    break;
                case 0x05:
                    manipulateBitField(State.Buttons, Gamepad_Up, buttonState);
                    break;
                case 0x06:
                    manipulateBitField(State.Buttons, Gamepad_Right, buttonState);
                    break;
                case 0x07:
                    manipulateBitField(State.Buttons, Gamepad_Down, buttonState);
                    break;
                case 0x08:
                    manipulateBitField(State.Buttons, Gamepad_Left, buttonState);
                    break;
                case 0x09:
                    State.LT = buttonState ? 1.0f:0.0f;
                    break;
                case 0x0A:
                    State.RT = buttonState ? 1.0f:0.0f;
                    break;
                case 0x0B:
                    manipulateBitField(State.Buttons, Gamepad_L1, buttonState);
                    break;
                case 0x0C:
                    manipulateBitField(State.Buttons, Gamepad_R1, buttonState);
                    break;
                case 0x0D:
                    // PS3 Triangle.
                    manipulateBitField(State.Buttons, Gamepad_TRIANGLE, buttonState);
                    break;
                case 0x0E:
                    // PS3 Circle
                    manipulateBitField(State.Buttons, Gamepad_CIRCLE, buttonState);
                    break;
                case 0x0F:
                    // PS3 Cross
                    manipulateBitField(State.Buttons, Gamepad_CROSS, buttonState);
                    break;
                case 0x10:
                    // PS3 Square
                    manipulateBitField(State.Buttons, Gamepad_SQUARE, buttonState);
                    break;
                default:
                    return;
            }
        }
        else if (usagePage == kHIDPage_GenericDesktop)
        {
            float v;
            switch(usage)
            {
                case kHIDUsage_GD_X:
                    v = mapAnalogAxis(value, element);
                    if (!setStateIfDifferent(State.LX, v))
                        return;
                    break;
                case kHIDUsage_GD_Y:
                    v = mapAnalogAxis(value, element);
                    if (!setStateIfDifferent(State.LY, -v))
                        return;
                    break;
                case kHIDUsage_GD_Z:
                    v = mapAnalogAxis(value, element);
                    if (!setStateIfDifferent(State.RX, v))
                        return;
                    break;
                case kHIDUsage_GD_Rz:
                    v = mapAnalogAxis(value, element);
                    if (!setStateIfDifferent(State.RY, -v))
                        return;
                    break;
                default:
                    return;
            }
        }
    }
    
    bStateChanged = true;
}
static void PsychHIDKbQueueCallbackFunction(void *target, IOReturn result, void *sender)
{
    // This routine is executed each time the queue transitions from empty to non-empty
    // The CFRunLoop of the thread in KbQueueWorkerThreadMain() is the one that executes here:
    IOHIDQueueRef queue = (IOHIDQueueRef) sender;
    IOHIDValueRef valueRef = NULL;
    int deviceIndex = (int) target;
    double timestamp;
    int eventValue;
    long keysUsage = -1;
    PsychHIDEventRecord evt;
    
    result=kIOReturnError;
    if (!queue) return; // Nothing we can do because we can't access queue, (shouldn't happen)
    
    while (1) {
        // This function only gets called when queue transitions from empty to non-empty
        // Therefore, we must process all available events in this while loop before
        // it will be possible for this function to be notified again.
        if (valueRef) {
            CFRelease(valueRef);
            valueRef = NULL;
        }
        
        // Dequeue next event from queue in a polling non-blocking fashion:
        valueRef = IOHIDQueueCopyNextValueWithTimeout(queue, 0.0);
        
        // Done? Exit, if so:
        if (!valueRef) break;
        
        // Get event value, e.g., the key state of a key or button 1 = pressed, 0 = released:
        eventValue = IOHIDValueGetIntegerValue(valueRef);
        
        // Get usage value, ie., the identity of the key:
        IOHIDElementRef element = IOHIDValueGetElement(valueRef);
        keysUsage = IOHIDElementGetUsage(element);
        
        // Get double GetSecs timestamp, computed from returned uint64 nanoseconds timestamp:
        timestamp = convertTime(IOHIDValueGetTimeStamp(valueRef));
        
        // Don't bother with keysUsage of 0 (meaningless) or 1 (ErrorRollOver) for keyboards:
        if ((queueIsAKeyboard[deviceIndex]) && (keysUsage <= 1)) continue;
        
        // Clear ringbuffer event:
        memset(&evt, 0 , sizeof(evt));
        
        // Cooked key code defaults to "unhandled", and stays that way for anything but keyboards:
        evt.cookedEventCode = -1;
        
        // For real keyboards we can compute cooked key codes: Requires OSX 10.5 or later.
        if (queueIsAKeyboard[deviceIndex]) {
            // Keyboard(ish) device. We can handle this under some conditions.
            // Init to a default of handled, but unmappable/ignored keycode:
            evt.cookedEventCode = 0;
            
            // Keypress event code available in mapping table?
            if (keysUsage < kHID2VKCSize) {
                // Yes: We try to map this to a character code:
                
                // Step 1: Map HID usage value to virtual keycode via LUT:
                uint16_t vcKey = kHID2VKC[keysUsage];
                
                // Keep track of SHIFT keys as modifier keys: Bits 0 == Command, 1 == Shift, 2 == CapsLock, 3 == Alt/Option, 4 == CTRL
                if ((vcKey == kVKC_Shift || vcKey == kVKC_rShift) && (eventValue != 0)) modifierKeyState[deviceIndex] |=  (1 << 1);
                if ((vcKey == kVKC_Shift || vcKey == kVKC_rShift) && (eventValue == 0)) modifierKeyState[deviceIndex] &= ~(1 << 1);
                
                // Keep track of ALT keys as modifier keys:
                if ((vcKey == kVKC_Option || vcKey == kVKC_rOption) && (eventValue != 0)) modifierKeyState[deviceIndex] |=  (1 << 3);
                if ((vcKey == kVKC_Option || vcKey == kVKC_rOption) && (eventValue == 0)) modifierKeyState[deviceIndex] &= ~(1 << 3);
                
                // Keep track of CTRL keys as modifier keys:
                if ((vcKey == kVKC_Control || vcKey == kVKC_rControl) && (eventValue != 0)) modifierKeyState[deviceIndex] |=  (1 << 4);
                if ((vcKey == kVKC_Control || vcKey == kVKC_rControl) && (eventValue == 0)) modifierKeyState[deviceIndex] &= ~(1 << 4);
                
                // Was this a CTRL + C interrupt request?
                if ((eventValue != 0) && (vcKey == 0x08) && (modifierKeyState[deviceIndex] & (1 << 4))) {
                    // Yes: Tell the console input helper about it, so it can send interrupt
                    // signals to the runtime and reenable keyboard input if appropriate:
                    // Note: Not sure if the mutex exclusion is needed here, but better safe than sorry.
                    PsychLockMutex(&KbQueueMutex);
                    ConsoleInputHelper(-1);
                    PsychUnlockMutex(&KbQueueMutex);
                }
                
                // Key press?
                if (eventValue != 0) {
                    // Step 2: Translate virtual key code into unicode char:
                    // Ok, this is the usual horrifying complexity of Apple's system. We use code
                    // snippets found on StackOverflow, modified to suit our needs, e.g., we track
                    // modifier keys manually, at least left and right ALT and SHIFT keys. We don't
                    // care about other modifiers.
                    TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
                    CFDataRef uchr = (CFDataRef) ((currentKeyboard) ? TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData) : NULL);
                    const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout*) ((uchr) ? CFDataGetBytePtr(uchr) : NULL);
                    
                    if (keyboardLayout) {
                        UInt32 deadKeyState = 0;
                        UniCharCount maxStringLength = 255;
                        UniCharCount actualStringLength = 0;
                        UniChar unicodeString[maxStringLength];
                        
                        OSStatus status = UCKeyTranslate(keyboardLayout,
                                                         vcKey, kUCKeyActionDown, modifierKeyState[deviceIndex],
                                                         LMGetKbdType(), 0,
                                                         &deadKeyState,
                                                         maxStringLength,
                                                         &actualStringLength, unicodeString);
                        
                        if ((actualStringLength == 0) && deadKeyState) {
                            status = UCKeyTranslate(keyboardLayout,
                                                    kVK_Space, kUCKeyActionDown, 0,
                                                    LMGetKbdType(), 0,
                                                    &deadKeyState,
                                                    maxStringLength,
                                                    &actualStringLength, unicodeString);
                        }
                        
                        if((actualStringLength > 0) && (status == noErr)) {
                            // Assign final cooked / mapped keycode:
                            evt.cookedEventCode = (int) unicodeString[0];
                            
                            // Send same keystroke character to console input helper.
                            // In kbqueue-based ListenChar(1) mode, the helper will
                            // inject/forward the character into the runtime:
                            // Note: ConsoleInputHelper() should be safe to call without
                            // mutex protection for >= 0 event codes.
                            ConsoleInputHelper(evt.cookedEventCode);
                        }
                    }
                }
            }
        }
        
        PsychLockMutex(&KbQueueMutex);

        // Update records of first and latest key presses and releases
        if (eventValue != 0) {
            if (psychHIDKbQueueFirstPress[deviceIndex]) {
                // First key press timestamp:
                if (psychHIDKbQueueFirstPress[deviceIndex][keysUsage-1] == 0) {
                    psychHIDKbQueueFirstPress[deviceIndex][keysUsage-1] = timestamp;
                }
            }

            if (psychHIDKbQueueLastPress[deviceIndex]) {
                // Last key press timestamp:
                psychHIDKbQueueLastPress[deviceIndex][keysUsage-1] = timestamp;
            }
            evt.status |= (1 << 0);
        }
        else {
            if (psychHIDKbQueueFirstRelease[deviceIndex]) {
                // First key release timestamp:
                if (psychHIDKbQueueFirstRelease[deviceIndex][keysUsage-1] == 0) psychHIDKbQueueFirstRelease[deviceIndex][keysUsage-1] = timestamp;
            }

            if (psychHIDKbQueueLastRelease[deviceIndex]) {
                // Last key release timestamp:
                psychHIDKbQueueLastRelease[deviceIndex][keysUsage-1] = timestamp;
            }
            evt.status &= ~(1 << 0);
        }

        // Update event buffer:
        evt.timestamp = timestamp;
        evt.rawEventCode = keysUsage;
        PsychHIDAddEventToEventBuffer(deviceIndex, &evt);

        // Tell waiting userspace (under KbQueueMutxex protection for better scheduling) something interesting has changed:
        PsychSignalCondition(&KbQueueCondition);

        PsychUnlockMutex(&KbQueueMutex);

        // Next while loop iteration to dequeue potentially more events:
    }
    
    // Done for this queue transition. Return to runloop.
}
예제 #16
0
static void apple_hid_device_input_callback(void *data, IOReturn result,
      void* sender, IOHIDValueRef value)
{
   driver_t                  *driver = driver_get_ptr();
   apple_input_data_t         *apple = (apple_input_data_t*)driver->input_data;
   struct apple_hid_adapter *adapter = (struct apple_hid_adapter*)data;
   IOHIDElementRef element           = IOHIDValueGetElement(value);
   uint32_t type                     = IOHIDElementGetType(element);
   uint32_t page                     = IOHIDElementGetUsagePage(element);
   uint32_t use                      = IOHIDElementGetUsage(element);

   if (type != kIOHIDElementTypeInput_Misc)
      if (type != kIOHIDElementTypeInput_Button)
         if (type != kIOHIDElementTypeInput_Axis)
            return;

   /* Joystick handler.
    * TODO: Can GamePad work the same? */

   switch (page)
   {
      case kHIDPage_GenericDesktop:
         switch (type)
         {
            case kIOHIDElementTypeInput_Misc:
               switch (use)
               {
                  case kHIDUsage_GD_Hatswitch:
                     break;
                  default:
                     {
                        int i;
                        static const uint32_t axis_use_ids[4] = { 48, 49, 50, 53 };

                        for (i = 0; i < 4; i ++)
                        {
                           CFIndex min   = IOHIDElementGetPhysicalMin(element);
                           CFIndex max   = IOHIDElementGetPhysicalMax(element) - min;
                           CFIndex state = IOHIDValueGetIntegerValue(value) - min;
                           float val     = (float)state / (float)max;

                           if (use != axis_use_ids[i])
                              continue;

                           apple->axes[adapter->slot][i] =
                              ((val * 2.0f) - 1.0f) * 32767.0f;
                        }
                     }
                     break;
               }
               break;
         }
         break;
      case kHIDPage_Button:
         switch (type)
         {
            case kIOHIDElementTypeInput_Button:
               {
                  CFIndex state = IOHIDValueGetIntegerValue(value);
                  unsigned id = use - 1;

                  if (state)
                     BIT64_SET(apple->buttons[adapter->slot], id);
                  else
                     BIT64_CLEAR(apple->buttons[adapter->slot], id);
               }
               break;
         }
         break;
   }
}
예제 #17
0
void Burger::Mouse::InputCallback(void *pData, int iReturn,void * /* pSender */,IOHIDValueRef pValue)
{
	if (iReturn == kIOReturnSuccess) {
		Mouse *pMouse = static_cast<Mouse *>(pData);
		Word uCount = pMouse->m_uMiceCount;
		if (uCount) {
			IOHIDElementRef pElement = IOHIDValueGetElement(pValue);
			IOHIDDeviceRef pDevice = IOHIDElementGetDevice(pElement);
#if 0
			Word uRatNumber = BURGER_MAXUINT;
			const DeviceStruct *pRat = pMouse->m_Mice;
			do {
				if (pRat->m_pDevice == pDevice) {
					uRatNumber = pMouse->m_uMiceCount-uCount;
					break;
				}
				++pRat;
			} while (--uCount);
			if (uRatNumber==BURGER_MAXUINT) {
			}
#endif
			Word32 uTime = static_cast<Word32>(IOHIDValueGetTimeStamp(pValue));
			CFIndex iValue = IOHIDValueGetIntegerValue(pValue);
			
			uint32_t uPage = IOHIDElementGetUsagePage(pElement);
			uint32_t uUsage = IOHIDElementGetUsage(pElement);
			switch (uPage) {
			case kHIDPage_GenericDesktop:
				if (iValue) {
					switch (uUsage) {
					case kHIDUsage_GD_X:
						pMouse->PostMouseMotion(static_cast<Int32>(iValue),0,uTime);
						break;
					case kHIDUsage_GD_Y:
						pMouse->PostMouseMotion(0,static_cast<Int32>(iValue),uTime);
						break;
					case kHIDUsage_GD_Wheel:
						pMouse->PostMouseWheel(0,static_cast<Int32>(iValue),uTime);
						break;
					default:
						printf("Unknown usage %u\n",uUsage);
						break;
					}
				}
				break;
			case kHIDPage_Button:
				// iValue == down
				// Usage = which 1.2.3.4
				if (iValue) {
					pMouse->PostMouseDown(1<<(uUsage-1));
				} else {
					pMouse->PostMouseUp(1<<(uUsage-1));
				}
				break;
				// Ignore this one
			case kHIDPage_Consumer:
				break;
			default:
				printf("Unknown page found %u\n",uPage);
				break;
			}
		}
	}
}
예제 #18
0
static void iohidmanager_hid_device_input_callback(void *data, IOReturn result,
      void* sender, IOHIDValueRef value)
{
   iohidmanager_hid_t *hid = (iohidmanager_hid_t*)hid_driver_get_data();
   struct iohidmanager_hid_adapter *adapter = (struct iohidmanager_hid_adapter*)data;
   IOHIDElementRef element           = IOHIDValueGetElement(value);
   uint32_t type                     = IOHIDElementGetType(element);
   uint32_t page                     = IOHIDElementGetUsagePage(element);
   uint32_t use                      = IOHIDElementGetUsage(element);

   if (type != kIOHIDElementTypeInput_Misc)
      if (type != kIOHIDElementTypeInput_Button)
         if (type != kIOHIDElementTypeInput_Axis)
            return;

   /* Joystick handler.
    * TODO: Can GamePad work the same? */

   switch (page)
   {
      case kHIDPage_GenericDesktop:
         switch (type)
         {
            case kIOHIDElementTypeInput_Misc:
               switch (use)
               {
                  case kHIDUsage_GD_Hatswitch:
                     break;
                  default:
                     {
                        int i;
                        // +0/-0   =>   Left Stick Horizontal       => 48
                        // +1/-1   =>   Left Stick Vertical         => 49
                        // +2/-2   =>   Right Stick Horizontal      => 51
                        // +3/-3   =>   Right Stick Vertical        => 52
                        // +4/-4   =>   Left Trigger (if exists)    => 50
                        // +5/-5   =>   Right Trigger (if exists)   => 53
                        static const uint32_t axis_use_ids[6] = { 48, 49, 51, 52, 50, 53 };

                        for (i = 0; i < 6; i ++)
                        {
                           CFIndex min   = IOHIDElementGetPhysicalMin(element);
                           CFIndex state = IOHIDValueGetIntegerValue(value) - min;
                           CFIndex max   = IOHIDElementGetPhysicalMax(element) - min;
                           float val     = (float)state / (float)max;

                           if (use != axis_use_ids[i])
                              continue;

                           hid->axes[adapter->slot][i] =
                              ((val * 2.0f) - 1.0f) * 32767.0f;
                        }
                     }
                     break;
               }
               break;
         }
         break;
      case kHIDPage_Button:
         switch (type)
         {
            case kIOHIDElementTypeInput_Button:
               {
                  CFIndex state = IOHIDValueGetIntegerValue(value);
                  unsigned   id = use - 1;

                  if (state)
                     BIT64_SET(hid->buttons[adapter->slot], id);
                  else
                     BIT64_CLEAR(hid->buttons[adapter->slot], id);
               }
               break;
         }
         break;
   }
}