Neurological problems, such as stroke, can display early symptoms such as Hemiparesis, which leads to extreme differences in the motor ability of different sides of the body. Hence, the dexterity of each hand is also impacted. Abnormally poor performance of one hand in comparison to the other can reveal signs of a stroke corresponding to the opposite side of the brain. By using an analysis of an individual’s textual input and typing style, due to multiple factors, the performance of each hand can be examined to diagnose early indications of stroke.
Introduction
Introduction
The following essay will use language analysis with the ultimate goal of determining whether the textual input is likely indicative of displaying stroke synonyms. Hemiparesis is a condition manifested in one-sided muscle weakness, typically a consequence of deeper neurological issues. Accordingly, in many cases, occurrences of Hemiparesis can be reflective of a stroke corresponding to the opposite side of the brain as the occurrence of the hemiparesis, and should be addressed with urgency. The hemiparesis results in poor dexterity in one hand, leading to differences in their performance.
However, a typo can manifest itself in a plethora of manners- it is insufficient to simply scan through the dictionary and determine what word the typo was most likely supposed to be using a function like “Nearest[]”. In some cases, the typo could be obvious, however, the likelihood that there is only one possible word that a typo could have been is improbable. Furthermore, to be realistically applicable, it should also be considered that certain words might simply be difficult to spell, and therefore, the typo might be a result of imperfect spelling, rather than paralysis. Due to the fact that all these factors, amongst others, contribute to the significance of a typo in our analysis, a nuanced approach must be taken to acknowledge them all.
However, a typo can manifest itself in a plethora of manners- it is insufficient to simply scan through the dictionary and determine what word the typo was most likely supposed to be using a function like “Nearest[]”. In some cases, the typo could be obvious, however, the likelihood that there is only one possible word that a typo could have been is improbable. Furthermore, to be realistically applicable, it should also be considered that certain words might simply be difficult to spell, and therefore, the typo might be a result of imperfect spelling, rather than paralysis. Due to the fact that all these factors, amongst others, contribute to the significance of a typo in our analysis, a nuanced approach must be taken to acknowledge them all.
Detecting Typos
Detecting Typos
To approach performance assessment, the accuracy of the inputted text had to be analyzed through typo detection. The purpose of this is to analyze for extreme disparities in typing performance between the two hands. It is based on user given input, and this input can pertain to any topic of the users choice- therefore, each word must be analyzed in the context of its sentence to search for typos. This is where GPT-2 was called to search for typos by analysing words. Every word had to be taken with consideration to the part of the section of the sentence preceding it.
The function below initialized a function passing an intended string “x” as a parameter, while calling the GPT-2 model integrated into Wolfram. It then generates the Top 100 words the model predicts should follow the inputted string, based on its context.
In[]:=
generateTopWords[x_]:=NetModel[{"GPT-2 Transformer Trained on WebText Data","Task"->"LanguageModeling"}][x,{"TopProbabilities",100}]
This function had to be called for essentially every word in the user’s complete input (with the exception of the initial two, as they could not provide enough context for the GPT-2 model to predict the following word with accuracy).
This function parts each input by starting with the initial word, and using a Table to iterate through the input, consistently adding one more word to the partition, eventually outputting a list of each section. An example execution of the inputted string “The Earth is a planet” is displayed below.
In[]:=
goThruSentence[input_]:= Module[{currString = "",sentenceParts},sentenceParts = StringSplit[input];currString = sentenceParts[[1]]; Table[ currString = StringJoin[currString, " ", StringSplit[input][[i+1]]], {i, WordCount[input]-1} ]]
goThruSentence["The Earth is a planet"]
(Debug) Out[]=
{The Earth,The Earth is,The Earth is a,The Earth is a planet}
This is synthesized in the checkForTypo function, which determines whether or not a given word is a typo based on the sentence preceding it (each of which are passed as parameters).
Generates the Top 100 predictions for a sentence fragment using generateTopWords, and then converts that into an Association. Next, uses NumberQ to check if the probability associated with the next word exists in the GPT generated predictions, and therefore, if the word is in that prediction set. If True is returned, it is assumed that the word makes sense in its context, otherwise, the model flags that word as a typo.
In[]:=
checkForTypo[preceeding_,word_]:=Module[{partPredictions},partPredictions=Association@generateTopWords[preceeding];NumberQ[partPredictions[[" "<>word]]]]
This returns True or False, where True means there is not a typo. It will late be called as an entire text input is evaluated by the model.
Determining Typo Correction
Determining Typo Correction
Once it has been determined that a word is a typo, the model needs to decide what word the user meant to enter. As previously mentioned, due to the nature of this project, the model must settle upon one “correct” word to replace the typo, which it can base its analysis off , unlike an autocorrect model that has more leeway to suggest a couple top possibilities. Because of this, we had to consider a variety of factors that could have contributed to the typo, and weight each of them to ultimately settle on the correct word.
The first one that came to mind was the distance between keys on a standard QWERTY keyboard- it would be much less likely for someone to accidentally type a key the entire distance across the keyboard than for them to accidentally hit the key right next to what they were striving for. Furthermore, for a patient with decreased dexterity, this movement would become even more improbable, and thus, the physical distance between the mistyped keys on the keyboard was one of the heaviest factors we took into consideration.
To analyze and calculate this distance, a 3 by 10 array was created containing major characters on the keyboard (however, it did omit numbers). While there exists a horizontal offset between the different rows on the keyboard, this shift has nominal impact on the actual distance between keys. Since we are not calculating where on the key the user clicked, the shortest distance between any point on a specific key to its direct neighbors is relatively the same, regardless of the offset. A simple calculation using Pythagorean Theorem can therefore be made to get a gauge of the distance between points on two different keys.
The first one that came to mind was the distance between keys on a standard QWERTY keyboard- it would be much less likely for someone to accidentally type a key the entire distance across the keyboard than for them to accidentally hit the key right next to what they were striving for. Furthermore, for a patient with decreased dexterity, this movement would become even more improbable, and thus, the physical distance between the mistyped keys on the keyboard was one of the heaviest factors we took into consideration.
To analyze and calculate this distance, a 3 by 10 array was created containing major characters on the keyboard (however, it did omit numbers). While there exists a horizontal offset between the different rows on the keyboard, this shift has nominal impact on the actual distance between keys. Since we are not calculating where on the key the user clicked, the shortest distance between any point on a specific key to its direct neighbors is relatively the same, regardless of the offset. A simple calculation using Pythagorean Theorem can therefore be made to get a gauge of the distance between points on two different keys.
calculateDistance takes in two keys as parameters to calculate the distance between. The keyboard grid is initialized as seen, and the Pythagorean theorem is applied under the scale that the distance between a key and its direct neighbor up/down/left/right is 1 unit.
In[]:=
calculateDistance[x_,y_]:=Module[{keyboard={{"q","w","e","r","t","y","u","i","o","p"},{"a","s","d","f","g","h","j","k","l",";"},{"z","x","c","v","b","n","m",",",".","/"}}},Sqrt[Total[(First@Position[keyboard,x]-First@Position[keyboard,y])^2]]]
After the keyboard grid had been established, a function was written to calculate the distance on the keyboard between two words. It considers both the cases where the words are equivalent in length, and also when they are not. A study by Peterson examining a set of 988,192 typing errors found that over 63% of these typos were the same length as the word meant to be typed. This is why extra/missing letters were more heavily weighted and the difference in length between the words was doubled to produce a score for these cases.
The conditional checks for length equivalency between the two words, passed as parameters. If they are the same length, it picks out what characters differ, and calculated the distance between character pairs. These distances are all totalled. If they are of unequal length, it assigns a blanket addition for every extra letter (or every missing letter). The function calls calculateDistance after comparing each character.
In[]:=
offCharacters[x_, y_] := Module[{dist},If[StringLength[x]== StringLength[y], dist = calculateDistance @@@ Select[ Transpose[{Characters[ToLowerCase[x]], Characters[ToLowerCase[y]]}], #[[1]] =!= #[[2]] &]; Total[dist], dist = 2*Abs[StringLength[x]-StringLength[y]] ] ]
Example for equal length:
(Debug) In[]:=
offCharacters["hing","hang"]
(Debug) Out[]=
5
2
Example for unequal length:
(Debug) In[]:=
offCharacters["hing","hinge"]
(Debug) Out[]=
2
To improve the accuracy of the predictions, the typo also had to be considered in the context of its sentence. Once again, the GPT-2 model was called to achieve this. The GPT-2 model was used in a similar way as when it had been checking whether or not a word was a typo. Immediately, when a word was flagged as a typo, the GPT-2 model generated the Top 100 words most likely to follow the sentence preceding the typo. This again utilizes the aforementioned generateTopWords[] function.
To recall, an execution of generateTopWords[] for the input parameter “My favorite winter activity is” can be seen below.
generateTopWords["My favorite winter activity is"]
(Debug) Out[]=
{ gardening0.00131076, ro0.00132027, pe0.0013274, writing0.00132847, growing0.00134451, sc0.00135153, traveling0.00136871, camp0.00136992, seeing0.00137744, sun0.00142088, planting0.00146049, pulling0.00148132, digging0.00151989, wearing0.00153405, exploring0.00153538, this0.00155854, hiber0.00155874, sailing0.00157455, cutting0.00157691, spring0.00159396, that0.00160442, an0.0016181, outdoor0.00171694, back0.00172796, holding0.00173277, spending0.00176306, doing0.00178156, at0.00178159, gathering0.0018457, throwing0.00185669, for0.00188607, keeping0.00189136, "0.00191084, always0.00191642, my0.00194321, staying0.00196987, actually0.00203347, with0.00207287, coming0.00209246, cycling0.00218458, trying0.00219275, not0.00223603, on0.00234227, finding0.00234738, cold0.00241286, knitting0.00247364, putting0.00251304, shovel0.00251497, picking0.00255306, shooting0.00255944, carving0.00266379, having0.0027238, h0.00275877, sleeping0.00283207, simply0.00288002, sk0.0030282, eating0.00319157, skating0.00322594, falling0.00330108, baking0.00339477, working0.00367592, biking0.0036936, winter0.0037303, reading0.0038169, catching0.00396465, driving0.00397761, just0.00402079, using0.00417286, jumping0.00423809, being0.00425374, hunting0.00429158, in0.00429965, freezing0.00462046, cooking0.00480045, sn0.00484826, sled0.00527604, standing0.00543593, sitting0.00635098, hanging0.00660125, ice0.00725542, fishing0.00732182, making0.0078144, swimming0.00784792, running0.00786578, camping0.00823346, climbing0.00884549, riding0.0104747, taking0.0106425, watching0.010664, a0.0134886, going0.0146018, when0.0146518, getting0.0146901, playing0.0161099, walking0.0189756, hiking0.0363729, snow0.039194, the0.0543641, skiing0.0550822, to0.0791506}
The outputs are ordered so that the bottom right has the word with the highest probability, and that probability continuously decreases as we move leftward and up through the list. As evident, a word like “gardening”, which is the 100th most likely word according to GPT-2, with a probability of around 0.13%, ranks much lower than “skiing”, the 2nd highest prediction, with a probability of approximately 5.5%. Theoretically, if the list were to be extended infinitely, all the probabilities should sum to 100.
Finally, after physical distance and contextual probability were taken into consideration, another factor that was incorporated was the distance between two words. This time, it was not the physical distance, rather the Levenshtein distance. The Levenshtein distance between two strings returns the number of single character manipulations (additions, deletions, substitutions) that are made to get from one of the strings to another. Again, it is much more likely for the user to have intended to type a word where 1 or 2 letters are amiss, than a word where every single letter was typed horribly wrong, or the words were incredibly different in length. The words with a minimized Levenshtein distance to the typo should have heavier weight than those with larger Levenshtein distances. Thankfully, a function exists in the Wolfram language to do just that: the Nearest[] function can output the words from a given list with the smallest Levenshtein distance to a specified word.
Scoring Correction Possibilities
Scoring Correction Possibilities
Now, all these functions had to come together to actually assign scores to different possibilities that might replace the flagged typo. Note that decreased distances between mistype characters on a keyboard and lower Levenshtein distances between words both indicated higher likelihood for a certain possibility to be the actual replacement for the typo. On the other hand, a high probability given by GPT-2 was a sign of higher likelihood. Ultimately, it was decided that a lower score for any given possibility would make it more likely to be the correct replacement for a typo- due to this, the probabilities outputted by GPT-2 were instead subtracted from 1, so that a higher probability would actually yield an overall lower score, and fit into the model. Furthermore, since GPT-2 can occasionally be inconsistent in its predictions, especially if the context given by the words before the typo is difficult to understand, both cases where the possible replacement existed in GPT-2’s Top 100 predictions, and also the case where it did not, were considered.
evaluateWord[] takes in the typo, one of the possible replacements, and an input of the GPT-2 predictions for the context as parameters. The score calculations for the keyboard and Levenshtein distances are constant for all words. For the GPT-2 score, its assigned probability is used if the word exists in the predictions. Otherwise, a constant of 0.9 is added. the weights for factors can be seen below.
In[]:=
evaluateWord[typo_, option_, input_]:= Module[{gpt = Association[Thread[Map[StringDelete[" "],Keys@Association@input]->Values@Association@input]], gptWords=StringDelete[" "]@Keys@Association@input,initialSum = 0.1*offCharacters[typo, option]+EditDistance[typo, option]},If[ContainsAny[gptWords,{option}],{initialSum+1-(2*gpt[[option]]),option},{initialSum+initialSum+0.9,option}]]
Once the function can calculate a score given a single typo and specific correction, along with the GPT-2 predictions, that needs to be done for every possible option the model looks at for a single typo. The words the model will evaluate tie back to the Levenshtein distance. By calling Nearest[] , the model chooses the 100 words with the closest Levenshtein distance to the typo, and this becomes the list of words that will all be scored to ultimately settle upon the correction. The model also chooses the one word deduced to be the correct substitution.
After options are generated through Nearest, evaluateFunction[] is repeatedly called for the typo, with every element in options, each of which is scored. Then, the minimum score is found from all the evaluated scores, and the function returns the score along with the word the score corresponds to.
In[]:=
scoresWord[typo_, input_]:= Module[{options, gptProbs, initialsums},options = Nearest[WordList[], typo, 100];gptProbs = generateTopWords[input];Flatten[Table[evaluateWord[typo, options[[i]], gptProbs],{i,50}][[PositionSmallest[Table[evaluateWord[typo, options[[i]], gptProbs][[1]],{i,100}]]]]]]
Now, the function has successfully determined the corrected word that was meant to replace the typo. To bring it together, the same thing must be done for every single typo in a sentence. The input must be partitioned into the context sentences, and split into individual words. These then need to be scanned to flag typos, and if there is a typo, it needs to be resolved with the corrected word, otherwise if a typo is not detected, the model should move on.
This is the purpose of evaluateSentence[], which splits input by both contextual sentences and individual words, then calling on checkForTypo[] to see if a word needs to be investigated. If so, it uses scoresWord for that typo, eventually making its way through the entire sentence. It returns the corrected word, a score, and the typo, all as a list for each typo.
The last objective of this section is to determine what characters differ between the original typo, and the correction determined by the previous functions. Once the characters are obtained, they can be analyzed for patterns to search for abnormalities that could indicate hemiparesis.
pickChars[] using the Pick[] function to compare characters of two Strings, and return those that do not match. It is limited in the fact that this works only for Strings of equal length.
Finally, wrongCharsAll[] takes in the user’s entire input to output the characters that were supposed to have been typed, but were not. It would be likely that a person with hemiparesis would have trouble reaching the intended keys, so figuring out what characters were in the word they intended to type, and comparing it to the characters they actually typed, will give us these. As mentioned above, the pick function used does not work for Strings of unequal length, so this function uses SymmetricDifference[] to evaluate the differences between Strings of unequal length.
The function gets all the typos in the input and then goes through each one, either using the Pick[] function or SymmetricDifferences[] to output the characters.
Classifying Keystrokes
Classifying Keystrokes
The Standard Model
The Standard Model
Currently, Wolfram does not offer a way to determine which hand typed each key, which acts as a limitation for this model. There can be variability in the typing techniques from individual to individual, which could make the accuracy of diagnosis inaccurate in those cases. However, the assumption of using a standard home-row typing style does offer a foundation to go off of. Under the home-row typing style, each key was easily categorized into either left or right, based on what side of the keyboard it is on, and how it is typically typed.
basicQwerty uses a switch to place the keys into groups, either left, right, or unknown if it cannot be concluded, as seen. It takes in the character and outputs a list, where {1,0} is left, {0,1} is right, and {0,0} is unknown.
To put it into action, there is a live input box into which the user can type. This way the user directly types into a text-box and can submit their input once they are done for analysis. Visuals can be used to illustrate the spread of missed characters.
Once a user chooses to submit their input, the function calls basicQwerty[] to run on every element outputted from wrongCharsAll[]. This way, it can classify every character that was missed in the input as either being on the left or right. This is displayed as a list and also a pie chart. An example execution is shown below.
Above shown is the result of an input, “the children that I am teafhing ara hidde”.
As we can see, the model thinks the input should be corrected to “the children that I am teaching are hidden”. The Analysis list classifying the characters as left or right handed asserts that both “c” and “e” should have been typed using the left hand, and “n” using the left hand (based on standard typing). The pie chart displays the 2:1 ratio of errors attributed to the left hand compared to the right hand. This visual would be especially effective for larger inputs. Consider a dataset or document written by a random sample- the text could be extracted and put into this function, and the spread of errors by hand could easily be visualized with the chart. Especially since there would be more input, the results are less likely to be skewed, whereas in this case, there is only one more error with the left hand than the right, yet the difference looks greater in the chart.
Overall, this visualization and function is effective in displaying the fraction of typing errors that can be attributed to each hand. Especially with a large input, huge disparities between the error rate of each hand can be highly suggestive of an issue such as hemiparesis.
Overall, this visualization and function is effective in displaying the fraction of typing errors that can be attributed to each hand. Especially with a large input, huge disparities between the error rate of each hand can be highly suggestive of an issue such as hemiparesis.
Tracking Pair Times
Tracking Pair Times
The concerning disparities between the rate of typos for each hand can be a strong indicator of a deeper medical issue, particularly if these differences in rate are considered abnormal for the individual. Another sign that can be taken into account for early diagnosis of issues such as hemiparesis is the pace of typing. This is useful for two reasons:
a) Studies show that the fastest typing times between keys typically exists between keys that are typed with opposite hands. Therefore, analyzing the timing between pairs can be used as data to feed into a model and deduce patterns in the individual’s personal typing style.
b) If certain pairs have times that are much higher than the rest, or even certain clusters of pairs. This can be suggestive of user difficulty in getting to the keys in that pair. Hence, it can also be a sign of poor dexterity in a certain hand. once again tied back to early indications of stroke.
A function that constantly updates based on user input can be used to achieve this.
a) Studies show that the fastest typing times between keys typically exists between keys that are typed with opposite hands. Therefore, analyzing the timing between pairs can be used as data to feed into a model and deduce patterns in the individual’s personal typing style.
b) If certain pairs have times that are much higher than the rest, or even certain clusters of pairs. This can be suggestive of user difficulty in getting to the keys in that pair. Hence, it can also be a sign of poor dexterity in a certain hand. once again tied back to early indications of stroke.
A function that constantly updates based on user input can be used to achieve this.
This stores the currentKey pressed, the lastKey, and also calculates the time between the pressing of each using an event handler. Furthermore, it groups all the logged instances of pairs to calculate the mean time between two keys. All of this data is added to a bar chart for easy visualization.
Distinguishing Between Types of Typos
Distinguishing Between Types of Typos
With the entire premise of this model, one question I kept asking myself was: How can it be asserted that a typo is linked with the possibility of a serious medical condition?
Even while writing the code, this essay, or everyday texts, I have no lack of typos in my writing. I am sure they lean more heavily towards one hand than another as well, just based on the fact that I am right-handed. Does this mean I am displaying signs of possible neurological problems?
Of course it does not. The issue of distinguishing between the likely cause of a typo is essential if it is to be used as a real world application, but it can be a difficult task to complete. One approach utilized here was to import a dataset containing the most commonly misspelled and mistyped words. The dataset, curated by the University of London, Birkbeck, contains an extensive list with correctly typed words (indicated with a $ at their start), which are followed by the most common typos of said word, whether that is due to variations in spelling, or simple human error. This dataset was utilized to check whether a specified typo was present in it or not.
Even while writing the code, this essay, or everyday texts, I have no lack of typos in my writing. I am sure they lean more heavily towards one hand than another as well, just based on the fact that I am right-handed. Does this mean I am displaying signs of possible neurological problems?
Of course it does not. The issue of distinguishing between the likely cause of a typo is essential if it is to be used as a real world application, but it can be a difficult task to complete. One approach utilized here was to import a dataset containing the most commonly misspelled and mistyped words. The dataset, curated by the University of London, Birkbeck, contains an extensive list with correctly typed words (indicated with a $ at their start), which are followed by the most common typos of said word, whether that is due to variations in spelling, or simple human error. This dataset was utilized to check whether a specified typo was present in it or not.
commonTypo[] takes in a word as a parameter, and determines if a word is part of the common typos. It extracts the words that are correctly spelled by identifying the $ symbol, and then putting their respective typos into a list. If the specified word is part of the typo list, the function returns True.
Example to check if “accknowledgement” is a commonly mistyped word
Conclusion
Conclusion
With the rise of Machine Learning as a tool in the field of medicine, analyzing user text input seems to be one of the promising applications to detect neurological issues, such as stroke. This investigation developed a way for users to input text, and for that text to be analyzed to detect probabilities of stroke symptoms. Stroke is commonly tied to hemiparesis, which results in muscle weakness and partial paralysis on one side of the body. Therefore, disparities in the performance of hands when texting could serve as indication of it. The investigation began by building a model to take in text, detect all the typos within it, and then establish what word the typo was intended to be. The selection of a word was based on many factors, including the Levenshtein distance, as well as the distance on a keyboard between characters. GPT-2 was then utilized to give words contextual scores on if they were likely to be the correct choice based on the content preceding the typo. From this selected word, the characters that were mistyped of missed entirely can be found, and they can then be associated with either hand. The performance of each hand can be visualised to detect abnormalities in their performance, which is one of the considerations taken into account for analysis of stroke probability. Other considerations included the typing rate between pairs of keys, and how this related to decreased dexterity on a certain side. To connect these models to feasible medical applications, a dataset was imported to distinguish between typos that were likely indicative of a neurological issue, such as stroke, versus a simple spelling mistake, or human error.
Future Recommendations
Future Recommendations
For future application, the methodology of selecting the correct word to replace a typo can be improved upon by using a more consistent LLM, and the possible incorporation of additional factors to assign a score to different words. Additionally, as previously acknowledged, the Wolfram Language has certain limitations on what it can track regarding user-interface action. For example, a function that could have been useful would be a way to measure how long a key has pressed down for. Based on the NeuroQWERTY keyboard model at MIT, which attempts to examine user typing patterns for Parkinson’s diagnosis, I noticed my non-dominant hand had much longer press times for keys than my dominant hand. When it comes to this model, a function tracking this would be useful in predicting what hands an individual uses for certain keys by grouping hold times. This way, it could be applied at a larger scale, without relying upon the assumption that the individual is adhering to a standard manner of typing. It could also build an overall scale to output a general probability of stroke symptoms by synthesizing the time between pairs, different types of typos, and of course, performance of each hand.
Acknowledgements
Acknowledgements
I would like to thank my mentor, Jenny Wang, for patiently guiding me through the process of approaching this topic and developing the paper, while making it an incredibly enjoyable experience. I also want to thank Nora Popescu for helping me deeply explore the scope of this project, and William Choi-Kim for his assistance. Finally, I want to express gratitude to all the staff and organizers of the WSRP for making this program an opportunity that enables me to explore my passions.
References
References
Hemiparesis. (n.d.). Cleveland Clinic. Retrieved July 3, 2025, from https://my.clevelandclinic.org/health/symptoms/24952-hemiparesis
Letourneau, P.-J. (2012, June 14). [How Do YOU Type “wolfram”? Analyzing Your Typing Style Using Mathematica]. Wolfram. Retrieved July 2, 2025, from https://blog.wolfram.com/2012/06/14/how-do-you-type-wolfram-analyzing-your-typing-style-using-mathematica/
Trafton, A. (2015, April 1). [Diagnosis by keyboard By revealing loss of motor skills, typing patterns may help to identify early onset of Parkinson’s.]. MIT News. Retrieved July 5, 2025, from https://news.mit.edu/2015/typing-patterns-diagnose-early-onset-parkinsons-0401
Letourneau, P.-J. (2012, June 14). [How Do YOU Type “wolfram”? Analyzing Your Typing Style Using Mathematica]. Wolfram. Retrieved July 2, 2025, from https://blog.wolfram.com/2012/06/14/how-do-you-type-wolfram-analyzing-your-typing-style-using-mathematica/
Trafton, A. (2015, April 1). [Diagnosis by keyboard By revealing loss of motor skills, typing patterns may help to identify early onset of Parkinson’s.]. MIT News. Retrieved July 5, 2025, from https://news.mit.edu/2015/typing-patterns-diagnose-early-onset-parkinsons-0401