diff --git a/bin/Yolo32.pdb b/bin/Yolo32.pdb deleted file mode 100644 index d2b903d..0000000 Binary files a/bin/Yolo32.pdb and /dev/null differ diff --git a/build/Installer32/Product.wxs b/build/Installer32/Product.wxs index 8c3c25b..c816b74 100644 --- a/build/Installer32/Product.wxs +++ b/build/Installer32/Product.wxs @@ -1,6 +1,6 @@ - + diff --git a/build/Installer64/Product.wxs b/build/Installer64/Product.wxs index 24833da..f52abb8 100644 --- a/build/Installer64/Product.wxs +++ b/build/Installer64/Product.wxs @@ -1,6 +1,6 @@ - + diff --git a/build/YoloMouse.Loader/YoloMouse.Loader.vcxproj b/build/YoloMouse.Loader/YoloMouse.Loader.vcxproj index 4034848..6ebf0e1 100644 --- a/build/YoloMouse.Loader/YoloMouse.Loader.vcxproj +++ b/build/YoloMouse.Loader/YoloMouse.Loader.vcxproj @@ -102,6 +102,7 @@ Windows true + Opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) @@ -117,6 +118,7 @@ Windows true + Opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) @@ -137,6 +139,7 @@ true true true + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) @@ -157,6 +160,7 @@ true true true + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) @@ -189,7 +193,7 @@ - + diff --git a/build/YoloMouse.Loader/YoloMouse.Loader.vcxproj.filters b/build/YoloMouse.Loader/YoloMouse.Loader.vcxproj.filters index c22eb17..8e7878d 100644 --- a/build/YoloMouse.Loader/YoloMouse.Loader.vcxproj.filters +++ b/build/YoloMouse.Loader/YoloMouse.Loader.vcxproj.filters @@ -30,6 +30,6 @@ - + \ No newline at end of file diff --git a/build/YoloMouse.Share/YoloMouse.Share.vcxproj b/build/YoloMouse.Share/YoloMouse.Share.vcxproj index b5ba64e..97ddcb9 100644 --- a/build/YoloMouse.Share/YoloMouse.Share.vcxproj +++ b/build/YoloMouse.Share/YoloMouse.Share.vcxproj @@ -26,6 +26,7 @@ + diff --git a/build/YoloMouse.Share/YoloMouse.Share.vcxproj.filters b/build/YoloMouse.Share/YoloMouse.Share.vcxproj.filters index fb5e22e..acf9b0f 100644 --- a/build/YoloMouse.Share/YoloMouse.Share.vcxproj.filters +++ b/build/YoloMouse.Share/YoloMouse.Share.vcxproj.filters @@ -13,5 +13,6 @@ + \ No newline at end of file diff --git a/source/Core/Constants.hpp b/source/Core/Constants.hpp index bb0cef5..4ba7485 100644 --- a/source/Core/Constants.hpp +++ b/source/Core/Constants.hpp @@ -26,8 +26,10 @@ namespace Core // numeric //------------------------------------------------------------------------- - static const ULong STRING_SHORT_SIZE = 16; - static const ULong STRING_MEDIUM_SIZE = 64; - static const ULong STRING_MAX_SIZE = 512; - static const ULong STRING_PATH_SIZE = STRING_MAX_SIZE; + static const ULong STRING_SHORT_SIZE = 16; + static const ULong STRING_MEDIUM_SIZE = 64; + static const ULong STRING_MAX_SIZE = 512; + static const ULong STRING_PATH_SIZE = STRING_MAX_SIZE; + static const ULong GAME_WINDOW_MIN_WIDTH = 240; + static const ULong GAME_WINDOW_MIN_HEIGHT = 240; } diff --git a/source/Core/Container/Array.hpp b/source/Core/Container/Array.hpp index 6265bea..3e081a6 100644 --- a/source/Core/Container/Array.hpp +++ b/source/Core/Container/Array.hpp @@ -252,20 +252,20 @@ namespace Core } /**/ - const Iterator Begin() const + const Iterator begin() const { return const_cast(_memory); } - const Iterator End() const + const Iterator end() const { return const_cast(_memory + _count); } - Iterator Begin() + Iterator begin() { return _memory; } - Iterator End() + Iterator end() { return _memory + _count; } @@ -299,7 +299,7 @@ namespace Core template Iterator Find( const OBJECT& o ) const { - for( Iterator i = Begin(); i != End(); ++i ) + for( Iterator i = begin(); i != end(); ++i ) if(*i == o) return i; @@ -338,9 +338,9 @@ namespace Core return false; else { - Iterator i = Begin(), j = other.Begin(); - for(; i != End() && *i == *j; i++, j++ ); - return i == End(); + Iterator i = begin(), j = other.begin(); + for(; i != end() && *i == *j; i++, j++ ); + return i == end(); } } diff --git a/source/Core/Container/String.hpp b/source/Core/Container/String.hpp index b0ef61e..ec0a0c9 100644 --- a/source/Core/Container/String.hpp +++ b/source/Core/Container/String.hpp @@ -40,24 +40,24 @@ namespace Core /**/ Bool ReadToken( BaseString& token, Char delimiter ) const { - Iterator begin = token.IsEmpty() ? Begin() : token.End(); + Iterator b = token.IsEmpty() ? begin() : token.end(); // skip delimiter - for( ; begin != End() && *begin == delimiter; ++begin ); - Iterator end = begin; + for( ; b != end() && *b == delimiter; ++b ); + Iterator e = b; // read token - for( ; end != End() && *end != delimiter; ++end ); + for( ; e != end() && *e != delimiter; ++e ); // get count - ULong count = (ULong)(end - begin); + ULong count = (ULong)(e - b); // done if empty if( count == 0 ) return false; // create token - token.SetMemory(begin); + token.SetMemory(b); token.SetCount(count); return true; @@ -79,7 +79,7 @@ namespace Core /**/ BaseString& ToUpper() { - for( Iterator c = Begin(); c != End(); c++ ) + for( Iterator c = begin(); c != end(); c++ ) if(*c >= 'a' && *c <= 'z') *c += 'A'-'a'; @@ -91,7 +91,7 @@ namespace Core { Index hash = 0; - for( Iterator c = Begin(); c != End(); c++ ) + for( Iterator c = begin(); c != end(); c++ ) hash = *c + (hash << 6) + (hash << 16) - hash; return hash; diff --git a/source/Core/Root.hpp b/source/Core/Root.hpp index 1bbc874..48db198 100644 --- a/source/Core/Root.hpp +++ b/source/Core/Root.hpp @@ -31,6 +31,7 @@ #define LOG_PATH "debug.log" #define INVALID_ID (~0) #define INVALID_INDEX (~0) +#define INVALID_HANDLE (~0) namespace Core { diff --git a/source/Core/Support/Enum.hpp b/source/Core/Support/Enum.hpp index 887a8a1..acfaa38 100644 --- a/source/Core/Support/Enum.hpp +++ b/source/Core/Support/Enum.hpp @@ -52,7 +52,7 @@ namespace Core { String s; - for( KeyValueIterator i = _items.Begin(); i != _items.End(); ++i ) + for( KeyValueIterator i = _items.begin(); i != _items.end(); ++i ) { if( value == i->value ) { diff --git a/source/Core/Support/Settings.cpp b/source/Core/Support/Settings.cpp index d68d503..4da026e 100644 --- a/source/Core/Support/Settings.cpp +++ b/source/Core/Support/Settings.cpp @@ -57,7 +57,7 @@ namespace Core if(_wfopen_s(&file, _path, L"wt") == 0) { - for( KeyValueIterator i = _keyvalues.Begin(); i != _keyvalues.End(); ++i ) + for( KeyValueIterator i = _keyvalues.begin(); i != _keyvalues.end(); ++i ) fprintf(file, "%s=%s\n", i->key.GetMemory(), i->value.GetMemory()); fclose(file); diff --git a/source/Core/Windows/InputMonitor.cpp b/source/Core/Windows/InputMonitor.cpp index 3123839..236e8a4 100644 --- a/source/Core/Windows/InputMonitor.cpp +++ b/source/Core/Windows/InputMonitor.cpp @@ -264,16 +264,16 @@ namespace Core InputMonitor::Combo* InputMonitor::_FindCombo() { // for each combo - for( ComboIterator combo = _combos.Begin(); combo != _combos.End(); ++combo ) + for( ComboIterator combo = _combos.begin(); combo != _combos.end(); ++combo ) { KeyCollection& keys = combo->keys; - KeyIterator key = keys.Begin(); + KeyIterator key = keys.begin(); // for each key or translated key - for(; key != keys.End() && (_state[*key] || _state[_GetAlternateKey(*key)]); ++key ); + for(; key != keys.end() && (_state[*key] || _state[_GetAlternateKey(*key)]); ++key ); // success if all matched - if( key == keys.End() ) + if( key == keys.end() ) return combo; } diff --git a/source/Core/Windows/ShellUi.cpp b/source/Core/Windows/ShellUi.cpp index afb7c05..1490c9b 100644 --- a/source/Core/Windows/ShellUi.cpp +++ b/source/Core/Windows/ShellUi.cpp @@ -122,7 +122,7 @@ namespace Core if(GetMenuItemInfo(_menu, wid, FALSE, &mi)) { // notify - for( ListenerIterator l = _listeners.Begin(); l != _listeners.End(); ++l ) + for( ListenerIterator l = _listeners.begin(); l != _listeners.end(); ++l ) { // get current state Bool enabled = (mi.fState & MFS_CHECKED) != 0; @@ -183,7 +183,7 @@ namespace Core default: // notify - for( ListenerIterator l = _listeners.Begin(); l != _listeners.End(); ++l ) + for( ListenerIterator l = _listeners.begin(); l != _listeners.end(); ++l ) if((*l)->OnMessage(hwnd, message, wparam, lparam)) return 0; } diff --git a/source/Core/Windows/SystemTools.cpp b/source/Core/Windows/SystemTools.cpp index e7342d7..1b89c95 100644 --- a/source/Core/Windows/SystemTools.cpp +++ b/source/Core/Windows/SystemTools.cpp @@ -193,4 +193,173 @@ namespace Core // close token handle CloseHandle(handle); } + + //------------------------------------------------------------------------- + Bool SystemTools::TestGameWindow( HWND hwnd ) + { + // constants + static const ULong TEST_FRAMES_UPDATING_COUNT = 3; + + /* + ghetto attempt at determining if a window belongs to a game :) + TODO: find better way! + */ + RECT client_region = { 0 }; + + // get required window client region + if( !GetClientRect( hwnd, &client_region ) ) + return false; + + // cannot be desktop window + if( GetDesktopWindow() == hwnd ) + return false; + + // require a valid minimum game window size + if( !IsValidGameWindowSize( RectToSize( client_region ) ) ) + return false; + + // require frames are updating. this will false positive with various apps + // like running video players and screen savers but oh well /shrug + if( !TestFramesUpdating( client_region, hwnd, TEST_FRAMES_UPDATING_COUNT ) ) + return false; + + return true; + } + + //------------------------------------------------------------------------- + Bool SystemTools::IsValidGameWindowSize( const SIZE& size ) + { + // require min width/height + return size.cx >= GAME_WINDOW_MIN_WIDTH && size.cy >= GAME_WINDOW_MIN_HEIGHT; + } + + //------------------------------------------------------------------------- + Bool SystemTools::TestFramesUpdating( const RECT& region, HWND hwnd, ULong test_count ) + { + ULong success_count = 0; + + // use desktop window with screen coords (to avoid some anticheats such as with WoW) + RECT desktop_region = region; + HWND desktop_hwnd = GetDesktopWindow(); + + // map region to desktop, if 0 result, then fullscreen app + if( MapWindowPoints( hwnd, desktop_hwnd, (LPPOINT)&desktop_region, 2 ) == 0 ) + { + // success if fullscreen app is foreground window suggesting dedicated fullscreen game + //TODO: find better way to determine dedicated fullscreen app + return GetForegroundWindow() == hwnd; + } + HDC desktop_hdc = GetDC(desktop_hwnd); + + // test frames updating by desktop hdc + for( Index i = 0; i < test_count; ++i ) + success_count += _TestFramesUpdating( desktop_region, desktop_hdc ); + + // release hdc + ReleaseDC( desktop_hwnd, desktop_hdc ); + + // succes if all test successful + return success_count == test_count; + } + + //------------------------------------------------------------------------- + SIZE SystemTools::RectToSize( const RECT& rect ) + { + SIZE size; + + size.cx = rect.right - rect.left; + size.cy = rect.bottom - rect.top; + + return size; + }; + + //private + //------------------------------------------------------------------------- + Bool SystemTools::_TestFramesUpdating( const RECT& region, HDC hdc ) + { + // constants + static const ULong TEST_FRAMES_UPDATING_DELAY = 20; //ms + static const ULong TEST_FRAMES_UPDATING_ITERATIONS = 10; + static const Long TEST_PIXEL_OFFSET = 5; + + // types + struct TestPixel + { + POINT position; + COLORREF color; + }; + + // choose 4 pixels in region corners + TestPixel test_pixels[] = { + { { region.left + TEST_PIXEL_OFFSET, region.bottom - TEST_PIXEL_OFFSET } }, + { { region.left + TEST_PIXEL_OFFSET, region.top + TEST_PIXEL_OFFSET } }, + { { region.right - TEST_PIXEL_OFFSET, region.bottom - TEST_PIXEL_OFFSET } }, + { { region.right - TEST_PIXEL_OFFSET, region.top + TEST_PIXEL_OFFSET } }, + }; + ULong valid_count = 0; + + // initialize pixels + for( Index i = 0; i < COUNT( test_pixels ); ++i ) + { + // get test pixel + TestPixel& test_pixel = test_pixels[i]; + + // get/save current pixel color in test pixel entry + test_pixel.color = GetPixel(hdc, test_pixel.position.x, test_pixel.position.y); + + // skip if invalid + if( test_pixel.color == CLR_INVALID ) + continue; + + // change it a little by flipping lower color component bits + test_pixel.color ^= 0x00010101; + + // apply new color + SetPixel(hdc, test_pixel.position.x, test_pixel.position.y, test_pixel.color); + + // increment valid count + ++valid_count; + } + + // fail if no valid pixels + if( valid_count == 0 ) + return false; + + // test pixels for changes + for( Index i = 0; i < TEST_FRAMES_UPDATING_ITERATIONS; ++i ) + { + // track total pixels changed + ULong change_count = 0; + + // let frames update + Sleep( TEST_FRAMES_UPDATING_DELAY ); + + // for each test pixel + for( Index j = 0; j < COUNT( test_pixels ); ++j ) + { + // get test pixel + const TestPixel& test_pixel = test_pixels[j]; + + // if valid + if( test_pixel.color != CLR_INVALID ) + { + // get current pixel color + COLORREF current_color = GetPixel( hdc, test_pixel.position.x, test_pixel.position.y ); + + // if changed, increment change count + if( current_color != test_pixel.color ) + ++change_count; + } + } + + // success if all valid pixels changed + if( change_count == valid_count ) + return true; + // else fail if some, but none, changed + else if( change_count != 0 ) + return false; + } + + return false; + } } diff --git a/source/Core/Windows/SystemTools.hpp b/source/Core/Windows/SystemTools.hpp index f2c90dc..3acab9d 100644 --- a/source/Core/Windows/SystemTools.hpp +++ b/source/Core/Windows/SystemTools.hpp @@ -22,5 +22,21 @@ namespace Core /**/ static HANDLE OpenDebugPrivileges(); static void CloseDebugPrivileges( HANDLE handle ); + + /**/ + static Bool TestGameWindow( HWND hwnd ); + + /**/ + static Bool IsValidGameWindowSize( const SIZE& size ); + + /**/ + static Bool TestFramesUpdating( const RECT& region, HWND hwnd, ULong test_count=1 ); + + /**/ + static SIZE RectToSize( const RECT& rect ); + + private: + /**/ + static Bool _TestFramesUpdating( const RECT& region, HDC hdc ); }; } diff --git a/source/YoloMouse/Dll/App.cpp b/source/YoloMouse/Dll/App.cpp index c8590f5..cfc7ccd 100644 --- a/source/YoloMouse/Dll/App.cpp +++ b/source/YoloMouse/Dll/App.cpp @@ -6,30 +6,29 @@ namespace YoloMouse { // fields //------------------------------------------------------------------------- - Bool App::_active (false); - HWND App::_hwnd = NULL; + Bool App::_active = false; + HWND App::_hwnd = NULL; CursorBindings App::_bindings; CursorVault App::_vault; HandleCache App::_cache; - HCURSOR App::_last_cursor (NULL); - HCURSOR App::_replace_cursor (NULL); - CursorBindings::Binding* App::_current_binding(NULL); + HCURSOR App::_last_cursor = NULL; + HCURSOR App::_replace_cursor = NULL; + CursorBindings::Binding* App::_current_binding = NULL; PathString App::_target_id; - Bool App::_refresh_ready (false); - Native App::_classlong_original = 0; - Native App::_classlong_last = 0; + Bool App::_refresh_ready = false; + Bool App::_setclasslong_self = false; + Native App::_classlong_save = INVALID_HANDLE; - Index App::_update_group (INVALID_INDEX); - Long App::_update_size (0); - Bool App::_update_default (false); + Index App::_update_preset_major_index = INVALID_INDEX; + Long App::_update_size_delta = 0; - Hook App::_hook_setcursor (SetCursor, App::_OnHookSetCursor, Hook::BEFORE); + Hook App::_hook_setcursor (SetCursor, App::_OnHookSetCursor, Hook::BEFORE); #if CPU_64 - Hook App::_hook_setclasslonga (SetClassLongPtrA, App::_OnHookSetClassLong, Hook::BEFORE); - Hook App::_hook_setclasslongw (SetClassLongPtrW, App::_OnHookSetClassLong, Hook::BEFORE); + Hook App::_hook_setclasslonga (SetClassLongPtrA, App::_OnHookSetClassLong, Hook::BEFORE); + Hook App::_hook_setclasslongw (SetClassLongPtrW, App::_OnHookSetClassLong, Hook::BEFORE); #else - Hook App::_hook_setclasslonga (SetClassLongA, App::_OnHookSetClassLong, Hook::BEFORE); - Hook App::_hook_setclasslongw (SetClassLongW, App::_OnHookSetClassLong, Hook::BEFORE); + Hook App::_hook_setclasslonga (SetClassLongA, App::_OnHookSetClassLong, Hook::BEFORE); + Hook App::_hook_setclasslongw (SetClassLongW, App::_OnHookSetClassLong, Hook::BEFORE); #endif // public @@ -53,9 +52,6 @@ namespace YoloMouse return false; } - // backup class long value - _SaveCursorClassLong(); - // load hooks if( !_LoadHooks() ) return false; @@ -86,20 +82,20 @@ namespace YoloMouse // unload hooks _UnloadHooks(); - // restore original classlong - _RestoreCursorClassLong(); + // restore original class cursor + _RestoreClassCursor(); // unload state state.Close(); - // reset - _update_size = 0; - _update_group = INVALID_INDEX; + // reset fields + _update_size_delta = 0; + _update_preset_major_index = INVALID_INDEX; _active = false; } //------------------------------------------------------------------------- - Bool App::UpdateCursor( Index group_index ) + Bool App::UpdatePreset( Index preset_major_index ) { // require active if( !_active ) @@ -109,7 +105,7 @@ namespace YoloMouse } // mark for update - _update_group = group_index; + _update_preset_major_index = preset_major_index; // refresh cursor Refresh(); @@ -126,26 +122,8 @@ namespace YoloMouse return false; } - // mark for update - _update_size = size_index_delta; - - // refresh cursor - Refresh(); - - return true; - } - - Bool App::UpdateDefault() - { - // require active - if( !_active ) - { - elog("DllApp.UpdateDefault.NotActive"); - return false; - } - - // mark for update - _update_default = true; + // mark size index delta update + _update_size_delta = size_index_delta; // refresh cursor Refresh(); @@ -168,7 +146,7 @@ namespace YoloMouse // get last cursor HCURSOR refresh_cursor = _last_cursor; - // get target window + // get focus window HWND hwnd = SystemTools::GetFocusWindow(); if( hwnd == NULL ) { @@ -195,11 +173,15 @@ namespace YoloMouse // attach to window thread. this is to make GetCursor and SetCursor work properly if( AttachThreadInput(hwnd_thread_id, current_thread_id, TRUE) ) { - // if does not exist + // if refresh cursor does not exist if( refresh_cursor == NULL ) { - // get active windows cursor - refresh_cursor = GetCursor(); + // get current application class cursor + refresh_cursor = _GetClassCursor(); + + // if does not exist, try global windows cursor (error prone) + if( refresh_cursor == NULL ) + refresh_cursor = GetCursor(); // cannot be yolomouse cursor if( _vault.HasCursor(refresh_cursor) ) @@ -217,7 +199,7 @@ namespace YoloMouse SetCursor( refresh_cursor ); // then trigger application to call SetCursor with its own cursor - PostMessage(hwnd, WM_SETCURSOR, (WPARAM)hwnd, MAKELPARAM(HTCLIENT, WM_MOUSEMOVE)); + PostMessage(hwnd, WM_SETCURSOR, (WPARAM)hwnd, MAKELPARAM(HTCLIENT, WM_LBUTTONDOWN)); // detach from window thread AttachThreadInput(hwnd_thread_id, current_thread_id, FALSE); @@ -280,43 +262,87 @@ namespace YoloMouse //------------------------------------------------------------------------- void App::_LoadCursors() { - const CursorBindings::MapTable& map = _bindings.GetMap(); - // load cursor map from file _bindings.Load(_target_id); - // get default - CursorBindings::Binding& default_binding = _bindings.EditDefault(); - if( default_binding.Isvalid() ) + // for each binding + for( CursorBindings::Binding& binding: _bindings.GetBindings() ) { - // load default cursor - _vault.Load(default_binding.resource_index, default_binding.size_index); + // load preset cursor + if( binding.cursor_hash != 0 ) + _vault.LoadPreset(binding.preset_index, binding.size_index); } - // for each map entry - for( CursorBindings::MapIterator cm = map.Begin(); cm != map.End(); ++cm ) - { - // load cursor - if( cm->bitmap_hash != 0 ) - _vault.Load(cm->resource_index, cm->size_index); - } + // identity cursors will be loaded on demand } void App::_UnloadCursors() { - // unload cursors + // unload all cursors _vault.UnloadAll(); } //------------------------------------------------------------------------- - Bool App::_OnUpdateGroup( HCURSOR hcursor ) + Bool App::_LoadCursorByBinding( const CursorBindings::Binding& binding, HCURSOR hcursor ) { - Index size_index = CURSOR_INDEX_DEFAULT; - Index group_index = _update_group; - Index last_resource_index = INVALID_INDEX; + // by resource type + switch( binding.resource_type ) + { + case RESOURCE_IDENTITY: + // load identity cursor + return _vault.LoadIdentity(binding.cursor_hash, binding.size_index, hcursor); + case RESOURCE_PRESET: + // load preset cursor + return _vault.LoadPreset(binding.preset_index, binding.size_index); + default: + return false; + } + } + + void App::_UnloadCursorByBinding( const CursorBindings::Binding& binding ) + { + // by resource type + switch( binding.resource_type ) + { + case RESOURCE_IDENTITY: + // unload identity cursor + _vault.UnloadIdentity(binding.cursor_hash, binding.size_index); + break; + case RESOURCE_PRESET: + // unload preset cursor + _vault.UnloadPreset(binding.preset_index, binding.size_index); + break; + default:; + } + } + + Bool App::_GetCursorByBinding( HCURSOR& hcursor, const CursorBindings::Binding& binding ) + { + // by resource type + switch( binding.resource_type ) + { + case RESOURCE_IDENTITY: + // get identity cursor + hcursor = _vault.GetIdentity(binding.cursor_hash, binding.size_index); + return hcursor != NULL; + case RESOURCE_PRESET: + // get preset cursor + hcursor = _vault.GetPreset(binding.preset_index, binding.size_index); + return hcursor != NULL; + default: + return false; + } + } + + //------------------------------------------------------------------------- + Bool App::_OnUpdatePreset( HCURSOR hcursor ) + { + Index size_index = CURSOR_SIZE_INDEX_DEFAULT; + Index preset_major_index = _update_preset_major_index; + Index last_preset_index = INVALID_INDEX; // clear state - _update_group = INVALID_INDEX; + _update_preset_major_index = INVALID_INDEX; // cannot be yolomouse cursor if( _vault.HasCursor(hcursor) ) @@ -336,18 +362,18 @@ namespace YoloMouse } // get cursor binding - CursorBindings::Binding* binding = _bindings.GetBinding(cursor_hash); + CursorBindings::Binding* binding = _bindings.GetBindingByHash(cursor_hash); // remove previous binding if( binding ) { - // save last resource index - last_resource_index = binding->resource_index; + // save last preset index + last_preset_index = binding->preset_index; - // unload cursor - _vault.Unload(last_resource_index, binding->size_index); + // unload previous cursor + _UnloadCursorByBinding( *binding ); - // save size index + // keep last size index size_index = binding->size_index; // remove binding @@ -355,52 +381,53 @@ namespace YoloMouse } // add new binding if not explicitly removing - if( group_index != CURSOR_SPECIAL_REMOVE && group_index < CURSOR_GROUP_COUNT ) + if( preset_major_index != CURSOR_SPECIAL_REMOVE && preset_major_index < CURSOR_RESOURCE_PRESET_MAJOR_COUNT ) { - Index cursor_index = 0; - Index resource_index = INVALID_INDEX; + CursorBindings::Binding binding; + Index preset_minor_index = 0; + Index preset_index = INVALID_INDEX; + Bool loaded = false; - // if has previous resource index and same group iterate that cursor index - if( last_resource_index != INVALID_INDEX && group_index == (last_resource_index / CURSOR_GROUP_SIZE) ) - cursor_index = (last_resource_index + 1) % CURSOR_GROUP_SIZE; + // if has previous preset index and same major index iterate minor index + if( last_preset_index != INVALID_INDEX && preset_major_index == (last_preset_index / CURSOR_RESOURCE_PRESET_MINOR_COUNT) ) + preset_minor_index = (last_preset_index + 1) % CURSOR_RESOURCE_PRESET_MINOR_COUNT; // load attempt loop - for( Index load_attempt = 0; load_attempt < CURSOR_GROUP_SIZE; load_attempt++, cursor_index = (cursor_index + 1) % CURSOR_GROUP_SIZE ) + for( Index load_attempt = 0; load_attempt < CURSOR_RESOURCE_PRESET_MINOR_COUNT; load_attempt++, preset_minor_index = (preset_minor_index + 1) % CURSOR_RESOURCE_PRESET_MINOR_COUNT ) { - // calculate resource index - resource_index = (group_index * CURSOR_GROUP_SIZE) + cursor_index; + // calculate preset index + preset_index = (preset_major_index * CURSOR_RESOURCE_PRESET_MINOR_COUNT) + preset_minor_index; - // if valid index load cursor - if( resource_index < CURSOR_RESOURCE_LIMIT && _vault.Load(resource_index, size_index) ) + // load if valid preset index + if( preset_index < CURSOR_RESOURCE_PRESET_COUNT && _vault.LoadPreset( preset_index, size_index ) ) + { + loaded = true; break; + } } // fail if nothing loaded - if( resource_index == INVALID_INDEX ) + if( !loaded ) { elog("DllApp.OnUpdateGroup.NothingLoaded"); return false; } + // create binding + binding.cursor_hash = cursor_hash; + binding.size_index = size_index; + binding.resource_type = RESOURCE_PRESET; + binding.preset_index = preset_index; + // add binding - if( _bindings.Add(cursor_hash, resource_index, size_index) == NULL ) + if( _bindings.Add(binding) == NULL ) { elog("DllApp.OnUpdateGroup.AddBinding"); return false; } } - // else if removing - else - { - // if no previous binding - if( binding == NULL ) - { - // update default (to clear it) - _update_default = true; - } - } - // save cursor map to file + // save cursor bindings _bindings.Save(_target_id); return true; @@ -408,10 +435,10 @@ namespace YoloMouse Bool App::_OnUpdateSize( HCURSOR hcursor ) { - Long size_index_delta = _update_size; + Long size_index_delta = _update_size_delta; - // clear state - _update_size = 0; + // clear size state + _update_size_delta = 0; // cannot be yolomouse cursor if( _vault.HasCursor(hcursor) ) @@ -431,58 +458,48 @@ namespace YoloMouse } // get cursor binding - CursorBindings::Binding* binding = _bindings.GetBinding(cursor_hash); + CursorBindings::Binding* binding = _bindings.GetBindingByHash(cursor_hash); - // require binding - if( binding == NULL ) - return false; + // if has binding + if( binding != NULL ) + { + // unload previous cursor + _UnloadCursorByBinding( *binding ); + } + // create identity binding (bind current application cursor for resizing) + else + { + CursorBindings::Binding identity_binding; - // unload previous cursor - _vault.Unload(binding->resource_index, binding->size_index); + // create identity binding + identity_binding.cursor_hash = cursor_hash; + identity_binding.resource_type = RESOURCE_IDENTITY; + + // select initial size index as nearest current cursor's size + identity_binding.size_index = SharedTools::CursorSizeToSizeIndex( SharedTools::CursorToSize( hcursor ) ); + + // add identity binding + binding = _bindings.Add( identity_binding ); + if( binding == NULL ) + { + elog("DllApp.OnUpdateSize.AddBinding"); + return false; + } + } // calculate new size index - Index size_index = Tools::Clamp(binding->size_index + size_index_delta, 0, CURSOR_INDEX_COUNT - 1); - + binding->size_index = Tools::Clamp(binding->size_index + size_index_delta, 0, CURSOR_SIZE_INDEX_COUNT - 1); + // load cursor with new size - if( !_vault.Load(binding->resource_index, size_index) ) + if( !_LoadCursorByBinding(*binding, hcursor) ) return false; - // update binding size index - binding->size_index = size_index; - // save cursor map to file _bindings.Save(_target_id); return true; } - void App::_OnUpdateDefault() - { - // clear state - _update_default = false; - - // get default binding - CursorBindings::Binding& default_binding = _bindings.EditDefault(); - - // if valid unload that cursor - if( default_binding.Isvalid() ) - _vault.Unload(default_binding.resource_index, default_binding.size_index); - - // if has current binding make that the default - if( _current_binding ) - default_binding = *_current_binding; - // else clear default binding - else - default_binding = CursorBindings::Binding(); - - // if valid load that cursor - if( default_binding.Isvalid() ) - _vault.Load(default_binding.resource_index, default_binding.size_index); - - // save cursor map to file - _bindings.Save(_target_id); - } - //------------------------------------------------------------------------- Bool App::_OnCursorChanging( HCURSOR hcursor ) { @@ -507,26 +524,28 @@ namespace YoloMouse _replace_cursor = NULL; // get cursor binding - _current_binding = _bindings.GetBinding(cursor_hash); + _current_binding = _bindings.GetBindingByHash(cursor_hash); - // if has binding - if( _current_binding ) - { - // update replacement cursor - _replace_cursor = _vault.GetCursor(_current_binding->resource_index, _current_binding->size_index); - } - // else try default - else + // fail if no binding + if( _current_binding == nullptr ) + return false; + + // success if get replacement cursor from binding + if( _GetCursorByBinding( _replace_cursor, *_current_binding ) ) + return true; + + // if identity binding + if( _current_binding->resource_type == RESOURCE_IDENTITY ) { - // get default - CursorBindings::Binding& default_binding = _bindings.EditDefault(); + // if failed and identity cursor, then attempt to load and try again + if( !_LoadCursorByBinding(*_current_binding, hcursor) ) + return false; - // replace if valid - if( default_binding.Isvalid() ) - _replace_cursor = _vault.GetCursor(default_binding.resource_index, default_binding.size_index); + // try again + return _GetCursorByBinding( _replace_cursor, *_current_binding ); } - return true; + return false; } //------------------------------------------------------------------------- @@ -547,10 +566,10 @@ namespace YoloMouse _last_cursor = NULL; // if updating new cursor - if( _update_group != INVALID_INDEX ) + if( _update_preset_major_index != INVALID_INDEX ) { - // handle cursor group - if(!_OnUpdateGroup(old_cursor)) + // handle cursor preset update + if(!_OnUpdatePreset(old_cursor)) return; // set refresh state @@ -558,9 +577,9 @@ namespace YoloMouse } // if updating size - if( _update_size != 0 ) + if( _update_size_delta != 0 ) { - // handle cursor size + // handle cursor size update if(!_OnUpdateSize(old_cursor)) return; @@ -568,13 +587,6 @@ namespace YoloMouse _refresh_ready = true; } - // if updating default - if( _update_default ) - { - // handle cursor default - _OnUpdateDefault(); - } - // if refreshing cursor if( _refresh_ready ) { @@ -600,11 +612,8 @@ namespace YoloMouse //------------------------------------------------------------------------- VOID HOOK_CALL App::_OnHookSetCursor( Native* arguments ) { - // backup class long value - _SaveCursorClassLong(); - - // update cursor using setclasslong method first - _SetCursorClassLong( arguments[1] ); + // update cursor using class method first + _SetClassCursor( arguments[1] ); // if replacement cursor was set pass it out to setcursor method if( _replace_cursor != NULL ) @@ -620,51 +629,59 @@ namespace YoloMouse if((int)arguments[2] == GCL_HCURSOR) #endif { + // backup class cursor value if not yet saved. yes do it here ;) + if( _classlong_save == INVALID_HANDLE ) + _SaveClassCursor(); + + // if not self calling this, save classlong value to be restored on exit + if( !_setclasslong_self ) + _classlong_save = static_cast(arguments[3]); + // update cursor _OnCursorHook((HCURSOR&)arguments[3], (HCURSOR)arguments[3]); } } //------------------------------------------------------------------------- - void App::_SetCursorClassLong( Native value ) + HCURSOR App::_GetClassCursor() { - // set class long value + // save current class long value #if CPU_64 - SetClassLongPtrA( _hwnd, GCLP_HCURSOR, (LONG_PTR)value ); + return (HCURSOR)GetClassLongPtrA( _hwnd, GCLP_HCURSOR ); #else - SetClassLongA( _hwnd, GCL_HCURSOR, (LONG)value ); + return (HCURSOR)GetClassLongA( _hwnd, GCL_HCURSOR ); #endif - - // set last class long value - _classlong_last = value; } - void App::_SaveCursorClassLong() + void App::_SetClassCursor( Native value ) { - Native current_value; + // set self caller state + _setclasslong_self = true; - // get current class long value + // set class long value #if CPU_64 - current_value = (Native)GetClassLongPtrA( _hwnd, GCLP_HCURSOR ); + SetClassLongPtrA( _hwnd, GCLP_HCURSOR, (LONG_PTR)value ); #else - current_value = (Native)GetClassLongA( _hwnd, GCL_HCURSOR ); + SetClassLongA( _hwnd, GCL_HCURSOR, (LONG)value ); #endif - // if not last then update as original value - if( current_value != _classlong_last ) - _classlong_original = current_value; + // reset self caller state + _setclasslong_self = false; + } + + void App::_SaveClassCursor() + { + // save current class cursor + _classlong_save = reinterpret_cast(_GetClassCursor()); } - void App::_RestoreCursorClassLong() + void App::_RestoreClassCursor() { // if any changes made - if( _classlong_last ) + if( _classlong_save != INVALID_HANDLE ) { - // get current original class long - _SaveCursorClassLong(); - // restore original class long - _SetCursorClassLong( _classlong_original ); + _SetClassCursor( _classlong_save ); } } } diff --git a/source/YoloMouse/Dll/App.hpp b/source/YoloMouse/Dll/App.hpp index 846893a..bce8c27 100644 --- a/source/YoloMouse/Dll/App.hpp +++ b/source/YoloMouse/Dll/App.hpp @@ -18,9 +18,8 @@ namespace YoloMouse static void Unload(); /**/ - static Bool UpdateCursor( Index resource_index ); + static Bool UpdatePreset( Index preset_major_index ); static Bool UpdateSize( Long size_index_delta ); - static Bool UpdateDefault(); /**/ static Bool Refresh(); @@ -35,9 +34,13 @@ namespace YoloMouse static void _UnloadCursors(); /**/ - static Bool _OnUpdateGroup( HCURSOR hcursor ); + static Bool _LoadCursorByBinding( const CursorBindings::Binding& binding, HCURSOR hcursor=NULL ); + static void _UnloadCursorByBinding( const CursorBindings::Binding& binding ); + static Bool _GetCursorByBinding( HCURSOR& hcursor, const CursorBindings::Binding& binding ); + + /**/ + static Bool _OnUpdatePreset( HCURSOR hcursor ); static Bool _OnUpdateSize( HCURSOR hcursor ); - static void _OnUpdateDefault(); /**/ static Bool _OnCursorChanging( HCURSOR hcursor ); @@ -47,9 +50,10 @@ namespace YoloMouse static VOID HOOK_CALL _OnHookSetCursor( Native* arguments ); static VOID HOOK_CALL _OnHookSetClassLong( Native* arguments ); - static void _SetCursorClassLong( Native value ); - static void _SaveCursorClassLong(); - static void _RestoreCursorClassLong(); + static HCURSOR _GetClassCursor(); + static void _SetClassCursor( Native value ); + static void _SaveClassCursor(); + static void _RestoreClassCursor(); // fields: state static Bool _active; @@ -62,13 +66,12 @@ namespace YoloMouse static CursorBindings::Binding* _current_binding; static PathString _target_id; static Bool _refresh_ready; - static Native _classlong_original; - static Native _classlong_last; + static Bool _setclasslong_self; + static Native _classlong_save; // fields: input - static Index _update_group; - static Long _update_size; - static Bool _update_default; + static Index _update_preset_major_index; + static Long _update_size_delta; // fields: hooks static Hook _hook_setcursor; diff --git a/source/YoloMouse/Dll/CursorBindings.cpp b/source/YoloMouse/Dll/CursorBindings.cpp index 91cc15d..924086b 100644 --- a/source/YoloMouse/Dll/CursorBindings.cpp +++ b/source/YoloMouse/Dll/CursorBindings.cpp @@ -2,7 +2,6 @@ #include #include #include -#include #include namespace YoloMouse @@ -10,27 +9,16 @@ namespace YoloMouse // CursorBindings.Binding //------------------------------------------------------------------------- CursorBindings::Binding::Binding(): - bitmap_hash (0), - resource_index (INVALID_INDEX), - size_index (INVALID_INDEX) + cursor_hash (0), + size_index (INVALID_INDEX), + resource_type (RESOURCE_UNKNOWN), + resource_index (0) { } - CursorBindings::Binding::Binding( Hash bitmap_hash_, Index resource_index_, Index size_index_ ): - bitmap_hash (bitmap_hash_), - resource_index (resource_index_), - size_index (size_index_) + Bool CursorBindings::Binding::operator==( const Hash& cursor_hash_ ) const { - } - - Bool CursorBindings::Binding::Isvalid() const - { - return resource_index != INVALID_INDEX && size_index != INVALID_INDEX; - } - - Bool CursorBindings::Binding::operator==( const Hash& hash_ ) const - { - return bitmap_hash == hash_; + return cursor_hash == cursor_hash_; } // public @@ -40,48 +28,28 @@ namespace YoloMouse } //------------------------------------------------------------------------- - CursorBindings::Binding* CursorBindings::GetBinding( Hash cursor_hash ) const + CursorBindings::Binding* CursorBindings::GetBindingByHash( Hash cursor_hash ) const { - // find binding - MapIterator binding = _bindings.Find(cursor_hash); - - // return binding - return binding ? binding : NULL; + return _bindings.Find(cursor_hash); } - const CursorBindings::MapTable& CursorBindings::GetMap() const + const CursorBindings::BindingCollection& CursorBindings::GetBindings() const { return _bindings; } //------------------------------------------------------------------------- - CursorBindings::Binding& CursorBindings::EditDefault() - { - return _default; - } - - //------------------------------------------------------------------------- - CursorBindings::Binding* CursorBindings::Add( Hash cursor_hash, Index resource_index, Index size_index ) + CursorBindings::Binding* CursorBindings::Add( const Binding& binding ) { - // bounds checks - if( cursor_hash == 0 ) + // validate + if( !_ValidateBinding( binding ) ) { - elog("CursorBindings.Add.CursorHashIsZero"); - return NULL; - } - if( resource_index >= CURSOR_RESOURCE_LIMIT ) - { - elog("CursorBindings.Add.ResourceIndexOverLimit: %d", resource_index); - return NULL; - } - if( size_index >= CURSOR_INDEX_COUNT ) - { - elog("CursorBindings.Add.SizeIndexOverLimit: %d", size_index); + elog("CursorBindings.Add.ValidateBinding"); return NULL; } // find free binding - MapIterator binding = _bindings.Find(0); + Binding* free_binding = _bindings.Find(0); // fail if full if( binding == NULL ) @@ -90,18 +58,16 @@ namespace YoloMouse return NULL; } - // build - binding->resource_index = resource_index; - binding->size_index = size_index; - binding->bitmap_hash = cursor_hash; + // update free binding + *free_binding = binding; - return binding; + return free_binding; } //------------------------------------------------------------------------- void CursorBindings::Remove( CursorBindings::Binding& binding ) { - // reset + // resets hash to 0, making it free entry binding = Binding(); } @@ -109,8 +75,6 @@ namespace YoloMouse Bool CursorBindings::Load( const WCHAR* target_id ) { PathString load_path; - Hash bitmap_hash; - Index resource_index; FILE* file = NULL; // build save path @@ -124,27 +88,24 @@ namespace YoloMouse if( _wfopen_s(&file, load_path, L"rt") != 0 ) return false; - // reset map + // reset bindings collection _bindings.Zero(); - // for each line - while( true ) + // for each line in file, until end of file or sanity limit reached + for( Index linei = 0; feof(file) == 0 && linei < (CURSOR_BINDING_LIMIT * 3); ++linei ) { - Index size = CURSOR_INDEX_DEFAULT; + Binding binding; - // read line - if( fscanf_s(file, "%u=%I64u,%u\n", &resource_index, &bitmap_hash, &size) < 2 ) - break; - - // get size index from size - Index size_index = _GetSizeIndex(size); + // read binding line + if( _ReadBindingLine( binding, file ) ) + { + // find free binding + Binding* free_binding = _bindings.Find(0); - // set default - if( bitmap_hash == 0 ) - _default = Binding(bitmap_hash, resource_index, size_index); - // else add entry - else - Add( bitmap_hash, resource_index, size_index ); + // if available, replace with read binding + if( free_binding != NULL ) + *free_binding = binding; + } } // close file @@ -173,22 +134,15 @@ namespace YoloMouse return false; } - // if valid default - if( _default.Isvalid() ) - { - // write default entry - fprintf_s(file, "%u=0,%u\n", _default.resource_index, CURSOR_SIZE_TABLE[_default.size_index]); - written++; - } - - // for each map entry - for( MapIterator binding = _bindings.Begin(); binding != _bindings.End(); ++binding ) + // for each binding + for( const Binding& binding: _bindings ) { - // write valid entry - if( binding->bitmap_hash != 0 ) + // if valid entry + if( binding.cursor_hash != 0 ) { - fprintf_s(file, "%u=%I64u,%u\n", binding->resource_index, binding->bitmap_hash, CURSOR_SIZE_TABLE[binding->size_index]); - written++; + // if successfully written, increment written count + if( _WriteBindingLine( binding, file ) ) + written++; } } @@ -202,30 +156,77 @@ namespace YoloMouse return true; } + // private //------------------------------------------------------------------------- - Index CursorBindings::_GetSizeIndex( ULong size ) + Bool CursorBindings::_ReadBindingLine( Binding& binding, FILE* file ) { - // if original size - if( size == CURSOR_INDEX_ORIGINAL ) - return 0; + Index size = CURSOR_SIZE_INDEX_DEFAULT; + Char iresource_type = 0; + Char ini_line[INI_LINE_LIMIT]; + + // set defaults + binding.cursor_hash = 0; + binding.resource_type = RESOURCE_UNKNOWN; + binding.resource_index = INVALID_INDEX; + + // read line + if( fgets( ini_line, sizeof( ini_line ), file ) == NULL ) + return false; - // if old table (size is index) - if( size < CURSOR_SIZE_TABLE[1] ) + // read binding line from file (hash,size,resource-type,resource-id) + if( sscanf_s( ini_line, "%I64u,%u,%c,%u\n", &binding.cursor_hash, &size, &iresource_type, 1, &binding.resource_index ) != 4 ) { - // get size from old table - if( size < COUNT( CURSOR_SIZE_TABLE_V_0_8_3 ) ) - size = CURSOR_SIZE_TABLE_V_0_8_3[size]; - // else return default index - else - return CURSOR_INDEX_DEFAULT; + //BEGIN: v0.9.1 backwards compatibility + if( sscanf_s( ini_line, "%u=%I64u,%u\n", &binding.resource_index, &binding.cursor_hash, &size ) < 2 ) + return false; + iresource_type = RESOURCE_PRESET; + //END: v0.9.1 backwards compatibility } - // locate size index nearest requested size - for( Index i = 0; i < CURSOR_INDEX_COUNT; ++i ) - if( size <= CURSOR_SIZE_TABLE[i] ) - return i; + // translate fields + binding.resource_type = static_cast(iresource_type); + binding.size_index = SharedTools::CursorSizeToSizeIndex(size); + + // validate + return _ValidateBinding( binding ); + } + + Bool CursorBindings::_WriteBindingLine( const Binding& binding, FILE* file ) + { + // write binding line to file + fprintf_s( file, "%I64u,%u,%c,%u\n", + binding.cursor_hash, + CURSOR_SIZE_TABLE[binding.size_index], + binding.resource_type, + binding.resource_index ); + + return true; + } + + //------------------------------------------------------------------------- + Bool CursorBindings::_ValidateBinding( const Binding& binding ) + { + // validate hash + if( binding.cursor_hash == 0 ) + return false; + + // validate size index + if( binding.size_index >= CURSOR_SIZE_INDEX_COUNT ) + return false; - // use default - return CURSOR_INDEX_DEFAULT; + // validate resource type + parameters + switch( binding.resource_type ) + { + case RESOURCE_PRESET: + if( binding.resource_index >= CURSOR_RESOURCE_PRESET_COUNT ) + return false; + break; + case RESOURCE_IDENTITY: + break; + default: + return false; + } + + return true; } } diff --git a/source/YoloMouse/Dll/CursorBindings.hpp b/source/YoloMouse/Dll/CursorBindings.hpp index 51e6dd1..767838b 100644 --- a/source/YoloMouse/Dll/CursorBindings.hpp +++ b/source/YoloMouse/Dll/CursorBindings.hpp @@ -1,6 +1,8 @@ #pragma once #include #include +#include +#include namespace YoloMouse { @@ -8,40 +10,37 @@ namespace YoloMouse class CursorBindings { public: - /**/ + // types struct Binding { - Hash bitmap_hash; // hash of original cursor image bits - Index resource_index; // cursor resource index - Index size_index; // size index + Hash cursor_hash; // hash of original cursor image bits + Index size_index; // size index + ResourceType resource_type; // resource type + union + { + Index resource_index; + Index preset_index; // preset file index + }; /**/ Binding(); - Binding( Hash bitmap_hash_, Index resource_index_, Index size_index_ ); - - /**/ - Bool Isvalid() const; /**/ - Bool operator==( const Hash& hash_ ) const; + Bool operator==( const Hash& cursor_hash_ ) const; }; - /**/ - typedef FlatArray MapTable; - typedef MapTable::Iterator MapIterator; + // aliases + typedef FlatArray BindingCollection; /**/ CursorBindings(); /**/ - Binding* GetBinding( Hash cursor_hash ) const; - const MapTable& GetMap() const; + Binding* GetBindingByHash( Hash cursor_hash ) const; + const BindingCollection& GetBindings() const; /**/ - Binding& EditDefault(); - - /**/ - Binding* Add( Hash cursor_hash, Index resource_index, Index size_index ); + Binding* Add( const Binding& binding ); /**/ void Remove( CursorBindings::Binding& binding ); @@ -52,10 +51,13 @@ namespace YoloMouse private: /**/ - static Index _GetSizeIndex( ULong size ); + Bool _ReadBindingLine( Binding& binding, FILE* file ); + Bool _WriteBindingLine( const Binding& binding, FILE* file ); + + /**/ + static Bool _ValidateBinding( const Binding& binding ); // fields - MapTable _bindings; - Binding _default; + BindingCollection _bindings; }; } diff --git a/source/YoloMouse/Dll/CursorVault.cpp b/source/YoloMouse/Dll/CursorVault.cpp index 7d29e92..e44649a 100644 --- a/source/YoloMouse/Dll/CursorVault.cpp +++ b/source/YoloMouse/Dll/CursorVault.cpp @@ -4,17 +4,17 @@ namespace YoloMouse { - // CursorResource + // CursorCache //------------------------------------------------------------------------- - CursorVault::CursorResource::CursorResource(): - handle (NULL), + CursorVault::CursorCache::CursorCache(): + hcursor (NULL), referenced (0) { } - // CacheEntry + // PresetEntry //------------------------------------------------------------------------- - CursorVault::CacheEntry::CacheEntry(): + CursorVault::PresetEntry::PresetEntry(): state (RESOURCE_NONE), resizable (true), width (0), @@ -23,6 +23,19 @@ namespace YoloMouse { } + // IdentityEntry + //------------------------------------------------------------------------- + CursorVault::IdentityEntry::IdentityEntry(): + cursor_hash(0) + { + } + + //------------------------------------------------------------------------- + Bool CursorVault::IdentityEntry::operator==( const Hash& cursor_hash_ ) const + { + return cursor_hash == cursor_hash_; + } + // public //------------------------------------------------------------------------- CursorVault::CursorVault(): @@ -35,10 +48,93 @@ namespace YoloMouse } //------------------------------------------------------------------------- - Bool CursorVault::Load( Index resource_index, Index size_index ) + Bool CursorVault::HasCursor( HCURSOR hcursor ) + { + // for each preset entry + for( const PresetEntry& entry: _preset_table ) + { + // for each cache entry + for( const CursorCache& cache: entry.cache_table ) + { + // success if found + if( hcursor == cache.hcursor ) + return true; + } + } + + // for each identity entry + for( const IdentityEntry& entry: _identity_map ) + { + // for each cache entry + for( const CursorCache& cache: entry.cache_table ) + { + // success if found + if( hcursor == cache.hcursor ) + return true; + } + } + + return false; + } + + //------------------------------------------------------------------------- + HCURSOR CursorVault::GetIdentity( Hash cursor_hash, Index size_index ) + { + // find existing entry + IdentityEntry* entry = _identity_map.Find(cursor_hash); + + // return cursor handle if exists else null + return entry != nullptr ? entry->cache_table[size_index].hcursor : nullptr; + } + + HCURSOR CursorVault::GetPreset( Index preset_index, Index size_index ) + { + // get entry + PresetEntry& entry = _preset_table[preset_index]; + + // return cursor handle if any + return entry.resizable ? entry.cache_table[size_index].hcursor : entry.cache_table[0].hcursor; + } + + //------------------------------------------------------------------------- + Bool CursorVault::LoadIdentity( Hash cursor_hash, Index size_index, HCURSOR hcursor ) + { + xassert( cursor_hash != 0 ); + xassert( size_index < CURSOR_SIZE_INDEX_COUNT ); + xassert( hcursor != NULL ); + + // do use original size index + if( size_index == CURSOR_SIZE_INDEX_ORIGINAL ) + return false; + + // find existing entry + IdentityEntry* entry = _identity_map.Find(cursor_hash); + + // if does not exist + if( entry == nullptr ) + { + // fail if full + if( _identity_map.IsFull() ) + { + elog("CursorVault.LoadIdentity.Full"); + return false; + } + + // add new entry + entry = _identity_map.Add(); + + // add entry + entry->cursor_hash = cursor_hash; + } + + // load entry + return _LoadIdentity( *entry, size_index, hcursor ); + } + + Bool CursorVault::LoadPreset( Index preset_index, Index size_index ) { // get entry - CacheEntry& entry = _table[resource_index]; + PresetEntry& entry = _preset_table[preset_index]; // if not ready if( entry.state != RESOURCE_READY ) @@ -47,74 +143,177 @@ namespace YoloMouse if( entry.state == RESOURCE_FAILED ) return false; - // initialize cache - if( !_CacheInit( entry, resource_index ) ) + // initialize preset + if( !_InitPreset( entry, preset_index ) ) return false; } - // load into cache - return _CacheLoad( entry, size_index ); + // load preset + return _LoadPreset( entry, size_index ); } //------------------------------------------------------------------------- - void CursorVault::Unload( Index resource_index, Index size_index ) + void CursorVault::UnloadIdentity( Hash cursor_hash, Index size_index ) { - // get entry - CacheEntry& entry = _table[resource_index]; + xassert( cursor_hash != 0 ); + xassert( size_index < CURSOR_SIZE_INDEX_COUNT ); - // unload from cache - _CacheUnload(entry, size_index); + // find existing entry + IdentityEntry* entry = _identity_map.Find(cursor_hash); + + // if found + if( entry != nullptr ) + { + // unload identity entry + _UnloadIdentity( *entry, size_index ); + } + } + + void CursorVault::UnloadPreset( Index preset_index, Index size_index ) + { + xassert( preset_index < CURSOR_RESOURCE_PRESET_COUNT ); + xassert( size_index < CURSOR_SIZE_INDEX_COUNT ); + + // unload preset + _UnloadPreset( _preset_table[preset_index], size_index ); } void CursorVault::UnloadAll() { - // for each cursor - for( Index i = 0; i < _table.GetCount(); ++i ) + // for each identity entry + for( IdentityEntry& entry: _identity_map ) { - // for each handle by size - for( Index j = 0; j < CURSOR_INDEX_COUNT; ++j ) - { - // unload - Unload(i, j); - } + // for each size index, unload cursor cache + for( Index size_index = 0; size_index < CURSOR_SIZE_INDEX_COUNT; ++size_index ) + _UnloadIdentity( entry, size_index ); + } + + // for each preset entry + for( PresetEntry& entry: _preset_table ) + { + // for each size index, unload cursor cache + for( Index size_index = 0; size_index < CURSOR_SIZE_INDEX_COUNT; ++size_index ) + _UnloadPreset( entry, size_index ); } } + // private //------------------------------------------------------------------------- - HCURSOR CursorVault::GetCursor( Index resource_index, Index size_index ) + Bool CursorVault::_LoadIdentity( IdentityEntry& entry, Index size_index, HCURSOR hcursor ) { - // get entry - CacheEntry& entry = _table[resource_index]; + Bool status = false; - // return cursor handle if any - return entry.resizable ? entry.resources[size_index].handle : entry.resources[0].handle; - } + // get cache by size index + CursorCache& cache = entry.cache_table[size_index]; - //------------------------------------------------------------------------- - Bool CursorVault::HasCursor( HCURSOR hcursor ) - { - // for each cursor - for( Index i = 0; i < _table.GetCount(); ++i ) + // if not referenced + if( cache.referenced == 0 ) { - const ResourceTable& resources = _table[i].resources; + ICONINFO ii_base; + BITMAP bitmap_base; - // for each size - for( Index j = 0; j < CURSOR_INDEX_COUNT; ++j ) + // get base icon info + if( GetIconInfo(hcursor, &ii_base) == FALSE ) { - // success if found - if( hcursor == resources[j].handle ) - return true; + elog("CursorVault.LoadIdentity.GetIconInfo"); + return false; } + + // select bitmap handle to get bitmap from + HBITMAP hbitmap = ii_base.hbmColor ? ii_base.hbmColor : ii_base.hbmMask; + + // get base icon bitmap object + if( hbitmap == NULL || !GetObject( hbitmap, sizeof( BITMAP ), &bitmap_base ) ) + elog( "CursorVault.LoadIdentity.GetBitmapDimensionEx" ); + else + { + // require width/height over sane minimum + if( bitmap_base.bmWidth < 2 || bitmap_base.bmHeight < 2 ) + elog( "CursorVault.LoadIdentity.SizeTooSmall" ); + else + { + ULong width; + ULong height; + + // determine target width/height + height = CURSOR_SIZE_TABLE[size_index]; + + // if same, use height for width (typical case, avoids float scaling errors) + if( bitmap_base.bmWidth == bitmap_base.bmHeight ) + width = height; + // else scale + else + width = static_cast((static_cast(bitmap_base.bmWidth) / static_cast(bitmap_base.bmHeight)) * static_cast(height)); + + // fail if width or height is 0 + if( width == 0 || height == 0 ) + elog( "CursorVault.LoadIdentity.ResizeTooSmall" ); + else + { + ICONINFO ii_new = { 0 }; + + // resize hotspot + ii_new.xHotspot = static_cast((static_cast(ii_base.xHotspot) / static_cast(bitmap_base.bmWidth)) * static_cast(width)); + ii_new.yHotspot = static_cast((static_cast(ii_base.yHotspot) / static_cast(bitmap_base.bmHeight)) * static_cast(height)); + + // scale mask+color bitmap + if( ii_base.hbmMask != NULL ) + ii_new.hbmMask = (HBITMAP)CopyImage( ii_base.hbmMask, IMAGE_BITMAP, width, height, 0 ); + if( ii_base.hbmColor != NULL ) + ii_new.hbmColor = (HBITMAP)CopyImage( ii_base.hbmColor, IMAGE_BITMAP, width, height, 0 ); + + // creating cursor not icon + ii_new.fIcon = FALSE; + + // create scaled cursor + cache.hcursor = ::CreateIconIndirect( &ii_new ); + + // require new cursor created + if( cache.hcursor == NULL ) + elog( "CursorVault.LoadIdentity.CreateIconIndirect" ); + else + status = cache.hcursor != NULL; + + // cleanup new icon info + if( ii_new.hbmMask != NULL ) + DeleteObject( ii_new.hbmMask ); + if( ii_new.hbmColor != NULL ) + DeleteObject( ii_new.hbmColor ); + } + } + } + + // cleanup base icon info + if( ii_base.hbmColor != NULL ) + DeleteObject( ii_base.hbmColor ); + if( ii_base.hbmMask != NULL ) + DeleteObject( ii_base.hbmMask ); } - return false; + // increment referenced + cache.referenced++; + + return status; + } + + void CursorVault::_UnloadIdentity( IdentityEntry& entry, Index size_index ) + { + // get cache by size index + CursorCache& cache = entry.cache_table[size_index]; + + // if referenced + if( cache.referenced > 0 ) + { + // decrement referenced and unload if 0 + if( --cache.referenced == 0 ) + _UnloadCache( cache ); + } } - // private //------------------------------------------------------------------------- - Bool CursorVault::_CacheInit( CacheEntry& entry, Index resource_index ) + Bool CursorVault::_InitPreset( PresetEntry& entry, Index resource_index ) { - static const WCHAR* EXTENSIONS[] = { EXTENSION_ANIMATED, EXTENSION_STATIC }; + static const WCHAR* EXTENSIONS[] = { EXTENSION_ANIMATED_CURSOR, EXTENSION_STATIC_CURSOR }; static const WCHAR* SEARCH_PATHS[] = { PATH_CURSORS_CUSTOM, PATH_CURSORS_DEFAULT }; // for each search path @@ -154,15 +353,20 @@ namespace YoloMouse entry.height = abs(bmpinfo.bmHeight) / (iconinfo.hbmColor==NULL ? 2 : 1); entry.state = RESOURCE_READY; - // cleanup - if( iconinfo.hbmColor ) + // cleanup temporary resources + if( iconinfo.hbmColor != NULL ) DeleteObject(iconinfo.hbmColor); - if( iconinfo.hbmMask ) + if( iconinfo.hbmMask != NULL ) DeleteObject(iconinfo.hbmMask); DestroyCursor(hcursor); return true; } + // cleanup on fail + else + { + DestroyCursor(hcursor); + } } } } @@ -174,18 +378,18 @@ namespace YoloMouse return false; } - Bool CursorVault::_CacheLoad( CacheEntry& entry, Index size_index ) + Bool CursorVault::_LoadPreset( PresetEntry& entry, Index size_index ) { - CursorResource& resource = entry.resources[entry.resizable ? size_index : 0]; + CursorCache& cache = entry.cache_table[entry.resizable ? size_index : 0]; // if not referenced - if( resource.referenced == 0 ) + if( cache.referenced == 0 ) { ULong width; ULong height; // if resizable - if( entry.resizable && size_index != CURSOR_INDEX_ORIGINAL ) + if( entry.resizable && size_index != CURSOR_SIZE_INDEX_ORIGINAL ) { xassert(entry.width > 0 && entry.height > 0); @@ -200,8 +404,8 @@ namespace YoloMouse } // load cursor - resource.handle = reinterpret_cast(LoadImage(NULL, entry.path, IMAGE_CURSOR, width, height, entry.loadimage_flags)); - if( resource.handle == NULL ) + cache.hcursor = reinterpret_cast(LoadImage(NULL, entry.path, IMAGE_CURSOR, width, height, entry.loadimage_flags)); + if( cache.hcursor == NULL ) { elog("CursorVault.CacheLoad.LoadImage: %s %d %d %x", Tools::WToCString(entry.path), width, height, entry.loadimage_flags); return false; @@ -209,30 +413,35 @@ namespace YoloMouse } // increment referenced - resource.referenced++; + cache.referenced++; return true; } - void CursorVault::_CacheUnload( CacheEntry& entry, Index size_index ) + void CursorVault::_UnloadPreset( PresetEntry& entry, Index size_index ) { - CursorResource& resource = entry.resources[entry.resizable ? size_index : 0]; + // unload from cache + CursorCache& cache = entry.cache_table[entry.resizable ? size_index : 0]; // if referenced - if( resource.referenced > 0 ) + if( cache.referenced > 0 ) { - // decrement referenced and free if 0 - if( --resource.referenced == 0 ) - { - // must be loaded - xassert(resource.handle != NULL); + // decrement referenced and unload if 0 + if( --cache.referenced == 0 ) + _UnloadCache( cache ); + } + } + + //------------------------------------------------------------------------- + void CursorVault::_UnloadCache( CursorCache& cache ) + { + // must be loaded + xassert(cache.hcursor != NULL); - // free cursor - DestroyCursor(resource.handle); + // free cursor + DestroyCursor(cache.hcursor); - // reset - resource.handle = NULL; - } - } + // reset + cache.hcursor = NULL; } } diff --git a/source/YoloMouse/Dll/CursorVault.hpp b/source/YoloMouse/Dll/CursorVault.hpp index 2a375b1..80eb5f1 100644 --- a/source/YoloMouse/Dll/CursorVault.hpp +++ b/source/YoloMouse/Dll/CursorVault.hpp @@ -14,17 +14,20 @@ namespace YoloMouse ~CursorVault(); /**/ - Bool Load( Index resource_index, Index size_index ); + Bool HasCursor( HCURSOR hcursor ); /**/ - void Unload( Index resource_index, Index size_index ); - void UnloadAll(); + HCURSOR GetIdentity( Hash cursor_hash, Index size_index ); + HCURSOR GetPreset( Index preset_index, Index size_index ); /**/ - HCURSOR GetCursor( Index resource_index, Index size_index ); + Bool LoadIdentity( Hash cursor_hash, Index size_index, HCURSOR hcursor ); + Bool LoadPreset( Index preset_index, Index size_index ); /**/ - Bool HasCursor( HCURSOR hcursor ); + void UnloadIdentity( Hash cursor_hash, Index size_index ); + void UnloadPreset( Index preset_index, Index size_index ); + void UnloadAll(); private: // types @@ -35,36 +38,63 @@ namespace YoloMouse RESOURCE_FAILED, }; - struct CursorResource + struct CursorCache { - HCURSOR handle; + // fields + HCURSOR hcursor; ULong referenced; - CursorResource(); + /**/ + CursorCache(); + }; + typedef FlatArray CacheTable; + + struct IdentityEntry + { + // fields + Hash cursor_hash; + CacheTable cache_table; + + /**/ + IdentityEntry(); + + /**/ + Bool operator==( const Hash& cursor_hash_ ) const; }; - typedef FlatArray ResourceTable; - struct CacheEntry + struct PresetEntry { + // fields ResourceState state; Bool resizable; ULong width; ULong height; PathString path; UINT loadimage_flags; - ResourceTable resources; + CacheTable cache_table; - CacheEntry(); + /**/ + PresetEntry(); }; - typedef FlatArray CacheTable; + + typedef FixedArray IdentityMap; + typedef FlatArray PresetTable; + + /**/ + Bool _LoadIdentity( IdentityEntry& entry, Index size_index, HCURSOR hcursor ); + void _UnloadIdentity( IdentityEntry& entry, Index size_index ); + + /**/ + Bool _InitPreset( PresetEntry& entry, Index preset_index ); + Bool _LoadPreset( PresetEntry& entry, Index size_index ); + void _UnloadPreset( PresetEntry& entry, Index size_index ); /**/ - Bool _CacheInit( CacheEntry& entry, Index resource_index ); - Bool _CacheLoad( CacheEntry& entry, Index size_index ); - void _CacheUnload( CacheEntry& entry, Index size_index ); + void _UnloadCache( CursorCache& cache ); // fields - CacheTable _table; - SharedState& _state; + IdentityMap _identity_map; + PresetTable _preset_table; + SharedState& _state; }; } diff --git a/source/YoloMouse/Dll/HandleCache.cpp b/source/YoloMouse/Dll/HandleCache.cpp index bbf43c6..618668c 100644 --- a/source/YoloMouse/Dll/HandleCache.cpp +++ b/source/YoloMouse/Dll/HandleCache.cpp @@ -26,7 +26,7 @@ namespace YoloMouse return _CalculateHash(handle); // locate existing handle - for( CacheIterator i = _cache.Begin(); i != _cache.End(); ++i ) + for( CacheIterator i = _cache.begin(); i != _cache.end(); ++i ) if( i->handle == handle ) return i->hash; diff --git a/source/YoloMouse/Dll/Main.cpp b/source/YoloMouse/Dll/Main.cpp index efee841..1ad50ac 100644 --- a/source/YoloMouse/Dll/Main.cpp +++ b/source/YoloMouse/Dll/Main.cpp @@ -16,18 +16,14 @@ YoloNotify( void* arg ) App::Load(); break; - case NOTIFY_SETCURSOR: - App::UpdateCursor(static_cast(m.parameter)); + case NOTIFY_UPDATEPRESET: + App::UpdatePreset(static_cast(m.parameter)); break; - case NOTIFY_SETSIZE: + case NOTIFY_UPDATESIZE: App::UpdateSize(static_cast(m.parameter)); break; - case NOTIFY_SETDEFAULT: - App::UpdateDefault(); - break; - case NOTIFY_REFRESH: App::Refresh(); break; diff --git a/source/YoloMouse/Loader/App.cpp b/source/YoloMouse/Loader/App.cpp index 2b0e0b3..4e8a487 100644 --- a/source/YoloMouse/Loader/App.cpp +++ b/source/YoloMouse/Loader/App.cpp @@ -17,7 +17,8 @@ namespace YoloMouse _input_monitor (_ui), _system_monitor (SystemMonitor::Instance()), _settings (SETTINGS_ITEMS), - _elevate (false) + _elevate (false), + _games_only (false) { // init ui _ui.SetName(APP_NAME); @@ -90,7 +91,7 @@ namespace YoloMouse _input_monitor.SetListener(this); // for each cursor key - for( Id id = SETTING_GROUPKEY_1; id <= SETTING_DEFAULTKEY; id++ ) + for( Id id = SETTING_GROUPKEY_1; id <= SETTING_SIZEKEY_LARGER; id++ ) { String format = _settings.Get(id); @@ -108,6 +109,9 @@ namespace YoloMouse // enable autostart if( _settings.GetBoolean(SETTING_AUTOSTART) ) _OptionAutoStart(true, false); + + // update "games only" option + _OptionGamesOnly(_settings.GetBoolean(SETTING_GAMESONLY), false); } void App::_StartSettings() @@ -156,14 +160,21 @@ namespace YoloMouse // add menu break _ui.AddMenuBreak(); - + // add show settings + _ui.AddMenuOption(MENU_OPTION_SETTINGSFOLDER, APP_MENU_STRINGS[MENU_OPTION_SETTINGSFOLDER], false); // add run-as-administrator option if not already admin if( !IsUserAnAdmin() ) _ui.AddMenuOption(MENU_OPTION_RUNASADMIN, APP_MENU_STRINGS[MENU_OPTION_RUNASADMIN], false); + + // add menu break + _ui.AddMenuBreak(); // add autostart option _ui.AddMenuOption(MENU_OPTION_AUTOSTART, APP_MENU_STRINGS[MENU_OPTION_AUTOSTART], _settings.GetBoolean(SETTING_AUTOSTART)); - // add show settings - _ui.AddMenuOption(MENU_OPTION_SETTINGS, APP_MENU_STRINGS[MENU_OPTION_SETTINGS], false); + // add games only option + _ui.AddMenuOption(MENU_OPTION_GAMESONLY, APP_MENU_STRINGS[MENU_OPTION_GAMESONLY], _settings.GetBoolean(SETTING_GAMESONLY)); + + // add menu break + _ui.AddMenuBreak(); // add debug log _ui.AddMenuOption(MENU_OPTION_ERRORS, APP_MENU_STRINGS[MENU_OPTION_ERRORS], false); // add about dialog @@ -217,6 +228,22 @@ namespace YoloMouse } //------------------------------------------------------------------------- + void App::_OptionAbout() + { + MediumString about_text; + + // generate about text + about_text.Format( TEXT_ABOUT, + APP_VERSION[0], // version major + APP_VERSION[1], // version minor + APP_VERSION[2], // version patch + CPU_64 ? 64 : 32 // bitness + ); + + // show about dialog + SharedTools::MessagePopup(false, about_text.GetMemory()); + } + void App::_OptionErrors() { FILE* file; @@ -253,27 +280,18 @@ namespace YoloMouse } } - Bool App::_OptionRunAsAdmin() - { - // exit current process - ShellUi::Instance().Exit(); - - // set elevate state - _elevate = true; - - return true; - } - - void App::_OptionSettingsFolder() + void App::_OptionGamesOnly( Bool enable, Bool save ) { - PathString settings_path; + // update games only state + _games_only = enable; - // get settings path - if( !SharedTools::BuildUserPath(settings_path, COUNT(settings_path), NULL, NULL, NULL) ) - return; - - // open in default text editor - ShellExecute(NULL, L"open", settings_path, L"", NULL, SW_SHOWNORMAL); + // update settings + if( save ) + { + _settings.SetBoolean(SETTING_GAMESONLY, enable); + if( !_settings.Save() ) + elog("App.OptionGamesOnly.Save"); + } } Bool App::_OptionAutoStart( Bool enable, Bool save ) @@ -306,35 +324,31 @@ namespace YoloMouse return false; } - void App::_OptionAbout() + Bool App::_OptionRunAsAdmin() { - MediumString about_text; + // exit current process + ShellUi::Instance().Exit(); - // generate about text - about_text.Format( TEXT_ABOUT, - APP_VERSION[0], // version major - APP_VERSION[1], // version minor - APP_VERSION[2], // version patch - CPU_64 ? 64 : 32 // bitness - ); + // set elevate state + _elevate = true; - // show about dialog - SharedTools::MessagePopup(false, about_text.GetMemory()); + return true; } - //------------------------------------------------------------------------- - Bool App::_AssignCursor( Index group_index ) + void App::_OptionSettingsFolder() { - // access active instance - Instance* instance = _AccessCurrentInstance(); - if( instance == NULL ) - return false; + PathString settings_path; - // notify instance to assign - return instance->Notify(NOTIFY_SETCURSOR, group_index); + // get settings path + if( !SharedTools::BuildUserPath(settings_path, COUNT(settings_path), NULL, NULL, NULL) ) + return; + + // open in default text editor + ShellExecute(NULL, L"open", settings_path, L"", NULL, SW_SHOWNORMAL); } - Bool App::_AssignSize( Long size_index_delta ) + //------------------------------------------------------------------------- + Bool App::_AssignCursor( Index group_index ) { // access active instance Instance* instance = _AccessCurrentInstance(); @@ -342,10 +356,10 @@ namespace YoloMouse return false; // notify instance to assign - return instance->Notify(NOTIFY_SETSIZE, size_index_delta); + return instance->Notify(NOTIFY_UPDATEPRESET, group_index); } - Bool App::_AssignDefault() + Bool App::_AssignSize( Long size_index_delta ) { // access active instance Instance* instance = _AccessCurrentInstance(); @@ -353,7 +367,7 @@ namespace YoloMouse return false; // notify instance to assign - return instance->Notify(NOTIFY_SETDEFAULT); + return instance->Notify(NOTIFY_UPDATESIZE, size_index_delta); } //------------------------------------------------------------------------- @@ -380,6 +394,17 @@ namespace YoloMouse Instance* instance = _instance_manager.Find(process_id); if( instance == NULL ) { + // if games only option enabled + if( _games_only ) + { + // fail if game window test fails + if( !SystemTools::TestGameWindow( hwnd ) ) + { + elog("App.AccessCurrentInstance.TestGameWindow"); + return NULL; + } + } + // allocate new instance instance = _instance_manager.Load(process_id); } @@ -399,9 +424,6 @@ namespace YoloMouse // change size else if( combo_id >= SETTING_SIZEKEY_SMALLER && combo_id <= SETTING_SIZEKEY_LARGER ) _AssignSize(combo_id == SETTING_SIZEKEY_SMALLER ? -1 : 1); - // assign default - else if( combo_id == SETTING_DEFAULTKEY ) - _AssignDefault(); } //------------------------------------------------------------------------- @@ -441,31 +463,38 @@ namespace YoloMouse { switch(id) { - // run as administrator - case MENU_OPTION_RUNASADMIN: - _OptionRunAsAdmin(); + // show menu + case MENU_OPTION_ABOUT: + _OptionAbout(); + return true; + + // show debug log + case MENU_OPTION_ERRORS: + _OptionErrors(); + return true; + + // games only + case MENU_OPTION_GAMESONLY: + // toggle games only + _OptionGamesOnly( !enabled, true ); + _ui.SetMenuOption(MENU_OPTION_GAMESONLY, !enabled); return true; // auto start case MENU_OPTION_AUTOSTART: // toggle auto start - if(_OptionAutoStart(!enabled, true)) - _ui.SetMenuOption(id, !enabled); + if( _OptionAutoStart(!enabled, true) ) + _ui.SetMenuOption(MENU_OPTION_AUTOSTART, !enabled); return true; - // open settings folder - case MENU_OPTION_SETTINGS: - _OptionSettingsFolder(); - return true; - - // show debug log - case MENU_OPTION_ERRORS: - _OptionErrors(); + // run as administrator + case MENU_OPTION_RUNASADMIN: + _OptionRunAsAdmin(); return true; - // show menu - case MENU_OPTION_ABOUT: - _OptionAbout(); + // open settings folder + case MENU_OPTION_SETTINGSFOLDER: + _OptionSettingsFolder(); return true; default: diff --git a/source/YoloMouse/Loader/App.hpp b/source/YoloMouse/Loader/App.hpp index ed406f0..23b4455 100644 --- a/source/YoloMouse/Loader/App.hpp +++ b/source/YoloMouse/Loader/App.hpp @@ -46,16 +46,16 @@ namespace YoloMouse void _StopUi(); /**/ + void _OptionAbout(); void _OptionErrors(); + void _OptionGamesOnly( Bool enable, Bool save ); + Bool _OptionAutoStart( Bool enable, Bool save ); Bool _OptionRunAsAdmin(); void _OptionSettingsFolder(); - Bool _OptionAutoStart( Bool enable, Bool save ); - void _OptionAbout(); /**/ Bool _AssignCursor( Index group_index ); Bool _AssignSize( Long size_index_delta ); - Bool _AssignDefault(); /**/ Instance* _AccessCurrentInstance(); @@ -78,5 +78,6 @@ namespace YoloMouse SystemMonitor& _system_monitor; Settings _settings; Bool _elevate; + Bool _games_only; }; } diff --git a/source/YoloMouse/Loader/InstanceManager.cpp b/source/YoloMouse/Loader/InstanceManager.cpp index f4e84f7..4b32cb6 100644 --- a/source/YoloMouse/Loader/InstanceManager.cpp +++ b/source/YoloMouse/Loader/InstanceManager.cpp @@ -47,7 +47,7 @@ namespace YoloMouse //------------------------------------------------------------------------- Instance* InstanceManager::Find( DWORD process_id ) { - for( InstanceIterator target = _targets.Begin(); target != _targets.End(); ++target ) + for( InstanceIterator target = _targets.begin(); target != _targets.end(); ++target ) if( process_id == target->GetProcessId() ) return target; diff --git a/source/YoloMouse/Loader/Main.cpp b/source/YoloMouse/Loader/Main.cpp index f2dde25..ad6f8b0 100644 --- a/source/YoloMouse/Loader/Main.cpp +++ b/source/YoloMouse/Loader/Main.cpp @@ -1,6 +1,7 @@ #include #include #include +#include namespace YoloMouse { diff --git a/source/YoloMouse/Share/Constants.cpp b/source/YoloMouse/Share/Constants.cpp index 8bcd009..177389b 100644 --- a/source/YoloMouse/Share/Constants.cpp +++ b/source/YoloMouse/Share/Constants.cpp @@ -5,14 +5,18 @@ namespace YoloMouse //------------------------------------------------------------------------ const WCHAR* APP_MENU_STRINGS[MENU_OPTION_COUNT] = { - L"Run as administrator", //MENU_OPTION_RUNASADMIN - L"Start with Windows", //MENU_OPTION_AUTOSTART - L"Open settings folder", //MENU_OPTION_SETTINGS - L"Errors", //MENU_OPTION_ERRORS + // info L"About", //MENU_OPTION_ABOUT + L"Errors", //MENU_OPTION_ERRORS + // settings + L"Games only", //MENU_OPTION_GAMESONLY + L"Start with Windows", //MENU_OPTION_AUTOSTART + // etc + L"Run as Administrator", //MENU_OPTION_RUNASADMIN + L"Open settings folder", //MENU_OPTION_SETTINGSFOLDER }; - const ULong CURSOR_SIZE_TABLE[CURSOR_INDEX_COUNT] = + const ULong CURSOR_SIZE_TABLE[CURSOR_SIZE_INDEX_COUNT] = { 0, 16, @@ -47,7 +51,7 @@ namespace YoloMouse }; //------------------------------------------------------------------------ - static Settings::KeyValue _settings[] = + static Settings::KeyValue _settings[SETTING_COUNT] = { { "CursorKey1", "CONTROL ALT 1" }, { "CursorKey2", "CONTROL ALT 2" }, @@ -61,9 +65,9 @@ namespace YoloMouse { "CursorKeyReset", "CONTROL ALT 0" }, { "CursorKeySmaller", "CONTROL ALT -" }, { "CursorKeyLarger", "CONTROL ALT =" }, - { "CursorKeyDefault", "CONTROL ALT D" }, + { "GamesOnly", "1" }, { "AutoStart", "1" }, { "ShowMenu", "1" }, }; - Settings::KeyValueCollection SETTINGS_ITEMS(_settings, COUNT(_settings)); + Settings::KeyValueCollection SETTINGS_ITEMS(_settings, SETTING_COUNT); } diff --git a/source/YoloMouse/Share/Constants.hpp b/source/YoloMouse/Share/Constants.hpp index 7eacab4..ba8ef4f 100644 --- a/source/YoloMouse/Share/Constants.hpp +++ b/source/YoloMouse/Share/Constants.hpp @@ -1,64 +1,26 @@ #pragma once #include -#include +#include namespace YoloMouse { - // enums - //------------------------------------------------------------------------- - enum NotifyId - { - NOTIFY_INIT, - NOTIFY_SETCURSOR, - NOTIFY_SETSIZE, - NOTIFY_SETDEFAULT, - NOTIFY_REFRESH, - }; - - enum - { - SETTING_GROUPKEY_1, - SETTING_GROUPKEY_2, - SETTING_GROUPKEY_3, - SETTING_GROUPKEY_4, - SETTING_GROUPKEY_5, - SETTING_GROUPKEY_6, - SETTING_GROUPKEY_7, - SETTING_GROUPKEY_8, - SETTING_GROUPKEY_9, - SETTING_GROUPKEY_RESET, - SETTING_SIZEKEY_SMALLER, - SETTING_SIZEKEY_LARGER, - SETTING_DEFAULTKEY, - SETTING_AUTOSTART, - SETTING_SHOWMENU, - }; - - enum - { - MENU_OPTION_RUNASADMIN, - MENU_OPTION_AUTOSTART, - MENU_OPTION_SETTINGS, - MENU_OPTION_ERRORS, - MENU_OPTION_ABOUT, - MENU_OPTION_COUNT - }; - // numeric //------------------------------------------------------------------------- - static const ULong APP_VERSION[] = { 0, 9, 1 }; - static const ULong APP_NAME_LIMIT = 64; - static const ULong LOG_MEMORY_LIMIT = KILOBYTES(8); - static const ULong LOADER_TARGET_LIMIT = 20; - static const ULong CURSOR_BINDING_LIMIT = 100; - static const ULong CURSOR_GROUP_SIZE = 10; - static const ULong CURSOR_GROUP_COUNT = 9; - static const ULong CURSOR_INDEX_ORIGINAL = 0; - static const ULong CURSOR_INDEX_DEFAULT = 7; - static const ULong CURSOR_INDEX_COUNT = 16; - static const ULong CURSOR_RESOURCE_LIMIT = CURSOR_GROUP_COUNT * CURSOR_GROUP_SIZE; - static const Index CURSOR_SPECIAL_REMOVE = 9999; - static const ULong CURSOR_CACHE_LIMIT = 50; + static const ULong APP_VERSION[] = { 0, 10, 0 }; + static const ULong APP_NAME_LIMIT = 64; + static const ULong LOG_MEMORY_LIMIT = KILOBYTES(8); + static const ULong LOADER_TARGET_LIMIT = 20; + static const ULong CURSOR_BINDING_LIMIT = 100; + static const ULong CURSOR_SIZE_INDEX_ORIGINAL = 0; + static const ULong CURSOR_SIZE_INDEX_DEFAULT = 7; + static const ULong CURSOR_SIZE_INDEX_COUNT = 16; + static const ULong CURSOR_RESOURCE_PRESET_MINOR_COUNT = 10; + static const ULong CURSOR_RESOURCE_PRESET_MAJOR_COUNT = 9; + static const ULong CURSOR_RESOURCE_PRESET_COUNT = CURSOR_RESOURCE_PRESET_MINOR_COUNT* CURSOR_RESOURCE_PRESET_MAJOR_COUNT; + static const ULong CURSOR_RESOURCE_IDENTITY_LIMIT = 50; + static const Index CURSOR_SPECIAL_REMOVE = 9999; + static const ULong CURSOR_CACHE_LIMIT = 50; + static const ULong INI_LINE_LIMIT = 256; // strings //------------------------------------------------------------------------- @@ -75,8 +37,8 @@ namespace YoloMouse static const WCHAR* PATH_ERRORS = L"errors"; static const WCHAR* EXTENSION_INI = L"ini"; static const WCHAR* EXTENSION_LOG = L"txt"; - static const WCHAR* EXTENSION_STATIC = L"cur"; - static const WCHAR* EXTENSION_ANIMATED = L"ani"; + static const WCHAR* EXTENSION_STATIC_CURSOR = L"cur"; + static const WCHAR* EXTENSION_ANIMATED_CURSOR = L"ani"; static const CHAR* INJECT_NOTIFY_FUNCTION = "YoloNotify"; @@ -89,6 +51,6 @@ namespace YoloMouse // tables //------------------------------------------------------------------------- extern Settings::KeyValueCollection SETTINGS_ITEMS; - extern const ULong CURSOR_SIZE_TABLE[CURSOR_INDEX_COUNT]; + extern const ULong CURSOR_SIZE_TABLE[CURSOR_SIZE_INDEX_COUNT]; extern const ULong CURSOR_SIZE_TABLE_V_0_8_3[10]; } diff --git a/source/YoloMouse/Share/Enums.hpp b/source/YoloMouse/Share/Enums.hpp new file mode 100644 index 0000000..be49b7d --- /dev/null +++ b/source/YoloMouse/Share/Enums.hpp @@ -0,0 +1,58 @@ +#pragma once +#include + +namespace YoloMouse +{ + // enums + //------------------------------------------------------------------------- + enum NotifyId + { + NOTIFY_INIT, + NOTIFY_UPDATEPRESET, + NOTIFY_UPDATESIZE, + NOTIFY_SETDEFAULT, + NOTIFY_REFRESH, + }; + + enum + { + SETTING_GROUPKEY_1, + SETTING_GROUPKEY_2, + SETTING_GROUPKEY_3, + SETTING_GROUPKEY_4, + SETTING_GROUPKEY_5, + SETTING_GROUPKEY_6, + SETTING_GROUPKEY_7, + SETTING_GROUPKEY_8, + SETTING_GROUPKEY_9, + SETTING_GROUPKEY_RESET, + SETTING_SIZEKEY_SMALLER, + SETTING_SIZEKEY_LARGER, + SETTING_GAMESONLY, + SETTING_AUTOSTART, + SETTING_SHOWMENU, + SETTING_COUNT + }; + + enum + { + // info + MENU_OPTION_ABOUT, + MENU_OPTION_ERRORS, + // options + MENU_OPTION_GAMESONLY, + MENU_OPTION_AUTOSTART, + // etc + MENU_OPTION_RUNASADMIN, + MENU_OPTION_SETTINGSFOLDER, + + MENU_OPTION_COUNT + }; + + enum ResourceType: Char + { + RESOURCE_PRESET = 'p', + RESOURCE_IDENTITY = 'i', + RESOURCE_UNKNOWN = '?', + }; +} diff --git a/source/YoloMouse/Share/SharedTools.cpp b/source/YoloMouse/Share/SharedTools.cpp index 59b2b02..a87360d 100644 --- a/source/YoloMouse/Share/SharedTools.cpp +++ b/source/YoloMouse/Share/SharedTools.cpp @@ -124,4 +124,57 @@ namespace YoloMouse // show message MessageBoxA(NULL, message, APP_NAMEC, MB_OK|(error ? MB_ICONERROR : MB_ICONINFORMATION)); } + + //------------------------------------------------------------------------- + Index SharedTools::CursorSizeToSizeIndex( ULong size ) + { + // if original size + if( size == CURSOR_SIZE_INDEX_ORIGINAL ) + return 0; + + // if old table (size is index) + if( size < CURSOR_SIZE_TABLE[1] ) + { + // get size from old table + if( size < COUNT( CURSOR_SIZE_TABLE_V_0_8_3 ) ) + size = CURSOR_SIZE_TABLE_V_0_8_3[size]; + // else return default index + else + return CURSOR_SIZE_INDEX_DEFAULT; + } + + // locate size index nearest requested size + for( Index i = 0; i < CURSOR_SIZE_INDEX_COUNT; ++i ) + if( size <= CURSOR_SIZE_TABLE[i] ) + return i; + + // use default + return CURSOR_SIZE_INDEX_DEFAULT; + } + + ULong SharedTools::CursorToSize( HCURSOR hcursor ) + { + ICONINFO icon_info; + BITMAP bitmap = { 0 }; + + // get base icon info + if( GetIconInfo(hcursor, &icon_info) == FALSE ) + return 0; + + // select bitmap handle to get bitmap from + HBITMAP hbitmap = icon_info.hbmColor ? icon_info.hbmColor : icon_info.hbmMask; + + // if either bitmap handle exists get base icon bitmap object + if( hbitmap != NULL ) + GetObject( hbitmap, sizeof( BITMAP ), &bitmap ); + + // cleanup temporary resources + if( icon_info.hbmColor != NULL ) + DeleteObject(icon_info.hbmColor); + if( icon_info.hbmMask != NULL ) + DeleteObject(icon_info.hbmMask); + + // return size as bitmap height (will be 0 if failed) + return bitmap.bmHeight; + } } diff --git a/source/YoloMouse/Share/SharedTools.hpp b/source/YoloMouse/Share/SharedTools.hpp index 73b2a12..7bead86 100644 --- a/source/YoloMouse/Share/SharedTools.hpp +++ b/source/YoloMouse/Share/SharedTools.hpp @@ -15,5 +15,9 @@ namespace YoloMouse /**/ static void MessagePopup( Bool error, const Char* format, ... ); + + /**/ + static Index CursorSizeToSizeIndex( ULong size ); + static ULong CursorToSize( HCURSOR hcursor ); }; }