diff --git a/Reader/Cache.cpp b/Reader/Cache.cpp index c2f0fda..9f06781 100644 --- a/Reader/Cache.cpp +++ b/Reader/Cache.cpp @@ -366,6 +366,7 @@ void Cache::default_header(header_t* header) // default bk color header->bg_color = 0x00ffffff; // White header->alpha = 0xff; + header->transparent_bg = 0; header->char_gap = 0; header->line_gap = 5; diff --git a/Reader/DisplaySet.cpp b/Reader/DisplaySet.cpp index 92ceafa..766fa02 100644 --- a/Reader/DisplaySet.cpp +++ b/Reader/DisplaySet.cpp @@ -23,6 +23,7 @@ typedef struct display_set_data_t int word_wrap; int line_indent; int blank_lines; + int transparent_bg; int chapter_page; int is_save; } display_set_data_t; @@ -80,6 +81,7 @@ static void _update_preview(HDC hDC, RECT *rc); (d)->word_wrap = (s)->word_wrap; \ (d)->line_indent = (s)->line_indent; \ (d)->blank_lines = (s)->blank_lines; \ + (d)->transparent_bg = (s)->transparent_bg; \ (d)->chapter_page = (s)->chapter_page; void OpenDisplaySetDlg(void) @@ -224,6 +226,10 @@ static INT_PTR CALLBACK DisplaySetDlgProc(HWND hDlg, UINT message, WPARAM wParam res = (int)SendMessage(GetDlgItem(hDlg, IDC_CHECK_BLANKLINES), BM_GETCHECK, 0, NULL); _display.blank_lines = BST_CHECKED == res ? 1 : 0; break; + case IDC_CHECK_TRANS_BG: + res = (int)SendMessage(GetDlgItem(hDlg, IDC_CHECK_TRANS_BG), BM_GETCHECK, 0, NULL); + _display.transparent_bg = BST_CHECKED == res ? 1 : 0; + break; case IDC_CHECK_CHAPTER_PAGE: res = (int)SendMessage(GetDlgItem(hDlg, IDC_CHECK_CHAPTER_PAGE), BM_GETCHECK, 0, NULL); _display.chapter_page = BST_CHECKED == res ? 1 : 0; @@ -315,6 +321,7 @@ static void _init_layout_set(HWND hDlg) SendMessage(GetDlgItem(hDlg, IDC_CHECK_WORD_WRAP), BM_SETCHECK, _display.word_wrap ? BST_CHECKED : BST_UNCHECKED, NULL); SendMessage(GetDlgItem(hDlg, IDC_CHECK_INDENT), BM_SETCHECK, _display.line_indent ? BST_CHECKED : BST_UNCHECKED, NULL); SendMessage(GetDlgItem(hDlg, IDC_CHECK_BLANKLINES), BM_SETCHECK, _display.blank_lines ? BST_CHECKED : BST_UNCHECKED, NULL); + SendMessage(GetDlgItem(hDlg, IDC_CHECK_TRANS_BG), BM_SETCHECK, _display.transparent_bg ? BST_CHECKED : BST_UNCHECKED, NULL); SendMessage(GetDlgItem(hDlg, IDC_CHECK_CHAPTER_PAGE), BM_SETCHECK, _display.chapter_page ? BST_CHECKED : BST_UNCHECKED, NULL); } diff --git a/Reader/Jsondata.cpp b/Reader/Jsondata.cpp index 2407fec..1cd8327 100644 --- a/Reader/Jsondata.cpp +++ b/Reader/Jsondata.cpp @@ -600,6 +600,7 @@ class json_header_t cJSON* line_indent; cJSON* blank_lines; cJSON* chapter_page; + cJSON* transparent_bg; cJSON* ingore_version; cJSON* checkver_time; cJSON* global_key; @@ -656,6 +657,7 @@ class json_header_t line_indent = cJSON_AddNumberToObject(parent, "line_indent", data->line_indent); blank_lines = cJSON_AddNumberToObject(parent, "blank_lines", data->blank_lines); chapter_page = cJSON_AddNumberToObject(parent, "chapter_page", data->chapter_page); + transparent_bg = cJSON_AddNumberToObject(parent, "transparent_bg", data->transparent_bg); ingore_version = cJSON_AddStringToObject(parent, "ingore_version", Utf16ToUtf8(data->ingore_version)); checkver_time = cJSON_AddULongToObject(parent, "checkver_time", data->checkver_time); @@ -779,6 +781,7 @@ class json_header_t line_indent = cJSON_GetObjectItem(parent, "line_indent"); blank_lines = cJSON_GetObjectItem(parent, "blank_lines"); chapter_page = cJSON_GetObjectItem(parent, "chapter_page"); + transparent_bg = cJSON_GetObjectItem(parent, "transparent_bg"); ingore_version = cJSON_GetObjectItem(parent, "ingore_version"); checkver_time = cJSON_GetObjectItem(parent, "checkver_time"); @@ -966,6 +969,8 @@ class json_header_t data->blank_lines = blank_lines->valueint; if (chapter_page) data->chapter_page = chapter_page->valueint; + if (transparent_bg) + data->transparent_bg = transparent_bg->valueint; if (ingore_version) wcscpy(data->ingore_version, Utf8ToUtf16(ingore_version->valuestring)); if (checkver_time) diff --git a/Reader/Keyset.cpp b/Reader/Keyset.cpp index 3c5a861..70e6a8c 100644 --- a/Reader/Keyset.cpp +++ b/Reader/Keyset.cpp @@ -19,6 +19,7 @@ extern LRESULT OnChapterUp(HWND, UINT, WPARAM, LPARAM); extern LRESULT OnChapterDown(HWND, UINT, WPARAM, LPARAM); extern LRESULT OnFontZoomIn(HWND, UINT, WPARAM, LPARAM); extern LRESULT OnFontZoomOut(HWND, UINT, WPARAM, LPARAM); +extern LRESULT OnTransBG(HWND, UINT, WPARAM, LPARAM); extern int MessageBoxFmt_(HWND hWnd, UINT captionId, UINT uType, UINT formatId, ...); extern HINSTANCE hInst; @@ -34,6 +35,9 @@ static BOOL _unregister_hotkey(HWND hWnd, DWORD kid); keydata_t g_Keysets[KI_MAXCOUNT] = { { MAKELONG(KT_HOTKEY, KI_HIDE), IDHK_SHWIN, 0, 0, MAKEWORD('H', HOTKEYF_ALT), IDC_HK_HIDE, IDC_CHECK_HIDE, OnHideWin, IDS_HIDE_SHOW_WINDOW }, + { MAKELONG(KT_HOTKEY, KI_HIDE2), ID_HOTKEY_SHOW_HIDE_WINDOW2, 0, 0, MAKEWORD('H', HOTKEYF_CONTROL|HOTKEYF_ALT), IDC_HK_HIDE2, IDC_CHECK_HIDE2, OnHideWin, IDS_HIDE_SHOW_WINDOW }, + { MAKELONG(KT_HOTKEY, KI_HIDE3), ID_HOTKEY_SHOW_HIDE_WINDOW3, 0, 0, MAKEWORD('H', HOTKEYF_CONTROL|HOTKEYF_SHIFT), IDC_HK_HIDE3, IDC_CHECK_HIDE3, OnHideWin, IDS_HIDE_SHOW_WINDOW }, + { MAKELONG(KT_HOTKEY, KI_HIDE4), ID_HOTKEY_SHOW_HIDE_WINDOW4, 0, 0, MAKEWORD('Q', HOTKEYF_ALT), IDC_HK_HIDE4, IDC_CHECK_HIDE4, OnHideWin, IDS_HIDE_SHOW_WINDOW }, { MAKELONG(KT_SHORTCUTKEY, KI_BORDER), 0, 0, 0, MAKEWORD(VK_F12, 0), IDC_HK_BORDER, IDC_CHECK_BORDER, OnHideBorder, IDS_HIDE_SHOW_BORDER }, { MAKELONG(KT_SHORTCUTKEY, KI_FULLSCREEN), 0, 0, 0, MAKEWORD(VK_F11, 0), IDC_HK_FULLSCREEN, IDC_CHECK_FULLSCREEN, OnFullScreen, IDS_FULLSRCEEN }, { MAKELONG(KT_SHORTCUTKEY, KI_TOP), 0, 0, 0, MAKEWORD('T', HOTKEYF_CONTROL), IDC_HK_TOP, IDC_CHECK_TOP, OnTopmost, IDS_TOPMOST }, @@ -50,7 +54,8 @@ keydata_t g_Keysets[KI_MAXCOUNT] = { MAKELONG(KT_SHORTCUTKEY, KI_CHAPTERUP), 0, 0, 0, MAKEWORD(VK_LEFT, HOTKEYF_EXT|HOTKEYF_CONTROL), IDC_HK_CHAPTERUP, IDC_CHECK_CHAPTERUP, OnChapterUp, IDS_CHAPTER_UP }, { MAKELONG(KT_SHORTCUTKEY, KI_CHAPTERDOWN), 0, 0, 0, MAKEWORD(VK_RIGHT, HOTKEYF_EXT|HOTKEYF_CONTROL), IDC_HK_CHAPTERDOWN, IDC_CHECK_CHAPTERDOWN, OnChapterDown, IDS_CHAPTER_DOWN }, { MAKELONG(KT_SHORTCUTKEY, KI_FONTZOOMIN), 0, 0, 0, MAKEWORD(VK_OEM_PLUS, HOTKEYF_CONTROL), IDC_HK_FONTZOOMIN, IDC_CHECK_FONTZOOMIN, OnFontZoomIn, IDS_FONT_ZOOMIN }, - { MAKELONG(KT_SHORTCUTKEY, KI_FONTZOOMOUT), 0, 0, 0, MAKEWORD(VK_OEM_MINUS, HOTKEYF_CONTROL), IDC_HK_FONTZOOMOUT, IDC_CHECK_FONTZOOMOUT, OnFontZoomOut, IDS_FONT_ZOOMOUT } + { MAKELONG(KT_SHORTCUTKEY, KI_FONTZOOMOUT), 0, 0, 0, MAKEWORD(VK_OEM_MINUS, HOTKEYF_CONTROL), IDC_HK_FONTZOOMOUT, IDC_CHECK_FONTZOOMOUT, OnFontZoomOut, IDS_FONT_ZOOMOUT }, + { MAKELONG(KT_SHORTCUTKEY, KI_TRANS), 0, 0, 0, MAKEWORD(VK_F9, 0), IDC_HK_TRANS, IDC_CHECK_TRANS, OnTransBG, IDS_TRANS_TOGGLE } }; @@ -65,31 +70,69 @@ void KS_Init(HWND hWnd, keyset_t *keyset) SetGlobalKey(hWnd); } +// The config slot of an entry is the keyid stored in key (HIWORD), NOT its array +// index in g_Keysets. This decouples the table layout from the persisted config: +// a new key can be inserted anywhere in g_Keysets without moving the slot of any +// existing key, so configs written by older versions keep their meaning +// (keyset[] is serialized positionally into JSON). +static int _keyset_slot(const keydata_t *kd) +{ + int kid = (int)HIWORD(kd->key); + + return (kid >= 0 && kid < MAX_KEYSET_COUNT) ? kid : -1; +} + +// Which keys are enabled out of the box. Everything else starts disabled and +// is opt-in from the key settings dialog. +static BOOL _default_enable(int kid) +{ + switch (kid) + { + case KI_HIDE: // boss key 1 (Alt+H) + case KI_BORDER: // hide/show border (F12) + case KI_PAGEUP: // previous page (Left) + case KI_PAGEDOWN: // next page (Right) + case KI_LINEUP: // line up (Up) + case KI_LINEDOWN: // line down (Down) + return TRUE; + default: + return FALSE; + } +} + void KS_UpdateKeyset(keyset_t *keyset) { - int i; + int i, kid; if (!keyset) return; - for (i=KI_HIDE; iexstyle & WS_EX_TOPMOST) == WS_EX_TOPMOST; _WndInfo.status = (_header->style & WS_MINIMIZEBOX) == 0 ? ds_fullscreen : (((_header->style & WS_CAPTION) == 0) ? ds_borderless : ds_normal); + // Borderless mode removes the menu bar, so the "hide/show border" key is the only + // way back to it. Never run without that escape hatch (e.g. after hand-editing the + // config), otherwise the menu would be unreachable for good. + if (_WndInfo.status == ds_borderless && _header->keyset[KI_BORDER].is_disable) + _header->keyset[KI_BORDER].is_disable = 0; + _WndInfo.hMenu = GetMenu(hWnd); // create status bar _WndInfo.hStatusBar = CreateStatusWindow(WS_CHILD | WS_VISIBLE, _T("Please open a text."), hWnd, IDC_STATUSBAR); @@ -2191,6 +2197,13 @@ VOID OnDraw(HWND hWnd) { alpha = _header->alpha < MIN_ALPHA_VALUE ? MIN_ALPHA_VALUE : _header->alpha; } + else if (_header->transparent_bg) + { + // Transparent background: alpha 0 makes the desktop show through and + // UpdateLayeredWindow turns those pixels click-through. The text is + // composited separately with _textAlpha, so it stays opaque. + alpha = 0; + } // load bg image image = LoadBGImage(w, h, alpha); @@ -2505,6 +2518,15 @@ LRESULT OnTopmost(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) return 0; } +// Toggle the transparent-background flag. The visual effect only shows in +// borderless mode (F12), matching the display-settings checkbox behaviour. +LRESULT OnTransBG(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + _header->transparent_bg = !_header->transparent_bg; + Invalidate(hWnd, TRUE, FALSE); + return 0; +} + LRESULT OnOpenFile(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { if (IsWindow(_hFindDlg)) diff --git a/Reader/Reader.h b/Reader/Reader.h index 7bbcb74..f1f2be7 100644 --- a/Reader/Reader.h +++ b/Reader/Reader.h @@ -78,6 +78,7 @@ LRESULT OnSize(HWND, UINT, WPARAM, LPARAM); // WM_KEYWORD begin LRESULT OnHideWin(HWND, UINT, WPARAM, LPARAM); LRESULT OnHideBorder(HWND, UINT, WPARAM, LPARAM); +LRESULT OnTransBG(HWND, UINT, WPARAM, LPARAM); LRESULT OnFullScreen(HWND, UINT, WPARAM, LPARAM); LRESULT OnTopmost(HWND, UINT, WPARAM, LPARAM); LRESULT OnOpenFile(HWND, UINT, WPARAM, LPARAM); diff --git a/Reader/Reader_zh-cn.rc b/Reader/Reader_zh-cn.rc index 2b3ec6d..327591a 100644 Binary files a/Reader/Reader_zh-cn.rc and b/Reader/Reader_zh-cn.rc differ diff --git a/Reader/resource.h b/Reader/resource.h index d364e4e..ad772b2 100644 Binary files a/Reader/resource.h and b/Reader/resource.h differ diff --git a/Reader/types.h b/Reader/types.h index 7faf5cb..b274242 100644 --- a/Reader/types.h +++ b/Reader/types.h @@ -63,6 +63,12 @@ #define ID_HOTKEY_SHOW_HIDE_WINDOW 100 + +#define ID_HOTKEY_SHOW_HIDE_WINDOW2 200 // RegisterHotKey id: boss key 2 +#define ID_HOTKEY_SHOW_HIDE_WINDOW3 201 // RegisterHotKey id: boss key 3 +#define ID_HOTKEY_SHOW_HIDE_WINDOW4 202 // RegisterHotKey id: boss key 4 +#define MAX_BOSS_KEY 4 // boss key count + #define IDT_TIMER_PAGE 102 #ifdef ENABLE_NETWORK #define IDT_TIMER_UPGRADE 103 @@ -203,6 +209,7 @@ typedef struct header_t int use_same_font; u32 bg_color; BYTE alpha; + int transparent_bg; // 1 = background fully transparent, text stays opaque int char_gap; int line_gap; int paragraph_gap;