|
| 1 | +const { ipcMain } = require('electron'); |
| 2 | +const { exec } = require('child_process'); |
| 3 | +const util = require('util'); |
| 4 | +const fs = require('fs'); |
| 5 | +const path = require('path'); |
| 6 | +const { getText, setGamingTool } = require('./utils'); |
| 7 | +const execPromise = util.promisify(exec); |
| 8 | + |
| 9 | +let mainWindow, settingsWindow; |
| 10 | +let isDarkMode = true; |
| 11 | +let isMuted = false; |
| 12 | +let wifiEnabled = true; |
| 13 | + |
| 14 | +function log(message, level = 'info') { |
| 15 | + const logMessage = `${new Date().toISOString()} - ${level.toUpperCase()} - ${message}\n`; |
| 16 | + fs.appendFileSync('/tmp/hacker-mode.log', logMessage); |
| 17 | +} |
| 18 | + |
| 19 | +function setWindows(main, settings) { |
| 20 | + mainWindow = main; |
| 21 | + settingsWindow = settings; |
| 22 | +} |
| 23 | + |
| 24 | +ipcMain.handle('audioAction', async (event, action) => { |
| 25 | + const actions = { |
| 26 | + increaseVolume: () => { |
| 27 | + log('Increasing volume', 'info'); |
| 28 | + isMuted = false; |
| 29 | + exec('pactl set-sink-volume @DEFAULT_SINK@ +5%', (err) => { |
| 30 | + if (err) log(`Error increasing volume: ${err}`, 'error'); |
| 31 | + }); |
| 32 | + }, |
| 33 | + decreaseVolume: () => { |
| 34 | + log('Decreasing volume', 'info'); |
| 35 | + isMuted = false; |
| 36 | + exec('pactl set-sink-volume @DEFAULT_SINK@ -5%', (err) => { |
| 37 | + if (err) log(`Error decreasing volume: ${err}`, 'error'); |
| 38 | + }); |
| 39 | + }, |
| 40 | + toggleMute: () => { |
| 41 | + log('Toggling mute', 'info'); |
| 42 | + isMuted = !isMuted; |
| 43 | + exec('pactl set-sink-mute @DEFAULT_SINK@ toggle', (err) => { |
| 44 | + if (err) log(`Error toggling mute: ${err}`, 'error'); |
| 45 | + }); |
| 46 | + } |
| 47 | + }; |
| 48 | + |
| 49 | + if (actions[action]) actions[action](); |
| 50 | +}); |
| 51 | + |
| 52 | +ipcMain.handle('displayAction', async (event, action) => { |
| 53 | + const actions = { |
| 54 | + increaseBrightness: () => { |
| 55 | + log('Increasing brightness', 'info'); |
| 56 | + exec('brightnessctl set +5%', (err) => { |
| 57 | + if (err) log(`Error increasing brightness: ${err}`, 'error'); |
| 58 | + }); |
| 59 | + }, |
| 60 | + decreaseBrightness: () => { |
| 61 | + log('Decreasing brightness', 'info'); |
| 62 | + exec('brightnessctl set 5%-', (err) => { |
| 63 | + if (err) log(`Error decreasing brightness: ${err}`, 'error'); |
| 64 | + }); |
| 65 | + }, |
| 66 | + toggleTheme: () => { |
| 67 | + log('Toggling theme', 'info'); |
| 68 | + isDarkMode = !isDarkMode; |
| 69 | + const theme = isDarkMode ? 'dark' : 'light'; |
| 70 | + const configPath = path.join(require('os').homedir(), '.config/sway/config'); |
| 71 | + try { |
| 72 | + let config = fs.readFileSync(configPath, 'utf8'); |
| 73 | + config = config.replace(/set \$theme (dark|light)/, `set $theme ${theme}`); |
| 74 | + fs.writeFileSync(configPath, config); |
| 75 | + exec('swaymsg reload', (err) => { |
| 76 | + if (err) log(`Error reloading Sway: ${err}`, 'error'); |
| 77 | + }); |
| 78 | + } catch (e) { |
| 79 | + log(`Error toggling theme: ${e}`, 'error'); |
| 80 | + } |
| 81 | + } |
| 82 | + }; |
| 83 | + |
| 84 | + if (actions[action]) actions[action](); |
| 85 | +}); |
| 86 | + |
| 87 | +ipcMain.handle('networkAction', async (event, action) => { |
| 88 | + const actions = { |
| 89 | + showWifiSettings: () => { |
| 90 | + log('Showing Wi-Fi settings', 'info'); |
| 91 | + settingsWindow.webContents.executeJavaScript(` |
| 92 | + document.getElementById('wifi-panel').classList.remove('hidden'); |
| 93 | + document.getElementById('bluetooth-panel').classList.add('hidden'); |
| 94 | + document.getElementById('wifi-list').innerHTML = ''; |
| 95 | + `).catch(e => log(`Error showing Wi-Fi settings: ${e}`, 'error')); |
| 96 | + exec('nmcli -t -f SSID,SIGNAL dev wifi', (err, stdout) => { |
| 97 | + if (err) { |
| 98 | + log(`Error scanning Wi-Fi: ${err}`, 'error'); |
| 99 | + settingsWindow.webContents.executeJavaScript(`document.getElementById('wifi-list').innerHTML = '<p>${getText('no_networks')}</p>';`).catch(e => log(`Error updating Wi-Fi list: ${e}`, 'error')); |
| 100 | + return; |
| 101 | + } |
| 102 | + const networks = stdout.split('\n').filter(line => line).map(line => { |
| 103 | + const [ssid, signal] = line.split(':'); |
| 104 | + return { ssid, signal }; |
| 105 | + }); |
| 106 | + if (!networks.length) { |
| 107 | + settingsWindow.webContents.executeJavaScript(`document.getElementById('wifi-list').innerHTML = '<p>${getText('no_networks')}</p>';`).catch(e => log(`Error updating Wi-Fi list: ${e}`, 'error')); |
| 108 | + return; |
| 109 | + } |
| 110 | + const networkItems = networks.map(n => `<div class="wifi-item p-2 cursor-pointer" onclick="window.electronApi.selectWifi('${n.ssid}')">${n.ssid} (${n.signal}%)</div>`).join(''); |
| 111 | + settingsWindow.webContents.executeJavaScript(` |
| 112 | + document.getElementById('wifi-list').innerHTML = '${networkItems}'; |
| 113 | + gsap.from('.wifi-item', { duration: 0.5, y: 20, opacity: 0, stagger: 0.1 }); |
| 114 | + `).catch(e => log(`Error updating Wi-Fi list: ${e}`, 'error')); |
| 115 | + }); |
| 116 | + }, |
| 117 | + toggleWifi: () => { |
| 118 | + log('Toggling Wi-Fi', 'info'); |
| 119 | + wifiEnabled = !wifiEnabled; |
| 120 | + const action = wifiEnabled ? 'on' : 'off'; |
| 121 | + exec(`nmcli radio wifi ${action}`, (err, stdout, stderr) => { |
| 122 | + if (err) { |
| 123 | + log(`Error toggling Wi-Fi: ${err}`, 'error'); |
| 124 | + settingsWindow.webContents.executeJavaScript(`alert('${getText('wifi_toggle_failed', { error: stderr })}');`).catch(e => log(`Error showing alert: ${e}`, 'error')); |
| 125 | + return; |
| 126 | + } |
| 127 | + settingsWindow.webContents.executeJavaScript(`alert('${getText('wifi_toggle_success', { state: action })}');`).catch(e => log(`Error showing alert: ${e}`, 'error')); |
| 128 | + }); |
| 129 | + }, |
| 130 | + showBluetooth: () => { |
| 131 | + log('Showing Bluetooth', 'info'); |
| 132 | + settingsWindow.webContents.executeJavaScript(` |
| 133 | + document.getElementById('bluetooth-panel').classList.remove('hidden'); |
| 134 | + document.getElementById('wifi-panel').classList.add('hidden'); |
| 135 | + document.getElementById('bluetooth-list').innerHTML = ''; |
| 136 | + `).catch(e => log(`Error showing Bluetooth: ${e}`, 'error')); |
| 137 | + } |
| 138 | + }; |
| 139 | + |
| 140 | + if (actions[action]) actions[action](); |
| 141 | +}); |
| 142 | + |
| 143 | +ipcMain.handle('powerAction', async (event, profile) => { |
| 144 | + log(`Setting power profile to ${profile}`, 'info'); |
| 145 | + exec(`powerprofilesctl set ${profile}`, (err) => { |
| 146 | + if (err) log(`Error setting power profile: ${err}`, 'error'); |
| 147 | + }); |
| 148 | +}); |
| 149 | + |
| 150 | +ipcMain.handle('setLanguage', async (event, newLang) => { |
| 151 | + log(`Setting language to ${newLang}`, 'info'); |
| 152 | + require('./utils').setLanguage(newLang); |
| 153 | + mainWindow.webContents.executeJavaScript(` |
| 154 | + document.getElementById('title').innerText = '${getText('title')}'; |
| 155 | + document.getElementById('settings-btn').innerText = '${getText('settings')}'; |
| 156 | + document.getElementById('hacker-menu-btn').innerText = '${getText('hacker_menu')}'; |
| 157 | + `).catch(e => log(`Error updating main window: ${e}`, 'error')); |
| 158 | + if (settingsWindow) { |
| 159 | + settingsWindow.webContents.executeJavaScript(` |
| 160 | + document.getElementById('settings-title').innerText = '${getText('settings')}'; |
| 161 | + document.getElementById('language-select').value = '${newLang}'; |
| 162 | + document.getElementById('audio-title').innerText = '${getText('audio')}'; |
| 163 | + document.getElementById('display-title').innerText = '${getText('display')}'; |
| 164 | + document.getElementById('network-title').innerText = '${getText('network')}'; |
| 165 | + document.getElementById('power-title').innerText = '${getText('power')}'; |
| 166 | + document.getElementById('general-title').innerText = '${getText('general')}'; |
| 167 | + document.getElementById('gaming-tools-title').innerText = '${getText('gaming_tools')}'; |
| 168 | + document.getElementById('wifi-title').innerText = '${getText('wifi_settings')}'; |
| 169 | + document.getElementById('bluetooth-title').innerText = '${getText('bluetooth')}'; |
| 170 | + document.querySelector('.back-btn').innerText = '${getText('back')}'; |
| 171 | + document.querySelector('.close-btn').innerText = '${getText('close')}'; |
| 172 | + document.getElementById('label_enable_gamescope').innerText = '${getText('enable_gamescope')}'; |
| 173 | + document.getElementById('label_enable_mangohud').innerText = '${getText('enable_mangohud')}'; |
| 174 | + document.getElementById('label_enable_vkbasalt').innerText = '${getText('enable_vkbasalt')}'; |
| 175 | + `).catch(e => log(`Error updating settings window: ${e}`, 'error')); |
| 176 | + } |
| 177 | +}); |
| 178 | + |
| 179 | +ipcMain.handle('selectWifi', async (event, ssid) => { |
| 180 | + settingsWindow.webContents.executeJavaScript(` |
| 181 | + window.selectedWifi = '${ssid}'; |
| 182 | + document.querySelectorAll('.wifi-item').forEach(item => item.classList.remove('bg-gray-600')); |
| 183 | + document.querySelector(\`.wifi-item[onclick="window.electronApi.selectWifi('${ssid}')"]\`).classList.add('bg-gray-600'); |
| 184 | + `).catch(e => log(`Error selecting Wi-Fi: ${e}`, 'error')); |
| 185 | +}); |
| 186 | + |
| 187 | +ipcMain.handle('connectWifi', async () => { |
| 188 | + log('Connecting to Wi-Fi', 'info'); |
| 189 | + const ssid = await settingsWindow.webContents.executeJavaScript(`window.selectedWifi`); |
| 190 | + const password = await settingsWindow.webContents.executeJavaScript(`document.getElementById('wifi-password').value`); |
| 191 | + if (!ssid) { |
| 192 | + settingsWindow.webContents.executeJavaScript(`alert('${getText('no_selection')}');`).catch(e => log(`Error showing alert: ${e}`, 'error')); |
| 193 | + return; |
| 194 | + } |
| 195 | + try { |
| 196 | + const cmd = password ? `nmcli dev wifi connect "${ssid}" password "${password}"` : `nmcli dev wifi connect "${ssid}"`; |
| 197 | + const { stderr } = await execPromise(cmd); |
| 198 | + if (stderr) { |
| 199 | + settingsWindow.webContents.executeJavaScript(`alert('${getText('connection_failed', { error: stderr })}');`).catch(e => log(`Error showing alert: ${e}`, 'error')); |
| 200 | + log(`Wi-Fi connection failed: ${stderr}`, 'error'); |
| 201 | + } else { |
| 202 | + settingsWindow.webContents.executeJavaScript(`alert('${getText('connecting', { ssid })}');`).catch(e => log(`Error showing alert: ${e}`, 'error')); |
| 203 | + } |
| 204 | + } catch (e) { |
| 205 | + settingsWindow.webContents.executeJavaScript(`alert('${getText('connection_failed', { error: e.message })}');`).catch(e => log(`Error showing alert: ${e}`, 'error')); |
| 206 | + log(`Error connecting to Wi-Fi: ${e}`, 'error'); |
| 207 | + } |
| 208 | +}); |
| 209 | + |
| 210 | +ipcMain.handle('scanBluetooth', async () => { |
| 211 | + log('Scanning Bluetooth', 'info'); |
| 212 | + exec('bluetoothctl power on && bluetoothctl scan on && bluetoothctl devices && bluetoothctl scan off', (err, stdout) => { |
| 213 | + if (err) { |
| 214 | + log(`Error scanning Bluetooth: ${err}`, 'error'); |
| 215 | + settingsWindow.webContents.executeJavaScript(`document.getElementById('bluetooth-list').innerHTML = '<p>No devices found</p>';`).catch(e => log(`Error updating Bluetooth list: ${e}`, 'error')); |
| 216 | + return; |
| 217 | + } |
| 218 | + const devices = stdout.split('\n').filter(line => line.startsWith('Device')).map(line => { |
| 219 | + const parts = line.split(' '); |
| 220 | + return { id: parts[1], name: parts.slice(2).join(' ') }; |
| 221 | + }); |
| 222 | + if (!devices.length) { |
| 223 | + settingsWindow.webContents.executeJavaScript(`document.getElementById('bluetooth-list').innerHTML = '<p>No devices found</p>';`).catch(e => log(`Error updating Bluetooth list: ${e}`, 'error')); |
| 224 | + return; |
| 225 | + } |
| 226 | + const deviceItems = devices.map(d => `<div class="bluetooth-item p-2 cursor-pointer" onclick="window.electronApi.selectBluetooth('${d.id}')">${d.name} (${d.id})</div>`).join(''); |
| 227 | + settingsWindow.webContents.executeJavaScript(` |
| 228 | + document.getElementById('bluetooth-list').innerHTML = '${deviceItems}'; |
| 229 | + gsap.from('.bluetooth-item', { duration: 0.5, y: 20, opacity: 0, stagger: 0.1 }); |
| 230 | + `).catch(e => log(`Error updating Bluetooth list: ${e}`, 'error')); |
| 231 | + }); |
| 232 | +}); |
| 233 | + |
| 234 | +ipcMain.handle('selectBluetooth', async (event, deviceId) => { |
| 235 | + settingsWindow.webContents.executeJavaScript(` |
| 236 | + window.selectedBluetooth = '${deviceId}'; |
| 237 | + document.querySelectorAll('.bluetooth-item').forEach(item => item.classList.remove('bg-gray-600')); |
| 238 | + document.querySelector(\`.bluetooth-item[onclick="window.electronApi.selectBluetooth('${deviceId}')"]\`).classList.add('bg-gray-600'); |
| 239 | + `).catch(e => log(`Error selecting Bluetooth: ${e}`, 'error')); |
| 240 | +}); |
| 241 | + |
| 242 | +ipcMain.handle('pairBluetooth', async () => { |
| 243 | + log('Pairing Bluetooth', 'info'); |
| 244 | + const deviceId = await settingsWindow.webContents.executeJavaScript(`window.selectedBluetooth`); |
| 245 | + if (!deviceId) { |
| 246 | + settingsWindow.webContents.executeJavaScript(`alert('${getText('no_selection')}');`).catch(e => log(`Error showing alert: ${e}`, 'error')); |
| 247 | + return; |
| 248 | + } |
| 249 | + try { |
| 250 | + const { stderr: pairErr } = await execPromise(`bluetoothctl pair ${deviceId}`); |
| 251 | + if (pairErr) { |
| 252 | + settingsWindow.webContents.executeJavaScript(`alert('${getText('pairing_failed', { error: pairErr })}');`).catch(e => log(`Error showing alert: ${e}`, 'error')); |
| 253 | + log(`Bluetooth pairing failed: ${pairErr}`, 'error'); |
| 254 | + return; |
| 255 | + } |
| 256 | + const { stderr: connectErr } = await execPromise(`bluetoothctl connect ${deviceId}`); |
| 257 | + if (connectErr) { |
| 258 | + settingsWindow.webContents.executeJavaScript(`alert('${getText('pairing_failed', { error: connectErr })}');`).catch(e => log(`Error showing alert: ${e}`, 'error')); |
| 259 | + log(`Bluetooth connection failed: ${connectErr}`, 'error'); |
| 260 | + } else { |
| 261 | + settingsWindow.webContents.executeJavaScript(`alert('${getText('pairing', { device: deviceId })}');`).catch(e => log(`Error showing alert: ${e}`, 'error')); |
| 262 | + } |
| 263 | + } catch (e) { |
| 264 | + settingsWindow.webContents.executeJavaScript(`alert('${getText('pairing_failed', { error: e.message })}');`).catch(e => log(`Error showing alert: ${e}`, 'error')); |
| 265 | + log(`Error pairing Bluetooth: ${e}`, 'error'); |
| 266 | + } |
| 267 | +}); |
| 268 | + |
| 269 | +ipcMain.handle('toggleGamingTool', async (event, tool, enabled) => { |
| 270 | + require('./utils').setGamingTool(tool, enabled); |
| 271 | + log(`Toggled ${tool} to ${enabled}`, 'info'); |
| 272 | +}); |
| 273 | + |
| 274 | +module.exports = { setWindows }; |
0 commit comments