Index: src/Fl_Input_.cxx
===================================================================
--- src/Fl_Input_.cxx	(revision 6655)
+++ src/Fl_Input_.cxx	(working copy)
@@ -50,6 +50,7 @@
 #include <ctype.h>
 
 #define MAXBUF 1024
+#define ISBLANK(c)	((c) == ' ' || (c) == '\t')
 
 extern void fl_draw(const char*, int, float, float);
 
@@ -66,7 +67,7 @@
   int width_to_lastspace = 0;
   int word_count = 0;
   int word_wrap;
-//  const char *pe = p + strlen(p);
+  const char *pe = p + strlen(p);
 
   if (input_type()==FL_SECRET_INPUT) {
     while (o<e && p < value_+size_) {
@@ -75,12 +76,18 @@
     }
 
   } else while (o<e) {
-    if (wrap() && (p >= value_+size_ || isspace(*p & 255))) {
+    int u8len;
+    unsigned ucs = fl_utf8decode(p, pe, &u8len);
+    if ((*p & 0x80) && (u8len < 2))  u8len = -1;
+    if (wrap() &&
+	((p >= value_ + size_) || ((u8len > 0) && fl_is_linebreak(ucs)))) {
       word_wrap = w() - Fl::box_dw(box()) - 2;
       width_to_lastspace += (int)fl_width(lastspace_out, o-lastspace_out);
       if (p > lastspace+1) {
 	if (word_count && width_to_lastspace > word_wrap) {
-	  p = lastspace; o = lastspace_out; break;
+	  p = lastspace; o = lastspace_out;
+	  if (*p != ' ' && *p != '\n')  p--;
+	  break;
 	}
 	word_count++;
       }
@@ -89,19 +96,23 @@
     }
 
     if (p >= value_+size_) break;
-    int c = *p++ & 255;
-    if (c < ' ' || c == 127) {
-      if (c=='\n' && input_type()==FL_MULTILINE_INPUT) {p--; break;}
-      if (c == '\t' && input_type()==FL_MULTILINE_INPUT) {
-        for (c = fl_utf_nb_char((uchar*)buf, o-buf)%8; c<8 && o<e; c++) {
-          *o++ = ' ';
-        }
+    if (u8len > 0) {
+      if (ucs < ' ' || ucs == 127) {
+	if (ucs == '\n' && input_type()==FL_MULTILINE_INPUT) break;
+	if (ucs == '\t' && input_type()==FL_MULTILINE_INPUT) {
+	  int ucs_len = fl_utf_nb_char((uchar*)buf, o-buf);
+	  for (int n = ucs_len%8; n<8 && o<e; n++) *o++ = ' ';
       } else {
 	*o++ = '^';
-	*o++ = c ^ 0x40;
+	  *o++ = ucs ^ 0x40;
       }
     } else {
-      *o++ = c;
+	memcpy(o, p, u8len);
+	o += u8len;
+      }
+      p += u8len;
+    } else {
+      p++;
     }
   }
   *o = 0;
@@ -127,7 +138,7 @@
     if (c < ' ' || c == 127) {
       if (c == '\t' && input_type()==FL_MULTILINE_INPUT) {
          n += 8-(chr%8);
-         chr += 8-(chr%8);
+         chr += 7-(chr%8);
       } else n += 2;
     } else {
       n++;
@@ -206,6 +217,7 @@
   // count how many lines and put the last one into the buffer:
   // And figure out where the cursor is:
   int height = fl_height();
+  int threshold = height / 2;
   int lines;
   int curx, cury;
   for (p=value(), curx=cury=lines=0; ;) {
@@ -215,15 +227,15 @@
       if (Fl::focus()==this && !was_up_down) up_down_pos = curx;
       cury = lines*height;
       int newscroll = xscroll_;
-      if (curx > newscroll+W-20) {
+      if (curx > newscroll+W-threshold) {
 	// figure out scrolling so there is space after the cursor:
-	newscroll = curx+20-W;
+	newscroll = curx+threshold-W;
 	// figure out the furthest left we ever want to scroll:
 	int ex = int(expandpos(p, e, buf, 0))+2-W;
 	// use minimum of both amounts:
 	if (ex < newscroll) newscroll = ex;
-      } else if (curx < newscroll+20) {
-	newscroll = curx-20;
+      } else if (curx < newscroll+threshold) {
+	newscroll = curx-threshold;
       }
       if (newscroll < 0) newscroll = 0;
       if (newscroll != xscroll_) {
@@ -336,8 +348,7 @@
   CONTINUE:
     ypos += height;
     if (e >= value_+size_) break;
-    if (*e == '\n' || *e == ' ') e++;
-    p = e;
+    p = e+1;
   }
 
   // for minimal update, erase all lines below last one if necessary:
@@ -363,16 +374,33 @@
 
 int Fl_Input_::word_end(int i) const {
   if (input_type() == FL_SECRET_INPUT) return size();
-  //while (i < size() && !isword(index(i))) i++;
-  while (i < size() && isword(index(i))) i++;
+  const char* e = value_ + size_;
+  unsigned    ucs;
+  for (const char* p = value_ + i;  p < e;  i++, p++)
+  {
+    int u8len;
+    ucs = fl_utf8decode(p, e, &u8len);
+    if ((*p & 0x80) && (u8len < 2))  continue;
+    if (fl_is_linebreak(ucs))  break;
+    if ((ucs < 0x80) && !isword(*p))  break;
+  }
   return i;
 }
 
 int Fl_Input_::word_start(int i) const {
   if (input_type() == FL_SECRET_INPUT) return 0;
-//   if (i >= size() || !isword(index(i)))
-//     while (i > 0 && !isword(index(i-1))) i--;
-  while (i > 0 && isword(index(i-1))) i--;
+  const char* e = value_ + size_;
+  unsigned ucs;
+  for (const char* p = value_ + i;  i > 0;  i--)
+  {
+    int u8len;
+    bool multi = (*p & 0x80);
+    ucs = fl_utf8decode(p, e, &u8len);
+    p--;
+    if (multi && (u8len < 2))  continue;
+    if (fl_is_linebreak(ucs))  break;
+    if ((ucs < 0x80) && !isword(*p))  break;
+  }
   return i;
 }
 
@@ -554,6 +582,8 @@
     int f = (int)expandpos(p, t, buf, 0);
     if (f <= up_down_pos) l = t; else r = t-1;
   }
+  e = value() + size();
+  while ((l < e) && (fl_utf8len((char)l[0]) < 1))  l--;
   int j = l-value();
   j = position(j, keepmark ? mark_ : j);
   was_up_down = 1;
@@ -702,7 +732,7 @@
     for (i=0; i<ilen; i++)
       if (text[i]==' ') break;
     if (i==ilen)
-      while (b > 0 && !isspace(index(b) & 255) && index(b)!='\n') b--;
+      while (b > 0 && !ISBLANK(index(b)) && index(b)!='\n') b--;
     else
       while (b > 0 && index(b)!='\n') b--;
   }
@@ -845,10 +875,10 @@
     // strip trailing control characters and spaces before pasting:
     const char* t = Fl::event_text();
     const char* e = t+Fl::event_length();
-    if (input_type() != FL_MULTILINE_INPUT) while (e > t && isspace(*(e-1) & 255)) e--;
+    if (input_type() != FL_MULTILINE_INPUT) while (e > t && ISBLANK(*(e-1))) e--;
     if (!t || e <= t) return 1; // Int/float stuff will crash without this test
     if (input_type() == FL_INT_INPUT) {
-      while (isspace(*t & 255) && t < e) t ++;
+      while (ISBLANK(*t) && t < e) t ++;
       const char *p = t;
       if (*p == '+' || *p == '-') p ++;
       if (strncmp(p, "0x", 2) == 0) {
@@ -862,7 +892,7 @@
         return 1;
       } else return replace(0, size(), t, e - t);
     } else if (input_type() == FL_FLOAT_INPUT) {
-      while (isspace(*t & 255) && t < e) t ++;
+      while (ISBLANK(*t) && t < e) t ++;
       const char *p = t;
       if (*p == '+' || *p == '-') p ++;
       while (isdigit(*p & 255) && p < e) p ++;
Index: src/Fl_Input.cxx
===================================================================
--- src/Fl_Input.cxx	(revision 6655)
+++ src/Fl_Input.cxx	(working copy)
@@ -211,6 +211,7 @@
   }
 
   int i;
+  uchar* p;
   switch (ascii) {
   case ctrl('A'):
     return shift_position(line_start(position())) + NORMAL_INPUT_MOVE;
@@ -227,7 +228,14 @@
     if (mark() != position()) return cut();
     else return cut(1);
   case ctrl('E'):
-    return shift_position(line_end(position())) + NORMAL_INPUT_MOVE;
+    i = line_end(position());
+    p = (uchar*)value() + i;
+    if (i && *p != ' ' && *p != '\n' && *p != '\0')
+      do {
+        i--;
+        p--;
+      } while (i && *p >= 0x80 && *p <= 0xbf);
+    return shift_position(i) + NORMAL_INPUT_MOVE;
   case ctrl('F'):
     return shift_position(position()+1) + NORMAL_INPUT_MOVE;
   case ctrl('H'):
@@ -458,6 +466,31 @@
     take_focus();
     return 1;
 
+  case FL_MOUSEWHEEL:
+    if (Fl::e_dy > 0)
+    {
+      int i = position();
+      int repeat_num = Fl::e_dy;
+      while (repeat_num--) {  
+        i = line_end(i);
+        if (i >= size()) return NORMAL_INPUT_MOVE;
+        i++;
+      }
+      shift_up_down_position(i);
+    }
+    else
+    {
+      int i = position();
+      int repeat_num = -Fl::e_dy;
+      while(repeat_num--) {
+        i = line_start(i);
+        if (!i) return NORMAL_INPUT_MOVE;
+        i--;
+      }
+      shift_up_down_position(line_start(i));
+    }
+    return 1;
+
   }
   Fl_Boxtype b = box();
   return Fl_Input_::handletext(event,
Index: src/fl_utf8.cxx
===================================================================
--- src/fl_utf8.cxx	(revision 6655)
+++ src/fl_utf8.cxx	(working copy)
@@ -472,6 +472,53 @@
 } // fl_mbcs2utf
 #endif
 
+
+// Returns non-zero value if character allows line-break after it
+int fl_is_linebreak(unsigned int ucs)
+{
+	/* Space or tab */
+	if (ucs == ' ' || ucs == '\t')  return 1;
+
+	/* U+2E80..U+2EFF: CJK Radical Supplement */
+	/* U+2F00..U+2FDF: Kangxi Radicals */
+	/* U+2FF0..U+2FFF: Ideographic Description Characters */
+	/* U+3000..U+303F: CJK Symbols and Punctuation */
+	/* U+3040..U+309F: Hiragana */
+	/* U+30A0..U+30FF: Katakana */
+	/* U+3100..U+312F: Bopomofo */
+	/* U+3130..U+318F: Hangul Compatibility Jamo */
+	/* U+3190..U+319F: Kanbun */
+	/* U+31A0..U+31BF: Bopomofo Extended */
+	/* U+31C0..U+31EF: CJK Strokes */
+	/* U+31F0..U+31FF: Katakana Phonetic Extensions */
+	/* U+3200..U+32FF: Enclosed CJK Letters and Months */
+	/* U+3300..U+33FF: CJK Compatibility */
+	/* U+3400..U+4DB5: CJK Ideographs Extension A */
+	if (ucs >= 0x2e80 && ucs <= 0x4db5)  return 1;
+
+	/* U+4E00..U+9FBB: CJK Ideographs */
+	if (ucs >= 0x4e00 && ucs <= 0x9fbb)  return 1;
+
+	/* U+A000..U+A48F: Yi Syllables */
+	/* U+A490..U+A4CF: Yi Radicals */
+	if (ucs >= 0xa000 && ucs <= 0xa4cf)  return 1;
+
+	/* U+F900..U+FAFF: CJK Compatibility Ideographs */
+	if (ucs >= 0xf900 && ucs <= 0xfaff)  return 1;
+
+	/* U+FE30..U+FE4F: CJK Compatibility Forms */
+	/* U+FE50..U+FE6F: Small Form Variants */
+	if (ucs >= 0xfe30 && ucs <= 0xfe6f)  return 1;
+
+	/* U+FF00..U+FFEF: Half-Width CJK Symbols and Punctuation */
+	if (ucs == 0xff0c || ucs == 0xff0e || ucs == 0xff1a || ucs == 0xff1b)
+		return 1;
+	if (ucs >= 0xff60 && ucs <= 0xffdf)  return 1;
+
+	return 0;
+}
+
+
 #if defined(WIN32)  && !defined(__CYGWIN__)
 static xchar *wbuf = NULL;
 static xchar *wbuf1 = NULL;
Index: FL/fl_utf8.h
===================================================================
--- FL/fl_utf8.h	(revision 6655)
+++ FL/fl_utf8.h	(working copy)
@@ -143,6 +143,9 @@
 /* OD: Convert a local multi-byte encoding to UTF8 */
 //FL_EXPORT char* fl_mbcs2utf(const char *src);
 
+/* Check weather this wide character allows line-break after it */
+int fl_is_linebreak(unsigned ucs);
+
 /*****************************************************************************/
 #ifdef WIN32
 /* OD: Attempt to convert the UTF8 string to the current locale */
