diff --git a/include/keyboard.js b/include/keyboard.js
index 342f806e63792db681571e0b7446c1b86a6abaa7..623d5b293c96c51605e0987e65ee711812bb956d 100644
--- a/include/keyboard.js
+++ b/include/keyboard.js
@@ -1,6 +1,22 @@
 var kbdUtil = (function() {
     "use strict";
 
+    function substituteCodepoint(cp) {
+        // Any Unicode code points which do not have corresponding keysym entries
+        // can be swapped out for another code point by adding them to this table
+        var substitutions = {
+            // {S,s} with comma below -> {S,s} with cedilla
+            0x218 : 0x15e,
+            0x219 : 0x15f,
+            // {T,t} with comma below -> {T,t} with cedilla
+            0x21a : 0x162,
+            0x21b : 0x163
+        };
+
+        var sub = substitutions[cp];
+        return sub ? sub : cp;
+    };
+
     function isMac() {
         return navigator && !!(/macintosh/i).exec(navigator.appVersion);
     }
@@ -156,7 +172,7 @@ var kbdUtil = (function() {
         }
 
         if (codepoint) {
-            var res = keysyms.fromUnicode(codepoint);
+            var res = keysyms.fromUnicode(substituteCodepoint(codepoint));
             if (res) {
                 return res;
             }
@@ -258,7 +274,8 @@ var kbdUtil = (function() {
         getKey : getKey,
         getKeysym : getKeysym,
         keysymFromKeyCode : keysymFromKeyCode,
-        nonCharacterKey : nonCharacterKey
+        nonCharacterKey : nonCharacterKey,
+        substituteCodepoint : substituteCodepoint
     };
 })();
 
diff --git a/tests/test.helper.js b/tests/test.helper.js
index cb6d88bca6a338a12e46e65ffd4efbfa446ca796..d6a68cd9ada271176237d62a1d4b12053f1f8a23 100644
--- a/tests/test.helper.js
+++ b/tests/test.helper.js
@@ -42,6 +42,18 @@ describe('Helpers', function() {
         });
     });
 
+    describe('substituteCodepoint', function() {
+        it('should replace characters which don\'t have a keysym', function() {
+            expect(kbdUtil.substituteCodepoint('Ș'.charCodeAt())).to.equal('Ş'.charCodeAt());
+            expect(kbdUtil.substituteCodepoint('È™'.charCodeAt())).to.equal('ÅŸ'.charCodeAt());
+            expect(kbdUtil.substituteCodepoint('Èš'.charCodeAt())).to.equal('Å¢'.charCodeAt());
+            expect(kbdUtil.substituteCodepoint('È›'.charCodeAt())).to.equal('Å£'.charCodeAt());
+        });
+        it('should pass other characters through unchanged', function() {
+            expect(kbdUtil.substituteCodepoint('T'.charCodeAt())).to.equal('T'.charCodeAt());
+        });
+    });
+
     describe('nonCharacterKey', function() {
         it('should  recognize the right keys', function() {
             expect(kbdUtil.nonCharacterKey({keyCode: 0xd}), 'enter').to.be.defined;
@@ -77,6 +89,9 @@ describe('Helpers', function() {
             expect(kbdUtil.getKeysym({which: 0x43, shiftKey: false})).to.have.property('keysym', 0x63);
             expect(kbdUtil.getKeysym({which: 0x43, shiftKey: true})).to.have.property('keysym', 0x43);
         });
+        it('should substitute where applicable', function() {
+            expect(kbdUtil.getKeysym({char : 'Ș'})).to.have.property('keysym', 0x1aa);
+        });
     });
 
     describe('Modifier Sync', function() { // return a list of fake events necessary to fix modifier state