Posted By

jsatt on 10/21/09


Tagged

jquery widget keyboard ui virtual ten-key numpad qwerty dvorak


Versions (?)

Virtual Keyboard Widget


 / Published in: jQuery
 

URL: http://github.com/Mottie/Keyboard

This code is no longer under development. Please use the branch at the URL listed above.

An on-screen virtual keyboard embedded within the browser window which will popup when a specified input field is focused. The user can then type and preview their input before Accepting or Canceling.

Include additional css available here.

Usage:

$('input[type=text], input[type=password], textarea')
    .keyboard({
        layout:"qwerty",
        customLayout:
            [["q w e r t y {bksp}","Q W E R T Y {bksp}"],
            ["s a m p l e {shift}","S A M P L E {shift}"],
            ["{accept} {space} {cancel}","{accept} {space} {cancel}"]]
    }); 

Options:

layout - [String] specify which keyboard layout to use

  • qwerty - Standard QWERTY layout (Default)

  • alpha - Alphabetical layout

  • dvorak - Dvorak Simplified layout

  • num - Numerical (ten-key) layout

  • custom - Uses a custom layout as defined by the customLayout option

customLayout - [Array] Specify a customer layout

  • An Array of arrays

  • Each internal array is a new keyboard row

  • Each internal array can contain either one or two

  • String elements (Lower case and Upper case respectively)

  • Each string element must have each character or key seperated by a space

  • Special/"Action" keys include:

    • {space} - Spacebar
    • {bksp} - Backspace
    • {shift} - Shift/Capslock
    • {return} - Return/New Line
    • {accept} - Updates element value and closes keyboard
    • {cancel} - Clears changes and closes keyboard
    • {dec} - Decimal for numeric entry, only allows one decimal
    • {neg} - Negative for numeric entry
    • {sp:#} - Replace # with a numerical value, adds blank space, value of 1 ~ width of one key

Creative Commons Attribution-Share Alike 3.0 Unported License

  1. /*
  2. jQuery UI Virtual Keyboard Widget
  3. Version 1.4.1
  4.  
  5. Author: Jeremy Satterfield
  6. -----------------------------------------
  7. Creative Commons Attribution-Share Alike 3.0 Unported License
  8. http://creativecommons.org/licenses/by-sa/3.0/
  9. -----------------------------------------
  10.  
  11. An on-screen virtual keyboard embedded within the browser window which
  12. will popup when a specified entry field is focused. The user can then
  13. type and preview their input before Accepting or Canceling.
  14.  
  15. As a plugin to jQuery UI styling and theme will automatically
  16. match that used by jQuery UI with the exception of the required
  17. CSS listed below.
  18.  
  19. Requires:
  20.   jQuery
  21.   jQuery UI
  22.  
  23. Usage:
  24.   $('input[type=text], input[type=password], textarea')
  25.   .keyboard({
  26.   layout:"qwerty",
  27.   customLayout:
  28.   [["q w e r t y {bksp}","Q W E R T Y {bksp}"],
  29.   ["s a m p l e {shift}","S A M P L E {shift}"],
  30.   ["{accept} {space} {cancel}","{accept} {space} {cancel}"]]
  31.   });
  32.  
  33. Options:
  34.   layout
  35.   [String] specify which keyboard layout to use
  36.   qwerty - Standard QWERTY layout (Default)
  37.   alpha - Alphabetical layout
  38.   dvorak - Dvorak Simplified layout
  39.   num - Numerical (ten-key) layout
  40.   custom - Uses a custom layout as defined by the customLayout option
  41.  
  42.   customLayout
  43.   [Array] Specify a customer layout
  44.   An Array of arrays
  45.   Each internal array is a new keyboard row
  46.   Each internal array can contain either one or two
  47.   String elements (Lower case and Upper
  48.   case respectively)
  49.   Each string element must have each character
  50.   or key seperated by a space
  51.   Special/"Action" keys include:
  52.   {space} - Spacebar
  53.   {bksp} - Backspace
  54.   {shift} - Shift/Capslock
  55.   {return} - Return/New Line
  56.   {accept} - Updates element value and closes keyboard
  57.   {cancel} - Clears changes and closes keyboard
  58.   {dec} - Decimal for numeric entry, only allows one decimal
  59.   {neg} - Negative for numeric entry
  60.   {sp:#} - Replace # with a numerical value,
  61.   adds blank space, value of 1 ~ width of one key
  62.  
  63. CSS:
  64.   .ui-keyboard{padding: .3em; position: absolute; z-index: 16000;}
  65.   .ui-keyboard-button{height: 2em; width: 2em; margin: .1em;}
  66.   .ui-keyboard-actionkey{width: 4em;}
  67.   .ui-keyboard-space{width: 15em;}
  68.   .ui-keyboard-preview{width: 100%; text-align: left;}
  69.  
  70. TODO:
  71.  
  72. Changelog:
  73.   11/18/2010 1.4.1 Attach keyboard to the body tag for instances where
  74.   a parent element is position relative
  75.   Add focus method to refocus the input preview so that
  76.   a cursor is visible
  77.   1.4 Update positioning to jQuery UI 1.8 position method
  78.   Other tweaks for cleaning code
  79.   1/17/2010 1.3 Hide keyboard when clicking outside of keyboard
  80. Tweek positioning to fit better on screen if page
  81. scrolled or resized
  82. 1/15/2010 1.2 Align keyboard with element it is called from
  83. Append keyboard DOM to elements parent instead of body
  84.   10/30/2009 1.1 Change Preview window to clone the selected element
  85.   to match the proper formatting of the element
  86.   (i.e. not showing characters in password fields)
  87.   Add Return key to insert new lines into textareas
  88.   Change style of Accept and Cancel buttons
  89.   to "ui-state-highlight" to standout
  90.   Add ability for designer to create a custom keyboard
  91.   layout
  92.   10/21/2009 1.0 initial build
  93. */
  94. jQuery.widget('ui.keyboard', {
  95.  
  96. layouts: {
  97. "qwerty": [
  98. ['1 2 3 4 5 6 7 8 9 0 - = `',
  99. '! @ # $ % ^ & * ( ) _ + ~'],
  100. ['q w e r t y u i o p [ ] \\',
  101. 'Q W E R T Y U I O P { } |'],
  102. ['{sp:.5} a s d f g h j k l ; \' {return}',
  103. '{sp:.5} A S D F G H J K L : " {return}'],
  104. ['{sp:1} z x c v b n m , . / {shift}',
  105. '{sp:1} Z X C V B N M < > ? {shift}' ],
  106. ['{accept} {space} {cancel} {bksp}',
  107. '{accept} {space} {cancel} {bksp}']
  108. ],
  109. "alpha": [
  110. ['1 2 3 4 5 6 7 8 9 0 - = `',
  111. '! @ # $ % ^ & * ( ) _ + ~'],
  112. ['a b c d e f g h i j [ ] \\',
  113. 'A B C D E F G H I J { } |'],
  114. ['{sp:.5} k l m n o p q r s ; \' {return}',
  115. '{sp:.5} K L M N O P Q R S : " {return}'],
  116. ['{sp:1} t u v w x y z , . / {shift}',
  117. '{sp:1} T U V W X Y Z < > ? {shift}' ],
  118. ['{accept} {space} {cancel} {bksp}',
  119. '{accept} {space} {cancel} {bksp}']
  120. ],
  121. "dvorak": [
  122. ['1 2 3 4 5 6 7 8 9 0 [ ] `',
  123. '! @ # $ % ^ & * ( ) { } ~'],
  124. ['\' , . p y f g c r l / = \\',
  125. '" < > P Y F G C R L ? + |'],
  126. ['{sp:.5} a o e u i d h t n s - {return}',
  127. '{sp:.5} A O E U I D H T N S _ {return}'],
  128. ['{sp:1} ; q j k x b m w v z {shift}',
  129. '{sp:1} : Q J K X B M W V Z {shift}' ],
  130. ['{accept} {space} {cancel} {bksp}',
  131. '{accept} {space} {cancel} {bksp}']
  132. ],
  133. "num": [
  134. ['1 2 3 {bksp}'],
  135. ['4 5 6 {accept}'],
  136. ['7 8 9 {cancel}'],
  137. ['0 {dec} {neg}']
  138. ]
  139. },
  140.  
  141. _init: function(){
  142. this.options.layout = this.options.layout || "qwerty";
  143. this.layouts.custom = this.options.customLayout || [['{cancel}']];
  144. var ui = this;
  145. var element = ui.element;
  146. var keyboard = this._buildKeyboard(ui);
  147. var allKeys = keyboard.find('.ui-keyboard-button');
  148. var inputKeys = allKeys.filter(':not(.ui-keyboard-actionkey)');
  149. var previewInput = keyboard.find('.ui-keyboard-preview');
  150. var decBtn = keyboard.find('[name=key_decimal]');
  151.  
  152. jQuery(document)
  153. .unbind('mousedown', this._hideonexternalclick)
  154. .bind('mousedown', this._hideonexternalclick);
  155.  
  156. element
  157. .focus(function(){
  158. var element = jQuery(this)
  159. jQuery('.ui-keyboard').hide();
  160. previewInput
  161. .val(element.val());
  162.  
  163. keyboard
  164. .position({
  165. of: element,
  166. my: "left top",
  167. at: "left top",
  168. collision: "fit",
  169. })
  170. .show();
  171.  
  172. previewInput
  173. .scrollTop(previewInput.attr('scrollHeight'))
  174. .focus();
  175. });
  176.  
  177. jQuery('body')
  178. .append(keyboard);
  179.  
  180. inputKeys
  181. .click(function(){
  182. previewInput
  183. .val( previewInput.val() + this.value)
  184. });
  185.  
  186. allKeys.click(function(){
  187. previewInput
  188. .scrollTop(previewInput.attr('scrollHeight'))
  189. .focus();
  190. })
  191.  
  192. if(decBtn.length > 0){
  193. allKeys
  194. .click(function(){
  195. if(/\./.test(previewInput.val())){
  196. decBtn
  197. .attr('disabled','disabled')
  198. .removeClass('ui-state-default')
  199. .addClass('ui-state-disabled');
  200. }else{
  201. decBtn
  202. .removeAttr("disabled")
  203. .addClass('ui-state-default')
  204. .removeClass('ui-state-disabled');
  205. }
  206.  
  207. });
  208. }
  209. },
  210.  
  211. _hideonexternalclick: function(e){
  212. if(jQuery(e.target).closest('.ui-keyboard').length < 1){
  213. jQuery('.ui-keyboard').hide();
  214. }
  215. },
  216.  
  217. _buildKeyboard: function(ui){
  218. var container = jQuery('<div></div>')
  219. .addClass('ui-keyboard')
  220. .addClass('ui-widget-content')
  221. .addClass('ui-widget')
  222. .hide();
  223.  
  224. //build preview display
  225.  
  226. var previewInput = ui.element.clone()
  227. .attr('name','preview')
  228. .attr('readonly','readonly')
  229. .addClass('ui-state-active')
  230. .addClass('ui-keyboard-preview');
  231.  
  232. //build preview container and append preview display
  233. var entryPreview = jQuery('<div></div>')
  234. .append(previewInput)
  235. .appendTo(container);
  236.  
  237.  
  238. //build default button
  239. keyBtn = jQuery('<input />')
  240. .attr('type','button')
  241. .addClass('ui-keyboard-button')
  242. .addClass('ui-state-default');
  243.  
  244. actionKey = keyBtn.clone()
  245. .addClass('ui-keyboard-actionkey');
  246.  
  247. for( row in this.layouts[this.options.layout] ){
  248. currentRow = this.layouts[this.options.layout][row];
  249. newRow = jQuery('<div></div>')
  250. .attr('id','ui-keyboard-row'+row)
  251. .addClass('ui-keyboard-row')
  252. .appendTo(container);
  253.  
  254. for( set in currentRow ){
  255. newSet = jQuery('<div></div>')
  256. .addClass('ui-keyboard-keyset')
  257. .appendTo(newRow);
  258. if(set==1){
  259. newSet
  260. .addClass('ui-keyboard-shiftset')
  261. .hide();
  262. }
  263. currentSet = currentRow[set];
  264. keys = currentSet.split(/\s+/);
  265. for( key in keys ){
  266.  
  267. //if it's an action key
  268. if( /^{\S+}$/.test(keys[key])){
  269.  
  270. action = keys[key].match(/^{(\S+)}$/)[1];
  271.  
  272. if(action == 'space'){
  273. actionKey.clone()
  274. .attr('name','key_space')
  275. .val('Space')
  276. .addClass('ui-keyboard-space')
  277. .click(function(){
  278. previewInput.val(
  279. previewInput.val() + ' ');
  280. })
  281. .appendTo(newSet);
  282. }else if(action == 'bksp'){
  283. actionKey.clone()
  284. .attr('name','key_bksp')
  285. .val('<Bksp')
  286. .click(function(){
  287. previewInput.val(
  288. previewInput.val().substring(
  289. 0,
  290. previewInput
  291. .val().length - 1
  292. )
  293. );
  294. })
  295. .appendTo(newSet);
  296.  
  297. }else if(action == 'shift'){
  298. actionKey.clone()
  299. .attr('name','key_shift')
  300. .val('Shift')
  301. .click(function(){
  302. hidden = container
  303. .find('.ui-keyboard-keyset:hidden');
  304. visible = container
  305. .find('.ui-keyboard-keyset:visible');
  306. visible.hide();
  307. hidden.show();
  308. })
  309. .appendTo(newSet);
  310. }else if(action == 'accept'){
  311. actionKey.clone()
  312. .attr('name','key_accept')
  313. .val('Accept')
  314. .addClass('ui-state-highlight')
  315. .removeClass('ui-state-active')
  316. .click(function(){
  317. ui.element.val(
  318. previewInput.val()
  319. );
  320. container.hide();
  321. })
  322. .appendTo(newSet);
  323. }else if(action == 'cancel'){
  324. actionKey.clone()
  325. .attr('name','key_cancel')
  326. .val('Cancel')
  327. .addClass('ui-state-highlight')
  328. .removeClass('ui-state-active')
  329. .click(function(){
  330. container.hide();
  331. })
  332. .appendTo(newSet);
  333. }else if(/^sp:\.?\d+$/.test(action)){
  334. margin = action.match(/^sp:(\.?\d+)$/)[1];
  335. jQuery('<span>&nbsp;</span>')
  336. .css('margin','0 ' + margin + 'em')
  337. .appendTo(newSet);
  338. }else if(action == "dec"){
  339. keyBtn.clone()
  340. .attr('name','key_decimal')
  341. .val('.')
  342. .appendTo(newSet);
  343. }else if(action == "neg"){
  344. actionKey.clone()
  345. .attr('name','key_negative')
  346. .val('+/-')
  347. .click(function(){
  348. if(/^\-?\d*\.?\d*$/.test(
  349. previewInput.val()
  350. )){
  351. previewInput.val(
  352. (previewInput.val() * -1)
  353. );
  354. }
  355. })
  356. .appendTo(newSet);
  357. }else if(action == "return"){
  358. actionKey.clone()
  359. .attr('name','key_return')
  360. .val('Return')
  361. .click(function(){
  362. previewInput.val(
  363. previewInput.val() + ' \n'
  364. );
  365. })
  366. .appendTo(newSet);
  367. }
  368. }else{
  369. keyBtn.clone()
  370. .attr('name','key_'+row+'_'+key)
  371. .val(keys[key])
  372. .appendTo(newSet);
  373. }
  374. }
  375.  
  376. }
  377.  
  378. }
  379.  
  380. return container;
  381. }
  382. })

Report this snippet  

Comments

RSS Icon Subscribe to comments
Posted By: ofadlaoui on August 9, 2010

Thanks very much !

Posted By: synergy_ek on October 26, 2010

this script doesn't works with jQuery UI 1.8.x

Posted By: jsatt on November 19, 2010

@synergy_ek, I've just updated the code to take advantage of a couple of jquery-ui 1.8 features. Try it out and see if it works better for you. Otherwise, please give me more info about the issue, Jquery version, browser, OS, any error message that might be in the console, etc.

Posted By: rlmattax on December 2, 2010

I'm having trouble as well. I'm sure its a minor oversight on my part, but I'm not sure what it is.

I'm no stranger to jquery or css or anything else involved here really.

I'm using jquery 1.4.4 and jquery ui 1.8.6, in Chrome, on OS X, and no error messages.

I'm not really sure what to expect since you don't have a demo up, but maybe that would be a good place to start. :)

Thanks!

Posted By: dylan19 on January 21, 2011

Is nice work but it cannot work in IE 7

You need to login to post a comment.