mirror of
https://github.com/Kvan7/Exiled-Exchange-2.git
synced 2025-12-12 11:06:44 +00:00
Added MacOS support (#403)
This commit is contained in:
43
DEVELOPING.md
Normal file
43
DEVELOPING.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# How this works
|
||||
|
||||
There are 2 main parts of the app:
|
||||
|
||||
1. renderer: this is the HTML/Javascript-based UI rendered within the Electron container. This runs Vue.js, a React-like Javascript framework for rendering front-end.
|
||||
2. main: includes the main app (written in Electron). Handles keyboard shortcuts, brings up the UI and overlays.
|
||||
|
||||
Note that these 2 both depend on each other, and one cannot run without the other.
|
||||
|
||||
# How to develop
|
||||
|
||||
The most up-to-date instructions can always be derived from CI:
|
||||
|
||||
[.github/workflows/main.yml](https://github.com/SnosMe/awakened-poe-trade/blob/master/.github/workflows/main.yml)
|
||||
|
||||
Here's what that looks like as of 2023-12-03.
|
||||
|
||||
```shell
|
||||
cd renderer
|
||||
yarn install
|
||||
yarn make-index-files
|
||||
yarn dev
|
||||
|
||||
# In a second shell
|
||||
cd main
|
||||
yarn install
|
||||
yarn dev
|
||||
```
|
||||
|
||||
# How to build
|
||||
|
||||
```shell
|
||||
cd renderer
|
||||
yarn install
|
||||
yarn make-index-files
|
||||
yarn build
|
||||
|
||||
cd ../main
|
||||
yarn build
|
||||
# We want to sign with a distribution certificate to ensure other users can
|
||||
# install without errors
|
||||
CSC_NAME="Certificate name in Keychain" yarn package
|
||||
```
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
### Development
|
||||
|
||||
Follow instructions similar to CI [.github/workflows/main.yml](https://github.com/SnosMe/awakened-poe-trade/blob/master/.github/workflows/main.yml)
|
||||
See [DEVELOPING.md](./DEVELOPING.md)
|
||||
|
||||
### Acknowledgments
|
||||
|
||||
|
||||
@@ -217,7 +217,9 @@ export const KeyToElectron = {
|
||||
Backslash: '\\',
|
||||
BracketRight: ']',
|
||||
Quote: "'",
|
||||
Ctrl: 'CmdOrCtrl',
|
||||
// Do not change Ctrl to CmdOrCtrl. It causes registered shortcuts to
|
||||
// often not work on Mac for unknown reasons.
|
||||
Ctrl: 'Ctrl',
|
||||
Alt: 'Alt',
|
||||
Shift: 'Shift'
|
||||
}
|
||||
|
||||
@@ -21,6 +21,13 @@ win:
|
||||
linux:
|
||||
target:
|
||||
- "AppImage"
|
||||
mac:
|
||||
target:
|
||||
- target: default
|
||||
arch:
|
||||
- universal
|
||||
# MacOS apps can only be run on other systems if signed
|
||||
forceCodeSigning: true
|
||||
appImage:
|
||||
executableArgs:
|
||||
- "--sandbox"
|
||||
|
||||
@@ -8,9 +8,21 @@ export class AppTray {
|
||||
serverPort = 0
|
||||
|
||||
constructor (server: ServerEvents) {
|
||||
this.tray = new Tray(
|
||||
nativeImage.createFromPath(path.join(__dirname, process.env.STATIC!, process.platform === 'win32' ? 'icon.ico' : 'icon.png'))
|
||||
let trayImage = nativeImage.createFromPath(
|
||||
path.join(
|
||||
__dirname,
|
||||
process.env.STATIC!,
|
||||
process.platform === "win32" ? "icon.ico" : "icon.png"
|
||||
)
|
||||
)
|
||||
|
||||
if (process.platform === 'darwin') {
|
||||
// Mac image size needs to be smaller, or else it looks huge. Size
|
||||
// guideline is from https://iconhandbook.co.uk/reference/chart/osx/
|
||||
trayImage = trayImage.resize({ width: 22, height: 22 })
|
||||
}
|
||||
|
||||
this.tray = new Tray(trayImage)
|
||||
this.tray.setToolTip(`Awakened PoE Trade v${app.getVersion()}`)
|
||||
this.rebuildMenu()
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import fs from 'fs/promises'
|
||||
import path from 'path'
|
||||
import ini from 'ini'
|
||||
import { app } from 'electron'
|
||||
import process from 'process';
|
||||
import { hotkeyToString, CodeToKey } from '../../../ipc/KeyToCode'
|
||||
import type { Logger } from '../RemoteLogger'
|
||||
import type { ServerEvents } from '../server'
|
||||
@@ -21,7 +22,12 @@ export class GameConfig {
|
||||
if (this.filePath === filePath) return
|
||||
|
||||
if (!filePath) {
|
||||
filePath = path.join(app.getPath('documents'), 'My Games', 'Path of Exile', 'production_Config.ini')
|
||||
if (process.platform === 'darwin') {
|
||||
filePath = path.join(app.getPath('appData'), 'Path of Exile', 'Preferences', 'production_Config.ini')
|
||||
} else {
|
||||
filePath = path.join(app.getPath('documents'), 'My Games', 'Path of Exile', 'production_Config.ini')
|
||||
}
|
||||
|
||||
try {
|
||||
await fs.access(filePath)
|
||||
// this.server.sendEventTo('any', {
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
import { promises as fs, watchFile, unwatchFile } from 'fs'
|
||||
import { app } from 'electron';
|
||||
import { ServerEvents } from '../server'
|
||||
import { Logger } from '../RemoteLogger'
|
||||
|
||||
const COMMON_PATH = [
|
||||
'C:\\Program Files (x86)\\Grinding Gear Games\\Path of Exile\\logs\\Client.txt',
|
||||
'C:\\Program Files (x86)\\Steam\\steamapps\\common\\Path of Exile\\logs\\Client.txt'
|
||||
]
|
||||
|
||||
export class GameLogWatcher {
|
||||
private offset = 0
|
||||
private filePath?: string
|
||||
@@ -22,8 +18,20 @@ export class GameLogWatcher {
|
||||
async restart (logFile: string | null) {
|
||||
if (this.filePath === logFile) return
|
||||
|
||||
if (!logFile && process.platform === 'win32') {
|
||||
for (const filePath of COMMON_PATH) {
|
||||
if (!logFile) {
|
||||
let possiblePaths: string[] = []
|
||||
if (process.platform === 'win32') {
|
||||
possiblePaths = [
|
||||
'C:\\Program Files (x86)\\Grinding Gear Games\\Path of Exile\\logs\\Client.txt',
|
||||
'C:\\Program Files (x86)\\Steam\\steamapps\\common\\Path of Exile\\logs\\Client.txt'
|
||||
]
|
||||
} else if (process.platform === 'darwin') {
|
||||
possiblePaths = [
|
||||
`${app.getPath('home')}/Library/Caches/com.GGG.PathOfExile/Logs/Client.txt`
|
||||
]
|
||||
}
|
||||
|
||||
for (const filePath of possiblePaths) {
|
||||
try {
|
||||
await fs.access(filePath)
|
||||
// this.server.sendEventTo('any', {
|
||||
|
||||
@@ -224,7 +224,16 @@ export class Shortcuts {
|
||||
|
||||
function pressKeysToCopyItemText (pressedModKeys: string[] = [], showModsKey: string) {
|
||||
let keys = mergeTwoHotkeys('Ctrl + C', showModsKey).split(' + ')
|
||||
keys = keys.filter(key => key !== 'C' && !pressedModKeys.includes(key))
|
||||
keys = keys.filter(key => key !== 'C')
|
||||
if (process.platform !== 'darwin') {
|
||||
// On non-Mac platforms, don't toggle keys that are already being pressed.
|
||||
//
|
||||
// For unknown reasons, we need to toggle pressed keys on Mac for advanced
|
||||
// mod descriptions to be copied. You can test this by setting the shortcut
|
||||
// to "Alt + any letter". They'll work with this line, but not if it's
|
||||
// commented out.
|
||||
keys = keys.filter(key => !pressedModKeys.includes(key))
|
||||
}
|
||||
|
||||
for (const key of keys) {
|
||||
uIOhook.keyToggle(UiohookKey[key as UiohookKeyT], 'down')
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { uIOhook, UiohookKey as Key } from 'uiohook-napi'
|
||||
import process from 'process';
|
||||
import type { HostClipboard } from './HostClipboard'
|
||||
import type { OverlayWindow } from '../windowing/OverlayWindow'
|
||||
|
||||
@@ -14,14 +15,16 @@ const AUTO_CLEAR = [
|
||||
|
||||
export function typeInChat (text: string, send: boolean, clipboard: HostClipboard) {
|
||||
clipboard.restoreShortly((clipboard) => {
|
||||
const modifiers = process.platform === 'darwin' ? [Key.Meta] : [Key.Ctrl]
|
||||
|
||||
if (text.startsWith(PLACEHOLDER_LAST)) {
|
||||
text = text.slice(`${PLACEHOLDER_LAST} `.length)
|
||||
clipboard.writeText(text)
|
||||
uIOhook.keyTap(Key.Enter, [Key.Ctrl])
|
||||
uIOhook.keyTap(Key.Enter, modifiers)
|
||||
} else if (text.endsWith(PLACEHOLDER_LAST)) {
|
||||
text = text.slice(0, -PLACEHOLDER_LAST.length)
|
||||
clipboard.writeText(text)
|
||||
uIOhook.keyTap(Key.Enter, [Key.Ctrl])
|
||||
uIOhook.keyTap(Key.Enter, modifiers)
|
||||
uIOhook.keyTap(Key.Home)
|
||||
// press twice to focus input when using controller
|
||||
uIOhook.keyTap(Key.Home)
|
||||
@@ -30,11 +33,11 @@ export function typeInChat (text: string, send: boolean, clipboard: HostClipboar
|
||||
clipboard.writeText(text)
|
||||
uIOhook.keyTap(Key.Enter)
|
||||
if (!AUTO_CLEAR.includes(text[0])) {
|
||||
uIOhook.keyTap(Key.A, [Key.Ctrl])
|
||||
uIOhook.keyTap(Key.A, modifiers)
|
||||
}
|
||||
}
|
||||
|
||||
uIOhook.keyTap(Key.V, [Key.Ctrl])
|
||||
uIOhook.keyTap(Key.V, modifiers)
|
||||
|
||||
if (send) {
|
||||
uIOhook.keyTap(Key.Enter)
|
||||
@@ -56,7 +59,7 @@ export function stashSearch (
|
||||
overlay.assertGameActive()
|
||||
clipboard.writeText(text)
|
||||
uIOhook.keyTap(Key.F, [Key.Ctrl])
|
||||
uIOhook.keyTap(Key.V, [Key.Ctrl])
|
||||
uIOhook.keyTap(Key.V, [process.platform === 'darwin' ? Key.Meta : Key.Ctrl])
|
||||
uIOhook.keyTap(Key.Enter)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ export class GameWindow extends EventEmitter {
|
||||
if (!this._isTracking) {
|
||||
OverlayController.events.on('focus', () => { this.isActive = true })
|
||||
OverlayController.events.on('blur', () => { this.isActive = false })
|
||||
OverlayController.attachByTitle(window, title)
|
||||
OverlayController.attachByTitle(window, title, { hasTitleBarOnMac: true })
|
||||
this._isTracking = true
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user