├── AddIns ├── spconvd │ ├── .gitignore │ ├── Makefile │ ├── readme.txt │ └── main.c ├── SpaceMouse │ ├── SpaceMouse.manifest │ └── SpaceMouse.py └── README.md ├── siappdll.dll ├── siappdll ├── src │ ├── log.cpp │ ├── config.h │ ├── sock.h │ ├── sock_ll.h │ ├── log.h │ ├── siappdll_impl.h │ ├── sock.cpp │ ├── sock_ll.asm │ ├── siappdll.h │ ├── syncapi.h │ ├── sidef.h │ ├── syncapi.cpp │ └── siappdll.cpp ├── x64 │ └── Release │ │ └── siappdll.dll ├── packages.config ├── siappdll.sln ├── siappdll.def ├── siappdll.vcxproj.filters ├── .gitignore ├── siappdll.vcproj └── siappdll.vcxproj ├── win_dll_test ├── siappdll.dll └── jet.exe └── README.md /AddIns/spconvd/.gitignore: -------------------------------------------------------------------------------- 1 | spconvd 2 | -------------------------------------------------------------------------------- /siappdll.dll: -------------------------------------------------------------------------------- 1 | siappdll/x64/Release/siappdll.dll -------------------------------------------------------------------------------- /siappdll/src/log.cpp: -------------------------------------------------------------------------------- 1 | #include "log.h" 2 | 3 | Logger logger; -------------------------------------------------------------------------------- /win_dll_test/siappdll.dll: -------------------------------------------------------------------------------- 1 | ../siappdll/x64/Release/siappdll.dll -------------------------------------------------------------------------------- /AddIns/spconvd/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | gcc main.c -o spconvd 3 | install: 4 | cp spconvd ~/.local/bin/ 5 | -------------------------------------------------------------------------------- /win_dll_test/jet.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DD1984/SpaceMouse_Fusion360_Wine/HEAD/win_dll_test/jet.exe -------------------------------------------------------------------------------- /AddIns/spconvd/readme.txt: -------------------------------------------------------------------------------- 1 | build: make && make install 2 | spconvd will be installed to ~/.local/bin/ 3 | 4 | -------------------------------------------------------------------------------- /siappdll/x64/Release/siappdll.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DD1984/SpaceMouse_Fusion360_Wine/HEAD/siappdll/x64/Release/siappdll.dll -------------------------------------------------------------------------------- /siappdll/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /siappdll/src/config.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_H_ 2 | #define CONFIG_H_ 3 | 4 | #define VER_MAJOR 17 5 | #define VER_MINOR 2 6 | #define VER_BUILD 14205 7 | #define VER_STR "fake 3dxsrv/siappdll" 8 | 9 | #endif /* CONFIG_H_ */ -------------------------------------------------------------------------------- /AddIns/SpaceMouse/SpaceMouse.manifest: -------------------------------------------------------------------------------- 1 | { 2 | "autodeskProduct": "Fusion360", 3 | "type": "addin", 4 | "id": "6b509eec-34ca-4044-875d-cfb30563b658", 5 | "author": "", 6 | "description": { 7 | "": "Creates a spur gear component." 8 | }, 9 | "version": "", 10 | "runOnStartup": false, 11 | "supportedOS": "windows|mac", 12 | "editEnabled": true 13 | } -------------------------------------------------------------------------------- /siappdll/src/sock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define SOCK_FILE "/var/run/spnav.sock" 4 | 5 | #define AF_UNIX 1 6 | #define SOCK_STREAM 1 7 | 8 | struct sockaddr_un { 9 | unsigned short sun_family; /* AF_UNIX */ 10 | char sun_path[108]; /* pathname */ 11 | }; 12 | 13 | int sock_connect(const char* sock_file); 14 | int sock_read(int fd, char* buf, size_t count); 15 | void sock_close(int fd); -------------------------------------------------------------------------------- /siappdll/src/sock_ll.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | extern "C" int __fastcall l_open(const char* filename, int flags, int mode); 4 | extern "C" int __fastcall l_read(int fd, char* buf, unsigned int count); 5 | extern "C" int __fastcall l_close(int fd); 6 | extern "C" int __fastcall l_socket(int domain, int type, int protocol); 7 | extern "C" int __fastcall l_connect(int sockfd, const struct sockaddr* addr, unsigned int addrlen); 8 | 9 | extern "C" int __fastcall l_socket_int80h(int domain, int type, int protocol); 10 | extern "C" int __fastcall l_connect_int80h(int sockfd, const struct sockaddr* addr, unsigned int addrlen); 11 | extern "C" int __fastcall l_read_int80h(int fd, char* buf, unsigned int count); 12 | extern "C" int __fastcall l_close_int80h(int fd); 13 | -------------------------------------------------------------------------------- /siappdll/src/log.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | enum class DbgType { 10 | INFO_T = 0, 11 | ERROR_T, 12 | TRACE_T, 13 | }; 14 | 15 | class Logger 16 | { 17 | using Stream = std::ostringstream; 18 | using Buffer_p = std::unique_ptr>; 19 | 20 | public: 21 | void log(const std::string& cmd) { 22 | std::cout << cmd << std::endl; 23 | } 24 | 25 | Buffer_p log(DbgType l) { 26 | return Buffer_p(new Stream, [&, this, l](Stream* st) { 27 | if (l <= dbgLevel) 28 | log(st->str()); 29 | }); 30 | } 31 | 32 | private: 33 | DbgType dbgLevel = DbgType::ERROR_T; 34 | }; 35 | 36 | extern Logger logger; 37 | 38 | #define LOG(x) *(logger.log(DbgType:: ## x ## _T)) << "[*** SPMOUSE ***] " << #x << " " 39 | -------------------------------------------------------------------------------- /siappdll/src/siappdll_impl.h: -------------------------------------------------------------------------------- 1 | /* 2 | SpaceNavigatorEmulator - 3dconnexion-compatible siappdll.dll replacement 3 | Copyright (C) 2014 John Tsiombikas 4 | Copyright (C) 2015 Luke Nuttall 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | #pragma once 20 | #ifndef __SIAPPDLL_IMPL_H__ 21 | #define __SIAPPDLL_IMPL_H__ 22 | 23 | #include 24 | 25 | extern "C" { 26 | 27 | struct SiHdl { 28 | SiOpenData opendata; 29 | // SpaceNavigatorEmulator::SpaceNavConnector* connector; 30 | }; 31 | 32 | unsigned int space_ware_message; 33 | 34 | bool initialised = false; 35 | } 36 | #endif 37 | -------------------------------------------------------------------------------- /siappdll/siappdll.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.1.32228.430 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "siappdll", "siappdll.vcxproj", "{E3AE0F7F-2BBD-4563-AE22-1A92E11630F0}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Profile|x64 = Profile|x64 12 | Release|x64 = Release|x64 13 | EndGlobalSection 14 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 15 | {E3AE0F7F-2BBD-4563-AE22-1A92E11630F0}.Debug|x64.ActiveCfg = Debug|x64 16 | {E3AE0F7F-2BBD-4563-AE22-1A92E11630F0}.Debug|x64.Build.0 = Debug|x64 17 | {E3AE0F7F-2BBD-4563-AE22-1A92E11630F0}.Profile|x64.ActiveCfg = Release|Win32 18 | {E3AE0F7F-2BBD-4563-AE22-1A92E11630F0}.Release|x64.ActiveCfg = Release|x64 19 | {E3AE0F7F-2BBD-4563-AE22-1A92E11630F0}.Release|x64.Build.0 = Release|x64 20 | EndGlobalSection 21 | GlobalSection(SolutionProperties) = preSolution 22 | HideSolutionNode = FALSE 23 | EndGlobalSection 24 | GlobalSection(ExtensibilityGlobals) = postSolution 25 | SolutionGuid = {43BB3D89-917B-413A-84C4-584E2EC97223} 26 | EndGlobalSection 27 | EndGlobal 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **if something does not work - pls, use development wine branch, in staging branch "ntdll-Syscall_Emulation" feature is enabled - and this feature prevent to use direct linux syscalls execution, whitch using by this dll to access to driver unix socket, but dll have workaround solution - int80h api - and it is workable in my tests on wine-9.0-rc2 (Staging)** 2 | 3 | This is new solution to make 3Dconnexion SpaceMouse workable in Fusion 360 in Linux under WINE (other applications may work too) 4 | New solution based on dll replacment and work together with open source linux driver for space mouse [spacenavd](http://spacenav.sourceforge.net/), 5 | [old](https://github.com/DD1984/SpaceMouse_Fusion360_Wine/tree/master/AddIns) solution - based on AddIns 6 | 7 | 8 | #### instalation: 9 | * **spacenavd** must be installed first from you distributive repositories 10 | * copy **siappdll.dll** to the folder of your program (folder where Fusion360.exe placed) 11 | * setup **_legacy_** SpaceMouse driver in Fusion 360 *Preferences* 12 | * **spnavcfg** could be installed - this is graphical util for fine tune space mouse parameters (this package do not exist in ubuntu repos, but you could download it from spacenavd website) 13 | 14 | #### TODO: 15 | * [ ] Buttons 16 | * [ ] CPU load 17 | 18 | #### Very Thanks: 19 | * [SpaceNavigatorEmulator](https://github.com/lukenuttall/SpaceNavigatorEmulator) 20 | * [wine-discord-ipc-bridge](https://github.com/0e4ef622/wine-discord-ipc-bridge) 21 | -------------------------------------------------------------------------------- /AddIns/README.md: -------------------------------------------------------------------------------- 1 | This is workaround solution to make 3Dconnexion SpaceMouse workable in Fusion 360 in Linux under WINE - [video](https://youtu.be/KpPamemM14c) 2 | #### how it work: 3 | solution consist from two part: 4 | * spconvd - daemon that connect to [spacenavd](http://spacenav.sourceforge.net/) (open source linux driver for spacemouse), read mouse events and then send it to Fusion 360 via network through *localhost:11111* 5 | * AddIns (plugin) for Fusion 360, that read mouse events from spconvd and convert it to camera motions using Fusion 360 API 6 | #### instalation: 7 | * **spacenavd** must be installed first from you distributive repositories (this package exist in Ubuntu 21.04 repos) 8 | * **spnavcfg** could be installed - this is graphical util for fine tune space mouse parameters (this package do not exist in ubuntu repos, but you could download it from spacenavd website) 9 | * clone this repo, go to spconvd directory and execute: ```make && make install``` - this will build and install spconvd daemon to ```~/.local/bin/``` 10 | * run spconvd **manually** 11 | * copy **SpaceMouse** folder into Fusion 360 AddIns path: ```~/.wine/drive_c/users//Application Data/Autodesk/Autodesk Fusion 360/API/AddIns``` 12 | * start Fusion 360, go to AddIns menu and **Run** SpaceMouse - that is all 13 | * #### TODO: 14 | * - [ ] move mouse events shaper(it need to decrease cpu load by decrease screen refresh rate) from spconvd to AddIns 15 | * - [ ] rewrite spconvd on python 16 | * - [ ] fine tune coefficients of motions, rotations and zoom 17 | -------------------------------------------------------------------------------- /siappdll/siappdll.def: -------------------------------------------------------------------------------- 1 | LIBRARY "siappdll" 2 | 3 | EXPORTS 4 | SpwErrorVal 5 | 6 | SiInitialize 7 | SiIsInitialized 8 | SiTerminate 9 | 10 | SiGetLibraryInfo 11 | SiGetDriverInfo 12 | SiGetDevicePort 13 | 14 | SiGetNumDevices 15 | SiDeviceIndex 16 | 17 | SiOpenWinInit 18 | SiOpen 19 | SiOpenPort 20 | SiClose 21 | 22 | SiGetDeviceID 23 | SiGetDeviceImageFileName 24 | SiGetDeviceInfo 25 | SiGetDeviceName 26 | 27 | SiGrabDevice 28 | SiReleaseDevice 29 | 30 | SiRezero 31 | SiBeep 32 | SiSetLEDs 33 | SiSetUiMode 34 | 35 | SiDispatch 36 | 37 | SiGetEventWinInit 38 | SiGetEvent 39 | SiPeekEvent 40 | 41 | SiIsSpaceWareEvent 42 | SiButtonPressed 43 | SiButtonReleased 44 | SiGetButtonName 45 | 46 | SiSyncSendQuery 47 | SiSyncGetVersion 48 | SiSyncGetNumberOfFunctions 49 | SiSyncGetFunction 50 | SiSyncGetButtonAssignment 51 | SiSyncSetButtonAssignment 52 | SiSyncSetButtonAssignmentAbsolute 53 | SiSyncSetButtonName 54 | SiSyncGetAxisLabel 55 | SiSyncSetAxisLabel 56 | SiSyncGetOrientation 57 | SiSyncSetOrientation 58 | SiSyncGetFilter 59 | SiSyncSetFilter 60 | SiSyncGetAxesState 61 | SiSyncSetAxesState 62 | SiSyncSetInfoLine 63 | SiSyncGetScaleOverall 64 | SiSyncSetScaleOverall 65 | SiSyncGetScaleTx 66 | SiSyncSetScaleTx 67 | SiSyncGetScaleTy 68 | SiSyncSetScaleTy 69 | SiSyncGetScaleTz 70 | SiSyncSetScaleTz 71 | SiSyncGetScaleRx 72 | SiSyncSetScaleRx 73 | SiSyncGetScaleRy 74 | SiSyncSetScaleRy 75 | SiSyncGetScaleRz 76 | SiSyncSetScaleRz 77 | SiSyncInvokeAbsoluteFunction 78 | SiSyncSetButtonState 79 | 80 | SiGetCompanyIcon 81 | SiGetCompanyLogoFileName 82 | 83 | SpwErrorString 84 | 85 | SiSetTypeMask -------------------------------------------------------------------------------- /siappdll/src/sock.cpp: -------------------------------------------------------------------------------- 1 | #include "sock_ll.h" 2 | #include "sock.h" 3 | #include "log.h" 4 | 5 | bool int80h = false; 6 | 7 | int sock_connect(const char *sock_file) 8 | { 9 | LOG(INFO) << "Creating socket"; 10 | 11 | int fd = -1; 12 | if (int80h || (fd = l_socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { 13 | LOG(ERROR) << "l_socket() return err: 0x" << std::hex << fd; 14 | 15 | /* workaround because l_socket() sometime return strange 0xc0000002 value */ 16 | LOG(INFO) << "trying l_socket_int80h()"; 17 | fd = l_socket_int80h(AF_UNIX, SOCK_STREAM, 0); 18 | if (fd < 0) { 19 | LOG(ERROR) << "l_socket_int80h() return err: 0x" << std::hex << fd; 20 | LOG(ERROR) << "Failed to create socket"; 21 | return -1; 22 | } 23 | 24 | LOG(INFO) << "Using int80h api!!!"; 25 | int80h = true; 26 | } 27 | 28 | LOG(INFO) << "fd: " << fd; 29 | 30 | struct sockaddr_un addr; 31 | addr.sun_family = AF_UNIX; 32 | snprintf(addr.sun_path, sizeof(addr.sun_path), sock_file); 33 | 34 | LOG(INFO) << "Attempting to connect to " << addr.sun_path; 35 | 36 | int (*connect_func)(int sockfd, const struct sockaddr* addr, unsigned int addrlen) = l_connect; 37 | if (int80h) 38 | connect_func = l_connect_int80h; 39 | 40 | int ret; 41 | if ((ret = connect_func(fd, (struct sockaddr*)&addr, sizeof(addr))) < 0) { 42 | LOG(ERROR) << "connect() return err: 0x" << std::hex << ret; 43 | LOG(ERROR) << "Failed to connect"; 44 | 45 | sock_close(fd); 46 | return -1; 47 | } 48 | 49 | return fd; 50 | } 51 | 52 | int sock_read(int fd, char* buf, size_t count) 53 | { 54 | int (*read_func)(int fd, char* buf, unsigned int count) = l_read; 55 | if (int80h) 56 | read_func = l_read_int80h; 57 | 58 | return read_func(fd, buf, count); 59 | } 60 | 61 | void sock_close(int fd) 62 | { 63 | int (*close_func)(int fd) = l_close; 64 | if (int80h) 65 | close_func = l_close_int80h; 66 | 67 | close_func(fd); 68 | } -------------------------------------------------------------------------------- /siappdll/siappdll.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | 32 | 33 | Source Files 34 | 35 | 36 | 37 | 38 | 39 | Header Files 40 | 41 | 42 | Header Files 43 | 44 | 45 | Header Files 46 | 47 | 48 | Header Files 49 | 50 | 51 | Header Files 52 | 53 | 54 | Header Files 55 | 56 | 57 | Header Files 58 | 59 | 60 | Header Files 61 | 62 | 63 | 64 | 65 | Source Files 66 | 67 | 68 | -------------------------------------------------------------------------------- /siappdll/src/sock_ll.asm: -------------------------------------------------------------------------------- 1 | .data 2 | 3 | .code 4 | ALIGN 16 5 | 6 | ;RCX, b in RDX, c in R8 7 | ; https://learn.microsoft.com/en-us/cpp/build/x64-software-conventions?view=msvc-170#x64-register-usage 8 | ; https://syscall.sh/ 9 | 10 | l_open PROC 11 | sub rsp, 28h ; shadow stack 12 | 13 | push rdi 14 | push rsi 15 | 16 | mov rax, 2 17 | 18 | mov rdi, rcx 19 | mov rsi, rdx 20 | mov rdx, r8 21 | 22 | syscall 23 | 24 | pop rsi 25 | pop rdi 26 | 27 | add rsp, 28h ; restoring shadow stack 28 | ret 29 | l_open ENDP 30 | 31 | l_read PROC 32 | sub rsp, 28h ; shadow stack 33 | 34 | push rdi 35 | push rsi 36 | 37 | mov rax, 0 38 | 39 | mov rdi, rcx 40 | mov rsi, rdx 41 | mov rdx, r8 42 | 43 | syscall 44 | 45 | pop rsi 46 | pop rdi 47 | 48 | add rsp, 28h ; restoring shadow stack 49 | ret 50 | l_read ENDP 51 | 52 | l_read_int80h PROC 53 | sub rsp, 28h ; shadow stack 54 | 55 | push rbx 56 | 57 | mov rax, 3 58 | mov rbx, rcx 59 | mov rcx, rdx 60 | mov rdx, r8 61 | int 80h 62 | 63 | pop rbx 64 | 65 | add rsp, 28h ; restoring shadow stack 66 | ret 67 | l_read_int80h ENDP 68 | 69 | l_close PROC 70 | sub rsp, 28h ; shadow stack 71 | 72 | push rdi 73 | 74 | mov rax, 3 75 | 76 | mov rdi, rcx 77 | 78 | syscall 79 | 80 | pop rdi 81 | 82 | add rsp, 28h ; restoring shadow stack 83 | ret 84 | l_close ENDP 85 | 86 | l_close_int80h PROC 87 | sub rsp, 28h ; shadow stack 88 | 89 | push rbx 90 | 91 | mov rax, 6 92 | mov rbx, rcx 93 | int 80h 94 | 95 | pop rbx 96 | 97 | add rsp, 28h ; restoring shadow stack 98 | ret 99 | l_close_int80h ENDP 100 | 101 | l_socket PROC 102 | sub rsp, 28h ; shadow stack 103 | 104 | push rdi 105 | push rsi 106 | 107 | mov rax, 41 108 | 109 | mov rdi, rcx 110 | mov rsi, rdx 111 | mov rdx, r8 112 | 113 | syscall 114 | 115 | pop rsi 116 | pop rdi 117 | 118 | add rsp, 28h ; restoring shadow stack 119 | ret 120 | l_socket ENDP 121 | 122 | l_socket_int80h PROC 123 | sub rsp, 28h ; shadow stack 124 | 125 | push rbx 126 | 127 | mov eax, 359 128 | mov ebx, ecx 129 | mov ecx, edx 130 | mov edx, r8d 131 | int 80h 132 | 133 | pop rbx 134 | 135 | add rsp, 28h ; restoring shadow stack 136 | ret 137 | l_socket_int80h ENDP 138 | 139 | l_connect PROC 140 | sub rsp, 28h ; shadow stack 141 | 142 | push rdi 143 | push rsi 144 | 145 | mov rax, 42 146 | 147 | mov rdi, rcx 148 | mov rsi, rdx 149 | mov rdx, r8 150 | 151 | syscall 152 | 153 | pop rsi 154 | pop rdi 155 | 156 | add rsp, 28h ; restoring shadow stack 157 | ret 158 | l_connect ENDP 159 | 160 | l_connect_int80h PROC 161 | sub rsp, 28h ; shadow stack 162 | 163 | push rbx 164 | 165 | mov rax, 362 166 | mov rbx, rcx 167 | mov rcx, rdx 168 | mov rdx, r8 169 | int 80h 170 | 171 | pop rbx 172 | 173 | add rsp, 28h ; restoring shadow stack 174 | ret 175 | l_connect_int80h ENDP 176 | 177 | END -------------------------------------------------------------------------------- /siappdll/src/siappdll.h: -------------------------------------------------------------------------------- 1 | /* 2 | SpaceNavigatorEmulator - 3dconnexion-compatible siappdll.dll replacement 3 | Copyright (C) 2014 John Tsiombikas 4 | Copyright (C) 2015 Luke Nuttall 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | #pragma once 20 | 21 | #include "sidef.h" 22 | 23 | enum SpwRetVal SpwErrorVal; 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | #endif 28 | 29 | int _afxForceUSRDLL; 30 | 31 | BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved); 32 | 33 | enum SpwRetVal SPWAPI SiInitialize(void); 34 | SPWbool SiIsInitialized(); 35 | void SPWAPI SiTerminate(void); 36 | 37 | void SPWAPI SiGetLibraryInfo(SiVerInfo *info); 38 | enum SpwRetVal SPWAPI SiGetDriverInfo(SiVerInfo *info); 39 | enum SpwRetVal SPWAPI SiGetDevicePort(int devid, SiDevPort *port); 40 | 41 | int SPWAPI SiGetNumDevices(void); 42 | 43 | void SPWAPI SiOpenWinInit(SiOpenData *opendata, void *win); 44 | struct SiHdl *SPWAPI SiOpen(const char *appname, int devid, SiTypeMask *tmask, int mode, SiOpenData *opendata); 45 | struct SiHdl* SPWAPI SiOpenPort(const char *pAppName, const SiDevPort *pPort, int mode, const SiOpenData *pData); 46 | enum SpwRetVal SPWAPI SiClose(struct SiHdl *si); 47 | 48 | int SPWAPI SiGetDeviceID(struct SiHdl *si); 49 | enum SpwRetVal SPWAPI SiGetDeviceImageFileName(struct SiHdl *si, char *name, unsigned long *maxlen); 50 | enum SpwRetVal SPWAPI SiGetDeviceInfo(struct SiHdl *si, SiDevInfo *info); 51 | enum SpwRetVal SPWAPI SiGetDeviceName(struct SiHdl *si, SiDeviceName *name); 52 | 53 | enum SpwRetVal SPWAPI SiGrabDevice(struct SiHdl *si, SPWbool exclusive); 54 | enum SpwRetVal SPWAPI SiReleaseDevice(struct SiHdl *si); 55 | 56 | enum SpwRetVal SPWAPI SiRezero(struct SiHdl *si); 57 | enum SpwRetVal SPWAPI SiBeep(struct SiHdl *si, char *str); 58 | enum SpwRetVal SPWAPI SiSetLEDs(struct SiHdl *si, unsigned long mask); 59 | enum SpwRetVal SPWAPI SiSetUiMode(struct SiHdl *si, unsigned long mode); 60 | 61 | int SPWAPI SiDispatch(struct SiHdl *si, SiGetEventData *data, SiSpwEvent *ev, SiSpwHandlers *handlers); 62 | 63 | void SPWAPI SiGetEventWinInit(SiGetEventData *evdata, unsigned int msg, unsigned int wparam, long lparam); 64 | SpwRetVal SPWAPI SiGetEvent(struct SiHdl *si, int flags, const SiGetEventData *data, SiSpwEvent *ev); 65 | SpwRetVal SPWAPI SiPeekEvent(struct SiHdl *si, int flags, const SiGetEventData *data, SiSpwEvent *ev); 66 | 67 | int SPWAPI SiButtonPressed(SiSpwEvent *ev); 68 | int SPWAPI SiButtonReleased(SiSpwEvent *ev); 69 | enum SpwRetVal SPWAPI SiGetButtonName(struct SiHdl *si, unsigned long bnum, SiButtonName *name); 70 | 71 | void *SPWAPI SiGetCompanyIcon(void); 72 | enum SpwRetVal SPWAPI SiGetCompanyLogoFileName(char *name, unsigned long *maxlen); 73 | 74 | const char *SPWAPI SpwErrorString(enum SpwRetVal err); 75 | 76 | 77 | 78 | /* deprecated */ 79 | enum SpwRetVal SiSetTypeMask(SiTypeMask *mask, int type1, ...); 80 | 81 | #include "syncapi.h" 82 | 83 | #ifdef __cplusplus 84 | } 85 | #endif 86 | 87 | -------------------------------------------------------------------------------- /siappdll/.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/**/* 19 | x86/ 20 | build/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studo 2015 cache/options directory 26 | .vs/ 27 | 28 | # MSTest test Results 29 | [Tt]est[Rr]esult*/ 30 | [Bb]uild[Ll]og.* 31 | 32 | # NUNIT 33 | *.VisualState.xml 34 | TestResult.xml 35 | 36 | # Build Results of an ATL Project 37 | [Dd]ebugPS/ 38 | [Rr]eleasePS/ 39 | dlldata.c 40 | 41 | # DNX 42 | project.lock.json 43 | artifacts/ 44 | 45 | *_i.c 46 | *_p.c 47 | *_i.h 48 | *.ilk 49 | *.meta 50 | *.obj 51 | *.pch 52 | *.pdb 53 | *.pgc 54 | *.pgd 55 | *.rsp 56 | *.sbr 57 | *.tlb 58 | *.tli 59 | *.tlh 60 | *.tmp 61 | *.tmp_proj 62 | *.log 63 | *.vspscc 64 | *.vssscc 65 | .builds 66 | *.pidb 67 | *.svclog 68 | *.scc 69 | 70 | # Chutzpah Test files 71 | _Chutzpah* 72 | 73 | # Visual C++ cache files 74 | ipch/ 75 | *.aps 76 | *.ncb 77 | *.opensdf 78 | *.sdf 79 | *.cachefile 80 | 81 | # Visual Studio profiler 82 | *.psess 83 | *.vsp 84 | *.vspx 85 | 86 | # TFS 2012 Local Workspace 87 | $tf/ 88 | 89 | # Guidance Automation Toolkit 90 | *.gpState 91 | 92 | # ReSharper is a .NET coding add-in 93 | _ReSharper*/ 94 | *.[Rr]e[Ss]harper 95 | *.DotSettings.user 96 | 97 | # JustCode is a .NET coding add-in 98 | .JustCode 99 | 100 | # TeamCity is a build add-in 101 | _TeamCity* 102 | 103 | # DotCover is a Code Coverage Tool 104 | *.dotCover 105 | 106 | # NCrunch 107 | _NCrunch_* 108 | .*crunch*.local.xml 109 | 110 | # MightyMoose 111 | *.mm.* 112 | AutoTest.Net/ 113 | 114 | # Web workbench (sass) 115 | .sass-cache/ 116 | 117 | # Installshield output folder 118 | [Ee]xpress/ 119 | 120 | # DocProject is a documentation generator add-in 121 | DocProject/buildhelp/ 122 | DocProject/Help/*.HxT 123 | DocProject/Help/*.HxC 124 | DocProject/Help/*.hhc 125 | DocProject/Help/*.hhk 126 | DocProject/Help/*.hhp 127 | DocProject/Help/Html2 128 | DocProject/Help/html 129 | 130 | # Click-Once directory 131 | publish/ 132 | 133 | # Publish Web Output 134 | *.[Pp]ublish.xml 135 | *.azurePubxml 136 | # TODO: Comment the next line if you want to checkin your web deploy settings 137 | # but database connection strings (with potential passwords) will be unencrypted 138 | *.pubxml 139 | *.publishproj 140 | 141 | # NuGet Packages 142 | *.nupkg 143 | # The packages folder can be ignored because of Package Restore 144 | **/packages/* 145 | # except build/, which is used as an MSBuild target. 146 | !**/packages/build/ 147 | # Uncomment if necessary however generally it will be regenerated when needed 148 | #!**/packages/repositories.config 149 | 150 | # Windows Azure Build Output 151 | csx/ 152 | *.build.csdef 153 | 154 | # Windows Store app package directory 155 | AppPackages/ 156 | 157 | # Visual Studio cache files 158 | # files ending in .cache can be ignored 159 | *.[Cc]ache 160 | # but keep track of directories ending in .cache 161 | !*.[Cc]ache/ 162 | 163 | # Others 164 | ClientBin/ 165 | [Ss]tyle[Cc]op.* 166 | ~$* 167 | *~ 168 | *.dbmdl 169 | *.dbproj.schemaview 170 | *.pfx 171 | *.publishsettings 172 | node_modules/ 173 | bower_components/ 174 | orleans.codegen.cs 175 | 176 | # RIA/Silverlight projects 177 | Generated_Code/ 178 | 179 | # Backup & report files from converting an old project file 180 | # to a newer Visual Studio version. Backup files are not needed, 181 | # because we have git ;-) 182 | _UpgradeReport_Files/ 183 | Backup*/ 184 | UpgradeLog*.XML 185 | UpgradeLog*.htm 186 | 187 | # SQL Server files 188 | *.mdf 189 | *.ldf 190 | 191 | # Business Intelligence projects 192 | *.rdl.data 193 | *.bim.layout 194 | *.bim_*.settings 195 | 196 | # Microsoft Fakes 197 | FakesAssemblies/ 198 | 199 | # Node.js Tools for Visual Studio 200 | .ntvs_analysis.dat 201 | 202 | # Visual Studio 6 build log 203 | *.plg 204 | 205 | # Visual Studio 6 workspace options file 206 | *.opt 207 | 208 | !x64/Release/siappdll.dll 209 | !x64/Release/ 210 | !x64/ 211 | -------------------------------------------------------------------------------- /AddIns/spconvd/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define DEBUG 13 | #ifdef DEBUG 14 | #define DPRN(format, args...) printf(format, ##args) 15 | #else 16 | #define DPRN(format, args...) do {} while (0) 17 | #endif 18 | 19 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) 20 | 21 | #define SOCK_FILE "/var/run/spnav.sock" 22 | #define PORT 11111 23 | 24 | // decreasing events rate from spacemouse - this need for decrease rate of screen refresh in fusion360 - decrease cpu load 25 | #define SHAPE 26 | #define SHAPE_DELAY_MS 30 27 | #define SHAPE_DELAY_US (SHAPE_DELAY_MS * 1000) 28 | 29 | #ifdef SHAPE 30 | #define POLL_TIMEOUT SHAPE_DELAY_MS 31 | #else 32 | #define POLL_TIMEOUT -1 33 | #endif 34 | 35 | #ifdef SHAPE 36 | unsigned int get_time_us(void) 37 | { 38 | struct timespec tp; 39 | clock_gettime(CLOCK_MONOTONIC_RAW, &tp); 40 | return tp.tv_sec * 1000000 + tp.tv_nsec / 1000; 41 | } 42 | #endif 43 | 44 | int daem_connect(void) 45 | { 46 | int daemfd = socket(AF_UNIX, SOCK_STREAM, 0); 47 | if (daemfd < 0) { 48 | DPRN("could not create unix sock\n"); 49 | return -1; 50 | } 51 | 52 | struct sockaddr_un addr_un = {0}; 53 | 54 | addr_un.sun_family = AF_UNIX; 55 | strncpy(addr_un.sun_path, SOCK_FILE, sizeof(addr_un.sun_path) - 1); 56 | 57 | if (connect(daemfd, (struct sockaddr*)&addr_un, sizeof(addr_un))) { 58 | DPRN("could not connect to spacenavd\n"); 59 | close(daemfd); 60 | return -1; 61 | } 62 | 63 | return daemfd; 64 | } 65 | 66 | void daem_close(int fd) 67 | { 68 | close(fd); 69 | } 70 | 71 | int main(void) 72 | { 73 | if (daemon(0, 1)) { 74 | DPRN("could not daemonize\n"); 75 | return -1; 76 | } 77 | 78 | int listenfd = socket(AF_INET, SOCK_STREAM, 0); 79 | if (listenfd < 0) { 80 | DPRN("could not create inet sock\n"); 81 | return -1; 82 | } 83 | 84 | int enable = 1; 85 | setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)); 86 | 87 | struct sockaddr_in addr_in = {0}; 88 | addr_in.sin_family = AF_INET; 89 | addr_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 90 | addr_in.sin_port = htons(PORT); 91 | 92 | if (bind(listenfd, (struct sockaddr*)&addr_in, sizeof(addr_in))) { 93 | DPRN("could bind\n"); 94 | close(listenfd); 95 | return -1; 96 | } 97 | 98 | listen(listenfd, 1); 99 | 100 | while (1) { 101 | DPRN("waiting for connection\n"); 102 | 103 | int confd = accept(listenfd, (struct sockaddr*)NULL, NULL); 104 | if (confd < 0) { 105 | printf("could not accept\n"); 106 | continue; 107 | } 108 | 109 | DPRN("connection accepted\n"); 110 | 111 | int daemfd = daem_connect(); 112 | if (daemfd >= 0) 113 | DPRN("daemon connection success\n"); 114 | else 115 | continue; 116 | 117 | struct pollfd fds[2]; 118 | 119 | fds[0].fd = confd; 120 | fds[0].events = POLLIN; 121 | 122 | fds[1].fd = daemfd; 123 | fds[1].events = POLLIN; 124 | 125 | int motion[8] = {0}; 126 | 127 | #ifdef SHAPE 128 | unsigned int last = get_time_us(); 129 | #endif 130 | int run = 1; 131 | while (run) { 132 | int i; 133 | int ret = poll(fds, ARRAY_SIZE(fds), POLL_TIMEOUT); 134 | 135 | #ifdef SHAPE 136 | unsigned int now = get_time_us(); 137 | 138 | if ((now - last) > SHAPE_DELAY_US) { 139 | int sum = 0; 140 | for (i = 1; i < 7; i++) 141 | sum |= motion[i]; 142 | if (sum) { 143 | if (write(confd, motion, sizeof(motion)) != sizeof(motion)) { 144 | run = 0; 145 | break; 146 | } 147 | bzero(motion, sizeof(motion)); 148 | } 149 | 150 | last = now; 151 | } 152 | #endif 153 | 154 | if (ret <= 0) { 155 | if (ret < 0) 156 | DPRN("poll() failed\n"); 157 | continue; 158 | } 159 | 160 | for (i = 0; i < ARRAY_SIZE(fds); i++) { 161 | if(fds[i].revents == 0) 162 | continue; 163 | 164 | if(fds[i].revents != POLLIN) { 165 | DPRN("poll() invalid revents == 0x%04x fds[%d]\n", fds[i].revents, i); 166 | continue; 167 | } 168 | 169 | if (fds[i].fd == confd) { 170 | run = 0; 171 | break; 172 | } 173 | 174 | if (fds[i].fd == daemfd) { 175 | int data[8]; 176 | ssize_t len = read(daemfd, data, sizeof(data)); 177 | if (len <= 0) { 178 | run = 0; 179 | break; 180 | } 181 | #ifdef SHAPE 182 | if (data[0] == 0) { 183 | int j; 184 | for (j = 1; j < 7; j++) 185 | motion[j] += data[j]; 186 | } 187 | else 188 | #endif 189 | { 190 | if (write(confd, data, len) != len) { 191 | run = 0; 192 | break; 193 | } 194 | } 195 | } 196 | } 197 | } 198 | 199 | DPRN("daemon connection close\n"); 200 | daem_close(daemfd); 201 | 202 | DPRN("close connection\n"); 203 | close(confd); 204 | } 205 | 206 | close(listenfd); 207 | 208 | return 0; 209 | } 210 | -------------------------------------------------------------------------------- /siappdll/siappdll.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 26 | 29 | 32 | 35 | 38 | 41 | 54 | 57 | 60 | 63 | 72 | 75 | 78 | 81 | 84 | 87 | 90 | 93 | 94 | 102 | 105 | 108 | 111 | 114 | 117 | 129 | 132 | 135 | 138 | 149 | 152 | 155 | 158 | 161 | 164 | 167 | 170 | 171 | 172 | 173 | 174 | 175 | 180 | 183 | 184 | 187 | 188 | 191 | 192 | 195 | 196 | 197 | 202 | 205 | 206 | 209 | 210 | 213 | 214 | 217 | 218 | 221 | 222 | 223 | 228 | 229 | 230 | 231 | 232 | 233 | -------------------------------------------------------------------------------- /AddIns/SpaceMouse/SpaceMouse.py: -------------------------------------------------------------------------------- 1 | #Author- 2 | #Description- 3 | 4 | import adsk.core, adsk.fusion, adsk.cam, traceback 5 | import threading, random, json, socket, array, math 6 | 7 | HOST = "127.0.0.1" 8 | PORT = 11111 9 | 10 | app = None 11 | ui = None 12 | handlers = [] 13 | stopFlag = None 14 | myCustomEvent = 'MyCustomEventId' 15 | customEvent = None 16 | 17 | mysock = None 18 | 19 | check = False 20 | 21 | def sign(x): 22 | return 1 if x > 0 else -1 if x < 0 else 0 23 | 24 | # The event handler that responds to the custom event being fired. 25 | class ThreadEventHandler(adsk.core.CustomEventHandler): 26 | def __init__(self): 27 | super().__init__() 28 | def notify(self, args): 29 | try: 30 | global app 31 | 32 | rotx_en = roty_en = rotz_en = movx_en = movy_en = movz_en = False 33 | 34 | rotx_en = True 35 | roty_en = True 36 | rotz_en = True 37 | movx_en = True 38 | movy_en = True 39 | movz_en = True 40 | 41 | eventArgs = json.loads(args.additionalInfo) 42 | 43 | rx = eventArgs['rx'] 44 | ry = eventArgs['ry'] 45 | rz = eventArgs['rz'] 46 | x = eventArgs['x'] 47 | y = eventArgs['y'] 48 | z = eventArgs['z'] 49 | 50 | # get state 51 | vi = app.activeViewport 52 | camera = vi.camera #This is a deep copy. 53 | eye = camera.eye 54 | tgt = camera.target 55 | up = camera.upVector 56 | 57 | # calc coef 58 | coef = math.sqrt(camera.viewExtents) 59 | 60 | MOV_COEF = 0.0002 * coef 61 | ROT_COEF = 0.00015 62 | TILT_COEF = 0.00007 63 | ZOOM_COEF = 0.0005 * coef 64 | 65 | 66 | # get matrix 67 | front = eye.vectorTo(tgt) 68 | right = front.crossProduct(up) 69 | 70 | matr = adsk.core.Matrix3D.create() 71 | matr.setWithCoordinateSystem(eye, right, front, up) 72 | 73 | if rotx_en: 74 | rotx = adsk.core.Matrix3D.create() 75 | rotx.setToRotation(-rx * TILT_COEF, right, tgt) 76 | 77 | matr.transformBy(rotx) 78 | 79 | if rotz_en: 80 | rotz = adsk.core.Matrix3D.create() 81 | rotz.setToRotation(-ry * ROT_COEF, up, tgt) 82 | 83 | matr.transformBy(rotz) 84 | 85 | if roty_en: 86 | roty = adsk.core.Matrix3D.create() 87 | roty.setToRotation(-rz * TILT_COEF, front, tgt) 88 | 89 | matr.transformBy(roty) 90 | 91 | (eye, right, front, up) = matr.getAsCoordinateSystem() 92 | 93 | if movx_en: 94 | movx = right.copy() 95 | movx.normalize() 96 | movx.scaleBy(-x * MOV_COEF) 97 | 98 | eye.translateBy(movx) 99 | tgt.translateBy(movx) 100 | 101 | if movy_en: 102 | movy = up.copy() 103 | movy.normalize() 104 | movy.scaleBy(-y * MOV_COEF) 105 | 106 | eye.translateBy(movy) 107 | tgt.translateBy(movy) 108 | 109 | if movz_en: 110 | ve = camera.viewExtents 111 | ve += z * ZOOM_COEF 112 | if ve > 0: 113 | camera.viewExtents = ve 114 | 115 | 116 | # write back 117 | camera.isSmoothTransition = False 118 | 119 | camera.target = tgt 120 | camera.eye = eye 121 | camera.upVector = up 122 | vi.camera = camera 123 | vi.refresh() 124 | 125 | #adsk.doEvents() 126 | except: 127 | if ui: 128 | ui.messageBox('Failed:\n{}'.format(traceback.format_exc())) 129 | 130 | 131 | # The class for the new thread. 132 | class MyThread(threading.Thread): 133 | def __init__(self, event): 134 | threading.Thread.__init__(self) 135 | self.stopped = event 136 | 137 | def run(self): 138 | global mysock 139 | 140 | mysock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 141 | mysock.connect((HOST, PORT)) 142 | 143 | while True: 144 | data = mysock.recv(32) 145 | arr = array.array('i', data) 146 | if arr[0] == 0: 147 | args = {'x': arr[1], 'y': arr[2], 'z': arr[3], 'rx': arr[4], 'ry': arr[5], 'rz': arr[6]} 148 | app.fireCustomEvent(myCustomEvent, json.dumps(args)) 149 | 150 | def run(context): 151 | global ui 152 | global app 153 | 154 | try: 155 | app = adsk.core.Application.get() 156 | ui = app.userInterface 157 | 158 | ui.messageBox('SpaceMouse start !!!') 159 | 160 | # Register the custom event and connect the handler. 161 | global customEvent 162 | customEvent = app.registerCustomEvent(myCustomEvent) 163 | 164 | onThreadEvent = ThreadEventHandler() 165 | customEvent.add(onThreadEvent) 166 | handlers.append(onThreadEvent) 167 | 168 | # Create a new thread for the other processing. 169 | global stopFlag 170 | stopFlag = threading.Event() 171 | myThread = MyThread(stopFlag) 172 | myThread.start() 173 | except: 174 | if ui: 175 | ui.messageBox('Failed:\n{}'.format(traceback.format_exc())) 176 | 177 | 178 | def stop(context): 179 | global mysock 180 | try: 181 | mysock.close() 182 | 183 | if handlers.count: 184 | customEvent.remove(handlers[0]) 185 | 186 | stopFlag.set() 187 | app.unregisterCustomEvent(myCustomEvent) 188 | ui.messageBox('Stop addin') 189 | except: 190 | if ui: 191 | ui.messageBox('Failed:\n{}'.format(traceback.format_exc())) 192 | -------------------------------------------------------------------------------- /siappdll/src/syncapi.h: -------------------------------------------------------------------------------- 1 | /* 2 | SpaceNavigatorEmulator - 3dconnexion-compatible siappdll.dll replacement 3 | Copyright (C) 2014 John Tsiombikas 4 | Copyright (C) 2015 Luke Nuttall 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #pragma once 21 | #include "sidef.h" 22 | 23 | extern "C" { 24 | 25 | typedef struct SiSyncAxesState { 26 | int state; 27 | } SiSyncAxesState; 28 | 29 | typedef enum SiSyncAbsFunctionNumber { 30 | SI_SYNC_FUNCTION_MENU_TOGGLE = 12, 31 | SI_SYNC_FUNCTION_TRANS_TOGGLE = 13, 32 | SI_SYNC_FUNCTION_ROT_TOGGLE = 14, 33 | SI_SYNC_FUNCTION_HPV_TOGGLE = 15, 34 | SI_SYNC_FUNCTION_DEC_SENS = 16, 35 | SI_SYNC_FUNCTION_INC_SENS = 17, 36 | SI_SYNC_FUNCTION_RESTORE_DEF = 18, 37 | SI_SYNC_FUNCTION_PAN = 19, 38 | SI_SYNC_FUNCTION_ZOOM = 20, 39 | SI_SYNC_FUNCTION_TX = 21, 40 | SI_SYNC_FUNCTION_TY = 22, 41 | SI_SYNC_FUNCTION_TZ = 23, 42 | SI_SYNC_FUNCTION_RX = 24, 43 | SI_SYNC_FUNCTION_RY = 25, 44 | SI_SYNC_FUNCTION_RZ = 26, 45 | SI_SYNC_FUNCTION_REZERO_DEVICE = 27, 46 | SI_SYNC_FUNCTION_SAVE = 33, 47 | SI_SYNC_FUNCTION_RELOAD = 57, 48 | SI_SYNC_FUNCTION_SHIFT_KEY = 60, 49 | SI_SYNC_FUNCTION_CTRL_KEY = 61, 50 | SI_SYNC_FUNCTION_ALT_KEY = 62, 51 | SI_SYNC_FUNCTION_RESTORE_SENS = 63, 52 | SI_SYNC_FUNCTION_SPACE_KEY = 64, 53 | SI_SYNC_FUNCTION_CTRL_SHIFT_KEY = 65, 54 | SI_SYNC_FUNCTION_CTRL_ALT_KEY = 66, 55 | SI_SYNC_FUNCTION_SHIFT_ALT_KEY = 67, 56 | SI_SYNC_FUNCTION_TAB_KEY = 68, 57 | SI_SYNC_FUNCTION_RETURN_KEY = 69, 58 | SI_SYNC_FUNCTION_DEC_TRANS_SENS = 70, 59 | SI_SYNC_FUNCTION_INC_TRANS_SENS = 71, 60 | SI_SYNC_FUNCTION_DEC_ROT_SENS = 72, 61 | SI_SYNC_FUNCTION_INC_ROT_SENS = 73, 62 | SI_SYNC_FUNCTION_DEC_PAN_SENS = 74, 63 | SI_SYNC_FUNCTION_INC_PAN_SENS = 75, 64 | SI_SYNC_FUNCTION_DEC_ZOOM_SENS = 76, 65 | SI_SYNC_FUNCTION_INC_ZOOM_SENS = 77, 66 | SI_SYNC_FUNCTION_ESC_KEY = 78, 67 | SI_SYNC_FUNCTION_3DX_HELP = 94, 68 | SI_SYNC_FUNCTION_APP_HELP = 95, 69 | SI_SYNC_FUNCTION_DIALOG_TOGGLE_FN = 96, 70 | SI_SYNC_FUNCTION_FIT_FN = 97, 71 | SI_SYNC_FUNCTION_TOGGLE_3DXLCD_FN = 198, 72 | SI_SYNC_FUNCTION_TOGGLE_3DXNUMPAD_FN = 199 73 | } SiSyncAbsFunctionNumber; 74 | 75 | 76 | typedef enum SiSyncFilter { 77 | SI_SYNC_FILTER_TRANSLATIONS = 1, 78 | SI_SYNC_FILTER_ROTATIONS = 2, 79 | SI_SYNC_FILTER_DOMINANT = 3 80 | } SiSyncFilter; 81 | 82 | typedef enum SiSyncFilterValue { 83 | SI_SYNC_FILTER_OFF = 0, 84 | SI_SYNC_FILTER_ON = 1, 85 | SI_SYNC_FILTER_IN_BETWEEN = 2 86 | } SiSyncFilterValue; 87 | 88 | typedef enum SiSyncAxesStateBits { 89 | SI_SYNC_AXES_STATE_TX = (1 << 0), 90 | SI_SYNC_AXES_STATE_TY = (1 << 1), 91 | SI_SYNC_AXES_STATE_TZ = (1 << 2), 92 | SI_SYNC_AXES_STATE_RX = (1 << 3), 93 | SI_SYNC_AXES_STATE_RY = (1 << 4), 94 | SI_SYNC_AXES_STATE_RZ = (1 << 5) 95 | } SiSyncAxesStateBits; 96 | 97 | typedef enum SiSyncButtonState { 98 | SI_SYNC_BUTTON_STATE_OFF = 0, 99 | SI_SYNC_BUTTON_STATE_ON = 1, 100 | SI_SYNC_BUTTON_STATE_DISABLED = 2 101 | } SiSyncButtonState; 102 | 103 | SpwRetVal SPWAPI SiSyncSendQuery(struct SiHdl *si); 104 | SpwRetVal SPWAPI SiSyncGetVersion(struct SiHdl *si, SPWuint32 *major, SPWuint32 *minor); 105 | SpwRetVal SPWAPI SiSyncGetNumberOfFunctions(struct SiHdl *si, SPWuint32 *num_func); 106 | SpwRetVal SPWAPI SiSyncGetFunction(struct SiHdl *hdl, SPWuint32 index, SPWint32 *abs_func_num, wchar_t *name, SPWuint32 *name_len); 107 | SpwRetVal SPWAPI SiSyncGetButtonAssignment(struct SiHdl *hdl, SPWuint32 bn_num, SPWint32 *assigned_func_index); 108 | SpwRetVal SPWAPI SiSyncSetButtonAssignment(struct SiHdl *hdl, SPWuint32 bn_num, SPWint32 func_index); 109 | SpwRetVal SPWAPI SiSyncSetButtonAssignmentAbsolute(struct SiHdl *hdl, SPWuint32 bn_num, SPWint32 abs_func_num); 110 | SpwRetVal SPWAPI SiSyncSetButtonName(struct SiHdl *hdl, SPWuint32 bn_num, const wchar_t *name); 111 | SpwRetVal SPWAPI SiSyncGetAxisLabel(struct SiHdl *hdl, SPWuint32 axis_num, wchar_t *name, SPWuint32 *name_len); 112 | SpwRetVal SPWAPI SiSyncSetAxisLabel(struct SiHdl *hdl, SPWuint32 axis_num, const wchar_t *name); 113 | SpwRetVal SPWAPI SiSyncGetOrientation(struct SiHdl *hdl, SPWint32 axes[6]); 114 | SpwRetVal SPWAPI SiSyncSetOrientation(struct SiHdl *hdl, const SPWint32 axes[6]); 115 | SpwRetVal SPWAPI SiSyncGetFilter(struct SiHdl *hdl, SiSyncFilter i, SiSyncFilterValue *pv); 116 | SpwRetVal SPWAPI SiSyncSetFilter(struct SiHdl *hdl, SiSyncFilter i, SiSyncFilterValue v); 117 | SpwRetVal SPWAPI SiSyncGetAxesState(struct SiHdl *hdl, SiSyncAxesState *pa); 118 | SpwRetVal SPWAPI SiSyncSetAxesState(struct SiHdl *hdl, SiSyncAxesState a); 119 | SpwRetVal SPWAPI SiSyncSetInfoLine(struct SiHdl *hdl, SPWint32 duration, const wchar_t *text); 120 | SpwRetVal SPWAPI SiSyncGetScaleOverall(struct SiHdl *hdl, SPWfloat32 *pv); 121 | SpwRetVal SPWAPI SiSyncSetScaleOverall(struct SiHdl *hdl, SPWfloat32 v); 122 | SpwRetVal SPWAPI SiSyncGetScaleTx(struct SiHdl *hdl, SPWfloat32 *pv); 123 | SpwRetVal SPWAPI SiSyncSetScaleTx(struct SiHdl *hdl, SPWfloat32 v); 124 | SpwRetVal SPWAPI SiSyncGetScaleTy(struct SiHdl *hdl, SPWfloat32 *pv); 125 | SpwRetVal SPWAPI SiSyncSetScaleTy(struct SiHdl *hdl, SPWfloat32 v); 126 | SpwRetVal SPWAPI SiSyncGetScaleTz(struct SiHdl *hdl, SPWfloat32 *pv); 127 | SpwRetVal SPWAPI SiSyncSetScaleTz(struct SiHdl *hdl, SPWfloat32 v); 128 | SpwRetVal SPWAPI SiSyncGetScaleRx(struct SiHdl *hdl, SPWfloat32 *pv); 129 | SpwRetVal SPWAPI SiSyncSetScaleRx(struct SiHdl *hdl, SPWfloat32 v); 130 | SpwRetVal SPWAPI SiSyncGetScaleRy(struct SiHdl *hdl, SPWfloat32 *pv); 131 | SpwRetVal SPWAPI SiSyncSetScaleRy(struct SiHdl *hdl, SPWfloat32 v); 132 | SpwRetVal SPWAPI SiSyncGetScaleRz(struct SiHdl *hdl, SPWfloat32 *pv); 133 | SpwRetVal SPWAPI SiSyncSetScaleRz(struct SiHdl *hdl, SPWfloat32 v); 134 | SpwRetVal SPWAPI SiSyncInvokeAbsoluteFunction(struct SiHdl *hdl, SiSyncAbsFunctionNumber i); 135 | SpwRetVal SPWAPI SiSyncSetButtonState(struct SiHdl *hdl, SPWuint32 bn_num, SiSyncButtonState state); 136 | 137 | } -------------------------------------------------------------------------------- /siappdll/src/sidef.h: -------------------------------------------------------------------------------- 1 | /* 2 | SpaceNavigatorEmulator - 3dconnexion-compatible siappdll.dll replacement 3 | Copyright (C) 2014 John Tsiombikas 4 | Copyright (C) 2015 Luke Nuttall 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | #pragma once 20 | 21 | #define SPWAPI WINAPI 22 | 23 | #include 24 | 25 | #ifndef _MSC_VER 26 | #include 27 | #else 28 | typedef __int32 int32_t; 29 | typedef unsigned __int32 uint32_t; 30 | #endif 31 | 32 | typedef int32_t SPWint32; 33 | typedef uint32_t SPWuint32; 34 | typedef long SPWbool; 35 | typedef float SPWfloat32; 36 | typedef double SPWfloat64; 37 | 38 | #define SI_RESET_BUTTON 0 39 | #define SI_PICK_BUTTON 31 40 | #define SI_DIALOG_BUTTON 30 41 | 42 | #define SI_RESET_BIT (1L << SI_RESET_BUTTON) 43 | #define SI_PICK_BIT (1L << SI_PICK_BUTTON) 44 | #define SI_DIALOG_BIT (1L << SI_DIALOG_BUTTON) 45 | 46 | #define SI_STRSIZE 128 47 | #define SI_MAXBUF 128 48 | #define SI_MAXPORTNAME 128 49 | 50 | #define SI_NO_MASK 0 51 | 52 | struct SiHdl; 53 | 54 | #pragma pack(push, 4) 55 | 56 | typedef int SiDevID; 57 | 58 | typedef struct SiButtonData { 59 | unsigned long last; /* previous button bitmask */ 60 | unsigned long current; /* current button bitmask */ 61 | unsigned long pressed; /* buttons pressed */ 62 | unsigned long release; /* buttons released */ 63 | } SiButtonData; 64 | 65 | typedef struct SiDevInfo { 66 | int dev_type; 67 | int num_buttons; 68 | int num_degrees; 69 | SPWbool can_beep; 70 | char firmware[SI_STRSIZE]; 71 | } SiDevInfo; 72 | 73 | typedef struct SiGetEventData { 74 | unsigned int msg; 75 | unsigned int wparam; 76 | long lparam; 77 | } SiGetEventData; 78 | 79 | typedef struct SiOpenData { 80 | void *win; 81 | void *trans_ctl; 82 | unsigned long pid; 83 | char exe_file[MAX_PATH]; 84 | int lib_flag; 85 | } SiOpenData; 86 | 87 | typedef struct SiTypeMask { 88 | unsigned char mask[8]; 89 | } SiTypeMask; 90 | 91 | /* SiSpwData::motion[6] index names */ 92 | enum { SI_TX, SI_TY, SI_TZ, SI_RX, SI_RY, SI_RZ }; 93 | 94 | typedef struct SiSpwData { 95 | SiButtonData button; 96 | long motion[6]; 97 | unsigned long period; 98 | } SiSpwData; 99 | 100 | typedef enum SiEventType { 101 | SI_BUTTON_EVENT = 1, 102 | SI_MOTION_EVENT, 103 | SI_COMBO_EVENT, 104 | SI_ZERO_EVENT, 105 | SI_EXCEPTION_EVENT, 106 | SI_OUT_OF_BAND, 107 | SI_ORIENTATION_EVENT, 108 | SI_KEYBOARD_EVENT, 109 | SI_LPFK_EVENT, 110 | SI_APP_EVENT, 111 | SI_SYNC_EVENT, 112 | SI_BUTTON_PRESS_EVENT, 113 | SI_BUTTON_RELEASE_EVENT, 114 | SI_DEVICE_CHANGE_EVENT, 115 | SI_MOUSE_EVENT, 116 | SI_JOYSTICK_EVENT 117 | } SiEventType; 118 | 119 | typedef enum SiOrientation { SI_LEFT, SI_RIGHT } SiOrientation; 120 | 121 | typedef struct /* Data for SI_BUTTON_PRESS/RELEASE_EVENT */ 122 | { 123 | SPWuint32 buttonNumber; /* The button number that went down/up in a * 124 | * SI_BUTTON_PRESS/RELEASE_EVENT event */ 125 | } SiHWButtonData; 126 | 127 | typedef struct SiSpwEvent { 128 | int type; 129 | union { 130 | SiSpwData spw_data; 131 | SiOrientation spw_orient; 132 | char ex_data[SI_MAXBUF]; /* exception data */ 133 | SiHWButtonData hwButtonEvent; 134 | } u; 135 | } SiSpwEvent; 136 | 137 | typedef struct { 138 | int (*func)(SiOpenData*, SiGetEventData*, SiSpwEvent*, void*); 139 | void *cls; 140 | } SiEventHandler; 141 | 142 | typedef struct SiSpwHandlers { 143 | SiEventHandler button, motion, combo, zero, exception; 144 | } SiSpwHandlers; 145 | 146 | typedef struct SiVerInfo { 147 | int major, minor, build; 148 | char version[SI_STRSIZE]; 149 | char data[SI_STRSIZE]; 150 | } SiVerInfo; 151 | 152 | typedef struct SiDevPort { 153 | SiDevID devID; /* Device ID */ 154 | int devType; /* Device type */ 155 | int devClass; /* Device class */ 156 | char devName[SI_STRSIZE]; /* Device name */ 157 | char portName[SI_MAXPORTNAME]; 158 | } SiDevPort; 159 | 160 | typedef struct SiDeviceName { 161 | char name[SI_STRSIZE]; 162 | } SiDeviceName; 163 | 164 | typedef struct SiButtonName { 165 | char name[SI_STRSIZE]; 166 | } SiButtonName; 167 | 168 | typedef struct SiPortName { 169 | char name[SI_STRSIZE]; 170 | } SiPortName; 171 | 172 | typedef enum SiDevTypes { 173 | SI_ALL_TYPES = -1, 174 | SI_UNKNOWN_DEVICE = 0, 175 | SI_SPACEBALL_2003 = 1, 176 | SI_SPACEBALL_3003 = 2, 177 | SI_SPACE_CONTROLLER = 3, 178 | SI_SPACEEXPLORER = 4, 179 | SI_SPACENAVIGATOR_FOR_NOTEBOOKS = 5, 180 | SI_SPACENAVIGATOR = 6, 181 | SI_SPACEBALL_2003A = 7, 182 | SI_SPACEBALL_2003B = 8, 183 | SI_SPACEBALL_2003C = 9, 184 | SI_SPACEBALL_3003A = 10, 185 | SI_SPACEBALL_3003B = 11, 186 | SI_SPACEBALL_3003C = 12, 187 | SI_SPACEBALL_4000 = 13, 188 | SI_SPACEMOUSE_CLASSIC = 14, 189 | SI_SPACEMOUSE_PLUS = 15, 190 | SI_SPACEMOUSE_XT = 16, 191 | SI_CYBERMAN = 17, 192 | SI_CADMAN = 18, 193 | SI_SPACEMOUSE_CLASSIC_PROMO = 19, 194 | SI_SERIAL_CADMAN = 20, 195 | SI_SPACEBALL_5000 = 21, 196 | SI_TEST_NO_DEVICE = 22, 197 | SI_3DX_KEYBOARD_BLACK = 23, 198 | SI_3DX_KEYBOARD_WHITE = 24, 199 | SI_TRAVELER = 25, 200 | SI_TRAVELER1 = 26, 201 | SI_SPACEBALL_5000A = 27, 202 | SI_SPACEDRAGON = 28, 203 | SI_SPACEPILOT = 29, 204 | SI_MB = 30, 205 | SI_SPACEPILOT_PRO = 0xc629, 206 | SI_SPACEMOUSE_PRO = 0xc62b 207 | } SiDevType; 208 | 209 | 210 | 211 | enum SpwRetVal { 212 | SPW_NO_ERROR , /* no error */ 213 | SPW_ERROR, /* error -- function failed */ 214 | SI_BAD_HANDLE, /* invalid 3DxWare handle */ 215 | SI_BAD_ID, /* invalid device ID */ 216 | SI_BAD_VALUE, /* invalid argument value */ 217 | SI_IS_EVENT, /* event is a 3DxWare event */ 218 | SI_SKIP_EVENT, /* skip this 3DxWare event */ 219 | SI_NOT_EVENT, /* event is not a 3DxWare event */ 220 | SI_NO_DRIVER, /* 3DxWare driver is not running */ 221 | SI_NO_RESPONSE, /* 3DxWare driver is not responding */ 222 | SI_UNSUPPORTED, /* the function is unsupported by this version */ 223 | SI_UNINITIALIZED, /* 3DxWare Input Library is uninitialized */ 224 | SI_WRONG_DRIVER, /* incorrect driver for this 3DxWare version */ 225 | SI_INTERNAL_ERROR /* internal 3DxWare error */ 226 | }; 227 | 228 | #pragma pack(pop) /* restore default packing */ 229 | -------------------------------------------------------------------------------- /siappdll/src/syncapi.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SpaceNavigatorEmulator - 3dconnexion-compatible siappdll.dll replacement 3 | Copyright (C) 2014 John Tsiombikas 4 | Copyright (C) 2015 Luke Nuttall 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | #include 20 | #include "syncapi.h" 21 | #include "log.h" 22 | 23 | SpwRetVal SPWAPI SiSyncSendQuery(struct SiHdl *si) 24 | { 25 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 26 | return SPW_NO_ERROR; 27 | } 28 | 29 | enum SpwRetVal SPWAPI SiSyncGetVersion(struct SiHdl *si, SPWuint32 *major, SPWuint32 *minor) 30 | { 31 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 32 | return SPW_NO_ERROR; 33 | } 34 | 35 | enum SpwRetVal SPWAPI SiSyncGetNumberOfFunctions(struct SiHdl *si, SPWuint32 *num_func) 36 | { 37 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 38 | return SPW_NO_ERROR; 39 | } 40 | 41 | enum SpwRetVal SPWAPI SiSyncGetFunction(struct SiHdl *hdl, SPWuint32 index, SPWint32 *abs_func_num, wchar_t *name, SPWuint32 *name_len) 42 | { 43 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 44 | return SPW_NO_ERROR; 45 | } 46 | 47 | enum SpwRetVal SPWAPI SiSyncGetButtonAssignment(struct SiHdl *hdl, SPWuint32 bn_num, SPWint32 *assigned_func_index) 48 | { 49 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 50 | return SPW_NO_ERROR; 51 | } 52 | 53 | enum SpwRetVal SPWAPI SiSyncSetButtonAssignment(struct SiHdl *hdl, SPWuint32 bn_num, SPWint32 func_index) 54 | { 55 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 56 | return SPW_NO_ERROR; 57 | } 58 | 59 | enum SpwRetVal SPWAPI SiSyncSetButtonAssignmentAbsolute(struct SiHdl *hdl, SPWuint32 bn_num, SPWint32 abs_func_num) 60 | { 61 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 62 | return SPW_NO_ERROR; 63 | } 64 | 65 | enum SpwRetVal SPWAPI SiSyncSetButtonName(struct SiHdl *hdl, SPWuint32 bn_num, const wchar_t *name) 66 | { 67 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 68 | return SPW_NO_ERROR; 69 | } 70 | 71 | enum SpwRetVal SPWAPI SiSyncGetAxisLabel(struct SiHdl *hdl, SPWuint32 axis_num, wchar_t *name, SPWuint32 *name_len) 72 | { 73 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 74 | return SPW_NO_ERROR; 75 | } 76 | 77 | enum SpwRetVal SPWAPI SiSyncSetAxisLabel(struct SiHdl *hdl, SPWuint32 axis_num, const wchar_t *name) 78 | { 79 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 80 | return SPW_NO_ERROR; 81 | } 82 | 83 | enum SpwRetVal SPWAPI SiSyncGetOrientation(struct SiHdl *hdl, SPWint32 axes[6]) 84 | { 85 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 86 | return SPW_NO_ERROR; 87 | } 88 | 89 | enum SpwRetVal SPWAPI SiSyncSetOrientation(struct SiHdl *hdl, const SPWint32 axes[6]) 90 | { 91 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 92 | return SPW_NO_ERROR; 93 | } 94 | 95 | enum SpwRetVal SPWAPI SiSyncGetFilter(struct SiHdl *hdl, SiSyncFilter i, SiSyncFilterValue *pv) 96 | { 97 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 98 | return SPW_NO_ERROR; 99 | } 100 | 101 | enum SpwRetVal SPWAPI SiSyncSetFilter(struct SiHdl *hdl, SiSyncFilter i, SiSyncFilterValue v) 102 | { 103 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 104 | return SPW_NO_ERROR; 105 | } 106 | 107 | enum SpwRetVal SPWAPI SiSyncGetAxesState(struct SiHdl *hdl, SiSyncAxesState *pa) 108 | { 109 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 110 | return SPW_NO_ERROR; 111 | } 112 | 113 | enum SpwRetVal SPWAPI SiSyncSetAxesState(struct SiHdl *hdl, SiSyncAxesState a) 114 | { 115 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 116 | return SPW_NO_ERROR; 117 | } 118 | 119 | enum SpwRetVal SPWAPI SiSyncSetInfoLine(struct SiHdl *hdl, SPWint32 duration, const wchar_t *text) 120 | { 121 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 122 | return SPW_NO_ERROR; 123 | } 124 | 125 | enum SpwRetVal SPWAPI SiSyncGetScaleOverall(struct SiHdl *hdl, SPWfloat32 *pv) 126 | { 127 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 128 | return SPW_NO_ERROR; 129 | } 130 | 131 | enum SpwRetVal SPWAPI SiSyncSetScaleOverall(struct SiHdl *hdl, SPWfloat32 v) 132 | { 133 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 134 | return SPW_NO_ERROR; 135 | } 136 | 137 | enum SpwRetVal SPWAPI SiSyncGetScaleTx(struct SiHdl *hdl, SPWfloat32 *pv) 138 | { 139 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 140 | return SPW_NO_ERROR; 141 | } 142 | 143 | enum SpwRetVal SPWAPI SiSyncSetScaleTx(struct SiHdl *hdl, SPWfloat32 v) 144 | { 145 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 146 | return SPW_NO_ERROR; 147 | } 148 | 149 | enum SpwRetVal SPWAPI SiSyncGetScaleTy(struct SiHdl *hdl, SPWfloat32 *pv) 150 | { 151 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 152 | 153 | return SPW_NO_ERROR; 154 | } 155 | 156 | enum SpwRetVal SPWAPI SiSyncSetScaleTy(struct SiHdl *hdl, SPWfloat32 v) 157 | { 158 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 159 | 160 | return SPW_NO_ERROR; 161 | } 162 | 163 | enum SpwRetVal SPWAPI SiSyncGetScaleTz(struct SiHdl *hdl, SPWfloat32 *pv) 164 | { 165 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 166 | return SPW_NO_ERROR; 167 | } 168 | 169 | enum SpwRetVal SPWAPI SiSyncSetScaleTz(struct SiHdl *hdl, SPWfloat32 v) 170 | { 171 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 172 | return SPW_NO_ERROR; 173 | } 174 | 175 | enum SpwRetVal SPWAPI SiSyncGetScaleRx(struct SiHdl *hdl, SPWfloat32 *pv) 176 | { 177 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 178 | 179 | return SPW_NO_ERROR; 180 | } 181 | 182 | enum SpwRetVal SPWAPI SiSyncSetScaleRx(struct SiHdl *hdl, SPWfloat32 v) 183 | { 184 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 185 | 186 | return SPW_NO_ERROR; 187 | } 188 | 189 | enum SpwRetVal SPWAPI SiSyncGetScaleRy(struct SiHdl *hdl, SPWfloat32 *pv) 190 | { 191 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 192 | return SPW_NO_ERROR; 193 | } 194 | 195 | enum SpwRetVal SPWAPI SiSyncSetScaleRy(struct SiHdl *hdl, SPWfloat32 v) 196 | { 197 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 198 | return SPW_NO_ERROR; 199 | } 200 | 201 | enum SpwRetVal SPWAPI SiSyncGetScaleRz(struct SiHdl *hdl, SPWfloat32 *pv) 202 | { 203 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 204 | 205 | return SPW_NO_ERROR; 206 | } 207 | 208 | enum SpwRetVal SPWAPI SiSyncSetScaleRz(struct SiHdl *hdl, SPWfloat32 v) 209 | { 210 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 211 | 212 | return SPW_NO_ERROR; 213 | } 214 | 215 | enum SpwRetVal SPWAPI SiSyncInvokeAbsoluteFunction(struct SiHdl *hdl, SiSyncAbsFunctionNumber i) 216 | { 217 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 218 | 219 | return SPW_NO_ERROR; 220 | } 221 | 222 | enum SpwRetVal SPWAPI SiSyncSetButtonState(struct SiHdl *hdl, SPWuint32 bn_num, SiSyncButtonState state) 223 | { 224 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 225 | 226 | return SPW_NO_ERROR; 227 | } -------------------------------------------------------------------------------- /siappdll/siappdll.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {E3AE0F7F-2BBD-4563-AE22-1A92E11630F0} 23 | siappdll 24 | Win32Proj 25 | 10.0.18362.0 26 | 27 | 28 | 29 | DynamicLibrary 30 | v143 31 | MultiByte 32 | true 33 | 34 | 35 | DynamicLibrary 36 | v141 37 | MultiByte 38 | false 39 | 40 | 41 | DynamicLibrary 42 | v143 43 | MultiByte 44 | 45 | 46 | DynamicLibrary 47 | v141 48 | MultiByte 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | <_ProjectFileVersion>12.0.21005.1 69 | 70 | 71 | $(SolutionDir)$(Configuration)\ 72 | $(Configuration)\ 73 | true 74 | 75 | 76 | true 77 | 78 | 79 | $(SolutionDir)$(Configuration)\ 80 | $(Configuration)\ 81 | false 82 | 83 | 84 | false 85 | 86 | 87 | 88 | Disabled 89 | $(SolutionDir);$(SolutionDir)\include;%(AdditionalIncludeDirectories);C:\Boost\include\boost-1_78 90 | WIN32;_DEBUG;_WINDOWS;_USRDLL;SIAPPDLL_EXPORTS;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions) 91 | true 92 | EnableFastChecks 93 | MultiThreadedDebugDLL 94 | 95 | Level3 96 | EditAndContinue 97 | 4996;%(DisableSpecificWarnings) 98 | 99 | 100 | dinput8.lib;dxguid.lib;comctl32.lib;ws2_32.lib;%(AdditionalDependencies);Shlwapi.lib 101 | siappdll.def 102 | true 103 | Windows 104 | MachineX86 105 | C:\Boost\lib 106 | 107 | 108 | 109 | 110 | Disabled 111 | $(SolutionDir);$(SolutionDir)\include;%(AdditionalIncludeDirectories) 112 | WIN32;_DEBUG;_WINDOWS;_USRDLL;SIAPPDLL_EXPORTS;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions) 113 | EnableFastChecks 114 | MultiThreadedDebugDLL 115 | 116 | 117 | Level3 118 | ProgramDatabase 119 | 4996;%(DisableSpecificWarnings) 120 | 121 | 122 | dinput8.lib;dxguid.lib;comctl32.lib;ws2_32.lib;%(AdditionalDependencies);Shlwapi.lib 123 | siappdll.def 124 | true 125 | Windows 126 | 127 | 128 | 129 | 130 | MaxSpeed 131 | true 132 | $(SolutionDir);$(SolutionDir)\include;%(AdditionalIncludeDirectories) 133 | WIN32;NDEBUG;_WINDOWS;_USRDLL;SIAPPDLL_EXPORTS;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions) 134 | MultiThreadedDLL 135 | true 136 | 137 | Level3 138 | ProgramDatabase 139 | 140 | 141 | dinput8.lib;dxguid.lib;comctl32.lib;ws2_32.lib;%(AdditionalDependencies);Shlwapi.lib 142 | siappdll.def 143 | true 144 | Windows 145 | true 146 | true 147 | MachineX86 148 | 149 | 150 | 151 | 152 | MaxSpeed 153 | true 154 | $(SolutionDir);$(SolutionDir)\include;%(AdditionalIncludeDirectories) 155 | WIN32;NDEBUG;_WINDOWS;_USRDLL;SIAPPDLL_EXPORTS;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions) 156 | MultiThreadedDLL 157 | true 158 | 159 | 160 | Level3 161 | ProgramDatabase 162 | 163 | 164 | dinput8.lib;dxguid.lib;comctl32.lib;ws2_32.lib;%(AdditionalDependencies);Shlwapi.lib 165 | siappdll.def 166 | true 167 | Windows 168 | true 169 | true 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 203 | 204 | 205 | -------------------------------------------------------------------------------- /siappdll/src/siappdll.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SpaceNavigatorEmulator - 3dconnexion-compatible siappdll.dll replacement 3 | Copyright (C) 2014 John Tsiombikas 4 | Copyright (C) 2015 Luke Nuttall 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | #include "config.h" 20 | #include 21 | #include 22 | #include 23 | #include "siappdll.h" 24 | #include "siappdll_impl.h" 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include "log.h" 30 | #include "sock.h" 31 | 32 | #include "MinHook.h" 33 | 34 | #define SHAPE 35 | #define SHAPE_DELAY_MS 30 36 | 37 | extern "C" { 38 | typedef UINT(__stdcall* GETRAWINPUTDEVICEINFOW)(HANDLE, UINT, LPVOID, PUINT); 39 | 40 | GETRAWINPUTDEVICEINFOW fpOldGetRawInput = NULL; 41 | 42 | typedef UINT(WINAPI* GetDeviceList)(PRAWINPUTDEVICELIST pRawInputDeviceList, PUINT puiNumDevices, UINT cbSize); 43 | 44 | GetDeviceList fpOldGetDeviceList = NULL; 45 | } 46 | 47 | bool hookNext = false; 48 | UINT WINAPI DetourGetRawInputDeviceList(PRAWINPUTDEVICELIST pRawInputDeviceList, PUINT puiNumDevices, UINT cbSize) 49 | { 50 | if (hookNext) 51 | { 52 | LOG(TRACE) << "Faking GetRawInputDeviceList"; 53 | hookNext = false; 54 | return 1; 55 | } 56 | else 57 | { 58 | return fpOldGetDeviceList(pRawInputDeviceList, puiNumDevices, cbSize); 59 | } 60 | } 61 | 62 | UINT WINAPI DetourGetRawInputDeviceInfoW(HANDLE hDevice, UINT uiCommand, LPVOID pData, PUINT pcbSize) 63 | { 64 | if (hookNext) 65 | { 66 | LOG(TRACE) << "Faking GetRawInputDeviceInfoW"; 67 | hookNext = false; 68 | return 1; 69 | } 70 | else 71 | { 72 | return fpOldGetRawInput(hDevice, uiCommand, pData, pcbSize); 73 | } 74 | } 75 | 76 | int startHook() 77 | { 78 | // Initialize MinHook. 79 | if (MH_Initialize() != MH_OK) 80 | { 81 | return 1; 82 | } 83 | 84 | // Create a hook in disabled state. 85 | if (MH_CreateHook(&GetRawInputDeviceInfoW, &DetourGetRawInputDeviceInfoW, 86 | reinterpret_cast(&fpOldGetRawInput)) != MH_OK) 87 | { 88 | return 1; 89 | } 90 | if (MH_CreateHook(&GetRawInputDeviceList, &DetourGetRawInputDeviceList, 91 | reinterpret_cast(&fpOldGetDeviceList)) != MH_OK) 92 | { 93 | return 1; 94 | } 95 | 96 | // Enable the hook 97 | if (MH_EnableHook(&GetRawInputDeviceInfoW) != MH_OK) 98 | { 99 | LOG(ERROR) << "Could not hook GetRawInputDeviceInfoW"; 100 | return 1; 101 | } 102 | 103 | // Enable the hook 104 | if (MH_EnableHook(&GetRawInputDeviceList) != MH_OK) 105 | { 106 | LOG(ERROR) << "Could not hook GetRawInputDeviceList"; 107 | return 1; 108 | } 109 | return -1; 110 | } 111 | 112 | typedef struct { 113 | long data[7]; 114 | } motion_t; 115 | 116 | std::deque m_queue; 117 | 118 | HWND tgt_wndw; 119 | 120 | HANDLE ghMutex = NULL; 121 | HANDLE hRcvThread = NULL; 122 | int sock_fd = -1; 123 | 124 | 125 | void clear_context(void) 126 | { 127 | // TODO: clear 128 | // space_ware_message 129 | 130 | sock_close(sock_fd); 131 | if (hRcvThread) { 132 | TerminateThread(hRcvThread, NULL); 133 | WaitForSingleObject(hRcvThread, INFINITE); 134 | CloseHandle(hRcvThread); 135 | } 136 | if (ghMutex) 137 | CloseHandle(ghMutex); 138 | } 139 | 140 | void collectMotionEvent(motion_t m) 141 | { 142 | WaitForSingleObject(ghMutex, INFINITE); 143 | 144 | m_queue.push_back(m); 145 | 146 | ReleaseMutex(ghMutex); 147 | 148 | int ret = PostMessage(tgt_wndw, space_ware_message, SI_MOTION_EVENT, 1); 149 | if (ret == 0) 150 | std::cout << "error " << GetLastError() << "\n"; 151 | LOG(TRACE) << "message send"; 152 | } 153 | 154 | DWORD WINAPI RcvThreadFunction(LPVOID lpParam) 155 | { 156 | int fd = *(int *)lpParam; 157 | 158 | #ifdef SHAPE 159 | ULONGLONG last = GetTickCount64(); 160 | #endif 161 | motion_t m; 162 | memset(&m, 0, sizeof(motion_t)); 163 | 164 | while (1) 165 | { 166 | int buf[8]; 167 | int ret = sock_read(fd, (char*)buf, sizeof(buf)); 168 | if (ret <= 0) 169 | break; 170 | 171 | #ifdef SHAPE 172 | ULONGLONG now = GetTickCount64(); 173 | 174 | if ((now - last) > SHAPE_DELAY_MS) { 175 | long sum = 0; 176 | for (int i = 0; i < 6; i++) 177 | sum |= m.data[i]; 178 | if (sum) { 179 | collectMotionEvent(m); 180 | memset(&m, 0, sizeof(motion_t)); 181 | } 182 | 183 | last = now; 184 | } 185 | #endif 186 | 187 | if (buf[0] == 0) 188 | { 189 | for (int i = 0; i < 7; i++) 190 | #ifdef SHAPE 191 | m.data[i] += buf[i + 1]; 192 | #else 193 | m.data[i] = buf[i + 1]; 194 | 195 | collectMotionEvent(m); 196 | #endif 197 | } 198 | 199 | #if 1 200 | char out[128]; 201 | int ocnt = 0; 202 | 203 | for (int i = 0; i < 7; i++) 204 | ocnt += snprintf(out + ocnt, sizeof(out) - ocnt, "%d ", buf[i]); 205 | ocnt += snprintf(out + ocnt, sizeof(out) - ocnt, "%u ", (unsigned int)buf[7]); 206 | 207 | LOG(TRACE) << out; 208 | #endif 209 | } 210 | 211 | return 0; 212 | } 213 | 214 | BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) 215 | { 216 | switch (ul_reason_for_call) 217 | { 218 | case DLL_PROCESS_ATTACH: 219 | { 220 | LOG(INFO) << "Starting siappdll replacement"; 221 | 222 | auto startedHook = startHook(); 223 | 224 | LOG(INFO) << "Siappdll loaded: "; 225 | char buffer[MAX_PATH]; 226 | if (!FAILED(::GetModuleFileName(::GetModuleHandle("siappdll.dll"), buffer, MAX_PATH))) 227 | { 228 | LOG(INFO) << "Loaded from: "<< buffer; 229 | } 230 | 231 | // We could set this byte as an alternative to hooking the device input functions 232 | // but it's more liable to blow up with different versions of the static libraries included 233 | // in apps using the space navigator sdk 234 | //byte* actualbRawInputFound3DxDevice = (byte *)0x413489; 235 | //*actualbRawInputFound3DxDevice = 1; 236 | } 237 | case DLL_THREAD_ATTACH: 238 | case DLL_THREAD_DETACH: 239 | case DLL_PROCESS_DETACH: 240 | break; 241 | } 242 | return TRUE; 243 | } 244 | 245 | enum SpwRetVal SPWAPI SiInitialize(void) 246 | { 247 | enum SpwRetVal ret = SPW_ERROR; 248 | 249 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 250 | 251 | sock_fd = sock_connect(SOCK_FILE); 252 | if (sock_fd < 0) 253 | { 254 | LOG(ERROR) << "connection to daemon failed"; 255 | goto err; 256 | } 257 | 258 | if (!(space_ware_message = RegisterWindowMessage("SpaceWareMessage00"))) 259 | { 260 | LOG(ERROR) << "failed to register window message"; 261 | goto err; 262 | } 263 | 264 | ghMutex = CreateMutex( 265 | NULL, // default security attributes 266 | FALSE, // initially not owned 267 | NULL); // unnamed mutex 268 | 269 | if (ghMutex == NULL) 270 | { 271 | LOG(ERROR) << "CreateMutex error " << GetLastError(); 272 | goto err; 273 | } 274 | 275 | hRcvThread = CreateThread( 276 | NULL, // default security attributes 277 | 0, // use default stack size 278 | RcvThreadFunction, // thread function name 279 | &sock_fd, // argument to thread function 280 | 0, // use default creation flags 281 | NULL); // returns the thread identifier 282 | 283 | if (!hRcvThread) 284 | { 285 | LOG(ERROR) << "failed to create thread"; 286 | goto err; 287 | } 288 | 289 | initialised = true; 290 | 291 | return SPW_NO_ERROR; 292 | 293 | err: 294 | clear_context(); 295 | 296 | return SPW_ERROR; 297 | } 298 | 299 | SPWbool SiIsInitialized() 300 | { 301 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 302 | return initialised; 303 | } 304 | 305 | void SPWAPI SiTerminate(void) 306 | { 307 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 308 | 309 | clear_context(); 310 | 311 | initialised = false; 312 | } 313 | 314 | void SPWAPI SiGetLibraryInfo(SiVerInfo *info) 315 | { 316 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 317 | info->major = VER_MAJOR; 318 | info->minor = VER_MINOR; 319 | info->build = VER_BUILD; 320 | strcpy(info->version, VER_STR); 321 | info->data[0] = 0; 322 | } 323 | 324 | enum SpwRetVal SPWAPI SiGetDriverInfo(SiVerInfo *info) 325 | { 326 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 327 | info->major = VER_MAJOR; 328 | info->minor = VER_MINOR; 329 | info->build = VER_BUILD; 330 | strcpy(info->version, VER_STR); 331 | info->data[0] = 0; 332 | 333 | return SPW_NO_ERROR; 334 | } 335 | 336 | enum SpwRetVal SPWAPI SiGetDevicePort(int devid, SiDevPort *port) 337 | { 338 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 339 | port->devID = 0; 340 | port->devClass = 341 | port->devType = SI_SPACENAVIGATOR; 342 | strcpy(port->devName, "SpaceNavigatorEmulator"); 343 | strcpy(port->portName, "Pretend Port"); 344 | return SPW_NO_ERROR; 345 | } 346 | 347 | int SPWAPI SiGetNumDevices(void) 348 | { 349 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 350 | return 1; 351 | } 352 | 353 | int SPWAPI SiDeviceIndex(int idx) 354 | { 355 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 356 | return 0; 357 | } 358 | 359 | void SPWAPI SiOpenWinInit(SiOpenData *opendata, void *win) 360 | { 361 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 362 | opendata->win = win; 363 | } 364 | 365 | struct SiHdl *SPWAPI SiOpen(const char *appname, int devid, SiTypeMask *tmask, int mode, SiOpenData *opendata) 366 | { 367 | LOG(TRACE) << "SiOpen called for app: " << appname; 368 | struct SiHdl *si = new SiHdl(); 369 | 370 | if (!si) 371 | { 372 | SpwErrorVal = SPW_ERROR; 373 | return 0; 374 | } 375 | 376 | si->opendata = *opendata; 377 | si->opendata.lib_flag = 1; 378 | si->opendata.trans_ctl = nullptr; 379 | // FIXME - get an actual process id. 380 | si->opendata.pid = 1; 381 | 382 | tgt_wndw = (HWND)opendata->win; 383 | 384 | SpwErrorVal = SPW_NO_ERROR; 385 | return si; 386 | } 387 | 388 | struct SiHdl* SPWAPI SiOpenPort(const char *pAppName, const SiDevPort *pPort, int mode, const SiOpenData *pData) 389 | { 390 | LOG(TRACE) << __FUNCTION__ << " passing to SiOpen"; 391 | // FIXME - copy data instead on const cast 392 | return SiOpen(pAppName, 0, nullptr, mode, const_cast(pData)); 393 | } 394 | 395 | enum SpwRetVal SPWAPI SiClose(struct SiHdl *si) 396 | { 397 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 398 | 399 | delete si; 400 | return SPW_NO_ERROR; 401 | } 402 | 403 | int SPWAPI SiGetDeviceID(struct SiHdl *si) 404 | { 405 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 406 | SpwErrorVal = SPW_NO_ERROR; 407 | return 0; /* TODO */ 408 | } 409 | 410 | enum SpwRetVal SPWAPI SiGetDeviceImageFileName(struct SiHdl *si, char *name, unsigned long *maxlen) 411 | { 412 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 413 | name[0] = 0; 414 | *maxlen = 0; 415 | return SPW_NO_ERROR; /* TODO */ 416 | } 417 | 418 | SpwRetVal SPWAPI SiGetDeviceInfo(struct SiHdl *si, SiDevInfo *info) 419 | { 420 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 421 | info->dev_type = SI_SPACENAVIGATOR; 422 | info->num_buttons = 2; 423 | info->num_degrees = 6; 424 | info->can_beep = 0; 425 | return SPW_NO_ERROR; 426 | } 427 | 428 | enum SpwRetVal SPWAPI SiGetDeviceName(struct SiHdl *si, SiDeviceName *name) 429 | { 430 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 431 | strcpy(name->name, "SpaceNavigatorEmulator"); 432 | return SPW_NO_ERROR; 433 | } 434 | 435 | 436 | enum SpwRetVal SPWAPI SiGrabDevice(struct SiHdl *si, SPWbool exclusive) 437 | { 438 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 439 | return SPW_NO_ERROR; 440 | } 441 | 442 | enum SpwRetVal SPWAPI SiReleaseDevice(struct SiHdl *si) 443 | { 444 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 445 | return SPW_NO_ERROR; 446 | } 447 | 448 | enum SpwRetVal SPWAPI SiRezero(struct SiHdl *si) 449 | { 450 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 451 | return SPW_NO_ERROR; 452 | } 453 | 454 | enum SpwRetVal SPWAPI SiBeep(struct SiHdl *si, char *str) 455 | { 456 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 457 | return SPW_NO_ERROR; 458 | } 459 | 460 | enum SpwRetVal SPWAPI SiSetLEDs(struct SiHdl *si, unsigned long mask) 461 | { 462 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 463 | return SPW_NO_ERROR; 464 | } 465 | 466 | enum SpwRetVal SPWAPI SiSetUiMode(struct SiHdl *si, unsigned long mode) 467 | { 468 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 469 | return SPW_NO_ERROR; 470 | } 471 | 472 | #define CALL_CB(cb, od, evdata, ev) cb.func(od, evdata, ev, cb.cls) 473 | 474 | int SPWAPI SiDispatch(struct SiHdl *si, SiGetEventData *data, SiSpwEvent *ev, SiSpwHandlers *handlers) 475 | { 476 | LOG(TRACE) << "Stub called: " << __FUNCTION__ << " - event: " << ev->type; 477 | 478 | if (handlers != nullptr) 479 | { 480 | switch (ev->type) { 481 | case SI_BUTTON_EVENT: 482 | return CALL_CB(handlers->button, &si->opendata, data, ev); 483 | case SI_MOTION_EVENT: 484 | if (handlers->motion.func != nullptr) 485 | return CALL_CB(handlers->motion, &si->opendata, data, ev); 486 | case SI_COMBO_EVENT: 487 | return CALL_CB(handlers->combo, &si->opendata, data, ev); 488 | case SI_ZERO_EVENT: 489 | return CALL_CB(handlers->zero, &si->opendata, data, ev); 490 | default: 491 | break; 492 | } 493 | } 494 | return 0; 495 | } 496 | 497 | void SPWAPI SiGetEventWinInit(SiGetEventData *evdata, unsigned int msg, unsigned int wparam, long lparam) 498 | { 499 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 500 | if (evdata == nullptr) 501 | { 502 | LOG(ERROR) << __FUNCTION__ << " called with null pointer for event storage"; 503 | } 504 | evdata->msg = msg; 505 | evdata->lparam = lparam; 506 | evdata->wparam = wparam; 507 | } 508 | 509 | SpwRetVal SPWAPI SiGetEvent(struct SiHdl *si, int flags, const SiGetEventData *data, SiSpwEvent *ev) 510 | { 511 | LOG(TRACE) << "called: " << __FUNCTION__; 512 | 513 | // If we weren't given a valid pointer, we return bad value. 514 | if (!ev || !si || !data) 515 | return SI_BAD_VALUE; 516 | 517 | WaitForSingleObject(ghMutex, INFINITE); 518 | bool empty = m_queue.empty(); 519 | ReleaseMutex(ghMutex); 520 | if (empty) 521 | return SI_NOT_EVENT; 522 | 523 | if (data->msg == space_ware_message) 524 | { 525 | long buf[7]; 526 | std::deque ::size_type size; 527 | 528 | WaitForSingleObject(ghMutex, INFINITE); 529 | 530 | motion_t m = m_queue.front(); 531 | memcpy(buf, m.data, sizeof(buf)); 532 | 533 | m_queue.pop_front(); 534 | 535 | size = m_queue.size(); 536 | 537 | ReleaseMutex(ghMutex); 538 | 539 | LOG(TRACE) << "Queue size: " << size; 540 | 541 | // completely fake an event 542 | if (data->wparam == SI_MOTION_EVENT) 543 | { 544 | ev->type = data->wparam; 545 | ev->u.spw_data.button.last = 0; 546 | ev->u.spw_data.button.current = 0; 547 | ev->u.spw_data.button.release = 0; 548 | ev->u.spw_data.button.pressed = 0; 549 | 550 | ev->u.spw_data.motion[0] = buf[0]; 551 | ev->u.spw_data.motion[1] = buf[1]; 552 | ev->u.spw_data.motion[2] = buf[2]; 553 | ev->u.spw_data.motion[3] = buf[3]; 554 | ev->u.spw_data.motion[4] = buf[4]; 555 | ev->u.spw_data.motion[5] = buf[5]; 556 | 557 | ev->u.spw_data.period = buf[6]; 558 | #if 1 // maybe not needed, but original test program - jet.exe reaction to long period is not good, fusion360 reaction is good 559 | if (ev->u.spw_data.period > 500) 560 | ev->u.spw_data.period = 0; 561 | #endif 562 | 563 | if (data->wparam == SI_MOTION_EVENT) 564 | hookNext = true; 565 | } 566 | else if (data->wparam == SI_BUTTON_EVENT) 567 | { 568 | #if 0 569 | ev->type = data->wparam; 570 | ev->u.spw_data.button.last = record.buttonData.last; 571 | ev->u.spw_data.button.current = record.buttonData.current; 572 | ev->u.spw_data.button.release = record.buttonData.release; 573 | ev->u.spw_data.button.pressed = record.buttonData.pressed; 574 | ev->u.spw_data.motion[0] = 0; 575 | ev->u.spw_data.motion[1] = 0; 576 | ev->u.spw_data.motion[2] = 0; 577 | ev->u.spw_data.motion[3] = 0; 578 | ev->u.spw_data.motion[4] = 0; 579 | ev->u.spw_data.motion[5] = 0; 580 | ev->u.spw_data.period = 0; 581 | #endif 582 | } 583 | else if (data->wparam == SI_BUTTON_PRESS_EVENT || data->wparam == SI_BUTTON_RELEASE_EVENT) 584 | { 585 | ev->type = data->wparam; 586 | ev->u.hwButtonEvent.buttonNumber = data->lparam; 587 | } 588 | 589 | return SI_IS_EVENT; 590 | } 591 | else 592 | { 593 | return SI_NOT_EVENT; 594 | } 595 | } 596 | 597 | SpwRetVal SPWAPI SiPeekEvent(struct SiHdl *si, int flags, const SiGetEventData *data, SiSpwEvent *ev) 598 | { 599 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 600 | 601 | // FIXME - implement 602 | return SPW_NO_ERROR; 603 | } 604 | 605 | SPWbool SPWAPI SiIsSpaceWareEvent(const SiGetEventData *data, struct SiHdl *si) 606 | { 607 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 608 | return data->msg == space_ware_message; 609 | } 610 | 611 | int SPWAPI SiButtonPressed(SiSpwEvent *ev) 612 | { 613 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 614 | 615 | long pressed = ev->u.spw_data.button.pressed; 616 | 617 | for (unsigned int i = 0; i < 32; i++) 618 | { 619 | if ((1 << i) & pressed) 620 | { 621 | return i; 622 | } 623 | } 624 | return 0; 625 | } 626 | 627 | int SPWAPI SiButtonReleased(SiSpwEvent *ev) 628 | { 629 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 630 | 631 | long released = ev->u.spw_data.button.release; 632 | 633 | for (unsigned int i = 0; i < 32; i++) 634 | { 635 | if ((1 << i) & released) 636 | { 637 | return i; 638 | } 639 | } 640 | return 0; 641 | } 642 | 643 | enum SpwRetVal SPWAPI SiGetButtonName(struct SiHdl *si, unsigned long bnum, SiButtonName *name) 644 | { 645 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 646 | strcpy(name->name, "Smoooth buttony text"); 647 | return SPW_NO_ERROR; 648 | } 649 | 650 | void *SPWAPI SiGetCompanyIcon(void) 651 | { 652 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 653 | 654 | return NULL; 655 | } 656 | 657 | enum SpwRetVal SPWAPI SiGetCompanyLogoFileName(char *name, unsigned long *maxlen) 658 | { 659 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 660 | 661 | return SPW_ERROR; 662 | } 663 | 664 | 665 | static const char *errnames[] = { 666 | "no error", 667 | "error -- function failed", 668 | "invalid 3DxWare handle", 669 | "invalid device ID", 670 | "invalid argument value", 671 | "event is a 3DxWare event", 672 | "skip this 3DxWare event", 673 | "event is not a 3DxWare event", 674 | "3DxWare driver is not running", 675 | "3DxWare driver is not responding", 676 | "the function is unsupported by this version", 677 | "3DxWare Input Library is uninitialized", 678 | "incorrect driver for this 3DxWare version", 679 | "internal 3DxWare error" 680 | }; 681 | 682 | const char *SPWAPI SpwErrorString(enum SpwRetVal err) 683 | { 684 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 685 | return errnames[(int)err]; 686 | } 687 | 688 | /* deprecated */ 689 | enum SpwRetVal SiSetTypeMask(SiTypeMask *mask, int type1, ...) 690 | { 691 | LOG(TRACE) << "Stub called: " << __FUNCTION__; 692 | return SPW_NO_ERROR; 693 | } 694 | 695 | --------------------------------------------------------------------------------