Study & Project ✏️/electron 🐣

[라즈베리파이 크로스컴파일] 3. electron keyboard shortcuts 예제

JM 2022. 1. 5. 15:10
반응형

출처. https://www.electronjs.org/docs/latest/tutorial/keyboard-shortcuts

 

Keyboard Shortcuts | Electron

This feature allows you to configure local and global keyboard shortcuts for your Electron application.

www.electronjs.org

프로그램을 사용할 때 단축키를 지정해서 사용할 때가 있다.

(Ctrl + S = 저장) 같이!

QT5 하면서 keyPressEvent였나 키가 눌렸을 때 입력을 인지하는 API가 있었는데

Electron에서도 있다니 연습해봐야겠다.


Local Short Cut 등록 후 Console창에서 출력하기!

(Local의 의미는 Application에 포커스가 있을 때다.)

//main.js
const { app, BrowserWindow, Menu, MenuItem } = require('electron')

function createWindow () {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
  })

  win.loadFile('index.html')
}

// Menu.setApplicationMenu(menu)
// Accelerator는 여러 수식어와 단일 키 코드를 담을 수 있는 문자열이다. '+'로 합칠 수 있고 이걸로 Shortcuts를 만들 수 있다.
// globalShorcut는 register라는 모듈을 사용하는 방법으로 등록할 수 있다.
// mac = Command, Linux & Window = Control 이므로 둘 다 사용하려면 CommandOrContorl을 사용해야 한다.
// Window기준 window키는 Meta, Mac기준 Cmd키는 Super이다.
const menu = new Menu()
menu.append(new MenuItem({
    label: 'Electron',
    submenu: [{
        role: 'help',
        accelerator: process.platform === 'darwin' ? 'Alt+Cmd+I' : 'Alt+Shift+I',
        click: () => {console.log('Electron Short Cut!')}
    }]
}))

Menu.setApplicationMenu(menu);

app.whenReady().then(createWindow)

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', () => {
  if (BrowserWindow.getAllWindows().length === 0) {
    createWindow()
  }
})
//index.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Hello World!</title>
    <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
</head>
<body>
    <h1>Hello World!</h1>
    <p>Hit Alt+Shift+I on Windows, or Opt+Cmd+I on mac to see a message printed to the console.</p>
</body>
</html>

이런 식으로 console창에 찍힌다.

생각보다 복잡한 것들이 많다.

 

1. window에서 입력받는 시스템이 아닌 프로그램 자체에서 키보드 입력을 받기 때문에

BrowserWindow 바깥에서 선언하는 점.

 

2. Accelerator라는 페이지에서는 GlobalShorCuts에 관해서 설명해주는데

실제로 사용할 때는 Menu 모듈의 setApplicationMenu의 MenuItem에서 지정하는 행동을 하도록 해줘야 한다.

 

3. menu.append()안의 MenuItem에서

json형태의 포멧의 label, submenu를 지정해주고

submenu안에 accelerator에서 원하는 shortcut을 지정해주는 것!!

 

4. role에 들어가는 이미 지정되어 있는 function은 하단 홈페이지에서 Role 부분을 참고하면 된다.

https://www.electronjs.org/docs/latest/api/menu-item

 

Class: MenuItem | Electron

Add items to native application menus and context menus.

www.electronjs.org

추가로 하나 더 해봤다.

menu.append() 부분을 이렇게 바꿔주면 된다.

menu.append(new MenuItem({
    label: 'Electron',
    submenu: [{
        role: 'toggleDevTools',
        accelerator: process.platform === 'darwin' ? 'Alt+Cmd+I' : 'Alt+Shift+I',
        // click: () => {console.log('Electron Short Cut!')}
    }]
}))

잘 동작한다.


Global Short Cut 등록 후 Console창에 출력하기!

(Global의 의미는 Application에 Focus가 없을 때다)

잘 된다.

Local때와 마찬가지로 특이한 개념이 있었다.

 

1. Global하게 입력을 받기 위해서 app.whenReady().then() => 으로 처리했다.

 

2. register안에서 prameter로 accelerator와 callback 함수를 받고 있다.

3.  register doc에서 다루는 내용인데

app.whenReady() 일때 globalShortcut을 등록하고

app.on('will-quit') 상태일 때 globalShortcut을 등록 해제할 수 있다.

https://www.electronjs.org/docs/latest/api/global-shortcut

 

globalShortcut | Electron

Detect keyboard events when the application does not have keyboard focus.

www.electronjs.org

 

3번 내용을 통해서 Devtool을 여는 걸 복습해보자.

//main.js
const { app, BrowserWindow, globalShortcut } = require('electron')
let win;

