diff options
| author | Greg Ercolano <erco@seriss.com> | 2010-12-20 06:42:38 +0000 |
|---|---|---|
| committer | Greg Ercolano <erco@seriss.com> | 2010-12-20 06:42:38 +0000 |
| commit | df6de286e7421062372c468b6dca426c254ef379 (patch) | |
| tree | cd2082dd898c5e3c507aff71dfd6bbc6bf559610 | |
| parent | 31f6505cb313c4448ccffef08e2d281ebe7c95d0 (diff) | |
Removed emacs shortcuts from Fl_Input,
conformed Fl_Input keystrokes to native environment (much research went into this, citations included).
Tested editing functions on all three platforms. Doxygen docs updated.
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@8067 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
| -rw-r--r-- | FL/Fl_Input.H | 258 | ||||
| -rw-r--r-- | src/Fl_Input.cxx | 676 |
2 files changed, 596 insertions, 338 deletions
diff --git a/FL/Fl_Input.H b/FL/Fl_Input.H index 10b0882df..9e5550cbb 100644 --- a/FL/Fl_Input.H +++ b/FL/Fl_Input.H @@ -44,57 +44,225 @@ Characters can be input using the keyboard or the character palette/map. Character composition is done using dead keys and/or a compose key as defined by the operating system. -</P> - - <CENTER><TABLE border=1 WIDTH=90% summary="Fl_Input keyboard and mouse bindings."> - - <TR><TD WIDTH=200><B>Mouse button 1</B></TD><TD>Moves the cursor to - this point. Drag selects characters. Double click selects words. - Triple click selects all text. Shift+click extends the selection. - When you select text it is automatically copied to the clipboard. - </TD></TR> - - <TR><TD><B>Mouse button 2</B></TD><TD>Insert the clipboard at - the point clicked. You can also select a region and replace it with the - clipboard by selecting the region with mouse button 2. - </TD></TR> - - <TR><TD><B>Mouse button 3</B></TD><TD>Currently acts like button 1.</TD></TR> - - <TR><TD><B>Backspace</B></TD><TD>Deletes one character to the left, or - deletes the selected region.</TD></TR> - <TR><TD><B>Enter</B></TD><TD>May cause the callback, see when().</TD></TR> - <TR><TD><B>^A or Home</B></TD><TD>Go to start of line.</TD></TR> - <TR><TD><B>^B or Left</B></TD><TD>Move left</TD></TR> - <TR><TD><B>^C</B></TD><TD>Copy the selection to the clipboard</TD></TR> - <TR><TD><B>^D or Delete</B></TD><TD>Deletes one character to the right - or deletes the selected region.</TD></TR> - <TR><TD><B>^E or End</B></TD><TD>Go to the end of line.</TD></TR> - <TR><TD><B>^F or Right</B></TD><TD>Move right</TD></TR> - <TR><TD><B>^K</B></TD><TD>Delete to the end of line (next \\n character) - or deletes a single \\n character. These deletions are all concatenated - into the clipboard.</TD></TR> - <TR><TD><B>^N or Down</B></TD><TD>Move down (for Fl_Multiline_Input - only, otherwise it moves to the next input field).</TD></TR> - <TR><TD><B>^P or Up</B></TD><TD>Move up (for Fl_Multiline_Input only, - otherwise it moves to the previous input field).</TD></TR> - <TR><TD><B>^U</B></TD><TD>Delete everything.</TD></TR> - <TR><TD><B>^V or ^Y</B></TD><TD>Paste the clipboard</TD></TR> - <TR><TD><B>^X or ^W</B></TD><TD>Copy the region to the clipboard and - delete it.</TD></TR> - <TR><TD><B>^Z or ^_</B></TD><TD>Undo. This is a single-level undo - mechanism, but all adjacent deletions and insertions are concatenated - into a single "undo". Often this will undo a lot more than you - expected.</TD></TR> - <TR><TD><B>Shift+move</B></TD><TD>Move the cursor but also extend the - selection.</TD></TR> - </TABLE></CENTER> + <P> + <TABLE WIDTH=90% BORDER=1 SUMMARY="Fl_Input keyboard and mouse bindings."> + <CAPTION>Fl_Input keyboard and mouse bindings.</CAPTION> + <TR><TD NOWRAP="NOWRAP" WIDTH="1%"> + <B>Mouse button 1</B> + </TD><TD> + Moves the cursor to this point. + Drag selects characters. + Double click selects words. + Triple click selects all text. + Shift+click extends the selection. + When you select text it is automatically copied to the clipboard. + </TD></TR><TR><TD NOWRAP="NOWRAP"> + <B>Mouse button 2</B> + </TD><TD> + Insert the clipboard at the point clicked. + You can also select a region and replace it with the clipboard + by selecting the region with mouse button 2. + </TD></TR><TR><TD NOWRAP="NOWRAP"> + <B>Mouse button 3</B> + </TD><TD> + Currently acts like button 1. + </TD></TR><TR><TD NOWRAP="NOWRAP"> + <B>Backspace</B> + </TD><TD> + Deletes one character to the left, or deletes the selected region. + </TD></TR><TR><TD NOWRAP="NOWRAP"> + <B>Delete</B> + </TD><TD> + Deletes one character to the right, or deletes the selected region. + Combine with Shift for equivalent of ^X (copy+cut). + </TD></TR><TR><TD NOWRAP="NOWRAP"> + <B>Enter</b> + </TD><TD> + May cause the callback, see when(). + </TD></TR></TABLE> + + <P> + + <TABLE WIDTH="90%" BORDER="1" SUMMARY="Fl_Input platform specific keyboard bindings."> + <CAPTION>Fl_Input platform specific keyboard bindings.</CAPTION> + <TR> + <TD NOWRAP="NOWRAP" WIDTH="1%"><B> Windows/Linux </B></TD> + <TD NOWRAP="NOWRAP" WIDTH="1%"><B> Mac </B></TD> + <TD NOWRAP="NOWRAP" ><B> Function </B></TD> + + </TR><TR> + <TD NOWRAP="NOWRAP"><B> ^A </B></TD> + <TD NOWRAP="NOWRAP"><B> Command-A </B></TD> + <TD> + <B>Selects all text in the widget.</B> + + </TD></TR><TR> + <TD NOWRAP="NOWRAP"><B> ^C </B></TD> + <TD NOWRAP="NOWRAP"><B> Command-C </B></TD> + <TD> + <B>Copy the current selection to the clipboard.</B> + + </TD></TR><TR> + <TD NOWRAP="NOWRAP"><B> ^I </B></TD> + <TD NOWRAP="NOWRAP"><B> ^I </B></TD> + <TD> + <B>Insert a tab.</B> + + </TD></TR><TR> + <TD NOWRAP="NOWRAP"><B> ^J </B></TD> + <TD NOWRAP="NOWRAP"><B> ^J </B></TD> + <TD> + <B>Insert a Line Feed.</B> <BR> + (Similar to literal 'Enter' character) + + </TD></TR><TR> + <TD NOWRAP="NOWRAP"><B> ^L </B></TD> + <TD NOWRAP="NOWRAP"><B> ^L </B></TD> + <TD> + <B>Insert a Form Feed.</B> + + </TD></TR><TR> + <TD NOWRAP="NOWRAP"><B> ^M </B></TD> + <TD NOWRAP="NOWRAP"><B> ^M </B></TD> + <TD> + <B>Insert a Carriage Return.</B> + + </TD></TR><TR> + <TD NOWRAP="NOWRAP"><B> ^V,<BR>Shift-Insert </B></TD> + <TD NOWRAP="NOWRAP"><B> Command-V </B></TD> + <TD> + <B>Paste the clipboard.</B> <BR> + (Macs keyboards don't have "Insert" keys, + but if they did, Shift-Insert would work) + + </TD></TR><TR> + <TD NOWRAP="NOWRAP"><B> ^X,<BR>Shift-Delete </B></TD> + <TD NOWRAP="NOWRAP"><B> Command-X,<BR>Shift-Delete </B></TD> + <TD> + <B>Cut.</B> <BR> + Copy the selection to the clipboard and delete it. + (If there's no selection, Shift-Delete acts like Delete) + + </TD></TR><TR> + <TD NOWRAP="NOWRAP"><B> ^Z </B></TD> + <TD NOWRAP="NOWRAP"><B> Command-Z </B></TD> + <TD> + <B>Undo.</B> <BR> + This is a single-level undo mechanism, but all adjacent + deletions and insertions are concatenated into a single "undo". + Often this will undo a lot more than you expected. + + </TD></TR><TR> + <TD NOWRAP="NOWRAP"><B> Shift-^Z </B></TD> + <TD NOWRAP="NOWRAP"><B> Shift-Command-Z </B></TD> + <TD> + <B>Redo.</B> <BR> + Currently same behavior as ^Z. + Reserved for future multilevel undo/redo. + + </TD></TR><TR> + <TD NOWRAP="NOWRAP"><B> Arrow Keys </B></TD> + <TD NOWRAP="NOWRAP"><B> Arrow Keys </B></TD> + <TD> + <B>Standard cursor movement.</B> <BR> + Can be combined with Shift to extend selection. + + </TD></TR><TR> + <TD NOWRAP="NOWRAP"><B> Home </B></TD> + <TD NOWRAP="NOWRAP"><B> Command-Up,<BR>Command-Left </B></TD> + <TD> + <B>Move to start of line.</B> <BR> + Can be combined with Shift to extend selection. + + </TD></TR><TR> + <TD NOWRAP="NOWRAP"><B> End </B></TD> + <TD NOWRAP="NOWRAP"><B> Command-Down,<BR>Command-Right </B></TD> + <TD> + <B>Move to end of line.</B> <BR> + Can be combined with Shift to extend selection. + + </TD></TR><TR> + <TD NOWRAP="NOWRAP"><B>Ctrl-Home</B></TD> + <TD NOWRAP="NOWRAP"><B>Command-Up,<BR>Command-PgUp,<BR>Ctrl-Left</B></TD> + <TD> + <B>Move to top of document/field.</B> <BR> + In single line input, moves to start of line. + In multiline input, moves to start of top line. + Can be combined with Shift to extend selection. + + </TD></TR><TR> + <TD NOWRAP="NOWRAP"><B> Ctrl-End </B></TD> + <TD NOWRAP="NOWRAP"><B> Command-End,<BR>Command-PgDn,<BR>Ctrl-Right</B></TD> + <TD> + <B>Move to bottom of document/field.</B> <BR> + In single line input, moves to end of line. + In multiline input, moves to end of last line. + Can be combined with Shift to extend selection. + + </TD></TR><TR> + <TD NOWRAP="NOWRAP"><B> Ctrl-Left </B></TD> + <TD NOWRAP="NOWRAP"><B> Alt-Left </B></TD> + <TD> + <B>Word left.</B> <BR> + Can be combined with Shift to extend selection. + + </TD></TR><TR> + <TD NOWRAP="NOWRAP"><B> Ctrl-Right </B></TD> + <TD NOWRAP="NOWRAP"><B> Alt-Right </B></TD> + <TD> + <B>Word right.</B> <BR> + Can be combined with Shift to extend selection. + + </TD></TR><TR> + <TD NOWRAP="NOWRAP"><B> Ctrl-Backspace </B></TD> + <TD NOWRAP="NOWRAP"><B> Alt-Delete, Alt-Backspace </B></TD> + <TD> + <B>Delete word left.</B> + + </TD></TR><TR> + <TD NOWRAP="NOWRAP"><B> Ctrl-Delete </B></TD> + <TD NOWRAP="NOWRAP"><B> Alt-Delete </B></TD> + <TD> + <B>Delete word right.</B> + + </TD></TR></TABLE> */ class FL_EXPORT Fl_Input : public Fl_Input_ { int handle_key(); int shift_position(int p); int shift_up_down_position(int p); void handle_mouse(int keepmark=0); + + // Private keyboard functions + int kf_lines_up(int repeat_num); + int kf_lines_down(int repeat_num); + int kf_page_up(); + int kf_page_down(); + int kf_insert_toggle(); + int kf_delete_word_right(); + int kf_delete_word_left(); + int kf_delete_sol(); + int kf_delete_eol(); + int kf_delete_char_right(); + int kf_delete_char_left(); + int kf_move_sol(); + int kf_move_eol(); + int kf_clear_eol(); + int kf_move_char_left(); + int kf_move_char_right(); + int kf_move_word_left(); + int kf_move_word_right(); + int kf_move_up_and_sol(); + int kf_move_down_and_eol(); + int kf_top(); + int kf_bottom(); + int kf_select_all(); + int kf_undo(); + int kf_redo(); + int kf_copy(); + int kf_paste(); + int kf_copy_cut(); + protected: void draw(); public: diff --git a/src/Fl_Input.cxx b/src/Fl_Input.cxx index aee5f0510..b0d656e2c 100644 --- a/src/Fl_Input.cxx +++ b/src/Fl_Input.cxx @@ -90,12 +90,220 @@ static const char *legal_fp_chars = 0L; static const char *legal_fp_chars = ".eE+-"; #endif +// Move cursor up specified #lines +// If OPTION_ARROW_FOCUS is disabled, return 1 to prevent focus navigation. +// +int Fl_Input::kf_lines_up(int repeat_num) { + int i = position(); + if (!line_start(i)) { + //UNNEEDED if (input_type()==FL_MULTILINE_INPUT && !Fl::option(Fl::OPTION_ARROW_FOCUS)) return 1; + return NORMAL_INPUT_MOVE; + } + while(repeat_num--) { + i = line_start(i); + if (!i) break; + i--; + } + shift_up_down_position(line_start(i)); + return 1; +} + +// Move cursor down specified #lines +// If OPTION_ARROW_FOCUS is disabled, return 1 to prevent focus navigation. +// +int Fl_Input::kf_lines_down(int repeat_num) { + int i = position(); + if (line_end(i) >= size()) { + //UNNEEDED if (input_type()==FL_MULTILINE_INPUT && !Fl::option(Fl::OPTION_ARROW_FOCUS)) return 1; + return NORMAL_INPUT_MOVE; + } + while (repeat_num--) { + i = line_end(i); + if (i >= size()) break; + i++; + } + shift_up_down_position(i); + return 1; +} + +// Move up a page +int Fl_Input::kf_page_up() { + return kf_lines_up(linesPerPage()); +} + +// Move down a page +int Fl_Input::kf_page_down() { + return kf_lines_down(linesPerPage()); +} + +// Toggle insert mode +int Fl_Input::kf_insert_toggle() { + return 1; // \todo: needs insert mode +} + +// Delete word right +int Fl_Input::kf_delete_word_right() { + if (readonly()) { fl_beep(); return 1; } + if (mark() != position()) return cut(); + cut(position(), word_end(position())); + return 1; +} + +// Delete word left +int Fl_Input::kf_delete_word_left() { + if (readonly()) { fl_beep(); return 1; } + if (mark() != position()) return cut(); + cut(word_start(position()), position()); + return 1; +} + +// Delete to start of line +int Fl_Input::kf_delete_sol() { + if (mark() != position()) return cut(); + cut(line_start(position()), position()); + return 1; +} + +// Delete to end of line +int Fl_Input::kf_delete_eol() { + if (readonly()) { fl_beep(); return 1; } + if (mark() != position()) return cut(); + cut(position(), line_end(position())); + return 1; +} + +int Fl_Input::kf_delete_char_right() { + if (readonly()) { fl_beep(); return 1; } + if (mark() != position()) return cut(); + else return cut(1); +} + +int Fl_Input::kf_delete_char_left() { + if (readonly()) { fl_beep(); return 1; } + if (mark() != position()) cut(); + else cut(-1); + return 1; +} + +// Move cursor to start of line +int Fl_Input::kf_move_sol() { + return shift_position(line_start(position())) + NORMAL_INPUT_MOVE; +} + +// Move cursor to end of line +int Fl_Input::kf_move_eol() { + return shift_position(line_end(position())) + NORMAL_INPUT_MOVE; +} + +// Clear to end of line +int Fl_Input::kf_clear_eol() { + if (readonly()) { fl_beep(); return 1; } + if (position()>=size()) return 0; + int i = line_end(position()); + if (i == position() && i < size()) i++; + cut(position(), i); + return copy_cuts(); +} + +// Move cursor one character to the left +// If OPTION_ARROW_FOCUS is disabled, return 1 to prevent focus navigation. +// +int Fl_Input::kf_move_char_left() { + int i = shift_position(position()-1) + NORMAL_INPUT_MOVE; + return Fl::option(Fl::OPTION_ARROW_FOCUS) ? i : 1; +} + +// Move cursor one character to the right +// If OPTION_ARROW_FOCUS is disabled, return 1 to prevent focus navigation. +// +int Fl_Input::kf_move_char_right() { + int i = shift_position(position()+1) + NORMAL_INPUT_MOVE; + return Fl::option(Fl::OPTION_ARROW_FOCUS) ? i : 1; +} + +// Move cursor word-left +int Fl_Input::kf_move_word_left() { + shift_position(word_start(position())); + return 1; +} + +// Move cursor word-right +int Fl_Input::kf_move_word_right() { + shift_position(word_end(position())); + return 1; +} + +// Move cursor up one line and to the start of line (paragraph up) +int Fl_Input::kf_move_up_and_sol() { + if (line_start(position())==position() && position()>0) + return shift_position(line_start(position()-1)) + NORMAL_INPUT_MOVE; + else + return shift_position(line_start(position())) + NORMAL_INPUT_MOVE; +} + +// Move cursor down one line and to the end of line (paragraph down) +int Fl_Input::kf_move_down_and_eol() { + if (line_end(position())==position() && position()<size()) + return shift_position(line_end(position()+1)) + NORMAL_INPUT_MOVE; + else + return shift_position(line_end(position())) + NORMAL_INPUT_MOVE; +} + +// Move to top of document +int Fl_Input::kf_top() { + shift_position(0); + return 1; +} + +// Move to bottom of document +int Fl_Input::kf_bottom() { + shift_position(size()); + return 1; +} + +// Select all text in the widget +int Fl_Input::kf_select_all() { + position(0,size()); + return 1; +} + +// Undo. +int Fl_Input::kf_undo() { + if (readonly()) { fl_beep(); return 1; } + return undo(); +} + +// Redo. (currently unimplemented.. toggles undo() instead) +int Fl_Input::kf_redo() { + return kf_undo(); // currently we don't support multilevel undo +} + +// Do a copy operation +int Fl_Input::kf_copy() { + return copy(1); +} + +// Do a paste operation +int Fl_Input::kf_paste() { + if (readonly()) { fl_beep(); return 1; } + Fl::paste(*this, 1); + return 1; +} + +// Do a cut with copy +int Fl_Input::kf_copy_cut() { + if (readonly()) { fl_beep(); return 1; } + copy(1); + return cut(); +} + +// Handle a keystroke. +// Returns 1 if handled by us, 0 if not. +// int Fl_Input::handle_key() { char ascii = Fl::event_text()[0]; - int repeat_num=1; - int del; if (Fl::compose(del)) { @@ -153,349 +361,223 @@ int Fl_Input::handle_key() { } unsigned int mods = Fl::event_state() & (FL_META|FL_CTRL|FL_ALT); + unsigned int shift = Fl::event_state() & FL_SHIFT; + unsigned int multiline = (input_type() == FL_MULTILINE_INPUT) ? 1 : 0; + // + // The following lists apps that support these keypresses. + // Prefixes: '!' indicates NOT supported, '?' indicates un-verified. + // + // HIG=Human Interface Guide, + // TE=TextEdit.app, SA=Safari.app, WOX=MS Word/OSX -- OSX 10.4.x + // NP=Notepad, WP=WordPad, WOW=MS Word/Windows -- WinXP + // GE=gedit, KE=kedit -- Ubuntu8.04 + // OF=old FLTK behavior (<=1.1.10) + // + // Example: (NP,WP,!WO) means supported in notepad + wordpad, but NOT word. + // switch (Fl::event_key()) { + case FL_Insert: - if (Fl::event_state() & FL_CTRL) ascii = ctrl('C'); - else if (Fl::event_state() & FL_SHIFT) ascii = ctrl('V'); - break; - case FL_Delete: + // Note: Mac has no "Insert" key; it's the "Help" key. + // This keypress is apparently not possible on macs. + // + if (mods==0 && shift) return kf_paste(); // Shift-Insert (WP,NP,WOW,GE,KE,OF) + if (mods==0) return kf_insert_toggle(); // Insert (Standard) + if (mods==FL_CTRL) return kf_copy(); // Ctrl-Insert (WP,NP,WOW,GE,KE,OF) + return 0; // ignore other combos, pass to parent + + case FL_Delete: { #ifdef __APPLE__ - if (mods==0 || mods==FL_CTRL) { // delete next char - ascii = ctrl('D'); - } else if (mods==FL_ALT) { // delete next word - if (mark() != position()) return cut(); - cut(position(), word_end(position())); - return 1; - } else if (mods==FL_META) { // delete to the end of the line - if (mark() != position()) return cut(); - cut(position(), line_end(position())); - return 1; - } else return 1; + if (mods==0) return kf_delete_char_right(); // Delete (OSX-HIG,TE,SA,WOX) + if (mods==FL_CTRL) return kf_delete_char_right(); // Ctrl-Delete (??? TE,!SA,!WOX) + if (mods==FL_ALT) return kf_delete_word_right(); // Alt-Delete (OSX-HIG,TE,SA) + return 0; // ignore other combos, pass to parent #else - if (mods) return 1; // Alt-Del/Ctrl-Del/Meta-Del: do nothing - if (Fl::event_state() & FL_SHIFT) { - ascii = ctrl('X'); // Shift-Del -> ^X - } else { - ascii = ctrl('D'); // Del -> ^D - } + int selected = (position() != mark()) ? 1 : 0; + if (mods==0 && shift && selected) + return kf_copy_cut(); // Shift-Delete with selection (WP,NP,WOW,GE,KE,OF) + if (mods==0 && shift && !selected) + return kf_delete_char_right(); // Shift-Delete no selection (WP,NP,WOW,GE,KE,!OF) + if (mods==0) return kf_delete_char_right(); // Delete (Standard) + if (mods==FL_CTRL) return kf_delete_word_right(); // Ctrl-Delete (WP,!NP,WOW,GE,KE,!OF) + return 0; // ignore other combos, pass to parent #endif - break; + } + case FL_Left: #ifdef __APPLE__ - if (mods==0) { // char left - ascii = ctrl('B'); - } else if (mods==FL_ALT) { // word left - shift_position(word_start(position())); - return 1; - } else if (mods==FL_CTRL || mods==FL_META) { // start of line - shift_position(line_start(position())); - return 1; - } else return 1; + if (mods==0) return kf_move_char_left(); // Left (OSX-HIG) + if (mods==FL_ALT) return kf_move_word_left(); // Alt-Left (OSX-HIG) + if (mods==FL_META) return kf_move_sol(); // Meta-Left (OSX-HIG) + if (mods==FL_CTRL) return kf_move_sol(); // Ctrl-Left (TE/SA) + return 1; // other combos absorb and ignore #else - if (mods==0) { // char left - ascii = ctrl('B'); - } else if (mods==FL_CTRL) { // word left - shift_position(word_start(position())); - return 1; - } else return 1; + if (mods==0) return kf_move_char_left(); // Left (WP,NP,WOW,GE,KE,OF) + if (mods==FL_CTRL) return kf_move_word_left(); // Ctrl-Left (WP,NP,WOW,GE,KE,!OF) + if (mods==FL_META) return kf_move_char_left(); // Meta-Left (WP,NP,?WOW,GE,KE) + return 1; // other combos absorb and ignore #endif - break; + case FL_Right: #ifdef __APPLE__ - if (mods==0) { // char right - ascii = ctrl('F'); - } else if (mods==FL_ALT) { // word right - shift_position(word_end(position())); - return 1; - } else if (mods==FL_CTRL || mods==FL_META) { // end of line - shift_position(line_end(position())); - return 1; - } else return 1; + if (mods==0) return kf_move_char_right(); // Right (OSX-HIG) + if (mods==FL_ALT) return kf_move_word_right(); // Alt-Right (OSX-HIG) + if (mods==FL_META) return kf_move_eol(); // Meta-Right (OSX-HIG) + if (mods==FL_CTRL) return kf_move_eol(); // Ctrl-Right (TE/SA) + return 1; // other combos absorb and ignore #else - if (mods==0) { // char right - ascii = ctrl('F'); - } else if (mods==FL_CTRL) { // word right - shift_position(word_end(position())); - return 1; - } else return 1; -#endif // __APPLE__ - break; - case FL_Page_Up: + if (mods==0) return kf_move_char_right(); // Right (WP,NP,WOW,GE,KE,OF) + if (mods==FL_CTRL) return kf_move_word_right(); // Ctrl-Right (WP,NP,WOW,GE,KE,!OF) + if (mods==FL_META) return kf_move_char_right(); // Meta-Right (WP,NP,?WOW,GE,KE,!OF) + return 1; // other combos absorb and ignore +#endif + + case FL_Up: #ifdef __APPLE__ - if (mods==0) { // scroll text one page - // OS X scrolls the view, but does not move the cursor - // Fl_Input has no scroll control, so instead we move the cursor by one page - repeat_num = linesPerPage(); - ascii = ctrl('P'); - } else if (mods==FL_ALT) { // move cursor one page - repeat_num = linesPerPage(); - ascii = ctrl('P'); - } else return 1; - break; + if (mods==0) return kf_lines_up(1); // Up (OSX-HIG) + if (mods==FL_CTRL) return kf_page_up(); // Ctrl-Up (TE !HIG) + if (mods==FL_ALT) return kf_move_up_and_sol(); // Alt-Up (OSX-HIG) + if (mods==FL_META) return kf_top(); // Meta-Up (OSX-HIG) + return 1; // other combos absorb and ignore #else - repeat_num = linesPerPage(); - // fall through + if (mods==0) return kf_lines_up(1); // Up (WP,NP,WOW,GE,KE,OF) + if (mods==FL_CTRL) return kf_move_up_and_sol(); // Ctrl-Up (WP,!NP,WOW,GE,!KE,OF) + return 1; // other combos absorb and ignore #endif - case FL_Up: + + case FL_Down: #ifdef __APPLE__ - if (mods==0) { // line up - ascii = ctrl('P'); - } else if (mods==FL_CTRL) { // scroll text down one page - // OS X scrolls the view, but does not move the cursor - // Fl_Input has no scroll control, so instead we move the cursor by one page - repeat_num = linesPerPage(); - ascii = ctrl('P'); - } else if (mods==FL_ALT) { // line start and up - if (line_start(position())==position() && position()>0) - return shift_position(line_start(position()-1)) + NORMAL_INPUT_MOVE; - else - return shift_position(line_start(position())) + NORMAL_INPUT_MOVE; - } else if (mods==FL_META) { // start of document - shift_position(0); - return 1; - } else return 1; + if (mods==0) return kf_lines_down(1); // Dn (OSX-HIG) + if (mods==FL_CTRL) return kf_page_down(); // Ctrl-Dn (TE !HIG) + if (mods==FL_ALT) return kf_move_down_and_eol(); // Alt-Dn (OSX-HIG) + if (mods==FL_META) return kf_bottom(); // Meta-Dn (OSX-HIG) + return 1; // other combos absorb and ignore #else - if (mods==0) { // line up - ascii = ctrl('P'); - } else if (mods==FL_CTRL) { // scroll text down one line - // Fl_Input has no scroll control, so instead we move the cursor by one page - ascii = ctrl('P'); - } else return 1; + if (mods==0) return kf_lines_down(1); // Dn (WP,NP,WOW,GE,KE,OF) + if (mods==FL_CTRL) return kf_move_down_and_eol(); // Ctrl-Down (WP,!NP,WOW,GE,!KE,OF) + return 1; // other combos absorb and ignore #endif - break; - case FL_Page_Down: + + case FL_Page_Up: + // Fl_Input has no scroll control, so instead we move the cursor by one page + // OSX-HIG recommends Alt increase one semantic unit, Meta next higher.. #ifdef __APPLE__ - if (mods==0) { // scroll text one page - // OS X scrolls the view, but does not move the cursor - // Fl_Input has no scroll control, so instead we move the cursor by one page - repeat_num = linesPerPage(); - ascii = ctrl('N'); - } else if (mods==FL_ALT) { // move cursor one page - repeat_num = linesPerPage(); - ascii = ctrl('N'); - } else return 1; - break; + if (mods==0) return kf_page_up(); // PgUp (OSX-HIG) + if (mods==FL_ALT) return kf_page_up(); // Alt-PageUp (OSX-HIG) + if (mods==FL_META) return kf_top(); // Meta-PageUp (OSX-HIG,!TE) + return 1; // other combos absorb and ignore #else - repeat_num = linesPerPage(); - // fall through + if (mods==0) return kf_page_up(); // PageUp (WP,NP,WOW,GE,KE) + if (mods==FL_CTRL) return kf_page_up(); // Ctrl-PageUp (!WP,!NP,!WOW,!GE,KE,OF) + if (mods==FL_ALT) return kf_page_up(); // Alt-PageUp (!WP,!NP,!WOW,!GE,KE,OF) + return 1; // other combos absorb and ignore #endif - case FL_Down: + + case FL_Page_Down: #ifdef __APPLE__ - if (mods==0) { // line down - ascii = ctrl('N'); - } else if (mods==FL_CTRL) { - // OS X scrolls the view, but does not move the cursor - // Fl_Input has no scroll control, so instead we move the cursor by one page - repeat_num = linesPerPage(); - ascii = ctrl('N'); - } else if (mods==FL_ALT) { // line end and down - if (line_end(position())==position() && position()<size()) - return shift_position(line_end(position()+1)) + NORMAL_INPUT_MOVE; - else - return shift_position(line_end(position())) + NORMAL_INPUT_MOVE; - } else if (mods==FL_META) { // end of document - shift_position(size()); - return 1; - } else return 1; + // Fl_Input has no scroll control, so instead we move the cursor by one page + // OSX-HIG recommends Alt increase one semantic unit, Meta next higher.. + if (mods==0) return kf_page_down(); // PgDn (OSX-HIG) + if (mods==FL_ALT) return kf_page_down(); // Alt-PageDn (OSX-HIG) + if (mods==FL_META) return kf_bottom(); // Meta-PageDn (OSX-HIG,!TE) + return 1; // other combos absorb and ignore #else - if (mods==0) { // line down - ascii = ctrl('N'); - } else if (mods==FL_CTRL) { // scroll text up one line - // Fl_Input has no scroll control, so instead we move the cursor by one page - ascii = ctrl('N'); - } else return 1; + if (mods==0) return kf_page_down(); // PageDn (WP,NP,WOW,GE,KE) + if (mods==FL_CTRL) return kf_page_down(); // Ctrl-PageDn (!WP,!NP,!WOW,!GE,KE,OF) + if (mods==FL_ALT) return kf_page_down(); // Alt-PageDn (!WP,!NP,!WOW,!GE,KE,OF) + return 1; // other combos absorb and ignore #endif - break; + case FL_Home: #ifdef __APPLE__ - if (mods==0) { // scroll display to the top - // OS X scrolls the view, but does not move the cursor - // Fl_Input has no scroll control, so instead we move the cursor by one page - shift_position(0); - return 1; - } else return 1; + if (mods==0) return kf_top(); // Home (OSX-HIG) + if (mods==FL_ALT) return kf_top(); // Alt-Home (???) + return 1; // other combos absorb and ignore #else - if (mods==0) { - ascii = ctrl('A'); - } else if (mods==FL_CTRL) { - shift_position(0); - return 1; - } + if (mods==0) return kf_move_sol(); // Home (WP,NP,WOW,GE,KE,OF) + if (mods==FL_CTRL) return kf_top(); // Ctrl-Home (WP,NP,WOW,GE,KE,OF) + return 1; // other combos absorb and ignore #endif - break; + case FL_End: #ifdef __APPLE__ - if (mods==0) { // scroll display to the bottom - // OS X scrolls the view, but does not move the cursor - // Fl_Input has no scroll control, so instead we move the cursor by one page - shift_position(size()); - return 1; - } else return 1; + if (mods==0) return kf_bottom(); // End (OSX-HIG) + if (mods==FL_ALT) return kf_bottom(); // Alt-End (???) + return 1; // other combos absorb and ignore #else - if (mods==0) { - ascii = ctrl('E'); - } else if (mods==FL_CTRL) { - shift_position(size()); - return 1; - } else return 1; + if (mods==0) return kf_move_eol(); // End (WP,NP,WOW,GE,KE,OF) + if (mods==FL_CTRL) return kf_bottom(); // Ctrl-End (WP,NP,WOW,GE,KE,OF) + return 1; // other combos absorb and ignore #endif - break; + case FL_BackSpace: #ifdef __APPLE__ - if (mods==0 || mods==FL_CTRL) { // delete previous char - ascii = ctrl('H'); - } else if (mods==FL_ALT) { // delete previous word - if (mark() != position()) return cut(); - cut(word_start(position()), position()); - return 1; - } else if (mods==FL_META) { // delete to the beginning of the line - if (mark() != position()) return cut(); - cut(line_start(position()), position()); - return 1; - } else return 1; + if (mods==0) return kf_delete_char_left(); // Backspace (OSX-HIG) + if (mods==FL_CTRL) return kf_delete_char_left(); // Ctrl-Backspace (TE/SA) + if (mods==FL_ALT) return kf_delete_word_left(); // Alt-Backspace (OSX-HIG) + if (mods==FL_META) return kf_delete_sol(); // Meta-Backspace (OSX-HIG,!TE) + return 1; // other combos absorb and ignore #else - ascii = ctrl('H'); + if (mods==0) return kf_delete_char_left(); // Backspace (WP,NP,WOW,GE,KE,OF) + if (mods==FL_CTRL) return kf_delete_word_left(); // Ctrl-Backspace (WP,!NP,WOW,GE,KE,!OF) + return 1; // other combos absorb and ignore #endif - break; + case FL_Enter: case FL_KP_Enter: if (when() & FL_WHEN_ENTER_KEY) { position(size(), 0); maybe_do_callback(); return 1; - } else if (input_type() == FL_MULTILINE_INPUT && !readonly()) + } else if (multiline && !readonly()) { return replace(position(), mark(), "\n", 1); - else - return 0; // reserved for shortcuts + } return 0; // reserved for shortcuts + case FL_Tab: - if (Fl::event_state(FL_CTRL|FL_SHIFT) || input_type()!=FL_MULTILINE_INPUT || readonly()) return 0; - return replace(position(), mark(), &ascii, 1); -#ifdef __APPLE__ - case 'c' : - case 'v' : - case 'x' : - case 'z' : - // printf("'%c' (0x%02x) pressed with%s%s%s%s\n", ascii, ascii, - // Fl::event_state(FL_SHIFT) ? " FL_SHIFT" : "", - // Fl::event_state(FL_CTRL) ? " FL_CTRL" : "", - // Fl::event_state(FL_ALT) ? " FL_ALT" : "", - // Fl::event_state(FL_META) ? " FL_META" : ""); - if (Fl::event_state(FL_META)) ascii -= 0x60; - // printf("using '%c' (0x%02x)...\n", ascii, ascii); + // Handle special case for multiline input with 'old tab behavior'; + // tab handled as a normal insertable character. + // + if (mods==0 && !shift // Tab? + //// PROPOSED && !tab_nav() // old tab behavior enabled? + && multiline) { // multiline input? + break; // insert tab character + } + if (mods==0) return 0; // Tab, Shift-Tab? nav focus (Standard/OSX-HIG) + return 0; // ignore other combos, pass to parent + + case 'a': + if (mods==FL_COMMAND) return kf_select_all(); // Ctrl-A, Mac:Meta-A (Standard/OSX-HIG) + break; // handle other combos elsewhere + case 'c': + if (mods==FL_COMMAND) return kf_copy(); // Ctrl-C, Mac:Meta-C (Standard/OSX-HIG) + break; // handle other combos elsewhere + case 'v': + if (mods==FL_COMMAND) return kf_paste(); // Ctrl-V, Mac:Meta-V (Standard/OSX-HIG) + break; // handle other combos elsewhere + case 'x': + if (mods==FL_COMMAND) return kf_copy_cut(); // Ctrl-X, Mac:Meta-X (Standard/OSX-HIG) break; -#endif // __APPLE__ + case 'z': + if (mods==FL_COMMAND && !shift) return kf_undo(); // Ctrl-Z, Mac:Meta-Z (Standard/OSX-HIG) + if (mods==FL_COMMAND && shift) return kf_redo(); // Shift-Ctrl-Z, Mac:Shift-Meta-Z (Standard/OSX-HIG) + break; // handle other combos elsewhere } - int i; switch (ascii) { - case ctrl('A'): // go to the beginning of the current line - return shift_position(line_start(position())) + NORMAL_INPUT_MOVE; - case ctrl('B'): // go one character backward - i = shift_position(position()-1) + NORMAL_INPUT_MOVE; - return Fl::option(Fl::OPTION_ARROW_FOCUS) ? i : 1; - case ctrl('C'): // copy - return copy(1); - case ctrl('D'): // cut the next character - case ctrl('?'): - if (readonly()) { - fl_beep(); - return 1; - } - if (mark() != position()) return cut(); - else return cut(1); - case ctrl('E'): // go to the end of the line - return shift_position(line_end(position())) + NORMAL_INPUT_MOVE; - case ctrl('F'): // go to the next character - i = shift_position(position()+1) + NORMAL_INPUT_MOVE; - return Fl::option(Fl::OPTION_ARROW_FOCUS) ? i : 1; - case ctrl('H'): // cut the previous character - if (readonly()) { - fl_beep(); - return 1; - } - if (mark() != position()) cut(); - else cut(-1); - return 1; - case ctrl('K'): // cut to the end of the line - if (readonly()) { - fl_beep(); - return 1; - } - if (position()>=size()) return 0; - i = line_end(position()); - if (i == position() && i < size()) i++; - cut(position(), i); - return copy_cuts(); - case ctrl('N'): // go down one line - i = position(); - if (line_end(i) >= size()) { - if (input_type()==FL_MULTILINE_INPUT && !Fl::option(Fl::OPTION_ARROW_FOCUS)) return 1; - return NORMAL_INPUT_MOVE; - } - while (repeat_num--) { - i = line_end(i); - if (i >= size()) break; - i++; - } - shift_up_down_position(i); - return 1; - case ctrl('P'): // go up one line - i = position(); - if (!line_start(i)) { - if (input_type()==FL_MULTILINE_INPUT && !Fl::option(Fl::OPTION_ARROW_FOCUS)) return 1; - return NORMAL_INPUT_MOVE; - } - while(repeat_num--) { - i = line_start(i); - if (!i) break; - i--; - } - shift_up_down_position(line_start(i)); - return 1; - case ctrl('U'): // clear the whole document? - if (readonly()) { - fl_beep(); - return 1; - } - return cut(0, size()); - case ctrl('V'): // paste text - case ctrl('Y'): - if (readonly()) { - fl_beep(); - return 1; - } - Fl::paste(*this, 1); - return 1; - case ctrl('X'): // cut the selected text - case ctrl('W'): - if (readonly()) { - fl_beep(); - return 1; - } - copy(1); - return cut(); - case ctrl('Z'): // undo - case ctrl('_'): - if (readonly()) { - fl_beep(); - return 1; - } - return undo(); - case ctrl('I'): // insert literal - case ctrl('J'): - case ctrl('L'): - case ctrl('M'): - if (readonly()) { - fl_beep(); - return 1; - } + case ctrl('H'): + return kf_delete_char_left(); // Ctrl-H (!WP,!NP,!WOW,!WOX,TE,SA,GE,KE,OF) + case ctrl('I'): // Ctrl-I (literal Tab) (!WP,NP,!WOW,!GE,KE,OF) + case ctrl('J'): // Ctrl-J (literal Line Feed/Enter) (Standard) + case ctrl('L'): // Ctrl-L (literal Form Feed) (Standard) + case ctrl('M'): // Ctrl-M (literal Cr) (Standard) + if (readonly()) { fl_beep(); return 1; } // insert a few selected control characters literally: if (input_type() != FL_FLOAT_INPUT && input_type() != FL_INT_INPUT) return replace(position(), mark(), &ascii, 1); break; } - return 0; + return 0; // ignored } int Fl_Input::handle(int event) { @@ -526,8 +608,16 @@ int Fl_Input::handle(int event) { break; case FL_KEYBOARD: - if (Fl::event_key() == FL_Tab && mark() != position()) { - // Set the current cursor position to the end of the selection... + // Handle special case for multiline input with 'old tab behavior' + // where tab is entered as a character: make sure user attempt to 'tab over' + // widget doesn't destroy the field, replacing it with a tab character. + // + if (Fl::event_key() == FL_Tab // Tab key? + && !Fl::event_state(FL_SHIFT) // no shift? + //// PROPOSED && !tab_nav() // with tab navigation disabled? + && input_type() == FL_MULTILINE_INPUT // with a multiline input? + && (mark()==0 && position()==size())) { // while entire field selected? + // Set cursor to the end of the selection... if (mark() > position()) position(mark()); else |
