mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-11-02 20:51:23 -07:00 
			
		
		
		
	ENABLE_3DCONNEXION_DEVICES - 1st installment of support for 3Dconnexion devices
Implemented using hidapi library (https://github.com/libusb/hidapi) and https://github.com/koenieee/CrossplatformSpacemouseDriver/tree/master/SpaceMouseDriver as reference Unsolved issues: - When manipulating the SpaceNavigator wxWidgets generates a mouse wheel event that needs to be filtered out - wxWidgets does not detect devices being connected/disconnected to the pc - Current state forces a continuous rendering - Current state misses dependence on camera zoom - Non intuitive movement limits - Translation and rotation speed factors are hardcoded - Number of device buttons hardcoded
This commit is contained in:
		
							parent
							
								
									c1e3be9b27
								
							
						
					
					
						commit
						f958cfd2ff
					
				
					 14 changed files with 3805 additions and 1 deletions
				
			
		| 
						 | 
				
			
			@ -365,6 +365,25 @@ include_directories(${GLEW_INCLUDE_DIRS})
 | 
			
		|||
add_library(cereal INTERFACE)
 | 
			
		||||
target_include_directories(cereal INTERFACE include)
 | 
			
		||||
 | 
			
		||||
# Find the hidapi library
 | 
			
		||||
if(WIN32)
 | 
			
		||||
add_library(hidapi STATIC
 | 
			
		||||
    ${LIBDIR}/hidapi/win/hid.c
 | 
			
		||||
)
 | 
			
		||||
elseif (APPLE)
 | 
			
		||||
add_library(hidapi STATIC
 | 
			
		||||
    ${LIBDIR}/hidapi/mac/hid.c
 | 
			
		||||
)
 | 
			
		||||
else ()
 | 
			
		||||
add_library(hidapi STATIC
 | 
			
		||||
    ${LIBDIR}/hidapi/linux/hid.c
 | 
			
		||||
)
 | 
			
		||||
endif ()
 | 
			
		||||
set(HIDAPI_FOUND 1)
 | 
			
		||||
set(HIDAPI_INCLUDE_DIRS ${LIBDIR}/hidapi/)
 | 
			
		||||
set(HIDAPI_LIBRARIES hidapi)
 | 
			
		||||
include_directories(${HIDAPI_INCLUDE_DIRS})
 | 
			
		||||
 | 
			
		||||
# l10n
 | 
			
		||||
set(L10N_DIR "${SLIC3R_RESOURCES_DIR}/localization")
 | 
			
		||||
add_custom_target(pot
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										395
									
								
								src/hidapi/hidapi.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										395
									
								
								src/hidapi/hidapi.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,395 @@
 | 
			
		|||
/*******************************************************
 | 
			
		||||
 HIDAPI - Multi-Platform library for
 | 
			
		||||
 communication with HID devices.
 | 
			
		||||
 | 
			
		||||
 Alan Ott
 | 
			
		||||
 Signal 11 Software
 | 
			
		||||
 | 
			
		||||
 8/22/2009
 | 
			
		||||
 | 
			
		||||
 Copyright 2009, All Rights Reserved.
 | 
			
		||||
 | 
			
		||||
 At the discretion of the user of this library,
 | 
			
		||||
 this software may be licensed under the terms of the
 | 
			
		||||
 GNU General Public License v3, a BSD-Style license, or the
 | 
			
		||||
 original HIDAPI license as outlined in the LICENSE.txt,
 | 
			
		||||
 LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
 | 
			
		||||
 files located at the root of the source distribution.
 | 
			
		||||
 These files may also be found in the public source
 | 
			
		||||
 code repository located at:
 | 
			
		||||
        http://github.com/signal11/hidapi .
 | 
			
		||||
********************************************************/
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 * @defgroup API hidapi API
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef HIDAPI_H__
 | 
			
		||||
#define HIDAPI_H__
 | 
			
		||||
 | 
			
		||||
#include <wchar.h>
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
      #define HID_API_EXPORT __declspec(dllexport)
 | 
			
		||||
      #define HID_API_CALL
 | 
			
		||||
#else
 | 
			
		||||
      #define HID_API_EXPORT /**< API export macro */
 | 
			
		||||
      #define HID_API_CALL /**< API call macro */
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define HID_API_EXPORT_CALL HID_API_EXPORT HID_API_CALL /**< API export and call macro*/
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
		struct hid_device_;
 | 
			
		||||
		typedef struct hid_device_ hid_device; /**< opaque hidapi structure */
 | 
			
		||||
 | 
			
		||||
		/** hidapi info structure */
 | 
			
		||||
		struct hid_device_info {
 | 
			
		||||
			/** Platform-specific device path */
 | 
			
		||||
			char *path;
 | 
			
		||||
			/** Device Vendor ID */
 | 
			
		||||
			unsigned short vendor_id;
 | 
			
		||||
			/** Device Product ID */
 | 
			
		||||
			unsigned short product_id;
 | 
			
		||||
			/** Serial Number */
 | 
			
		||||
			wchar_t *serial_number;
 | 
			
		||||
			/** Device Release Number in binary-coded decimal,
 | 
			
		||||
			    also known as Device Version Number */
 | 
			
		||||
			unsigned short release_number;
 | 
			
		||||
			/** Manufacturer String */
 | 
			
		||||
			wchar_t *manufacturer_string;
 | 
			
		||||
			/** Product string */
 | 
			
		||||
			wchar_t *product_string;
 | 
			
		||||
			/** Usage Page for this Device/Interface
 | 
			
		||||
			    (Windows/Mac only). */
 | 
			
		||||
			unsigned short usage_page;
 | 
			
		||||
			/** Usage for this Device/Interface
 | 
			
		||||
			    (Windows/Mac only).*/
 | 
			
		||||
			unsigned short usage;
 | 
			
		||||
			/** The USB interface which this logical device
 | 
			
		||||
			    represents.
 | 
			
		||||
 | 
			
		||||
				* Valid on both Linux implementations in all cases.
 | 
			
		||||
				* Valid on the Windows implementation only if the device
 | 
			
		||||
				  contains more than one interface.
 | 
			
		||||
				* Valid on the Mac implementation if and only if the device
 | 
			
		||||
				  is a USB HID device. */
 | 
			
		||||
			int interface_number;
 | 
			
		||||
 | 
			
		||||
			/** Pointer to the next device */
 | 
			
		||||
			struct hid_device_info *next;
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		/** @brief Initialize the HIDAPI library.
 | 
			
		||||
 | 
			
		||||
			This function initializes the HIDAPI library. Calling it is not
 | 
			
		||||
			strictly necessary, as it will be called automatically by
 | 
			
		||||
			hid_enumerate() and any of the hid_open_*() functions if it is
 | 
			
		||||
			needed.  This function should be called at the beginning of
 | 
			
		||||
			execution however, if there is a chance of HIDAPI handles
 | 
			
		||||
			being opened by different threads simultaneously.
 | 
			
		||||
			
 | 
			
		||||
			@ingroup API
 | 
			
		||||
 | 
			
		||||
			@returns
 | 
			
		||||
				This function returns 0 on success and -1 on error.
 | 
			
		||||
		*/
 | 
			
		||||
		int HID_API_EXPORT HID_API_CALL hid_init(void);
 | 
			
		||||
 | 
			
		||||
		/** @brief Finalize the HIDAPI library.
 | 
			
		||||
 | 
			
		||||
			This function frees all of the static data associated with
 | 
			
		||||
			HIDAPI. It should be called at the end of execution to avoid
 | 
			
		||||
			memory leaks.
 | 
			
		||||
 | 
			
		||||
			@ingroup API
 | 
			
		||||
 | 
			
		||||
		    @returns
 | 
			
		||||
				This function returns 0 on success and -1 on error.
 | 
			
		||||
		*/
 | 
			
		||||
		int HID_API_EXPORT HID_API_CALL hid_exit(void);
 | 
			
		||||
 | 
			
		||||
		/** @brief Enumerate the HID Devices.
 | 
			
		||||
 | 
			
		||||
			This function returns a linked list of all the HID devices
 | 
			
		||||
			attached to the system which match vendor_id and product_id.
 | 
			
		||||
			If @p vendor_id is set to 0 then any vendor matches.
 | 
			
		||||
			If @p product_id is set to 0 then any product matches.
 | 
			
		||||
			If @p vendor_id and @p product_id are both set to 0, then
 | 
			
		||||
			all HID devices will be returned.
 | 
			
		||||
 | 
			
		||||
			@ingroup API
 | 
			
		||||
			@param vendor_id The Vendor ID (VID) of the types of device
 | 
			
		||||
				to open.
 | 
			
		||||
			@param product_id The Product ID (PID) of the types of
 | 
			
		||||
				device to open.
 | 
			
		||||
 | 
			
		||||
		    @returns
 | 
			
		||||
		    	This function returns a pointer to a linked list of type
 | 
			
		||||
		    	struct #hid_device_info, containing information about the HID devices
 | 
			
		||||
		    	attached to the system, or NULL in the case of failure. Free
 | 
			
		||||
		    	this linked list by calling hid_free_enumeration().
 | 
			
		||||
		*/
 | 
			
		||||
		struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id);
 | 
			
		||||
 | 
			
		||||
		/** @brief Free an enumeration Linked List
 | 
			
		||||
 | 
			
		||||
		    This function frees a linked list created by hid_enumerate().
 | 
			
		||||
 | 
			
		||||
			@ingroup API
 | 
			
		||||
		    @param devs Pointer to a list of struct_device returned from
 | 
			
		||||
		    	      hid_enumerate().
 | 
			
		||||
		*/
 | 
			
		||||
		void  HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs);
 | 
			
		||||
 | 
			
		||||
		/** @brief Open a HID device using a Vendor ID (VID), Product ID
 | 
			
		||||
			(PID) and optionally a serial number.
 | 
			
		||||
 | 
			
		||||
			If @p serial_number is NULL, the first device with the
 | 
			
		||||
			specified VID and PID is opened.
 | 
			
		||||
 | 
			
		||||
			@ingroup API
 | 
			
		||||
			@param vendor_id The Vendor ID (VID) of the device to open.
 | 
			
		||||
			@param product_id The Product ID (PID) of the device to open.
 | 
			
		||||
			@param serial_number The Serial Number of the device to open
 | 
			
		||||
				               (Optionally NULL).
 | 
			
		||||
 | 
			
		||||
			@returns
 | 
			
		||||
				This function returns a pointer to a #hid_device object on
 | 
			
		||||
				success or NULL on failure.
 | 
			
		||||
		*/
 | 
			
		||||
		HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number);
 | 
			
		||||
 | 
			
		||||
		/** @brief Open a HID device by its path name.
 | 
			
		||||
 | 
			
		||||
			The path name be determined by calling hid_enumerate(), or a
 | 
			
		||||
			platform-specific path name can be used (eg: /dev/hidraw0 on
 | 
			
		||||
			Linux).
 | 
			
		||||
 | 
			
		||||
			@ingroup API
 | 
			
		||||
		    @param path The path name of the device to open
 | 
			
		||||
 | 
			
		||||
			@returns
 | 
			
		||||
				This function returns a pointer to a #hid_device object on
 | 
			
		||||
				success or NULL on failure.
 | 
			
		||||
		*/
 | 
			
		||||
		HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path);
 | 
			
		||||
 | 
			
		||||
		/** @brief Write an Output report to a HID device.
 | 
			
		||||
 | 
			
		||||
			The first byte of @p data[] must contain the Report ID. For
 | 
			
		||||
			devices which only support a single report, this must be set
 | 
			
		||||
			to 0x0. The remaining bytes contain the report data. Since
 | 
			
		||||
			the Report ID is mandatory, calls to hid_write() will always
 | 
			
		||||
			contain one more byte than the report contains. For example,
 | 
			
		||||
			if a hid report is 16 bytes long, 17 bytes must be passed to
 | 
			
		||||
			hid_write(), the Report ID (or 0x0, for devices with a
 | 
			
		||||
			single report), followed by the report data (16 bytes). In
 | 
			
		||||
			this example, the length passed in would be 17.
 | 
			
		||||
 | 
			
		||||
			hid_write() will send the data on the first OUT endpoint, if
 | 
			
		||||
			one exists. If it does not, it will send the data through
 | 
			
		||||
			the Control Endpoint (Endpoint 0).
 | 
			
		||||
 | 
			
		||||
			@ingroup API
 | 
			
		||||
			@param dev A device handle returned from hid_open().
 | 
			
		||||
			@param data The data to send, including the report number as
 | 
			
		||||
				the first byte.
 | 
			
		||||
			@param length The length in bytes of the data to send.
 | 
			
		||||
 | 
			
		||||
			@returns
 | 
			
		||||
				This function returns the actual number of bytes written and
 | 
			
		||||
				-1 on error.
 | 
			
		||||
		*/
 | 
			
		||||
		int  HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length);
 | 
			
		||||
 | 
			
		||||
		/** @brief Read an Input report from a HID device with timeout.
 | 
			
		||||
 | 
			
		||||
			Input reports are returned
 | 
			
		||||
			to the host through the INTERRUPT IN endpoint. The first byte will
 | 
			
		||||
			contain the Report number if the device uses numbered reports.
 | 
			
		||||
 | 
			
		||||
			@ingroup API
 | 
			
		||||
			@param dev A device handle returned from hid_open().
 | 
			
		||||
			@param data A buffer to put the read data into.
 | 
			
		||||
			@param length The number of bytes to read. For devices with
 | 
			
		||||
				multiple reports, make sure to read an extra byte for
 | 
			
		||||
				the report number.
 | 
			
		||||
			@param milliseconds timeout in milliseconds or -1 for blocking wait.
 | 
			
		||||
 | 
			
		||||
			@returns
 | 
			
		||||
				This function returns the actual number of bytes read and
 | 
			
		||||
				-1 on error. If no packet was available to be read within
 | 
			
		||||
				the timeout period, this function returns 0.
 | 
			
		||||
		*/
 | 
			
		||||
		int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds);
 | 
			
		||||
 | 
			
		||||
		/** @brief Read an Input report from a HID device.
 | 
			
		||||
 | 
			
		||||
			Input reports are returned
 | 
			
		||||
		    to the host through the INTERRUPT IN endpoint. The first byte will
 | 
			
		||||
			contain the Report number if the device uses numbered reports.
 | 
			
		||||
 | 
			
		||||
			@ingroup API
 | 
			
		||||
			@param dev A device handle returned from hid_open().
 | 
			
		||||
			@param data A buffer to put the read data into.
 | 
			
		||||
			@param length The number of bytes to read. For devices with
 | 
			
		||||
				multiple reports, make sure to read an extra byte for
 | 
			
		||||
				the report number.
 | 
			
		||||
 | 
			
		||||
			@returns
 | 
			
		||||
				This function returns the actual number of bytes read and
 | 
			
		||||
				-1 on error. If no packet was available to be read and
 | 
			
		||||
				the handle is in non-blocking mode, this function returns 0.
 | 
			
		||||
		*/
 | 
			
		||||
		int  HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, size_t length);
 | 
			
		||||
 | 
			
		||||
		/** @brief Set the device handle to be non-blocking.
 | 
			
		||||
 | 
			
		||||
			In non-blocking mode calls to hid_read() will return
 | 
			
		||||
			immediately with a value of 0 if there is no data to be
 | 
			
		||||
			read. In blocking mode, hid_read() will wait (block) until
 | 
			
		||||
			there is data to read before returning.
 | 
			
		||||
 | 
			
		||||
			Nonblocking can be turned on and off at any time.
 | 
			
		||||
 | 
			
		||||
			@ingroup API
 | 
			
		||||
			@param dev A device handle returned from hid_open().
 | 
			
		||||
			@param nonblock enable or not the nonblocking reads
 | 
			
		||||
			 - 1 to enable nonblocking
 | 
			
		||||
			 - 0 to disable nonblocking.
 | 
			
		||||
 | 
			
		||||
			@returns
 | 
			
		||||
				This function returns 0 on success and -1 on error.
 | 
			
		||||
		*/
 | 
			
		||||
		int  HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *dev, int nonblock);
 | 
			
		||||
 | 
			
		||||
		/** @brief Send a Feature report to the device.
 | 
			
		||||
 | 
			
		||||
			Feature reports are sent over the Control endpoint as a
 | 
			
		||||
			Set_Report transfer.  The first byte of @p data[] must
 | 
			
		||||
			contain the Report ID. For devices which only support a
 | 
			
		||||
			single report, this must be set to 0x0. The remaining bytes
 | 
			
		||||
			contain the report data. Since the Report ID is mandatory,
 | 
			
		||||
			calls to hid_send_feature_report() will always contain one
 | 
			
		||||
			more byte than the report contains. For example, if a hid
 | 
			
		||||
			report is 16 bytes long, 17 bytes must be passed to
 | 
			
		||||
			hid_send_feature_report(): the Report ID (or 0x0, for
 | 
			
		||||
			devices which do not use numbered reports), followed by the
 | 
			
		||||
			report data (16 bytes). In this example, the length passed
 | 
			
		||||
			in would be 17.
 | 
			
		||||
 | 
			
		||||
			@ingroup API
 | 
			
		||||
			@param dev A device handle returned from hid_open().
 | 
			
		||||
			@param data The data to send, including the report number as
 | 
			
		||||
				the first byte.
 | 
			
		||||
			@param length The length in bytes of the data to send, including
 | 
			
		||||
				the report number.
 | 
			
		||||
 | 
			
		||||
			@returns
 | 
			
		||||
				This function returns the actual number of bytes written and
 | 
			
		||||
				-1 on error.
 | 
			
		||||
		*/
 | 
			
		||||
		int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length);
 | 
			
		||||
 | 
			
		||||
		/** @brief Get a feature report from a HID device.
 | 
			
		||||
 | 
			
		||||
			Set the first byte of @p data[] to the Report ID of the
 | 
			
		||||
			report to be read.  Make sure to allow space for this
 | 
			
		||||
			extra byte in @p data[]. Upon return, the first byte will
 | 
			
		||||
			still contain the Report ID, and the report data will
 | 
			
		||||
			start in data[1].
 | 
			
		||||
 | 
			
		||||
			@ingroup API
 | 
			
		||||
			@param dev A device handle returned from hid_open().
 | 
			
		||||
			@param data A buffer to put the read data into, including
 | 
			
		||||
				the Report ID. Set the first byte of @p data[] to the
 | 
			
		||||
				Report ID of the report to be read, or set it to zero
 | 
			
		||||
				if your device does not use numbered reports.
 | 
			
		||||
			@param length The number of bytes to read, including an
 | 
			
		||||
				extra byte for the report ID. The buffer can be longer
 | 
			
		||||
				than the actual report.
 | 
			
		||||
 | 
			
		||||
			@returns
 | 
			
		||||
				This function returns the number of bytes read plus
 | 
			
		||||
				one for the report ID (which is still in the first
 | 
			
		||||
				byte), or -1 on error.
 | 
			
		||||
		*/
 | 
			
		||||
		int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length);
 | 
			
		||||
 | 
			
		||||
		/** @brief Close a HID device.
 | 
			
		||||
 | 
			
		||||
			@ingroup API
 | 
			
		||||
			@param dev A device handle returned from hid_open().
 | 
			
		||||
		*/
 | 
			
		||||
		void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev);
 | 
			
		||||
 | 
			
		||||
		/** @brief Get The Manufacturer String from a HID device.
 | 
			
		||||
 | 
			
		||||
			@ingroup API
 | 
			
		||||
			@param dev A device handle returned from hid_open().
 | 
			
		||||
			@param string A wide string buffer to put the data into.
 | 
			
		||||
			@param maxlen The length of the buffer in multiples of wchar_t.
 | 
			
		||||
 | 
			
		||||
			@returns
 | 
			
		||||
				This function returns 0 on success and -1 on error.
 | 
			
		||||
		*/
 | 
			
		||||
		int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen);
 | 
			
		||||
 | 
			
		||||
		/** @brief Get The Product String from a HID device.
 | 
			
		||||
 | 
			
		||||
			@ingroup API
 | 
			
		||||
			@param dev A device handle returned from hid_open().
 | 
			
		||||
			@param string A wide string buffer to put the data into.
 | 
			
		||||
			@param maxlen The length of the buffer in multiples of wchar_t.
 | 
			
		||||
 | 
			
		||||
			@returns
 | 
			
		||||
				This function returns 0 on success and -1 on error.
 | 
			
		||||
		*/
 | 
			
		||||
		int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen);
 | 
			
		||||
 | 
			
		||||
		/** @brief Get The Serial Number String from a HID device.
 | 
			
		||||
 | 
			
		||||
			@ingroup API
 | 
			
		||||
			@param dev A device handle returned from hid_open().
 | 
			
		||||
			@param string A wide string buffer to put the data into.
 | 
			
		||||
			@param maxlen The length of the buffer in multiples of wchar_t.
 | 
			
		||||
 | 
			
		||||
			@returns
 | 
			
		||||
				This function returns 0 on success and -1 on error.
 | 
			
		||||
		*/
 | 
			
		||||
		int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen);
 | 
			
		||||
 | 
			
		||||
		/** @brief Get a string from a HID device, based on its string index.
 | 
			
		||||
 | 
			
		||||
			@ingroup API
 | 
			
		||||
			@param dev A device handle returned from hid_open().
 | 
			
		||||
			@param string_index The index of the string to get.
 | 
			
		||||
			@param string A wide string buffer to put the data into.
 | 
			
		||||
			@param maxlen The length of the buffer in multiples of wchar_t.
 | 
			
		||||
 | 
			
		||||
			@returns
 | 
			
		||||
				This function returns 0 on success and -1 on error.
 | 
			
		||||
		*/
 | 
			
		||||
		int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen);
 | 
			
		||||
 | 
			
		||||
		/** @brief Get a string describing the last error which occurred.
 | 
			
		||||
 | 
			
		||||
			@ingroup API
 | 
			
		||||
			@param dev A device handle returned from hid_open().
 | 
			
		||||
 | 
			
		||||
			@returns
 | 
			
		||||
				This function returns a string containing the last error
 | 
			
		||||
				which occurred or NULL if none has occurred.
 | 
			
		||||
		*/
 | 
			
		||||
		HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *dev);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										797
									
								
								src/hidapi/linux/hid.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										797
									
								
								src/hidapi/linux/hid.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,797 @@
 | 
			
		|||
