diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..462abb4 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: futurITsic# Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/README.md b/README.md index 127a14a..e019b8b 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ Download ====== -[![Github All Releases](https://img.shields.io/github/downloads/Tylemagne/Gopher360/total.svg?style=flat&label=Download%20Gopher360%20Standalone&logo=appveyor&colorA=00cc0a&colorB=000000)](https://github.com/Tylemagne/Gopher360/releases/download/v0.989/Gopher.exe) +[![Github All Releases](https://img.shields.io/github/downloads/Tylemagne/Gopher360/total.svg?style=flat&label=Download%20GopherRenewed%20Standalone&logo=appveyor&colorA=00cc0a&colorB=000000)](https://github.com/mike1084/GopherRenewed/releases/download/v0.991/GopherRenewed.exe) Donate ====== -[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=ETDWNUEJG2UY2) +[![Become a patron](https://c5.patreon.com/external/logo/become_a_patron_button@2x.png)](https://www.patreon.com/bePatron?u=1002457) Compatible Controllers ====== @@ -25,7 +25,7 @@ Compatible Controllers DualShock controllers are great, but you NEED to emulate Xinput for Gopher to see and understand them. Fortunately, Xinput emulation is a very popular thing, as there are just as many people with DualShock controllers as there are Xbox controllers. Listings coming soon. ### Third party -SOME third party controllers will most likely work as well. I haven't seen one not work, but I'd imagine some wouldn't. Research before buying, Gopher expects native Xinput devices, so the controller should as well. I won't be listing any for now until I know what ones will work. If I can find one that does the job and saves you from Microsoft's extreme profit margins, I'll list it. +SOME third party controllers will most likely work as well. I haven't seen one not work, but I'd imagine some wouldn't. Research before buying, **Gopher expects native Xinput devices,** so the controller should as well. I won't be listing any for now until I know what ones will work. If I can find one that does the job and saves you from Microsoft's extreme profit margins, I'll list it. Feedback ====== @@ -62,7 +62,7 @@ Gopher separates itself from the competition by being efficient, small, portable [![GitHub release](https://img.shields.io/github/release/Tylemagne/gopher360.svg)]() -[![Github commits (since latest release)](https://img.shields.io/github/commits-since/Tylemagne/gopher360/latest.svg)]() +[![Github commits (since latest release)](https://img.shields.io/github/commits-since/mike1084/GopherRenewed/latest.svg)]() Requirements ====== diff --git a/Windows/Gopher/ConfigFile.cpp b/Windows/Gopher/ConfigFile.cpp index 5fe7343..b0bfea1 100644 --- a/Windows/Gopher/ConfigFile.cpp +++ b/Windows/Gopher/ConfigFile.cpp @@ -98,8 +98,8 @@ void ConfigFile::ExtractKeys() std::ofstream outfile("config.ini"); // Begin config dump to file - outfile << "# GOPHER DEFAULT CONFIGURATION rev1.0 - Auto generated by Gopher360." << std::endl; - outfile << "# If you want a fresh one, just DELETE THIS FILE and re-run Gopher360." << std::endl; + outfile << "# GOPHER DEFAULT CONFIGURATION rev1.0 - Auto generated by GopherRenewed." << std::endl; + outfile << "# If you want a fresh one, just DELETE THIS FILE and re-run GopherRenewed." << std::endl; outfile << "# Set which controller buttons will activate the configuration events." << std::endl; outfile << "# SET 0 FOR NO FUNCTION." << std::endl; outfile << "# AVAILABLE VALUES AT https://msdn.microsoft.com/en-us/library/windows/desktop/microsoft.directx_sdk.reference.xinput_gamepad(v=vs.85).aspx" << std::endl; @@ -135,13 +135,29 @@ void ConfigFile::ExtractKeys() outfile << "GAMEPAD_TRIGGER_LEFT = 0" << std::endl; outfile << "GAMEPAD_TRIGGER_RIGHT = 0" << std::endl; outfile << "\n" << std::endl; - outfile << "# ADVANCED CONFIGURATION SETTINGS" << std::endl; + outfile << "# ADVANCED CONFIGURATION SETTINGS, REMOVE # ON SPECIFIC LINES TO ENABLE." << std::endl; + outfile << "\n" << std::endl; outfile << "# ALLOWED CURSOR SPEEDS, FIRST WILL BE CHOSEN BY DEFAULT. VALUES > 1.0 WILL BE IGNORED. NO SPACES." << std::endl; outfile << "CURSOR_SPEED = ULTRALOW=0.005,LOW=0.015,MED=0.025,HIGH=0.04" << std::endl; + outfile << "# CURSOR DEADZONE, DEFAULT = 6000" << std::endl; + outfile << "#DEAD_ZONE = 6000" << std::endl; + outfile << "\n" << std::endl; + + outfile << "# PARAMETERS FOR SETTING SCROLLING SPEED AND DEADZONE." << std::endl; + outfile << "# SET SCROLLING SPEED." << std::endl; + outfile << "# SCROLL_SPEED = 0.1" << std::endl; + outfile << "# SET SCROLL DEADZONE, DEFAULT = 5000" << std::endl; + outfile << "# SCROLL_DEAD_ZONE = 5000" << std::endl; + outfile << "\n" << std::endl; + outfile << "# SET ACCELERATION FACTOR FOR NON-LINEAR CURSOR SPEED" << std::endl; outfile << "# ACCELERATION_FACTOR = 3" << std::endl; + outfile << "\n" << std::endl; outfile << "# Swaps the function of the thumbsticks. Set to 0 for default behavior or set to 1 to have the mouse movement on the right stick and scrolling on the left stick." << std::endl; outfile << "SWAP_THUMBSTICKS = 0" << std::endl; + outfile << "\n" << std::endl; + outfile << "# HIGHLY EXPERIMENTAL FPS MODE, SET TO 1 TO ENABLE" << std::endl; + outfile << "FPS_MODE = 0" << std::endl; // End config dump outfile.close(); diff --git a/Windows/Gopher/Gopher.cpp b/Windows/Gopher/Gopher.cpp index 32b47f0..7e6491d 100644 --- a/Windows/Gopher/Gopher.cpp +++ b/Windows/Gopher/Gopher.cpp @@ -20,6 +20,32 @@ void inputKeyboard(WORD cmd, DWORD flag) SendInput(1, &input, sizeof(INPUT)); } +// Description: +// Send a keyboard input to the system based on the key value +// and its event type. +// +// Params: +// cmd The value of the key to send(see http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731%28v=vs.85%29.aspx) +// flag The KEYEVENT for the key +void inputKeyboardScan(WORD cmd, WORD flag) +{ + INPUT input; + input.type = INPUT_KEYBOARD; + input.ki.wScan = cmd; + input.ki.time = 0; + input.ki.dwExtraInfo = 0; + input.ki.wVk = 0; + input.ki.dwFlags = flag; + SendInput(1, &input, sizeof(INPUT)); +} + +void inputKeyboardRaw(USHORT cmd, USHORT flag = 0) +{ + RAWINPUT input; + input.data.keyboard.Flags = flag; + input.data.keyboard.VKey = cmd; +} + // Description: // Send a keyboard input based on the key value with the "pressed down" event. // @@ -117,6 +143,10 @@ void Gopher::loadConfigFile() //-------------------------------- // Advanced settings //-------------------------------- + + // (EXPERIMENTAL) FPS mode toggle + FPS_MODE = strtol(cfg.getValueOfKey("FPS_MODE").c_str(), 0, 0); + // Acceleration factor acceleration_factor = strtof(cfg.getValueOfKey("ACCELERATION_FACTOR").c_str(), 0); @@ -167,6 +197,8 @@ void Gopher::loadConfigFile() { speeds.push_back(cur_speedf); speed_names.push_back(cur_name); + // To make the vibration dependent on speed, multiply it to get in the same range. + speed_intensities.push_back(cur_speedf * 500000); } } @@ -181,6 +213,10 @@ void Gopher::loadConfigFile() speed_names.push_back("LOW"); speed_names.push_back("MED"); speed_names.push_back("HIGH"); + speed_intensities.push_back(500); + speed_intensities.push_back(1000); + speed_intensities.push_back(1500); + speed_intensities.push_back(2000); } speed = speeds[0]; // Initialize the speed to the first speed stored. TODO: Set the speed to a saved speed that was last used when the application was closed last. @@ -213,7 +249,14 @@ void Gopher::loop() // Mouse functions handleMouseMovement(); - handleScrolling(); + if (FPS_MODE) + { + handleStickMovement(); + } + else + { + handleScrolling(); + } if (CONFIG_MOUSE_LEFT) { @@ -266,7 +309,7 @@ void Gopher::loop() if (_xboxClickIsDown[CONFIG_SPEED_CHANGE]) { const int CHANGE_SPEED_VIBRATION_INTENSITY = 65000; // Speed of the vibration motors when changing cursor speed. - const int CHANGE_SPEED_VIBRATION_DURATION = 450; // Duration of the cursor speed change vibration in milliseconds. + const int CHANGE_SPEED_VIBRATION_DURATION = 420; // Duration of the cursor speed change vibration in milliseconds. speed_idx++; if (speed_idx >= speeds.size()) @@ -275,7 +318,7 @@ void Gopher::loop() } speed = speeds[speed_idx]; printf("Setting speed to %f (%s)...\n", speed, speed_names[speed_idx].c_str()); - pulseVibrate(CHANGE_SPEED_VIBRATION_DURATION, CHANGE_SPEED_VIBRATION_INTENSITY, CHANGE_SPEED_VIBRATION_INTENSITY); + pulseVibrate(CHANGE_SPEED_VIBRATION_DURATION, speed_intensities[speed_idx], speed_intensities[speed_idx]); } // Update all controller keys. @@ -502,7 +545,7 @@ void Gopher::handleMouseMovement() short tx; short ty; - if (SWAP_THUMBSTICKS == 0) + if ((SWAP_THUMBSTICKS == 0 && FPS_MODE == 0) || (SWAP_THUMBSTICKS == 1 && FPS_MODE == 1)) { // Use left stick tx = _currentState.Gamepad.sThumbLX; @@ -537,7 +580,82 @@ void Gopher::handleMouseMovement() y -= dy; _yRest = y - (float)((int)y); - SetCursorPos((int)x, (int)y); //after all click input processing + INPUT input; + input.type = INPUT_MOUSE; + input.mi.dx = dx; + input.mi.dy = dy * -1; + input.mi.dwFlags = MOUSEEVENTF_MOVE; + input.mi.time = 0; + SendInput(1, &input, sizeof(INPUT)); +} + + +void Gopher::handleKeyboardPress(int keyToPress) { + DWORD keyFlag = KEYEVENTF_UNICODE; + + // If there previously has been a key press, check it! + if (key_pressed) { + if (key_pressed != keyToPress) { + printf("We got a mismatch!"); + inputKeyboardUp(key_pressed); + + //inputKeyboardScan(keyToPress, keyFlag); + inputKeyboardDown(keyToPress); + } + else { + //inputKeyboardScan(keyToPress, keyFlag); + + } + } + // Otherwise, we can just send the key. + else { + inputKeyboardDown(keyToPress); + //inputKeyboardScan(keyToPress, keyFlag); + } + printf("%d", key_pressed); + key_pressed = keyToPress; +} + + +void Gopher::handleStickMovement() { + + short tx = _currentState.Gamepad.sThumbLX; + short ty = _currentState.Gamepad.sThumbLY; + //int aKey = 0x1E, wKey = 0x11, dKey = 0x20, sKey = 0x1F; + int aKey = 37, wKey = 38, dKey = 39, sKey = 40; + //int dKey = 68, aKey = 65, wKey = 87, sKey = 83; + float lengthsq = tx * tx + ty * ty; + if (lengthsq > DEAD_ZONE * DEAD_ZONE) { + + // If the x-distance is greater than the y-distance... + if (tx * tx > ty * ty) { + // d-key (right movement!) + if (tx > 0) { + handleKeyboardPress(dKey); + } + else { + handleKeyboardPress(aKey); + } + } + + else { + // w-key (up movement!) + if (ty > 0) { + handleKeyboardPress(wKey); + } + // s-key (down movement!) + else { + handleKeyboardPress(sKey); + } + } + } + + else { + inputKeyboardUp(key_pressed); + key_pressed = NULL; + } + + } // Description: @@ -611,6 +729,68 @@ void Gopher::handleTriggers(WORD lKey, WORD rKey) } } + +// This function only takes the left and right mouse as input. +// It handles the triggers so as to click the mouse buttons accordingly. +void Gopher::handleTriggersMouse(WORD lKey, WORD rKey) +{ + bool lTriggerIsDown = _currentState.Gamepad.bLeftTrigger > TRIGGER_DEAD_ZONE; + bool rTriggerIsDown = _currentState.Gamepad.bRightTrigger > TRIGGER_DEAD_ZONE; + DWORD lKeyDown = NULL, lKeyUp = NULL, rKeyDown = NULL, rKeyUp = NULL; + if (lKey == 0x01) { + if (rKey == 0x02) { + lKeyDown = MOUSEEVENTF_LEFTDOWN; + lKeyUp = MOUSEEVENTF_LEFTUP; + rKeyDown = MOUSEEVENTF_RIGHTDOWN; + rKeyUp = MOUSEEVENTF_RIGHTUP; + } + else { + return; + } + } + else if (lKey == 0x02) { + if (rKey == 0x01) { + lKeyDown = MOUSEEVENTF_RIGHTDOWN; + lKeyUp = MOUSEEVENTF_RIGHTUP; + rKeyDown = MOUSEEVENTF_LEFTDOWN; + rKeyUp = MOUSEEVENTF_LEFTUP; + } + else { + return; + } + } + else { + return; + } + + + if (lTriggerIsDown != _lTriggerPrevious) + { + _lTriggerPrevious = lTriggerIsDown; + if (lTriggerIsDown) + { + mouseEvent(lKeyDown); + } + else + { + mouseEvent(lKeyUp); + } + } + + if (rTriggerIsDown != _rTriggerPrevious) + { + _rTriggerPrevious = rTriggerIsDown; + if (rTriggerIsDown) + { + mouseEvent(rKeyDown); + } + else + { + mouseEvent(rKeyUp); + } + } +} + // Description: // Handles the state of a controller button press. // @@ -818,3 +998,11 @@ bool Gopher::erasePressedKey(WORD key) return false; } + + + +void Gopher::toggleFPSMode() +{ + FPS_MODE = !FPS_MODE; + printf("FPS Mode: %d\n", FPS_MODE); +} diff --git a/Windows/Gopher/Gopher.h b/Windows/Gopher/Gopher.h index bf4aebe..3599082 100644 --- a/Windows/Gopher/Gopher.h +++ b/Windows/Gopher/Gopher.h @@ -47,6 +47,7 @@ class Gopher std::vector speeds; // Contains actual speeds to choose std::vector speed_names; // Contains display names of speeds to display + std::vector speed_intensities; // Contains increasing intensities to indicate selected speed unsigned int speed_idx = 0; // Mouse Clicks @@ -79,6 +80,12 @@ class Gopher DWORD GAMEPAD_TRIGGER_LEFT = NULL; DWORD GAMEPAD_TRIGGER_RIGHT = NULL; + //Experimental FPS mode + DWORD CONFIG_TOGGLE_FPS = NULL; + int FPS_MODE = NULL; + //Maintain track of which (WASD) key was pressed, if any. + int key_pressed = 0; + // Button press state logic variables std::map _xboxClickStateLastIteration; std::map _xboxClickIsDown; @@ -114,10 +121,16 @@ class Gopher void handleVibrationButton(); + void handleKeyboardPress(int keyToPress); + + void handleStickMovement(); + void handleScrolling(); void handleTriggers(WORD lKey, WORD rKey); + void handleTriggersMouse(WORD lKey, WORD rKey); + bool xboxClickStateExists(DWORD xinput); void mapKeyboard(DWORD STATE, WORD key); @@ -126,6 +139,8 @@ class Gopher void setXboxClickState(DWORD state); + void toggleFPSMode(); + HWND getOskWindow(); private: diff --git a/Windows/Gopher/Gopher.vcxproj b/Windows/Gopher/Gopher.vcxproj index 6e307ef..86f6f57 100644 --- a/Windows/Gopher/Gopher.vcxproj +++ b/Windows/Gopher/Gopher.vcxproj @@ -11,11 +11,11 @@ - Gopher360 + GopherRenewed {896B8CDE-8FC8-42F3-AC14-FA6D202DBBD7} Win32Proj Gopher - 10.0.16299.0 + 10.0.17134.0 diff --git a/Windows/Gopher/main.cpp b/Windows/Gopher/main.cpp index 777e9ea..5c95931 100644 --- a/Windows/Gopher/main.cpp +++ b/Windows/Gopher/main.cpp @@ -13,12 +13,24 @@ along with this program. If not, see . ---------------------------------------------------------------------------------*/ -//changes 0.96 -> 0.97: speed variable is global, detects bumpers, all timed (no enter), lbumper speed toggler -//changes 0.97 -> 0.98: performance improvements, operational volume function, shorter beeps, no XY text -//changes 0.98 -> 0.985: 144Hz, Y to hide window(added float stillHoldingY), code cleanup, comments added -//changes 0.985 -> 0.986: Adding configuration file, changing from beeps to vibration. -//changes 0.986 -> 0.989: Improved speeds and speed reporting, created automatic config generator! -//TODO FOR FUTURE VERSIONS - offload speeds into config file + +/* ---------------------------------- CHANGELOG ---------------------------------- + + changes 0.96 -> 0.97: speed variable is global, detects bumpers, all timed (no enter), lbumper speed toggler + changes 0.97 -> 0.98: performance improvements, operational volume function, shorter beeps, no XY text + changes 0.98 -> 0.985: 144Hz, Y to hide window(added float stillHoldingY), code cleanup, comments added + changes 0.985 -> 0.986: Adding configuration file, changing from beeps to vibration. + changes 0.986 -> 0.989: Improved speeds and speed reporting, created automatic config generator! + changes 0.989 -> 0.99: Added speed vibration intensity to vary depending on speed. + Implemented SendInput to facilitate (game) UI functionality. + + + TODO FOR FUTURE VERSIONS: + - fix input lag when changing speed + - put all buttons into single input device and merely change flags + perhaps with a map to map controller buttons and read them? + +---------------------------------------------------------------------------------- */ #include // for Beep() #include @@ -45,11 +57,11 @@ int main() CXBOXController controller(1); Gopher gopher(&controller); HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); - SetConsoleTitle( TEXT( "Gopher360" ) ); + SetConsoleTitle( TEXT( "GopherRenewed" ) ); system("Color 1D"); - printf("Welcome to Gopher360 - a VERY fast and lightweight controller-to-keyboard & mouse input tool.\n"); + printf("Welcome to GopherRenewed - a VERY fast and lightweight controller-to-keyboard & mouse input tool.\n"); printf("All you need is an Xbox360/Xbone controller (wired or wireless adapter), or DualShock (with InputMapper 1.5+)\n"); printf("Gopher will autofind the xinput device and begin reading input - if nothing happens, verify connectivity.\n"); printf("See the GitHub repository at bit.ly/1syAhMT for more info. Twitter contact: TylerAt60FPS\n\n-------------------------\n\n"); diff --git a/Windows/UpgradeLog.htm b/Windows/UpgradeLog.htm new file mode 100644 index 0000000..69363c6 Binary files /dev/null and b/Windows/UpgradeLog.htm differ