Giải pháp Free gõ tiếng Việt Telex,VNI,VIQR cho iPad

thuannp
10/5/2010 5:22Phản hồi: 34
Thân chào

Hiện tại theo tôi biết thì Ipad có 2 cách để gõ tiếng Việt:
1 là sử dụng các phần mềm gõ TV mua trên itunes như .VN: nhược điểm là phải mất phí, phải mua tài khoản ...
2 là bật một trang web có hỗ trợ gõ tiếng việt lên và type sau đó copy, paste. Nhược điểm là phải có mạng wifi thì mới làm được.

Tôi rất trông đợi một bộ gõ tiếng việt tích hợp trực tiếp trên keyboard để anh em có thể type ngay tại từng ứng dụng, cái này thì phải chờ vietnamese developer thôi.

Trong thời gian chờ đợi tôi đã tìm ra 1 phương pháp khắc phục được nhược điểm của 2 cách hiện tại. Đó là sử dụng js (javascript).


Cách thức thực hiện như sau:
1. Copy toàn bộ đoạn code dưới đây vào Notepad, save lại thành file Unikey.htm (lưu ý khi save phần Save as type chọn All Type)
2. Sync file này vào Ipad qua các phần mềm hỗ trợ đọc htm. Tôi đã test ok trên ReaddleDocs và GoodReader.
3. Mở file này ra và gõ tiếng việt rất chuẩn. Gõ xong thì copy và paste thôi.

Tôi đã thử làm 1 button Select All và Copy All để copy nhanh nội dung bằng javascript nhưng chạy trên IE ở win7 thì OK, FF cũng ok nhưng đưa vào ipad thì ko hoạt động được. Bro nào thạo js thử nghiên cứu cùng tôi để phát triển ứng dụng này.

Ngoài ra tôi cũng đang tìm cách mở ứng dụng này bằng safari nhưng cũng chưa thành công. Nếu mở được thì sử dụng kèm với 1 app browser hỗ trợ 2 cửa sổ web là có thể type và paste khá dễ dàng. Hy vọng bro nào đó tiếp tục nghiên cứu theo hướng này và share cho ae

Bắt đầu copy từ đây:

Lưu ý: đã có bản cập nhật cho phép gõ tiếng việt telex, vni và viqr, xin xem bài của tôi ở trang 3


Code:

<html>

<head>
<meta name="GENERATOR" content="Microsoft FrontPage 5.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Unikey</title>
</head>

<body onload="setTypingMode(1);" bgcolor="#FFFFCC">

<form name="myform" id="myform">
<textarea name="holdtext" id="holdtext" rows="38" cols="66" style="font-family:Arial; font-size:25px;" onKeyUp="initTyper(this);"></textarea>
</form>


<script language="JavaScript1.2" type="text/javascript">
var supported = (document.all || document.getElementById);
var disabled = false;
var charmapid = 1;
var keymodeid = 0;
var linebreak = 0;
var theTyper = null;

reset = function(){}
initTyper = telexingVietUC;

function setTypingMode(mode) {
  keymodeid = mode;
  if (theTyper) theTyper.keymode= initKeys();
  if (!supported && !disabled) {
    alert("Xin loi, trinh duyet web cua ban khong cho phep dung VietTyping.\n");
    disabled = true;
  }
}

initCharMap = function() { return new CVietUniCodeMap(); }

initKeys = function() {
  switch (keymodeid) {
    case 1: return new CTelexKeys();
    case 2: return new CVniKeys();
    case 3: return new CViqrKeys();
    case 4: return new CAllKeys();
    default: return new CVKOff();
  }
}

function telexingVietUC (txtarea) {
  txtarea.vietarea= true;
  txtarea.onkeyup= null;
  if (!supported) return;
  txtarea.onkeypress= vietTyping;
  txtarea.getCurrentWord= getCurrentWord;
  txtarea.replaceWord= replaceWord;
  txtarea.onkeydown= onKeyDown;
  txtarea.onmousedown= onMouseDown;
  if(!theTyper) theTyper = new CVietString("");
}

function getEvt(evt) {
  if (typeof(evt)=='string') return evt.charCodeAt(0);
  return document.all? event.keyCode: (evt && evt.which)? evt.which: 0;
}