function createWindow() {
    win = new BrowserWindow({
        width: 800,
        height: 600,
    })

    win.loadFile('index.html')
}

app.whenReady().then(() => {
    // Ready상태일때 'Alt + Shift + I'를 Global ShortCut로 register를 이용해서 등록한다.
    // Callback함수를 통해 DevTool를 연다.
    // win를 바깥에서 쓰기 위해 let win;으로 전역 변수를 설정해준다.
    const shortcut = globalShortcut.register('Alt + Shift + I', () => {
        win.webContents.openDevTools();
    })

    if (!shortcut) {
        console.log('registration failed')
    }
    // 해당 globackShortcut이 등록됐는지 확인하는 것.
    console.log(globalShortcut.isRegistered('Alt + Shift + I'))
}).then(createWindow)

app.on('window-all-closed', () => {
    if (process.platform !== 'darwin') {
        app.quit()
    }
})

app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) {
        createWindow()
    }
})

app.on('will-quit', () => {
    // Shortcut 등록 해제.
    globalShortcut.unregister('Ctrl+Shift+I')

    // 모든 Shortcut 등록 해제.
    globalShortcut.unregisterAll()
})

console만 찍는게 아니라 BrowerWindow에서 행동을 시키는 법을 찾아보니

let win; 으로 전역 변수를 선언해서 app.on() 안에서 win을 사용할 수 있도록 해주더라.


다음은 web API를 이용해서 Shortcut을 사용해보자.

html요소를 바꿀때 renderer.js에서 접근해서 변경해줬다.

//renderer.js
function handleKeyPress (event) {
    document.getElementById("last-keypress").innerText = event.key
    console.log(`${event.key}`)
}

window.addEventListener('keyup', handleKeyPress, true)
//index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
    <title>Hello World!</title>
    <meta http-equiv="X-Content-Security-Policy" content="default-src 'self'; script-src 'self'">
    <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline';">
  </head>
  <body>
    <h1>Hello World!</h1>
    <p>Hit any key with this window focused to see it captured here.</p>
    <div><span>Last Key Pressed: </span><span id="last-keypress"></span></div>
    <script src="./renderer.js"></script>
  </body>
</html>

1. 웹 API인 addEventListener()를 이용해서 type, listener파라미터를 주고

true파라미터는 다른 listener보다 우선적이게 키 입력을 받겠다는 것 같다.

 

2. DOM를 보면 keyup, keydown은 a, b, c처럼 문자로 기록되지만 keypress는 char형으로 기록된다.

 

추가적으로 renderer.js가 아닌 main.js에서 하는 방법도 있다.

win.webContents.on('before-input-event')의 'before-input-event'는

keydown, keyup 신호를 페이지에 보내기 전에 신호를 방출하는 이벤트다.

이 신호를 이용해서 메뉴에 없는 커스텀 Short cuts를 만들 수 있단다.

//main.js
const { app, BrowserWindow } = require('electron')

app.whenReady().then(() => {
  //app모듈 안에서 BrowserWindow를 선언해서 사용할 수 있게 했다.
  const win = new BrowserWindow({ width: 800, height: 600 })

  win.loadFile('index.html')
  win.webContents.on('before-input-event', (event, input) => {
    if (input.control && input.key.toLowerCase() === 'i') {
      console.log('Pressed Control+I')
      event.preventDefault()
    }
  })
})

console.log는 식상하니 DevTools를 열어보자

//main.js 의 해당 부분 수정
app.whenReady().then(() => {
    const win = new BrowserWindow({ width: 800, height: 600 })
    win.loadFile('index.html')
    // createWindow()
    win.webContents.on('before-input-event', (event, input) => {
        if(input.control && input.key.toLowerCase() === 'i') {
            win.webContents.openDevTools()
            event.preventDefault()
        }
    })
})

잘 동작한다.


마지막으로!!!!!! third-party libraries를 이용한 shortcut 사용이 있다.

웹 개발을 안해봐서 그런지 Mousetrap을 이용한 shortcut 등록에 실패했다 ㅠㅠ

https://github.com/ccampbell/mousetrap

 

GitHub - ccampbell/mousetrap: Simple library for handling keyboard shortcuts in Javascript

Simple library for handling keyboard shortcuts in Javascript - GitHub - ccampbell/mousetrap: Simple library for handling keyboard shortcuts in Javascript

github.com

혹시나 나중에 필요하다면 더 공부해서 수정해보겠다.


하나하나 완료하고 포스팅하는 게 은근히 재밌다.

다음은 Linux에서 .desktop을 만드는 것과

SerialPort를 적용하는 걸 연습해보려고 한다.