Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ Switchify PC uses `uiAccess="true"` so the installed app can interact with eleva

Windows only honors `uiAccess` when all of these are true:

- The app executable manifest has `level="asInvoker"` and `uiAccess="true"`.
- The app executable manifest has `level="highestAvailable"` and `uiAccess="true"`.
- The executable is Authenticode signed.
- The executable is installed in a secure location such as `C:\Program Files\Switchify PC\`.
- Signing happens after icon and manifest resource embedding.
Expand Down
2 changes: 1 addition & 1 deletion build/win-uiaccess.manifest
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="true" />
<requestedExecutionLevel level="highestAvailable" uiAccess="true" />
</requestedPrivileges>
</security>
</trustInfo>
Expand Down
6 changes: 3 additions & 3 deletions scripts/verify-win-uiaccess-package.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ try {
runTool(mtExe, ['-nologo', `-inputresource:${executablePath};#1`, `-out:${manifestOutPath}`]);
const manifest = fs.readFileSync(manifestOutPath, 'utf8');
const hasUiAccess = /uiAccess\s*=\s*"true"/.test(manifest);
const hasAsInvoker = /level\s*=\s*"asInvoker"/.test(manifest);
const hasHighestAvailable = /level\s*=\s*"highestAvailable"/.test(manifest);

const signatureResult = runTool(signtoolExe, ['verify', '/pa', '/v', executablePath], { stdio: 'pipe' });
const signatureOutput = `${signatureResult.stdout || ''}${signatureResult.stderr || ''}`;
Expand All @@ -52,15 +52,15 @@ try {

console.log(`manifest embedded: yes`);
console.log(`uiAccess=true: ${hasUiAccess ? 'yes' : 'no'}`);
console.log(`asInvoker: ${hasAsInvoker ? 'yes' : 'no'}`);
console.log(`highestAvailable: ${hasHighestAvailable ? 'yes' : 'no'}`);
console.log(`signature status: ${signatureOutput.includes('Successfully verified') ? 'valid' : 'check output above'}`);
console.log('cursor overlay helper: present');
console.log(`cursor overlay helper signature: ${helperSignatureOutput.includes('Successfully verified') ? 'valid' : 'check output above'}`);
console.log('Bluetooth transport helper: present');
console.log(`Bluetooth transport helper signature: ${bluetoothHelperSignatureOutput.includes('Successfully verified') ? 'valid' : 'check output above'}`);
console.log('secure install location required: install per-machine under Program Files for uiAccess to take effect.');

if (!hasUiAccess || !hasAsInvoker) {
if (!hasUiAccess || !hasHighestAvailable) {
throw new Error('Packaged executable manifest does not contain the required uiAccess settings.');
}

Expand Down