function onKeyDown(evt) {
  var c= getEvt(evt);
  if ((c==10) || (c==13)) { reset(1); linebreak= 1; }
  else if ((c<49) && (c!=16) && (c!=20)) { linebreak= 0; reset(c==32); }
  return true;
}

function onMouseDown(evt) { reset(0); linebreak= 0; return true; }

function vietTyping(evt) {
  var c= getEvt(evt);
  theTyper.value= this.getCurrentWord();
  var changed= ((c>32) && theTyper.typing(c));
  if (changed) this.replaceWord(theTyper.value);
  return !changed;
}

function getCurrentWord() {
  if(!document.all) return this.value;
  var caret = this.document.selection.createRange();
  if (caret.text) return null;
  var backward = -10;
  do {
    var caret2 = caret.duplicate();
    caret2.moveStart("character", backward++);
  } while (caret2.parentElement() != this && backward <0);
  this.curword = caret2.duplicate();
  return caret2.text;
}

function replaceWord(newword) {
  if(!document.all) { this.value= newword; return; }
  this.curword.text = newword;
  this.curword.collapse(false);
}
// end interface


// "class": CVietString
//
function CVietString(str) {
  this.value= str;
  this.keymode= initKeys();
  this.charmap= initCharMap();
  this.ctrlchar= '-';
  this.changed= 0;

  this.typing= typing;
  this.Compose= Compose;
  this.Correct= Correct;
  this.findCharToChange= findCharToChange;
  return this;
}

function typing(ctrl) {
  this.changed = 0;
  this.ctrlchar = String.fromCharCode(ctrl);
  if (linebreak) linebreak= 0; else this.keymode.getAction(this);
  this.Correct();
  return this.changed;
}

function Compose(type) {
  if(!this.value) return;
  var info = this.findCharToChange(type);
  if (!info || !info[0]) return;
  var telex;
  if (info[0]=='\\') telex= [1,this.ctrlchar,1];
  else if (type>6) telex= this.charmap.getAEOWD(info[0], type, info[3]);
  else telex= this.charmap.getDau(info[0], type);
  if (!(this.changed = telex[0])) return;
  this.value = this.value.replaceAt(info[1],telex[1],info[2]);
  if (!telex[2]) { spellerror= 1; this.value+= this.ctrlchar; }
}

function Correct() {
  if (this.charmap.maxchrlen || !document.all) return 0;
  var tmp= this.value;
  if ('nNcC'.indexOf(this.ctrlchar)>=0) tmp+= this.ctrlchar;
  var er= /[^\x01-\x7f](hn|hc|gn)$/i.exec(tmp);
  if (er) {
    this.value= tmp.substring(0,tmp.length-2)+er[1].charAt(1)+er[1].charAt(0);
    this.changed= 1;
  }
  else if(!this.changed) return 0;
  er= /\w([^\x01-\x7f])(\w*)([^\x01-\x7f])\S*$/.exec(this.value);
  if (!er) return 0;
  var i= this.charmap.isVowel(er[1]);
  var ri= (i-1)%24 + 1, ci= (i-ri)/24;
  var i2= this.charmap.isVowel(er[3]);
  if (!ci || !i2) return 0;
  var ri2= (i2-1)%24 + 1, ci2= (i2-ri2)/24;
  var nc= this.charmap.charAt(ri)+ er[2]+ this.charmap.charAt(ci*24+ri2);
  this.value= this.value.replace(new RegExp(er[1]+er[2]+er[3],'g'), nc);
}

