diff --git a/Cargo.toml b/Cargo.toml
index 5b165446..5d6bbf1a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -38,6 +38,7 @@ backtrace = "0.3"
 toml = "0.5.6"
 serde = {version = "1.0", features = ["derive"] }
 unicode-segmentation = "1.6.0"
+unicode-width = "0.1.7"
 
 [dev-dependencies]
 assert_cmd = "0.12"
diff --git a/src/app.rs b/src/app.rs
index d54fce76..1f983e32 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -6,9 +6,12 @@ pub mod data_farmer;
 use data_farmer::*;
 
 use crate::{canvas, constants, utils::error::Result};
-
 mod process_killer;
 
+use unicode_segmentation::GraphemeCursor;
+
+const MAX_SEARCH_LENGTH: usize = 200;
+
 #[derive(Debug, Clone, Copy)]
 pub enum WidgetPosition {
 	Cpu,
@@ -60,9 +63,9 @@ pub struct AppSearchState {
 	pub is_enabled: bool,
 	current_search_query: String,
 	current_regex: Option<std::result::Result<regex::Regex, regex::Error>>,
-	current_cursor_position: usize,
 	pub is_blank_search: bool,
 	pub is_invalid_search: bool,
+	pub grapheme_cursor: GraphemeCursor,
 }
 
 impl Default for AppSearchState {
@@ -71,9 +74,9 @@ impl Default for AppSearchState {
 			is_enabled: false,
 			current_search_query: String::default(),
 			current_regex: None,
-			current_cursor_position: 0,
 			is_invalid_search: false,
 			is_blank_search: true,
+			grapheme_cursor: GraphemeCursor::new(0, 0, true),
 		}
 	}
 }
