Пример #1
0
void QXcbConnection::xi2SetupTabletDevices()
{
    Display *xDisplay = static_cast<Display *>(m_xlib_display);
    m_tabletData.clear();
    int deviceCount = 0;
    XIDeviceInfo *devices = XIQueryDevice(xDisplay, XIAllDevices, &deviceCount);
    if (devices) {
        for (int i = 0; i < deviceCount; ++i) {
            int unused = 0;
            XIDeviceInfo *dev = XIQueryDevice(xDisplay, devices[i].deviceid, &unused);
            if (dev) {
                if (q_xi2_is_tablet(dev)) {
                    TabletData tabletData;
                    xi2QueryTabletData(dev, &tabletData);
#ifdef XI2_TOUCH_DEBUG
                    qDebug() << "found tablet" << dev->name;
#endif
                    m_tabletData.append(tabletData);
                }
                XIFreeDeviceInfo(dev);
            }
        }
        XIFreeDeviceInfo(devices);
    }
}
Пример #2
0
// Apply the event mask to the device and all its slaves. Only used in the
// constructor. Remember, each KeyboardMouse has its own copy of the event
// stream, which is how multiple event masks can "coexist."
void KeyboardMouse::SelectEventsForDevice(Window window, XIEventMask *mask, int deviceid)
{
	// Set the event mask for the master device.
	mask->deviceid = deviceid;
	XISelectEvents(m_display, window, mask, 1);

	// Query all the master device's slaves and set the same event mask for
	// those too. There are two reasons we want to do this. For mouse devices,
	// we want the raw motion events, and only slaves (i.e. physical hardware
	// devices) emit those. For keyboard devices, selecting slaves avoids
	// dealing with key focus.

	XIDeviceInfo* all_slaves;
	XIDeviceInfo* current_slave;
	int           num_slaves;

	all_slaves = XIQueryDevice(m_display, XIAllDevices, &num_slaves);

	for (int i = 0; i < num_slaves; i++)
	{
		current_slave = &all_slaves[i];
		if ((current_slave->use != XISlavePointer && current_slave->use != XISlaveKeyboard) || current_slave->attachment != deviceid)
			continue;
		mask->deviceid = current_slave->deviceid;
		XISelectEvents(m_display, window, mask, 1);
	}

	XIFreeDeviceInfo(all_slaves);
}
Пример #3
0
static void uninstall_grabs_mouse( void )
{
	int i;
	int num_devices;
	XIDeviceInfo *info;

	assert( x11display.dpy && x11display.win );

	if( !mouse_active )
		return;

	XUndefineCursor(x11display.dpy, x11display.win);

	info = XIQueryDevice(x11display.dpy, XIAllDevices, &num_devices);

	for(i = 0; i < num_devices; i++) {
		if(info[i].use == XIFloatingSlave) {
			XIUngrabDevice(x11display.dpy, info[i].deviceid, CurrentTime);
		}
		else if(info[i].use == XIMasterPointer) {
			XIWarpPointer(x11display.dpy, info[i].deviceid, None, x11display.win, 0, 0, 0, 0,
				x11display.win_width/2, x11display.win_height/2);
		}
	}
	XIFreeDeviceInfo(info);

	mouse_active = qfalse;
	mx = my = 0;
}
Пример #4
0
KeyboardMouse::KeyboardMouse(Window window, int opcode, int pointer, int keyboard)
	: m_window(window), xi_opcode(opcode), pointer_deviceid(pointer), keyboard_deviceid(keyboard)
{
	memset(&m_state, 0, sizeof(m_state));

	// The cool thing about each KeyboardMouse object having its own Display
	// is that each one gets its own separate copy of the X11 event stream,
	// which it can individually filter to get just the events it's interested
	// in. So be aware that each KeyboardMouse object actually has its own X11
	// "context."
	m_display = XOpenDisplay(nullptr);

	int min_keycode, max_keycode;
	XDisplayKeycodes(m_display, &min_keycode, &max_keycode);

	int unused; // should always be 1
	XIDeviceInfo* pointer_device = XIQueryDevice(m_display, pointer_deviceid, &unused);
	name = std::string(pointer_device->name);
	XIFreeDeviceInfo(pointer_device);

	XIEventMask   mask;
	unsigned char mask_buf[(XI_LASTEVENT + 7)/8];

	mask.mask_len = sizeof(mask_buf);
	mask.mask = mask_buf;
	memset(mask_buf, 0, sizeof(mask_buf));

	XISetMask(mask_buf, XI_ButtonPress);
	XISetMask(mask_buf, XI_ButtonRelease);
	XISetMask(mask_buf, XI_RawMotion);
	XISetMask(mask_buf, XI_KeyPress);
	XISetMask(mask_buf, XI_KeyRelease);

	SelectEventsForDevice(DefaultRootWindow(m_display), &mask, pointer_deviceid);
	SelectEventsForDevice(DefaultRootWindow(m_display), &mask, keyboard_deviceid);

	// Keyboard Keys
	for (int i = min_keycode; i <= max_keycode; ++i)
	{
		Key* temp_key = new Key(m_display, i, m_state.keyboard);
		if (temp_key->m_keyname.length())
			AddInput(temp_key);
		else
			delete temp_key;
	}

	// Mouse Buttons
	for (int i = 0; i < 5; i++)
		AddInput(new Button(i, m_state.buttons));

	// Mouse Cursor, X-/+ and Y-/+
	for (int i = 0; i != 4; ++i)
		AddInput(new Cursor(!!(i & 2), !!(i & 1), (&m_state.cursor.x)[!!(i & 2)]));

	// Mouse Axis, X-/+ and Y-/+
	for (int i = 0; i != 4; ++i)
		AddInput(new Axis(!!(i & 2), !!(i & 1), (&m_state.axis.x)[!!(i & 2)]));
}
Пример #5
0
static int
add_mpx_for_window (char *name)
{
  XIAddMasterInfo add;
  int ndevices;
  XIDeviceInfo *devices, *device;
  int i;
  int result;

  /* add the device */

  add.type = XIAddMaster;
  add.name = name;
  add.send_core = True;
  add.enable = True;

  XIChangeHierarchy (gdk_x11_get_default_xdisplay (),
		     (XIAnyHierarchyChangeInfo*) &add,
		     1);

  /* now see whether it's in the list */

  result = -1;

  devices = XIQueryDevice(gdk_x11_get_default_xdisplay (),
			  XIAllDevices, &ndevices);

  for (i = 0; i < ndevices; i++) {
    device = &devices[i];

    if (g_str_has_prefix (device->name,
			  name))
      {
	switch (device->use)
	  {
	  case XIMasterPointer:
	    result = device->deviceid;
	    break;
	  }
      }
  }

  if (result==-1)
    {
      g_warning ("The doppelganger pointer '%s' could not be created.",
		 name);
    }

  XIFreeDeviceInfo(devices);

  return result;
}
Пример #6
0
static void install_grabs_mouse( void )
{
	int i;
	int num_devices;
	XIDeviceInfo *info;
	XIEventMask mask;

	assert( x11display.dpy && x11display.win );

	if( mouse_active )
		return;

	XDefineCursor(x11display.dpy, x11display.win, CreateNullCursor(x11display.dpy, x11display.win));

	mask.deviceid = XIAllDevices;
	mask.mask_len = XIMaskLen(XI_LASTEVENT);
	mask.mask = calloc(mask.mask_len, sizeof(char));
	XISetMask(mask.mask, XI_Enter);
	XISetMask(mask.mask, XI_Leave);
	XISetMask(mask.mask, XI_ButtonPress);
	XISetMask(mask.mask, XI_ButtonRelease);

	info = XIQueryDevice(x11display.dpy, XIAllDevices, &num_devices);
	for(i = 0; i < num_devices; i++) {
		int id = info[i].deviceid;
		if(info[i].use == XISlavePointer) {
			mask.deviceid = id;
			XIGrabDevice(x11display.dpy, id, x11display.win, CurrentTime, None, GrabModeSync,
				GrabModeSync, True, &mask);
		}
		else if(info[i].use == XIMasterPointer) {
			if (x11display.features.wmStateFullscreen)
				XIWarpPointer(x11display.dpy, id, None, x11display.win, 0, 0, 0, 0, 0, 0);
			else
				XIWarpPointer(x11display.dpy, id, None, x11display.win, 0, 0, 0, 0, x11display.win_width/2, x11display.win_height/2);
		}
	}
	XIFreeDeviceInfo(info);

	mask.deviceid = XIAllDevices;
	memset(mask.mask, 0, mask.mask_len);
	XISetMask(mask.mask, XI_RawMotion);

	XISelectEvents(x11display.dpy, DefaultRootWindow(x11display.dpy), &mask, 1);

	free(mask.mask);

	XSync(x11display.dpy, True);

	mx = my = 0;
	mouse_active = qtrue;
}
Пример #7
0
void
_ecore_x_input_shutdown(void)
{
#ifdef ECORE_XI2
   if (_ecore_x_xi2_devs)
     {
        XIFreeDeviceInfo(_ecore_x_xi2_devs);
        _ecore_x_xi2_devs = NULL;
     }

   _ecore_x_xi2_num = 0;
   _ecore_x_xi2_opcode = -1;
#endif /* ifdef ECORE_XI2 */
} /* _ecore_x_input_shutdown */
Пример #8
0
void
_ecore_x_input_shutdown(void)
{
#ifdef ECORE_XI2
   if (_ecore_x_xi2_devs)
     {
        XIFreeDeviceInfo(_ecore_x_xi2_devs);
        _ecore_x_xi2_devs = NULL;
#ifdef ECORE_XI2_2
        _ecore_x_input_touch_info_clear();
#endif /* ifdef ECORE_XI2_2 */
     }

   _ecore_x_xi2_num = 0;
   _ecore_x_xi2_opcode = -1;
#endif /* ifdef ECORE_XI2 */
}
Пример #9
0
void XInputMTInputDevice::findMTDevice()
{
    int ndevices;
    XIDeviceInfo* pDevices;
    XIDeviceInfo* pDevice;

    pDevices = XIQueryDevice(s_pDisplay, XIAllDevices, &ndevices);

    XITouchClassInfo* pTouchClass = 0;
    for (int i = 0; i < ndevices && !pTouchClass; ++i) {
        pDevice = &pDevices[i];
//        cerr << "Device " << pDevice->name << "(id: " << pDevice->deviceid << ")."
//                << endl;
        if (pDevice->use == XISlavePointer || pDevice->use == XIFloatingSlave) {
            for (int j = 0; j < pDevice->num_classes; ++j) {
                XIAnyClassInfo * pClass = pDevice->classes[j];
                if (pClass->type == XITouchClass) {
                    XITouchClassInfo* pTempTouchClass = (XITouchClassInfo *)pClass;
                    if (pTempTouchClass->mode == XIDirectTouch) {
                        pTouchClass = pTempTouchClass;
                        m_sDeviceName = pDevice->name;
                        m_DeviceID = pDevice->deviceid;
                        if (pDevice->use == XISlavePointer) {
                            m_OldMasterDeviceID = pDevice->attachment;
                        } else {
                            m_OldMasterDeviceID = -1;
                        }
                        break;
                    }
                }
            }
        }
    }
    if (pTouchClass) {
        AVG_TRACE(Logger::category::CONFIG,Logger::severity::INFO,
                "Using multitouch input device " << m_sDeviceName << ", max touches: " <<
                pTouchClass->num_touches);
    } else {
        throw Exception(AVG_ERR_MT_INIT, 
                "XInput multitouch event source: No multitouch device found.");
    }
    XIFreeDeviceInfo(pDevices);
}
Пример #10
0
// This function will add zero or more KeyboardMouse objects to devices.
void Init(std::vector<Core::Device*>& devices, void* const hwnd)
{
  Display* dpy = XOpenDisplay(nullptr);

  // xi_opcode is important; it will be used to identify XInput events by
  // the polling loop in UpdateInput.
  int xi_opcode, event, error;

  // verify that the XInput extension is available
  if (!XQueryExtension(dpy, "XInputExtension", &xi_opcode, &event, &error))
    return;

  // verify that the XInput extension is at at least version 2.0
  int major = 2, minor = 0;

  if (XIQueryVersion(dpy, &major, &minor) != Success)
    return;

  // register all master devices with Dolphin

  XIDeviceInfo* all_masters;
  XIDeviceInfo* current_master;
  int num_masters;

  all_masters = XIQueryDevice(dpy, XIAllMasterDevices, &num_masters);

  for (int i = 0; i < num_masters; i++)
  {
    current_master = &all_masters[i];
    if (current_master->use == XIMasterPointer)
      // Since current_master is a master pointer, its attachment must
      // be a master keyboard.
      devices.push_back(new KeyboardMouse((Window)hwnd, xi_opcode, current_master->deviceid,
                                          current_master->attachment));
  }

  XCloseDisplay(dpy);

  XIFreeDeviceInfo(all_masters);
}
Пример #11
0
static void install_grabs_keyboard( void )
{
	int i;
	int num_devices;
	XIDeviceInfo *info;
	XIEventMask mask;

	assert( x11display.dpy && x11display.win );

	if( input_active )
		return;

	XDefineCursor(x11display.dpy, x11display.win, CreateNullCursor(x11display.dpy, x11display.win));

	mask.deviceid = XIAllMasterDevices;
	mask.mask_len = XIMaskLen(XI_LASTEVENT);
	mask.mask = calloc(mask.mask_len, sizeof(char));
	XISetMask(mask.mask, XI_KeyPress);
	XISetMask(mask.mask, XI_KeyRelease);
	XISetMask(mask.mask, XI_ButtonPress);
	XISetMask(mask.mask, XI_ButtonRelease);
	XISelectEvents(x11display.dpy, x11display.win, &mask, 1);

	info = XIQueryDevice(x11display.dpy, XIAllDevices, &num_devices);
	for(i = 0; i < num_devices; i++) {
		int id = info[i].deviceid;
		if(info[i].use == XIMasterKeyboard)
		{
			XIGrabDevice(x11display.dpy, id, x11display.win, CurrentTime, None, GrabModeAsync, GrabModeAsync, False, &mask);
		}
	}
	XIFreeDeviceInfo(info);

	free(mask.mask);

	XSync(x11display.dpy, True);

	input_active = qtrue;
}
Пример #12
0
static void uninstall_grabs_keyboard( void )
{
	int i;
	int num_devices;
	XIDeviceInfo *info;

	assert( x11display.dpy && x11display.win );

	if( !input_active )
		return;

	info = XIQueryDevice(x11display.dpy, XIAllDevices, &num_devices);

	for(i = 0; i < num_devices; i++) {
		if(info[i].use == XIMasterKeyboard) {
			XIUngrabDevice(x11display.dpy, info[i].deviceid, CurrentTime);
		}
	}
	XIFreeDeviceInfo(info);

	input_active = qfalse;
}
PsychError SCREENGetMouseHelper(void) 
{

    const char *valuatorInfo[]={"label", "min", "max", "resolution", "mode", "sourceID"};
    int numValuatorStructFieldNames = 6;
    int numIValuators = 0;
    PsychGenericScriptType *valuatorStruct = NULL;

#if PSYCH_SYSTEM == PSYCH_OSX
	Point		mouseXY;
	UInt32		buttonState;
	double		*buttonArray;
	int		numButtons, i;
	psych_bool	doButtonArray;
	PsychWindowRecordType *windowRecord;
	
	//all subfunctions should have these two lines.  
	PsychPushHelp(useString, synopsisString, seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
	
	//cap the numbers of inputs and outputs
	PsychErrorExit(PsychCapNumInputArgs(3));   //The maximum number of inputs
	PsychErrorExit(PsychCapNumOutputArgs(6));  //The maximum number of outputs
	
	//Buttons.  
	// The only way I know to detect the  number number of mouse buttons is directly via HID.  The device reports
	//that information but OS X seems to ignore it above the level of the HID driver, that is, no OS X API above the HID driver
	//exposes it.  So GetMouse.m function calls PsychHID detect the number of buttons and then passes that value to GetMouseHelper 
	//which returns that number of button values in a vector.      
	PsychCopyInIntegerArg(1, kPsychArgRequired, &numButtons);
	if(numButtons > 32)
		PsychErrorExitMsg(PsychErorr_argumentValueOutOfRange, "numButtons must not exceed 32");

	// Special codes -10 to -15? --> Console keyboard queries:
	if(numButtons <= -10 && numButtons >= -15) {
		ConsoleInputHelper((int) numButtons);
		return(PsychError_none);
	}

	if(numButtons < 1) 
		PsychErrorExitMsg(PsychErorr_argumentValueOutOfRange, "numButtons must exceed 1");

	doButtonArray=PsychAllocOutDoubleMatArg(3, kPsychArgOptional, (int)1, (int)numButtons, (int)1, &buttonArray);
	if(doButtonArray){
		buttonState=GetCurrentButtonState();
		for(i=0;i<numButtons;i++)
			buttonArray[i]=(double)(buttonState & (1<<i));
	}
			
	// Get cursor position:
#ifndef __LP64__
    // 32-Bit Carbon version:
	GetGlobalMouse(&mouseXY);
	PsychCopyOutDoubleArg(1, kPsychArgOptional, (double)mouseXY.h);
	PsychCopyOutDoubleArg(2, kPsychArgOptional, (double)mouseXY.v);
#else
    // 64-Bit HIToolbox version (OSX 10.5 and later):
    HIPoint outPoint;
    HIGetMousePosition(kHICoordSpaceScreenPixel, NULL, &outPoint);
	PsychCopyOutDoubleArg(1, kPsychArgOptional, (double) outPoint.x);
	PsychCopyOutDoubleArg(2, kPsychArgOptional, (double) outPoint.y);
#endif
	// Return optional keyboard input focus status:
	if (numButtons > 0) {
		// Window provided?
        // We only have the function GetUserFocusWindow on 32-Bit Carbon.
        // We have a drop-in replacement in OSX/PsychCocoaGlue.c for 64-Bit Cocoa.
		if (PsychIsWindowIndexArg(2)) {
			// Yes: Check if it has focus.
			PsychAllocInWindowRecordArg(2, TRUE, &windowRecord);
			if (!PsychIsOnscreenWindow(windowRecord)) {
				PsychErrorExitMsg(PsychError_user, "Provided window handle isn't an onscreen window, as required.");
			}

			PsychCopyOutDoubleArg(4, kPsychArgOptional, (double) (GetUserFocusWindow() == windowRecord->targetSpecific.windowHandle) ? 1 : 0);
		} else
        {
			// No. Just always return "has focus":
			PsychCopyOutDoubleArg(4, kPsychArgOptional, (double) 1);
		}
	}

	// Return optional valuator values: Unimplemented on OS/X. Just return an empty matrix.
	// The buttonArray is just a dummy assignment without any meaning.
	PsychCopyOutDoubleMatArg(5, kPsychArgOptional, (int) 1, (int) 0, (int) 1, buttonArray);
	PsychCopyOutDoubleMatArg(6, kPsychArgOptional, (int) 1, (int) 0, (int) 1, buttonArray);
#endif

#if PSYCH_SYSTEM == PSYCH_WINDOWS
	static unsigned char disabledKeys[256];
	static unsigned char firsttime = 1;
	int keysdown, i, priorityLevel;
	unsigned char keyState[256];
	double* buttonArray;
	double numButtons, timestamp;
	PsychNativeBooleanType* buttonStates;
	POINT		point;
	HANDLE	   currentProcess;
	DWORD   oldPriority = NORMAL_PRIORITY_CLASS;
    const  DWORD   realtime_class = REALTIME_PRIORITY_CLASS;
	PsychWindowRecordType *windowRecord;

	PsychPushHelp(useString, synopsisString, seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};

	// Retrieve optional number of mouse buttons:
	numButtons = 0;
	PsychCopyInDoubleArg(1, FALSE, &numButtons);

	// Are we operating in 'GetMouseHelper' mode? numButtons>=0 indicates this.
	if (numButtons>=0) {
		// GetMouse-Mode: Return mouse button states and mouse cursor position:

		PsychAllocOutDoubleMatArg(3, kPsychArgOptional, (int)1, (int)3, (int)1, &buttonArray);
		// Query and return mouse button state:
		PsychGetMouseButtonState(buttonArray);
		// Query and return cursor position in global coordinates:
		GetCursorPos(&point);
		PsychCopyOutDoubleArg(1, kPsychArgOptional, (double) point.x);
		PsychCopyOutDoubleArg(2, kPsychArgOptional, (double) point.y);
		
		// Window provided?
		if (PsychIsWindowIndexArg(2)) {
			// Yes: Check if it has focus.
			PsychAllocInWindowRecordArg(2, TRUE, &windowRecord);
			if (!PsychIsOnscreenWindow(windowRecord)) {
				PsychErrorExitMsg(PsychError_user, "Provided window handle isn't an onscreen window, as required.");
			}

			PsychCopyOutDoubleArg(4, kPsychArgOptional, (double) (GetForegroundWindow() == windowRecord->targetSpecific.windowHandle) ? 1 : 0);
		} else {
			// No. Just always return "has focus":
			PsychCopyOutDoubleArg(4, kPsychArgOptional, (double) 1);
		}		

		// Return optional valuator values: Unimplemented on Windows. Just return an empty matrix.
		// The &timestamp is just a dummy assignment without any meaning.
		PsychCopyOutDoubleMatArg(5, kPsychArgOptional, (int) 1, (int) 0, (int) 1, &timestamp);
		PsychCopyOutDoubleMatArg(6, kPsychArgOptional, (int) 1, (int) 0, (int) 1, buttonArray);
	}
	else {
	  // 'KeyboardHelper' mode: We implement either KbCheck() or KbWait() via X11.
	  // This is a hack to provide keyboard queries until a PsychHID() implementation
	  // for Microsoft Windows is available...

		// Special codes -10 to -15? --> Console keyboard queries:
		if(numButtons <= -10 && numButtons >= -15) {
			ConsoleInputHelper((int) numButtons);
			return(PsychError_none);
		}
		
	  if (firsttime) {
			// First time init:
			firsttime = 0;
			memset(keyState, 0, sizeof(keyState));
			memset(disabledKeys, 0, sizeof(disabledKeys));
			// These keycodes are always disabled: 0, 255:
			disabledKeys[0]=1;
			disabledKeys[255]=1;
			// Mouse buttone (left, right, middle) are also disabled by default:
			disabledKeys[1]=1;
			disabledKeys[2]=1;
			disabledKeys[4]=1;
	  }

	  if (numButtons==-1 || numButtons==-2) {
	    // KbCheck()/KbWait() mode
	    do {
	      // Reset overall key state to "none pressed":
	      keysdown=0;

	      // Request current time of query:
	      PsychGetAdjustedPrecisionTimerSeconds(&timestamp);

			// Query state of all keys:
			for(i=1;i<255;i++){
				keyState[i] = (GetAsyncKeyState(i) & -32768) ? 1 : 0;
			}

	      // Disable all keys that are registered in disabledKeys. Check if
			// any non-disabled key is down.
	      for (i=0; i<256; i++) {
				if (disabledKeys[i]>0) keyState[i] = 0;
				keysdown+=(unsigned int) keyState[i];
	      }

	      // We repeat until any key pressed if in KbWait() mode, otherwise we
	      // exit the loop after first iteration in KbCheck mode.
	      if ((numButtons==-1) || ((numButtons==-2) && (keysdown>0))) break;

	      // Sleep for a millisecond before next KbWait loop iteration:
	      PsychWaitIntervalSeconds(0.001);

	    } while(1);

	    if (numButtons==-2) {
	      // KbWait mode: Copy out time value.
	      PsychCopyOutDoubleArg(1, kPsychArgOptional, timestamp);
	    }
	    else {
	      // KbCheck mode:
	      
	      // Copy out overall keystate:
	      PsychCopyOutDoubleArg(1, kPsychArgOptional, (keysdown>0) ? 1 : 0);

	      // Copy out timestamp:
	      PsychCopyOutDoubleArg(2, kPsychArgOptional, timestamp);	      

	      // Copy out keyboard state:
	      PsychAllocOutBooleanMatArg(3, kPsychArgOptional, 1, 256, 1, &buttonStates);

	      // Build 256 elements return vector:
	      for(i=0; i<255; i++) {
		  		buttonStates[i] = (PsychNativeBooleanType)((keyState[i+1]) ? 1 : 0);
	      }
			// Special case: Null out last element:
			buttonStates[255] = (PsychNativeBooleanType) 0;
	    }
	  }
	  
	  if (numButtons==-3) {
		// Priority() - helper mode: The 2nd argument is the priority level:

		// Determine our processID:
		currentProcess = GetCurrentProcess();
    
		// Get current scheduling policy:
		oldPriority = GetPriorityClass(currentProcess);
		
		// Map to PTB's scheme:
		switch(oldPriority) {
			case NORMAL_PRIORITY_CLASS:
				priorityLevel = 0;
			break;

			case HIGH_PRIORITY_CLASS:
				priorityLevel = 1;
			break;

			case REALTIME_PRIORITY_CLASS:
				priorityLevel = 2;
			break;

			default:
				priorityLevel = 0;
		}
        
		// Copy it out as optional return argument:
		PsychCopyOutDoubleArg(1, kPsychArgOptional, (double) priorityLevel);
		
		// Query if a new level should be set:
		priorityLevel = -1;
		PsychCopyInIntegerArg(2, kPsychArgOptional, &priorityLevel);

		// Priority level provided?
		if (priorityLevel > -1) {
			// Map to new scheduling class:
			if (priorityLevel > 2) PsychErrorExitMsg(PsychErorr_argumentValueOutOfRange, "Invalid Priority level: Requested Priority() level must not exceed 2.");

			switch(priorityLevel) {
				case 0: // Standard scheduling:
					SetPriorityClass(currentProcess, NORMAL_PRIORITY_CLASS);

					// Disable any MMCSS scheduling for us:
					PsychSetThreadPriority((psych_thread*) 0x1, 0, 0);
				break;
				
				case 1: // High priority scheduling:
					SetPriorityClass(currentProcess, HIGH_PRIORITY_CLASS);

					// Additionally try to schedule us MMCSS: This will lift us roughly into the
					// same scheduling range as REALTIME_PRIORITY_CLASS, even if we are non-admin users
					// on Vista and Windows-7 and later, however with a scheduler safety net applied.
					PsychSetThreadPriority((psych_thread*) 0x1, 10, 0);
				break;
				
				case 2: // Realtime scheduling:
					// This can fail if Matlab is not running under a user account with proper permissions:
					if ((0 == SetPriorityClass(currentProcess, REALTIME_PRIORITY_CLASS)) || (REALTIME_PRIORITY_CLASS != GetPriorityClass(currentProcess))) {
						// Failed to get RT-Scheduling. Let's try at least high priority scheduling:
						SetPriorityClass(currentProcess, HIGH_PRIORITY_CLASS);
						
						// Additionally try to schedule us MMCSS: This will lift us roughly into the
						// same scheduling range as REALTIME_PRIORITY_CLASS, even if we are non-admin users
						// on Vista and Windows-7 and later, however with a scheduler safety net applied.
						PsychSetThreadPriority((psych_thread*) 0x1, 10, 0);
					}
				break;
			}
		}
		// End of Priority() helper for Win32.
	  }
	}
#endif
	
#if PSYCH_SYSTEM == PSYCH_LINUX
	double myvaluators[100];
	int    numvaluators;
	unsigned char keys_return[32];
	char* keystring;
	PsychGenericScriptType *kbNames;
	CGDirectDisplayID dpy;
	Window rootwin, childwin, mywin;
	int i, j, mx, my, dx, dy;
	double mxd, myd, dxd, dyd;
	unsigned int mask_return;
	double timestamp;
	int numButtons;
	double* buttonArray;
	PsychNativeBooleanType* buttonStates;
	int keysdown;
	XEvent event_return;
	XKeyPressedEvent keypressevent;
	int screenNumber;
	int priorityLevel;
	struct sched_param schedulingparam;
	PsychWindowRecordType *windowRecord;
	int mouseIndex;
	XIButtonState buttons_return;
	XIModifierState modifiers_return;
	XIGroupState group_return;

	PsychPushHelp(useString, synopsisString, seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};

	PsychCopyInIntegerArg(1, kPsychArgRequired, &numButtons);

	// Retrieve optional screenNumber argument:
	if (numButtons!=-5) {
		screenNumber = 0;
		if (PsychIsScreenNumberArg(2)) {
			PsychCopyInScreenNumberArg(2, FALSE, &screenNumber);
		}

		// Map screenNumber to X11 display handle and screenid:
		PsychGetCGDisplayIDFromScreenNumber(&dpy, screenNumber);

		if (PsychIsWindowIndexArg(2)) {
			PsychAllocInWindowRecordArg(2, TRUE, &windowRecord);
			if (!PsychIsOnscreenWindow(windowRecord)) {
				PsychErrorExitMsg(PsychError_user, "Provided window handle isn't an onscreen window, as required.");
			}

			screenNumber = windowRecord->screenNumber;
			mywin = windowRecord->targetSpecific.xwindowHandle;

			// Map screenNumber to X11 display handle and screenid:
			PsychGetCGDisplayIDFromScreenNumber(&dpy, screenNumber);

		} else {
			mywin = RootWindow(dpy, PsychGetXScreenIdForScreen(screenNumber));
		}
	}

	// Default to "old school" mouse query - System default mouse via X core protocol:
	mouseIndex = -1;
	PsychCopyInIntegerArg(3, FALSE, &mouseIndex);

	// Are we operating in 'GetMouseHelper' mode? numButtons>=0 indicates this.
	if (numButtons>=0) {
	  // Mouse pointer query mode:
	  numvaluators = 0;

	  if (mouseIndex >= 0) {
		// XInput-2 query for handling of multiple mouse pointers:

		// Query input device list for screen:
		int nDevices;
		XIDeviceInfo* indevs = PsychGetInputDevicesForScreen(screenNumber, &nDevices);

		// Sanity check:
		if (NULL == indevs) PsychErrorExitMsg(PsychError_user, "Sorry, your system does not support individual mouse pointer queries.");
		if (mouseIndex >= nDevices) PsychErrorExitMsg(PsychError_user, "Invalid 'mouseIndex' provided. No such device.");
		if ((indevs[mouseIndex].use != XIMasterPointer) && (indevs[mouseIndex].use != XISlavePointer) && (indevs[mouseIndex].use != XIFloatingSlave)) {
			PsychErrorExitMsg(PsychError_user, "Invalid 'mouseIndex' provided. Not a pointer device.");
		}

		// We requery the device info struct to retrieve updated live device state:
		// Crucial for slave pointers to get any state at all, but also needed on
		// master pointers to get the state of additional valuators, e.g., pen pressure,
		// touch area, tilt etc. for digitizer tablets, touch pads etc. For master pointers,
		// the primary 2 axis for 2D (x,y) position and the button/modifier state will be
		// queried via a dedicated XIQueryPointer() call, so that info gets overriden.
		indevs = XIQueryDevice(dpy, indevs[mouseIndex].deviceid, &numButtons);
		modifiers_return.effective = 0;

		// Query real number of mouse buttons and the raw button and axis state
		// stored inside the device itself. This is done mostly because slave pointer
		// devices don't support XIQueryPointer() so we get their relevant info from the
		// XIDeviceInfo struct itself:
		numButtons = 0;
		numvaluators = 0;
		memset(myvaluators, 0, sizeof(myvaluators));

		if (PsychIsArgPresent(PsychArgOut, 6)) {
			// Usercode wants valuator info structs:
			for (i = 0; i < indevs->num_classes; i++) if (indevs->classes[i]->type == XIValuatorClass) numIValuators++;
			PsychAllocOutStructArray(6, TRUE, numIValuators, numValuatorStructFieldNames, valuatorInfo, &valuatorStruct);
		}

		for (i = 0; i < indevs->num_classes; i++) {
			// printf("Class %i: Type %i\n", i, (int) indevs->classes[i]->type);
			if (indevs->classes[i]->type == XIButtonClass) {
				// Number of buttons: For all pointers.
				numButtons = ((XIButtonClassInfo*) indevs->classes[i])->num_buttons;

				// Button state for slave pointers. Will get overriden for master pointers:
				buttons_return.mask = ((XIButtonClassInfo*) indevs->classes[i])->state.mask;
				buttons_return.mask_len = ((XIButtonClassInfo*) indevs->classes[i])->state.mask_len;
			}

			// Axis state for slave pointers. First two axis (x,y) will get overriden for master pointers:
			if (indevs->classes[i]->type == XIValuatorClass) {
				XIValuatorClassInfo* axis = (XIValuatorClassInfo*) indevs->classes[i];
				if (axis->number == 0) mxd = axis->value;  // x-Axis.
				if (axis->number == 1) myd = axis->value;  // y-Axis.

				// Additional axis, e.g., digitizer tablet, touchpads etc.:
				if (axis->number >= 0 && axis->number < 100) {
					myvaluators[axis->number] = axis->value;
					numvaluators = (numvaluators >= axis->number + 1) ? numvaluators : axis->number + 1;
				}

				// Assign valuator info struct, if requested:
				if (valuatorStruct) {
					if (axis->label != None) {
						char* atomlabel =  XGetAtomName(dpy, axis->label);
						PsychSetStructArrayStringElement("label", axis->number, atomlabel, valuatorStruct);
						XFree(atomlabel);
					} else {
						PsychSetStructArrayStringElement("label", axis->number, "None", valuatorStruct);
					}

					PsychSetStructArrayDoubleElement("min", axis->number, (double) axis->min, valuatorStruct);
					PsychSetStructArrayDoubleElement("max", axis->number, (double) axis->max, valuatorStruct);
					PsychSetStructArrayDoubleElement("resolution", axis->number, (double) axis->resolution, valuatorStruct);
					PsychSetStructArrayDoubleElement("mode", axis->number, (double) axis->mode, valuatorStruct);
					PsychSetStructArrayDoubleElement("sourceID", axis->number, (double) axis->sourceid, valuatorStruct);
				}
				// printf("AXIS %i, LABEL = %s, MIN = %f, MAX = %f, VAL = %f\n", axis->number, (char*) "NONE", (float) axis->min, (float) axis->max, (float) axis->value);
			}
		}

		// Add 32 buttons for modifier key state vector:
		numButtons += 32;

		// A real master pointer: Use official query for mouse devices.
		if (indevs->use == XIMasterPointer) {
			// Query pointer location and state:
			XIQueryPointer(dpy, indevs->deviceid, RootWindow(dpy, PsychGetXScreenIdForScreen(screenNumber)), &rootwin, &childwin, &mxd, &myd, &dxd, &dyd,
				       &buttons_return, &modifiers_return, &group_return);
		}

		// Copy out mouse x and y position:
		PsychCopyOutDoubleArg(1, kPsychArgOptional, mxd);
		PsychCopyOutDoubleArg(2, kPsychArgOptional, myd);

		// Copy out mouse button state:
		PsychAllocOutDoubleMatArg(3, kPsychArgOptional, (int)1, (int) numButtons, (int)1, &buttonArray);
		memset(buttonArray, 0, sizeof(double) * numButtons);

		if (numButtons > 0) {
			// Mouse buttons:
			const int buttonOffset = 1; // Buttons start at bit 1, not 0 for some strange reason? At least so on Ubuntu 10.10 and 11.10 with 2 mice and 1 joystick?
			for (i = buttonOffset; (i < numButtons - 32) && ((i / 8 ) < buttons_return.mask_len); i++) {
				buttonArray[i - buttonOffset] = (double) ((buttons_return.mask[i / 8] & (1 << (i % 8))) ? 1 : 0);
			}

			// Free mask if retrieved via XIQueryPointer():
			if (indevs->use == XIMasterPointer) free(buttons_return.mask);

			// Append modifier key state from associated master keyboard. Last 32 entries:
			for (i = 0; i < 32; i++) {
				buttonArray[numButtons - 32 + i] = (double) ((modifiers_return.effective & (1 << i)) ? 1 : 0);
			}
		}

		// Release live state info structure:
		XIFreeDeviceInfo(indevs);
	  }
	  else {
		// Old school core protocol query of virtual core pointer:
		XQueryPointer(dpy, RootWindow(dpy, PsychGetXScreenIdForScreen(screenNumber)), &rootwin, &childwin, &mx, &my, &dx, &dy, &mask_return);
	  
		// Copy out mouse x and y position:
		PsychCopyOutDoubleArg(1, kPsychArgOptional, (double) mx);
		PsychCopyOutDoubleArg(2, kPsychArgOptional, (double) my);
	  
		// Copy out mouse button state:
		PsychAllocOutDoubleMatArg(3, kPsychArgOptional, (int)1, (int)numButtons, (int)1, &buttonArray);

		// Bits 8, 9 and 10 of mask_return seem to correspond to mouse buttons
		// 1, 2 and 3 of a mouse for some weird reason. Bits 0-7 describe keyboard modifier keys
		// like Alt, Ctrl, Shift, ScrollLock, NumLock, CapsLock...
		// We remap here, so the first three returned entries correspond to the mouse buttons and
		// the rest is attached behind, if requested...
	  
		// Mouse buttons: Left, Middle, Right == 0, 1, 2, aka 1,2,3 in Matlab space...
		for (i=0; i<numButtons && i<3; i++) {
			buttonArray[i] = (mask_return & (1<<(i+8))) ? 1 : 0; 
		}
		// Modifier keys 0 to 7 appended:
		for (i=3; i<numButtons && i<3+8; i++) {
			buttonArray[i] = (mask_return & (1<<(i-3))) ? 1 : 0; 
		}
		// Everything else appended:
		for (i=11; i<numButtons; i++) {
			buttonArray[i] = (mask_return & (1<<i)) ? 1 : 0; 
		}
	  }

	  // Return optional 4th argument: Focus state. Returns 1 if our window has
	  // keyboard input focus, zero otherwise:
	  XGetInputFocus(dpy, &rootwin, &i);
	  PsychCopyOutDoubleArg(4, kPsychArgOptional, (double) (rootwin == mywin) ? 1 : 0);

	  // Return optional valuator values:
	  PsychCopyOutDoubleMatArg(5, kPsychArgOptional, (int) 1, (int) numvaluators, (int) 1, &myvaluators[0]);
	}
	else {
	  // 'KeyboardHelper' mode: We implement either KbCheck() or KbWait() via X11.
	  // This is a hack to provide keyboard queries until a PsychHID() implementation
	  // for Linux is available...

		// Special codes -10 to -15? --> Console keyboard queries:
		if(numButtons <= -10 && numButtons >= -15) {
			ConsoleInputHelper((int) numButtons);
			return(PsychError_none);
		}
		
	  if (numButtons==-1 || numButtons==-2) {
	    // KbCheck()/KbWait() mode:

	    // Switch X-Server into synchronous mode: We need this to get
	    // a higher timing precision.
	    XSynchronize(dpy, TRUE);

	    do {
	      // Reset overall key state to "none pressed":
	      keysdown=0;

	      // Request current keyboard state from X-Server:
	      XQueryKeymap(dpy, keys_return);

	      // Request current time of query:
	      PsychGetAdjustedPrecisionTimerSeconds(&timestamp);

	      // Any key down?
	      for (i=0; i<32; i++) keysdown+=(unsigned int) keys_return[i];
	      
	      // We repeat until any key pressed if in KbWait() mode, otherwise we
	      // exit the loop after first iteration in KbCheck mode.
	      if ((numButtons==-1) || ((numButtons==-2) && (keysdown>0))) break;

	      // Sleep for a few milliseconds before next KbWait loop iteration:
	      PsychWaitIntervalSeconds(0.01);
	    } while(1);

	    if (numButtons==-2) {
	      // Copy out time:
	      PsychCopyOutDoubleArg(1, kPsychArgOptional, timestamp);
	    }
	    else {
	      // KbCheck mode:
	      
	      // Copy out overall keystate:
	      PsychCopyOutDoubleArg(1, kPsychArgOptional, (keysdown>0) ? 1 : 0);
	      // copy out timestamp:
	      PsychCopyOutDoubleArg(2, kPsychArgOptional, timestamp);	      
	      // Copy keyboard state:
	      PsychAllocOutBooleanMatArg(3, kPsychArgOptional, 1, 256, 1, &buttonStates);

	      // Map 32 times 8 bitvector to 256 element return vector:
	      for(i=0; i<32; i++) {
				for(j=0; j<8; j++) {
		  			buttonStates[i*8 + j] = (PsychNativeBooleanType)(keys_return[i] & (1<<j)) ? 1 : 0;
				}
	      }
	    }
	  }
	  else if (numButtons == -3) {
	    // numButtons == -3 --> KbName mapping mode:
	    // Return the full keyboard keycode to ASCII character code mapping table...
	    PsychAllocOutCellVector(1, kPsychArgOptional, 256, &kbNames);

	    for(i=0; i<256; i++) {
	      // Map keyboard scan code to KeySym:
	      keystring = XKeysymToString(XKeycodeToKeysym(dpy, i, 0));
	      if (keystring) {
		// Character found: Return its ASCII name string:
		PsychSetCellVectorStringElement(i, keystring, kbNames);
	      }
	      else {
		// No character for this keycode:
		PsychSetCellVectorStringElement(i, "", kbNames);
	      }
	    }
	  }
	  else if (numButtons == -4) {
	    // GetChar() emulation.

/* 	    do { */
/* 	      // Fetch next keypress event from queue, block if none is available... */
/* 	      keystring = NULL; */
/* 	      XNextEvent(dpy, &event_return); */
/* 	      // Check for valid keypress event and extract character: */
/* 	      if (event_return.type == KeyPress) { */
/* 		keypressevent = (XKeyPressedEvent) event_return; */
/* 		keystring = NULL; */
/* 		keystring = XKeysymToString(XKeycodeToKeysym(dpy, keypressevent.keycode, 0)); */
/* 	      } */
/* 	      // Repeat until a valid char is returned. */
/* 	    } while (keystring == NULL); */

/* 	    // Copy out character: */
/* 	    PsychCopyOutCharArg(1, kPsychArgOptional, (char) keystring); */
/* 	    // Copy out time: */
/* 	    PsychCopyOutDoubleArg(2, kPsychArgOptional, (double) keypressevent.time); */
	  }
	  else if (numButtons==-5) {
		// Priority() - helper mode: The 2nd argument is the priority level:

		// Query scheduling policy and priority:
		pthread_getschedparam(pthread_self(), &priorityLevel, &schedulingparam);

		// If scheduling mode is a realtime mode (RoundRobin realtime RR, or FIFO realtime),
		// then assign RT priority level (range 1-99) as current priorityLevel, otherwise
		// assign non realtime priority level zero:
		priorityLevel = (priorityLevel == SCHED_RR || priorityLevel == SCHED_FIFO) ? schedulingparam.sched_priority : 0;
        
		// Copy it out as optional return argument:
		PsychCopyOutDoubleArg(1, kPsychArgOptional, (double) priorityLevel);
		
		// Query if a new level should be set:
		priorityLevel = -1;
		PsychCopyInIntegerArg(2, kPsychArgOptional, &priorityLevel);

		errno=0;
		// Priority level provided?
		if (priorityLevel > -1) {
			// Map to new scheduling class:
			if (priorityLevel > 99 || priorityLevel < 0) PsychErrorExitMsg(PsychErorr_argumentValueOutOfRange, "Invalid Priority level: Requested Priority() level must be between zero and 99!");

			if (priorityLevel > 0) {
				// Realtime FIFO scheduling and all pages of Matlab/Octave locked into memory:
				schedulingparam.sched_priority = priorityLevel;
				priorityLevel = pthread_setschedparam(pthread_self(), SCHED_FIFO, &schedulingparam);
				if (priorityLevel == -1) {
					// Failed!
					if(!PsychPrefStateGet_SuppressAllWarnings()) {
	    					printf("PTB-ERROR: Failed to enable realtime-scheduling with Priority(%i) [%s]!\n", schedulingparam.sched_priority, strerror(errno));
						if (errno==EPERM) {
							printf("PTB-ERROR: You need to run Matlab/Octave with root-privileges, or run the script PsychLinuxConfiguration once for this to work.\n");
						}
					}
					errno=0;
				}
				else {
					// RT-Scheduling active. Lock all current and future memory:
					priorityLevel = mlockall(MCL_CURRENT | MCL_FUTURE);
					if (priorityLevel!=0) {
						// Failed! Report problem as warning, but don't worry further. 
	    					if(!PsychPrefStateGet_SuppressAllWarnings()) printf("PTB-WARNING: Failed to enable system memory locking with Priority(%i) [%s]!\n", schedulingparam.sched_priority, strerror(errno));
						// Undo any possibly partial mlocks....
						munlockall();
						errno=0;
					}
				}
			}
			else {
				// Standard scheduling and no memory locking:
				schedulingparam.sched_priority = 0;
				priorityLevel = pthread_setschedparam(pthread_self(), SCHED_OTHER, &schedulingparam);
				if (priorityLevel == -1) {
					// Failed!
					if(!PsychPrefStateGet_SuppressAllWarnings()) {
	    					printf("PTB-ERROR: Failed to disable realtime-scheduling with Priority(%i) [%s]!\n", schedulingparam.sched_priority, strerror(errno));
						if (errno==EPERM) {
							printf("PTB-ERROR: You need to run Matlab/Octave with root-privileges, or run the script PsychLinuxConfiguration once for this to work.\n");
						}
					}
					errno=0;
				}

				munlockall();
				errno=0;
			}
			// End of setup of new Priority...
		}
		// End of Priority() helper for Linux.
	  }
	}	// End of special functions handling for Linux...
#endif
	return(PsychError_none);	
}
Пример #14
0
void QXcbConnection::xi2SetupDevices()
{
#ifndef QT_NO_TABLETEVENT
    m_tabletData.clear();
#endif
    m_scrollingDevices.clear();

    if (!m_xi2Enabled)
        return;

    Display *xDisplay = static_cast<Display *>(m_xlib_display);
    int deviceCount = 0;
    XIDeviceInfo *devices = XIQueryDevice(xDisplay, XIAllDevices, &deviceCount);
    for (int i = 0; i < deviceCount; ++i) {
        // Only non-master pointing devices are relevant here.
        if (devices[i].use != XISlavePointer)
            continue;
        qCDebug(lcQpaXInputDevices) << "input device "<< devices[i].name;
#ifndef QT_NO_TABLETEVENT
        TabletData tabletData;
#endif
        ScrollingDevice scrollingDevice;
        for (int c = 0; c < devices[i].num_classes; ++c) {
            switch (devices[i].classes[c]->type) {
            case XIValuatorClass: {
                XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(devices[i].classes[c]);
                const int valuatorAtom = qatom(vci->label);
                qCDebug(lcQpaXInputDevices) << "   has valuator" << atomName(vci->label) << "recognized?" << (valuatorAtom < QXcbAtom::NAtoms);
#ifndef QT_NO_TABLETEVENT
                if (valuatorAtom < QXcbAtom::NAtoms) {
                    TabletData::ValuatorClassInfo info;
                    info.minVal = vci->min;
                    info.maxVal = vci->max;
                    info.number = vci->number;
                    tabletData.valuatorInfo[valuatorAtom] = info;
                }
#endif // QT_NO_TABLETEVENT
                if (valuatorAtom == QXcbAtom::RelHorizScroll || valuatorAtom == QXcbAtom::RelHorizWheel)
                    scrollingDevice.lastScrollPosition.setX(vci->value);
                else if (valuatorAtom == QXcbAtom::RelVertScroll || valuatorAtom == QXcbAtom::RelVertWheel)
                    scrollingDevice.lastScrollPosition.setY(vci->value);
                break;
            }
#ifdef XCB_USE_XINPUT21
            case XIScrollClass: {
                XIScrollClassInfo *sci = reinterpret_cast<XIScrollClassInfo *>(devices[i].classes[c]);
                if (sci->scroll_type == XIScrollTypeVertical) {
                    scrollingDevice.orientations |= Qt::Vertical;
                    scrollingDevice.verticalIndex = sci->number;
                    scrollingDevice.verticalIncrement = sci->increment;
                }
                else if (sci->scroll_type == XIScrollTypeHorizontal) {
                    scrollingDevice.orientations |= Qt::Horizontal;
                    scrollingDevice.horizontalIndex = sci->number;
                    scrollingDevice.horizontalIncrement = sci->increment;
                }
                break;
            }
            case XIButtonClass: {
                XIButtonClassInfo *bci = reinterpret_cast<XIButtonClassInfo *>(devices[i].classes[c]);
                if (bci->num_buttons >= 5) {
                    Atom label4 = bci->labels[3];
                    Atom label5 = bci->labels[4];
                    // Some drivers have no labels on the wheel buttons, some have no label on just one and some have no label on
                    // button 4 and the wrong one on button 5. So we just check that they are not labelled with unrelated buttons.
                    if ((!label4 || qatom(label4) == QXcbAtom::ButtonWheelUp || qatom(label4) == QXcbAtom::ButtonWheelDown) &&
                        (!label5 || qatom(label5) == QXcbAtom::ButtonWheelUp || qatom(label5) == QXcbAtom::ButtonWheelDown))
                        scrollingDevice.legacyOrientations |= Qt::Vertical;
                }
                if (bci->num_buttons >= 7) {
                    Atom label6 = bci->labels[5];
                    Atom label7 = bci->labels[6];
                    if ((!label6 || qatom(label6) == QXcbAtom::ButtonHorizWheelLeft) && (!label7 || qatom(label7) == QXcbAtom::ButtonHorizWheelRight))
                        scrollingDevice.legacyOrientations |= Qt::Horizontal;
                }
                qCDebug(lcQpaXInputDevices, "   has %d buttons", bci->num_buttons);
                break;
            }
#endif
            case XIKeyClass:
                qCDebug(lcQpaXInputDevices) << "   it's a keyboard";
                break;
#ifdef XCB_USE_XINPUT22
            case XITouchClass:
                // will be handled in deviceForId()
                break;
#endif
            default:
                qCDebug(lcQpaXInputDevices) << "   has class" << devices[i].classes[c]->type;
                break;
            }
        }
        bool isTablet = false;
#ifndef QT_NO_TABLETEVENT
        // If we have found the valuators which we expect a tablet to have, it might be a tablet.
        if (tabletData.valuatorInfo.contains(QXcbAtom::AbsX) &&
                tabletData.valuatorInfo.contains(QXcbAtom::AbsY) &&
                tabletData.valuatorInfo.contains(QXcbAtom::AbsPressure))
            isTablet = true;

        // But we need to be careful not to take the touch and tablet-button devices as tablets.
        QByteArray name = QByteArray(devices[i].name).toLower();
        QString dbgType = QLatin1String("UNKNOWN");
        if (name.contains("eraser")) {
            isTablet = true;
            tabletData.pointerType = QTabletEvent::Eraser;
            dbgType = QLatin1String("eraser");
        } else if (name.contains("cursor")) {
            isTablet = true;
            tabletData.pointerType = QTabletEvent::Cursor;
            dbgType = QLatin1String("cursor");
        } else if ((name.contains("pen") || name.contains("stylus")) && isTablet) {
            tabletData.pointerType = QTabletEvent::Pen;
            dbgType = QLatin1String("pen");
        } else if (name.contains("wacom") && isTablet && !name.contains("touch")) {
            // combined device (evdev) rather than separate pen/eraser (wacom driver)
            tabletData.pointerType = QTabletEvent::Pen;
            dbgType = QLatin1String("pen");
        } else if (name.contains("aiptek") /* && device == QXcbAtom::KEYBOARD */) {
            // some "Genius" tablets
            isTablet = true;
            tabletData.pointerType = QTabletEvent::Pen;
            dbgType = QLatin1String("pen");
        } else {
            isTablet = false;
        }

        if (isTablet) {
            tabletData.deviceId = devices[i].deviceid;
            m_tabletData.append(tabletData);
            qCDebug(lcQpaXInputDevices) << "   it's a tablet with pointer type" << dbgType;
        }
#endif // QT_NO_TABLETEVENT

#ifdef XCB_USE_XINPUT21
        if (scrollingDevice.orientations || scrollingDevice.legacyOrientations) {
            scrollingDevice.deviceId = devices[i].deviceid;
            // Only use legacy wheel button events when we don't have real scroll valuators.
            scrollingDevice.legacyOrientations &= ~scrollingDevice.orientations;
            m_scrollingDevices.insert(scrollingDevice.deviceId, scrollingDevice);
            qCDebug(lcQpaXInputDevices) << "   it's a scrolling device";
        }
#endif

        if (!isTablet) {
            // touchDeviceForId populates XInput2DeviceData the first time it is called
            // with a new deviceId. On subsequent calls it will return the cached object.
            XInput2TouchDeviceData *dev = touchDeviceForId(devices[i].deviceid);
            if (dev && lcQpaXInputDevices().isDebugEnabled()) {
                if (dev->qtTouchDevice->type() == QTouchDevice::TouchScreen)
                    qCDebug(lcQpaXInputDevices, "   it's a touchscreen with type %d capabilities 0x%X max touch points %d",
                            dev->qtTouchDevice->type(), (unsigned int)dev->qtTouchDevice->capabilities(),
                            dev->qtTouchDevice->maximumTouchPoints());
                else if (dev->qtTouchDevice->type() == QTouchDevice::TouchPad)
                    qCDebug(lcQpaXInputDevices, "   it's a touchpad with type %d capabilities 0x%X max touch points %d size %f x %f",
                            dev->qtTouchDevice->type(), (unsigned int)dev->qtTouchDevice->capabilities(),
                            dev->qtTouchDevice->maximumTouchPoints(),
                            dev->size.width(), dev->size.height());
            }
        }
    }
    XIFreeDeviceInfo(devices);
}
Пример #15
0
bool xorg::testing::XServer::WaitForDevice(::Display *display, const std::string &name,
                                           time_t timeout)
{
    int opcode;
    int event_start;
    int error_start;
    bool device_found = false;

    if (!XQueryExtension(display, "XInputExtension", &opcode, &event_start,
                         &error_start))
        throw std::runtime_error("Failed to query XInput extension");

    XIEventMask *masks;
    int nmasks;
    bool mask_set, mask_created;
    masks = set_hierarchy_mask(display, &nmasks, &mask_set, &mask_created);

    XIDeviceInfo *info;
    int ndevices;

    info = XIQueryDevice(display, XIAllDevices, &ndevices);
    for (int i = 0; !device_found && i < ndevices; i++) {
      device_found = (name.compare(info[i].name) == 0);
    }
    XIFreeDeviceInfo(info);

    while (!device_found &&
           WaitForEventOfType(display, GenericEvent, opcode,
                              XI_HierarchyChanged, timeout)) {
        XEvent event;
        if (XNextEvent(display, &event) != Success)
            throw std::runtime_error("Failed to get X event");

        XGenericEventCookie *xcookie =
            reinterpret_cast<XGenericEventCookie*>(&event.xcookie);
        if (!XGetEventData(display, xcookie))
            throw std::runtime_error("Failed to get X event data");

        XIHierarchyEvent *hierarchy_event =
            reinterpret_cast<XIHierarchyEvent*>(xcookie->data);

        if (!(hierarchy_event->flags & XIDeviceEnabled)) {
            XFreeEventData(display, xcookie);
            continue;
        }

        device_found = false;
        for (int i = 0; i < hierarchy_event->num_info; i++) {
            if (!(hierarchy_event->info[i].flags & XIDeviceEnabled))
                continue;

            int num_devices;
            XIDeviceInfo *device_info =
                XIQueryDevice(display, hierarchy_event->info[i].deviceid,
                              &num_devices);
            if (num_devices != 1 || !device_info)
                throw std::runtime_error("Failed to query device");

            if (name.compare(device_info[0].name) == 0) {
                device_found = true;
                break;
            }
        }

        XFreeEventData(display, xcookie);

        if (device_found)
          break;
    }

    unset_hierarchy_mask(display, masks, nmasks, mask_set, mask_created);

    return device_found;
}
Пример #16
0
void setup_input_devices (GromitData *data)
{
    /* ungrab all */
    release_grab (data, NULL);

    /* and clear our own device data list */
    GHashTableIter it;
    gpointer value;
    g_hash_table_iter_init (&it, data->devdatatable);
    while (g_hash_table_iter_next (&it, NULL, &value))
        g_free(value);
    g_hash_table_remove_all(data->devdatatable);


    /* get devices */
    GdkDeviceManager *device_manager = gdk_display_get_device_manager(data->display);
    GList *devices, *d;
    int i = 0;

    devices = g_list_concat(gdk_device_manager_list_devices
                            (device_manager, GDK_DEVICE_TYPE_MASTER),
                            gdk_device_manager_list_devices
                            (device_manager, GDK_DEVICE_TYPE_SLAVE));
    for(d = devices; d; d = d->next)
    {
        GdkDevice *device = (GdkDevice *) d->data;

        /* only enable devices with 2 ore more axes */
        if (gdk_device_get_source(device) != GDK_SOURCE_KEYBOARD && gdk_device_get_n_axes(device) >= 2)
        {
            gdk_device_set_mode (device, GDK_MODE_SCREEN);

            GromitDeviceData *devdata;

            devdata  = g_malloc0(sizeof (GromitDeviceData));
            devdata->device = device;
            devdata->index = i;

            /* get attached keyboard and grab the hotkey */
            if (!data->hot_keycode)
            {
                g_printerr("ERROR: Grabbing hotkey from attached keyboard "
                           "of '%s' failed, no hotkey defined.\n",
                           gdk_device_get_name(device));
                g_free(devdata);
                continue;
            }

            /* if this is a slave device, we need the master */
            GdkDevice *kdevice=device;
            if(gdk_device_get_device_type (device) == GDK_DEVICE_TYPE_SLAVE)
                kdevice=gdk_device_get_associated_device (device);

            gint dev_id = -1;
            g_object_get(kdevice, "device-id", &dev_id, NULL);

            gint kbd_dev_id = -1;
            XIDeviceInfo* devinfo;
            int devicecount = 0;

            devinfo = XIQueryDevice(GDK_DISPLAY_XDISPLAY(data->display),
                                    dev_id,
                                    &devicecount);
            if(devicecount)
                kbd_dev_id = devinfo->attachment;
            XIFreeDeviceInfo(devinfo);

            if(kbd_dev_id != -1)
            {
                if(data->debug)
                    g_printerr("DEBUG: Grabbing hotkey from keyboard '%d' .\n", kbd_dev_id);

                XIEventMask mask;
                unsigned char bits[4] = {0,0,0,0};
                mask.mask = bits;
                mask.mask_len = sizeof(bits);

                XISetMask(bits, XI_KeyPress);
                XISetMask(bits, XI_KeyRelease);

                XIGrabModifiers modifiers[] = {{XIAnyModifier, 0}};
                int nmods = 1;

                gdk_error_trap_push ();

                XIGrabKeycode( GDK_DISPLAY_XDISPLAY(data->display),
                               kbd_dev_id,
                               data->hot_keycode,
                               GDK_WINDOW_XID(data->root),
                               GrabModeAsync,
                               GrabModeAsync,
                               True,
                               &mask,
                               nmods,
                               modifiers);

                XSync(GDK_DISPLAY_XDISPLAY(data->display), False);
                if(gdk_error_trap_pop())
                {
                    g_printerr("ERROR: Grabbing hotkey from keyboard device %d failed.\n",
                               kbd_dev_id);
                    g_free(devdata);
                    continue;
                }
            }

            g_hash_table_insert(data->devdatatable, device, devdata);
            g_printerr ("Enabled Device %d: \"%s\", (Type: %d)\n",
                        i++, gdk_device_get_name(device), gdk_device_get_source(device));
        }
    }

    g_printerr ("Now %d enabled devices.\n", g_hash_table_size(data->devdatatable));
}
Пример #17
0
// Constructor
CalibratorEvdev::CalibratorEvdev(const char* const device_name0,
                                 const XYinfo& axys0,
                                 XID device_id,
                                 const int thr_misclick,
                                 const int thr_doubleclick,
                                 const OutputType output_type,
                                 const char* geometry,
                                 const bool use_valuator,
                                 const bool use_timeout,
                                 const char* output_filename)
  : Calibrator(device_name0, axys0, thr_misclick, thr_doubleclick, output_type, geometry, use_timeout, output_filename)
{
    // init
    display = XOpenDisplay(NULL);
    if (display == NULL) {
        throw WrongCalibratorException("Evdev: Unable to connect to X server");
    }

    // normaly, we already have the device id
    if (device_id == (XID)-1) {
        devInfo = xinput_find_device_info(display, device_name, False);
        if (!devInfo) {
            XCloseDisplay(display);
            throw WrongCalibratorException("Evdev: Unable to find device");
        }
        device_id = devInfo->id;
    }

    dev = XOpenDevice(display, device_id);
    if (!dev) {
        XCloseDisplay(display);
        throw WrongCalibratorException("Evdev: Unable to open device");
    }

#ifndef HAVE_XI_PROP
    throw WrongCalibratorException("Evdev: you need at least libXi 1.2 and inputproto 1.5 for dynamic recalibration of evdev.");
#else

    // XGetDeviceProperty vars
    Atom            property;
    Atom            act_type;
    int             act_format;
    unsigned long   nitems, bytes_after;
    unsigned char   *data, *ptr;

    // get "Evdev Axis Calibration" property
    property = xinput_parse_atom(display, "Evdev Axis Calibration");
    if (XGetDeviceProperty(display, dev, property, 0, 1000, False,
                           AnyPropertyType, &act_type, &act_format,
                           &nitems, &bytes_after, &data) != Success)
    {
        XCloseDevice(display, dev);
        XCloseDisplay(display);
        throw WrongCalibratorException("Evdev: \"Evdev Axis Calibration\" property missing, not a (valid) evdev device");

    } else {
        if (act_format != 32 || act_type != XA_INTEGER) {
            XCloseDevice(display, dev);
            XCloseDisplay(display);
            throw WrongCalibratorException("Evdev: invalid \"Evdev Axis Calibration\" property format");

        } else if (use_valuator) {
            int ndevices = 0, i, j;
            XIDeviceInfo *info = XIQueryDevice(display, device_id, &ndevices);

            if (ndevices != 1) {
                XCloseDevice(display, dev);
                XCloseDisplay(display);
                throw WrongCalibratorException("Evdev: unknown Xinput device ID???");
            }

            for (i = 0; i < ndevices; i++) {
                XIDeviceInfo *dev = &info[i];

                for (j = 0; j < dev->num_classes; j++) {
                    switch(dev->classes[i]->type) {
                    case XIValuatorClass:
                    {
                        XIValuatorClassInfo *v = (XIValuatorClassInfo*)dev->classes[i];

                        /* Valuator 0 = X, Valuator 1 = Y, others are ignored */
                        switch (v->number) {
                        case 0:
                            old_axys.x.min = v->min;
                            old_axys.x.max = v->max;
                            old_axys.x.invert = false;
                            break;
                        case 1:
                            old_axys.y.min = v->min;
                            old_axys.y.max = v->max;
                            old_axys.y.invert = false;
                            break;
                        default:
                            break;
                        }
                        break;
                    }
                    default:
                        break;
                    }
                }
            }
            XIFreeDeviceInfo(info);

            if (verbose)
                printf("DEBUG: Evdev Axis Calibration set to axis valuators\n");
            (void) set_calibration(old_axys);

        } else if (nitems == 0) {
            if (verbose)
                printf("DEBUG: Evdev Axis Calibration not set, setting to axis valuators to be sure.\n");

            // No axis calibration set, set it to the default one
            // QUIRK: when my machine resumes from a sleep,
            // the calibration property is no longer exported through xinput, but still active
            // not setting the values here would result in a wrong first calibration
            (void) set_calibration(old_axys);

        } else if (nitems > 0) {
            ptr = data;

            old_axys.x.min = *((long*)ptr);
            ptr += sizeof(long);
            old_axys.x.max = *((long*)ptr);
            ptr += sizeof(long);
            old_axys.y.min = *((long*)ptr);
            ptr += sizeof(long);
            old_axys.y.max = *((long*)ptr);
            ptr += sizeof(long);
        }

        XFree(data);
    }

    // get "Evdev Axes Swap" property
    property = xinput_parse_atom(display, "Evdev Axes Swap");
    if (XGetDeviceProperty(display, dev, property, 0, 1000, False,
                           AnyPropertyType, &act_type, &act_format,
                           &nitems, &bytes_after, &data) == Success)
    {
        if (act_format == 8 && act_type == XA_INTEGER && nitems == 1) {
            old_axys.swap_xy = *((char*)data);

            if (verbose)
                printf("DEBUG: Read axes swap value of %i.\n", old_axys.swap_xy);
        }
    }

    // get "Evdev Axes Inversion" property
    property = xinput_parse_atom(display, "Evdev Axis Inversion");
    if (XGetDeviceProperty(display, dev, property, 0, 1000, False,
                AnyPropertyType, &act_type, &act_format,
                &nitems, &bytes_after, &data) == Success) {
        if (act_format == 8 && act_type == XA_INTEGER && nitems == 2) {
            old_axys.x.invert = *((char*)data++);
            old_axys.y.invert = *((char*)data);

            if (verbose)
                printf("DEBUG: Read InvertX=%i, InvertY=%i.\n", old_axys.x.invert, old_axys.y.invert);
        }
    }

    printf("Calibrating EVDEV driver for \"%s\" id=%i\n", device_name, (int)device_id);
    printf("\tcurrent calibration values (from XInput): min_x=%d, max_x=%d and min_y=%d, max_y=%d\n",
                old_axys.x.min, old_axys.x.max, old_axys.y.min, old_axys.y.max);
#endif // HAVE_XI_PROP

}
Пример #18
0
int xinput_init()
{
  int ret = 0;
  int event, error;
  int m_num = 0;
  int k_num = 0;

  memset(devices, 0x00, sizeof(devices));
  nb_devices = 0;

  unsigned int i;
  for(i=0; i<sizeof(device_index)/sizeof(*device_index); ++i)
  {
    device_index[i] = -1;
  }

  dpy = XOpenDisplay(NULL);

  if (!dpy)
  {
    fprintf(stderr, "Failed to open display.\n");
    return -1;
  }

  if (!XQueryExtension(dpy, "XInputExtension", &xi_opcode, &event, &error))
  {
    fprintf(stderr, "X Input extension not available.\n");
    return -1;
  }

  win = create_win(dpy);

  int nxdevices;
  XIDeviceInfo *xdevices, *xdevice;

  xdevices = XIQueryDevice(dpy, XIAllDevices, &nxdevices);

  for (i = 0; nxdevices > 0 && i < (unsigned int) nxdevices; i++)
  {
      xdevice = &xdevices[i];

      if(xdevice->deviceid >= GE_MAX_DEVICES)
      {
        continue;
      }

      device_index[xdevice->deviceid] = nb_devices;

      switch(xdevice->use) {
         case XISlaveKeyboard:
           devices[nb_devices].type = DEVTYPE_KEYBOARD;
           devices[nb_devices].id = k_num;
           ++k_num;
           break;
         case XISlavePointer:
           devices[nb_devices].type = DEVTYPE_MOUSE;
           devices[nb_devices].id = m_num;
           ++m_num;
           break;
      }

      if(devices[nb_devices].type)
      {
        devices[nb_devices].name = strdup(xdevice->name);
        ++nb_devices;
      }
  }

  XIFreeDeviceInfo(xdevices);

  ev_register_source(ConnectionNumber(dpy), i, &xinput_process_events, NULL, &xinput_close);

  XEvent xevent;

  /* get info about current pointer position */
  XQueryPointer(dpy, DefaultRootWindow(dpy),
  &xevent.xbutton.root, &xevent.xbutton.window,
  &xevent.xbutton.x_root, &xevent.xbutton.y_root,
  &xevent.xbutton.x, &xevent.xbutton.y,
  &xevent.xbutton.state);

  mouse_coordinates.x = xevent.xbutton.x;
  mouse_coordinates.y = xevent.xbutton.y;

  return ret;
}
Пример #19
0
/**
 * Build data storage by querying the X server for all input devices.
 * Can be called multiple times, in which case it'll clean out and re-fill
 * update the tree store.
 */
static GtkTreeStore* query_devices(GDeviceSetup* gds)
{
    GtkTreeStore *treestore;
    GtkTreeModel *model;
    GtkTreeIter iter, child;
    XIDeviceInfo *devices, *dev;
    int ndevices;
    int i, j;
    int icontype;
    GdkPixbuf *icon;
    int valid, child_valid;
    int id, masterid;

    if (!gds->treeview)
    {
        treestore = gtk_tree_store_new(NUM_COLS,
                                       G_TYPE_UINT, /* deviceid*/
                                       G_TYPE_STRING, /* name */
                                       G_TYPE_UINT,
                                       GDK_TYPE_PIXBUF,
                                       G_TYPE_UINT
                                       );
        model = GTK_TREE_MODEL(treestore);
    } else
    {
        model = gtk_tree_view_get_model(gds->treeview);
        treestore = GTK_TREE_STORE(model);
    }

    gds->generation++;
    devices = XIQueryDevice(gds->dpy, XIAllDevices, &ndevices);

    /* First, run through all master device and append them to the tree store
     */
    for (i = 0; i < ndevices; i++)
    {
        dev = &devices[i];

        if (dev->use != XIMasterPointer && dev->use != XIMasterKeyboard)
            continue;

        valid = gtk_tree_model_get_iter_first(model, &iter);
        g_debug("MD %d: %s", dev->deviceid,  dev->name);

        while(valid) {
            gtk_tree_model_get(model, &iter, COL_ID, &id, -1);
            if (id == dev->deviceid)
            {
                gtk_tree_store_set(treestore, &iter,
                                   COL_GENERATION, gds->generation, -1);
                valid = 0xFF;
                break;
            }
            valid = gtk_tree_model_iter_next(model, &iter);
        }

        if (valid != 0xFF) /* new MD */
        {
            icontype = (dev->use == XIMasterPointer) ? ICON_MOUSE : ICON_KEYBOARD;
            icon = load_icon(icontype);

            gtk_tree_store_append(treestore, &iter, NULL);
            gtk_tree_store_set(treestore, &iter,
                               COL_ID, dev->deviceid,
                               COL_NAME, dev->name,
                               COL_USE, dev->use,
                               COL_ICON, icon,
                               COL_GENERATION, gds->generation,
                               -1);
            g_object_unref(icon);
        }
    }

    /* search for Floating fake master device */
    valid = gtk_tree_model_get_iter_first(model, &iter);
    while(valid)
    {
        gtk_tree_model_get(model, &iter, COL_ID, &id, -1);
        if (id == ID_FLOATING)
            break;

        valid = gtk_tree_model_iter_next(model, &iter);
    }

    if (!valid)
    {
        /* Attach a fake master device for "Floating" */
        icon = load_icon(ICON_FLOATING);
        gtk_tree_store_append(treestore, &iter, NULL);
        gtk_tree_store_set(treestore, &iter,
                COL_ID, ID_FLOATING,
                COL_NAME, "Floating",
                COL_USE, ID_FLOATING,
                COL_ICON, icon,
                COL_GENERATION, gds->generation,
                -1);
        g_object_unref(icon);
    } else {
        GtkTreeIter prev;
        GtkTreeIter pos = iter; /* current position of Floating */

        /* always move Floating fake device to end of list */
        while(valid)
        {
            prev = iter;
            valid = gtk_tree_model_iter_next(model, &iter);
        }

        gtk_tree_store_move_after(treestore, &pos, &prev);

        /* update generation too */
        gtk_tree_store_set(treestore, &pos,
                           COL_GENERATION, gds->generation, -1);
    }


    /* now that we added all MDs, run through again and add SDs to the
     * respective MD */
    for (i = 0; i < ndevices; i++)
    {
        dev = &devices[i];

        if (dev->use == XIMasterPointer || dev->use == XIMasterKeyboard)
   	  continue;

        g_debug("SD %d: %s", dev->deviceid, dev->name);

	valid = gtk_tree_model_get_iter_first(model, &iter);
	while(valid) {
	  gtk_tree_model_get(model, &iter, COL_ID, &masterid, -1);
	  if(dev->attachment == masterid || (dev->use == XIFloatingSlave && masterid == ID_FLOATING))
	    {
	      /* found master, check if we're already attached to it in
	       * the tree model */
	      child_valid = gtk_tree_model_iter_children(model, &child, &iter);
	      while (child_valid)
		{
		  gtk_tree_model_get(model, &child, COL_ID, &id);

		  if (id == dev->deviceid)
		    {
		      gtk_tree_store_set(treestore, &child,
					 COL_GENERATION, gds->generation, -1);
		      child_valid = 0xFF;
		      break;
		    }

		  child_valid = gtk_tree_model_iter_next(model, &child);
		}

	      /* new slave device, attach */
	      if (child_valid != 0xFF)
		{
		  gtk_tree_store_append(treestore, &child, &iter);
		  gtk_tree_store_set(treestore, &child,
				     COL_ID, dev->deviceid,
				     COL_NAME, dev->name,
				     COL_USE, dev->use,
				     COL_GENERATION, gds->generation,
				     -1);
		}
	      break;
	    }

	  valid = gtk_tree_model_iter_next(model, &iter);
	}
    }

    XIFreeDeviceInfo(devices);

    /* clean tree store of anything that doesn't have the current
       server generation */

    valid = gtk_tree_model_get_iter_first(model, &iter);
    while(valid)
    {
        int gen;

        child_valid = gtk_tree_model_iter_children(model, &child, &iter);
        while(child_valid)
        {
            gtk_tree_model_get(model, &child, COL_GENERATION, &gen, -1);
            if (gen < gds->generation)
                child_valid = gtk_tree_store_remove(treestore, &child);
            else
                child_valid = gtk_tree_model_iter_next(model, &child);
        }

        gtk_tree_model_get(model, &iter, COL_GENERATION, &gen, -1);
        if (gen < gds->generation)
            valid = gtk_tree_store_remove(treestore, &iter);
        else
            valid = gtk_tree_model_iter_next(model, &iter);
    }

    return treestore;
}
Пример #20
0
void X11Extras::x11ResetMouseAccelerationChange()
 {
    //QTextStream out(stdout);

    int xi_opcode, event, error;
    xi_opcode = event = error = 0;
    Display *display = this->display();

    bool result = XQueryExtension(display, "XInputExtension", &xi_opcode, &event, &error);
    if (!result)
    {
        Logger::LogInfo(tr("xinput extension was not found. No mouse acceleration changes will occur."));
        //out << tr("xinput extension was not found. No mouse acceleration changes will occur.") << endl;
    }
    else
    {
        int ximajor = 2, ximinor = 0;
        if (XIQueryVersion(display, &ximajor, &ximinor) != Success)
        {
            Logger::LogInfo(tr("xinput version must be at least 2.0. No mouse acceleration changes will occur."));
            //out << tr("xinput version must be at least 2.0. No mouse acceleration changes will occur.") << endl;
        }
    }

    if (result)
    {
        XIDeviceInfo *all_devices = 0;
        XIDeviceInfo *current_devices = 0;
        XIDeviceInfo *mouse_device = 0;

        int num_devices = 0;
        all_devices = XIQueryDevice(display, XIAllDevices, &num_devices);
        for (int i=0; i < num_devices; i++)
        {
            current_devices = &all_devices[i];
            if (current_devices->use == XISlavePointer && QString::fromUtf8(current_devices->name) == mouseDeviceName)
            {
                Logger::LogInfo(tr("Virtual pointer found with id=%1.").arg(current_devices->deviceid));
                //out << tr("Virtual pointer found with id=%1.").arg(current_devices->deviceid)
                //    << endl;
                mouse_device = current_devices;
            }
        }

        if (mouse_device)
        {
            XDevice *device = XOpenDevice(display, mouse_device->deviceid);

            int num_feedbacks = 0;
            int feedback_id = -1;
            XFeedbackState *feedbacks = XGetFeedbackControl(display, device, &num_feedbacks);
            XFeedbackState *temp = feedbacks;
            for (int i=0; (i < num_feedbacks) && (feedback_id == -1); i++)
            {
                if (temp->c_class == PtrFeedbackClass)
                {
                    feedback_id = temp->id;
                }

                if (i+1 < num_feedbacks)
                {
                    temp = (XFeedbackState*) ((char*) temp + temp->length);
                }
            }

            XFree(feedbacks);
            feedbacks = temp = 0;

            if (feedback_id <= -1)
            {
                Logger::LogInfo(tr("PtrFeedbackClass was not found for virtual pointer."
                                   "No change to mouse acceleration will occur for device with id=%1").arg(device->device_id));
                //out << tr("PtrFeedbackClass was not found for virtual pointer."
                //          "No change to mouse acceleration will occur for device with id=%1").arg(device->device_id)
                //    << endl;
                result = false;
            }
            else
            {
                Logger::LogInfo(tr("Changing mouse acceleration for device with id=%1").arg(device->device_id));
                //out << tr("Changing mouse acceleration for device with id=%1").arg(device->device_id)
                //    << endl;

                XPtrFeedbackControl	feedback;
                feedback.c_class = PtrFeedbackClass;
                feedback.length = sizeof(XPtrFeedbackControl);
                feedback.id = feedback_id;
                feedback.threshold = 0;
                feedback.accelNum = 1;
                feedback.accelDenom = 1;

                XChangeFeedbackControl(display, device, DvAccelNum|DvAccelDenom|DvThreshold,
                           (XFeedbackControl*) &feedback);

                XSync(display, false);
            }

            XCloseDevice(display, device);
        }

        if (all_devices)
        {
            XIFreeDeviceInfo(all_devices);
        }
     }
 }
void handleDeviceChange() {


    int n;
    XIDeviceInfo *info = XIQueryDevice(display, XIAllDevices, &n);
    if (!info) {
        printf("No XInput devices available\n");
        exit(1);
    }

    int d;
    for(d = 0; d < profiles.nDeviceSettings; d++) {
        profiles.deviceSettings[d].inputDeviceCount = 0;
    }

    /* Go through input devices and add to matching profile  */
    int i;
    for (i = 0; i < n; i++) {
        if (info[i].use == XIMasterPointer || info[i].use == XIMasterKeyboard) {
        } else {
            int foundProfile = FALSE;
            for(d = 0; d < profiles.nDeviceSettings; d++) {
                if (profiles.deviceSettings[d].inputDeviceName != NULL && !strcmp(info[i].name, profiles.deviceSettings[d].inputDeviceName)) {
                    if(debugMode) {
                        printf("Device %s for profile %s found with ID %i\n", info[i].name, profiles.deviceSettings[d].inputDeviceName, info[i].deviceid);
                    }
                    if(profiles.deviceSettings[d].inputDeviceCount < MAX_DEVICES_PER_PROFILE) {
                        profiles.deviceSettings[d].inputDeviceCount++;
                        profiles.deviceSettings[d].inputDeviceIDs[profiles.deviceSettings[d].inputDeviceCount-1] = info[i].deviceid;

                        if(profiles.deviceSettings[d].autoCalibration) {
                            /* Set default calibration from axes */
                            setAutoCalibrationData(d, &(info[i]));
                        }
                    }
                    foundProfile = TRUE;
                    break;
                }
            }
            if(foundProfile == FALSE) {
                /* No profile available. If touchscreen, create dummy profile */
                if(isAbsoluteInputDevice(&(info[i]))) {
                    if(debugMode) {
                        printf("Found absolute X and Y axis on device %i, assume it's a touchscreen.\n", info[i].deviceid);
                        printf("No profile found for it, create dummy profile.\n");
                    }
                    /* Create dummy profile */
                    char *deviceName = malloc((strlen(info[i].name) + 1) * sizeof (char));
                    strcpy(deviceName, info[i].name);
                    addDeviceSettings(&profiles, deviceName, NULL, TRUE, TRUE, 0, 0, 0, 0, 0);
                    profiles.deviceSettings[profiles.nDeviceSettings-1].inputDeviceCount = 1;
                    profiles.deviceSettings[profiles.nDeviceSettings-1].inputDeviceIDs[0] = info[i].deviceid;

                    /* Set default calibration from axes */
                    setAutoCalibrationData(profiles.nDeviceSettings - 1, &(info[i]));
                }

            }
        }

    }

    XIFreeDeviceInfo(info);


    handleDisplayChange((XRRScreenChangeNotifyEvent*) NULL);
}
Пример #22
0
 foreach (XInput2TouchDeviceData *dev, m_touchDevices) {
     if (dev->xiDeviceInfo)
         XIFreeDeviceInfo(dev->xiDeviceInfo);
     delete dev->qtTouchDevice;
     delete dev;
 }
Пример #23
0
/* Reads the calibration data from evdev, should be self-explanatory. */
void readCalibrationData(int exitOnFail) {
	if(debugMode) {
		printf("Start calibration\n");
	}
	Atom retType;
	int retFormat;
	unsigned long retItems, retBytesAfter;
	unsigned int* data;
	if(XIGetProperty(display, deviceID, XInternAtom(display,
			"Evdev Axis Calibration", 0), 0, 4 * 32, False, XA_INTEGER,
			&retType, &retFormat, &retItems, &retBytesAfter,
			(unsigned char**) &data) != Success) {
		data = NULL;
	}

	if (data == NULL || retItems != 4 || data[0] == data[1] || data[2] == data[3]) {
		/* evdev might not be ready yet after resume. Let's wait a second and try again. */
		sleep(1);

		if(XIGetProperty(display, deviceID, XInternAtom(display,
				"Evdev Axis Calibration", 0), 0, 4 * 32, False, XA_INTEGER,
				&retType, &retFormat, &retItems, &retBytesAfter,
				(unsigned char**) &data) != Success) {
			return;
		}

		if (retItems != 4 || data[0] == data[1] || data[2] == data[3]) {

			if(debugMode) {
				printf("No calibration data found, use default values.\n");
			}

			/* Get minimum/maximum of axes */

			int nDev;
			XIDeviceInfo * deviceInfo = XIQueryDevice(display, deviceID, &nDev);

			int c;
			for(c = 0; c < deviceInfo->num_classes; c++) {
				if(deviceInfo->classes[c]->type == XIValuatorClass) {
					XIValuatorClassInfo* valuatorInfo = (XIValuatorClassInfo *) deviceInfo->classes[c];
					if(valuatorInfo->mode == XIModeAbsolute) {
						if(valuatorInfo->label == XInternAtom(display, "Abs X", 0)
						|| valuatorInfo->label == XInternAtom(display, "Abs MT Position X", 0)) 
						{
							calibMinX = valuatorInfo->min;
							calibMaxX = valuatorInfo->max;
						}
						else if(valuatorInfo->label == XInternAtom(display, "Abs Y", 0) 							|| valuatorInfo->label == XInternAtom(display, "Abs MT Position Y", 0))
						{
							calibMinY = valuatorInfo->min;
							calibMaxY = valuatorInfo->max;
						}
					}
				}
			}

			XIFreeDeviceInfo(deviceInfo);

		} else {
			calibMinX = data[0];
			calibMaxX = data[1];
			calibMinY = data[2];
			calibMaxY = data[3];
		}
	} else {
		calibMinX = data[0];
		calibMaxX = data[1];
		calibMinY = data[2];
		calibMaxY = data[3];
	}

	if(data != NULL) {
		XFree(data);
	}

	float * data4 = NULL;
	if(XIGetProperty(display, deviceID, XInternAtom(display,
			"Coordinate Transformation Matrix", 0), 0, 9 * 32, False, XInternAtom(display,
			"FLOAT", 0),
			&retType, &retFormat, &retItems, &retBytesAfter,
			(unsigned char **) &data4) != Success) {
		data4 = NULL;
	}
	calibMatrixUse = 0;
	if(data4 != NULL && retItems == 9) {
		int i;
		for(i = 0; i < 6; i++) {
			/* We only take the first two rows of the matrix, the rest is unimportant anyway */
			calibMatrix[i] = data4[i];
		}
		calibMatrixUse = 1;
	}
	if(data4 != NULL) {
		XFree(data4);
	}



	unsigned char* data2;

	if(XIGetProperty(display, deviceID, XInternAtom(display,
			"Evdev Axis Inversion", 0), 0, 2 * 8, False, XA_INTEGER, &retType,
			&retFormat, &retItems, &retBytesAfter, (unsigned char**) &data2) != Success) {
		return;
	}

	if (retItems != 2) {
		if (exitOnFail) {
			printf("No valid axis inversion data found.\n");
			exit(1);
		} else {
			return;
		}
	}

	calibSwapX = data2[0];
	calibSwapY = data2[1];

	XFree(data2);

	if(XIGetProperty(display, deviceID,
			XInternAtom(display, "Evdev Axes Swap", 0), 0, 8, False,
			XA_INTEGER, &retType, &retFormat, &retItems, &retBytesAfter,
			(unsigned char**) &data2) != Success) {
		return;
	}

	if (retItems != 1) {
		if (exitOnFail) {
			printf("No valid axes swap data found.\n");
			exit(1);
		} else {
			return;
		}
	}
	calibSwapAxes = data2[0];

	XFree(data2);

	if(debugMode)
	{
		printf("Calibration: MinX: %i; MaxX: %i; MinY: %i; MaxY: %i\n", calibMinX, calibMaxX, calibMinY, calibMaxY);
	}

}
Пример #24
0
/* Main function, contains kernel driver event loop */
int main(int argc, char **argv) {

	char* devname = 0;
	int doDaemonize = 1;
	int doWait = 0;
	int clickMode = 2;

	int i;
	for (i = 1; i < argc; i++) {
		if (strcmp(argv[i], "--debug") == 0) {
			doDaemonize = 0;
			debugMode = 1;
		} else if (strcmp(argv[i], "--wait") == 0) {
			doWait = 1;
		} else if (strcmp(argv[i], "--click=first") == 0) {
			clickMode = 0;
		} else if (strcmp(argv[i], "--click=second") == 0) {
			clickMode = 1;
		} else if (strcmp(argv[i], "--click=center") == 0) {
			clickMode = 2;
		} else {
			devname = argv[i];
		}

	}

	initGestures(clickMode);



	if (doDaemonize) {
		daemonize();
	}

	if (doWait) {
		/* Wait until all necessary things are loaded */
		sleep(10);
	}


	/* Connect to X server */
	if ((display = XOpenDisplay(NULL)) == NULL) {
		fprintf(stderr, "Couldn't connect to X server\n");
		exit(1);
	}

	/* Read X data */
	screenNum = DefaultScreen(display);

	root = RootWindow(display, screenNum);

//	realDisplayWidth = DisplayWidth(display, screenNum);
//	realDisplayHeight = DisplayHeight(display, screenNum);

	WM_CLASS = XInternAtom(display, "WM_CLASS", 0);

	/* Get notified about new windows */
	XSelectInput(display, root, StructureNotifyMask | SubstructureNotifyMask);

	//TODO load blacklist and profiles from file(s)

	/* Device file name */
	if (devname == 0) {
		devname = "/dev/twofingtouch";
	}

	/* Try to read from device file */
	int fileDesc;
	if ((fileDesc = open(devname, O_RDONLY)) < 0) {
		perror("twofing");
		return 1;
	}

	fd_set fileDescSet;
	FD_ZERO(&fileDescSet);

	int eventQueueDesc = XConnectionNumber(display);	

	while (1) {
		/* Perform initialization at beginning and after module has been re-loaded */
		int rd, i;
		struct input_event ev[64];

		char name[256] = "Unknown";

		/* Read device name */
		ioctl(fileDesc, EVIOCGNAME(sizeof(name)), name);
		printf("Input device name: \"%s\"\n", name);

		//TODO activate again?
		//XSetErrorHandler(invalidWindowHandler);


		int opcode, event, error;
		if (!XQueryExtension(display, "RANDR", &opcode, &event,
				&error)) {
			printf("X RANDR extension not available.\n");
			XCloseDisplay(display);
			exit(1);
		}

		/* Which version of XRandR? We support 1.3 */
		int major = 1, minor = 3;
		if (!XRRQueryVersion(display, &major, &minor)) {
			printf("XRandR version not available.\n");
			XCloseDisplay(display);
			exit(1);
		} else if(!(major>1 || (major == 1 && minor >= 3))) {
			printf("XRandR 1.3 not available. Server supports %d.%d\n", major, minor);
			XCloseDisplay(display);
			exit(1);
		}

		/* XInput Extension available? */
		if (!XQueryExtension(display, "XInputExtension", &opcode, &event,
				&error)) {
			printf("X Input extension not available.\n");
			XCloseDisplay(display);
			exit(1);
		}

		/* Which version of XI2? We support 2.1 */
		major = 2; minor = 1;
		if (XIQueryVersion(display, &major, &minor) == BadRequest) {
			printf("XI 2.1 not available. Server supports %d.%d\n", major, minor);
			XCloseDisplay(display);
			exit(1);
		}

		screenWidth = XDisplayWidth(display, screenNum);
		screenHeight = XDisplayHeight(display, screenNum);

		int n;
		XIDeviceInfo *info = XIQueryDevice(display, XIAllDevices, &n);
		if (!info) {
			printf("No XInput devices available\n");
			exit(1);
		}

		/* Go through input devices and look for that with the same name as the given device */
		int devindex;
		for (devindex = 0; devindex < n; devindex++) {
			if (info[devindex].use == XIMasterPointer || info[devindex].use
					== XIMasterKeyboard)
				continue;

			if (strcmp(info[devindex].name, name) == 0) {
				deviceID = info[devindex].deviceid;

				break;
			}

		}
		if (deviceID == -1) {
			printf("Input device not found in XInput device list.\n");
			exit(1);
		}

		XIFreeDeviceInfo(info);

		if(debugMode) printf("XInput device id is %i.\n", deviceID);

		/* Prepare by reading calibration */
		readCalibrationData(1);

		/* Receive device property change events */
		XIEventMask device_mask2;
		unsigned char mask_data2[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
		device_mask2.deviceid = deviceID;
		device_mask2.mask_len = sizeof(mask_data2);
		device_mask2.mask = mask_data2;
		XISetMask(device_mask2.mask, XI_PropertyEvent);
		XISetMask(device_mask2.mask, XI_ButtonPress);
		//XISetMask(device_mask2.mask, XI_TouchBegin);
		//XISetMask(device_mask2.mask, XI_TouchUpdate);
		//XISetMask(device_mask2.mask, XI_TouchEnd);
		XISelectEvents(display, root, &device_mask2, 1);

		/* Recieve events when screen size changes */
		XRRSelectInput(display, root, RRScreenChangeNotifyMask);


		/* Receive touch events */



		/* Needed for XTest to work correctly */
		XTestGrabControl(display, True);


		/* Needed for some reason to receive events */
/*		XGrabPointer(display, root, False, 0, GrabModeAsync, GrabModeAsync,
				None, None, CurrentTime);
		XUngrabPointer(display, CurrentTime);*/

		grab(display, deviceID);		

		printf("Reading input from device ... (interrupt to exit)\n");

		/* We perform raw event reading here as X touch events don't seem too reliable */
		int currentSlot = 0;

		/* If we use the legacy protocol, we collect all data of one finger into tempFingerInfo and set
		   it to the correct slot once MT_SYNC occurs. */
		FingerInfo tempFingerInfo = { .rawX=0, .rawY=0, .rawZ=0, .id = -1, .slotUsed = 0, .setThisTime = 0 };

		while (1) {


			FD_SET(fileDesc, &fileDescSet);
			FD_SET(eventQueueDesc, &fileDescSet);

			select(MAX(fileDesc, eventQueueDesc) + 1, &fileDescSet, NULL, NULL, getEasingStepTimeVal());
			
			checkEasingStep();

			if(FD_ISSET(fileDesc, &fileDescSet))
			{


				rd = read(fileDesc, ev, sizeof(struct input_event) * 64);
				if (rd < (int) sizeof(struct input_event)) {
					printf("Data stream stopped\n");
					break;
				}
				for (i = 0; i < rd / sizeof(struct input_event); i++) {

					if (ev[i].type == EV_SYN) {
						if (0 == ev[i].code) { // Ev_Sync event end
							/* All finger data received, so process now. */

							if(useLegacyProtocol) {
								/* Clear slots not set this time */
								int i;
								for(i = 0; i < 2; i++) {
									if(fingerInfos[i].setThisTime) {
										fingerInfos[i].setThisTime = 0;
									} else {
										/* Clear slot */
										fingerInfos[i].slotUsed = 0;
									}
								}
								tempFingerInfo.slotUsed = 0;
							}

							processFingers();

						} else if (2 == ev[i].code) { // MT_Sync : Multitouch event end

							if(!useLegacyProtocol) {

								/* This messsage indicates we use legacy protocol, so switch */
								useLegacyProtocol = 1;
								currentSlot = -1;
								tempFingerInfo.slotUsed = 0;
								if(debugMode) printf("Switch to legacy protocol.\n");
							} else {
								if(tempFingerInfo.slotUsed) {
									/* Finger info for one finger collected in tempFingerInfo, so save it to fingerInfos. */

									/* Look for slot to put the data into by looking at the tracking ids */
									int index = -1;
									int i;
									for(i = 0; i < 2; i++) {
										if(fingerInfos[i].slotUsed && fingerInfos[i].id == tempFingerInfo.id) {
											index = i;
											break;
										}
									}
							
									if(index == -1) {
										for(i = 0; i < 2; i++) {
											if(!fingerInfos[i].slotUsed) {
												/* "Empty" slot, so we can add it. */
												index = i;
												fingerInfos[i].id = tempFingerInfo.id;
												fingerInfos[i].slotUsed = 1;
												break;
											}
										}
									}

									if(index != -1) {
										/* Copy temporary data to slot */
										fingerInfos[index].setThisTime = 1;
										fingerInfos[index].rawX = tempFingerInfo.rawX;
										fingerInfos[index].rawY = tempFingerInfo.rawY;
										fingerInfos[index].rawZ = tempFingerInfo.rawZ;
									}
								}
							}
						}

					} else if (ev[i].type == EV_MSC && (ev[i].code == MSC_RAW
							|| ev[i].code == MSC_SCAN)) {
					} else if (ev[i].code == 47) {
						currentSlot = ev[i].value;
						if(currentSlot < 0 || currentSlot > 1) currentSlot = -1;
					} else {
						/* Set finger info values for current finger */
						if (ev[i].code == 57) {
							/* ABS_MT_TRACKING_ID */
							if(currentSlot != -1) {
								if(ev[i].value == -1)
								{
									fingerInfos[currentSlot].slotUsed = 0;
								}
								else
								{
									fingerInfos[currentSlot].id = ev[i].value;
									fingerInfos[currentSlot].slotUsed = 1;
								}
							} else if(useLegacyProtocol) {
								tempFingerInfo.id = ev[i].value;
								tempFingerInfo.slotUsed = 1;
							}
						};
						if (ev[i].code == 53) {
							if(currentSlot != -1) {
								fingerInfos[currentSlot].rawX = ev[i].value;
							} else if(useLegacyProtocol) {
								tempFingerInfo.rawX = ev[i].value;
							}
						};
						if (ev[i].code == 54) {
							if(currentSlot != -1) {
								fingerInfos[currentSlot].rawY = ev[i].value;
							} else if(useLegacyProtocol) {
								tempFingerInfo.rawY = ev[i].value;
							}
						};
						if (ev[i].code == 58) {
							if(currentSlot != -1) {
								fingerInfos[currentSlot].rawZ = ev[i].value;
							} else if(useLegacyProtocol) {
								tempFingerInfo.rawZ = ev[i].value;
							}
						};
					}
				}

			}

			if(FD_ISSET(eventQueueDesc, &fileDescSet)) {
				handleXEvent();
			}
		}

		/* Stream stopped, probably because module has been unloaded */
		close(fileDesc);

		/* Clean up */
		releaseButton();
		ungrab(display, deviceID);

		/* Wait until device file is there again */
		while ((fileDesc = open(devname, O_RDONLY)) < 0) {
			sleep(1);
		}

	}

}
Пример #25
0
/**
 * Remove a master device.
 * By default, all attached devices are set to Floating, unless parameters are
 * given.
 */
int
remove_master(Display* dpy, int argc, char** argv, char *name, char *desc)
{
    XIRemoveMasterInfo r;
    XIDeviceInfo *info;
    int ret;

    if (argc == 0)
    {
        fprintf(stderr, "usage: xinput %s %s\n", name, desc);
        return EXIT_FAILURE;
    }

    info = xi2_find_device_info(dpy, argv[0]);

    if (!info) {
	fprintf(stderr, "unable to find device %s\n", argv[0]);
	return EXIT_FAILURE;
    }

    r.type = XIRemoveMaster;
    r.deviceid = info->deviceid;
    if (argc >= 2)
    {
        if (!strcmp(argv[1], "Floating"))
            r.return_mode = XIFloating;
        else if (!strcmp(argv[1], "AttachToMaster"))
            r.return_mode = XIAttachToMaster;
        else
            Error(BadValue, "Invalid return_mode.\n");
    } else
        r.return_mode = XIFloating;

    if (r.return_mode == XIAttachToMaster)
    {
        r.return_pointer = 0;
        if (argc >= 3) {
            info = xi2_find_device_info(dpy, argv[2]);
            if (!info) {
                fprintf(stderr, "unable to find device %s\n", argv[2]);
                return EXIT_FAILURE;
            }

            r.return_pointer = info->deviceid;
        }

        r.return_keyboard = 0;
        if (argc >= 4) {
            info = xi2_find_device_info(dpy, argv[3]);
            if (!info) {
                fprintf(stderr, "unable to find device %s\n", argv[3]);
                return EXIT_FAILURE;
            }

            r.return_keyboard = info->deviceid;
        }

        if (!r.return_pointer || !r.return_keyboard) {
            int i, ndevices;
            info = XIQueryDevice(dpy, XIAllMasterDevices, &ndevices);
            for(i = 0; i < ndevices; i++) {
                if (info[i].use == XIMasterPointer && !r.return_pointer)
                    r.return_pointer = info[i].deviceid;
                if (info[i].use == XIMasterKeyboard && !r.return_keyboard)
                    r.return_keyboard = info[i].deviceid;
                if (r.return_pointer && r.return_keyboard)
                    break;
            }

            XIFreeDeviceInfo(info);
        }
    }

    ret = XIChangeHierarchy(dpy, (XIAnyHierarchyChangeInfo*)&r, 1);
    return ret;
}