Author: greg.ercolano
Date: 2010-12-19 22:42:38 -0800 (Sun, 19 Dec 2010)
New Revision: 8067
Log:
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.



Modified:
   branches/branch-1.3/FL/Fl_Input.H
   branches/branch-1.3/src/Fl_Input.cxx

Modified: branches/branch-1.3/FL/Fl_Input.H
===================================================================
--- branches/branch-1.3/FL/Fl_Input.H   2010-12-19 23:52:59 UTC (rev 8066)
+++ branches/branch-1.3/FL/Fl_Input.H   2010-12-20 06:42:38 UTC (rev 8067)
@@ -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:

Modified: branches/branch-1.3/src/Fl_Input.cxx
===================================================================
--- branches/branch-1.3/src/Fl_Input.cxx        2010-12-19 23:52:59 UTC (rev 
8066)
+++ branches/branch-1.3/src/Fl_Input.cxx        2010-12-20 06:42:38 UTC (rev 
8067)
@@ -90,12 +90,220 @@
 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 @@
   }
   
   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 @@
       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

_______________________________________________
fltk-commit mailing list
[email protected]
http://lists.easysw.com/mailman/listinfo/fltk-commit

Reply via email to