function findCharToChange(type) {
  var lastchars= this.charmap.lastCharsOf(this.value, 5);
  var i= 0, c=lastchars[0][0], chr=0;
  if (c=='\\') return [c,this.value.length-1,1];
  if (type==15) while (!(chr=this.charmap.isVD(c))) {
    if ((c < 'A') || (i>=4) || !(c=lastchars[++i][0])) return null;
  }
  else while( "cghmnptCGHMNPT".indexOf(c)>=0) {
    if ((c < 'A') || (i>=2) || !(c=lastchars[++i][0])) return null;
  }
  c = lastchars[0][0].toLowerCase();
  var pc = lastchars[1][0].toLowerCase();
  var ppc = lastchars[2][0].toLowerCase();
  if (i==0 && type!=15) {
    if ( (chr=this.charmap.isVowel(lastchars[1][0]))
      && ("uyoia".indexOf(c)>=0) && !this.charmap.isUO(pc,c)
      && !((pc=='o' && c=='a') || (pc=='u' && c=='y'))
      && !((ppc=='q' && pc=='u') || (ppc=='g' && pc=='i')) ) ++i;
    if (c=='a' && (type==9 || type==7)) i= 0;
  }
  c= lastchars[i][0];
  if ((i==0 || chr==0) && type!=15) chr= this.charmap.isVowel(c);
  if (!chr) return null;
  var clen= lastchars[i][1], isuo=0;
  if ((i>0) && (type==7 || type==8 || type==11)) {
    isuo=this.charmap.isUO(lastchars[i+1][0],c);
    if (isuo) { chr=isuo; clen+=lastchars[++i][1]; isuo=1; }
  }
  var pos= this.value.length;
  for (var j=0; j<= i; j++) pos -= lastchars[j][1];
  return [chr, pos, clen, isuo];
}
// end CVietString


// character-map template
//
function CVietCharMap(){
  this.vietchars = null;
  this.length = 149;
  this.chr_cache = new Array(20);
  this.ind_cache = new Array(20);
  this.cptr = 0;
  this.caching= function(chr, ind) {
    this.chr_cache[this.cptr] = chr;
    this.ind_cache[this.cptr++] = ind;
    this.cptr %= 20;
  }
  return this;
}

CVietCharMap.prototype.charAt= function(ind){
  var chrcode = this.vietchars[ind];
  return chrcode ? String.fromCharCode(chrcode) : null;
}

CVietCharMap.prototype.isVowel= function(chr){
  var i = 0;
  while ((i<20) && (chr != this.chr_cache[i])) ++i;
  if (i<20) return this.ind_cache[i];

  i = this.length-5;
  while ((chr != this.charAt(i)) && i) --i;
  this.caching(chr, i);
  return i;
}

CVietCharMap.prototype.isVD= function (chr){
  var ind = this.length-5;
  while ((chr != this.charAt(ind)) && (ind < this.length)) ++ind;
  return (ind<this.length)? ind: 0;
}

CVietCharMap.prototype.isUO= function (c1, c2){
  if (!c1 || !c2) return 0;
  var ind1 = this.isVowel(c1);
  var ci = (ind1-1)%12;
  if ((ci!=9) && (ci!=10)) return 0;
  var ind2 = this.isVowel(c2);
  ci = (ind2-1)%12;
  if ((ci!=6) && (ci!=7) && (ci!=8)) return 0;
  return [ind1,ind2];
}

CVietCharMap.prototype.getDau= function (ind, type){
  var accented= (ind < 25)? 0: 1;
  var ind_i= (ind-1) % 24 +1;
  var charset= (type == 6)? 0 : type;
  if ((type== 6) && !accented) return [0];
  var newind= charset*24 + ind_i;
  if (newind == ind) newind= ind_i;
  var chr= this.charAt(newind);
  if (!chr) chr= this.lowerCaseOf(0,newind);
  return [1, chr, newind>24 || type==6];
}

var map=[
[7,7,7,8,8, 8,9,10,11,15],
[0,3,6,0,6, 9,0, 3, 6, 0],
[1,4,7,2,8,10,1, 4, 7, 1]
];
CVietCharMap.prototype.getAEOWD= function(ind, type, isuo) {
  var c=0, i1=isuo? ind[0]: ind;
  var vc1= (type==15)? (i1-1)%2 : (i1-1)%12;
  if (isuo) {
    var base= ind[1]-(ind[1]-1)%12;
    if (type==7 || type==11) c= this.charAt(i1-vc1+9)+this.charAt(base+7);
    else if (type==8) c= this.charAt(i1-vc1+10)+this.charAt(base+8);
    return [c!=0, c, 1];
  }
  var i= -1, shift= 0, del= 0;
  while (shift==0 && ++i<map[0].length) {
    if (map[0][i]==type) {
      if(map[1][i]==vc1) shift= map[2][i]-vc1;
      else if(map[2][i]==vc1) shift= map[1][i]-vc1;
    }
  }
  if (shift==0) {
    if (type==7 && (vc1==2 || vc1==8)) shift=-1;
    else if ((type==9 && vc1==2) || (type==11 && vc1==8)) shift=-1;
    else if (type==8 && (vc1==1 || vc1==7)) shift=1;
    del= 1;
  } else del=(shift>0);
  i1 += shift;
  var chr= this.charAt(i1);
  if (i1<145) this.caching(chr, i1);
  if (!chr) chr= this.lowerCaseOf(0, i1);
  return [shift!=0, chr, del];
}

