RvEYoda Posted April 2, 2011 Share Posted April 2, 2011 (edited) Been away from the forum for a while but I read up on things every now and then. Some of you might know me, but most probably don't. Long story short: I got an idea for a new hotas/keyboard/*anything* programming/profiler tool/utility. (wow thats a lot of slashes!). We all sit with tons of different sim gear like throttle, stick, pedals (wheels anyone? ;)) and the list goes on. Some of these things come with decent programming/profiling tools, but seriously, none are really that powerful, and worst is that in almost every setup there are different tools for each hardware, they get non-backwards-compatible upgrades (for the profiles). On top of that the hardware don't play too well together. For example 1. Can my new game really support N number of devices? 2. Can my new game let different hardware act as modifiers for each other etc?. Now why can't normal profiler software support basic gestures like "double-clicking" or acting on different time-dependant conditions? MAYBE some do, maybe some obscure ones for parts of your hardware. ---------------- Ok so if you actually have read all the above without getting tired or bored, what is the point of this post? Let's say we make a new software (or more correctly named some kind of utility programming library), compatible with ALL directx devices (keyboard, mice, joysticks, wheels etc). How to do this? It is likely simpler than one would expect. My idea (that I need advice on and hopefully more devs) is this: 1. ask DirectX (DirectInput) what *real* devices are present 2. create a single *virtual* device for sending back commands 3. ask directinput to notify our program on any changes in the *real* devices we want to check. 4. act on arbitrary changes as if they were just normal program events. 5. send desired commands on *virtual* device Creating a hotas cougar profile in c++...lovely :). (Or maybe C#, I normally prefer Java but for low level global controller access then... maybe later we can wrap it in JNI) Example of multiple devices acting together: if (x52.throttle.slider(1).accelleration()< a && hCougar.stick.button(5).isDown()) // airbrakesOut(); or as a callback if preferred void onChange(Event& e) { globalState.update(e); Interface * interface = e->getDevice()->getInterface(); MappingList * activeMappings = mappings.getMappings(interface); if (activeMappings->length()>0) respond(globalState, MappingList); } I estimate such a program would be really short, maybe a few hundred lines (tops) for the actual framework. Then if anyone nice wants to add a GUI (boring... ) and profile file reader/writer that would be cool as well. ---------- END RANT Suggestions? Want to help? Post! Edited April 2, 2011 by =RvE=Yoda S = SPARSE(m,n) abbreviates SPARSE([],[],[],m,n,0). This generates the ultimate sparse matrix, an m-by-n all zero matrix. - Matlab help on 'sparse' Link to comment Share on other sites More sharing options...
SilentEagle Posted April 3, 2011 Share Posted April 3, 2011 This is an interesting concept! I'm not quite sure what you are proposing here. Would this be replacing cougar control panel/foxy for the couger, TARGET for the warthog, SST software for saitek, logitech software for keyboard, mouse, etc. and combine it all in one program with tabs for the different kinds of directx input devices? Seems like more than a few hundred lines of work to replace all that software functionality. In any case, you know I don't have a high level of programming knowledge, but I'd be happy to help out however I can with testing and problem solving. Link to comment Share on other sites More sharing options...
RvEYoda Posted April 3, 2011 Author Share Posted April 3, 2011 This is an interesting concept! I'm not quite sure what you are proposing here. Would this be replacing cougar control panel/foxy for the couger, TARGET for the warthog, SST software for saitek, logitech software for keyboard, mouse, etc. and combine it all in one program with tabs for the different kinds of directx input devices? You would not need any other profiling software, not even necessarily programming different devices in different tabs - all the devices can be programmed in the same code (and you can for example use a button on an x52 as a modifier for a functionality on your CH pedals etc). It would be a direct programming approach instead of wrapping it in a semi-programmable profiler application. You would get access to each of the devices' *states* and could write simple conditional statements as if you were doing very basic programming. Seems like more than a few hundred lines of work to replace all that software functionality. In any case, you know I don't have a high level of programming knowledge, but I'd be happy to help out however I can with testing and problem solving. The thing is that you don't need to replace or rewrite any of the functionality. You only need to Give access to 1. Read current state 2. Input virtual keystrokes ( that your game reads) These two things are what I mean will be only a few hundred lines (in fact it might even be below 100 lines of code, much shorter than my previous projects). What would require more work would be simplifications of profiles and GUIs, that could be a lot more code. 1 S = SPARSE(m,n) abbreviates SPARSE([],[],[],m,n,0). This generates the ultimate sparse matrix, an m-by-n all zero matrix. - Matlab help on 'sparse' Link to comment Share on other sites More sharing options...
Bvoiash Posted April 3, 2011 Share Posted April 3, 2011 Hi Yoda, quite an interesting proposition that you have here :). Unfortunately though, at the moment I don't know as to whether I would be able to give you a hand with this. As I'm still planning to add more features to EFFSSI among other reasons. Will let you know though when I'm able to give you some help with this :). Link to comment Share on other sites More sharing options...
RvEYoda Posted April 3, 2011 Author Share Posted April 3, 2011 Ill see if I can make a prototype after LLTM next weekend :P S = SPARSE(m,n) abbreviates SPARSE([],[],[],m,n,0). This generates the ultimate sparse matrix, an m-by-n all zero matrix. - Matlab help on 'sparse' Link to comment Share on other sites More sharing options...
RvEYoda Posted April 12, 2011 Author Share Posted April 12, 2011 (edited) Looking at it more closer now, I have solved part 1 but am still working on part 2, which is turning out to be quite difficult... 1. So detecting multiple controller input and creating conditions on when to react on each turns out to be fairly simple 2. But actually inputing something back is more difficult than I expected. :/. What I would like to do is to create three virtual inputs: virtual mouse input, virtual keyboard input and virtual joystick input. The first two are not too hard as windows has decent methods for doing this, however creating a virtual joystick seems to be harder than I expect. It seems like u actually have to make windows believe that you have connected a new hardware HID/usb device and then have that device give input. If anyone has some programming suggestions on how to create a virtual joystick for emulated input, then that would solve the last problem. So far I have not found anything for it but I'm still looking. update: This guy here has done part 2 http://ppjoy.blogspot.com/, but the code is not open source and from what I can tell there is no plan to make it so. Also what is worse is that creating a virtual joystick device means you must create a device driver, which for windows 7 in turn has to be (unless you specifically boot windows 7 into test mode) digitally signed......and for that you must pay microsoft a yearly fee :P. So it looks like my first go with this software will only allow: 1. Read and conditionalize events from all directinput devices (by using directinput http://msdn.microsoft.com/en-us/library/ee418273(v=vs.85).aspx) 2. Input virtual mouse and keyboard events (by using windows functions SendInput http://msdn.microsoft.com/en-us/library/ms646310(v=vs.85).aspx) (2b. Later, I wish to also be able to create virtual joystick input, see text above to see why it's not possible to make atm.) Google found a neat demonstration on how to use the SendInput function in a forum post :) (http://stackoverflow.com/questions/3726812/how-to-send-unicode-keys-with-c-keybd-event) KEYBDINPUT kb={0}; INPUT Input={0}; // down kb.wScan = 0x00c5; kb.dwFlags = KEYEVENTF_UNICODE; Input.type = INPUT_KEYBOARD; Input.ki = kb; ::SendInput(1,&Input,sizeof(Input)); // up kb.wScan = 0x00c5; kb.dwFlags = KEYEVENTF_UNICODE|KEYEVENTF_KEYUP; Input.type = INPUT_KEYBOARD; Input.ki = kb; ::SendInput(1,&Input,sizeof(Input)); Edited April 12, 2011 by =RvE=Yoda S = SPARSE(m,n) abbreviates SPARSE([],[],[],m,n,0). This generates the ultimate sparse matrix, an m-by-n all zero matrix. - Matlab help on 'sparse' Link to comment Share on other sites More sharing options...
skeemo Posted April 12, 2011 Share Posted April 12, 2011 update: This guy here has done part 2 http://ppjoy.blogspot.com/, but the code is not open source and from what I can tell there is no plan to make it so. Also what is worse is that creating a virtual joystick device means you must create a device driver, which for windows 7 in turn has to be (unless you specifically boot windows 7 into test mode) digitally signed......and for that you must pay microsoft a yearly fee :P. This was the first thing i was thinking about when i started to read your thread, that you need a driver. And that cannot be achieved without signing it in Win7, especially x64. So there is testmode. This is the point where you cannot address all users. I twiddled around with PPJoy several times, and yes it is working in test mode, but i dont have a good feeling using it that way. And it isn't a plug-and-play stuff anyway. Link to comment Share on other sites More sharing options...
RvEYoda Posted April 12, 2011 Author Share Posted April 12, 2011 This was the first thing i was thinking about when i started to read your thread, that you need a driver. And that cannot be achieved without signing it in Win7, especially x64. So there is testmode. This is the point where you cannot address all users. I twiddled around with PPJoy several times, and yes it is working in test mode, but i dont have a good feeling using it that way. And it isn't a plug-and-play stuff anyway. Yeah, same, I think it is too much work for most people. However if the program I/we make initially supports only virtual mouse and keyboard emulation, we can then later expand it to also a virtual joystick for those running test mode. S = SPARSE(m,n) abbreviates SPARSE([],[],[],m,n,0). This generates the ultimate sparse matrix, an m-by-n all zero matrix. - Matlab help on 'sparse' Link to comment Share on other sites More sharing options...
RvEYoda Posted April 12, 2011 Author Share Posted April 12, 2011 (edited) Began coding the stuff, but I've run into a strange problem. I've tried as best as I can to follow the directinput guides out there, here is what I have so far: #include "stdafx.h" #include "conio.h" #include "iostream" #include "dinput.h" #include "vector" using std::vector; using std::cout; using std::wcout; using std::endl; typedef LPDIRECTINPUT8 DinputInterface; typedef LPCDIDEVICEINSTANCE InputDeviceID; typedef LPDIRECTINPUTDEVICE8 InputDevice; BOOL CALLBACK addDevice(InputDeviceID device, LPVOID pvRef); vector<InputDeviceID> deviceIDs = vector<InputDeviceID>(); vector<InputDevice> devices = vector<InputDevice>(); HWND thisWindow; int _tmain(int argc, _TCHAR* argv[]) { // Check our app's window thisWindow = GetActiveWindow(); // The DirectInput interface DinputInterface dinputInterface; const HRESULT res1 = DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&dinputInterface, NULL); if (FAILED(res1)) { cout << endl << "Creation of dx interface failed"; _getch(); return 0; } // Get the DirectInput deviceIDs const HRESULT res2 = dinputInterface->EnumDevices(DI8DEVCLASS_GAMECTRL, addDevice, NULL, DIEDFL_ATTACHEDONLY); if (!FAILED(res2)) { // Create a device for each deviceID for each(InputDeviceID id in deviceIDs) { InputDevice dev = NULL; const HRESULT resDev = dinputInterface->CreateDevice(id->guidInstance, &dev, NULL); if (!FAILED(resDev)) { /*dev->SetDataFormat(&c_dfDIJoystick); dev->SetCooperativeLevel(thisWindow, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND); dev->Acquire(); dev->Poll(); DIJOYSTATE curState; dev->GetDeviceState(sizeof(DIJOYSTATE), &curState); cout << endl << curState.lZ; devices.push_back(dev);*/ } else if(DIERR_DEVICENOTREG == resDev) { cout << endl << "Failed to create device"; } } // Release all memory and references for each (InputDevice dev in devices) { dev->Release(); } devices.clear(); } else { cout << endl << "Creating Device IDs failed"; } deviceIDs.clear(); dinputInterface->Release(); // Wait for test window to close _getch(); return 0; } BOOL CALLBACK addDevice(InputDeviceID id, LPVOID pvRef) { deviceIDs.push_back(id); GUID instanceGuid = id->guidInstance; GUID productGuid = id->guidProduct; wcout << endl << "_GUID DATA_"; wcout << endl << "iguid.d1: " << instanceGuid.Data1 << endl << "iguid.d2: " << instanceGuid.Data2 << endl << "iguid.d3: " << instanceGuid.Data3 << endl << "iguid.d4: " << instanceGuid.Data4; wcout << endl << "pguid.d1: " << productGuid.Data1 << endl << "pguid.d2: " << productGuid.Data2 << endl << "pguid.d3: " << productGuid.Data3 << endl << "pguid.d4: " << productGuid.Data4; wcout << endl << "_DEVICE DATA_"; wcout << endl << "devtype: " << id->dwDevType << endl << "prodname: " << id->tszProductName << endl << "instancename: " << id->tszInstanceName; wcout << endl; return DIENUM_CONTINUE; } It fails on "dinputInterface->CreateDevice(...." and I have no idea why. It says DIERR_DEVICENOTREG, or "Device not Registered", but I have absolutely no idea what that means, if a device is registered or not :P. The devices are all connected and working fine. The program outputs: _GUID DATA_ iguid.d1: 2519117328 iguid.d2: 63399 iguid.d3: 4574 iguid.d4: 001FF864 pguid.d1: 67109967 pguid.d2: 0 pguid.d3: 0 pguid.d4: 001FF84C _DEVICE DATA_ devtype: 66068 prodname: Thrustmaster HOTAS Cougar instancename: Thrustmaster HOTAS Cougar _GUID DATA_ iguid.d1: 3723248736 iguid.d2: 25704 iguid.d3: 4576 iguid.d4: 001FF864 pguid.d1: 3008431183 pguid.d2: 0 pguid.d3: 0 pguid.d4: 001FF84C _DEVICE DATA_ devtype: 66076 prodname: F16 MFD 1 instancename: F16 MFD 1 _GUID DATA_ iguid.d1: 3723248736 iguid.d2: 25704 iguid.d3: 4576 iguid.d4: 001FF864 pguid.d1: 3008496719 pguid.d2: 0 pguid.d3: 0 pguid.d4: 001FF84C _DEVICE DATA_ devtype: 66076 prodname: F16 MFD 2 instancename: F16 MFD 2 _GUID DATA_ iguid.d1: 3833754032 iguid.d2: 48150 iguid.d3: 4574 iguid.d4: 001FF864 pguid.d1: 123471523 pguid.d2: 0 pguid.d3: 0 pguid.d4: 001FF84C _DEVICE DATA_ devtype: 66328 prodname: Saitek X52 Flight Control System instancename: Saitek X52 Flight Control System Failed to create device Failed to create device Failed to create device Failed to create device Update: AHA. Apparently MS has decided that you can only run CreateDevice inside the callback given at the enumerate-call (else u get the error above). Either that or I miss something else. What my guess is that the call to enumerate is blocking, and then some "CreateDevice"-allowed DX thread actually runs the callback instead of the main thread, and only it has the permissions to create a device......regardless....problem solved. Edited April 12, 2011 by =RvE=Yoda S = SPARSE(m,n) abbreviates SPARSE([],[],[],m,n,0). This generates the ultimate sparse matrix, an m-by-n all zero matrix. - Matlab help on 'sparse' Link to comment Share on other sites More sharing options...
RvEYoda Posted April 12, 2011 Author Share Posted April 12, 2011 (edited) Success :) I can now read any axis and any button of any device Sample output: _GUID DATA_ iguid.d1: 2519117328 iguid.d2: 63399 iguid.d3: 4574 iguid.d4: 0033F6F4 pguid.d1: 67109967 pguid.d2: 0 pguid.d3: 0 pguid.d4: 0033F704 _DEVICE DATA_ devtype: 66068 prodname: Thrustmaster HOTAS Cougar instancename: Thrustmaster HOTAS Cougar _GUID DATA_ iguid.d1: 3723248736 iguid.d2: 25704 iguid.d3: 4576 iguid.d4: 0033F6F4 pguid.d1: 3008431183 pguid.d2: 0 pguid.d3: 0 pguid.d4: 0033F704 _DEVICE DATA_ devtype: 66076 prodname: F16 MFD 1 instancename: F16 MFD 1 _GUID DATA_ iguid.d1: 3723248736 iguid.d2: 25704 iguid.d3: 4576 iguid.d4: 0033F6F4 pguid.d1: 3008496719 pguid.d2: 0 pguid.d3: 0 pguid.d4: 0033F704 _DEVICE DATA_ devtype: 66076 prodname: F16 MFD 2 instancename: F16 MFD 2 _GUID DATA_ iguid.d1: 3833754032 iguid.d2: 48150 iguid.d3: 4574 iguid.d4: 0033F6F4 pguid.d1: 123471523 pguid.d2: 0 pguid.d3: 0 pguid.d4: 0033F704 _DEVICE DATA_ devtype: 66328 prodname: Saitek X52 Flight Control System instancename: Saitek X52 Flight Control System Pressing button nr: 22 Pressing button nr: 22 Pressing button nr: 22 Pressing button nr: 20 Pressing button nr: 20 Pressing button nr: 20 Pressing button nr: 19 Pressing button nr: 29 Pressing button nr: 29 Pressing button nr: 29 Pressing button nr: 29 Pressing button nr: 29 Pressing button nr: 29 Pressing button nr: 6 Pressing button nr: 6 Pressing button nr: 6 Pressing button nr: 6 Test code below. Going to start working on buffered reading later or tomorrow: #include "stdafx.h" #include "conio.h" #include "iostream" #include "dinput.h" #include "vector" using std::vector; using std::cout; using std::wcout; using std::endl; typedef LPDIRECTINPUT8 DinputInterface; typedef LPCDIDEVICEINSTANCE InputDeviceID; typedef LPDIRECTINPUTDEVICE8 InputDevice; const size_t bufferSize_numItems = 20; HWND thisWindow; DinputInterface dinputInterface; BOOL CALLBACK addDevice(InputDeviceID device, LPVOID pvRef); vector<InputDevice> devices = vector<InputDevice>(); int _tmain(int argc, _TCHAR* argv[]) { // Check our app's window thisWindow = GetActiveWindow(); // The DirectInput interface const HRESULT res1 = DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&dinputInterface, NULL); if (FAILED(res1)) { cout << endl << "Creation of dx interface failed"; _getch(); return 0; } // Get the DirectInput deviceIDs const HRESULT res2 = dinputInterface->EnumDevices(DI8DEVCLASS_GAMECTRL, addDevice, NULL, DIEDFL_ATTACHEDONLY); if (SUCCEEDED(res2)) { // Create a device for each deviceID for (size_t i = 0; i < devices.size(); i++) { InputDevice dev = devices[i]; while (i==3) { dev->Poll(); DIJOYSTATE curState; dev->GetDeviceState(sizeof(DIJOYSTATE), &curState); /* cout << endl << curState.lX; cout << endl << curState.lY; cout << endl << curState.lZ; cout << endl << curState.lRx; cout << endl << curState.lRz;*/ // cout << endl << curState.lRy; if (curState.rgbButtons[21]) { break; } for (size_t i = 0; i < 32; i++) { if (curState.rgbButtons[i]) { cout << endl << "Pressing button nr: " << i; } } Sleep(1); } } // Release all memory and references for (size_t i = 0; i < devices.size(); i++) { devices[i]->Release(); } devices.clear(); } else { cout << endl << "Creating Device IDs failed"; } dinputInterface->Release(); _getch(); return 0; } BOOL CALLBACK addDevice(InputDeviceID id, LPVOID pvRef) { InputDevice dev = NULL; const HRESULT resDev = dinputInterface->CreateDevice(id->guidInstance, &dev, NULL); devices.push_back(dev); if(SUCCEEDED(resDev)) { wcout << endl << "_GUID DATA_"; wcout << endl << "iguid.d1: " << id->guidInstance.Data1 << endl << "iguid.d2: " << id->guidInstance.Data2 << endl << "iguid.d3: " << id->guidInstance.Data3 << endl << "iguid.d4: " << id->guidInstance.Data4; wcout << endl << "pguid.d1: " << id->guidProduct.Data1 << endl << "pguid.d2: " << id->guidProduct.Data2 << endl << "pguid.d3: " << id->guidProduct.Data3 << endl << "pguid.d4: " << id->guidProduct.Data4; wcout << endl << "_DEVICE DATA_"; wcout << endl << "devtype: " << id->dwDevType << endl << "prodname: " << id->tszProductName << endl << "instancename: " << id->tszInstanceName; wcout << endl; DIPROPDWORD dipdw; dipdw.diph.dwSize = sizeof(DIPROPDWORD); dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); dipdw.diph.dwObj = 0; dipdw.diph.dwHow = DIPH_DEVICE; dipdw.dwData = bufferSize_numItems; dev->SetCooperativeLevel(thisWindow, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND); dev->SetDataFormat(&c_dfDIJoystick); dev->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph); dev->Acquire(); } else { cout << endl << "Failed to create device"; } return DIENUM_CONTINUE; } Edited April 12, 2011 by =RvE=Yoda S = SPARSE(m,n) abbreviates SPARSE([],[],[],m,n,0). This generates the ultimate sparse matrix, an m-by-n all zero matrix. - Matlab help on 'sparse' Link to comment Share on other sites More sharing options...
Moa Posted April 13, 2011 Share Posted April 13, 2011 Hi Yoda. Another amazing project from you, as always. There is a Java library that amalgamates Joysticks, keyboards etc. On Windows it uses DirectInput http://java.net/projects/jinput/ (think this might be the old site) Forums about jinput: http://www.java-gaming.org/index.php?board=27.0 This library used to be rubbish (would throw NullPointerException on start) but a few months ago I tried it again and it worked with my Cougar. I don't think it would work fully with a Warthog as the Warthog has more buttons than DirectInput could enumerate (although this may have changed) - which I think is why LockOn couldn't see some of the buttons last time I tried setting them in-game (perhaps I'm wrong here, it was a while since I tried). Link to comment Share on other sites More sharing options...
RvEYoda Posted April 13, 2011 Author Share Posted April 13, 2011 (edited) Yeah the issue seems to be that most devices don't necessarily report all their buttons ans DirectInput buttons (as you say cause DirectInput only supports 32 buttons and 8 axii per device!) For example my X52 throttle (which I use together with an fssb r2 cougar stick) reports some buttons as a mouse by default etc. But I should be able to get around that :) I think I would prefer coding the "reading part" on my own, but if jinput has good facilities for inputing stuff back that would be nice, but I am already able to emulate keyboard buttons freely, so the question is only if jinput can create a virtual joystick device and emulate input from it.. One of the problems with Jinput when I used it last time is that it does not detect global input for all devices (only joysticks), so for example the input coming from the saitek mouse (that is part on the x52 throttle) would not be registered when the UPP is minimized if I used Jinput. Update: New OO test code running which basically allows me to map any arbitrary C++ function to a key event. #include "stdafx.h" #include "DID_headers.h" using namespace Yoda_DID; const size_t bufferSize_numItems = 20; DinputInterface dinputInterface; vector<DID_Joystick> joysticks = vector<DID_Joystick>(); vector<DID_Mouse> mice = vector<DID_Mouse>(); vector<DID_Other> others = vector<DID_Other>(); BOOL CALLBACK enumJoystickCallback(InputDeviceID, LPVOID); BOOL CALLBACK enumMouseCallback(InputDeviceID, LPVOID); BOOL CALLBACK enumOtherCallback(InputDeviceID, LPVOID); void releaseAllDevices(); void testBtn1P() { cout << endl << "PR btn 1"; } void testBtn1H() { cout << endl << "HL btn 1"; } void testBtn1R() { cout << endl << "RL btn 1"; } int _tmain(int argc, _TCHAR* argv[]) { // The DirectInput interface DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&dinputInterface, NULL); // Create the DirectInput devices dinputInterface->EnumDevices(DI8DEVCLASS_GAMECTRL, enumJoystickCallback, NULL, DIEDFL_ATTACHEDONLY); // Test some input joysticks[1].button(0).assignCallback_onKeyDown(&testBtn1P); // test callback to be displayed when button is first pressed down joysticks[1].button(0).assignCallback_onKeyHeld(&testBtn1H); // test callback to be displayed while button is held down (maybe someone needs this? ) joysticks[1].button(0).assignCallback_onKeyReleased(&testBtn1R); // test callback to be displayed when button is released bool toRun = true; while (toRun) { for (size_t i = 0; i < joysticks.size(); i++) { DID_Joystick& dev = joysticks[i]; dev.updateState(); if (dev.button(20).isPressed() && dev.button(23).isPressed()) { toRun = false; } } Sleep(1); } releaseAllDevices(); dinputInterface->Release(); _getch(); return 0; } void releaseAllDevices() { for (size_t i = 0; i < joysticks.size(); i++) { joysticks[i].release(); } for (size_t i = 0; i < mice.size(); i++) { mice[i].release(); } for (size_t i = 0; i < others.size(); i++) { others[i].release(); } } BOOL CALLBACK enumJoystickCallback(InputDeviceID id, LPVOID pvRef) { joysticks.push_back(DID_Joystick(dinputInterface, id, bufferSize_numItems)); return DIENUM_CONTINUE; } BOOL CALLBACK enumMouseCallback(InputDeviceID id, LPVOID pvRef) { mice.push_back(DID_Mouse(dinputInterface, id, bufferSize_numItems)); return DIENUM_CONTINUE; } BOOL CALLBACK enumOtherCallback(InputDeviceID id, LPVOID pvRef) { others.push_back(DID_Other(dinputInterface, id, bufferSize_numItems)); return DIENUM_CONTINUE; } and the output is _GUID DATA_ iguid.d1: 2519117328 iguid.d2: 63399 iguid.d3: 4574 iguid.d4: 0017F390 pguid.d1: 67109967 pguid.d2: 0 pguid.d3: 0 pguid.d4: 0017F3A0 _DEVICE DATA_ devtype: 66068 prodname: Thrustmaster HOTAS Cougar instancename: Thrustmaster HOTAS Cougar _GUID DATA_ iguid.d1: 3723248736 iguid.d2: 25704 iguid.d3: 4576 iguid.d4: 0017F390 pguid.d1: 3008431183 pguid.d2: 0 pguid.d3: 0 pguid.d4: 0017F3A0 _DEVICE DATA_ devtype: 66076 prodname: F16 MFD 1 instancename: F16 MFD 1 _GUID DATA_ iguid.d1: 3723248736 iguid.d2: 25704 iguid.d3: 4576 iguid.d4: 0017F390 pguid.d1: 3008496719 pguid.d2: 0 pguid.d3: 0 pguid.d4: 0017F3A0 _DEVICE DATA_ devtype: 66076 prodname: F16 MFD 2 instancename: F16 MFD 2 _GUID DATA_ iguid.d1: 3833754032 iguid.d2: 48150 iguid.d3: 4574 iguid.d4: 0017F390 pguid.d1: 123471523 pguid.d2: 0 pguid.d3: 0 pguid.d4: 0017F3A0 _DEVICE DATA_ devtype: 66328 prodname: Saitek X52 Flight Control System instancename: Saitek X52 Flight Control System PR btn 1 HL btn 1 HL btn 1 HL btn 1 HL btn 1 HL btn 1 HL btn 1 HL btn 1 RL btn 1 Edited April 13, 2011 by =RvE=Yoda S = SPARSE(m,n) abbreviates SPARSE([],[],[],m,n,0). This generates the ultimate sparse matrix, an m-by-n all zero matrix. - Matlab help on 'sparse' Link to comment Share on other sites More sharing options...
RvEYoda Posted April 14, 2011 Author Share Posted April 14, 2011 (edited) I've run into a problem.. Hotas cougar: can map everything fine Thrustmaster mfds: all fine Saitek X52 (i use the throttle): All axii except mouse ok, all buttons except mouse ok, all povs ok. It seems as Saitek has written som nasty driver here. As soon as any application creates a DirectInput device of the X52, then the saitek "magic mouse" is activated, and the buttons that control it are no longer readable as DirectInput buttons. So as soon as you start your own software or the saitek panel, BLING! Mouse activated. The worse problem is that the saitek magic mouse doesnt register as a directx device! Even if I uninstall the saitek profiling software, and there is no more magic mouse.....the buttons still dont show as dx input :( This means, effectively, that I cannot read it. Well I can read it through the global mouse input but that is pointless. :( ------- Update: There might be an evil way of getting raw data from the device and going from there...Investigating http://msdn.microsoft.com/en-us/library/microsoft.directx_sdk.reference.diobjectdataformat(v=VS.85).aspx :D Update 2: Through looking at the device's raw data sent I've been able to ask DirectInput to send me data from mouse controller on the x52 without having to use it as mouse :P. Now I just need to read those extra buttons... Getting close! Basically just need to define a custom data format for devices (like x52 but not cougar or TM mfds) that behave evil. Update 3: Now able to read all x52 states EXCEPT the mouse buttons (even though the mouse and profiling software is uninstalled). The cursor stick itself I can read, but not the buttons... hmm They do not send any dx information EXCEPT if the x52 control panel is opened, then they suddenly become DirectInput compatible buttons.....hm....evil drivers... Edited April 14, 2011 by =RvE=Yoda S = SPARSE(m,n) abbreviates SPARSE([],[],[],m,n,0). This generates the ultimate sparse matrix, an m-by-n all zero matrix. - Matlab help on 'sparse' Link to comment Share on other sites More sharing options...
pakfront Posted April 15, 2011 Share Posted April 15, 2011 (edited) Good luck! I have messed around with Inputs on windows years ago. I hope it has gotten better, but it used to be very easy to get 90% working and very hard to get 100% working. In the end I just used GlovePIE and PPJoy, though I understand that PPJoy will not work on the newer Windows. However, GlovePIE does a lot of what you are trying to do already (reampping inputs as other inputs) and allows use of some pretty unique input devices - TrackIR, VR Gloves, Wiimotes. http://glovepie.org/glovepie.php ... Edited April 15, 2011 by pakfront Link to comment Share on other sites More sharing options...
RvEYoda Posted April 15, 2011 Author Share Posted April 15, 2011 (edited) Solved the last piece of the puzzle. I can now read x52, cougar, mfds 100% :). Going back to work on the implementation now. It is not meant to be a scripting software, more like a static c++ and/or java library so that you can write conditions in low level programming language Basically what I've had to do is to dynamically generate the device data formats during program runtime, given what directinput reports on the device capabilities, (cause some, for example the x52 hotas have buttons that exceed the standard DirectInput data formats). I'm in the process of testing the new formats, basically dynamically generated structs at runtime (and with dyn generated I mean different amount of members and types), so working for filling in bytes here and there :P Update: So basically everything works now. Input, profiles, output. games detect my mappings just fine. There is just one total gamebreaker....... I'm unable to block the DX input to games. I can receive it myself, i can generate the keystrokes I want, but the games also receive the original DX input. This is a problem since some games does not allow me to unmap for example POV hats (damn u f4AF), while in lockon/dcs this isnt a problem. So unless someone knows a way how to block selective directinput information going to other applications, then I'm putting this project on hold for the moment. (Like it said everything is working, it's just that I cannot get the apps to get "double information") This is what my game profile looked like :P. At least I can use it to map my thrustmaster MFDs I guess XD //////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////// ///// Thrustmaster MFDs ////////////////////////////////////////////////// // Special buttons which do not have modifiers int L_mfd_btn[3*20] = { 0, 0, 0, 1, VK_ADD, 0, 2, 0, 0, 3, 0, 0, 4, 0, 0, 5, VK_HOME, 1, 6, 0, 0, 7, 0, 0, 8, 0, 0, 9, 0, 0, 10, 0, 0, 11, VK_F6, 0, 12, VK_F7, 0, 13, 0, 0, 14, 0, 0, 15, VK_F8, 0, 16, VK_MULTIPLY,0, 17, VK_DIVIDE, 1, 18, 0, 0, 19, VK_PRIOR, 1 }; int R_mfd_btn[3*20] = { 0, 0, 0, 1, VK_END, 1, 2, 0, 0, 3, 0, 0, 4, 0, 0, 5, 0, 0, 6, 0, 0, 7, 0, 0, 8, 0, 0, 9, 0, 0, 10, 0, 0, 11, 0, 0, 12, 0, 0, 13, 0, 0, 14, 0, 0, 15, 0, 0, 16, 0, 0, 17, 0, 0, 18, 0, 0, 19, 0, 0 }; void tapAfMfd(int mod1, int mod2, int bNum) { if (bNum<10) { tripleTap(mod1, mod2, number(oneToTenKeys(bNum))); } else if (bNum>=10 && bNum<20) { tripleTap(mod1, mod2, numpad(oneToTenKeys(bNum-10))); } } void stdTapLeftMfd(int bNum) { tapAfMfd(VK_LCONTROL, VK_LMENU, bNum); } void stdTapRightMfd(int bNum) { tapAfMfd(VK_LSHIFT, VK_LMENU, bNum); } // Mapping Thrustmaster left mfd void tapLeftMfdButton(int bNum) { if (isSimpleMapped(bNum, 3, L_mfd_btn)) { keyTap(getMapping(bNum, 3, L_mfd_btn), isExtended(bNum, 3, L_mfd_btn)); } else { stdTapLeftMfd(bNum); }; } // Mapping Thrustmaster right mfd void tapRightMfdButton(int bNum) { if (isSimpleMapped(bNum, 3, R_mfd_btn)) { keyTap(getMapping(bNum, 3, R_mfd_btn), isExtended(bNum, 3, R_mfd_btn)); } else { stdTapRightMfd(bNum); } } void assignMfds() { for (size_t i=0; i < mfd1->getNumButtons(); i++) mfd1->getButton(i).assignCallback_onKeyDown(&tapLeftMfdButton); for (size_t i=0; i < mfd2->getNumButtons(); i++) mfd2->getButton(i).assignCallback_onKeyDown(&tapRightMfdButton); } //////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////// ///// HOTAS COUGAR ////////////////////////////////////////////////// // Simple mappings: buttonNumber, vkey, extended state const int simpleCougarMappings[3*18] = { 0, VK_DELETE, 1, // first detent 1, VK_SPACE, 0, // pickle 2, 0, 0, // round pinky 3, 0, 0, // paddle 4, 0, 0, // nws 5, VK_INSERT, 1, // second detent 6, 0, 0, // tms u 7, 0, 0, // tms r 8, 0, 0, // tms d 9, 0, 0, // tms l 10, 0, 0, // dms u 11, 0, 0, // dms r 12, 0, 0, // dms d 13, 0, 0, // dms l 14, 0, 0, // cms fwd 15, 0, 0, // cms up/right 16, 0, 0, // cms back 17, 0, 0 // cms down left }; const int simplePov[3*8] = { 0, 0, 0, 1, 0, 0, 2, VkKeyScanA('l'), 0, 3, 0, 0, 4, VK_ADD, 0, 5, 0, 0, 6, VkKeyScanA('n'), 0, 7, 0, 0 }; void simpleCougarmappings(int bNum) { if (isSimpleMapped(bNum, 3, simpleCougarMappings)) { int key = getMapping(bNum, 3, simpleCougarMappings); bool isEx = isExtended(bNum, 3, simpleCougarMappings); if (cougar->getButton(bNum).isPressed()) { keyDown(key, isEx); } else { keyUp(key, isEx); } } } void cougarPovChange(int dirIndex) { if (dirIndex == 0) { if(cougar->getButton(2).isPressed()) { tapRightMfdButton(1); } else { tapLeftMfdButton(16); } } else{ keyTap(getMapping(dirIndex, 3, simplePov), isExtended(dirIndex, 3, simplePov)); } cout << endl << "Pov changed"; } void assignCougar() { for (size_t i=0; i < cougar->getNumButtons(); i++) { if (isSimpleMapped(i, 3, simpleCougarMappings)) { cougar->getButton(i).assignCallback_onKeyDown(&simpleCougarmappings); cougar->getButton(i).assignCallback_onKeyReleased(&simpleCougarmappings); } else { cougar->getButton(i).assignCallback_onKeyDown(&keyIdentifier); } } cougar->getPov(0).getPovButton(0).assignCallback_onKeyDown(&cougarPovChange); cougar->getPov(0).getPovButton(2).assignCallback_onKeyDown(&cougarPovChange); cougar->getPov(0).getPovButton(4).assignCallback_onKeyDown(&cougarPovChange); cougar->getPov(0).getPovButton(6).assignCallback_onKeyDown(&cougarPovChange); } //////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////// ///// General ////////////////////////////////////////////////// void assign() { assignMfds(); assignCougar(); } Update: Working F4Af profile, going to make a Fc2 profile later :P. 2xTM mfds, Hotas cougar and saitek x52 throttle now profiled with single software ^^ :: the profile (v1) -> http://gigurra.se/ProfilerTest.txt . Edited April 18, 2011 by =RvE=Yoda S = SPARSE(m,n) abbreviates SPARSE([],[],[],m,n,0). This generates the ultimate sparse matrix, an m-by-n all zero matrix. - Matlab help on 'sparse' Link to comment Share on other sites More sharing options...
Recommended Posts