diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-08-06 12:09:11 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-08-06 12:09:11 +0300 |
commit | 4c176d97043e33bb9d2db264f0ecb4912e32d553 (patch) | |
tree | a4f77b9e543e6c433abfce1793dbf78bc265a977 /src/ui/inputwidget.c | |
parent | 018bbd0f90809108c04019d7f661f157250edc1c (diff) |
InputWidget: Return key, input focus behavior
In the long-form text entry mode, don't use the user's configured Return key behavior, since that's meant for shorter input fields.
Input fields no longer lose focus when the window loses input focus, but the cursor will stop blinking. This makes it easier to resume typing after switching window focus, and also on macOS the symbol picker is easier to use.
Diffstat (limited to 'src/ui/inputwidget.c')
-rw-r--r-- | src/ui/inputwidget.c | 75 |
1 files changed, 54 insertions, 21 deletions
diff --git a/src/ui/inputwidget.c b/src/ui/inputwidget.c index d31130f5..f1f368b6 100644 --- a/src/ui/inputwidget.c +++ b/src/ui/inputwidget.c | |||
@@ -190,6 +190,7 @@ enum iInputWidgetFlag { | |||
190 | enterKeyEnabled_InputWidgetFlag = iBit(10), | 190 | enterKeyEnabled_InputWidgetFlag = iBit(10), |
191 | lineBreaksEnabled_InputWidgetFlag= iBit(11), | 191 | lineBreaksEnabled_InputWidgetFlag= iBit(11), |
192 | needBackup_InputWidgetFlag = iBit(12), | 192 | needBackup_InputWidgetFlag = iBit(12), |
193 | useReturnKeyBehavior_InputWidgetFlag = iBit(13), | ||
193 | }; | 194 | }; |
194 | 195 | ||
195 | /*----------------------------------------------------------------------------------------------*/ | 196 | /*----------------------------------------------------------------------------------------------*/ |
@@ -566,6 +567,28 @@ static void updateAllLinesAndResizeHeight_InputWidget_(iInputWidget *d) { | |||
566 | } | 567 | } |
567 | } | 568 | } |
568 | 569 | ||
570 | static uint32_t cursorTimer_(uint32_t interval, void *w) { | ||
571 | iInputWidget *d = w; | ||
572 | if (d->cursorVis > 1) { | ||
573 | d->cursorVis--; | ||
574 | } | ||
575 | else { | ||
576 | d->cursorVis ^= 1; | ||
577 | } | ||
578 | refresh_Widget(w); | ||
579 | return interval; | ||
580 | } | ||
581 | |||
582 | static void startOrStopCursorTimer_InputWidget_(iInputWidget *d, iBool doStart) { | ||
583 | if (doStart && !d->timer) { | ||
584 | d->timer = SDL_AddTimer(refreshInterval_InputWidget_, cursorTimer_, d); | ||
585 | } | ||
586 | else if (!doStart && d->timer) { | ||
587 | SDL_RemoveTimer(d->timer); | ||
588 | d->timer = 0; | ||
589 | } | ||
590 | } | ||
591 | |||
569 | void init_InputWidget(iInputWidget *d, size_t maxLen) { | 592 | void init_InputWidget(iInputWidget *d, size_t maxLen) { |
570 | iWidget *w = &d->widget; | 593 | iWidget *w = &d->widget; |
571 | init_Widget(w); | 594 | init_Widget(w); |
@@ -588,7 +611,7 @@ void init_InputWidget(iInputWidget *d, size_t maxLen) { | |||
588 | d->prevCursor = zero_I2(); | 611 | d->prevCursor = zero_I2(); |
589 | d->lastUpdateWidth = 0; | 612 | d->lastUpdateWidth = 0; |
590 | d->inFlags = eatEscape_InputWidgetFlag | enterKeyEnabled_InputWidgetFlag | | 613 | d->inFlags = eatEscape_InputWidgetFlag | enterKeyEnabled_InputWidgetFlag | |
591 | lineBreaksEnabled_InputWidgetFlag; | 614 | lineBreaksEnabled_InputWidgetFlag | useReturnKeyBehavior_InputWidgetFlag; |
592 | // if (deviceType_App() != desktop_AppDeviceType) { | 615 | // if (deviceType_App() != desktop_AppDeviceType) { |
593 | // d->inFlags |= enterKeyInsertsLineFeed_InputWidgetFlag; | 616 | // d->inFlags |= enterKeyInsertsLineFeed_InputWidgetFlag; |
594 | // } | 617 | // } |
@@ -627,9 +650,7 @@ void deinit_InputWidget(iInputWidget *d) { | |||
627 | delete_TextBuf(d->buffered); | 650 | delete_TextBuf(d->buffered); |
628 | clearUndo_InputWidget_(d); | 651 | clearUndo_InputWidget_(d); |
629 | deinit_Array(&d->undoStack); | 652 | deinit_Array(&d->undoStack); |
630 | if (d->timer) { | 653 | startOrStopCursorTimer_InputWidget_(d, iFalse); |
631 | SDL_RemoveTimer(d->timer); | ||
632 | } | ||
633 | deinit_String(&d->srcHint); | 654 | deinit_String(&d->srcHint); |
634 | deinit_String(&d->hint); | 655 | deinit_String(&d->hint); |
635 | deinit_String(&d->oldText); | 656 | deinit_String(&d->oldText); |
@@ -740,6 +761,10 @@ void setEnterKeyEnabled_InputWidget(iInputWidget *d, iBool enterKeyEnabled) { | |||
740 | iChangeFlags(d->inFlags, enterKeyEnabled_InputWidgetFlag, enterKeyEnabled); | 761 | iChangeFlags(d->inFlags, enterKeyEnabled_InputWidgetFlag, enterKeyEnabled); |
741 | } | 762 | } |
742 | 763 | ||
764 | void setUseReturnKeyBehavior_InputWidget(iInputWidget *d, iBool useReturnKeyBehavior) { | ||
765 | iChangeFlags(d->inFlags, useReturnKeyBehavior_InputWidgetFlag, useReturnKeyBehavior); | ||
766 | } | ||
767 | |||
743 | void setHint_InputWidget(iInputWidget *d, const char *hintText) { | 768 | void setHint_InputWidget(iInputWidget *d, const char *hintText) { |
744 | /* Keep original for retranslations. */ | 769 | /* Keep original for retranslations. */ |
745 | setCStr_String(&d->srcHint, hintText); | 770 | setCStr_String(&d->srcHint, hintText); |
@@ -866,18 +891,6 @@ void setTextCStr_InputWidget(iInputWidget *d, const char *cstr) { | |||
866 | delete_String(str); | 891 | delete_String(str); |
867 | } | 892 | } |
868 | 893 | ||
869 | static uint32_t cursorTimer_(uint32_t interval, void *w) { | ||
870 | iInputWidget *d = w; | ||
871 | if (d->cursorVis > 1) { | ||
872 | d->cursorVis--; | ||
873 | } | ||
874 | else { | ||
875 | d->cursorVis ^= 1; | ||
876 | } | ||
877 | refresh_Widget(w); | ||
878 | return interval; | ||
879 | } | ||
880 | |||
881 | static size_t cursorToIndex_InputWidget_(const iInputWidget *d, iInt2 pos) { | 894 | static size_t cursorToIndex_InputWidget_(const iInputWidget *d, iInt2 pos) { |
882 | if (pos.y < 0) { | 895 | if (pos.y < 0) { |
883 | return 0; | 896 | return 0; |
@@ -930,7 +943,7 @@ void begin_InputWidget(iInputWidget *d) { | |||
930 | setFlags_Widget(w, selected_WidgetFlag, iTrue); | 943 | setFlags_Widget(w, selected_WidgetFlag, iTrue); |
931 | showCursor_InputWidget_(d); | 944 | showCursor_InputWidget_(d); |
932 | refresh_Widget(w); | 945 | refresh_Widget(w); |
933 | d->timer = SDL_AddTimer(refreshInterval_InputWidget_, cursorTimer_, d); | 946 | startOrStopCursorTimer_InputWidget_(d, iTrue); |
934 | d->inFlags &= ~enterPressed_InputWidgetFlag; | 947 | d->inFlags &= ~enterPressed_InputWidgetFlag; |
935 | if (d->inFlags & selectAllOnFocus_InputWidgetFlag) { | 948 | if (d->inFlags & selectAllOnFocus_InputWidgetFlag) { |
936 | d->mark = (iRanges){ 0, lastLine_InputWidget_(d)->range.end }; | 949 | d->mark = (iRanges){ 0, lastLine_InputWidget_(d)->range.end }; |
@@ -955,8 +968,7 @@ void end_InputWidget(iInputWidget *d, iBool accept) { | |||
955 | splitToLines_(&d->oldText, &d->lines); | 968 | splitToLines_(&d->oldText, &d->lines); |
956 | } | 969 | } |
957 | d->inFlags |= needUpdateBuffer_InputWidgetFlag; | 970 | d->inFlags |= needUpdateBuffer_InputWidgetFlag; |
958 | SDL_RemoveTimer(d->timer); | 971 | startOrStopCursorTimer_InputWidget_(d, iFalse); |
959 | d->timer = 0; | ||
960 | SDL_StopTextInput(); | 972 | SDL_StopTextInput(); |
961 | setFlags_Widget(w, selected_WidgetFlag | keepOnTop_WidgetFlag, iFalse); | 973 | setFlags_Widget(w, selected_WidgetFlag | keepOnTop_WidgetFlag, iFalse); |
962 | const char *id = cstr_String(id_Widget(as_Widget(d))); | 974 | const char *id = cstr_String(id_Widget(as_Widget(d))); |
@@ -1383,6 +1395,20 @@ static iBool isArrowUpDownConsumed_InputWidget_(const iInputWidget *d) { | |||
1383 | return d->maxWrapLines > 1; | 1395 | return d->maxWrapLines > 1; |
1384 | } | 1396 | } |
1385 | 1397 | ||
1398 | static iBool checkLineBreakMods_InputWidget_(const iInputWidget *d, int mods) { | ||
1399 | if (d->inFlags & useReturnKeyBehavior_InputWidgetFlag) { | ||
1400 | return mods == lineBreakKeyMod_ReturnKeyBehavior(prefs_App()->returnKey); | ||
1401 | } | ||
1402 | return mods == 0; | ||
1403 | } | ||
1404 | |||
1405 | static iBool checkAcceptMods_InputWidget_(const iInputWidget *d, int mods) { | ||
1406 | if (d->inFlags & useReturnKeyBehavior_InputWidgetFlag) { | ||
1407 | return mods == acceptKeyMod_ReturnKeyBehavior(prefs_App()->returnKey); | ||
1408 | } | ||
1409 | return mods == 0; | ||
1410 | } | ||
1411 | |||
1386 | static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) { | 1412 | static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) { |
1387 | iWidget *w = as_Widget(d); | 1413 | iWidget *w = as_Widget(d); |
1388 | /* Resize according to width immediately. */ | 1414 | /* Resize according to width immediately. */ |
@@ -1401,6 +1427,13 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) { | |||
1401 | begin_InputWidget(d); | 1427 | begin_InputWidget(d); |
1402 | return iFalse; | 1428 | return iFalse; |
1403 | } | 1429 | } |
1430 | else if (isEditing_InputWidget_(d) && (isCommand_UserEvent(ev, "window.focus.lost") || | ||
1431 | isCommand_UserEvent(ev, "window.focus.gained"))) { | ||
1432 | startOrStopCursorTimer_InputWidget_(d, isCommand_UserEvent(ev, "window.focus.gained")); | ||
1433 | d->cursorVis = 1; | ||
1434 | refresh_Widget(d); | ||
1435 | return iFalse; | ||
1436 | } | ||
1404 | else if (isCommand_UserEvent(ev, "keyroot.changed")) { | 1437 | else if (isCommand_UserEvent(ev, "keyroot.changed")) { |
1405 | d->inFlags |= needUpdateBuffer_InputWidgetFlag; | 1438 | d->inFlags |= needUpdateBuffer_InputWidgetFlag; |
1406 | } | 1439 | } |
@@ -1617,7 +1650,7 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) { | |||
1617 | if (~d->inFlags & isSensitive_InputWidgetFlag && | 1650 | if (~d->inFlags & isSensitive_InputWidgetFlag && |
1618 | ~d->inFlags & isUrl_InputWidgetFlag && | 1651 | ~d->inFlags & isUrl_InputWidgetFlag && |
1619 | d->inFlags & lineBreaksEnabled_InputWidgetFlag && d->maxLen == 0) { | 1652 | d->inFlags & lineBreaksEnabled_InputWidgetFlag && d->maxLen == 0) { |
1620 | if (mods == lineBreakKeyMod_ReturnKeyBehavior(prefs_App()->returnKey)) { | 1653 | if (checkLineBreakMods_InputWidget_(d, mods)) { |
1621 | pushUndo_InputWidget_(d); | 1654 | pushUndo_InputWidget_(d); |
1622 | deleteMarked_InputWidget_(d); | 1655 | deleteMarked_InputWidget_(d); |
1623 | insertChar_InputWidget_(d, '\n'); | 1656 | insertChar_InputWidget_(d, '\n'); |
@@ -1626,7 +1659,7 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) { | |||
1626 | } | 1659 | } |
1627 | } | 1660 | } |
1628 | if (d->inFlags & enterKeyEnabled_InputWidgetFlag && | 1661 | if (d->inFlags & enterKeyEnabled_InputWidgetFlag && |
1629 | (mods == acceptKeyMod_ReturnKeyBehavior(prefs_App()->returnKey) || | 1662 | (checkAcceptMods_InputWidget_(d, mods) || |
1630 | (~d->inFlags & lineBreaksEnabled_InputWidgetFlag))) { | 1663 | (~d->inFlags & lineBreaksEnabled_InputWidgetFlag))) { |
1631 | d->inFlags |= enterPressed_InputWidgetFlag; | 1664 | d->inFlags |= enterPressed_InputWidgetFlag; |
1632 | setFocus_Widget(NULL); | 1665 | setFocus_Widget(NULL); |