/*******************************************************
 | 
			
		||||
 HIDAPI - Multi-Platform library for
 | 
			
		||||
 communication with HID devices.
 | 
			
		||||
 | 
			
		||||
 Alan Ott
 | 
			
		||||
 Signal 11 Software
 | 
			
		||||
 | 
			
		||||
 8/22/2009
 | 
			
		||||
 Linux Version - 6/2/2009
 | 
			
		||||
 | 
			
		||||
 Copyright 2009, All Rights Reserved.
 | 
			
		||||
 | 
			
		||||
 At the discretion of the user of this library,
 | 
			
		||||
 this software may be licensed under the terms of the
 | 
			
		||||
 GNU General Public License v3, a BSD-Style license, or the
 | 
			
		||||
 original HIDAPI license as outlined in the LICENSE.txt,
 | 
			
		||||
 LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
 | 
			
		||||
 files located at the root of the source distribution.
 | 
			
		||||
 These files may also be found in the public source
 | 
			
		||||
 code repository located at:
 | 
			
		||||
        http://github.com/signal11/hidapi .
 | 
			
		||||
********************************************************/
 | 
			
		||||
 | 
			
		||||
/* C */
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <locale.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
 | 
			
		||||
/* Unix */
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <sys/ioctl.h>
 | 
			
		||||
#include <sys/utsname.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <poll.h>
 | 
			
		||||
 | 
			
		||||
/* Linux */
 | 
			
		||||
#include <linux/hidraw.h>
 | 
			
		||||
#include <linux/version.h>
 | 
			
		||||
#include <linux/input.h>
 | 
			
		||||
#include <libudev.h>
 | 
			
		||||
 | 
			
		||||
#include "hidapi.h"
 | 
			
		||||
 | 
			
		||||
/* Definitions from linux/hidraw.h. Since these are new, some distros
 | 
			
		||||
   may not have header files which contain them. */
 | 
			
		||||
#ifndef HIDIOCSFEATURE
 | 
			
		||||
#define HIDIOCSFEATURE(len)    _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x06, len)
 | 
			
		||||
#endif
 | 
			
		||||
#ifndef HIDIOCGFEATURE
 | 
			
		||||
#define HIDIOCGFEATURE(len)    _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x07, len)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* USB HID device property names */
 | 
			
		||||
