ygolohcisp Posted November 15, 2017 Share Posted November 15, 2017 How can I get the K95's G key presses through USB without CUE software? The K95 shows up as these HID devices: ID 1b1c:1b11 \\?\hid#vid_1b1c&pid_1b11&mi_01&col01#8&2dd5e1ac&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030} Corsair K95 RGB Gaming Keyboard ID 1b1c:1b11 \\?\hid#vid_1b1c&pid_1b11&mi_01&col02#8&2dd5e1ac&0&0001#{4d1e55b2-f16f-11cf-88cb-001111000030} Corsair K95 RGB Gaming Keyboard ID 1b1c:1b11 \\?\hid#vid_1b1c&pid_1b11&mi_01&col03#8&2dd5e1ac&0&0002#{4d1e55b2-f16f-11cf-88cb-001111000030} Corsair K95 RGB Gaming Keyboard ID 1b1c:1b11 \\?\hid#vid_1b1c&pid_1b11&mi_01&col04#8&2dd5e1ac&0&0003#{4d1e55b2-f16f-11cf-88cb-001111000030} Corsair K95 RGB Gaming Keyboard ID 1b1c:1b11 \\?\hid#vid_1b1c&pid_1b11&mi_02#8&9fea3ea&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030} Corsair K95 RGB Gaming Keyboard ID 1b1c:1b11 \\?\hid#vid_1b1c&pid_1b11&mi_00#8&16125567&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030} Corsair K95 RGB Gaming Keyboard But when I try to open any one of these for reading, I get an error. What's the correct way to read from it to get the G key presses? And which of these HID devices is used for them? I'm already successfully sending the LED data via libusb but now I still need to get G key presses. They are sent via normal HID, right? Link to comment Share on other sites More sharing options...
Darth Affe Posted November 15, 2017 Share Posted November 15, 2017 Yes, it is possible to read the keys from the hid-device. If you read from the one with "col03" with a buffer size of 64 it should be working. I tried around with this a while ago and got some working (C#) code here. Link to comment Share on other sites More sharing options...
ygolohcisp Posted November 16, 2017 Author Share Posted November 16, 2017 I tried that but it's not working. I can't open the HID device with this hidapi lib. Apparently Windows doesn't allow to open keyboards/mice for security reasons: https://github.com/signal11/hidapi/issues/294#issuecomment-345071855 But isn't your C# program running in userspace, not as a driver in kernel space? Link to comment Share on other sites More sharing options...
ygolohcisp Posted November 16, 2017 Author Share Posted November 16, 2017 I captured these packets with wireshark/UsbPcap when pressing and releasing each G key one after another (G1 to G18). The key release packets all look the same (not key specific) for some reason, only the keypress packets are key-specific.. So I have to use 0x82 for wIndex, but what should I use for bmRequestType, bRequest and wValue when calling libusb_control_transfer()? http://libusb.sourceforge.net/api-1.0/group__syncio.html#gadb11f7a761bd12fc77a07f4568d56f38 Link to comment Share on other sites More sharing options...
Darth Affe Posted November 17, 2017 Share Posted November 17, 2017 I tried that but it's not working. I can't open the HID device with this hidapi lib. Apparently Windows doesn't allow to open keyboards/mice for security reasons: https://github.com/signal11/hidapi/issues/294#issuecomment-345071855 But isn't your C# program running in userspace, not as a driver in kernel space? Yes it is running in userspace. I've no idea how windows 8 handles such things but for me (win 7) it works fine, and as far as i know on win 10 it works too. The key release packets all look the same (not key specific) for some reason, only the keypress packets are key-specific.. Yes, this is expected. The keyboard always sends data containing isPressed-flags for every key. Therefore after releasing a key (if you only pressed one) it's always 0 only. if you press multiple keys and release one you'll still see the remaining ones as 1. That's what is parsed here: https://github.com/DarthAffe/CUE.NET.Input/blob/master/Input/DeviceInput.cs#L90 So I have to use 0x82 for wIndex, but what should I use for bmRequestType, bRequest and wValue when calling libusb_control_transfer()? Sorry i can't help with that. I've no idea how that lowlevel usb-libraries work. Link to comment Share on other sites More sharing options...
ygolohcisp Posted November 23, 2017 Author Share Posted November 23, 2017 Thanks for explaining the keypress msgs. I also tried with the hidapi lib again, but apparently userspace programs on Windows are not allowed (by the OS) to read HID devices that are keyboards or mice, for security reasons: https://github.com/signal11/hidapi/issues/247#issuecomment-161152387 So how did you get your program to open the keyboard's HID device while running in userspace (without having to override the Corsair HID driver)? :) Link to comment Share on other sites More sharing options...
Darth Affe Posted November 23, 2017 Share Posted November 23, 2017 So how did you get your program to open the keyboard's HID device while running in userspace (without having to override the Corsair HID driver)? :) I've no idea. Like I said this might be a win 8 issue. The only thing I can do to help with this is to give you the application I used to test back when I worked with this. I works 100% for me (just tested it again). If it doesn't work for you it's likely a os problem, if it does you're doing something wrong :p Just run it, open a notepad and press some keys. It should light up the pressed keys on the keyboard. (Don't press keys in the console-window of the application except you want to close it.)InputTest.zip Link to comment Share on other sites More sharing options...
ygolohcisp Posted December 6, 2017 Author Share Posted December 6, 2017 For me InputTest.exe crashes at start with an exception, even after I installed .NET and the VC++ redistributable :( Link to comment Share on other sites More sharing options...
hastegag Posted December 11, 2017 Share Posted December 11, 2017 For me InputTest.exe crashes at start with an exception, even after I installed .NET and the VC++ redistributable :( This has been on my back burner, but I've been dying to try it just tried it and it works on win10x64, but again as he said, you need to be inside a notepad. I had 2.20.xxx installed with the SDK enabled. If i was outside of notepad and hit the G keys it does not necessarily work and may crash, but ultimately, i know this is going to be a cool thing...I'm excited to look at how Darth Affe set this up and go from there Link to comment Share on other sites More sharing options...
ygolohcisp Posted December 12, 2017 Author Share Posted December 12, 2017 How did you get it to work instead of throw an exception? I got the exception right after starting it on the command line. Before I could even run it, I had to install .Net and VC++ redistributable because of msvcp140.dll, what else is missing? Link to comment Share on other sites More sharing options...
ygolohcisp Posted December 13, 2017 Author Share Posted December 13, 2017 The only thing I can do to help with this is to give you the application I used to test back when I worked with this. I works 100% for me (just tested it again). If it doesn't work for you it's likely a os problem, if it does you're doing something wrong :p Could you maybe upload the source of InputTest.exe somewhere so I can translate it into the language I'm using and try if that works? :) I'd really appreciate it. Link to comment Share on other sites More sharing options...
Darth Affe Posted December 16, 2017 Share Posted December 16, 2017 Just take the example project in the repo: https://github.com/DarthAffe/CUE.NET.Input/tree/master/Examples/SimpleDevTest Link to comment Share on other sites More sharing options...
hastegag Posted December 16, 2017 Share Posted December 16, 2017 Could you maybe upload the source of InputTest.exe somewhere so I can translate it into the language I'm using and try if that works? :) I'd really appreciate it. hey did you run it with CUE running and FULLY Loaded up? I tried again without cue running, got an exception in the command line. I tried running after running CUE but before loading all the devices and got a different error. Maybe just try again? I am going to try to take a closer look at what this code does and see if I can extrapolate for my purposes. I really just was looking for a way to fill in the gaps with CUE, like decision making macros on the Gkeys that can in and of themselves test for modifiers being pressed or something else happening at the same time to make them context sensitive/intelligent. Right now I have to often remap these G keys to an autohotkey recognizable key which limits my other possibilities on the keyboard at the same time (there are only so many Fkeys and in photoshop for example you have to sort of reserve fkeys and modifier states for actions - it gets crowded quickly). I think this would be the fix, bc there is clearly a way to see when the G keys are depressed...and he showed us how so i can go from here. Link to comment Share on other sites More sharing options...
Darth Affe Posted December 17, 2017 Share Posted December 17, 2017 If you only need the G-keys you can use the original SDK or CUE.NET since there is an event for them for a few weeks now. Link to comment Share on other sites More sharing options...
hastegag Posted December 17, 2017 Share Posted December 17, 2017 If you only need the G-keys you can use the original SDK or CUE.NET since there is an event for them for a few weeks now. I think I will try that. I did download your repository last night for InputTest / SimpleDevTest and got it to compile after some fiddling on Visual Studio 2017, I had to comment out a couple lines and I didn't get too far. It asked me to use the more modern .net targets which seemed to work finally when i opened the input project before the simple dev test. It wasn't getting where the namespace came from for CUE.Net.Input. The .net4.5 targets lower than version 4.5.2 don't seem to be able to be installed in VS Community '17, but it seems to play ok with the newer version. In the meantime, while I will definitely look into the Cue.net original SDK, i am going to hotfix this for myself a different route by making 18 executables in AHK that are linked to in CUE on each G key. The script/exe polls for whether a modifier key is pressed at execution and save out the keystate into an ini and i can read that back in with my primary script. Tricky part is telling Script 1 when to update and fire a hotkey. I suppose I could poll every second or so the same ini file for state changes and erase it after each iteration, but that is slow and even on an nvme its probably not a great method. I'm probably going to see if i can just save the keystate in memory someplace and read it back in periodically (which is i am sure less taxing on the system and should be faster). Obviously this is hacky and not the best approach, I am sure the SDK will prove to be a better method. Link to comment Share on other sites More sharing options...
hastegag Posted December 17, 2017 Share Posted December 17, 2017 ugh, that was dumb of me, I just struggled through using the ancient version 1.xx posted at the top of the forums, could not find the CorsairRegisterKeypressCallback() function...so now i have the modern one... :) Link to comment Share on other sites More sharing options...
hastegag Posted December 17, 2017 Share Posted December 17, 2017 The Register callback.cpp solution has what i need. It will be spaghetti with this approach, but should work for me: if(keyIdStrings.at(keyId) == "CorsairKeyKb_G1") { std::cout << keyIdStrings.at(keyId); //or anything else } Link to comment Share on other sites More sharing options...
hastegag Posted December 17, 2017 Share Posted December 17, 2017 So for anyone else looking to do this, and I am sure there are many, I have provided the following: http://smithany.com/register_callback.exe which is basically a modified version of the newer example D.A. suggested I pursue earlier: http://smithany.com/register_callback.cpp (sorry that's probably a terrible way to go about it, but as i understand c++ doesn't love switch statements based on strings in a straightforward manner - i could probably switch based on the key rather than the string compared keylist at the top...might be better method but I am out of my depth) Also, my autohotkey that runs along side it is: http://smithany.com/suitableRemap.ahk Which so far, although largely untested, appears to not stomp keyboard stuff as I gave it a quick brown fox jumps over the lazy dog and the top rows and fkeys and got no alerts...ymmv and I may have a problem in the future using these reserve keycodes, but it seems to be a working proof of concept that will be helpful for me. Link to comment Share on other sites More sharing options...
hastegag Posted December 19, 2017 Share Posted December 19, 2017 :D:If anybody cares, my code was bad as posted and linked above...down and up events were both triggering the fake keypress. That said, there were two ways to fix, one you could do this hacky thing in AHK: global ultraProfile:=0 global noRepeat:=1 SC0C1:: ;MsgBox G1 if(ultraProfile && !noRepeat){ Send, stuff noRepeat:=!noRepeat Sleep,500 } noRepeat:=!noRepeat Return SC0EA:: ;MsgBox M10 ultraProfile:=1 noRepeat:=0 return or better yet what appears to work is also check for the boolean in register_callback with the short circuit AND with the keyId (which is also better i assume than my earlier posted character string comparison) if(keyId == CorsairKeyKb_G1 && pressed) { keybd_event(VK_KANA, 0xC1, 0, 0); } and so on Link to comment Share on other sites More sharing options...
hastegag Posted December 24, 2017 Share Posted December 24, 2017 Quick follow up to this, assuming you always have certain keys that are statically lit a certain way, you can tell from the SDK what profile you have currently active by polling a specific key. Might not seem that helpful, but if you do have macros outside of CUE, it can be a good error checking process to ensure the profile is active if they either work hand in hand or if they might otherwise stomp each other etc. Below is an excerpt from the register_callback.cpp provided in the SDK, with some basic edits. Looks for all red brightness on the Q key in this example, polled for when G1 is hit: auto ledId = CLK_Q; CorsairLedColor ledColor = {ledId, 0, 0, 0}; CorsairGetLedsColors(1, &ledColor); //fills the rgb above if (keyId == CorsairKeyKb_G1 && pressed)//keyIdStrings.at(keyId) == "CorsairKeyKb_G1") { if (ledColor.r == 255) { keybd_event(VK_CONTROL, 0x11, 0, 0); // PRESS CONTROL keybd_event(VK_KANA, 0xC1, 0, 0); // PRESS FUNKY keybd_event(VK_CONTROL, 0x11, KEYEVENTF_KEYUP, 0); //KEYEVENTF_KEYUP DWORD FLAG TO RELEASE CTRL } else { keybd_event(VK_KANA, 0xC1, 0, 0); } } The above would send control + some key recognized elsewhere. I realized I have more than 6 profiles, and since I'd be potentially using modifiers inside of those profiles and recognizing them elsewhere, sending ctrl/shift/alt modified offkeyboard keypresses is not that constructive. Better alternative is to write to a file and read it back in when called to detect for the active profile in CUE. I guess you could pass this through memory, but i'm not sure how to do that other than polling for the PID and then using a consistent offset maybe). Better approach is more or less below: #include <fstream> ... if (ledColor.r == 255) { //WRITE to FILE OR MEMORY as you may have more than a half dozen profiles std::ofstream myfile; myfile.open("Profile.txt"); myfile << "Default"; myfile.close(); } else { keybd_event(VK_KANA, 0xC1, 0, 0); } Refactored code for my purposes at: http://www.smithany.com/register_callback.cpp Made a function for outputting the active profile in CUE, but with less lines etc Link to comment Share on other sites More sharing options...
hastegag Posted May 4, 2018 Share Posted May 4, 2018 Not sure if anyone cares, but I finally figured out how to get AutoHotkey to read from a memory address to avoid hitting the harddrive a million extra times a year to talk from CPP to Autohotkey without writing a custom DLL that's registered (think that works too). There are a million examples out there, but I swear I was doing everything correctly and tried a hundred different ways and it just wasn't working reliably, but the below works: Example below: global profilePointer:=0 ;other code ReadMemory(MADDRESS,PID) { VarSetCapacity(MVALUE,4,0) ProcessHandle := DllCall("OpenProcess", "Int", 24, "Char", 0, "UInt", PID, "UInt") DllCall("ReadProcessMemory", "UInt", ProcessHandle, "Ptr", MADDRESS, "Ptr", &MVALUE, "Uint",4) Loop 4 result += *(&MVALUE + A_Index-1) << 8*(A_Index-1) return, result } ProfileName(readNumber) { sendBackProfileName:="" if(readNumber=0) { sendBackProfileName:="Default" } if(readNumber=1) { sendBackProfileName:="UltraMod" } if(readNumber=2) { sendBackProfileName:="Sketchup" } if(readNumber=3) { sendBackProfileName:="ACrucial***" } if(readNumber=4) { sendBackProfileName:="Dreamweaver" } if(readNumber=5) { sendBackProfileName:="Outlook" } if(readNumber=6) { sendBackProfileName:="Word" } if(readNumber=7) { sendBackProfileName:="Photoshop" } if(readNumber=8) { sendBackProfileName:="Bridge" } if(readNumber=9) { sendBackProfileName:="Illustrator" } if(readNumber=10) { sendBackProfileName:="Excel" } return sendBackProfileName } getCurProfile() { Process, Exist, register_callback.exe PID:=ErrorLevel if(profilePointer=0) { FileRead, profilePointer, C:\CUESDK\examples\register_callback\x64\Release\Profile.txt ;MsgBox here? ;insurance on writes profilePointer := "0x"+profilePointer ;frontloaded zeros are ok but need to register string as hex } Return ProfileName(ReadMemory(profilePointer,PID)) } ;othercode SC0C1:: ;MsgBox G1 profile := getCurProfile() if(profile == "Photoshop"){ Click 390,42 ;Align Top G1 } Return ^SC0C1:: ;MsgBox Ctrl G1 ;do something else Return alongside www.smithany.com/register_callbackImproved.cpp A lot to fix still, need to figure out how to clock how long something was depressed and figure in a faux repeat rate for G and M keys, thinking the Chrono include can clock the time between one thing and another. Also need to maybe setup a side profile polling periodically even if no key is pressed if I end up toying with some RGB integration (not a priority for me atm, as I dont currently have a lot of supporting non corsair hardware tho) Link to comment Share on other sites More sharing options...
Recommended Posts
Archived
This topic is now archived and is closed to further replies.