diff --git a/CMakeLists.txt b/CMakeLists.txt

index 20def6a7..7d73956d 100644

--- a/CMakeLists.txt

+++ b/CMakeLists.txt

@@ -135,6 +135,7 @@ set (SOURCES

 src/ui/listwidget.h

 src/ui/lookupwidget.c

 src/ui/lookupwidget.h

+ src/ui/keys.c

 src/ui/keys.h

 src/ui/metrics.c

 src/ui/metrics.h

diff --git a/src/app.c b/src/app.c

index e4c31eaf..10f5f0d2 100644

--- a/src/app.c

+++ b/src/app.c

@@ -32,6 +32,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

#include "ui/command.h"

#include "ui/documentwidget.h"

#include "ui/inputwidget.h"

+#include "ui/keys.h"

#include "ui/labelwidget.h"

#include "ui/sidebarwidget.h"

#include "ui/text.h"

@@ -357,9 +358,11 @@ static void init_App_(iApp *d, int argc, char **argv) {

#if defined (iPlatformApple)

 setupApplication_MacOS();

#endif

+ init_Keys();

 loadPrefs_App_(d);

+ load_Keys(dataDir_App_);

 load_Visited(d->visited, dataDir_App_);

- load_Bookmarks(d->bookmarks, dataDir_App_);

+ load_Bookmarks(d->bookmarks, dataDir_App_); 

 if (isFirstRun) {

     /* Create the default bookmarks for a quick start. */

     add_Bookmarks(d->bookmarks,

@@ -426,6 +429,7 @@ static void init_App_(iApp *d, int argc, char **argv) {



static void deinit_App(iApp *d) {

 saveState_App_(d);

+ save_Keys(dataDir_App_);

 savePrefs_App_(d);

 deinit_Prefs(&d->prefs);

 save_Bookmarks(d->bookmarks, dataDir_App_);

@@ -501,6 +505,10 @@ void processEvents_App(enum iAppEventMode eventMode) {

         }

         default: {

             iBool wasUsed = processEvent_Window(d->window, &ev);

+ if (!wasUsed) {

+ /* There may be a key bindings for this. */

+ wasUsed = processEvent_Keys(&ev);

+ }

             if (ev.type == SDL_USEREVENT && ev.user.code == command_UserEventCode) {

#if defined (iPlatformApple) && !defined (iPlatformIOS)

                 handleCommand_MacOS(command_UserEvent(&ev));

diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c

index 5c6780d1..a2bea17b 100644

--- a/src/ui/documentwidget.c

+++ b/src/ui/documentwidget.c

@@ -1536,7 +1536,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)

     updateVisible_DocumentWidget_(d);

     return iTrue;

 }

- else if (equalWidget_Command(cmd, w, "scroll.page")) {

+ else if (equal_Command(cmd, "scroll.page") && document_App() == d) {

     if (argLabel_Command(cmd, "repeat")) {

         /* TODO: Adjust scroll animation to be linear during repeated scroll? */

     }

@@ -1547,6 +1547,40 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)

                                  smoothDuration_DocumentWidget_);

     return iTrue;

 }

+ else if (equal_Command(cmd, "scroll.top") && document_App() == d) {

+ init_Anim(&d->scrollY, 0);

+ invalidate_VisBuf(d->visBuf);

+ scroll_DocumentWidget_(d, 0);

+ updateVisible_DocumentWidget_(d);

+ refresh_Widget(w);

+ return iTrue;

+ }

+ else if (equal_Command(cmd, "scroll.bottom") && document_App() == d) {

+ init_Anim(&d->scrollY, scrollMax_DocumentWidget_(d));

+ invalidate_VisBuf(d->visBuf);

+ scroll_DocumentWidget_(d, 0);

+ updateVisible_DocumentWidget_(d);

+ refresh_Widget(w);

+ return iTrue;

+ }

+ else if (equal_Command(cmd, "scroll.step") && document_App() == d) {

+ smoothScroll_DocumentWidget_(d,

+ 3 * lineHeight_Text(paragraph_FontId) * arg_Command(cmd),

+ smoothDuration_DocumentWidget_);

+ return iTrue;

+ }

+#if 0

+ case SDLK_PAGEUP:

+ case SDLK_PAGEDOWN:

+ case SDLK_SPACE:

+ postCommand_Widget(

+ w,

+ "scroll.page arg:%d repeat:%d",

+ (key == SDLK_SPACE && mods & KMOD_SHIFT) || key == SDLK_PAGEUP ? -1 : +1,

+ ev->key.repeat != 0);

+ return iTrue;

+ }

+#endif

 else if (equal_Command(cmd, "document.goto") && document_App() == d) {

     const iRangecc heading = range_Command(cmd, "heading");

     if (heading.start) {

@@ -1790,45 +1824,6 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e

                 refresh_Widget(w);

             }

             break;

- case SDLK_HOME:

- init_Anim(&d->scrollY, 0);

- invalidate_VisBuf(d->visBuf);

- scroll_DocumentWidget_(d, 0);

- updateVisible_DocumentWidget_(d);

- refresh_Widget(w);

- return iTrue;

- case SDLK_END:

- init_Anim(&d->scrollY, scrollMax_DocumentWidget_(d));

- invalidate_VisBuf(d->visBuf);

- scroll_DocumentWidget_(d, 0);

- updateVisible_DocumentWidget_(d);

- refresh_Widget(w);

- return iTrue;

- case SDLK_UP:

- case SDLK_DOWN:

- if (mods == 0) {

- if (ev->key.repeat) {

-// if (!d->smoothContinue) {

-// d->smoothContinue = iTrue;

-// }

-// else return iTrue;

- }

- smoothScroll_DocumentWidget_(d,

- 3 * lineHeight_Text(paragraph_FontId) *

- (key == SDLK_UP ? -1 : 1),

- /*gap_Text * */smoothDuration_DocumentWidget_);

- return iTrue;

- }

- break;

- case SDLK_PAGEUP:

- case SDLK_PAGEDOWN:

- case SDLK_SPACE:

- postCommand_Widget(

- w,

- "scroll.page arg:%d repeat:%d",

- (key == SDLK_SPACE && mods & KMOD_SHIFT) || key == SDLK_PAGEUP ? -1 : +1,

- ev->key.repeat != 0);

- return iTrue;

#if 1

         case SDLK_KP_1:

         case '`': {

diff --git a/src/ui/keys.c b/src/ui/keys.c

new file mode 100644

index 00000000..d46d20bf

--- /dev/null

+++ b/src/ui/keys.c

@@ -0,0 +1,154 @@

+/* Copyright 2020 Jaakko Keränen jaakko.keranen@iki.fi

+

+Redistribution and use in source and binary forms, with or without

+modification, are permitted provided that the following conditions are met:

+

+1. Redistributions of source code must retain the above copyright notice, this

+ list of conditions and the following disclaimer.

+2. Redistributions in binary form must reproduce the above copyright notice,

+ this list of conditions and the following disclaimer in the documentation

+ and/or other materials provided with the distribution.

+

+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND

+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED

+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE

+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR

+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES

+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;

+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON

+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS

+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

+

+#include "keys.h"

+#include "util.h"

+#include "app.h"

+

+#include <the_Foundation/sortedarray.h>

+

+iDeclareType(Keys)

+iDeclareType(Binding)

+

+struct Impl_Binding {

+ int key;

+ int mods;

+ iString command;

+ iString label;

+};

+

+static int cmp_Binding_(const void *a, const void *b) {

+ const iBinding *d = a, *other = b;

+ const int cmp = iCmp(d->key, other->key);

+ if (cmp == 0) {

+ return iCmp(d->mods, other->mods);

+ }

+ return cmp;

+}

+

+struct Impl_Keys {

+ iSortedArray bindings;

+};

+

+static iKeys keys_;

+

+static void clear_Keys_(iKeys *d) {

+ iForEach(Array, i, &d->bindings.values) {

+ iBinding *bind = i.value;

+ deinit_String(&bind->command);

+ deinit_String(&bind->label);

+ }

+}

+

+static void bindDefaults_(void) {

+ bind_Keys("scroll.top", SDLK_HOME, 0);

+ bind_Keys("scroll.bottom", SDLK_END, 0);

+ bind_Keys("scroll.step arg:-1", SDLK_UP, 0);

+ bind_Keys("scroll.step arg:1", SDLK_DOWN, 0);

+ bind_Keys("scroll.page arg:-1", SDLK_PAGEUP, 0);

+ bind_Keys("scroll.page arg:-1", SDLK_SPACE, KMOD_SHIFT);

+ bind_Keys("scroll.page arg:1", SDLK_PAGEDOWN, 0);

+ bind_Keys("scroll.page arg:1", SDLK_SPACE, 0);

+}

+

+static iBinding *find_Keys_(iKeys *d, int key, int mods) {

+ const iBinding bind = { .key = key, .mods = mods };

+ size_t pos;

+ if (locate_SortedArray(&d->bindings, &bind, &pos)) {

+ return at_SortedArray(&d->bindings, pos);

+ }

+ return NULL;

+}

+

+static iBinding *findCommand_Keys_(iKeys *d, const char *command) {

+ /* Note: O(n) */

+ iForEach(Array, i, &d->bindings.values) {

+ iBinding *bind = i.value;

+ if (!cmp_String(&bind->command, command)) {

+ return bind;

+ }

+ }

+ return NULL;

+}

+

+/----------------------------------------------------------------------------------------------/

+

+void init_Keys(void) {

+ iKeys *d = &keys_;

+ init_SortedArray(&d->bindings, sizeof(iBinding), cmp_Binding_);

+ bindDefaults_();

+}

+

+void deinit_Keys(void) {

+ iKeys *d = &keys_;

+ clear_Keys_(d);

+ deinit_SortedArray(&d->bindings);

+}

+

+void load_Keys(const char *saveDir) {

+

+}

+

+void save_Keys(const char *saveDir) {

+

+}

+

+void bind_Keys(const char *command, int key, int mods) {

+ iKeys *d = &keys_;

+ iBinding *bind = find_Keys_(d, key, mods);

+ if (bind) {

+ setCStr_String(&bind->command, command);

+ }

+ else {

+ iBinding bind;

+ bind.key = key;

+ bind.mods = mods;

+ initCStr_String(&bind.command, command);

+ init_String(&bind.label);

+ insert_SortedArray(&d->bindings, &bind);

+ }

+}

+

+void setLabel_Keys(const char *command, const char *label) {

+ iBinding *bind = findCommand_Keys_(&keys_, command);

+ if (bind) {

+ setCStr_String(&bind->label, label);

+ }

+}

+

+//const iString *label_Keys(const char *command) {

+

+//}

+

+//const char *shortcutLabel_Keys(const char *command) {}

+

+iBool processEvent_Keys(const SDL_Event *ev) {

+ iKeys *d = &keys_;

+ if (ev->type == SDL_KEYDOWN) {

+ const iBinding *bind = find_Keys_(d, ev->key.keysym.sym, keyMods_Sym(ev->key.keysym.mod));

+ if (bind) {

+ postCommandString_App(&bind->command);

+ return iTrue;

+ }

+ }

+ return iFalse;

+}

diff --git a/src/ui/keys.h b/src/ui/keys.h

index a9b13df3..157ddea5 100644

--- a/src/ui/keys.h

+++ b/src/ui/keys.h

@@ -22,7 +22,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */



#pragma once



-#include <the_Foundation/defs.h>

+#include <the_Foundation/string.h>

+#include <SDL_events.h>



#if defined (iPlatformApple)

define reload_KeyShortcut SDLK_r, KMOD_PRIMARY

@@ -41,3 +42,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

define byWord_KeyModifier KMOD_CTRL

define byLine_KeyModifier 0

#endif

+

+void init_Keys (void);

+void deinit_Keys (void);

+

+void load_Keys (const char *saveDir);

+void save_Keys (const char *saveDir);

+

+void bind_Keys (const char *command, int key, int mods);

+void setLabel_Keys (const char *command, const char *label);

+

+//const iString * label_Keys (const char *command);

+//const char * shortcutLabel_Keys (const char *command);

+

+iBool processEvent_Keys (const SDL_Event *);

Proxy Information
Original URL
gemini://git.skyjake.fi/lagrange/work%2Fv1.10/pcdiff/b1e9b313f6810afbadde0f8079326ecf04c89817
Status Code
Success (20)
Meta
text/plain
Capsule Response Time
74.12578 milliseconds
Gemini-to-HTML Time
6.863278 milliseconds

This content has been proxied by September (ba2dc).