const char *device_string_names[] = {
 | 
			
		||||
	"manufacturer",
 | 
			
		||||
	"product",
 | 
			
		||||
	"serial",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Symbolic names for the properties above */
 | 
			
		||||
enum device_string_id {
 | 
			
		||||
	DEVICE_STRING_MANUFACTURER,
 | 
			
		||||
	DEVICE_STRING_PRODUCT,
 | 
			
		||||
	DEVICE_STRING_SERIAL,
 | 
			
		||||
 | 
			
		||||
	DEVICE_STRING_COUNT,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct hid_device_ {
 | 
			
		||||
	int device_handle;
 | 
			
		||||
	int blocking;
 | 
			
		||||
	int uses_numbered_reports;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static __u32 kernel_version = 0;
 | 
			
		||||
 | 
			
		||||
static __u32 detect_kernel_version(void)
 | 
			
		||||
{
 | 
			
		||||
	struct utsname name;
 | 
			
		||||
	int major, minor, release;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	uname(&name);
 | 
			
		||||
	ret = sscanf(name.release, "%d.%d.%d", &major, &minor, &release);
 | 
			
		||||
	if (ret == 3) {
 | 
			
		||||
		return KERNEL_VERSION(major, minor, release);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = sscanf(name.release, "%d.%d", &major, &minor);
 | 
			
		||||
	if (ret == 2) {
 | 
			
		||||
		return KERNEL_VERSION(major, minor, 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	printf("Couldn't determine kernel version from version string \"%s\"\n", name.release);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static hid_device *new_hid_device(void)
 | 
			
		||||
{
 | 
			
		||||
	hid_device *dev = calloc(1, sizeof(hid_device));
 | 
			
		||||
	dev->device_handle = -1;
 | 
			
		||||
	dev->blocking = 1;
 | 
			
		||||
	dev->uses_numbered_reports = 0;
 | 
			
		||||
 | 
			
		||||
	return dev;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* The caller must free the returned string with free(). */
 | 
			
		||||
static wchar_t *utf8_to_wchar_t(const char *utf8)
 | 
			
		||||
{
 | 
			
		||||
	wchar_t *ret = NULL;
 | 
			
		||||
 | 
			
		||||
	if (utf8) {
 | 
			
		||||
		size_t wlen = mbstowcs(NULL, utf8, 0);
 | 
			
		||||
		if ((size_t) -1 == wlen) {
 | 
			
		||||
			return wcsdup(L"");
 | 
			
		||||
		}
 | 
			
		||||
		ret = calloc(wlen+1, sizeof(wchar_t));
 | 
			
		||||
		mbstowcs(ret, utf8, wlen+1);
 | 
			
		||||
		ret[wlen] = 0x0000;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Get an attribute value from a udev_device and return it as a whar_t
 | 
			
		||||
   string. The returned string must be freed with free() when done.*/
 | 
			
		||||
static wchar_t *copy_udev_string(struct udev_device *dev, const char *udev_name)
 | 
			
		||||
{
 | 
			
		||||
	return utf8_to_wchar_t(udev_device_get_sysattr_value(dev, udev_name));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* uses_numbered_reports() returns 1 if report_descriptor describes a device
 | 
			
		||||
   which contains numbered reports. */
 | 
			
		||||
static int uses_numbered_reports(__u8 *report_descriptor, __u32 size) {
 | 
			
		||||
	unsigned int i = 0;
 | 
			
		||||
	int size_code;
 | 
			
		||||
	int data_len, key_size;
 | 
			
		||||
 | 
			
		||||
	while (i < size) {
 | 
			
		||||
		int key = report_descriptor[i];
 | 
			
		||||
 | 
			
		||||
		/* Check for the Report ID key */
 | 
			
		||||
		if (key == 0x85/*Report ID*/) {
 | 
			
		||||
			/* This device has a Report ID, which means it uses
 | 
			
		||||
			   numbered reports. */
 | 
			
		||||
			return 1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		//printf("key: %02hhx\n", key);
 | 
			
		||||
 | 
			
		||||
		if ((key & 0xf0) == 0xf0) {
 | 
			
		||||
			/* This is a Long Item. The next byte contains the
 | 
			
		||||
			   length of the data section (value) for this key.
 | 
			
		||||
			   See the HID specification, version 1.11, section
 | 
			
		||||
			   6.2.2.3, titled "Long Items." */
 | 
			
		||||
			if (i+1 < size)
 | 
			
		||||
				data_len = report_descriptor[i+1];
 | 
			
		||||
			else
 | 
			
		||||
				data_len = 0; /* malformed report */
 | 
			
		||||
			key_size = 3;
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			/* This is a Short Item. The bottom two bits of the
 | 
			
		||||
			   key contain the size code for the data section
 | 
			
		||||
			   (value) for this key.  Refer to the HID
 | 
			
		||||
			   specification, version 1.11, section 6.2.2.2,
 | 
			
		||||
			   titled "Short Items." */
 | 
			
		||||
			size_code = key & 0x3;
 | 
			
		||||
			switch (size_code) {
 | 
			
		||||
			case 0:
 | 
			
		||||
			case 1:
 | 
			
		||||
			case 2:
 | 
			
		||||
				data_len = size_code;
 | 
			
		||||
				break;
 | 
			
		||||
			case 3:
 | 
			
		||||
				data_len = 4;
 | 
			
		||||
				break;
 | 
			
		||||
			default:
 | 
			
		||||
				/* Can't ever happen since size_code is & 0x3 */
 | 
			
		||||
				data_len = 0;
 | 
			
		||||
				break;
 | 
			
		||||
			};
 | 
			
		||||
			key_size = 1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Skip over this key and it's associated data */
 | 
			
		||||
		i += data_len + key_size;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Didn't find a Report ID key. Device doesn't use numbered reports. */
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The caller is responsible for free()ing the (newly-allocated) character
 | 
			
		||||
 * strings pointed to by serial_number_utf8 and product_name_utf8 after use.
 | 
			
		||||
 */
 | 
			
		||||
static int
 | 
			
		||||
parse_uevent_info(const char *uevent, int *bus_type,
 | 
			
		||||
	unsigned short *vendor_id, unsigned short *product_id,
 | 
			
		||||
	char **serial_number_utf8, char **product_name_utf8)
 | 
			
		||||
{
 | 
			
		||||
	char *tmp = strdup(uevent);
 | 
			
		||||
	char *saveptr = NULL;
 | 
			
		||||
	char *line;
 | 
			
		||||
	char *key;
 | 
			
		||||
	char *value;
 | 
			
		||||
 | 
			
		||||
	int found_id = 0;
 | 
			
		||||
	int found_serial = 0;
 | 
			
		||||
	int found_name = 0;
 | 
			
		||||
 | 
			
		||||
	line = strtok_r(tmp, "\n", &saveptr);
 | 
			
		||||
	while (line != NULL) {
 | 
			
		||||
		/* line: "KEY=value" */
 | 
			
		||||
		key = line;
 | 
			
		||||
		value = strchr(line, '=');
 | 
			
		||||
		if (!value) {
 | 
			
		||||
			goto next_line;
 | 
			
		||||
		}
 | 
			
		||||
		*value = '\0';
 | 
			
		||||
		value++;
 | 
			
		||||
 | 
			
		||||
		if (strcmp(key, "HID_ID") == 0) {
 | 
			
		||||
			/**
 | 
			
		||||
			 *        type vendor   product
 | 
			
		||||
			 * HID_ID=0003:000005AC:00008242
 | 
			
		||||
			 **/
 | 
			
		||||
			int ret = sscanf(value, "%x:%hx:%hx", bus_type, vendor_id, product_id);
 | 
			
		||||
			if (ret == 3) {
 | 
			
		||||
				found_id = 1;
 | 
			
		||||
			}
 | 
			
		||||
		} else if (strcmp(key, "HID_NAME") == 0) {
 | 
			
		||||
			/* The caller has to free the product name */
 | 
			
		||||
			*product_name_utf8 = strdup(value);
 | 
			
		||||
			found_name = 1;
 | 
			
		||||
		} else if (strcmp(key, "HID_UNIQ") == 0) {
 | 
			
		||||
			/* The caller has to free the serial number */
 | 
			
		||||
			*serial_number_utf8 = strdup(value);
 | 
			
		||||
			found_serial = 1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
next_line:
 | 
			
		||||
		line = strtok_r(NULL, "\n", &saveptr);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	free(tmp);
 | 
			
		||||
	return (found_id && found_name && found_serial);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int get_device_string(hid_device *dev, enum device_string_id key, wchar_t *string, size_t maxlen)
 | 
			
		||||
{
 | 
			
		||||
	struct udev *udev;
 | 
			
		||||
	struct udev_device *udev_dev, *parent, *hid_dev;
 | 
			
		||||
	struct stat s;
 | 
			
		||||
	int ret = -1;
 | 
			
		||||
        char *serial_number_utf8 = NULL;
 | 
			
		||||
        char *product_name_utf8 = NULL;
 | 
			
		||||
 | 
			
		||||
	/* Create the udev object */
 | 
			
		||||
	udev = udev_new();
 | 
			
		||||
	if (!udev) {
 | 
			
		||||
		printf("Can't create udev\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Get the dev_t (major/minor numbers) from the file handle. */
 | 
			
		||||
	ret = fstat(dev->device_handle, &s);
 | 
			
		||||
	if (-1 == ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
	/* Open a udev device from the dev_t. 'c' means character device. */
 | 
			
		||||
	udev_dev = udev_device_new_from_devnum(udev, 'c', s.st_rdev);
 | 
			
		||||
	if (udev_dev) {
 | 
			
		||||
		hid_dev = udev_device_get_parent_with_subsystem_devtype(
 | 
			
		||||
			udev_dev,
 | 
			
		||||
			"hid",
 | 
			
		||||
			NULL);
 | 
			
		||||
		if (hid_dev) {
 | 
			
		||||
			unsigned short dev_vid;
 | 
			
		||||
			unsigned short dev_pid;
 | 
			
		||||
			int bus_type;
 | 
			
		||||
			size_t retm;
 | 
			
		||||
 | 
			
		||||
			ret = parse_uevent_info(
 | 
			
		||||
			           udev_device_get_sysattr_value(hid_dev, "uevent"),
 | 
			
		||||
			           &bus_type,
 | 
			
		||||
			           &dev_vid,
 | 
			
		||||
			           &dev_pid,
 | 
			
		||||
			           &serial_number_utf8,
 | 
			
		||||
			           &product_name_utf8);
 | 
			
		||||
 | 
			
		||||
			if (bus_type == BUS_BLUETOOTH) {
 | 
			
		||||
				switch (key) {
 | 
			
		||||
					case DEVICE_STRING_MANUFACTURER:
 | 
			
		||||
						wcsncpy(string, L"", maxlen);
 | 
			
		||||
						ret = 0;
 | 
			
		||||
						break;
 | 
			
		||||
					case DEVICE_STRING_PRODUCT:
 | 
			
		||||
						retm = mbstowcs(string, product_name_utf8, maxlen);
 | 
			
		||||
						ret = (retm == (size_t)-1)? -1: 0;
 | 
			
		||||
						break;
 | 
			
		||||
					case DEVICE_STRING_SERIAL:
 | 
			
		||||
						retm = mbstowcs(string, serial_number_utf8, maxlen);
 | 
			
		||||
						ret = (retm == (size_t)-1)? -1: 0;
 | 
			
		||||
						break;
 | 
			
		||||
					case DEVICE_STRING_COUNT:
 | 
			
		||||
					default:
 | 
			
		||||
						ret = -1;
 | 
			
		||||
						break;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				/* This is a USB device. Find its parent USB Device node. */
 | 
			
		||||
				parent = udev_device_get_parent_with_subsystem_devtype(
 | 
			
		||||
					   udev_dev,
 | 
			
		||||
					   "usb",
 | 
			
		||||
					   "usb_device");
 | 
			
		||||
				if (parent) {
 | 
			
		||||
					const char *str;
 | 
			
		||||
					const char *key_str = NULL;
 | 
			
		||||
 | 
			
		||||
					if (key >= 0 && key < DEVICE_STRING_COUNT) {
 | 
			
		||||
						key_str = device_string_names[key];
 | 
			
		||||
					} else {
 | 
			
		||||
						ret = -1;
 | 
			
		||||
						goto end;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					str = udev_device_get_sysattr_value(parent, key_str);
 | 
			
		||||
					if (str) {
 | 
			
		||||
						/* Convert the string from UTF-8 to wchar_t */
 | 
			
		||||
						retm = mbstowcs(string, str, maxlen);
 | 
			
		||||
						ret = (retm == (size_t)-1)? -1: 0;
 | 
			
		||||
						goto end;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
end:
 | 
			
		||||
        free(serial_number_utf8);
 | 
			
		||||
        free(product_name_utf8);
 | 
			
		||||
 | 
			
		||||
	udev_device_unref(udev_dev);
 | 
			
		||||
	/* parent and hid_dev don't need to be (and can't be) unref'd.
 | 
			
		||||
	   I'm not sure why, but they'll throw double-free() errors. */
 | 
			
		||||
	udev_unref(udev);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int HID_API_EXPORT hid_init(void)
 | 
			
		||||
{
 | 
			
		||||
	const char *locale;
 | 
			
		||||
 | 
			
		||||
	/* Set the locale if it's not set. */
 | 
			
		||||
	locale = setlocale(LC_CTYPE, NULL);
 | 
			
		||||
	if (!locale)
 | 
			
		||||
		setlocale(LC_CTYPE, "");
 | 
			
		||||
 | 
			
		||||
	kernel_version = detect_kernel_version();
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int HID_API_EXPORT hid_exit(void)
 | 
			
		||||
{
 | 
			
		||||
	/* Nothing to do for this in the Linux/hidraw implementation. */
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct hid_device_info  HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id)
 | 
			
		||||
{
 | 
			
		||||
	struct udev *udev;
 | 
			
		||||
	struct udev_enumerate *enumerate;
 | 
			
		||||
	struct udev_list_entry *devices, *dev_list_entry;
 | 
			
		||||
 | 
			
		||||
	struct hid_device_info *root = NULL; /* return object */
 | 
			
		||||
	struct hid_device_info *cur_dev = NULL;
 | 
			
		||||
	struct hid_device_info *prev_dev = NULL; /* previous device */
 | 
			
		||||
 | 
			
		||||
	hid_init();
 | 
			
		||||
 | 
			
		||||
	/* Create the udev object */
 | 
			
		||||
	udev = udev_new();
 | 
			
		||||
	if (!udev) {
 | 
			
		||||
		printf("Can't create udev\n");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Create a list of the devices in the 'hidraw' subsystem. */
 | 
			
		||||
	enumerate = udev_enumerate_new(udev);
 | 
			
		||||
	udev_enumerate_add_match_subsystem(enumerate, "hidraw");
 | 
			
		||||
	udev_enumerate_scan_devices(enumerate);
 | 
			
		||||
	devices = udev_enumerate_get_list_entry(enumerate);
 | 
			
		||||
	/* For each item, see if it matches the vid/pid, and if so
 | 
			
		||||
	   create a udev_device record for it */
 | 
			
		||||
	udev_list_entry_foreach(dev_list_entry, devices) {
 | 
			
		||||
		const char *sysfs_path;
 | 
			
		||||
		const char *dev_path;
 | 
			
		||||
		const char *str;
 | 
			
		||||
		struct udev_device *raw_dev; /* The device's hidraw udev node. */
 | 
			
		||||
		struct udev_device *hid_dev; /* The device's HID udev node. */
 | 
			
		||||
		struct udev_device *usb_dev; /* The device's USB udev node. */
 | 
			
		||||
		struct udev_device *intf_dev; /* The device's interface (in the USB sense). */
 | 
			
		||||
		unsigned short dev_vid;
 | 
			
		||||
		unsigned short dev_pid;
 | 
			
		||||
		char *serial_number_utf8 = NULL;
 | 
			
		||||
		char *product_name_utf8 = NULL;
 | 
			
		||||
		int bus_type;
 | 
			
		||||
		int result;
 | 
			
		||||
 | 
			
		||||
		/* Get the filename of the /sys entry for the device
 | 
			
		||||
		   and create a udev_device object (dev) representing it */
 | 
			
		||||
		sysfs_path = udev_list_entry_get_name(dev_list_entry);
 | 
			
		||||
		raw_dev = udev_device_new_from_syspath(udev, sysfs_path);
 | 
			
		||||
		dev_path = udev_device_get_devnode(raw_dev);
 | 
			
		||||
 | 
			
		||||
		hid_dev = udev_device_get_parent_with_subsystem_devtype(
 | 
			
		||||
			raw_dev,
 | 
			
		||||
			"hid",
 | 
			
		||||
			NULL);
 | 
			
		||||
 | 
			
		||||
		if (!hid_dev) {
 | 
			
		||||
			/* Unable to find parent hid device. */
 | 
			
		||||
			goto next;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		result = parse_uevent_info(
 | 
			
		||||
			udev_device_get_sysattr_value(hid_dev, "uevent"),
 | 
			
		||||
			&bus_type,
 | 
			
		||||
			&dev_vid,
 | 
			
		||||
			&dev_pid,
 | 
			
		||||
			&serial_number_utf8,
 | 
			
		||||
			&product_name_utf8);
 | 
			
		||||
 | 
			
		||||
		if (!result) {
 | 
			
		||||
			/* parse_uevent_info() failed for at least one field. */
 | 
			
		||||
			goto next;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (bus_type != BUS_USB && bus_type != BUS_BLUETOOTH) {
 | 
			
		||||
			/* We only know how to handle USB and BT devices. */
 | 
			
		||||
			goto next;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Check the VID/PID against the arguments */
 | 
			
		||||
		if ((vendor_id == 0x0 || vendor_id == dev_vid) &&
 | 
			
		||||
		    (product_id == 0x0 || product_id == dev_pid)) {
 | 
			
		||||
			struct hid_device_info *tmp;
 | 
			
		||||
 | 
			
		||||
			/* VID/PID match. Create the record. */
 | 
			
		||||
			tmp = malloc(sizeof(struct hid_device_info));
 | 
			
		||||
			if (cur_dev) {
 | 
			
		||||
				cur_dev->next = tmp;
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				root = tmp;
 | 
			
		||||
			}
 | 
			
		||||
			prev_dev = cur_dev;
 | 
			
		||||
			cur_dev = tmp;
 | 
			
		||||
 | 
			
		||||
			/* Fill out the record */
 | 
			
		||||
			cur_dev->next = NULL;
 | 
			
		||||
			cur_dev->path = dev_path? strdup(dev_path): NULL;
 | 
			
		||||
 | 
			
		||||
			/* VID/PID */
 | 
			
		||||
			cur_dev->vendor_id = dev_vid;
 | 
			
		||||
			cur_dev->product_id = dev_pid;
 | 
			
		||||
 | 
			
		||||
			/* Serial Number */
 | 
			
		||||
			cur_dev->serial_number = utf8_to_wchar_t(serial_number_utf8);
 | 
			
		||||
 | 
			
		||||
			/* Release Number */
 | 
			
		||||
			cur_dev->release_number = 0x0;
 | 
			
		||||
 | 
			
		||||
			/* Interface Number */
 | 
			
		||||
			cur_dev->interface_number = -1;
 | 
			
		||||
 | 
			
		||||
			switch (bus_type) {
 | 
			
		||||
				case BUS_USB:
 | 
			
		||||
					/* The device pointed to by raw_dev contains information about
 | 
			
		||||
					   the hidraw device. In order to get information about the
 | 
			
		||||
					   USB device, get the parent device with the
 | 
			
		||||
					   subsystem/devtype pair of "usb"/"usb_device". This will
 | 
			
		||||
					   be several levels up the tree, but the function will find
 | 
			
		||||
					   it. */
 | 
			
		||||
					usb_dev = udev_device_get_parent_with_subsystem_devtype(
 | 
			
		||||
							raw_dev,
 | 
			
		||||
							"usb",
 | 
			
		||||
							"usb_device");
 | 
			
		||||
 | 
			
		||||
					if (!usb_dev) {
 | 
			
		||||
						/* Free this device */
 | 
			
		||||
						free(cur_dev->serial_number);
 | 
			
		||||
						free(cur_dev->path);
 | 
			
		||||
						free(cur_dev);
 | 
			
		||||
 | 
			
		||||
						/* Take it off the device list. */
 | 
			
		||||
						if (prev_dev) {
 | 
			
		||||
							prev_dev->next = NULL;
 | 
			
		||||
							cur_dev = prev_dev;
 | 
			
		||||
						}
 | 
			
		||||
						else {
 | 
			
		||||
							cur_dev = root = NULL;
 | 
			
		||||
						}
 | 
			
		||||
 | 
			
		||||
						goto next;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					/* Manufacturer and Product strings */
 | 
			
		||||
					cur_dev->manufacturer_string = copy_udev_string(usb_dev, device_string_names[DEVICE_STRING_MANUFACTURER]);
 | 
			
		||||
					cur_dev->product_string = copy_udev_string(usb_dev, device_string_names[DEVICE_STRING_PRODUCT]);
 | 
			
		||||
 | 
			
		||||
					/* Release Number */
 | 
			
		||||
					str = udev_device_get_sysattr_value(usb_dev, "bcdDevice");
 | 
			
		||||
					cur_dev->release_number = (str)? strtol(str, NULL, 16): 0x0;
 | 
			
		||||
 | 
			
		||||
					/* Get a handle to the interface's udev node. */
 | 
			
		||||
					intf_dev = udev_device_get_parent_with_subsystem_devtype(
 | 
			
		||||
							raw_dev,
 | 
			
		||||
							"usb",
 | 
			
		||||
							"usb_interface");
 | 
			
		||||
					if (intf_dev) {
 | 
			
		||||
						str = udev_device_get_sysattr_value(intf_dev, "bInterfaceNumber");
 | 
			
		||||
						cur_dev->interface_number = (str)? strtol(str, NULL, 16): -1;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					break;
 | 
			
		||||
 | 
			
		||||
				case BUS_BLUETOOTH:
 | 
			
		||||
					/* Manufacturer and Product strings */
 | 
			
		||||
					cur_dev->manufacturer_string = wcsdup(L"");
 | 
			
		||||
					cur_dev->product_string = utf8_to_wchar_t(product_name_utf8);
 | 
			
		||||
 | 
			
		||||
					break;
 | 
			
		||||
 | 
			
		||||
				default:
 | 
			
		||||
					/* Unknown device type - this should never happen, as we
 | 
			
		||||
					 * check for USB and Bluetooth devices above */
 | 
			
		||||
					break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	next:
 | 
			
		||||
		free(serial_number_utf8);
 | 
			
		||||
		free(product_name_utf8);
 | 
			
		||||
		udev_device_unref(raw_dev);
 | 
			
		||||
		/* hid_dev, usb_dev and intf_dev don't need to be (and can't be)
 | 
			
		||||
		   unref()d.  It will cause a double-free() error.  I'm not
 | 
			
		||||
		   sure why.  */
 | 
			
		||||
	}
 | 
			
		||||
	/* Free the enumerator and udev objects. */
 | 
			
		||||
	udev_enumerate_unref(enumerate);
 | 
			
		||||
	udev_unref(udev);
 | 
			
		||||
 | 
			
		||||
	return root;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void  HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs)
 | 
			
		||||
{
 | 
			
		||||
	struct hid_device_info *d = devs;
 | 
			
		||||
	while (d) {
 | 
			
		||||
		struct hid_device_info *next = d->next;
 | 
			
		||||
		free(d->path);
 | 
			
		||||
		free(d->serial_number);
 | 
			
		||||
		free(d->manufacturer_string);
 | 
			
		||||
		free(d->product_string);
 | 
			
		||||
		free(d);
 | 
			
		||||
		d = next;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
hid_device * hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
 | 
			
		||||
{
 | 
			
		||||
	struct hid_device_info *devs, *cur_dev;
 | 
			
		||||
	const char *path_to_open = NULL;
 | 
			
		||||
	hid_device *handle = NULL;
 | 
			
		||||
 | 
			
		||||
	devs = hid_enumerate(vendor_id, product_id);
 | 
			
		||||
	cur_dev = devs;
 | 
			
		||||
	while (cur_dev) {
 | 
			
		||||
		if (cur_dev->vendor_id == vendor_id &&
 | 
			
		||||
		    cur_dev->product_id == product_id) {
 | 
			
		||||
			if (serial_number) {
 | 
			
		||||
				if (wcscmp(serial_number, cur_dev->serial_number) == 0) {
 | 
			
		||||
					path_to_open = cur_dev->path;
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				path_to_open = cur_dev->path;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		cur_dev = cur_dev->next;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (path_to_open) {
 | 
			
		||||
		/* Open the device */
 | 
			
		||||
		handle = hid_open_path(path_to_open);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	hid_free_enumeration(devs);
 | 
			
		||||
 | 
			
		||||
	return handle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
hid_device * HID_API_EXPORT hid_open_path(const char *path)
 | 
			
		||||
{
 | 
			
		||||
	hid_device *dev = NULL;
 | 
			
		||||
 | 
			
		||||
	hid_init();
 | 
			
		||||
 | 
			
		||||
	dev = new_hid_device();
 | 
			
		||||
 | 
			
		||||
	/* OPEN HERE */
 | 
			
		||||
	dev->device_handle = open(path, O_RDWR);
 | 
			
		||||
 | 
			
		||||
	/* If we have a good handle, return it. */
 | 
			
		||||
	if (dev->device_handle > 0) {
 | 
			
		||||
 | 
			
		||||
		/* Get the report descriptor */
 | 
			
		||||
		int res, desc_size = 0;
 | 
			
		||||
		struct hidraw_report_descriptor rpt_desc;
 | 
			
		||||
 | 
			
		||||
		memset(&rpt_desc, 0x0, sizeof(rpt_desc));
 | 
			
		||||
 | 
			
		||||
		/* Get Report Descriptor Size */
 | 
			
		||||
		res = ioctl(dev->device_handle, HIDIOCGRDESCSIZE, &desc_size);
 | 
			
		||||
		if (res < 0)
 | 
			
		||||
			perror("HIDIOCGRDESCSIZE");
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		/* Get Report Descriptor */
 | 
			
		||||
		rpt_desc.size = desc_size;
 | 
			
		||||
		res = ioctl(dev->device_handle, HIDIOCGRDESC, &rpt_desc);
 | 
			
		||||
		if (res < 0) {
 | 
			
		||||
			perror("HIDIOCGRDESC");
 | 
			
		||||
		} else {
 | 
			
		||||
			/* Determine if this device uses numbered reports. */
 | 
			
		||||
			dev->uses_numbered_reports =
 | 
			
		||||
				uses_numbered_reports(rpt_desc.value,
 | 
			
		||||
				                      rpt_desc.size);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return dev;
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		/* Unable to open any devices. */
 | 
			
		||||
		free(dev);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length)
 | 
			
		||||
{
 | 
			
		||||
	int bytes_written;
 | 
			
		||||
 | 
			
		||||
	bytes_written = write(dev->device_handle, data, length);
 | 
			
		||||
 | 
			
		||||
	return bytes_written;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
 | 
			
		||||
{
 | 
			
		||||
	int bytes_read;
 | 
			
		||||
 | 
			
		||||
	if (milliseconds >= 0) {
 | 
			
		||||
		/* Milliseconds is either 0 (non-blocking) or > 0 (contains
 | 
			
		||||
		   a valid timeout). In both cases we want to call poll()
 | 
			
		||||
		   and wait for data to arrive.  Don't rely on non-blocking
 | 
			
		||||
		   operation (O_NONBLOCK) since some kernels don't seem to
 | 
			
		||||
		   properly report device disconnection through read() when
 | 
			
		||||
		   in non-blocking mode.  */
 | 
			
		||||
		int ret;
 | 
			
		||||
		struct pollfd fds;
 | 
			
		||||
 | 
			
		||||
		fds.fd = dev->device_handle;
 | 
			
		||||
		fds.events = POLLIN;
 | 
			
		||||
		fds.revents = 0;
 | 
			
		||||
		ret = poll(&fds, 1, milliseconds);
 | 
			
		||||
		if (ret == -1 || ret == 0) {
 | 
			
		||||
			/* Error or timeout */
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			/* Check for errors on the file descriptor. This will
 | 
			
		||||
			   indicate a device disconnection. */
 | 
			
		||||
			if (fds.revents & (POLLERR | POLLHUP | POLLNVAL))
 | 
			
		||||
				return -1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bytes_read = read(dev->device_handle, data, length);
 | 
			
		||||
	if (bytes_read < 0 && (errno == EAGAIN || errno == EINPROGRESS))
 | 
			
		||||
		bytes_read = 0;
 | 
			
		||||
 | 
			
		||||
	if (bytes_read >= 0 &&
 | 
			
		||||
	    kernel_version != 0 &&
 | 
			
		||||
	    kernel_version < KERNEL_VERSION(2,6,34) &&
 | 
			
		||||
	    dev->uses_numbered_reports) {
 | 
			
		||||
		/* Work around a kernel bug. Chop off the first byte. */
 | 
			
		||||
		memmove(data, data+1, bytes_read);
 | 
			
		||||
		bytes_read--;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return bytes_read;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length)
 | 
			
		||||
{
 | 
			
		||||
	return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock)
 | 
			
		||||
{
 | 
			
		||||
	/* Do all non-blocking in userspace using poll(), since it looks
 | 
			
		||||
	   like there's a bug in the kernel in some versions where
 | 
			
		||||
	   read() will not return -1 on disconnection of the USB device */
 | 
			
		||||
 | 
			
		||||
	dev->blocking = !nonblock;
 | 
			
		||||
	return 0; /* Success */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)
 | 
			
		||||
{
 | 
			
		||||
	int res;
 | 
			
		||||
 | 
			
		||||
	res = ioctl(dev->device_handle, HIDIOCSFEATURE(length), data);
 | 
			
		||||
	if (res < 0)
 | 
			
		||||
		perror("ioctl (SFEATURE)");
 | 
			
		||||
 | 
			
		||||
	return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
 | 
			
		||||
{
 | 
			
		||||
	int res;
 | 
			
		||||
 | 
			
		||||
	res = ioctl(dev->device_handle, HIDIOCGFEATURE(length), data);
 | 
			
		||||
	if (res < 0)
 | 
			
		||||
		perror("ioctl (GFEATURE)");
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void HID_API_EXPORT hid_close(hid_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	if (!dev)
 | 
			
		||||
		return;
 | 
			
		||||
	close(dev->device_handle);
 | 
			
		||||
	free(dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)
 | 
			
		||||
{
 | 
			
		||||
	return get_device_string(dev, DEVICE_STRING_MANUFACTURER, string, maxlen);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)
 | 
			
		||||
{
 | 
			
		||||
	return get_device_string(dev, DEVICE_STRING_PRODUCT, string, maxlen);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)
 | 
			
		||||
{
 | 
			
		||||
	return get_device_string(dev, DEVICE_STRING_SERIAL, string, maxlen);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)
 | 
			
		||||
{
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
HID_API_EXPORT const wchar_t * HID_API_CALL  hid_error(hid_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1121
									
								
								src/hidapi/mac/hid.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1121
									
								
								src/hidapi/mac/hid.c
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										956
									
								
								src/hidapi/win/hid.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										956
									
								
								src/hidapi/win/hid.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,956 @@
 | 
			
		|||
/*******************************************************
 | 
			
		||||
 HIDAPI - Multi-Platform library for
 | 
			
		||||
 communication with HID devices.
 | 
			
		||||
 | 
			
		||||
 Alan Ott
 | 
			
		||||
 Signal 11 Software
 | 
			
		||||
 | 
			
		||||
 8/22/2009
 | 
			
		||||
 | 
			
		||||
 Copyright 2009, All Rights Reserved.
 | 
			
		||||
 
 | 
			
		||||
 At the discretion of the user of this library,
 | 
			
		||||
 this software may be licensed under the terms of the
 | 
			
		||||
 GNU General Public License v3, a BSD-Style license, or the
 | 
			
		||||
 original HIDAPI license as outlined in the LICENSE.txt,
 | 
			
		||||
 LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
 | 
			
		||||
 files located at the root of the source distribution.
 | 
			
		||||
 These files may also be found in the public source
 | 
			
		||||
 code repository located at:
 | 
			
		||||
        http://github.com/signal11/hidapi .
 | 
			
		||||
********************************************************/
 | 
			
		||||
 | 
			
		||||
#include <windows.h>
 | 
			
		||||
 | 
			
		||||
#ifndef _NTDEF_
 | 
			
		||||
typedef LONG NTSTATUS;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef __MINGW32__
 | 
			
		||||
#include <ntdef.h>
 | 
			
		||||
#include <winbase.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef __CYGWIN__
 | 
			
		||||
#include <ntdef.h>
 | 
			
		||||
#define _wcsdup wcsdup
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* The maximum number of characters that can be passed into the
 | 
			
		||||
   HidD_Get*String() functions without it failing.*/
 | 
			
		||||
#define MAX_STRING_WCHARS 0xFFF
 | 
			
		||||
 | 
			
		||||
/*#define HIDAPI_USE_DDK*/
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
	#include <setupapi.h>
 | 
			
		||||
	#include <winioctl.h>
 | 
			
		||||
	#ifdef HIDAPI_USE_DDK
 | 
			
		||||
		#include <hidsdi.h>
 | 
			
		||||
	#endif
 | 
			
		||||
 | 
			
		||||
	/* Copied from inc/ddk/hidclass.h, part of the Windows DDK. */
 | 
			
		||||
	#define HID_OUT_CTL_CODE(id)  \
 | 
			
		||||
		CTL_CODE(FILE_DEVICE_KEYBOARD, (id), METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
 | 
			
		||||
	#define IOCTL_HID_GET_FEATURE                   HID_OUT_CTL_CODE(100)
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
} /* extern "C" */
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include "hidapi.h"
 | 
			
		||||
 | 
			
		||||
#undef MIN
 | 
			
		||||
#define MIN(x,y) ((x) < (y)? (x): (y))
 | 
			
		||||
 | 
			
		||||
#ifdef _MSC_VER
 | 
			
		||||
	/* Thanks Microsoft, but I know how to use strncpy(). */
 | 
			
		||||
	#pragma warning(disable:4996)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef HIDAPI_USE_DDK
 | 
			
		||||
	/* Since we're not building with the DDK, and the HID header
 | 
			
		||||
	   files aren't part of the SDK, we have to define all this
 | 
			
		||||
	   stuff here. In lookup_functions(), the function pointers
 | 
			
		||||
	   defined below are set. */
 | 
			
		||||
	typedef struct _HIDD_ATTRIBUTES{
 | 
			
		||||
		ULONG Size;
 | 
			
		||||
		USHORT VendorID;
 | 
			
		||||
		USHORT ProductID;
 | 
			
		||||
		USHORT VersionNumber;
 | 
			
		||||
	} HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;
 | 
			
		||||
 | 
			
		||||
	typedef USHORT USAGE;
 | 
			
		||||
	typedef struct _HIDP_CAPS {
 | 
			
		||||
		USAGE Usage;
 | 
			
		||||
		USAGE UsagePage;
 | 
			
		||||
		USHORT InputReportByteLength;
 | 
			
		||||
		USHORT OutputReportByteLength;
 | 
			
		||||
		USHORT FeatureReportByteLength;
 | 
			
		||||
		USHORT Reserved[17];
 | 
			
		||||
		USHORT fields_not_used_by_hidapi[10];
 | 
			
		||||
	} HIDP_CAPS, *PHIDP_CAPS;
 | 
			
		||||
	typedef void* PHIDP_PREPARSED_DATA;
 | 
			
		||||
	#define HIDP_STATUS_SUCCESS 0x110000
 | 
			
		||||
 | 
			
		||||
	typedef BOOLEAN (__stdcall *HidD_GetAttributes_)(HANDLE device, PHIDD_ATTRIBUTES attrib);
 | 
			
		||||
	typedef BOOLEAN (__stdcall *HidD_GetSerialNumberString_)(HANDLE device, PVOID buffer, ULONG buffer_len);
 | 
			
		||||
	typedef BOOLEAN (__stdcall *HidD_GetManufacturerString_)(HANDLE handle, PVOID buffer, ULONG buffer_len);
 | 
			
		||||
	typedef BOOLEAN (__stdcall *HidD_GetProductString_)(HANDLE handle, PVOID buffer, ULONG buffer_len);
 | 
			
		||||
	typedef BOOLEAN (__stdcall *HidD_SetFeature_)(HANDLE handle, PVOID data, ULONG length);
 | 
			
		||||
	typedef BOOLEAN (__stdcall *HidD_GetFeature_)(HANDLE handle, PVOID data, ULONG length);
 | 
			
		||||
	typedef BOOLEAN (__stdcall *HidD_GetIndexedString_)(HANDLE handle, ULONG string_index, PVOID buffer, ULONG buffer_len);
 | 
			
		||||
	typedef BOOLEAN (__stdcall *HidD_GetPreparsedData_)(HANDLE handle, PHIDP_PREPARSED_DATA *preparsed_data);
 | 
			
		||||
	typedef BOOLEAN (__stdcall *HidD_FreePreparsedData_)(PHIDP_PREPARSED_DATA preparsed_data);
 | 
			
		||||
	typedef NTSTATUS (__stdcall *HidP_GetCaps_)(PHIDP_PREPARSED_DATA preparsed_data, HIDP_CAPS *caps);
 | 
			
		||||
	typedef BOOLEAN (__stdcall *HidD_SetNumInputBuffers_)(HANDLE handle, ULONG number_buffers);
 | 
			
		||||
 | 
			
		||||
	static HidD_GetAttributes_ HidD_GetAttributes;
 | 
			
		||||
	static HidD_GetSerialNumberString_ HidD_GetSerialNumberString;
 | 
			
		||||
	static HidD_GetManufacturerString_ HidD_GetManufacturerString;
 | 
			
		||||
	static HidD_GetProductString_ HidD_GetProductString;
 | 
			
		||||
	static HidD_SetFeature_ HidD_SetFeature;
 | 
			
		||||
	static HidD_GetFeature_ HidD_GetFeature;
 | 
			
		||||
	static HidD_GetIndexedString_ HidD_GetIndexedString;
 | 
			
		||||
	static HidD_GetPreparsedData_ HidD_GetPreparsedData;
 | 
			
		||||
	static HidD_FreePreparsedData_ HidD_FreePreparsedData;
 | 
			
		||||
	static HidP_GetCaps_ HidP_GetCaps;
 | 
			
		||||
	static HidD_SetNumInputBuffers_ HidD_SetNumInputBuffers;
 | 
			
		||||
 | 
			
		||||
	static HMODULE lib_handle = NULL;
 | 
			
		||||
	static BOOLEAN initialized = FALSE;
 | 
			
		||||
#endif /* HIDAPI_USE_DDK */
 | 
			
		||||
 | 
			
		||||
struct hid_device_ {
 | 
			
		||||
		HANDLE device_handle;
 | 
			
		||||
		BOOL blocking;
 | 
			
		||||
		USHORT output_report_length;
 | 
			
		||||
		size_t input_report_length;
 | 
			
		||||
		void *last_error_str;
 | 
			
		||||
		DWORD last_error_num;
 | 
			
		||||
		BOOL read_pending;
 | 
			
		||||
		char *read_buf;
 | 
			
		||||
		OVERLAPPED ol;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static hid_device *new_hid_device()
 | 
			
		||||
{
 | 
			
		||||
	hid_device *dev = (hid_device*) calloc(1, sizeof(hid_device));
 | 
			
		||||
	dev->device_handle = INVALID_HANDLE_VALUE;
 | 
			
		||||
	dev->blocking = TRUE;
 | 
			
		||||
	dev->output_report_length = 0;
 | 
			
		||||
	dev->input_report_length = 0;
 | 
			
		||||
	dev->last_error_str = NULL;
 | 
			
		||||
	dev->last_error_num = 0;
 | 
			
		||||
	dev->read_pending = FALSE;
 | 
			
		||||
	dev->read_buf = NULL;
 | 
			
		||||
	memset(&dev->ol, 0, sizeof(dev->ol));
 | 
			
		||||
	dev->ol.hEvent = CreateEvent(NULL, FALSE, FALSE /*initial state f=nonsignaled*/, NULL);
 | 
			
		||||
 | 
			
		||||
	return dev;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void free_hid_device(hid_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	CloseHandle(dev->ol.hEvent);
 | 
			
		||||
	CloseHandle(dev->device_handle);
 | 
			
		||||
	LocalFree(dev->last_error_str);
 | 
			
		||||
	free(dev->read_buf);
 | 
			
		||||
	free(dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void register_error(hid_device *dev, const char *op)
 | 
			
		||||
{
 | 
			
		||||
	WCHAR *ptr, *msg;
 | 
			
		||||
 | 
			
		||||
	FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
 | 
			
		||||
		FORMAT_MESSAGE_FROM_SYSTEM |
 | 
			
		||||
		FORMAT_MESSAGE_IGNORE_INSERTS,
 | 
			
		||||
		NULL,
 | 
			
		||||
		GetLastError(),
 | 
			
		||||
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
 | 
			
		||||
		(LPVOID)&msg, 0/*sz*/,
 | 
			
		||||
		NULL);
 | 
			
		||||
	
 | 
			
		||||
	/* Get rid of the CR and LF that FormatMessage() sticks at the
 | 
			
		||||
	   end of the message. Thanks Microsoft! */
 | 
			
		||||
	ptr = msg;
 | 
			
		||||
	while (*ptr) {
 | 
			
		||||
		if (*ptr == '\r') {
 | 
			
		||||
			*ptr = 0x0000;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		ptr++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Store the message off in the Device entry so that
 | 
			
		||||
	   the hid_error() function can pick it up. */
 | 
			
		||||
	LocalFree(dev->last_error_str);
 | 
			
		||||
	dev->last_error_str = msg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifndef HIDAPI_USE_DDK
 | 
			
		||||
static int lookup_functions()
 | 
			
		||||
{
 | 
			
		||||
	lib_handle = LoadLibraryA("hid.dll");
 | 
			
		||||
	if (lib_handle) {
 | 
			
		||||
#define RESOLVE(x) x = (x##_)GetProcAddress(lib_handle, #x); if (!x) return -1;
 | 
			
		||||
		RESOLVE(HidD_GetAttributes);
 | 
			
		||||
		RESOLVE(HidD_GetSerialNumberString);
 | 
			
		||||
		RESOLVE(HidD_GetManufacturerString);
 | 
			
		||||
		RESOLVE(HidD_GetProductString);
 | 
			
		||||
		RESOLVE(HidD_SetFeature);
 | 
			
		||||
		RESOLVE(HidD_GetFeature);
 | 
			
		||||
		RESOLVE(HidD_GetIndexedString);
 | 
			
		||||
		RESOLVE(HidD_GetPreparsedData);
 | 
			
		||||
		RESOLVE(HidD_FreePreparsedData);
 | 
			
		||||
		RESOLVE(HidP_GetCaps);
 | 
			
		||||
		RESOLVE(HidD_SetNumInputBuffers);
 | 
			
		||||
#undef RESOLVE
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static HANDLE open_device(const char *path, BOOL open_rw)
 | 
			
		||||
{
 | 
			
		||||
	HANDLE handle;
 | 
			
		||||
	DWORD desired_access = (open_rw)? (GENERIC_WRITE | GENERIC_READ): 0;
 | 
			
		||||
	DWORD share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
 | 
			
		||||
 | 
			
		||||
	handle = CreateFileA(path,
 | 
			
		||||
		desired_access,
 | 
			
		||||
		share_mode,
 | 
			
		||||
		NULL,
 | 
			
		||||
		OPEN_EXISTING,
 | 
			
		||||
		FILE_FLAG_OVERLAPPED,/*FILE_ATTRIBUTE_NORMAL,*/
 | 
			
		||||
		0);
 | 
			
		||||
 | 
			
		||||
	return handle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int HID_API_EXPORT hid_init(void)
 | 
			
		||||
{
 | 
			
		||||
#ifndef HIDAPI_USE_DDK
 | 
			
		||||
	if (!initialized) {
 | 
			
		||||
		if (lookup_functions() < 0) {
 | 
			
		||||
			hid_exit();
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
		initialized = TRUE;
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int HID_API_EXPORT hid_exit(void)
 | 
			
		||||
{
 | 
			
		||||
#ifndef HIDAPI_USE_DDK
 | 
			
		||||
	if (lib_handle)
 | 
			
		||||
		FreeLibrary(lib_handle);
 | 
			
		||||
	lib_handle = NULL;
 | 
			
		||||
	initialized = FALSE;
 | 
			
		||||
#endif
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id)
 | 
			
		||||
{
 | 
			
		||||
	BOOL res;
 | 
			
		||||
	struct hid_device_info *root = NULL; /* return object */
 | 
			
		||||
	struct hid_device_info *cur_dev = NULL;
 | 
			
		||||
 | 
			
		||||
	/* Windows objects for interacting with the driver. */
 | 
			
		||||
	GUID InterfaceClassGuid = {0x4d1e55b2, 0xf16f, 0x11cf, {0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30} };
 | 
			
		||||
	SP_DEVINFO_DATA devinfo_data;
 | 
			
		||||
	SP_DEVICE_INTERFACE_DATA device_interface_data;
 | 
			
		||||
	SP_DEVICE_INTERFACE_DETAIL_DATA_A *device_interface_detail_data = NULL;
 | 
			
		||||
	HDEVINFO device_info_set = INVALID_HANDLE_VALUE;
 | 
			
		||||
	int device_index = 0;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (hid_init() < 0)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	/* Initialize the Windows objects. */
 | 
			
		||||
	memset(&devinfo_data, 0x0, sizeof(devinfo_data));
 | 
			
		||||
	devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA);
 | 
			
		||||
	device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
 | 
			
		||||
 | 
			
		||||
	/* Get information for all the devices belonging to the HID class. */
 | 
			
		||||
	device_info_set = SetupDiGetClassDevsA(&InterfaceClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
 | 
			
		||||
	
 | 
			
		||||
	/* Iterate over each device in the HID class, looking for the right one. */
 | 
			
		||||
	
 | 
			
		||||
	for (;;) {
 | 
			
		||||
		HANDLE write_handle = INVALID_HANDLE_VALUE;
 | 
			
		||||
		DWORD required_size = 0;
 | 
			
		||||
		HIDD_ATTRIBUTES attrib;
 | 
			
		||||
 | 
			
		||||
		res = SetupDiEnumDeviceInterfaces(device_info_set,
 | 
			
		||||
			NULL,
 | 
			
		||||
			&InterfaceClassGuid,
 | 
			
		||||
			device_index,
 | 
			
		||||
			&device_interface_data);
 | 
			
		||||
		
 | 
			
		||||
		if (!res) {
 | 
			
		||||
			/* A return of FALSE from this function means that
 | 
			
		||||
			   there are no more devices. */
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Call with 0-sized detail size, and let the function
 | 
			
		||||
		   tell us how long the detail struct needs to be. The
 | 
			
		||||
		   size is put in &required_size. */
 | 
			
		||||
		res = SetupDiGetDeviceInterfaceDetailA(device_info_set,
 | 
			
		||||
			&device_interface_data,
 | 
			
		||||
			NULL,
 | 
			
		||||
			0,
 | 
			
		||||
			&required_size,
 | 
			
		||||
			NULL);
 | 
			
		||||
 | 
			
		||||
		/* Allocate a long enough structure for device_interface_detail_data. */
 | 
			
		||||
		device_interface_detail_data = (SP_DEVICE_INTERFACE_DETAIL_DATA_A*) malloc(required_size);
 | 
			
		||||
		device_interface_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
 | 
			
		||||
 | 
			
		||||
		/* Get the detailed data for this device. The detail data gives us
 | 
			
		||||
		   the device path for this device, which is then passed into
 | 
			
		||||
		   CreateFile() to get a handle to the device. */
 | 
			
		||||
		res = SetupDiGetDeviceInterfaceDetailA(device_info_set,
 | 
			
		||||
			&device_interface_data,
 | 
			
		||||
			device_interface_detail_data,
 | 
			
		||||
			required_size,
 | 
			
		||||
			NULL,
 | 
			
		||||
			NULL);
 | 
			
		||||
 | 
			
		||||
		if (!res) {
 | 
			
		||||
			/* register_error(dev, "Unable to call SetupDiGetDeviceInterfaceDetail");
 | 
			
		||||
			   Continue to the next device. */
 | 
			
		||||
			goto cont;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Make sure this device is of Setup Class "HIDClass" and has a
 | 
			
		||||
		   driver bound to it. */
 | 
			
		||||
		for (i = 0; ; i++) {
 | 
			
		||||
			char driver_name[256];
 | 
			
		||||
 | 
			
		||||
			/* Populate devinfo_data. This function will return failure
 | 
			
		||||
			   when there are no more interfaces left. */
 | 
			
		||||
			res = SetupDiEnumDeviceInfo(device_info_set, i, &devinfo_data);
 | 
			
		||||
			if (!res)
 | 
			
		||||
				goto cont;
 | 
			
		||||
 | 
			
		||||
			res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data,
 | 
			
		||||
			               SPDRP_CLASS, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL);
 | 
			
		||||
			if (!res)
 | 
			
		||||
				goto cont;
 | 
			
		||||
 | 
			
		||||
			if ((strcmp(driver_name, "HIDClass") == 0) ||
 | 
			
		||||
				(strcmp(driver_name, "Mouse") == 0) ||
 | 
			
		||||
				(strcmp(driver_name, "Keyboard") == 0)) {
 | 
			
		||||
				/* See if there's a driver bound. */
 | 
			
		||||
				res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data,
 | 
			
		||||
				           SPDRP_DRIVER, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL);
 | 
			
		||||
				if (res)
 | 
			
		||||
					break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		//wprintf(L"HandleName: %s\n", device_interface_detail_data->DevicePath);
 | 
			
		||||
 | 
			
		||||
		/* Open a handle to the device */
 | 
			
		||||
		write_handle = open_device(device_interface_detail_data->DevicePath, FALSE);
 | 
			
		||||
 | 
			
		||||
		/* Check validity of write_handle. */
 | 
			
		||||
		if (write_handle == INVALID_HANDLE_VALUE) {
 | 
			
		||||
			/* Unable to open the device. */
 | 
			
		||||
			//register_error(dev, "CreateFile");
 | 
			
		||||
			goto cont_close;
 | 
			
		||||
		}		
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		/* Get the Vendor ID and Product ID for this device. */
 | 
			
		||||
		attrib.Size = sizeof(HIDD_ATTRIBUTES);
 | 
			
		||||
		HidD_GetAttributes(write_handle, &attrib);
 | 
			
		||||
		//wprintf(L"Product/Vendor: %x %x\n", attrib.ProductID, attrib.VendorID);
 | 
			
		||||
 | 
			
		||||
		/* Check the VID/PID to see if we should add this
 | 
			
		||||
		   device to the enumeration list. */
 | 
			
		||||
		if ((vendor_id == 0x0 || attrib.VendorID == vendor_id) &&
 | 
			
		||||
		    (product_id == 0x0 || attrib.ProductID == product_id)) {
 | 
			
		||||
 | 
			
		||||
			#define WSTR_LEN 512
 | 
			
		||||
			const char *str;
 | 
			
		||||
			struct hid_device_info *tmp;
 | 
			
		||||
			PHIDP_PREPARSED_DATA pp_data = NULL;
 | 
			
		||||
			HIDP_CAPS caps;
 | 
			
		||||
			BOOLEAN res;
 | 
			
		||||
			NTSTATUS nt_res;
 | 
			
		||||
			wchar_t wstr[WSTR_LEN]; /* TODO: Determine Size */
 | 
			
		||||
			size_t len;
 | 
			
		||||
 | 
			
		||||
			/* VID/PID match. Create the record. */
 | 
			
		||||
			tmp = (struct hid_device_info*) calloc(1, sizeof(struct hid_device_info));
 | 
			
		||||
			if (cur_dev) {
 | 
			
		||||
				cur_dev->next = tmp;
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				root = tmp;
 | 
			
		||||
			}
 | 
			
		||||
			cur_dev = tmp;
 | 
			
		||||
 | 
			
		||||
			/* Get the Usage Page and Usage for this device. */
 | 
			
		||||
			res = HidD_GetPreparsedData(write_handle, &pp_data);
 | 
			
		||||
			if (res) {
 | 
			
		||||
				nt_res = HidP_GetCaps(pp_data, &caps);
 | 
			
		||||
				if (nt_res == HIDP_STATUS_SUCCESS) {
 | 
			
		||||
					cur_dev->usage_page = caps.UsagePage;
 | 
			
		||||
					cur_dev->usage = caps.Usage;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				HidD_FreePreparsedData(pp_data);
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			/* Fill out the record */
 | 
			
		||||
			cur_dev->next = NULL;
 | 
			
		||||
			str = device_interface_detail_data->DevicePath;
 | 
			
		||||
			if (str) {
 | 
			
		||||
				len = strlen(str);
 | 
			
		||||
				cur_dev->path = (char*) calloc(len+1, sizeof(char));
 | 
			
		||||
				strncpy(cur_dev->path, str, len+1);
 | 
			
		||||
				cur_dev->path[len] = '\0';
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
				cur_dev->path = NULL;
 | 
			
		||||
 | 
			
		||||
			/* Serial Number */
 | 
			
		||||
			res = HidD_GetSerialNumberString(write_handle, wstr, sizeof(wstr));
 | 
			
		||||
			wstr[WSTR_LEN-1] = 0x0000;
 | 
			
		||||
			if (res) {
 | 
			
		||||
				cur_dev->serial_number = _wcsdup(wstr);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			/* Manufacturer String */
 | 
			
		||||
			res = HidD_GetManufacturerString(write_handle, wstr, sizeof(wstr));
 | 
			
		||||
			wstr[WSTR_LEN-1] = 0x0000;
 | 
			
		||||
			if (res) {
 | 
			
		||||
				cur_dev->manufacturer_string = _wcsdup(wstr);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			/* Product String */
 | 
			
		||||
			res = HidD_GetProductString(write_handle, wstr, sizeof(wstr));
 | 
			
		||||
			wstr[WSTR_LEN-1] = 0x0000;
 | 
			
		||||
			if (res) {
 | 
			
		||||
				cur_dev->product_string = _wcsdup(wstr);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			/* VID/PID */
 | 
			
		||||
			cur_dev->vendor_id = attrib.VendorID;
 | 
			
		||||
			cur_dev->product_id = attrib.ProductID;
 | 
			
		||||
 | 
			
		||||
			/* Release Number */
 | 
			
		||||
			cur_dev->release_number = attrib.VersionNumber;
 | 
			
		||||
 | 
			
		||||
			/* Interface Number. It can sometimes be parsed out of the path
 | 
			
		||||
			   on Windows if a device has multiple interfaces. See
 | 
			
		||||
			   http://msdn.microsoft.com/en-us/windows/hardware/gg487473 or
 | 
			
		||||
			   search for "Hardware IDs for HID Devices" at MSDN. If it's not
 | 
			
		||||
			   in the path, it's set to -1. */
 | 
			
		||||
			cur_dev->interface_number = -1;
 | 
			
		||||
			if (cur_dev->path) {
 | 
			
		||||
				char *interface_component = strstr(cur_dev->path, "&mi_");
 | 
			
		||||
				if (interface_component) {
 | 
			
		||||
					char *hex_str = interface_component + 4;
 | 
			
		||||
					char *endptr = NULL;
 | 
			
		||||
					cur_dev->interface_number = strtol(hex_str, &endptr, 16);
 | 
			
		||||
					if (endptr == hex_str) {
 | 
			
		||||
						/* The parsing failed. Set interface_number to -1. */
 | 
			
		||||
						cur_dev->interface_number = -1;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
cont_close:
 | 
			
		||||
		CloseHandle(write_handle);
 | 
			
		||||
cont:
 | 
			
		||||
		/* We no longer need the detail data. It can be freed */
 | 
			
		||||
		free(device_interface_detail_data);
 | 
			
		||||
 | 
			
		||||
		device_index++;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Close the device information handle. */
 | 
			
		||||
	SetupDiDestroyDeviceInfoList(device_info_set);
 | 
			
		||||
 | 
			
		||||
	return root;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void  HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs)
 | 
			
		||||
{
 | 
			
		||||
	/* TODO: Merge this with the Linux version. This function is platform-independent. */
 | 
			
		||||
	struct hid_device_info *d = devs;
 | 
			
		||||
	while (d) {
 | 
			
		||||
		struct hid_device_info *next = d->next;
 | 
			
		||||
		free(d->path);
 | 
			
		||||
		free(d->serial_number);
 | 
			
		||||
		free(d->manufacturer_string);
 | 
			
		||||
		free(d->product_string);
 | 
			
		||||
		free(d);
 | 
			
		||||
		d = next;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
 | 
			
		||||
{
 | 
			
		||||
	/* TODO: Merge this functions with the Linux version. This function should be platform independent. */
 | 
			
		||||
	struct hid_device_info *devs, *cur_dev;
 | 
			
		||||
	const char *path_to_open = NULL;
 | 
			
		||||
	hid_device *handle = NULL;
 | 
			
		||||
	
 | 
			
		||||
	devs = hid_enumerate(vendor_id, product_id);
 | 
			
		||||
	cur_dev = devs;
 | 
			
		||||
	while (cur_dev) {
 | 
			
		||||
		if (cur_dev->vendor_id == vendor_id &&
 | 
			
		||||
		    cur_dev->product_id == product_id) {
 | 
			
		||||
			if (serial_number) {
 | 
			
		||||
				if (wcscmp(serial_number, cur_dev->serial_number) == 0) {
 | 
			
		||||
					path_to_open = cur_dev->path;
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				path_to_open = cur_dev->path;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		cur_dev = cur_dev->next;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (path_to_open) {
 | 
			
		||||
		/* Open the device */
 | 
			
		||||
		handle = hid_open_path(path_to_open);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	hid_free_enumeration(devs);
 | 
			
		||||
	
 | 
			
		||||
	return handle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path)
 | 
			
		||||
{
 | 
			
		||||
	hid_device *dev;
 | 
			
		||||
	HIDP_CAPS caps;
 | 
			
		||||
	PHIDP_PREPARSED_DATA pp_data = NULL;
 | 
			
		||||
	BOOLEAN res;
 | 
			
		||||
	NTSTATUS nt_res;
 | 
			
		||||
 | 
			
		||||
	if (hid_init() < 0) {
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dev = new_hid_device();
 | 
			
		||||
 | 
			
		||||
	/* Open a handle to the device */
 | 
			
		||||
	dev->device_handle = open_device(path, TRUE);
 | 
			
		||||
 | 
			
		||||
	/* Check validity of write_handle. */
 | 
			
		||||
	if (dev->device_handle == INVALID_HANDLE_VALUE) {
 | 
			
		||||
		/* System devices, such as keyboards and mice, cannot be opened in
 | 
			
		||||
		   read-write mode, because the system takes exclusive control over
 | 
			
		||||
		   them.  This is to prevent keyloggers.  However, feature reports
 | 
			
		||||
		   can still be sent and received.  Retry opening the device, but
 | 
			
		||||
		   without read/write access. */
 | 
			
		||||
		dev->device_handle = open_device(path, FALSE);
 | 
			
		||||
 | 
			
		||||
		/* Check the validity of the limited device_handle. */
 | 
			
		||||
		if (dev->device_handle == INVALID_HANDLE_VALUE) {
 | 
			
		||||
			/* Unable to open the device, even without read-write mode. */
 | 
			
		||||
			register_error(dev, "CreateFile");
 | 
			
		||||
			goto err;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Set the Input Report buffer size to 64 reports. */
 | 
			
		||||
	res = HidD_SetNumInputBuffers(dev->device_handle, 64);
 | 
			
		||||
	if (!res) {
 | 
			
		||||
		register_error(dev, "HidD_SetNumInputBuffers");
 | 
			
		||||
		goto err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Get the Input Report length for the device. */
 | 
			
		||||
	res = HidD_GetPreparsedData(dev->device_handle, &pp_data);
 | 
			
		||||
	if (!res) {
 | 
			
		||||
		register_error(dev, "HidD_GetPreparsedData");
 | 
			
		||||
		goto err;
 | 
			
		||||
	}
 | 
			
		||||
	nt_res = HidP_GetCaps(pp_data, &caps);
 | 
			
		||||
	if (nt_res != HIDP_STATUS_SUCCESS) {
 | 
			
		||||
		register_error(dev, "HidP_GetCaps");	
 | 
			
		||||
		goto err_pp_data;
 | 
			
		||||
	}
 | 
			
		||||
	dev->output_report_length = caps.OutputReportByteLength;
 | 
			
		||||
	dev->input_report_length = caps.InputReportByteLength;
 | 
			
		||||
	HidD_FreePreparsedData(pp_data);
 | 
			
		||||
 | 
			
		||||
	dev->read_buf = (char*) malloc(dev->input_report_length);
 | 
			
		||||
 | 
			
		||||
	return dev;
 | 
			
		||||
 | 
			
		||||
err_pp_data:
 | 
			
		||||
		HidD_FreePreparsedData(pp_data);
 | 
			
		||||
err:	
 | 
			
		||||
		free_hid_device(dev);
 | 
			
		||||
		return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length)
 | 
			
		||||
{
 | 
			
		||||
	DWORD bytes_written;
 | 
			
		||||
	BOOL res;
 | 
			
		||||
 | 
			
		||||
	OVERLAPPED ol;
 | 
			
		||||
	unsigned char *buf;
 | 
			
		||||
	memset(&ol, 0, sizeof(ol));
 | 
			
		||||
 | 
			
		||||
	/* Make sure the right number of bytes are passed to WriteFile. Windows
 | 
			
		||||
	   expects the number of bytes which are in the _longest_ report (plus
 | 
			
		||||
	   one for the report number) bytes even if the data is a report
 | 
			
		||||
	   which is shorter than that. Windows gives us this value in
 | 
			
		||||
	   caps.OutputReportByteLength. If a user passes in fewer bytes than this,
 | 
			
		||||
	   create a temporary buffer which is the proper size. */
 | 
			
		||||
	if (length >= dev->output_report_length) {
 | 
			
		||||
		/* The user passed the right number of bytes. Use the buffer as-is. */
 | 
			
		||||
		buf = (unsigned char *) data;
 | 
			
		||||
	} else {
 | 
			
		||||
		/* Create a temporary buffer and copy the user's data
 | 
			
		||||
		   into it, padding the rest with zeros. */
 | 
			
		||||
		buf = (unsigned char *) malloc(dev->output_report_length);
 | 
			
		||||
		memcpy(buf, data, length);
 | 
			
		||||
		memset(buf + length, 0, dev->output_report_length - length);
 | 
			
		||||
		length = dev->output_report_length;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	res = WriteFile(dev->device_handle, buf, length, NULL, &ol);
 | 
			
		||||
	
 | 
			
		||||
	if (!res) {
 | 
			
		||||
		if (GetLastError() != ERROR_IO_PENDING) {
 | 
			
		||||
			/* WriteFile() failed. Return error. */
 | 
			
		||||
			register_error(dev, "WriteFile");
 | 
			
		||||
			bytes_written = -1;
 | 
			
		||||
			goto end_of_function;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Wait here until the write is done. This makes
 | 
			
		||||
	   hid_write() synchronous. */
 | 
			
		||||
	res = GetOverlappedResult(dev->device_handle, &ol, &bytes_written, TRUE/*wait*/);
 | 
			
		||||
	if (!res) {
 | 
			
		||||
		/* The Write operation failed. */
 | 
			
		||||
		register_error(dev, "WriteFile");
 | 
			
		||||
		bytes_written = -1;
 | 
			
		||||
		goto end_of_function;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
end_of_function:
 | 
			
		||||
	if (buf != data)
 | 
			
		||||
		free(buf);
 | 
			
		||||
 | 
			
		||||
	return bytes_written;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
 | 
			
		||||
{
 | 
			
		||||
	DWORD bytes_read = 0;
 | 
			
		||||
	size_t copy_len = 0;
 | 
			
		||||
	BOOL res;
 | 
			
		||||
 | 
			
		||||
	/* Copy the handle for convenience. */
 | 
			
		||||
	HANDLE ev = dev->ol.hEvent;
 | 
			
		||||
 | 
			
		||||
	if (!dev->read_pending) {
 | 
			
		||||
		/* Start an Overlapped I/O read. */
 | 
			
		||||
		dev->read_pending = TRUE;
 | 
			
		||||
		memset(dev->read_buf, 0, dev->input_report_length);
 | 
			
		||||
		ResetEvent(ev);
 | 
			
		||||
		res = ReadFile(dev->device_handle, dev->read_buf, dev->input_report_length, &bytes_read, &dev->ol);
 | 
			
		||||
		
 | 
			
		||||
		if (!res) {
 | 
			
		||||
			if (GetLastError() != ERROR_IO_PENDING) {
 | 
			
		||||
				/* ReadFile() has failed.
 | 
			
		||||
				   Clean up and return error. */
 | 
			
		||||
				CancelIo(dev->device_handle);
 | 
			
		||||
				dev->read_pending = FALSE;
 | 
			
		||||
				goto end_of_function;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (milliseconds >= 0) {
 | 
			
		||||
		/* See if there is any data yet. */
 | 
			
		||||
		res = WaitForSingleObject(ev, milliseconds);
 | 
			
		||||
		if (res != WAIT_OBJECT_0) {
 | 
			
		||||
			/* There was no data this time. Return zero bytes available,
 | 
			
		||||
			   but leave the Overlapped I/O running. */
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Either WaitForSingleObject() told us that ReadFile has completed, or
 | 
			
		||||
	   we are in non-blocking mode. Get the number of bytes read. The actual
 | 
			
		||||
	   data has been copied to the data[] array which was passed to ReadFile(). */
 | 
			
		||||
	res = GetOverlappedResult(dev->device_handle, &dev->ol, &bytes_read, TRUE/*wait*/);
 | 
			
		||||
	
 | 
			
		||||
	/* Set pending back to false, even if GetOverlappedResult() returned error. */
 | 
			
		||||
	dev->read_pending = FALSE;
 | 
			
		||||
 | 
			
		||||
	if (res && bytes_read > 0) {
 | 
			
		||||
		if (dev->read_buf[0] == 0x0) {
 | 
			
		||||
			/* If report numbers aren't being used, but Windows sticks a report
 | 
			
		||||
			   number (0x0) on the beginning of the report anyway. To make this
 | 
			
		||||
			   work like the other platforms, and to make it work more like the
 | 
			
		||||
			   HID spec, we'll skip over this byte. */
 | 
			
		||||
			bytes_read--;
 | 
			
		||||
			copy_len = length > bytes_read ? bytes_read : length;
 | 
			
		||||
			memcpy(data, dev->read_buf+1, copy_len);
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			/* Copy the whole buffer, report number and all. */
 | 
			
		||||
			copy_len = length > bytes_read ? bytes_read : length;
 | 
			
		||||
			memcpy(data, dev->read_buf, copy_len);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
end_of_function:
 | 
			
		||||
	if (!res) {
 | 
			
		||||
		register_error(dev, "GetOverlappedResult");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	return copy_len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, size_t length)
 | 
			
		||||
{
 | 
			
		||||
	return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *dev, int nonblock)
 | 
			
		||||
{
 | 
			
		||||
	dev->blocking = !nonblock;
 | 
			
		||||
	return 0; /* Success */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)
 | 
			
		||||
{
 | 
			
		||||
	BOOL res = HidD_SetFeature(dev->device_handle, (PVOID)data, length);
 | 
			
		||||
	if (!res) {
 | 
			
		||||
		register_error(dev, "HidD_SetFeature");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return length;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
 | 
			
		||||
{
 | 
			
		||||
	BOOL res;
 | 
			
		||||
#if 0
 | 
			
		||||
	res = HidD_GetFeature(dev->device_handle, data, length);
 | 
			
		||||
	if (!res) {
 | 
			
		||||
		register_error(dev, "HidD_GetFeature");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	return 0; /* HidD_GetFeature() doesn't give us an actual length, unfortunately */
 | 
			
		||||
#else
 | 
			
		||||
	DWORD bytes_returned;
 | 
			
		||||
 | 
			
		||||
	OVERLAPPED ol;
 | 
			
		||||
	memset(&ol, 0, sizeof(ol));
 | 
			
		||||
 | 
			
		||||
	res = DeviceIoControl(dev->device_handle,
 | 
			
		||||
		IOCTL_HID_GET_FEATURE,
 | 
			
		||||
		data, length,
 | 
			
		||||
		data, length,
 | 
			
		||||
		&bytes_returned, &ol);
 | 
			
		||||
 | 
			
		||||
	if (!res) {
 | 
			
		||||
		if (GetLastError() != ERROR_IO_PENDING) {
 | 
			
		||||
			/* DeviceIoControl() failed. Return error. */
 | 
			
		||||
			register_error(dev, "Send Feature Report DeviceIoControl");
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Wait here until the write is done. This makes
 | 
			
		||||
	   hid_get_feature_report() synchronous. */
 | 
			
		||||
	res = GetOverlappedResult(dev->device_handle, &ol, &bytes_returned, TRUE/*wait*/);
 | 
			
		||||
	if (!res) {
 | 
			
		||||
		/* The operation failed. */
 | 
			
		||||
		register_error(dev, "Send Feature Report GetOverLappedResult");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* bytes_returned does not include the first byte which contains the
 | 
			
		||||
	   report ID. The data buffer actually contains one more byte than
 | 
			
		||||
	   bytes_returned. */
 | 
			
		||||
	bytes_returned++;
 | 
			
		||||
 | 
			
		||||
	return bytes_returned;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	if (!dev)
 | 
			
		||||
		return;
 | 
			
		||||
	CancelIo(dev->device_handle);
 | 
			
		||||
	free_hid_device(dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int HID_API_EXPORT_CALL HID_API_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)
 | 
			
		||||
{
 | 
			
		||||
	BOOL res;
 | 
			
		||||
 | 
			
		||||
	res = HidD_GetManufacturerString(dev->device_handle, string, sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS));
 | 
			
		||||
	if (!res) {
 | 
			
		||||
		register_error(dev, "HidD_GetManufacturerString");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int HID_API_EXPORT_CALL HID_API_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)
 | 
			
		||||
{
 | 
			
		||||
	BOOL res;
 | 
			
		||||
 | 
			
		||||
	res = HidD_GetProductString(dev->device_handle, string, sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS));
 | 
			
		||||
	if (!res) {
 | 
			
		||||
		register_error(dev, "HidD_GetProductString");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int HID_API_EXPORT_CALL HID_API_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)
 | 
			
		||||
{
 | 
			
		||||
	BOOL res;
 | 
			
		||||
 | 
			
		||||
	res = HidD_GetSerialNumberString(dev->device_handle, string, sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS));
 | 
			
		||||
	if (!res) {
 | 
			
		||||
		register_error(dev, "HidD_GetSerialNumberString");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int HID_API_EXPORT_CALL HID_API_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)
 | 
			
		||||
{
 | 
			
		||||
	BOOL res;
 | 
			
		||||
 | 
			
		||||
	res = HidD_GetIndexedString(dev->device_handle, string_index, string, sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS));
 | 
			
		||||
	if (!res) {
 | 
			
		||||
		register_error(dev, "HidD_GetIndexedString");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
HID_API_EXPORT const wchar_t * HID_API_CALL  hid_error(hid_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	return (wchar_t*)dev->last_error_str;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*#define PICPGM*/
 | 
			
		||||
/*#define S11*/
 | 
			
		||||
#define P32
 | 
			
		||||
#ifdef S11 
 | 
			
		||||
  unsigned short VendorID = 0xa0a0;
 | 
			
		||||
	unsigned short ProductID = 0x0001;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef P32
 | 
			
		||||
  unsigned short VendorID = 0x04d8;
 | 
			
		||||
	unsigned short ProductID = 0x3f;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef PICPGM
 | 
			
		||||
  unsigned short VendorID = 0x04d8;
 | 
			
		||||
  unsigned short ProductID = 0x0033;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
int __cdecl main(int argc, char* argv[])
 | 
			
		||||
{
 | 
			
		||||
	int res;
 | 
			
		||||
	unsigned char buf[65];
 | 
			
		||||
 | 
			
		||||
	UNREFERENCED_PARAMETER(argc);
 | 
			
		||||
	UNREFERENCED_PARAMETER(argv);
 | 
			
		||||
 | 
			
		||||
	/* Set up the command buffer. */
 | 
			
		||||
	memset(buf,0x00,sizeof(buf));
 | 
			
		||||
	buf[0] = 0;
 | 
			
		||||
	buf[1] = 0x81;
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	/* Open the device. */
 | 
			
		||||
	int handle = open(VendorID, ProductID, L"12345");
 | 
			
		||||
	if (handle < 0)
 | 
			
		||||
		printf("unable to open device\n");
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/* Toggle LED (cmd 0x80) */
 | 
			
		||||
	buf[1] = 0x80;
 | 
			
		||||
	res = write(handle, buf, 65);
 | 
			
		||||
	if (res < 0)
 | 
			
		||||
		printf("Unable to write()\n");
 | 
			
		||||
 | 
			
		||||
	/* Request state (cmd 0x81) */
 | 
			
		||||
	buf[1] = 0x81;
 | 
			
		||||
	write(handle, buf, 65);
 | 
			
		||||
	if (res < 0)
 | 
			
		||||
		printf("Unable to write() (2)\n");
 | 
			
		||||
 | 
			
		||||
	/* Read requested state */
 | 
			
		||||
	read(handle, buf, 65);
 | 
			
		||||
	if (res < 0)
 | 
			
		||||
		printf("Unable to read()\n");
 | 
			
		||||
 | 
			
		||||
	/* Print out the returned buffer. */
 | 
			
		||||
	for (int i = 0; i < 4; i++)
 | 
			
		||||
		printf("buf[%d]: %d\n", i, buf[i]);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
} /* extern "C" */
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -32,4 +32,13 @@
 | 
			
		|||
#define ENABLE_NONCUSTOM_DATA_VIEW_RENDERING (0 && ENABLE_1_42_0_ALPHA1)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//====================
 | 
			
		||||
// 2.0.0.alpha1 techs
 | 
			
		||||
//====================
 | 
			
		||||
#define ENABLE_2_0_0_ALPHA1 1
 | 
			
		||||
 | 
			
		||||
// Enabled 3Dconnexion devices
 | 
			
		||||
#define ENABLE_3DCONNEXION_DEVICES (1 && ENABLE_2_0_0_ALPHA1)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif // _technologies_h_
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -136,6 +136,8 @@ set(SLIC3R_GUI_SOURCES
 | 
			
		|||
    GUI/ProgressStatusBar.cpp
 | 
			
		||||
    GUI/PrintHostDialogs.cpp
 | 
			
		||||
    GUI/PrintHostDialogs.hpp
 | 
			
		||||
    GUI/Mouse3DController.cpp
 | 
			
		||||
    GUI/Mouse3DController.hpp
 | 
			
		||||
    Utils/Http.cpp
 | 
			
		||||
    Utils/Http.hpp
 | 
			
		||||
    Utils/FixModelByWin10.cpp
 | 
			
		||||
| 
						 | 
				
			
			@ -167,7 +169,7 @@ add_library(libslic3r_gui STATIC ${SLIC3R_GUI_SOURCES})
 | 
			
		|||
 | 
			
		||||
encoding_check(libslic3r_gui)
 | 
			
		||||
 | 
			
		||||
target_link_libraries(libslic3r_gui libslic3r avrdude cereal imgui ${GLEW_LIBRARIES})
 | 
			
		||||
target_link_libraries(libslic3r_gui libslic3r avrdude cereal imgui ${GLEW_LIBRARIES} ${HIDAPI_LIBRARIES})
 | 
			
		||||
if (SLIC3R_PCH AND NOT SLIC3R_SYNTAXONLY)
 | 
			
		||||
    add_precompiled_header(libslic3r_gui pchheader.hpp FORCEINCLUDE)
 | 
			
		||||
endif ()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,6 +22,9 @@
 | 
			
		|||
#include "GUI_App.hpp"
 | 
			
		||||
#include "GUI_ObjectList.hpp"
 | 
			
		||||
#include "GUI_ObjectManipulation.hpp"
 | 
			
		||||
#if ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
#include "Mouse3DController.hpp"
 | 
			
		||||
#endif // ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
#include "I18N.hpp"
 | 
			
		||||
 | 
			
		||||
#if ENABLE_RETINA_GL
 | 
			
		||||
| 
						 | 
				
			
			@ -2305,14 +2308,28 @@ void GLCanvas3D::on_idle(wxIdleEvent& evt)
 | 
			
		|||
    m_dirty |= m_main_toolbar.update_items_state();
 | 
			
		||||
    m_dirty |= m_undoredo_toolbar.update_items_state();
 | 
			
		||||
    m_dirty |= m_view_toolbar.update_items_state();
 | 
			
		||||
#if ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
    bool mouse3d_controller_applied = wxGetApp().plater()->get_mouse3d_controller().apply();
 | 
			
		||||
    m_dirty |= mouse3d_controller_applied;
 | 
			
		||||
#endif // ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
 | 
			
		||||
    if (!m_dirty)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    _refresh_if_shown_on_screen();
 | 
			
		||||
 | 
			
		||||
#if ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
    if (m_keep_dirty || wxGetApp().plater()->get_mouse3d_controller().is_device_connected())
 | 
			
		||||
    {
 | 
			
		||||
        m_dirty = true;
 | 
			
		||||
        evt.RequestMore();
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
        m_dirty = false;
 | 
			
		||||
#else
 | 
			
		||||
    if (m_keep_dirty)
 | 
			
		||||
        m_dirty = true;
 | 
			
		||||
#endif // ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLCanvas3D::on_char(wxKeyEvent& evt)
 | 
			
		||||
| 
						 | 
				
			
			@ -2531,6 +2548,13 @@ void GLCanvas3D::on_key(wxKeyEvent& evt)
 | 
			
		|||
 | 
			
		||||
void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt)
 | 
			
		||||
{
 | 
			
		||||
#if ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
    // try to filter out events coming from mouse 3d controller
 | 
			
		||||
    const Mouse3DController& controller = wxGetApp().plater()->get_mouse3d_controller();
 | 
			
		||||
    if (controller.has_rotation() || controller.has_translation())
 | 
			
		||||
        return;
 | 
			
		||||
#endif // ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
 | 
			
		||||
    if (!m_initialized)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3815,7 +3839,9 @@ void GLCanvas3D::_resize(unsigned int w, unsigned int h)
 | 
			
		|||
    // updates camera
 | 
			
		||||
    m_camera.apply_viewport(0, 0, w, h);
 | 
			
		||||
 | 
			
		||||
#if !ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
    m_dirty = false;
 | 
			
		||||
#endif // !ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BoundingBoxf3 GLCanvas3D::_max_bounding_box(bool include_gizmos, bool include_bed_model) const
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -486,6 +486,9 @@ public:
 | 
			
		|||
    void set_color_by(const std::string& value);
 | 
			
		||||
 | 
			
		||||
    const Camera& get_camera() const { return m_camera; }
 | 
			
		||||
#if ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
    Camera& get_camera() { return m_camera; }
 | 
			
		||||
#endif // ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
 | 
			
		||||
    BoundingBoxf3 volumes_bounding_box() const;
 | 
			
		||||
    BoundingBoxf3 scene_bounding_box() const;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,6 +24,9 @@
 | 
			
		|||
#include "PrintHostDialogs.hpp"
 | 
			
		||||
#include "wxExtensions.hpp"
 | 
			
		||||
#include "GUI_ObjectList.hpp"
 | 
			
		||||
#if ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
#include "Mouse3DController.hpp"
 | 
			
		||||
#endif // ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
#include "I18N.hpp"
 | 
			
		||||
 | 
			
		||||
#include <fstream>
 | 
			
		||||
| 
						 | 
				
			
			@ -108,6 +111,10 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
 | 
			
		|||
        }
 | 
			
		||||
        
 | 
			
		||||
        if(m_plater) m_plater->stop_jobs();
 | 
			
		||||
#if ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
        if (m_plater != nullptr)
 | 
			
		||||
            m_plater->get_mouse3d_controller().set_canvas(nullptr);
 | 
			
		||||
#endif // ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
 | 
			
		||||
        // Weird things happen as the Paint messages are floating around the windows being destructed.
 | 
			
		||||
        // Avoid the Paint messages by hiding the main window.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										332
									
								
								src/slic3r/GUI/Mouse3DController.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										332
									
								
								src/slic3r/GUI/Mouse3DController.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,332 @@
 | 
			
		|||
#include "libslic3r/libslic3r.h"
 | 
			
		||||
#include "Mouse3DController.hpp"
 | 
			
		||||
 | 
			
		||||
#if ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
 | 
			
		||||
#include "GLCanvas3D.hpp"
 | 
			
		||||
#include "GUI_App.hpp"
 | 
			
		||||
#include "PresetBundle.hpp"
 | 
			
		||||
 | 
			
		||||
#include <wx/glcanvas.h>
 | 
			
		||||
 | 
			
		||||
static const std::vector<int> _3DCONNEXION_VENDORS =
 | 
			
		||||
{
 | 
			
		||||
    0x046d,  // LOGITECH = 1133 // Logitech (3Dconnexion is made by Logitech)
 | 
			
		||||
    0x256F   // 3DCONNECTION = 9583 // 3Dconnexion
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const std::vector<int> _3DCONNEXION_DEVICES =
 | 
			
		||||
{
 | 
			
		||||
    0xC623, // TRAVELER = 50723
 | 
			
		||||
    0xC626, // NAVIGATOR = 50726
 | 
			
		||||
    0xc628,	// NAVIGATOR_FOR_NOTEBOOKS = 50728
 | 
			
		||||
    0xc627, // SPACEEXPLORER = 50727
 | 
			
		||||
    0xC603, // SPACEMOUSE = 50691
 | 
			
		||||
    0xC62B, // SPACEMOUSEPRO = 50731
 | 
			
		||||
    0xc621, // SPACEBALL5000 = 50721
 | 
			
		||||
    0xc625, // SPACEPILOT = 50725
 | 
			
		||||
    0xc629  // SPACEPILOTPRO = 50729
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const unsigned int _3DCONNEXION_BUTTONS_COUNT = 2;
 | 
			
		||||
 | 
			
		||||
namespace Slic3r {
 | 
			
		||||
namespace GUI {
 | 
			
		||||
    
 | 
			
		||||
const double Mouse3DController::State::DefaultTranslationScale = 2.5;
 | 
			
		||||
const float Mouse3DController::State::DefaultRotationScale = 1.0;
 | 
			
		||||
 | 
			
		||||
Mouse3DController::State::State()
 | 
			
		||||
    : m_translation(Vec3d::Zero())
 | 
			
		||||
    , m_rotation(Vec3f::Zero())
 | 
			
		||||
    , m_buttons(_3DCONNEXION_BUTTONS_COUNT, false)
 | 
			
		||||
    , m_translation_scale(DefaultTranslationScale)
 | 
			
		||||
    , m_rotation_scale(DefaultRotationScale)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Mouse3DController::State::set_translation(const Vec3d& translation)
 | 
			
		||||
{
 | 
			
		||||
    std::lock_guard<std::mutex> lock(m_mutex);
 | 
			
		||||
    m_translation = translation;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Mouse3DController::State::set_rotation(const Vec3f& rotation)
 | 
			
		||||
{
 | 
			
		||||
    std::lock_guard<std::mutex> lock(m_mutex);
 | 
			
		||||
    m_rotation = rotation;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Mouse3DController::State::set_button(unsigned int id)
 | 
			
		||||
{
 | 
			
		||||
    std::lock_guard<std::mutex> lock(m_mutex);
 | 
			
		||||
    if (id < _3DCONNEXION_BUTTONS_COUNT)
 | 
			
		||||
        m_buttons[id] = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Mouse3DController::State::has_translation() const
 | 
			
		||||
{
 | 
			
		||||
    std::lock_guard<std::mutex> lock(m_mutex);
 | 
			
		||||
    return !m_translation.isApprox(Vec3d::Zero());
 | 
			
		||||
}
 | 
			
		||||
bool Mouse3DController::State::has_rotation() const
 | 
			
		||||
{
 | 
			
		||||
    std::lock_guard<std::mutex> lock(m_mutex);
 | 
			
		||||
    return !m_rotation.isApprox(Vec3f::Zero());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Mouse3DController::State::has_any_button() const
 | 
			
		||||
{
 | 
			
		||||
    std::lock_guard<std::mutex> lock(m_mutex);
 | 
			
		||||
    for (int i = 0; i < _3DCONNEXION_BUTTONS_COUNT; ++i)
 | 
			
		||||
    {
 | 
			
		||||
        if (m_buttons[i])
 | 
			
		||||
            return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Mouse3DController::State::apply(GLCanvas3D& canvas)
 | 
			
		||||
{
 | 
			
		||||
    if (!wxGetApp().IsActive())
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    bool ret = false;
 | 
			
		||||
    Camera& camera = canvas.get_camera();
 | 
			
		||||
 | 
			
		||||
    if (has_translation())
 | 
			
		||||
    {
 | 
			
		||||
        camera.set_target(camera.get_target() + m_translation_scale * (m_translation(0) * camera.get_dir_right() + m_translation(1) * camera.get_dir_forward() + m_translation(2) * camera.get_dir_up()));
 | 
			
		||||
        m_translation = Vec3d::Zero();
 | 
			
		||||
        ret = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (has_rotation())
 | 
			
		||||
    {
 | 
			
		||||
        float theta = m_rotation_scale * m_rotation(0);
 | 
			
		||||
        float phi = m_rotation_scale * m_rotation(2);
 | 
			
		||||
        float sign = camera.inverted_phi ? -1.0f : 1.0f;
 | 
			
		||||
        camera.phi += sign * phi;
 | 
			
		||||
        camera.set_theta(camera.get_theta() + theta, wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA);
 | 
			
		||||
        m_rotation = Vec3f::Zero();
 | 
			
		||||
        ret = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (has_any_button())
 | 
			
		||||
    {
 | 
			
		||||
        if (m_buttons[0])
 | 
			
		||||
            canvas.set_camera_zoom(1.0);
 | 
			
		||||
        else if (m_buttons[1])
 | 
			
		||||
            canvas.set_camera_zoom(-1.0);
 | 
			
		||||
 | 
			
		||||
        m_buttons = std::vector<bool>(_3DCONNEXION_BUTTONS_COUNT, false);
 | 
			
		||||
        ret = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Mouse3DController::Mouse3DController()
 | 
			
		||||
    : m_initialized(false)
 | 
			
		||||
    , m_canvas(nullptr)
 | 
			
		||||
    , m_device(nullptr)
 | 
			
		||||
    , m_running(false)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Mouse3DController::init()
 | 
			
		||||
{
 | 
			
		||||
    if (m_initialized)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    // Initialize the hidapi library
 | 
			
		||||
    int res = hid_init();
 | 
			
		||||
    if (res != 0)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    m_initialized = true;
 | 
			
		||||
 | 
			
		||||
    connect_device();
 | 
			
		||||
    start();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Mouse3DController::shutdown()
 | 
			
		||||
{
 | 
			
		||||
    if (!m_initialized)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    stop();
 | 
			
		||||
 | 
			
		||||
    if (m_thread.joinable())
 | 
			
		||||
        m_thread.join();
 | 
			
		||||
 | 
			
		||||
    disconnect_device();
 | 
			
		||||
 | 
			
		||||
    // Finalize the hidapi library
 | 
			
		||||
    hid_exit();
 | 
			
		||||
    m_initialized = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Mouse3DController::connect_device()
 | 
			
		||||
{
 | 
			
		||||
    if (m_device != nullptr)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    // Enumerates devices
 | 
			
		||||
    hid_device_info* devices = hid_enumerate(0, 0);
 | 
			
		||||
    if (devices == nullptr)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    // Searches for 1st connected 3Dconnexion device
 | 
			
		||||
    unsigned short vendor_id = 0;
 | 
			
		||||
    unsigned short product_id = 0;
 | 
			
		||||
 | 
			
		||||
    hid_device_info* current = devices;
 | 
			
		||||
    while (current != nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        for (size_t i = 0; i < _3DCONNEXION_VENDORS.size(); ++i)
 | 
			
		||||
        {
 | 
			
		||||
            if (_3DCONNEXION_VENDORS[i] == current->vendor_id)
 | 
			
		||||
            {
 | 
			
		||||
                vendor_id = current->vendor_id;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (vendor_id != 0)
 | 
			
		||||
        {
 | 
			
		||||
            for (size_t i = 0; i < _3DCONNEXION_DEVICES.size(); ++i)
 | 
			
		||||
            {
 | 
			
		||||
                if (_3DCONNEXION_DEVICES[i] == current->product_id)
 | 
			
		||||
                {
 | 
			
		||||
                    product_id = current->product_id;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (product_id == 0)
 | 
			
		||||
                vendor_id = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (vendor_id != 0)
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        current = current->next;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Free enumerated devices
 | 
			
		||||
    hid_free_enumeration(devices);
 | 
			
		||||
 | 
			
		||||
    if (vendor_id == 0)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    // Open the 3Dconnexion device using the VID, PID
 | 
			
		||||
    m_device = hid_open(vendor_id, product_id, nullptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Mouse3DController::disconnect_device()
 | 
			
		||||
{
 | 
			
		||||
    if (m_device == nullptr)
 | 
			
		||||
        return;
 | 
			
		||||
    
 | 
			
		||||
    // Close the 3Dconnexion device
 | 
			
		||||
    hid_close(m_device);
 | 
			
		||||
    m_device = nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Mouse3DController::start()
 | 
			
		||||
{
 | 
			
		||||
    if ((m_device == nullptr) || m_running)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    m_thread = std::thread(&Mouse3DController::run, this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Mouse3DController::run()
 | 
			
		||||
{
 | 
			
		||||
    m_running = true;
 | 
			
		||||
    while (m_running)
 | 
			
		||||
    {
 | 
			
		||||
        collect_input();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double convert_input(int first, unsigned char val)
 | 
			
		||||
{
 | 
			
		||||
    int ret = 0;
 | 
			
		||||
 | 
			
		||||
    switch (val)
 | 
			
		||||
    {
 | 
			
		||||
    case 0: { ret = first; break; }
 | 
			
		||||
    case 1: { ret = first + 255; break; }
 | 
			
		||||
    case 254: { ret = -511 + first; break; }
 | 
			
		||||
    case 255: { ret = -255 + first; break; }
 | 
			
		||||
    default: { break; }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return (double)ret / 349.0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Mouse3DController::collect_input()
 | 
			
		||||
{
 | 
			
		||||
    // Read data from device
 | 
			
		||||
    enum EDataType
 | 
			
		||||
    {
 | 
			
		||||
        Translation = 1,
 | 
			
		||||
        Rotation,
 | 
			
		||||
        Button
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    unsigned char retrieved_data[8] = { 0 };
 | 
			
		||||
    int res = hid_read_timeout(m_device, retrieved_data, sizeof(retrieved_data), 100);
 | 
			
		||||
    if (res < 0)
 | 
			
		||||
    {
 | 
			
		||||
        // An error occourred (device detached from pc ?)
 | 
			
		||||
        stop();
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (res > 0)
 | 
			
		||||
    {
 | 
			
		||||
        switch (retrieved_data[0])
 | 
			
		||||
        {
 | 
			
		||||
        case Translation:
 | 
			
		||||
            {
 | 
			
		||||
                Vec3d translation(-convert_input((int)retrieved_data[1], retrieved_data[2]),
 | 
			
		||||
                        convert_input((int)retrieved_data[3], retrieved_data[4]),
 | 
			
		||||
                        convert_input((int)retrieved_data[5], retrieved_data[6]));
 | 
			
		||||
                if (!translation.isApprox(Vec3d::Zero()))
 | 
			
		||||
                    m_state.set_translation(translation);
 | 
			
		||||
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        case Rotation:
 | 
			
		||||
            {
 | 
			
		||||
                Vec3f rotation(-(float)convert_input((int)retrieved_data[1], retrieved_data[2]),
 | 
			
		||||
                    (float)convert_input((int)retrieved_data[3], retrieved_data[4]),
 | 
			
		||||
                    -(float)convert_input((int)retrieved_data[5], retrieved_data[6]));
 | 
			
		||||
                if (!rotation.isApprox(Vec3f::Zero()))
 | 
			
		||||
                    m_state.set_rotation(rotation);
 | 
			
		||||
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        case Button:
 | 
			
		||||
            {
 | 
			
		||||
                for (unsigned int i = 0; i < _3DCONNEXION_BUTTONS_COUNT; ++i)
 | 
			
		||||
                {
 | 
			
		||||
                    if (retrieved_data[1] & (0x1 << i))
 | 
			
		||||
                        m_state.set_button(i);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        default:
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace GUI
 | 
			
		||||
} // namespace Slic3r
 | 
			
		||||
 | 
			
		||||
#endif // ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
							
								
								
									
										96
									
								
								src/slic3r/GUI/Mouse3DController.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								src/slic3r/GUI/Mouse3DController.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,96 @@
 | 
			
		|||
#ifndef slic3r_Mouse3DController_hpp_
 | 
			
		||||
#define slic3r_Mouse3DController_hpp_
 | 
			
		||||
 | 
			
		||||
#if ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
 | 
			
		||||
#include "hidapi/hidapi.h"
 | 
			
		||||
#include <thread>
 | 
			
		||||
#include <mutex>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
namespace Slic3r {
 | 
			
		||||
namespace GUI {
 | 
			
		||||
 | 
			
		||||
class GLCanvas3D;
 | 
			
		||||
 | 
			
		||||
class Mouse3DController
 | 
			
		||||
{
 | 
			
		||||
    class State
 | 
			
		||||
    {
 | 
			
		||||
        static const double DefaultTranslationScale;
 | 
			
		||||
        static const float DefaultRotationScale;
 | 
			
		||||
 | 
			
		||||
        mutable std::mutex m_mutex;
 | 
			
		||||
 | 
			
		||||
        Vec3d m_translation;
 | 
			
		||||
        Vec3f m_rotation;
 | 
			
		||||
        std::vector<bool> m_buttons;
 | 
			
		||||
 | 
			
		||||
        double m_translation_scale;
 | 
			
		||||
        float m_rotation_scale;
 | 
			
		||||
 | 
			
		||||
    public:
 | 
			
		||||
        State();
 | 
			
		||||
 | 
			
		||||
        void set_translation(const Vec3d& translation);
 | 
			
		||||
        void set_rotation(const Vec3f& rotation);
 | 
			
		||||
        void set_button(unsigned int id);
 | 
			
		||||
 | 
			
		||||
        bool has_translation() const;
 | 
			
		||||
        bool has_rotation() const;
 | 
			
		||||
        bool has_any_button() const;
 | 
			
		||||
 | 
			
		||||
        // return true if any change to the camera took place
 | 
			
		||||
        bool apply(GLCanvas3D& canvas);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    bool m_initialized;
 | 
			
		||||
    State m_state;
 | 
			
		||||
    std::thread m_thread;
 | 
			
		||||
    GLCanvas3D* m_canvas;
 | 
			
		||||
    std::mutex m_mutex;
 | 
			
		||||
    hid_device* m_device;
 | 
			
		||||
    bool m_running;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    Mouse3DController();
 | 
			
		||||
 | 
			
		||||
    void init();
 | 
			
		||||
    void shutdown();
 | 
			
		||||
 | 
			
		||||
    bool is_device_connected() const { return m_device != nullptr; }
 | 
			
		||||
    bool is_running() const { return m_running; }
 | 
			
		||||
 | 
			
		||||
    void set_canvas(GLCanvas3D* canvas)
 | 
			
		||||
    {
 | 
			
		||||
        std::lock_guard<std::mutex> lock(m_mutex);
 | 
			
		||||
        m_canvas = canvas;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool has_translation() const { return m_state.has_translation(); }
 | 
			
		||||
    bool has_rotation() const { return m_state.has_rotation(); }
 | 
			
		||||
    bool has_any_button() const { return m_state.has_any_button(); }
 | 
			
		||||
 | 
			
		||||
    bool apply()
 | 
			
		||||
    {
 | 
			
		||||
        std::lock_guard<std::mutex> lock(m_mutex);
 | 
			
		||||
        return (m_canvas != nullptr) ? m_state.apply(*m_canvas) : false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void connect_device();
 | 
			
		||||
    void disconnect_device();
 | 
			
		||||
    void start();
 | 
			
		||||
    void stop() { m_running = false; }
 | 
			
		||||
 | 
			
		||||
    void run();
 | 
			
		||||
    void collect_input();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace GUI
 | 
			
		||||
} // namespace Slic3r
 | 
			
		||||
 | 
			
		||||
#endif // ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
 | 
			
		||||
#endif // slic3r_Mouse3DController_hpp_
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -61,6 +61,9 @@
 | 
			
		|||
#include "GUI_Preview.hpp"
 | 
			
		||||
#include "3DBed.hpp"
 | 
			
		||||
#include "Camera.hpp"
 | 
			
		||||
#if ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
#include "Mouse3DController.hpp"
 | 
			
		||||
#endif // ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
#include "Tab.hpp"
 | 
			
		||||
#include "PresetBundle.hpp"
 | 
			
		||||
#include "BackgroundSlicingProcess.hpp"
 | 
			
		||||
| 
						 | 
				
			
			@ -1367,6 +1370,9 @@ struct Plater::priv
 | 
			
		|||
    Sidebar *sidebar;
 | 
			
		||||
    Bed3D bed;
 | 
			
		||||
    Camera camera;
 | 
			
		||||
#if ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
    Mouse3DController mouse3d_controller;
 | 
			
		||||
#endif // ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
    View3D* view3D;
 | 
			
		||||
    GLToolbar view_toolbar;
 | 
			
		||||
    Preview *preview;
 | 
			
		||||
| 
						 | 
				
			
			@ -2094,12 +2100,20 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
 | 
			
		|||
    // updates camera type from .ini file
 | 
			
		||||
    camera.set_type(get_config("use_perspective_camera"));
 | 
			
		||||
 | 
			
		||||
#if ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
    mouse3d_controller.init();
 | 
			
		||||
#endif // ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
 | 
			
		||||
    // Initialize the Undo / Redo stack with a first snapshot.
 | 
			
		||||
    this->take_snapshot(_(L("New Project")));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Plater::priv::~priv()
 | 
			
		||||
{
 | 
			
		||||
#if ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
    mouse3d_controller.shutdown();
 | 
			
		||||
#endif // ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
 | 
			
		||||
    if (config != nullptr)
 | 
			
		||||
        delete config;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -3248,6 +3262,11 @@ void Plater::priv::set_current_panel(wxPanel* panel)
 | 
			
		|||
            } else
 | 
			
		||||
                view3D->reload_scene(true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
#if ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
        mouse3d_controller.set_canvas(view3D->get_canvas3d());
 | 
			
		||||
#endif // ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
 | 
			
		||||
        // sets the canvas as dirty to force a render at the 1st idle event (wxWidgets IsShownOnScreen() is buggy and cannot be used reliably)
 | 
			
		||||
        view3D->set_as_dirty();
 | 
			
		||||
        view_toolbar.select_item("3D");
 | 
			
		||||
| 
						 | 
				
			
			@ -3262,6 +3281,11 @@ void Plater::priv::set_current_panel(wxPanel* panel)
 | 
			
		|||
            this->q->reslice();
 | 
			
		||||
        // keeps current gcode preview, if any
 | 
			
		||||
        preview->reload_print(true);
 | 
			
		||||
 | 
			
		||||
#if ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
        mouse3d_controller.set_canvas(preview->get_canvas3d());
 | 
			
		||||
#endif // ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
 | 
			
		||||
        preview->set_canvas_as_dirty();
 | 
			
		||||
        view_toolbar.select_item("Preview");
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -5020,6 +5044,18 @@ const Camera& Plater::get_camera() const
 | 
			
		|||
    return p->camera;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
const Mouse3DController& Plater::get_mouse3d_controller() const
 | 
			
		||||
{
 | 
			
		||||
    return p->mouse3d_controller;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Mouse3DController& Plater::get_mouse3d_controller()
 | 
			
		||||
{
 | 
			
		||||
    return p->mouse3d_controller;
 | 
			
		||||
}
 | 
			
		||||
#endif // ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
 | 
			
		||||
bool Plater::can_delete() const { return p->can_delete(); }
 | 
			
		||||
bool Plater::can_delete_all() const { return p->can_delete_all(); }
 | 
			
		||||
bool Plater::can_increase_instances() const { return p->can_increase_instances(); }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -41,6 +41,7 @@ class ObjectSettings;
 | 
			
		|||
class ObjectLayers;
 | 
			
		||||
class ObjectList;
 | 
			
		||||
class GLCanvas3D;
 | 
			
		||||
class Mouse3DController;
 | 
			
		||||
 | 
			
		||||
using t_optgroups = std::vector <std::shared_ptr<ConfigOptionsGroup>>;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -251,6 +252,10 @@ public:
 | 
			
		|||
    void msw_rescale();
 | 
			
		||||
 | 
			
		||||
    const Camera& get_camera() const;
 | 
			
		||||
#if ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
    const Mouse3DController& get_mouse3d_controller() const;
 | 
			
		||||
    Mouse3DController& get_mouse3d_controller();
 | 
			
		||||
#endif // ENABLE_3DCONNEXION_DEVICES
 | 
			
		||||
 | 
			
		||||
	// ROII wrapper for suppressing the Undo / Redo snapshot to be taken.
 | 
			
		||||
	class SuppressSnapshots
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue