Use quiet Steam keyboard clicks for UI sound feedback

This commit is contained in:
toorux committed 2026-10-07 14:32:57 +08:00
1 parent 6589f85ec6
commit 3d2899fb6e
4 files changed
+8 -6

No files matched your search

+1 -1
View File
@@ -12,7 +12,7 @@ Plugin contains installed plugins, the plugin library, sources and notification
## Interaction feedback
In **Settings → General → Interaction feedback**, Haptic feedback is enabled by default; Sound feedback is disabled by default. Both preferences are saved across restarts. Haptic feedback controls laser hover and launcher gaze-focus vibration across Framely and plugin pages; it does not change APK game rumble. Sound feedback uses Steam’s installed navigation and activation sounds for focus and clicks. It requires the local Steam sound files and audio runtime; no sound files are bundled or downloaded.
In **Settings → General → Interaction feedback**, Haptic feedback is enabled by default; Sound feedback is disabled by default. Both preferences are saved across restarts. Haptic feedback controls laser hover and launcher gaze-focus vibration across Framely and plugin pages; it does not change APK game rumble. Sound feedback uses Steam’s installed keyboard sound at reduced volume for focus and clicks. It requires the local Steam sound files and audio runtime; no sound files are bundled or downloaded.
## Terminal
+1 -1
View File
@@ -12,7 +12,7 @@
## 交互反馈
在 **设置 → 通用 → 交互反馈** 中,振动反馈默认开启,提示音反馈默认关闭,修改后会保存。振动开关统一控制 Framely 和插件页面的激光悬停、启动台眼动聚焦振动,不影响 APK 游戏振动。提示音开关使用 Steam 本机的导航和点击音效,需要本机 Steam 音效文件与音频运行库,不打包或下载这些音效。
在 **设置 → 通用 → 交互反馈** 中,振动反馈默认开启,提示音反馈默认关闭,修改后会保存。振动开关统一控制 Framely 和插件页面的激光悬停、启动台眼动聚焦振动,不影响 APK 游戏振动。提示音开关使用 Steam 本机键盘音效,以较低音量反馈聚焦和点击,需要本机 Steam 音效文件与音频运行库,不打包或下载这些音效。
## 终端
+4 -3
View File
@@ -20,6 +20,7 @@ class SteamUiSounds {
bool (*resume)(void*)=nullptr;
bool (*put)(void*,const void*,int)=nullptr;
bool (*clear)(void*)=nullptr;
bool (*gain)(void*,float)=nullptr;
void (*destroy)(void*)=nullptr;
void (*release)(void*)=nullptr;
template<class T> bool bind(T& fn,const char* name){fn=reinterpret_cast<T>(dlsym(library,name));return fn!=nullptr;}
@@ -36,13 +37,13 @@ class SteamUiSounds {
if(root.empty())return false;
for(const auto* name:{"steamrtarm64/libSDL3.so.0","steamrt64/libSDL3.so.0"}){library=dlopen((root+"/"+name).c_str(),RTLD_NOW|RTLD_LOCAL);if(library)break;}
if(!library)return false;
if(!(bind(init,"SDL_InitSubSystem")&&bind(quit,"SDL_QuitSubSystem")&&bind(load,"SDL_LoadWAV")&&bind(open,"SDL_OpenAudioDeviceStream")&&bind(resume,"SDL_ResumeAudioStreamDevice")&&bind(put,"SDL_PutAudioStreamData")&&bind(clear,"SDL_ClearAudioStream")&&bind(destroy,"SDL_DestroyAudioStream")&&bind(release,"SDL_free"))){shutdown();return false;}
if(!(bind(init,"SDL_InitSubSystem")&&bind(quit,"SDL_QuitSubSystem")&&bind(load,"SDL_LoadWAV")&&bind(open,"SDL_OpenAudioDeviceStream")&&bind(resume,"SDL_ResumeAudioStreamDevice")&&bind(put,"SDL_PutAudioStreamData")&&bind(clear,"SDL_ClearAudioStream")&&bind(gain,"SDL_SetAudioStreamGain")&&bind(destroy,"SDL_DestroyAudioStream")&&bind(release,"SDL_free"))){shutdown();return false;}
if(!init(0x10)){shutdown();return false;}initialized=true;
const char* names[]={"deck_ui_navigation.wav","deck_ui_default_activation.wav"};
const char* names[]={"deck_ui_typing.wav","deck_ui_typing.wav"};
for(int i=0;i<2;++i){Spec spec{};auto& clip=clips[i];
if(!load((root+"/steamui/sounds/"+names[i]).c_str(),&spec,&clip.data,&clip.size)||!clip.size||clip.size>1024*1024){shutdown();return false;}
clip.stream=open(0xffffffffu,&spec,nullptr,nullptr);
if(!clip.stream||!resume(clip.stream)){shutdown();return false;}
if(!clip.stream||!gain(clip.stream,i==0?.30f:.45f)||!resume(clip.stream)){shutdown();return false;}
}
return true;
}
+2 -1
View File
@@ -14,8 +14,9 @@ static int loads=0, writes=0, streams=0, cleared=0;
extern "C" {
bool SDL_InitSubSystem(uint32_t flags){assert(flags==0x10);return true;}
void SDL_QuitSubSystem(uint32_t flags){assert(flags==0x10);assert(streams==0);}
bool SDL_LoadWAV(const char* path,void* spec,uint8_t** data,uint32_t* len){assert(strstr(path,"/steamui/sounds/deck_ui_"));++loads;*data=(uint8_t*)malloc(4);*len=4;return true;}
bool SDL_LoadWAV(const char* path,void* spec,uint8_t** data,uint32_t* len){assert(strstr(path,"/steamui/sounds/deck_ui_typing.wav"));++loads;*data=(uint8_t*)malloc(4);*len=4;return true;}
void* SDL_OpenAudioDeviceStream(uint32_t id,const void*,void* callback,void* userdata){assert(id==0xffffffffu&&!callback&&!userdata);++streams;return malloc(1);}
bool SDL_SetAudioStreamGain(void*,float gain){assert(gain==.30f||gain==.45f);return true;}
bool SDL_ResumeAudioStreamDevice(void*){return true;}
bool SDL_PutAudioStreamData(void*,const void*,int len){assert(loads==2&&len==4);++writes;return true;}
bool SDL_ClearAudioStream(void*){++cleared;return true;}