CVietCharMap.prototype.lastCharsOf= function(str, num){
  if (!num) return [str.charAt(str.length-1),1];
  var vchars = new Array(num);
  for (var i=0; i< num; i++) { vchars[i]= [str.charAt(str.length-i-1),1]; }
  return vchars;
}
// end CVietCharMap prototype


String.prototype.replaceAt= function(i,newchr,clen){
  return this.substring(0,i)+ newchr + this.substring(i+clen);
}

// output map: class CVietUniCodeMap
//
function CVietUniCodeMap(){ var map= new CVietCharMap();
map.vietchars = new Array(
"UNICODE",
97, 226, 259, 101, 234, 105, 111, 244, 417, 117, 432, 121,
65, 194, 258, 69, 202, 73, 79, 212, 416, 85, 431, 89,
225, 7845, 7855, 233, 7871, 237, 243, 7889, 7899, 250, 7913, 253,
193, 7844, 7854, 201, 7870, 205, 211, 7888, 7898, 218, 7912, 221,
224, 7847, 7857, 232, 7873, 236, 242, 7891, 7901, 249, 7915, 7923,
192, 7846, 7856, 200, 7872, 204, 210, 7890, 7900, 217, 7914, 7922,
7841, 7853, 7863, 7865, 7879, 7883, 7885, 7897, 7907, 7909, 7921, 7925,
7840, 7852, 7862, 7864, 7878, 7882, 7884, 7896, 7906, 7908, 7920, 7924,
7843, 7849, 7859, 7867, 7875, 7881, 7887, 7893, 7903, 7911, 7917, 7927,
7842, 7848, 7858, 7866, 7874, 7880, 7886, 7892, 7902, 7910, 7916, 7926,
227, 7851, 7861, 7869, 7877, 297, 245, 7895, 7905, 361, 7919, 7929,
195, 7850, 7860, 7868, 7876, 296, 213, 7894, 7904, 360, 7918, 7928,
100, 273, 68, 272);
return map;
}

// input methods: class C...Keys
function CVietKeys() {
  this.getAction= function(typer){
    var i= this.keys.indexOf(typer.ctrlchar.toLowerCase());
    if(i>=0) typer.Compose(this.actions[i]);
  }
  return this;
}

function CVKOff() {
  this.off = true;
  this.getAction= function(){};
  return this;
}

function CTelexKeys() {
  var k= new CVietKeys();
  k.keys= "sfjrxzaeowd";
  k.actions= [1,2,3,4,5,6,9,10,11,8,15];
  k.istelex= true;
  return k;
}

function CVniKeys() {
  var k= new CVietKeys();
  k.keys= "0123456789";
  k.actions= [6,1,2,4,5,3,7,8,8,15];
  return k;
}

function CViqrKeys() {
  var k= new CVietKeys();
  k.keys= "\xB4/'\u2019`.?~-^(*+d";
  k.actions= [1,1,1,1,2,3,4,5,6,7,8,8,8,15];
  return k;
}

function CAllKeys() {
  var k= new CVietKeys();
  k.keys= "sfjrxzaeowd0123456789\xB4/'`.?~-^(*+d";
  k.actions= [1,2,3,4,5,6,9,10,11,8,15,6,1,2,4,5,3,7,8,8,15,1,1,1,2,3,4,5,6,7,8,8,8,15];
  k.istelex= true;
  return k;
}

// end vietuni.js

</script>

</body>

</html>


Quảng cáo

34 bình luận
Chia sẻ

Xu hướng

