diff --git a/.travis.yml b/.travis.yml
index 4075f5cf0ba10e8aa718304e53ef4419a14e8edc..711713eb690688e32b2492e9f4e46eac737274dd 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,7 +1,5 @@
 sudo: false
 language: rust
-rust:
-  - nightly
 script:
   - cargo build --verbose
   - cargo test --verbose
diff --git a/README.md b/README.md
index dae7a212050fa379f958f9e8b634fc6aaaedf19b..33826e3656808bfc65799574d63393cbd86acf73 100644
--- a/README.md
+++ b/README.md
@@ -17,12 +17,6 @@ Readline implementation in Rust that is based on [Antirez' Linenoise](https://gi
 * Powershell ISE is not supported, check [issue #56](https://github.com/kkawakam/rustyline/issues/56)
 * Mintty (Cygwin/Mingw) is not supported
 
-## Build
-This project uses Cargo and Rust nightly
-```bash
-cargo build --release
-```
-
 ## Example
 ```rust
 extern crate rustyline;
diff --git a/appveyor.yml b/appveyor.yml
index 862c484b487650240e0e51835d73f13a8b6c8e7c..4506f3af83c2ae62fb45caec18f0bbc018d9ce5d 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -2,7 +2,7 @@ environment:
   TARGET: x86_64-pc-windows-msvc
 install:
   - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
-  - rustup-init -yv --default-toolchain nightly --default-host %TARGET%
+  - rustup-init -yv --default-toolchain stable --default-host %TARGET%
   - set PATH=%PATH%;%USERPROFILE%\.cargo\bin
   - rustc -V
   - cargo -V
diff --git a/src/error.rs b/src/error.rs
index 85183006914e8e08d1a11e90a3795960161aff7f..d9cfdb85e9d32362a44725b8eda47a9d3af0c6ea 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -6,6 +6,7 @@ use std::char;
 use std::error;
 use std::fmt;
 use std::io;
+use std::str;
 
 /// The error type for Rustyline errors that can arise from
 /// I/O related errors or Errno when using the nix-rust library
@@ -19,7 +20,7 @@ pub enum ReadlineError {
     Interrupted,
     /// Chars Error
     #[cfg(unix)]
-    Char(io::CharsError),
+    Char(str::Utf8Error),
     /// Unix Error from syscall
     #[cfg(unix)]
     Errno(nix::Error),
@@ -79,8 +80,8 @@ impl From<nix::Error> for ReadlineError {
 }
 
 #[cfg(unix)]
-impl From<io::CharsError> for ReadlineError {
-    fn from(err: io::CharsError) -> ReadlineError {
+impl From<str::Utf8Error> for ReadlineError {
+    fn from(err: str::Utf8Error) -> ReadlineError {
         ReadlineError::Char(err)
     }
 }
diff --git a/src/lib.rs b/src/lib.rs
index fdff16977f738c7e4fd6861fb1cbe9d3da28d9a6..712036f9985f9aa5db51cab0e44328d23e7748fd 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -15,7 +15,6 @@
 //!     Err(_) => println!("No input"),
 //! }
 //! ```
-#![feature(io)]
 #![allow(unknown_lints)]
 
 extern crate libc;
diff --git a/src/tty/unix.rs b/src/tty/unix.rs
index da3db4d05361ea1e95b863ea4f3c606987fc5da7..cd7fec625e4270320665553a04ccbfb8f3e61090 100644
--- a/src/tty/unix.rs
+++ b/src/tty/unix.rs
@@ -1,6 +1,6 @@
 //! Unix specific definitions
 use std;
-use std::io::{self, Chars, Read, Stdout, Write};
+use std::io::{self, Read, Stdout, Write};
 use std::sync;
 use std::sync::atomic;
 
@@ -96,16 +96,17 @@ impl Read for StdinRaw {
 
 /// Console input reader
 pub struct PosixRawReader {
-    chars: Chars<StdinRaw>,
+    stdin: StdinRaw,
     timeout_ms: i32,
+    buf: [u8; 4],
 }
 
 impl PosixRawReader {
     fn new(config: &Config) -> Result<PosixRawReader> {
-        let stdin = StdinRaw {};
         Ok(PosixRawReader {
-            chars: stdin.chars(),
+            stdin: StdinRaw{},
             timeout_ms: config.keyseq_timeout(),
+            buf: [0; 4],
         })
     }
 
@@ -258,6 +259,26 @@ impl PosixRawReader {
     }
 }
 
+// https://tools.ietf.org/html/rfc3629
+static UTF8_CHAR_WIDTH: [u8; 256] = [
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x1F
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x3F
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x5F
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x7F
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0x9F
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0xBF
+0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 0xDF
+3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 0xEF
+4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0, // 0xFF
+];
+
 impl RawReader for PosixRawReader {
     fn next_key(&mut self, single_esc_abort: bool) -> Result<KeyPress> {
         let c = try!(self.next_char());
@@ -287,9 +308,22 @@ impl RawReader for PosixRawReader {
     }
 
     fn next_char(&mut self) -> Result<char> {
-        match self.chars.next() {
-            Some(c) => Ok(try!(c)),
-            None => Err(error::ReadlineError::Eof),
+        let n = try!(self.stdin.read(&mut self.buf[..1]));
+        if n == 0 {
+            return Err(error::ReadlineError::Eof);
+        }
+        let first = self.buf[0];
+        if first >= 128 {
+            let width = UTF8_CHAR_WIDTH[first as usize] as usize;
+            if width == 0 {
+                try!(std::str::from_utf8(&self.buf[..1]));
+                unreachable!()
+            }
+            try!(self.stdin.read_exact(&mut self.buf[1..width]));
+            let s = try!(std::str::from_utf8(&self.buf[..width]));
+            Ok(s.chars().next().unwrap())
+        } else {
+            return Ok(first as char);
         }
     }
 }