Skip to content

Commit 174a701

Browse files
committed
Support for targetId added in getTypingPattern()
1 parent b5882be commit 174a701

3 files changed

Lines changed: 1324 additions & 94 deletions

File tree

README.md

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
# TypingDNA JavaScript recorder
2-
##### A simple way to record typing patterns
2+
##### A simple way to capture user’s typing patterns
33
Full documentation at [api.typingdna.com](https://api.typingdna.com)*
44

55
### Usage and description
6-
First create an instance of the TypingDNA class. Once it's done, the user typing starts being recorded (as a history of strokes). Whenever you want to get the user's typing pattern you have to invoke .getTypingPattern method described in detail below.
6+
First you need to import the [typingdna.js](https://typingdna.com/scripts/typingdna.js) file in the page that wants to record a typing pattern. You will need to record typing patterns when a user first creates his account and again whenever you want to authenticate that user on your platform. You can host the .js file yourself.
7+
8+
Alternative locations from where you can include the last class:
9+
* https://typingdna.com/scripts/typingdna.js
10+
* https://api.typingdna.com/scripts/typingdna.js
11+
12+
### TypingDNA class
13+
14+
Once you create an instance of the TypingDNA class, the user typing starts being recorded (as a history of strokes). Whenever you want to get the user's typing pattern you have to invoke .getTypingPattern method described in detail below.
715

816
**Returns**: Returns the instance of the TypingDNA class (singleton)
917

@@ -28,7 +36,7 @@ This is the main function that outputs the user's typing pattern as a `String`
2836

2937
**Returns**: A typing pattern in `String` form
3038

31-
**optionsObject**: An object of the following form {type:Number, text:String, textId:Number, length: Number, extended:Boolean}. Detail table below.
39+
**optionsObject**: An object of the following form {type:Number, text:String, textId:Number, length: Number, extended:Boolean, targetId:String}. Detail table below.
3240

3341
| Param | Type | Description |
3442
| --- | --- | --- |
@@ -37,6 +45,7 @@ This is the main function that outputs the user's typing pattern as a `String`
3745
| **textId** | `Number` | (Optional, only for type 1) a personalized id for the typed text |
3846
| **length** | `Number` | (Optional) the length of the text in the history for which you want the typing pattern, for type 0 is usually 140 or more |
3947
| **extended** | `Boolean` | (Only for type 1) specifies if full information about what was typed is produced, including the actual key pressed, if false, only the order of pressed keys is kept (no actual content) |
48+
| **targetId** | `String` | (Optional) specifies if pattern is obtain only from text typed in a certain target |
4049

4150
**Examples**
4251
```js
@@ -48,7 +57,7 @@ var generalPattern = tdna.getTypingPattern({type=0, length=160});
4857
### TypingDNA.addTarget(element_id)
4958
(Optional) Adds a target to the targetIds array. It has to be a text input or text area or any other HTML DOM element that has the .value property. You can add multiple targets (such as username and password fields).
5059

51-
If you omit adding targets the typing patterns will be outputed for the entire typing session.
60+
If you omit adding targets the typing patterns will be recorded for the entire typing session.
5261

5362
**Example**
5463
```js

typingdna.js

Lines changed: 80 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* https://api.typingdna.com/scripts/typingdna.js
44
* https://typingdna.com/scripts/typingdna.js (alternative)
55
*
6-
* @version 2.9
6+
* @version 2.11
77
* @author Raul Popa
88
* @copyright SC TypingDNA SRL, http://typingdna.com
99
* @license http://www.apache.org/licenses/LICENSE-2.0
@@ -20,8 +20,8 @@
2020
*
2121
* Typical usage:
2222
* var tdna = new TypingDNA(); // creates a new TypingDNA object and starts recording
23-
* var typingPattern = tdna.get(); // returns a typing pattern (and continues recording afterwards),
24-
* optionally you can pass a length, tdna.get(200) will return the pattern based on the last 200 key events.
23+
* var typingPattern = tdna.getTypingPattern({type=1, text="Hello5g21?*", extedend=false});
24+
* returns a type 1 typing pattern (and continues recording afterwards)
2525
*
2626
* Optional:
2727
* tdna.stop(); // ends recording and clears history stack (returns recording flag: false)
@@ -97,7 +97,7 @@ function TypingDNA() {
9797
TypingDNA.prototype.defaultHistoryLength = TypingDNA.defaultHistoryLength;
9898
TypingDNA.prototype.maxSeekTime = TypingDNA.maxSeekTime;
9999
TypingDNA.prototype.maxPressTime = TypingDNA.maxPressTime;
100-
TypingDNA.version = 2.9;
100+
TypingDNA.version = 2.11;
101101
TypingDNA.flags = 0;
102102
TypingDNA.instance = this;
103103
TypingDNA.document = document;
@@ -159,6 +159,9 @@ function TypingDNA() {
159159
return;
160160
}
161161
var keyCode = e.keyCode;
162+
if (TypingDNA.wfk[keyCode] == 1 || TypingDNA.dwfk[keyCode] == 1) {
163+
//return;
164+
}
162165
if (keyCode == 229 && TypingDNA.isMobile() && !TypingDNA.isAndroidChrome) {
163166
TypingDNA.isAndroidChrome = true;
164167

@@ -222,7 +225,7 @@ function TypingDNA() {
222225
if (TypingDNA.wfk[keyCode] == 1) {
223226
var pressTime = ut - TypingDNA.sti[keyCode];
224227
var seekTime = TypingDNA.skt[keyCode];
225-
var arr = [keyCode, seekTime, pressTime, TypingDNA.prevKeyCode, ut];
228+
var arr = [keyCode, seekTime, pressTime, TypingDNA.prevKeyCode, ut, e.target.id];
226229
TypingDNA.history.add(arr);
227230
TypingDNA.prevKeyCode = keyCode;
228231
}
@@ -235,7 +238,7 @@ function TypingDNA() {
235238
var pressTime = ut - TypingDNA.dsti[keyCode];
236239
var seekTime = TypingDNA.dskt[keyCode];
237240
var realKeyCode = TypingDNA.drkc[keyCode];
238-
var arrD = [keyCode, seekTime, pressTime, realKeyCode];
241+
var arrD = [keyCode, seekTime, pressTime, realKeyCode, ut, e.target.id];
239242
TypingDNA.history.addDiagram(arrD);
240243
}
241244
}
@@ -584,6 +587,7 @@ function TypingDNA() {
584587
* Automatically called at initilization. It starts the recording of keystrokes.
585588
*/
586589
TypingDNA.start = function() {
590+
TypingDNA.diagramRecording = true;
587591
return TypingDNA.recording = true;
588592
}
589593

@@ -592,6 +596,7 @@ function TypingDNA() {
592596
* either call TypingDNA.start() or create a new TypingDNA object again, not recommended.
593597
*/
594598
TypingDNA.stop = function() {
599+
TypingDNA.diagramRecording = false;
595600
return TypingDNA.recording = false;
596601
}
597602

@@ -609,45 +614,34 @@ function TypingDNA() {
609614
return TypingDNA.mouseRecording = TypingDNA.mouseMoveRecording = false;
610615
}
611616

612-
/**
613-
* Starts the recording of a non-fixed diagram typing pattern.
614-
*/
615-
TypingDNA.startDiagram = function() {
616-
return TypingDNA.diagramRecording = true;
617-
}
618-
619-
/**
620-
* Ends the recording of a non-fixed diagram typing pattern.
621-
*/
622-
TypingDNA.stopDiagram = function() {
623-
return TypingDNA.diagramRecording = false;
624-
}
625-
626617
/**
627618
* This is the main function that outputs the typing pattern as a String
628-
* {type:Number, text:String, textId:Number, length: Number, extended:Boolean}
619+
* {type:Number, text:String, textId:Number, length: Number, extended:Boolean, targetId:String}
629620
* @param {Object} obj an object with the following properties
630621
* * * @param {String} type 0 for standard pattern, 1 for diagram pattern
631-
* * * @param {Number} length (Optional) the length of the text in the history for which you want the typing pattern
622+
* * * @param {Number} length (Optional) the length of the text in the history for which you want
623+
* * * the typing pattern. length is ignored when text or targetId is set (or both).
632624
* * * @param {String} text (Only for type 1) a typed string that you want the typing pattern for
633625
* * * @param {Number} textId (Optional, only for type 1) a personalized id for the typed text
634626
* * * @param {Boolean} extended (Only for type 1) specifies if full information about what was typed is produced,
635627
* * * including the actual key pressed, if false, only the order of pressed keys is kept (no actual content)
628+
* * * @param {String} targetId (Optional) specifies if pattern is obtain only from text typed in a certain target
636629
* @return {String} A typing pattern in string form
637-
* @example var typingPattern = tdna.getDiagram();
638-
* @example var typingPattern = tdna.getDiagram("Hello5g21?*");
630+
* @example var typingPattern = tdna.getTypingPattern({type=1, length=160, extended=true});
631+
* @example var typingPattern = tdna.getTypingPattern({type=1, text="Hello5g21?*", extedend=false});
632+
* @example var typingPattern = tdna.getTypingPattern({type=0, length=180});
639633
*/
640634
TypingDNA.getTypingPattern = function(obj) {
641635
if (typeof obj === 'object') {
642636
switch (obj.type) {
643637
case 0:
644-
return TypingDNA.get(obj.length);
638+
return TypingDNA.get(obj.length, obj.targetId);
645639
break;
646640
case 1:
647641
if (obj.text != undefined) {
648-
return TypingDNA.history.getDiagram(obj.extended, obj.text, obj.textId);
642+
return TypingDNA.history.getDiagram(obj.extended, obj.text, obj.textId, obj.targetId);
649643
} else {
650-
return TypingDNA.history.getDiagram(obj.extended, obj.length, obj.textId);
644+
return TypingDNA.history.getDiagram(obj.extended, obj.length, obj.textId, obj.targetId);
651645
}
652646
break;
653647
default:
@@ -659,33 +653,10 @@ function TypingDNA() {
659653
}
660654
}
661655

662-
/**
663-
* This function outputs the linear diagram typing pattern as a String
664-
* @param {String} str Optional: The string represented by the diagram
665-
* The function checks for the exact string (with minor typos) in the recorded
666-
* history. Any letters that are not included in the string will be ommited from
667-
* the output diagram typing pattern.
668-
* @return {String} The TypingDNA linear diagram typing pattern, comma separated.
669-
* A non-fixed vector of only numeric values separated by commas.
670-
* @example var typingPattern = tdna.getDiagram();
671-
* @example var typingPattern = tdna.getDiagram("Hello5g21?*");
672-
*/
673656
TypingDNA.getDiagram = function(str, textId) {
674657
return TypingDNA.history.getDiagram(false, str, textId);
675658
}
676659

677-
/**
678-
* This function outputs the extended linear diagram typing pattern as a String
679-
* Compared to getDiagram, it includes char codes (not safe for storage)
680-
* @param {String} str Optional: The string represented by the diagram
681-
* The function checks for the exact string (with minor typos) in the recorded
682-
* history. Any letters that are not included in the string will be ommited from
683-
* the output diagram typing pattern.
684-
* @return {String} The TypingDNA linear diagram typing pattern, comma separated.
685-
* A non-fixed vector of only numeric values separated by commas.
686-
* @example var typingPattern = tdna.getExtendedDiagram();
687-
* @example var typingPattern = tdna.getExtendedDiagram("Hello5g21?*");
688-
*/
689660
TypingDNA.getExtendedDiagram = function(str, textId) {
690661
return TypingDNA.history.getDiagram(true, str, textId);
691662
}
@@ -694,32 +665,23 @@ function TypingDNA() {
694665
return TypingDNA.mouse.history.getDiagram();
695666
}
696667

697-
/**
698-
* This function outputs the typing pattern as a String, in a new basic structure for
699-
* easy storage and usage in any kind of keystroke dynamics applications (e.g. typing
700-
* pattern matching, user recognition)
701-
* @param {Number} length Optional: The amount of history keystrokes to use for the
702-
* typing pattern. By default it will use the last 500 recorded keystrokes (or as many
703-
* available if less than 500).
704-
* @return {String} The TypingDNA typing pattern, comma separated.
705-
* A fixed vector of only numeric values separated by commas.
706-
* @example var typingPattern = tdna.get();
707-
* @example var typingPattern = tdna.get(200);
708-
*/
709-
TypingDNA.get = function(length) {
668+
TypingDNA.get = function(length, targetId) {
710669
var historyTotalLength = TypingDNA.history.stack.length;
711-
if (length == undefined) {
670+
if (length == undefined || length == 0) {
712671
length = TypingDNA.defaultHistoryLength;
713672
}
714673
if (length > historyTotalLength) {
715674
length = historyTotalLength;
716675
}
717676
var obj = {};
718-
obj.arr = TypingDNA.history.get(length);
677+
[obj.arr, targetLength] = TypingDNA.history.get(length, "", targetId);
678+
if (targetId != undefined && targetId != "") {
679+
length = targetLength;
680+
}
719681
var zl = TypingDNA.zl;
720682
var histRev = length;
721-
var histSktF = TypingDNA.math.fo(TypingDNA.history.get(length, "seek"));
722-
var histPrtF = TypingDNA.math.fo(TypingDNA.history.get(length, "press"));
683+
var histSktF = TypingDNA.math.fo(TypingDNA.history.get(length, "seek", targetId));
684+
var histPrtF = TypingDNA.math.fo(TypingDNA.history.get(length, "press", targetId));
723685
var pressHistMean = Math.round(TypingDNA.math.avg(histPrtF));
724686
var seekHistMean = Math.round(TypingDNA.math.avg(histSktF));
725687
var pressHistSD = Math.round(TypingDNA.math.sd(histPrtF));
@@ -911,27 +873,39 @@ function TypingDNA() {
911873
this.stackDiagram.push(arr);
912874
}
913875

914-
TypingDNA.history.getDiagram = function(extended, str, textId) {
876+
TypingDNA.history.getDiagram = function(extended, str, textId, targetId) {
915877
var returnArr = [];
916878
var diagramType = (extended == true) ? 1 : 0;
917-
var diagramHistoryLength = this.stackDiagram.length;
918-
var targetLength = TypingDNA.targetIds.length;
919-
var missingCount = 0;
920-
if (str == undefined){
921-
if(targetLength > 0) {
922-
str = "";
923-
for (var i = 0; i < targetLength; i++) {
924-
var element = TypingDNA.document.getElementById(TypingDNA.targetIds[i]);
925-
if (element != null) {
926-
str += element.value;
927-
}
879+
var stackDiagram = this.stackDiagram;
880+
if (targetId != undefined && targetId != "" && stackDiagram.length > 0) {
881+
stackDiagram = TypingDNA.sliceStackByTargetId(stackDiagram, targetId);
882+
if (str == undefined || str == ""){
883+
var element = TypingDNA.document.getElementById(targetId);
884+
if (element != null) {
885+
str = element.value;
928886
}
929-
} else {
930-
if (!extended) {
931-
console.log("Please use extended diagram OR provide a fixed string param OR use the addTarget method.");
887+
}
888+
} else {
889+
var targetLength = TypingDNA.targetIds.length;
890+
if (str == undefined || str == ""){
891+
if(targetLength > 0) {
892+
str = "";
893+
for (var i = 0; i < targetLength; i++) {
894+
var element = TypingDNA.document.getElementById(TypingDNA.targetIds[i]);
895+
if (element != null) {
896+
str += element.value;
897+
}
898+
}
899+
} else {
900+
if (!extended) {
901+
console.log("Please use extended diagram OR provide a fixed string param OR use the addTarget method.");
902+
}
932903
}
933904
}
934905
}
906+
907+
var missingCount = 0;
908+
var diagramHistoryLength = stackDiagram.length;
935909
var strLength = diagramHistoryLength;
936910
if (typeof str === 'string') {
937911
strLength = str.length;
@@ -963,7 +937,7 @@ function TypingDNA() {
963937
var found = false
964938
while (found == false){
965939
for (var j = startPos; j < finishPos; j++) {
966-
var arr = this.stackDiagram[j];
940+
var arr = stackDiagram[j];
967941
var charCode = arr[3];
968942
if (charCode == currentCharCode) {
969943
found = true;
@@ -1032,7 +1006,7 @@ function TypingDNA() {
10321006
startCount = 0;
10331007
}
10341008
for (var i = startCount; i < diagramHistoryLength; i++) {
1035-
var arr = this.stackDiagram[i];
1009+
var arr = stackDiagram[i];
10361010
var keyCode = arr[0];
10371011
var seekTime = arr[1];
10381012
var pressTime = arr[2];
@@ -1047,8 +1021,24 @@ function TypingDNA() {
10471021
return returnArr.join("|");
10481022
}
10491023

1050-
TypingDNA.history.get = function(length, type) {
1051-
var historyTotalLength = this.stack.length;
1024+
TypingDNA.sliceStackByTargetId = function(stack, targetId){
1025+
var length = stack.length;
1026+
var newStack = [];
1027+
for (i = 0; i < length; i++) {
1028+
var arr = stack[i];
1029+
if (arr[5] == targetId){
1030+
newStack.push(arr);
1031+
}
1032+
}
1033+
return newStack;
1034+
}
1035+
1036+
TypingDNA.history.get = function(length, type, targetId) {
1037+
var stack = this.stack;
1038+
if (targetId != undefined && targetId != "" && stack.length > 0) {
1039+
stack = TypingDNA.sliceStackByTargetId(stack, targetId);
1040+
}
1041+
var historyTotalLength = stack.length;
10521042
if (length == 0 || length == undefined) {
10531043
length = TypingDNA.defaultHistoryLength;
10541044
}
@@ -1059,7 +1049,7 @@ function TypingDNA() {
10591049
case "seek":
10601050
var seekArr = [];
10611051
for (i = 1; i <= length; i++) {
1062-
var seekTime = this.stack[historyTotalLength - i][1];
1052+
var seekTime = stack[historyTotalLength - i][1];
10631053
if (seekTime <= TypingDNA.maxSeekTime) {
10641054
seekArr.push(seekTime);
10651055
}
@@ -1069,7 +1059,7 @@ function TypingDNA() {
10691059
case "press":
10701060
var pressArr = [];
10711061
for (i = 1; i <= length; i++) {
1072-
var pressTime = this.stack[historyTotalLength - i][2];
1062+
var pressTime = stack[historyTotalLength - i][2];
10731063
if (pressTime <= TypingDNA.maxPressTime) {
10741064
pressArr.push(pressTime);
10751065
}
@@ -1086,7 +1076,7 @@ function TypingDNA() {
10861076
];
10871077
}
10881078
for (i = 1; i <= length; i++) {
1089-
var arr = this.stack[historyTotalLength - i];
1079+
var arr = stack[historyTotalLength - i];
10901080
var keyCode = arr[0];
10911081
var seekTime = arr[1];
10921082
var pressTime = arr[2];
@@ -1103,7 +1093,7 @@ function TypingDNA() {
11031093
}
11041094
}
11051095
};
1106-
return historyStackObj;
1096+
return [historyStackObj, length];
11071097
}
11081098
}
11091099

0 commit comments

Comments
 (0)