diff --git a/vi.c b/vi.c
index b83a1df9..6e726818 100644
--- a/vi.c
+++ b/vi.c
@@ -356,6 +356,28 @@ static int vi_motionln(int *row, int cmd, int cnt)
 {
 	int mark, c = term_read();
 	switch (c) {
+	case '\033':	/* Arrow keys */
+		c = term_read();
+		if (c == '[') {
+			c = term_read();
+			switch (c) {
+			case 'A':	/* ↑ */
+				*row = MAX(*row - cnt, 0);
+				c = 'k';
+				break;
+			case 'B':	/* ↓ */
+				*row = MIN(*row + cnt, lbuf_len(xb) - 1);
+				c = 'j';
+				break;
+			default:	/* Not a line motion so we put back all the arrow characters */
+				term_back('\033');
+				term_back('[');
+				term_back(c);
+				return 0;
+			}
+		} else	/* Not an arrow sequence so we abort */
+			return 0;
+		break;
 	case '\n':
 	case '+':
 	case 'j':
@@ -590,6 +612,27 @@ static int vi_motion(int vc, int *row, int *off)
 	}
 	mv = term_read();
 	switch (mv) {
+	case '\033':	/* Arrow keys */
+		mv = term_read();
+		if (mv == '[') {
+			if (!(cs = lbuf_get(xb, *row)))
+				return -1;
+			dir = dir_context(lbuf_get(xb, *row));
+			mv = term_read();
+			switch (mv) {
+			case 'D':	/* ← */
+				dir = -dir;
+			case 'C':	/* → */
+				for (i = 0; i < cnt; i++)
+					if (vi_nextcol(cs, dir, off))
+						break;
+				break;
+			default:	/* Not a motion managed by this function so we abort */
+				return 0;
+			}
+		} else	/* Not a 033[X command so we abort */
+			return 0;
+		break;
 	case ',':
 	case ';':
 		if (!vi_charlast[0])