Bạn cho vài hình ảnh xem như thế nào,hiện giờ mình xài Viet free keyboard trên source của iphone.gsm.vn cũng OK.
thuannp
ĐẠI BÀNG
14 năm
Ủa vậy ra ipad jb xong cài app bạn nói là type đc TV trực tiếp từ keyboard à. Mình nghĩ app bạn nói chắc là cho iphone thôi đúng ko. Nếu như vậy thì khi cần type TV cho các app trong bộ iwork hay Notes thì vẫn phải copy paste đúng ko. Nếu như vẫn phải copy paste thì mình nghĩ dùng giải pháp của mình tiện hơn. Vừa ko cần jb, ko mất tiền mua trên appstore vừa đơn giản nhẹ nhàng, support ipad 100%. Giao diện thì cũng chẳng có j đâu chỉ đơn giản là một ô nhập liệu textarea phủ kín toàn màn hình thôi nên mình ko up ảnh chụp lên nữa. Bài post của mình là type từ cái ứng dụng này đấy.
Cái này không phải là app mà chỉ thêm các ký tự vào keyboard,có thể type trực tiếp bất cứ chổ nào và không cần copy,paste gì cả.

[​IMG]

[​IMG]
@caocaotac Sao không chọn ở phần senting ấy. Gõ theo kiểu Telex chả sướng hơn à. Nhìn mà hoa cả mắt:T
@nguyenmanhnl người lớn tuổi như mẹ và ba mình đánh quen vni rồi , giờ học lại nữa ah ?
thuannp
ĐẠI BÀNG
14 năm
À như vậy thì cũng ổn đấy ko phải copy paste chắc tôi cũng phải jb ipad để xài cái này. Tuy nhiên cũng có cái dở là ko type kiểu telex đc điều này sẽ làm giảm tốc độ type. Theo tôi lý tưởng nhất vẫn là dạng keyboard trực tiếp và cho phép gõ telex như vậy type vừa nhanh vừa ko cần copy paste. Ko biết bao giờ mới có app này
Bạn đợi phiên bản 4.0 trên iPad sẽ có bộ gõ telex mặc định luôn.Hiện giờ phiên bản 4.0 dành cho iPhone có có rồi.iPad chắc chờ vài tháng nữa.
iPad của bác là iPad 4G lun. ^^ 😁
cho mình hỏi IPAD có add fonts Vni được không?
thuannp
ĐẠI BÀNG
14 năm

Mình đã test thử nhưng ko đc. Có lẽ ipad chỉ hỗ trợ kiểu gõ telex thôi
phanuyvu
TÍCH CỰC
14 năm
mình thì không thích JB nên...đành đợi iPad firmware 4.0 vậy.
designxvn
ĐẠI BÀNG
14 năm
Cái này mình nghī lâu rùi.. Ko kha? thi .
Gõ tiếng Việt

làm sao thêm các ký tự vào keyboard được, bạn chỉ cho minh đi, cảm ơn
designxvn
ĐẠI BÀNG
14 năm
Đầu tiên jailbreak Ipad.. Sau đó vào Cydia addd souce : iphone.gsm.vn

Vào install Vietkeyboard !
Khi nào mới có gõ tiếng việt telex nhỉ, bây giờ chỉ gõ trên tinh tế được. Hi vọng 1 ngày không xa sẽ có telex để soạn thảo văn bản.
thuannp
ĐẠI BÀNG
14 năm
Ủa thế bạn đọc bài này của mình mà sao vẫn hỏi như vậy nhỉ ? Thử thực hiện theo hướng dẫn của mình ở trang 1, sẽ tạo ra 1 file là Unikey.htm. Sync vào Ipad với phần mềm Good Reader hoặc ReaddleDocs sẽ gõ được tiếng việt unicode theo kiểu telex một cách hoàn hảo, tương tự như việc gõ tiếng Việt trên tinhte vậy vì cùng một bộ mã hóa unicode như nhau. Sau khi gõ xong thì copy và paste vào ứng dụng mình cần.

Còn để gõ telex trực tiếp trên bàn phím ảo của Ipad thì đành phải đợi 4.0 thôi.
Hiểu lầm, ý là gõ tiếng việt trực tiếp trong phần mềm soạn thảo hoặc trong Notes đó bạ. Gõ telex như đang gõ trên ipad&tinh tế nè. Thanks nhé!

---------- Post added at 07:39 PM ---------- Previous post was at 07:38 PM ----------

