Some more fixes for the 1.4.10 client

This commit is contained in:
WolverinDEV 2020-08-23 11:35:52 +02:00
parent 02d683954b
commit 3611718bc7
10 changed files with 224 additions and 366 deletions

View File

@ -12,6 +12,7 @@ export async function close() {
break;
} catch(error) {} /* error will be already logged */
}
if(global_window) {
global_window.close();
global_window = undefined;

View File

@ -1,15 +1,14 @@
/* --------------- bootstrap --------------- */
import * as RequireProxy from "../renderer/RequireProxy";
import * as path from "path";
RequireProxy.initialize(path.join(__dirname, "backend-impl"));
/* --------------- entry point --------------- */
import * as loader from "tc-loader";
import {Stage} from "tc-loader";
import {Arguments, process_args} from "../shared/process-arguments";
import {remote} from "electron";
RequireProxy.initialize(path.join(__dirname, "backend-impl"));
export function initialize(manifestTarget: string) {
console.log("Initializing native client for manifest target %s", manifestTarget);
@ -42,12 +41,10 @@ export function initialize(manifestTarget: string) {
loader.register_task(loader.Stage.JAVASCRIPT, {
name: "teaclient jquery",
function: async () => {
//const jquery = require("jquery");
//console.error(jquery);
//window.$ = jquery;
window.$ = require("jquery");
//window.jQuery = window.$;
//Object.assign(window.$, window.jsrender = require('jsrender'));
window.jQuery = window.$;
Object.assign(window.$, window.jsrender = require('jsrender'));
},
priority: 80
});

View File

@ -2,7 +2,7 @@ set(MODULE_NAME "teaclient_ppt")
set(SOURCE_FILES src/KeyboardHook.cpp)
if (MSVC)
set(SOURCE_FILES ${SOURCE_FILES} src/Win32KeyboardHook.cpp src/Win32KeyboardHookLL.cpp src/Win32KeyboardRawInput.cpp)
set(SOURCE_FILES ${SOURCE_FILES} src/Win32KeyboardHook.cpp src/Win32KeyboardRawInput.cpp)
else()
set(SOURCE_FILES ${SOURCE_FILES} src/X11KeyboardHook.cpp)
endif()

View File

@ -13,8 +13,7 @@ using namespace std;
#include "src/Win32KeyboardHook.h"
#else
#include "src/KeyboardHook.h"
#include "src/X11KeyboardHook.h"
#include "src/X11KeyboardHook.h"
#endif

View File

@ -6,16 +6,10 @@
enum struct KeyboardHookType {
X11,
RAW_INPUT,
SYSTEM_HOOK
RAW_INPUT
};
class KeyboardHook {
#ifdef HOOK_WIN32_LL
friend LRESULT CALLBACK _keyboard_hook_callback(int, WPARAM, LPARAM);
friend LRESULT CALLBACK _mouse_hook_callback(int, WPARAM, LPARAM);
#endif
public:
typedef unsigned int KeyID;

View File

@ -9,29 +9,6 @@ namespace hooks {
extern std::string key_string_from_vk(DWORD code, bool extended);
extern std::string key_string_from_sc(USHORT code);
class Win32SystemHook : public KeyboardHook {
public:
Win32SystemHook();
bool attach() override;
void detach() override;
bool keytype_supported() const override { return true; }
private:
static LRESULT CALLBACK _keyboard_hook_callback(int, WPARAM, LPARAM);
static LRESULT CALLBACK _mouse_hook_callback(int, WPARAM, LPARAM);
HHOOK keyboad_hook_id{nullptr};
bool keyboard_hook_callback(int, WPARAM, LPARAM);
HHOOK mouse_hook_id{nullptr};
bool mouse_hook_callback(int, WPARAM, LPARAM);
bool active{false};
std::thread poll_thread;
void poll_events();
};
class Win32RawHook : public KeyboardHook {
public:
Win32RawHook();
@ -39,12 +16,12 @@ namespace hooks {
bool attach() override;
void detach() override;
bool keytype_supported() const override { return true; }
[[nodiscard]] bool keytype_supported() const override { return true; }
private:
static LRESULT CALLBACK window_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp);
std::thread wthread;
void wloop();
std::thread window_thread;
void window_loop();
enum struct WorkerStatus {
STOPPED,
@ -63,6 +40,6 @@ namespace hooks {
void set_wstatus(WorkerStatus);
void handle_raw_input(RAWINPUT&);
HWND hwnd{0};
HWND hwnd{nullptr};
};
}

View File

@ -1,301 +0,0 @@
#include <iostream>
#include <cassert>
#include <string>
#include <mutex>
#include "./Win32KeyboardHook.h"
using namespace std;
namespace hooks {
void init_global_ed();
void shutdown_global_ed();
typedef KBDLLHOOKSTRUCT KeyboardHookStruct;
thread_local Win32SystemHook* thread_hook{nullptr};
Win32SystemHook::Win32SystemHook() : KeyboardHook{KeyboardHookType::SYSTEM_HOOK} {}
bool Win32SystemHook::attach() {
if(!KeyboardHook::attach())
return false;
init_global_ed();
this->active = true;
this->poll_thread = std::thread(std::bind(&Win32SystemHook::poll_events, this));
return true;
}
void Win32SystemHook::detach() {
this->active = false;
{
//TODO trigger no message!
}
if(this->poll_thread.joinable())
this->poll_thread.join();
/* will flush all events */
shutdown_global_ed();
KeyboardHook::detach();
}
LRESULT Win32SystemHook::_mouse_hook_callback(int nCode, WPARAM event, LPARAM ptr_keyboard) {
assert(thread_hook);
auto consume = thread_hook->mouse_hook_callback(nCode, event, ptr_keyboard);
auto end = std::chrono::high_resolution_clock::now();
if(consume)
return 1;
return CallNextHookEx(nullptr, nCode, event, ptr_keyboard);
}
LRESULT Win32SystemHook::_keyboard_hook_callback(int nCode, WPARAM event, LPARAM ptr_keyboard) {
assert(thread_hook);
auto consume = thread_hook->keyboard_hook_callback(nCode, event, ptr_keyboard);
if(consume)
return 1;
return CallNextHookEx(nullptr, nCode, event, ptr_keyboard);
}
void Win32SystemHook::poll_events() {
thread_hook = this;
if(!SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS))
std::cerr << "Failed to set priority class to realtime!" << std::endl;
#if 0
std::string msg_box{"Priority Class: "};
msg_box += std::to_string((int) GetPriorityClass(GetCurrentProcess()));
msg_box += " Priority: ";
msg_box += std::to_string((int) GetThreadPriority(GetCurrentProcess()));
MessageBox(nullptr, msg_box.c_str(), "PPT-Thread", MB_OK);
#endif
#if 0
int cur_priority = GetThreadPriority(GetCurrentThread());
DWORD cur_priority_class = GetPriorityClass(GetCurrentProcess());
std::cout << "P: " << cur_priority << " C: " << cur_priority_class << std::endl;
#endif
this->keyboad_hook_id = SetWindowsHookEx(WH_KEYBOARD_LL, &Win32SystemHook::_keyboard_hook_callback, GetModuleHandle(nullptr), 0);
if(!this->keyboad_hook_id) {
cerr << "Failed to register keyboard hook" << endl;
return;
}
#if 1
this->mouse_hook_id = SetWindowsHookEx(WH_MOUSE_LL, &Win32SystemHook::_mouse_hook_callback, GetModuleHandle(nullptr), 0);
if(!this->keyboad_hook_id) {
UnhookWindowsHookEx(this->keyboad_hook_id);
cerr << "Failed to register mouse hook" << endl;
return;
}
#else
this->mouse_hook_id = 0;
#endif
MSG msg;
while(!GetMessage(&msg, nullptr, 0, 0) && this->active) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if(this->mouse_hook_id > 0)
UnhookWindowsHookEx(this->mouse_hook_id);
UnhookWindowsHookEx(this->keyboad_hook_id);
thread_hook = nullptr;
}
inline std::string key_code(KeyboardHookStruct* keyboard) {
return key_string_from_vk(keyboard->vkCode, (keyboard->flags & LLKHF_EXTENDED) > 0);
}
using KeyType = KeyboardHook::KeyType;
bool Win32SystemHook::keyboard_hook_callback(int nCode, WPARAM event, LPARAM ptr_keyboard) {
auto keyboard = (KeyboardHookStruct*) ptr_keyboard;
if(event == WM_KEYDOWN || event == WM_SYSKEYDOWN) {
auto& state = this->map_key[keyboard->vkCode];
bool typed = state;
state = true;
auto type = key_type_from_vk(keyboard->vkCode);
if(type != KeyType::KEY_NORMAL)
this->map_special[type] = true;
else
this->map_special[type] = keyboard->vkCode;
if(!typed)
this->trigger_key_event(KeyEvent::PRESS, type == KeyType::KEY_NORMAL ? key_code(keyboard) : key_string_from_vk(this->map_special[KeyType::KEY_NORMAL], false));
this->trigger_key_event(KeyEvent::TYPE, type == KeyType::KEY_NORMAL ? key_code(keyboard) : key_string_from_vk(this->map_special[KeyType::KEY_NORMAL], false));
} else if(event == WM_KEYUP || event == WM_SYSKEYUP) {
auto& state = this->map_key[keyboard->vkCode];
if(!state) return false; //Duplicate
state = false;
auto type = key_type_from_vk(keyboard->vkCode);
if(type != KeyType::KEY_NORMAL)
this->map_special[type] = false;
else if(this->map_special[KeyType::KEY_NORMAL] == keyboard->vkCode)
this->map_special[KeyType::KEY_NORMAL] = 0;
this->trigger_key_event(KeyEvent::RELEASE, type == KeyType::KEY_NORMAL ? key_code(keyboard) : key_string_from_vk(this->map_special[KeyType::KEY_NORMAL], false));
}
//Consume the event: return 1
return false;
}
typedef MSLLHOOKSTRUCT MouseLLHookStruct;
struct MouseButtonEventEntry {
MouseButtonEventEntry* next;
KeyboardHook* hook;
enum KeyboardHook::KeyEvent::type type;
std::string key;
};
inline MouseButtonEventEntry* allocate_mb_event() {
return new MouseButtonEventEntry{};
}
inline void delete_mb_event(MouseButtonEventEntry* event) {
delete event;
}
struct MouseButtonEventDispatcher {
bool active{true};
std::thread dispatcher{};
CRITICAL_SECTION mutex;
CONDITION_VARIABLE cv_flushed;
CONDITION_VARIABLE cv_work;
MouseButtonEventEntry* event_head{nullptr};
MouseButtonEventEntry** event_tail{&event_head};
};
MouseButtonEventDispatcher* global_event_dispatcher{};
size_t global_ed_ref_count{0};
void init_global_ed() {
if(global_event_dispatcher) {
global_ed_ref_count++;
return;
}
global_event_dispatcher = new MouseButtonEventDispatcher{};
InitializeCriticalSection(&global_event_dispatcher->mutex);
InitializeConditionVariable(&global_event_dispatcher->cv_flushed);
InitializeConditionVariable(&global_event_dispatcher->cv_work);
global_event_dispatcher->dispatcher = std::thread([]{
auto ed = global_event_dispatcher;
while(ed->active) {
MouseButtonEventEntry* entry{nullptr};
{
EnterCriticalSection(&ed->mutex);
while(!global_event_dispatcher->event_head && ed->active) {
WakeAllConditionVariable(&ed->cv_flushed);
SleepConditionVariableCS(&ed->cv_work, &ed->mutex, INFINITE);
}
entry = global_event_dispatcher->event_head;
global_event_dispatcher->event_head = nullptr;
global_event_dispatcher->event_tail = &global_event_dispatcher->event_head;
LeaveCriticalSection(&ed->mutex);
}
while(entry) {
entry->hook->trigger_key_event(entry->type, std::string{entry->key});
auto next = entry->next;
delete_mb_event(entry);
entry = next;
}
}
});
}
void shutdown_global_ed() {
/* flush all events */
EnterCriticalSection(&global_event_dispatcher->mutex);
WakeAllConditionVariable(&global_event_dispatcher->cv_work);
SleepConditionVariableCS(&global_event_dispatcher->cv_flushed, &global_event_dispatcher->mutex, INFINITE);
LeaveCriticalSection(&global_event_dispatcher->mutex);
if(--global_ed_ref_count > 0) return;
auto ed = std::exchange(global_event_dispatcher, nullptr);
ed->active = false;
WakeAllConditionVariable(&ed->cv_work);
if(ed->dispatcher.joinable())
ed->dispatcher.join();
DeleteCriticalSection(&ed->mutex);
delete ed;
}
bool Win32SystemHook::mouse_hook_callback(int nCode, WPARAM event, LPARAM ptr_mouse) {
MouseButtonEventEntry* mb_event;
switch (event) {
case WM_LBUTTONDOWN:
mb_event = allocate_mb_event();
mb_event->type = KeyEvent::PRESS;
mb_event->key = "MOUSE1";
break;
case WM_LBUTTONUP:
mb_event = allocate_mb_event();
mb_event->type = KeyEvent::RELEASE;
mb_event->key = "MOUSE1";
break;
case WM_RBUTTONDOWN:
mb_event = allocate_mb_event();
mb_event->type = KeyEvent::PRESS;
mb_event->key = "MOUSE3";
break;
case WM_RBUTTONUP:
mb_event = allocate_mb_event();
mb_event->type = KeyEvent::RELEASE;
mb_event->key = "MOUSE3";
break;
case WM_XBUTTONDOWN: {
auto mouse = (MouseLLHookStruct*) ptr_mouse;
auto x_index = GET_XBUTTON_WPARAM(mouse->mouseData);
mb_event = allocate_mb_event();
mb_event->type = KeyEvent::PRESS;
mb_event->key = "MOUSEX" + std::to_string(x_index);
break;
}
case WM_XBUTTONUP: {
auto mouse = (MouseLLHookStruct*) ptr_mouse;
auto x_index = GET_XBUTTON_WPARAM(mouse->mouseData);
mb_event = allocate_mb_event();
mb_event->type = KeyEvent::RELEASE;
mb_event->key = "MOUSEX" + std::to_string(x_index);
break;
}
default:
return false;
}
mb_event->next = nullptr;
mb_event->hook = thread_hook;
EnterCriticalSection(&global_event_dispatcher->mutex);
*global_event_dispatcher->event_tail = mb_event;
global_event_dispatcher->event_tail = &mb_event->next;
WakeAllConditionVariable(&global_event_dispatcher->cv_work);
LeaveCriticalSection(&global_event_dispatcher->mutex);
return false;
}
}

View File

@ -15,7 +15,7 @@ namespace hooks {
this->wactive = true;
this->set_wstatus(WorkerStatus::INITIALIZING);
this->wthread = std::thread(std::bind(&Win32RawHook::wloop, this));
this->window_thread = std::thread([this] { this->window_loop(); });
std::unique_lock ws_lock{this->wstatus_mutex};
this->wstatus_changed_cv.wait(ws_lock, [&]{
@ -27,12 +27,14 @@ namespace hooks {
void Win32RawHook::detach() {
this->wactive = false;
{
//TODO trigger no message!
if(this->hwnd) {
PostMessage(this->hwnd, WM_CLOSE, 0, 0);
}
if(this->wthread.joinable())
this->wthread.join();
if(this->window_thread.joinable())
this->window_thread.join();
this->set_wstatus(WorkerStatus::STOPPED);
KeyboardHook::detach();
@ -46,7 +48,7 @@ namespace hooks {
}
#define WORKER_CLASS_NAME ("TeaClient - KeyHook worker")
void Win32RawHook::wloop() {
void Win32RawHook::window_loop() {
this->set_wstatus(WorkerStatus::INITIALIZING);
/* setup */
@ -55,12 +57,12 @@ namespace hooks {
WNDCLASS wc = {0};
wc.lpfnWndProc = window_proc;
wc.cbWndExtra = sizeof(void*);
wc.hInstance = 0;
wc.hInstance = nullptr;
wc.lpszClassName = WORKER_CLASS_NAME;
RegisterClass(&wc);
}
this->hwnd = CreateWindow(WORKER_CLASS_NAME, "TeaClient - KeyHook worker window", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, this);
this->hwnd = CreateWindow(WORKER_CLASS_NAME, "TeaClient - KeyHook worker window", 0, 0, 0, 0, 0, HWND_MESSAGE, nullptr, nullptr, this);
if(!this->hwnd) {
this->worker_died_reason = "Failed to create window";
this->set_wstatus(WorkerStatus::DIED);
@ -70,12 +72,12 @@ namespace hooks {
RAWINPUTDEVICE devices[2];
devices[0].usUsagePage = 0x01; //HID_USAGE_PAGE_GENERIC;
devices[0].usUsage = 0x02; //HID_USAGE_GENERIC_MOUSE;
devices[0].dwFlags = RIDEV_NOLEGACY | RIDEV_INPUTSINK;
devices[0].dwFlags = (uint32_t) RIDEV_NOLEGACY | (uint32_t) RIDEV_INPUTSINK;
devices[0].hwndTarget = hwnd;
devices[1].usUsagePage = 0x01; //HID_USAGE_PAGE_GENERIC;
devices[1].usUsage = 0x06; //HID_USAGE_GENERIC_KEYBOARD;
devices[1].dwFlags = RIDEV_NOLEGACY | RIDEV_INPUTSINK;
devices[1].dwFlags = (uint32_t) RIDEV_NOLEGACY | (uint32_t) RIDEV_INPUTSINK;
devices[1].hwndTarget = hwnd;
if(!RegisterRawInputDevices(devices, 2, sizeof *devices)) {
@ -86,18 +88,19 @@ namespace hooks {
}
this->set_wstatus(WorkerStatus::RUNNING);
BOOL ret;
MSG msg;
while (this->wactive) {
ret = GetMessage(&msg, this->hwnd, 0, 0);
if(ret == 0)
break;
if (ret == -1) {
this->worker_died_reason = "GetMessage() threw an error";
this->set_wstatus(WorkerStatus::DIED);
goto cleanup;
}
else {
} else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
@ -105,10 +108,8 @@ namespace hooks {
this->set_wstatus(WorkerStatus::STOPPED);
cleanup:
if(this->hwnd > 0) {
DestroyWindow(this->hwnd);
this->hwnd = 0;
}
if(auto window{std::exchange(this->hwnd, nullptr)}; window)
DestroyWindow(window);
}
LRESULT Win32RawHook::window_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
@ -116,18 +117,17 @@ namespace hooks {
switch (msg) {
case WM_CREATE: {
CREATESTRUCT *s = reinterpret_cast<CREATESTRUCT *>(lp);
auto s = reinterpret_cast<CREATESTRUCT *>(lp);
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) s->lpCreateParams);
return 0;
}
case WM_CLOSE:
DestroyWindow(hwnd);
PostQuitMessage(0);
/* nothing to do here, the window will be cleaned up by the event dispatchers */
return 0;
case WM_INPUT: {
UINT target_size{0};
GetRawInputData((HRAWINPUT) lp, RID_INPUT, NULL, &target_size, sizeof(RAWINPUTHEADER));
GetRawInputData((HRAWINPUT) lp, RID_INPUT, nullptr, &target_size, sizeof(RAWINPUTHEADER));
if(target_size > sizeof(RAWINPUT)) {
std::cerr << "Failed to retrieve input (Target size is longer than expected)" << std::endl;
return 0;

190
package-lock.json generated
View File

@ -172,6 +172,11 @@
"integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==",
"dev": true
},
"@types/color-name": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ=="
},
"@types/ejs": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/@types/ejs/-/ejs-2.7.0.tgz",
@ -523,6 +528,11 @@
"integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=",
"dev": true
},
"astral-regex": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
"integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ=="
},
"async-each": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz",
@ -1102,6 +1112,50 @@
"resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.3.0.tgz",
"integrity": "sha512-Xs2Hf2nzrvJMFKimOR7YR0QwZ8fc0u98kdtwN1eNAZzNQgH3vK2pXzff6GJtKh7S5hoJ87ECiAiZFS2fb5Ii2w=="
},
"cli-truncate": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz",
"integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==",
"requires": {
"slice-ansi": "^3.0.0",
"string-width": "^4.2.0"
},
"dependencies": {
"ansi-regex": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg=="
},
"emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
},
"is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
},
"string-width": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
"integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
"requires": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.0"
}
},
"strip-ansi": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
"requires": {
"ansi-regex": "^5.0.0"
}
}
}
},
"cliui": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz",
@ -1679,6 +1733,26 @@
"extract-zip": "^1.0.3"
}
},
"electron-context-menu": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/electron-context-menu/-/electron-context-menu-2.3.0.tgz",
"integrity": "sha512-XYsYkNY+jvX4C5o09qMuZoKL6e9frnQzBFehZSIiKp6zK0u3XYowJYDyK3vDKKZxYsOIGiE/Gbx40jERC03Ctw==",
"requires": {
"cli-truncate": "^2.0.0",
"electron-dl": "^3.0.0",
"electron-is-dev": "^1.0.1"
}
},
"electron-dl": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/electron-dl/-/electron-dl-3.0.2.tgz",
"integrity": "sha512-pRgE9Jbhoo5z6Vk3qi+vIrfpMDlCp2oB1UeR96SMnsfz073jj0AZGQwp69EdIcEvlUlwBSGyJK8Jt6OB6JLn+g==",
"requires": {
"ext-name": "^5.0.0",
"pupa": "^2.0.1",
"unused-filename": "^2.1.0"
}
},
"electron-fetch": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/electron-fetch/-/electron-fetch-1.5.0.tgz",
@ -1770,6 +1844,11 @@
}
}
},
"electron-is-dev": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/electron-is-dev/-/electron-is-dev-1.2.0.tgz",
"integrity": "sha512-R1oD5gMBPS7PVU8gJwH6CtT0e6VSoD0+SzSnYpNm+dBkcijgA+K7VAMHDfnRq/lkKPZArpzplTW6jfiMYosdzw=="
},
"electron-osx-sign": {
"version": "0.4.15",
"resolved": "https://registry.npmjs.org/electron-osx-sign/-/electron-osx-sign-0.4.15.tgz",
@ -2318,6 +2397,11 @@
"integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==",
"optional": true
},
"escape-goat": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz",
"integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q=="
},
"escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
@ -2397,6 +2481,23 @@
}
}
},
"ext-list": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz",
"integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==",
"requires": {
"mime-db": "^1.28.0"
}
},
"ext-name": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz",
"integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==",
"requires": {
"ext-list": "^2.0.0",
"sort-keys-length": "^1.0.0"
}
},
"extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
@ -3901,6 +4002,11 @@
"path-is-inside": "^1.0.1"
}
},
"is-plain-obj": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
"integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4="
},
"is-plain-object": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
@ -4518,6 +4624,11 @@
}
}
},
"modify-filename": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/modify-filename/-/modify-filename-1.1.0.tgz",
"integrity": "sha1-mi3sg4Bvuy2XXyK+7IWcoms5OqE="
},
"moment": {
"version": "2.26.0",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.26.0.tgz",
@ -5313,6 +5424,14 @@
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
},
"pupa": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/pupa/-/pupa-2.0.1.tgz",
"integrity": "sha512-hEJH0s8PXLY/cdXh66tNEQGndDrIKNqNC5xmrysZy3i5C3oEoLna7YAOad+7u125+zH1HNXUmGEkrhb3c2VriA==",
"requires": {
"escape-goat": "^2.0.0"
}
},
"pure-uuid": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/pure-uuid/-/pure-uuid-1.6.0.tgz",
@ -5842,6 +5961,45 @@
"string-width": "^1.0.1"
}
},
"slice-ansi": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz",
"integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==",
"requires": {
"ansi-styles": "^4.0.0",
"astral-regex": "^2.0.0",
"is-fullwidth-code-point": "^3.0.0"
},
"dependencies": {
"ansi-styles": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
"integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
"requires": {
"@types/color-name": "^1.1.1",
"color-convert": "^2.0.1"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
}
}
},
"snapdragon": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
@ -5970,6 +6128,22 @@
}
}
},
"sort-keys": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz",
"integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=",
"requires": {
"is-plain-obj": "^1.0.0"
}
},
"sort-keys-length": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz",
"integrity": "sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg=",
"requires": {
"sort-keys": "^1.0.0"
}
},
"source-map": {
"version": "0.1.32",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.32.tgz",
@ -6668,6 +6842,22 @@
}
}
},
"unused-filename": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/unused-filename/-/unused-filename-2.1.0.tgz",
"integrity": "sha512-BMiNwJbuWmqCpAM1FqxCTD7lXF97AvfQC8Kr/DIeA6VtvhJaMDupZ82+inbjl5yVP44PcxOuCSxye1QMS0wZyg==",
"requires": {
"modify-filename": "^1.1.0",
"path-exists": "^4.0.0"
},
"dependencies": {
"path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
}
}
},
"unzip-response": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz",

View File

@ -58,6 +58,7 @@
"aws4": "^1.10.0",
"color.js": "^0.1.3",
"electron": "8.0.0",
"electron-context-menu": "^2.3.0",
"electron-installer-windows": "^1.1.0",
"electron-rebuild": "^1.11.0",
"electron-wix-msi": "^2.1.1",