@@ -535,7 +538,8 @@ impl App {
 	pub fn get_cursor_position(&self) -> usize {
 		self.process_search_state
 			.search_state
-			.current_cursor_position
+			.grapheme_cursor
+			.cur_cursor()
 	}
 
 	/// One of two functions allowed to run while in a dialog...
@@ -576,23 +580,26 @@ impl App {
 			WidgetPosition::Process => self.start_dd(),
 			WidgetPosition::ProcessSearch => {
 				if self.process_search_state.search_state.is_enabled
-					&& self
-						.process_search_state
-						.search_state
-						.current_cursor_position < self
-						.process_search_state
-						.search_state
-						.current_search_query
-						.len()
+					&& self.get_cursor_position()
+						< self
+							.process_search_state
+							.search_state
+							.current_search_query
+							.len()
 				{
 					self.process_search_state
 						.search_state
 						.current_search_query
-						.remove(
-							self.process_search_state
-								.search_state
-								.current_cursor_position,
-						);
+						.remove(self.get_cursor_position());
+
+					self.process_search_state.search_state.grapheme_cursor = GraphemeCursor::new(
+						self.get_cursor_position(),
+						self.process_search_state
+							.search_state
+							.current_search_query
+							.len(),
+						true,
+					);
 
 					self.update_regex();
 					self.update_process_gui = true;
@@ -619,9 +626,8 @@ impl App {
 
 	pub fn clear_search(&mut self) {
 		if let WidgetPosition::ProcessSearch = self.current_widget_selected {
-			self.process_search_state
-				.search_state
-				.current_cursor_position = 0;
+			self.process_search_state.search_state.grapheme_cursor =
+				GraphemeCursor::new(0, 0, true);
 			self.process_search_state.search_state.current_search_query = String::default();
 			self.process_search_state.search_state.is_blank_search = true;
 			self.process_search_state.search_state.is_invalid_search = false;
@@ -629,26 +635,46 @@ impl App {
 		}
 	}
 
+	pub fn search_walk_forward(&mut self, start_position: usize) {
+		self.process_search_state
+			.search_state
+			.grapheme_cursor
+			.next_boundary(
+				&self.process_search_state.search_state.current_search_query[start_position..],
+				start_position,
+			)
+			.unwrap();
+	}
+
+	pub fn search_walk_back(&mut self, start_position: usize) {
+		self.process_search_state
+			.search_state
+			.grapheme_cursor
+			.prev_boundary(
+				&self.process_search_state.search_state.current_search_query[..start_position],
+				0,
+			)
+			.unwrap();
+	}
+
 	pub fn on_backspace(&mut self) {
 		if let WidgetPosition::ProcessSearch = self.current_widget_selected {
-			if self.process_search_state.search_state.is_enabled
-				&& self
-					.process_search_state
-					.search_state
-					.current_cursor_position
-					> 0
-			{
-				self.process_search_state
-					.search_state
-					.current_cursor_position -= 1;
+			if self.process_search_state.search_state.is_enabled && self.get_cursor_position() > 0 {
+				self.search_walk_back(self.get_cursor_position());
+
 				self.process_search_state
 					.search_state
 					.current_search_query
-					.remove(
-						self.process_search_state
-							.search_state
-							.current_cursor_position,
-					);
+					.remove(self.get_cursor_position());
+
+				self.process_search_state.search_state.grapheme_cursor = GraphemeCursor::new(
+					self.get_cursor_position(),
+					self.process_search_state
+						.search_state
+						.current_search_query
+						.len(),
+					true,
+				);
 
 				self.update_regex();
 				self.update_process_gui = true;
@@ -683,16 +709,7 @@ impl App {
 	pub fn on_left_key(&mut self) {
 		if !self.is_in_dialog() {
 			if let WidgetPosition::ProcessSearch = self.current_widget_selected {
-				if self
-					.process_search_state
-					.search_state
-					.current_cursor_position
-					> 0
-				{
-					self.process_search_state
-						.search_state
-						.current_cursor_position -= 1;
-				}
+				self.search_walk_back(self.get_cursor_position());
 			}
 		} else if self.delete_dialog_state.is_showing_dd && !self.delete_dialog_state.is_on_yes {
 			self.delete_dialog_state.is_on_yes = true;
@@ -702,20 +719,7 @@ impl App {
 	pub fn on_right_key(&mut self) {
 		if !self.is_in_dialog() {
 			if let WidgetPosition::ProcessSearch = self.current_widget_selected {
-				if self
-					.process_search_state
-					.search_state
-					.current_cursor_position
-					< self
-						.process_search_state
-						.search_state
-						.current_search_query
-						.len()
-				{
-					self.process_search_state
-						.search_state
-						.current_cursor_position += 1;
-				}
+				self.search_walk_forward(self.get_cursor_position());
 			}
 		} else if self.delete_dialog_state.is_showing_dd && self.delete_dialog_state.is_on_yes {
 			self.delete_dialog_state.is_on_yes = false;
@@ -725,9 +729,14 @@ impl App {
 	pub fn skip_cursor_beginning(&mut self) {
 		if !self.is_in_dialog() {
 			if let WidgetPosition::ProcessSearch = self.current_widget_selected {
-				self.process_search_state
-					.search_state
-					.current_cursor_position = 0;
+				self.process_search_state.search_state.grapheme_cursor = GraphemeCursor::new(
+					0,
+					self.process_search_state
+						.search_state
+						.current_search_query
+						.len(),
+					true,
+				);
 			}
 		}
 	}
@@ -735,13 +744,17 @@ impl App {
 	pub fn skip_cursor_end(&mut self) {
 		if !self.is_in_dialog() {
 			if let WidgetPosition::ProcessSearch = self.current_widget_selected {
-				self.process_search_state
-					.search_state
-					.current_cursor_position = self
-					.process_search_state
-					.search_state
-					.current_search_query
-					.len();
+				self.process_search_state.search_state.grapheme_cursor = GraphemeCursor::new(
+					self.process_search_state
+						.search_state
+						.current_search_query
+						.len(),
+					self.process_search_state
+						.search_state
+						.current_search_query
+						.len(),
+					true,
+				);
 			}
 		}
 	}
@@ -788,13 +801,12 @@ impl App {
 	}
 
 	pub fn on_char_key(&mut self, caught_char: char) {
-		// Forbid any char key presses when showing a dialog box...
-
 		// Skip control code chars
 		if caught_char.is_control() {
 			return;
 		}
 
+		// Forbid any char key presses when showing a dialog box...
 		if !self.is_in_dialog() {
 			let current_key_press_inst = Instant::now();
 			if current_key_press_inst
@@ -806,21 +818,29 @@ impl App {
 			self.last_key_press = current_key_press_inst;
 
 			if let WidgetPosition::ProcessSearch = self.current_widget_selected {
-				self.process_search_state
+				if self
+					.process_search_state
 					.search_state
 					.current_search_query
-					.insert(
+					.len() <= MAX_SEARCH_LENGTH
+				{
+					self.process_search_state
+						.search_state
+						.current_search_query
+						.insert(self.get_cursor_position(), caught_char);
+
+					self.process_search_state.search_state.grapheme_cursor = GraphemeCursor::new(
+						self.get_cursor_position(),
 						self.process_search_state
 							.search_state
-							.current_cursor_position,
-						caught_char,
+							.current_search_query
+							.len(),
+						true,
 					);
-				self.process_search_state
-					.search_state
-					.current_cursor_position += 1;
-
-				self.update_regex();
-				self.update_process_gui = true;
+					self.search_walk_forward(self.get_cursor_position());
+					self.update_regex();
+					self.update_process_gui = true;
+				}
 			} else {
 				match caught_char {
 					'/' => {
diff --git a/src/canvas.rs b/src/canvas.rs
index 82a117f8..02ea3ab5 100644
--- a/src/canvas.rs
+++ b/src/canvas.rs
@@ -4,7 +4,7 @@ use crate::{
 	data_conversion::{ConvertedCpuData, ConvertedProcessData},
 	utils::error,
 };
-use std::cmp::max;
+use std::cmp::{max, min};
 use std::collections::HashMap;
 use tui::{
 	backend,
@@ -14,6 +14,8 @@ use tui::{
 	widgets::{Axis, Block, Borders, Chart, Dataset, Marker, Paragraph, Row, Table, Text, Widget},
 	Terminal,
 };
+use unicode_segmentation::UnicodeSegmentation;
+use unicode_width::UnicodeWidthStr;
 
 mod canvas_colours;
 use canvas_colours::*;
@@ -1155,55 +1157,60 @@ impl Painter {
 	fn draw_search_field<B: backend::Backend>(
 		&self, f: &mut Frame<'_, B>, app_state: &mut app::App, draw_loc: Rect,
 	) {
-		let width = max(0, draw_loc.width as i64 - 34) as u64;
-		let query = app_state.get_current_search_query();
-		let shrunk_query = if query.len() < width as usize {
-			query
-		} else {
-			&query[(query.len() - width as usize)..]
-		};
-
+		let width = max(0, draw_loc.width as i64 - 34) as u64; // TODO: [REFACTOR] Hard coding this is terrible.
+		let query = app_state.get_current_search_query().as_str();
+		let grapheme_indices = UnicodeSegmentation::grapheme_indices(query, true)
+			.rev()
+			.enumerate(); // Reverse due to us wanting to draw from back -> front
+		let num_graphemes = min(UnicodeWidthStr::width_cjk(query), width as usize);
 		let cursor_position = app_state.get_cursor_position();
 
-		let query_with_cursor: Vec<Text<'_>> =
-			if let app::WidgetPosition::ProcessSearch = app_state.current_widget_selected {
-				if cursor_position >= query.len() {
-					let mut q = vec![Text::styled(
-						shrunk_query.to_string(),
-						self.colours.text_style,
-					)];
+		let mut query_with_cursor: Vec<Text<'_>> = if let app::WidgetPosition::ProcessSearch =
+			app_state.current_widget_selected
+		{
+			let mut res = Vec::new();
+			if cursor_position >= query.len() {
+				res.push(Text::styled(
+					" ",
+					self.colours.currently_selected_text_style,
+				))
+			}
 
-					q.push(Text::styled(
-						" ".to_string(),
-						self.colours.currently_selected_text_style,
-					));
+			res.extend(
+				grapheme_indices
+					.filter_map(|(itx, grapheme)| {
+						if itx >= num_graphemes {
+							None
+						} else {
+							let styled = if grapheme.0 == cursor_position {
+								Text::styled(grapheme.1, self.colours.currently_selected_text_style)
+							} else {
+								Text::styled(grapheme.1, self.colours.text_style)
+							};
+							Some(styled)
+						}
+					})
+					.collect::<Vec<_>>(),
+			);
 
-					q
-				} else {
-					shrunk_query
-						.chars()
-						.enumerate()
-						.map(|(itx, c)| {
-							if let app::WidgetPosition::ProcessSearch =
-								app_state.current_widget_selected
-							{
-								if itx == cursor_position {
-									return Text::styled(
-										c.to_string(),
-										self.colours.currently_selected_text_style,
-									);
-								}
-							}
-							Text::styled(c.to_string(), self.colours.text_style)
-						})
-						.collect::<Vec<_>>()
-				}
-			} else {
-				vec![Text::styled(
-					shrunk_query.to_string(),
-					self.colours.text_style,
-				)]
-			};
+			res
+		} else {
+			// This is easier - we just need to get a range of graphemes, rather than
+			// dealing with possibly inserting a cursor (as none is shown!)
+			grapheme_indices
+				.filter_map(|(itx, grapheme)| {
+					if itx >= num_graphemes {
+						None
+					} else {
+						let styled = Text::styled(grapheme.1, self.colours.text_style);
+						Some(styled)
+					}
+				})
+				.collect::<Vec<_>>()
+		};
+
+		// I feel like this is most definitely not the efficient way of doing this but eh
+		query_with_cursor.reverse();
 
 		let mut search_text = vec![if app_state.is_grouped() {
 			Text::styled("Search by Name: ", self.colours.table_header_style)
diff --git a/src/main.rs b/src/main.rs
index da47da1f..e1c80dcd 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -315,12 +315,18 @@ fn handle_mouse_event(event: MouseEvent, app: &mut App) {
 fn handle_key_event_or_break(
 	event: KeyEvent, app: &mut App, rtx: &std::sync::mpsc::Sender<ResetEvent>,
 ) -> bool {
+	//debug!("KeyEvent: {:?}", event);
+
+	// TODO: [PASTE] Note that this does NOT support some emojis like flags.  This is due to us
+	// catching PER CHARACTER right now WITH A forced throttle!  This means multi-char will not work.
+	// We can solve this (when we do paste probably) while keeping the throttle (mainly meant for movement)
+	// by throttling after *bulk+singular* actions, not just singular ones.
+
 	if event.modifiers.is_empty() {
 		// Required catch for searching - otherwise you couldn't search with q.
 		if event.code == KeyCode::Char('q') && !app.is_in_search_widget() {
 			return true;
 		}
-
 		match event.code {
 			KeyCode::End => app.skip_to_last(),
 			KeyCode::Home => app.skip_to_first(),