Có thì nhắn tin nhé bạn.
davitru
ĐẠI BÀNG
14 năm
haizz.. có vẻ như vấn đề bộ gõ phức tạp quá nhỉ.. giá mà có Inspell cho ipad như Iphone thì hay biết mấy :|
đã có cách mở ứng dụng của bạn bằng safari ^^! tks đã share, xài telex gõ tiếng việt sướng lắm, gõ bằng cái này rồi copy qua những chỗ khác cho lẹ 😃
bạn tìm 1 host up file đó lên là có thể chạy trong safari, ở đây mình dùng skydrive của hotmail 😃 nhưng tiếc là phải có wifi 😔
mình nghĩ làm như vậy giống như mở 1 trang web, mà web thì cũng là htm thôi, hehe, với lại đa số xài ipad là phải có 3g hoặc wifi để online nên cách đó mình thấy cũng okie ^^!

mọi người có thể xài chung cái này với mình http://unikeytelex.co.cc 😃
thuannp
ĐẠI BÀNG
14 năm
Mình rất vui vì đã đóng góp đc một chút công sức cho cộng đồng. Xin lưu ý thêm một chút về vấn đề này: theo giải pháp load file htm lên server thì vẫn có bất tiện là phải có wifi. Trong khi nếu ipad đã jb thì theo mình đc biết là có giải pháp để safari đọc file htm ngay trên máy. Nhưng iPhone jb thì mình thử rồi còn ipad jb thì mình mới chỉ nhìn thấy thôi chưa thử. Hiện tại ipad của mình cũng ko jb. Nên bác nào đã jb thì test thử xem sao.
bác chỉ cách đi rồi mình test thử cho, ko biết cách chạy trực tiếp file htm trên safari 😔
thuannp
ĐẠI BÀNG
14 năm
Mình đã sửa lại thành bản hỗ trợ 3 kiểu gõ Telex, VNI và VIQR rồi. Các bạn làm theo hướng dẫn này nhé:
1. Vào http://www.mediafire.com/?q5de7ng613tdbq4 tải file unikey.zip xuống.
2. Giải nén được 3 file: telex.htm, vni.htm và viqr.htm
3. Có thể sync 3 file này vào ipad hoặc upload lên 1 free server hoặc google docs để dùng như các hướng dẫn ở trên. Bác nào rảnh thì up giùm anh em thì tốt. Tôi có server riêng nhưng bandwidth hơi hạn chế, còn free server thì chưa dùng bao giờ.
4. Chạy 1 trong 3 file, các file có link sang nhau ngay trên đầu trang.

Có gì trục trặc liên hệ lại mình nhé.
baluong
ĐẠI BÀNG
14 năm
có bác nào biết sửa code keyboard mặc định của 1 nước nào đấy trong ipad ko ? sửa như thế em nghĩ là được. ( em không giỏi về khoản này lắm, nếu nói ngu thì các bác đừng chửi nhé ^^ )
baluong
ĐẠI BÀNG
14 năm
Ý em là nếu bọn apple ko cho thêm bàn phím ảo tiếng việt vào thì mình sửa luôn code 1 bàn phím mặc định của Ipad (bọn chines hay bọn italia gì đó) thành kiểu gõ telex.
thuannp
ĐẠI BÀNG
14 năm
Vụ này muốn làm đc thì iPad phải jb, và phải có hacker can thiệp vào hệ thống. Nhưng hiện tại khi mà iOs4 for iPad sắp ra, có hỗ trợ mặc định keyboard t.việt thì chắc các hacker sẽ ko tốn công để làm việc đó đâu.

Cho nên giải pháp mình đưa ra đc xem là giải pháp tình thế trong khi chờ iOs4

Tiện đây thông báo là mình đã làm phiên bản mới cho ứng dụng này, xem tại đây

Xu hướng

Bài mới









  • Chịu trách nhiệm nội dung: Trần Mạnh Hiệp
  • © 2024 Công ty Cổ phần MXH Tinh Tế
  • Địa chỉ: Số 70 Bà Huyện Thanh Quan, P. Võ Thị Sáu, Quận 3, TPHCM
  • Số điện thoại: 02822460095
  • MST: 0313255119
  • Giấy phép thiết lập MXH số 11/GP-BTTTT, Ký ngày: 08/01/2019