diff --git a/ui/src/keyboardLayouts.ts b/ui/src/keyboardLayouts.ts
index 69b3ea9..2c0eeda 100644
--- a/ui/src/keyboardLayouts.ts
+++ b/ui/src/keyboardLayouts.ts
@@ -1,4 +1,5 @@
 import { chars as chars_en_US } from "@/keyboardLayouts/en_US"
+import { chars as chars_fr_FR } from "@/keyboardLayouts/fr_FR"
 import { chars as chars_de_DE } from "@/keyboardLayouts/de_DE"
 import { chars as chars_fr_CH } from "@/keyboardLayouts/fr_CH"
 import { chars as chars_de_CH } from "@/keyboardLayouts/de_CH"
@@ -8,6 +9,7 @@ export type KeyCombo = KeyInfo & { deadKey?: boolean, accentKey?: KeyInfo }
 
 export const layouts = {
   "en_US": "English (US)",
+  "fr_FR": "French",
   "de_DE": "German",
   "fr_CH": "Swiss French",
   "de_CH": "Swiss German"
@@ -15,6 +17,7 @@ export const layouts = {
 
 export const chars = {
   "en_US": chars_en_US,
+  "fr_FR": chars_fr_FR,
   "de_DE": chars_de_DE,
   "fr_CH": chars_fr_CH,
   "de_CH": chars_de_CH,
diff --git a/ui/src/keyboardLayouts/fr_FR.ts b/ui/src/keyboardLayouts/fr_FR.ts
new file mode 100644
index 0000000..9d66d16
--- /dev/null
+++ b/ui/src/keyboardLayouts/fr_FR.ts
@@ -0,0 +1,137 @@
+import { KeyCombo } from "../keyboardLayouts"
+
+const keyTrema = { key: "BracketLeft", shift: true } // tréma (umlaut), two dots placed above a vowel
+const keyHat = { key: "BracketLeft" } // accent circonflexe (accent hat), mark ^ placed above the letter
+
+export const chars = {
+  A: { key: "KeyQ", shift: true },
+  "Ä": { key: "KeyA", shift: true, accentKey: keyTrema },
+  "Â": { key: "KeyA", shift: true, accentKey: keyHat },
+  B: { key: "KeyB", shift: true },
+  C: { key: "KeyC", shift: true },
+  D: { key: "KeyD", shift: true },
+  E: { key: "KeyE", shift: true },
+  "Ë": { key: "KeyE", shift: true, accentKey: keyTrema },
+  "Ê": { key: "KeyE", shift: true, accentKey: keyHat },
+  F: { key: "KeyF", shift: true },
+  G: { key: "KeyG", shift: true },
+  H: { key: "KeyH", shift: true },
+  I: { key: "KeyI", shift: true },
+  "Ï": { key: "KeyI", shift: true, accentKey: keyTrema },
+  "Î": { key: "KeyI", shift: true, accentKey: keyHat },
+  J: { key: "KeyJ", shift: true },
+  K: { key: "KeyK", shift: true },
+  L: { key: "KeyL", shift: true },
+  M: { key: "Semicolon", shift: true },
+  N: { key: "KeyN", shift: true },
+  O: { key: "KeyO", shift: true },
+  "Ö": { key: "KeyO", shift: true, accentKey: keyTrema },
+  "Ô": { key: "KeyO", shift: true, accentKey: keyHat },
+  P: { key: "KeyP", shift: true },
+  Q: { key: "KeyA", shift: true },
+  R: { key: "KeyR", shift: true },
+  S: { key: "KeyS", shift: true },
+  T: { key: "KeyT", shift: true },
+  U: { key: "KeyU", shift: true },
+  "Ü": { key: "KeyU", shift: true, accentKey: keyTrema },
+  "Û": { key: "KeyU", shift: true, accentKey: keyHat },
+  V: { key: "KeyV", shift: true },
+  W: { key: "KeyZ", shift: true },
+  X: { key: "KeyX", shift: true },
+  Y: { key: "KeyY", shift: true },
+  Z: { key: "KeyW", shift: true },
+  a: { key: "KeyQ" },
+  "ä": { key: "KeyA", accentKey: keyTrema },
+  "â": { key: "KeyA", accentKey: keyHat },
+  b: { key: "KeyB" },
+  c: { key: "KeyC" },
+  d: { key: "KeyD" },
+  e: { key: "KeyE" },
+  "ë": { key: "KeyE", accentKey: keyTrema },
+  "ê": { key: "KeyE", accentKey: keyHat },
+  "€": { key: "KeyE", altRight: true },
+  f: { key: "KeyF" },
+  g: { key: "KeyG" },
+  h: { key: "KeyH" },
+  i: { key: "KeyI" },
+  "ï": { key: "KeyI", accentKey: keyTrema },
+  "î": { key: "KeyI", accentKey: keyHat },
+  j: { key: "KeyJ" },
+  k: { key: "KeyK" },
+  l: { key: "KeyL" },
+  m: { key: "Semicolon" },
+  n: { key: "KeyN" },
+  o: { key: "KeyO" },
+  "ö": { key: "KeyO", accentKey: keyTrema },
+  "ô": { key: "KeyO", accentKey: keyHat },
+  p: { key: "KeyP" },
+  q: { key: "KeyA" },
+  r: { key: "KeyR" },
+  s: { key: "KeyS" },
+  t: { key: "KeyT" },
+  u: { key: "KeyU" },
+  "ü": { key: "KeyU", accentKey: keyTrema },
+  "û": { key: "KeyU", accentKey: keyHat },
+  v: { key: "KeyV" },
+  w: { key: "KeyZ" },
+  x: { key: "KeyX" },
+  y: { key: "KeyY" },
+  z: { key: "KeyW" },
+  "²": { key: "Backquote" },
+  "&": { key: "Digit1" },
+  1: { key: "Digit1", shift: true },
+  "é": { key: "Digit2" },
+  2: { key: "Digit2", shift: true },
+  "~": { key: "Digit2", altRight: true },
+  "\"": { key: "Digit3" },
+  3: { key: "Digit3", shift: true },
+  "#": { key: "Digit3", altRight: true },
+  "'": { key: "Digit4" },
+  4: { key: "Digit4", shift: true },
+  "{": { key: "Digit4", altRight: true },
+  "(": { key: "Digit5" },
+  5: { key: "Digit5", shift: true },
+  "[": { key: "Digit5", altRight: true },
+  "-": { key: "Digit6" },
+  6: { key: "Digit6", shift: true },
+  "|": { key: "Digit6", altRight: true },
+  "è": { key: "Digit7" },
+  7: { key: "Digit7", shift: true },
+  "`": { key: "Digit7", altRight: true },
+  "_": { key: "Digit8" },
+  8: { key: "Digit8", shift: true },
+  "\\": { key: "Digit8", altRight: true },
+  "ç": { key: "Digit9" },
+  9: { key: "Digit9", shift: true },
+  "^": { key: "Digit9", altRight: true },
+  "à": { key: "Digit0" },
+  0: { key: "Digit0", shift: true },
+  "@": { key: "Digit0", altRight: true },
+  ")": { key: "Minus" },
+  "°": { key: "Minus", shift: true },
+  "]": { key: "Minus", altRight: true },
+  "=": { key: "Equal" },
+  "+": { key: "Equal", shift: true },
+  "}": { key: "Equal", altRight: true },
+  "$": { key: "BracketRight" },
+  "£": { key: "BracketRight", shift: true },
+  "¤": { key: "BracketRight", altRight: true },
+  "ù": { key: "Quote" },
+  "%": { key: "Quote", shift: true },
+  "*": { key: "Backslash" },
+  "µ": { key: "Backslash", shift: true },
+  ",": { key: "KeyM" },
+  "?": { key: "KeyM", shift: true },
+  ";": { key: "Comma" },
+  ".": { key: "Comma", shift: true },
+  ":": { key: "Period" },
+  "/": { key: "Period", shift: true },
+  "!": { key: "Slash" },
+  "§": { key: "Slash", shift: true },
+  "<": { key: "IntlBackslash" },
+  ">": { key: "IntlBackslash", shift: true },
+  " ": { key: "Space" },
+  "\n": { key: "Enter" },
+  Enter: { key: "Enter" },
+  Tab: { key: "Tab" },
+} as Record<string, KeyCombo>;