Skip to content

Commit 8baaa54

Browse files
committed
feat: support keyboard shortcuts
1 parent 4f99193 commit 8baaa54

File tree

5 files changed

+172
-12
lines changed

5 files changed

+172
-12
lines changed

forge.config.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ module.exports = {
3939
productName: 'BingGPT',
4040
description: 'AI-powered copilot',
4141
productDescription: 'AI-powered copilot',
42-
version: '0.3.1',
42+
version: '0.3.2',
4343
categories: ['Utility'],
4444
maintainer: 'dice2o',
4545
homepage: 'https://github.com/dice2o/BingGPT',
@@ -56,7 +56,7 @@ module.exports = {
5656
productName: 'BingGPT',
5757
description: 'AI-powered copilot',
5858
productDescription: 'AI-powered copilot',
59-
version: '0.3.1',
59+
version: '0.3.2',
6060
categories: ['Utility'],
6161
maintainer: 'dice2o',
6262
homepage: 'https://github.com/dice2o/BingGPT',

main.js

Lines changed: 70 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,7 @@ const createWindow = () => {
111111
type: 'checkbox',
112112
checked: mainWindow.isAlwaysOnTop() ? true : false,
113113
visible: parameters.selectionText.trim().length === 0,
114-
click: () => {
115-
config.set('alwaysOnTop', !mainWindow.isAlwaysOnTop())
116-
mainWindow.setAlwaysOnTop(!mainWindow.isAlwaysOnTop())
117-
},
114+
click: () => alwaysOnTopHandler(),
118115
},
119116
{
120117
type: 'separator',
@@ -222,7 +219,7 @@ const createWindow = () => {
222219
},
223220
},
224221
{
225-
label: 'BingGPT v0.3.1',
222+
label: 'BingGPT v0.3.2',
226223
visible: parameters.selectionText.trim().length === 0,
227224
click: () => {
228225
shell.openExternal('https://github.com/dice2o/BingGPT/releases')
@@ -273,10 +270,17 @@ const createWindow = () => {
273270
mainWindow.webContents.session.webRequest.onBeforeSendHeaders(
274271
(details, callback) => {
275272
details.requestHeaders['user-agent'] = userAgent
276-
details.requestHeaders['x-forwarded-for'] = '1.1.1.1'
273+
if (details.url !== bingUrl) {
274+
details.requestHeaders['x-forwarded-for'] = '1.1.1.1'
275+
}
277276
callback({ requestHeaders: details.requestHeaders, cancel: false })
278277
}
279278
)
279+
// Always on top
280+
const alwaysOnTopHandler = () => {
281+
config.set('alwaysOnTop', !mainWindow.isAlwaysOnTop())
282+
mainWindow.setAlwaysOnTop(!mainWindow.isAlwaysOnTop())
283+
}
280284
// Theme
281285
const themeHandler = (newTheme) => {
282286
config.set('theme', newTheme)
@@ -299,6 +303,66 @@ const createWindow = () => {
299303
config.set('fontSize', newSize)
300304
mainWindow.webContents.send('set-font-size', newSize)
301305
}
306+
// Shortcuts
307+
mainWindow.webContents.on('before-input-event', (event, input) => {
308+
const cmdKey = process.platform === 'darwin' ? input.meta : input.control
309+
if (cmdKey) {
310+
switch (input.code) {
311+
case 'KeyN':
312+
mainWindow.webContents.send('new-topic')
313+
event.preventDefault()
314+
break
315+
case 'KeyR':
316+
mainWindow.reload()
317+
event.preventDefault()
318+
break
319+
case 'KeyT':
320+
alwaysOnTopHandler()
321+
event.preventDefault()
322+
break
323+
case 'KeyI':
324+
mainWindow.webContents.send('focus-on-textarea')
325+
event.preventDefault()
326+
break
327+
case 'KeyS':
328+
mainWindow.webContents.send('stop-responding')
329+
event.preventDefault()
330+
break
331+
case 'Equal':
332+
if (
333+
configSchema.fontSize.enum.indexOf(config.get('fontSize') + 2) !==
334+
-1
335+
) {
336+
fontSizeHandler(config.get('fontSize') + 2)
337+
event.preventDefault()
338+
}
339+
break
340+
case 'Minus':
341+
if (
342+
configSchema.fontSize.enum.indexOf(config.get('fontSize') - 2) !==
343+
-1
344+
) {
345+
fontSizeHandler(config.get('fontSize') - 2)
346+
event.preventDefault()
347+
}
348+
break
349+
case 'Comma':
350+
mainWindow.webContents.send('switch-tone', 'left')
351+
event.preventDefault()
352+
break
353+
case 'Period':
354+
mainWindow.webContents.send('switch-tone', 'right')
355+
event.preventDefault()
356+
break
357+
default:
358+
if (input.code.indexOf('Digit') === 0) {
359+
const id = input.code.split('Digit')[1]
360+
mainWindow.webContents.send('quick-reply', Number(id))
361+
event.preventDefault()
362+
}
363+
}
364+
}
365+
})
302366
}
303367

304368
app.whenReady().then(() => {

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "binggpt",
33
"productName": "BingGPT",
4-
"version": "0.3.1",
4+
"version": "0.3.2",
55
"description": "AI-powered copilot",
66
"author": "dice2o",
77
"license": "Apache-2.0",

preload.js

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,102 @@ window.addEventListener('DOMContentLoaded', () => {
112112
}
113113
})
114114

115+
// New topic
116+
ipcRenderer.on('new-topic', () => {
117+
try {
118+
const newTopicBtn = document
119+
.getElementsByTagName('cib-serp')[0]
120+
.shadowRoot.getElementById('cib-action-bar-main')
121+
.shadowRoot.querySelector('button[class="button-compose"]')
122+
if (newTopicBtn) {
123+
newTopicBtn.click()
124+
}
125+
} catch (err) {
126+
console.log(err)
127+
}
128+
})
129+
130+
// Focus on textarea
131+
ipcRenderer.on('focus-on-textarea', () => {
132+
try {
133+
const textarea = document
134+
.getElementsByTagName('cib-serp')[0]
135+
.shadowRoot.getElementById('cib-action-bar-main')
136+
.shadowRoot.getElementById('searchbox')
137+
if (textarea) {
138+
textarea.focus()
139+
}
140+
} catch (err) {
141+
console.log(err)
142+
}
143+
})
144+
145+
// Stop responding
146+
ipcRenderer.on('stop-responding', () => {
147+
try {
148+
const stopBtn = document
149+
.getElementsByTagName('cib-serp')[0]
150+
.shadowRoot.getElementById('cib-action-bar-main')
151+
.shadowRoot.querySelector('cib-typing-indicator')
152+
.shadowRoot.getElementById('stop-responding-button')
153+
if (stopBtn) {
154+
stopBtn.click()
155+
}
156+
} catch (err) {
157+
console.log(err)
158+
}
159+
})
160+
161+
// Quick reply
162+
ipcRenderer.on('quick-reply', (event, id) => {
163+
try {
164+
const suggestionReplies = document
165+
.getElementsByTagName('cib-serp')[0]
166+
.shadowRoot.getElementById('cib-conversation-main')
167+
.shadowRoot.querySelector('cib-suggestion-bar')
168+
.shadowRoot.querySelectorAll('cib-suggestion-item')
169+
if (suggestionReplies) {
170+
suggestionReplies[id - 1].shadowRoot.querySelector('button').click()
171+
}
172+
} catch (err) {
173+
console.log(err)
174+
}
175+
})
176+
177+
// Switch tone
178+
ipcRenderer.on('switch-tone', (event, direction) => {
179+
try {
180+
const toneOptions = document
181+
.getElementsByTagName('cib-serp')[0]
182+
.shadowRoot.getElementById('cib-conversation-main')
183+
.shadowRoot.querySelector('cib-tone-selector')
184+
.shadowRoot.getElementById('tone-options')
185+
if (toneOptions) {
186+
const toneBtns = toneOptions.querySelectorAll('button')
187+
const selectedBtn = toneOptions.querySelector('button[selected]')
188+
let index = Array.from(toneBtns).indexOf(selectedBtn)
189+
switch (direction) {
190+
case 'right':
191+
if (index === toneBtns.length - 1) {
192+
index = 0
193+
} else {
194+
index++
195+
}
196+
break
197+
case 'left':
198+
if (index === 0) {
199+
index = toneBtns.length - 1
200+
} else {
201+
index--
202+
}
203+
}
204+
toneBtns[index].click()
205+
}
206+
} catch (err) {
207+
console.log(err)
208+
}
209+
})
210+
115211
// Set font size
116212
ipcRenderer.on('set-font-size', (event, size) => {
117213
try {
@@ -239,7 +335,7 @@ const markdownHandler = (element) => {
239335
replacement: (content, node) => {
240336
return `[${content.replace(/^(\d+)(\\.)/, '[$1]')}](${node.getAttribute(
241337
'href'
242-
)} "${node.getAttribute('title')}")`
338+
)} "${node.getAttribute('title').replace(/\"/g, '')}")`
243339
},
244340
})
245341
turndownService.addRule('userMessage', {

0 commit comments

Comments
 (0)