diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6bb8564 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +build/* +*.kdev4 +.kdev_include_paths +.directory +*.kate-swp +*.orig +*~ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..712ec17 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 2.6) + +project(fcitx-unikey) + +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) + +# uninstall target +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" + IMMEDIATE @ONLY) + +add_custom_target(uninstall + COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) + +set(CMAKE_C_FLAGS "-Wall -Wextra -Wno-sign-compare -Wno-unused-parameter -fvisibility=hidden ${CMAKE_C_FLAGS}") +set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-sign-compare -Wno-unused-parameter -fvisibility=hidden ${CMAKE_CXX_FLAGS}") +set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--as-needed ${CMAKE_SHARED_LINKER_FLAGS}") +set(CMAKE_MODULE_LINKER_FLAGS "-Wl,--as-needed ${CMAKE_MODULE_LINKER_FLAGS}") + +find_package(Fcitx 4.2.3 REQUIRED) +find_package(Libiconv REQUIRED) +find_package(Gettext REQUIRED) + +configure_file(config.h.in config.h) + +add_subdirectory(src) +add_subdirectory(data) +add_subdirectory(po) \ No newline at end of file diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/cmake/FindLibiconv.cmake b/cmake/FindLibiconv.cmake new file mode 100644 index 0000000..c9360a8 --- /dev/null +++ b/cmake/FindLibiconv.cmake @@ -0,0 +1,75 @@ +# Try to find Libiconv functionality +# Once done this will define +# +# LIBICONV_FOUND - system has Libiconv +# LIBICONV_INCLUDE_DIR - Libiconv include directory +# LIBICONV_LIBRARIES - Libraries needed to use Libiconv +# LIBICONV_SECOND_ARGUMENT_IS_CONST - iconv second argument is const +# +# TODO: This will enable translations only if Gettext functionality is +# present in libc. Must have more robust system for release, where Gettext +# functionality can also reside in standalone Gettext library, or the one +# embedded within kdelibs (cf. gettext.m4 from Gettext source). + +# Copyright (c) 2006, Chusslove Illich, +# Copyright (c) 2007, Alexander Neundorf, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +if(LIBICONV_INCLUDE_DIR AND LIBICONV_LIB_FOUND) + set(Libiconv_FIND_QUIETLY TRUE) +endif(LIBICONV_INCLUDE_DIR AND LIBICONV_LIB_FOUND) + +include(CheckCCompilerFlag) +include(CheckCSourceCompiles) + +find_path(LIBICONV_INCLUDE_DIR iconv.h) + +set(LIBICONV_LIB_FOUND FALSE) + +if(LIBICONV_INCLUDE_DIR) + include(CheckFunctionExists) + check_function_exists(iconv_open LIBICONV_LIBC_HAS_ICONV_OPEN) + + if (LIBICONV_LIBC_HAS_ICONV_OPEN) + set(LIBICONV_LIBRARIES) + set(LIBICONV_LIB_FOUND TRUE) + else (LIBICONV_LIBC_HAS_ICONV_OPEN) + find_library(LIBICONV_LIBRARIES NAMES iconv) + if(LIBICONV_LIBRARIES) + set(LIBICONV_LIB_FOUND TRUE) + endif(LIBICONV_LIBRARIES) + endif (LIBICONV_LIBC_HAS_ICONV_OPEN) + + if (LIBICONV_LIB_FOUND) + check_c_compiler_flag("-Werror" ICONV_HAVE_WERROR) + set (CMAKE_C_FLAGS_BACKUP "${CMAKE_C_FLAGS}") + if(ICONV_HAVE_WERROR) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") + endif(ICONV_HAVE_WERROR) + set(CMAKE_REQUIRED_INCLUDES "${LIBICONV_INCLUDE_DIR}") + set(CMAKE_REQUIRED_LIBRARIES "${LIBICONV_LIBRARIES}") + check_c_source_compiles(" + #include + int main(){ + iconv_t conv = 0; + const char* in = 0; + size_t ilen = 0; + char* out = 0; + size_t olen = 0; + iconv(conv, &in, &ilen, &out, &olen); + return 0; + } + " LIBICONV_SECOND_ARGUMENT_IS_CONST ) + set(CMAKE_REQUIRED_INCLUDES) + set(CMAKE_REQUIRED_LIBRARIES) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS_BACKUP}") + endif(LIBICONV_LIB_FOUND) + +endif(LIBICONV_INCLUDE_DIR) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Libiconv DEFAULT_MSG LIBICONV_INCLUDE_DIR LIBICONV_LIB_FOUND) + +mark_as_advanced(LIBICONV_INCLUDE_DIR LIBICONV_LIBRARIES LIBICONV_LIBC_HAS_ICONV_OPEN LIBICONV_LIB_FOUND) diff --git a/cmake/cmake_uninstall.cmake.in b/cmake/cmake_uninstall.cmake.in new file mode 100644 index 0000000..72fbc63 --- /dev/null +++ b/cmake/cmake_uninstall.cmake.in @@ -0,0 +1,21 @@ +if (NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + message(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") +endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + +file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) +string(REGEX REPLACE "\n" ";" files "${files}") +foreach (file ${files}) + message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") + if (EXISTS "$ENV{DESTDIR}${file}" OR IS_SYMLINK "$ENV{DESTDIR}${file}") + execute_process( + COMMAND @CMAKE_COMMAND@ -E remove "$ENV{DESTDIR}${file}" + OUTPUT_VARIABLE rm_out + RESULT_VARIABLE rm_retval + ) + if(NOT ${rm_retval} EQUAL 0) + message(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") + endif (NOT ${rm_retval} EQUAL 0) + else (EXISTS "$ENV{DESTDIR}${file}" OR IS_SYMLINK "$ENV{DESTDIR}${file}") + message(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") + endif (EXISTS "$ENV{DESTDIR}${file}" OR IS_SYMLINK "$ENV{DESTDIR}${file}") +endforeach(file) \ No newline at end of file diff --git a/config.h.in b/config.h.in new file mode 100644 index 0000000..aed0206 --- /dev/null +++ b/config.h.in @@ -0,0 +1 @@ +#cmakedefine LIBICONV_SECOND_ARGUMENT_IS_CONST \ No newline at end of file diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt new file mode 100644 index 0000000..66ff013 --- /dev/null +++ b/data/CMakeLists.txt @@ -0,0 +1,6 @@ +fcitx_add_addon_conf_file(fcitx-unikey.conf) +fcitx_add_configdesc_file(fcitx-unikey.desc) +fcitx_add_inputmethod_conf_file(unikey.conf) + +install(FILES unikey.png DESTINATION ${FCITX4_PREFIX}/share/fcitx/skin/default/) +install(FILES unikey.png RENAME fcitx-unikey.png DESTINATION share/icons/hicolor/256x256/apps/) \ No newline at end of file diff --git a/data/fcitx-unikey.conf.in b/data/fcitx-unikey.conf.in new file mode 100644 index 0000000..e472285 --- /dev/null +++ b/data/fcitx-unikey.conf.in @@ -0,0 +1,9 @@ +[Addon] +Name=fcitx-unikey +_GeneralName=Unikey +_Comment=Unikey Wrapper For Fcitx +Category=InputMethod +Enabled=True +Library=fcitx-unikey.so +Type=SharedLibrary +IMRegisterMethod=ConfigFile diff --git a/data/fcitx-unikey.desc b/data/fcitx-unikey.desc new file mode 100644 index 0000000..723366a --- /dev/null +++ b/data/fcitx-unikey.desc @@ -0,0 +1,56 @@ +[Unikey/InputMethod] +Type=Enum +DefaultValue=Telex +Description=Input Method +EnumCount=4 +Enum0=Telex +Enum1=Vni +Enum2=STelex +Enum3=STelex2 + +[Unikey/OutputCharset] +Type=Enum +DefaultValue=Unicode +Description=Output Charset +EnumCount=8 +Enum0=Unicode +Enum1=TCVN3 +Enum2=VNI Win +Enum3=VIQR +Enum4=BK HCM 2 +Enum5=CString +Enum6=NCR Decimal +Enum7=NCR Hex + +[Unikey/SpellCheck] +Type=Boolean +DefaultValue=True +Description=Enable spell check + +[Unikey/Macro] +Type=Boolean +DefaultValue=False +Description=Enable macro + +[Unikey/ModernStyle] +Type=Boolean +DefaultValue=False +Description=Use oà, _uý (instead of òa, úy) + +[Unikey/FreeMarking] +Type=Boolean +DefaultValue=True +Description=Allow type with more freedom + +[Unikey/AutoNonVnRestore] +Type=Boolean +DefaultValue=True +Description=Auto restore keys with invalid words + +[Unikey/ProcessWAtBegin] +Type=Boolean +DefaultValue=True +Description=Process W at word begin + +[DescriptionFile] +LocaleDomain=fcitx-unikey diff --git a/data/unikey.conf.in b/data/unikey.conf.in new file mode 100644 index 0000000..8a85eb5 --- /dev/null +++ b/data/unikey.conf.in @@ -0,0 +1,7 @@ +[InputMethod] +UniqueName=unikey +_Name=Unikey +IconName=unikey +Priority=1 +LangCode=vi +Parent=fcitx-unikey diff --git a/data/unikey.png b/data/unikey.png new file mode 100644 index 0000000..41991fc Binary files /dev/null and b/data/unikey.png differ diff --git a/po/CMakeLists.txt b/po/CMakeLists.txt new file mode 100644 index 0000000..c45f4e9 --- /dev/null +++ b/po/CMakeLists.txt @@ -0,0 +1,26 @@ +file(GLOB PO_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.po) +file(RELATIVE_PATH REL_SOURCE_ROOT ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}) +if ("${REL_SOURCE_ROOT}" STREQUAL "") + set(REL_SOURCE_ROOT ".") +endif("${REL_SOURCE_ROOT}" STREQUAL "") + +set(POT_FILE fcitx-unikey.pot) + +configure_file(POTFILES.in.in ${CMAKE_CURRENT_BINARY_DIR}/POTFILES.in) + +extract_fcitx_addon_conf_postring() + +add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/desc.po + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/getdescpo ${PROJECT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS getdescpo) + +add_custom_target( + pot + COMMAND INTLTOOL_EXTRACT=${INTLTOOL_EXTRACT} srcdir=${CMAKE_CURRENT_BINARY_DIR} ${INTLTOOL_UPDATE} --gettext-package fcitx-unikey --pot + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/conf.po ${CMAKE_CURRENT_BINARY_DIR}/desc.po + ) + +# Update .po files and compile them to binary .gmo files +gettext_create_translations(${POT_FILE} ALL ${PO_FILES}) + diff --git a/po/POTFILES.in.in b/po/POTFILES.in.in new file mode 100644 index 0000000..4a7773c --- /dev/null +++ b/po/POTFILES.in.in @@ -0,0 +1,10 @@ +# List of source files which contain translatable strings. +./po/desc.po +./po/conf.po +@REL_SOURCE_ROOT@/src/unikey-ui.cpp +@REL_SOURCE_ROOT@/src/unikey-config.cpp +@REL_SOURCE_ROOT@/src/unikey-config.h +@REL_SOURCE_ROOT@/src/unikey-im.cpp +@REL_SOURCE_ROOT@/src/unikey-im.h +@REL_SOURCE_ROOT@/data/fcitx-unikey.conf.in +@REL_SOURCE_ROOT@/data/unikey.conf.in diff --git a/po/fcitx-unikey.pot b/po/fcitx-unikey.pot new file mode 100644 index 0000000..c2fb863 --- /dev/null +++ b/po/fcitx-unikey.pot @@ -0,0 +1,149 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-05-05 16:38+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: /home/saber/Develop/fcitx-unikey/data/fcitx-unikey.desc:4 +msgid "Input Method" +msgstr "" + +#: /home/saber/Develop/fcitx-unikey/data/fcitx-unikey.desc:14 +#: /home/saber/Develop/fcitx-unikey/build/po/../..//src/unikey-ui.cpp:137 +msgid "Output Charset" +msgstr "" + +#: /home/saber/Develop/fcitx-unikey/data/fcitx-unikey.desc:28 +msgid "Enable spell check" +msgstr "" + +#: /home/saber/Develop/fcitx-unikey/data/fcitx-unikey.desc:33 +msgid "Enable macro" +msgstr "" + +#: /home/saber/Develop/fcitx-unikey/data/fcitx-unikey.desc:38 +msgid "Use oà, _uý (instead of òa, úy)" +msgstr "" + +#: /home/saber/Develop/fcitx-unikey/data/fcitx-unikey.desc:43 +msgid "Allow type with more freedom" +msgstr "" + +#: /home/saber/Develop/fcitx-unikey/data/fcitx-unikey.desc:48 +msgid "Auto restore keys with invalid words" +msgstr "" + +#: /home/saber/Develop/fcitx-unikey/data/fcitx-unikey.desc:53 +msgid "Process W at word begin" +msgstr "" + +# unknown +#: /home/saber/Develop/fcitx-unikey/build/po/tmp/fcitx-unikey.conf.in.h:1 +#: /home/saber/Develop/fcitx-unikey/build/po/tmp/unikey.conf.in.h:1 +#: /home/saber/Develop/fcitx-unikey/build/po/../..//src/unikey-im.cpp:131 +msgid "Unikey" +msgstr "" + +#: unknown +msgid "BK HCM 2" +msgstr "" + +#: unknown +msgid "CString" +msgstr "" + +#: unknown +msgid "NCR Decimal" +msgstr "" + +#: unknown +msgid "NCR Hex" +msgstr "" + +#: unknown +msgid "STelex" +msgstr "" + +#: unknown +msgid "STelex2" +msgstr "" + +#: unknown +msgid "TCVN3" +msgstr "" + +#: unknown +msgid "Telex" +msgstr "" + +#: unknown +msgid "Unicode" +msgstr "" + +#: unknown +msgid "VIQR" +msgstr "" + +#: unknown +msgid "Vni" +msgstr "" + +#: unknown +msgid "VNI Win" +msgstr "" + +#: /home/saber/Develop/fcitx-unikey/build/po/tmp/fcitx-unikey.conf.in.h:2 +msgid "Unikey Wrapper For Fcitx" +msgstr "" + +#: /home/saber/Develop/fcitx-unikey/build/po/../..//src/unikey-ui.cpp:86 +#: /home/saber/Develop/fcitx-unikey/build/po/../..//src/unikey-ui.cpp:153 +msgid "Choose input method" +msgstr "" + +#: /home/saber/Develop/fcitx-unikey/build/po/../..//src/unikey-ui.cpp:94 +#: /home/saber/Develop/fcitx-unikey/build/po/../..//src/unikey-ui.cpp:159 +msgid "Choose output charset" +msgstr "" + +#: /home/saber/Develop/fcitx-unikey/build/po/../..//src/unikey-ui.cpp:100 +#: /home/saber/Develop/fcitx-unikey/build/po/../..//src/unikey-ui.cpp:163 +msgid "Spell Check" +msgstr "" + +#: /home/saber/Develop/fcitx-unikey/build/po/../..//src/unikey-ui.cpp:101 +#: /home/saber/Develop/fcitx-unikey/build/po/../..//src/unikey-ui.cpp:164 +msgid "Enable Spell Check" +msgstr "" + +#: /home/saber/Develop/fcitx-unikey/build/po/../..//src/unikey-ui.cpp:108 +#: /home/saber/Develop/fcitx-unikey/build/po/../..//src/unikey-ui.cpp:168 +msgid "Macro" +msgstr "" + +#: /home/saber/Develop/fcitx-unikey/build/po/../..//src/unikey-ui.cpp:109 +#: /home/saber/Develop/fcitx-unikey/build/po/../..//src/unikey-ui.cpp:169 +msgid "Enable Macro" +msgstr "" + +#: /home/saber/Develop/fcitx-unikey/build/po/../..//src/unikey-ui.cpp:123 +msgid "Unikey Input Method" +msgstr "" + +#: /home/saber/Develop/fcitx-unikey/build/po/../..//src/unikey-ui.cpp:163 +#: /home/saber/Develop/fcitx-unikey/build/po/../..//src/unikey-ui.cpp:168 +msgid "N" +msgstr "" diff --git a/po/getdescpo b/po/getdescpo new file mode 100755 index 0000000..65289a2 --- /dev/null +++ b/po/getdescpo @@ -0,0 +1,46 @@ +#!/bin/sh +filename=desc.po +indir=$1 +outdir=$2 + +cd "$outdir" + +rm -f "$outdir/$filename"; touch "$outdir/$filename" + +cat > "$outdir/$filename" <, YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: fcitx-dev@googlegroups.com\n" +"POT-Creation-Date: 2010-11-17 11:48+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +EOF + +cd $indir + +descfiles=`find "$indir" -name ".hg" -prune -or -name "test" -prune -or -iname "*.desc" | grep desc` + +# Extract Description +for f in $descfiles +do + awk '/^[\t ]*Description=/ { print "\n#: '$f':" NR"\n" "msgid \"" substr($0, 13)"\"\n" "msgstr \"\""}' "$f" >> "$outdir/$filename" +done + +# Extract Group Name +grep -nH '^\[' $descfiles | grep -v 'DescriptionFile' | awk ' "^[" { split($0, a, ":"); split(a[3], b, "/"); print substr(b[1], 2); }' | sort | uniq | awk '{ print "# unknown\nmsgid \""$0"\"\nmsgstr \"\"\n"; }' >> "$outdir/$filename" + +# Extract Enum Name +grep -h 'Enum[0-9]' $descfiles | sed -e 's/Enum[0-9]=//g' | sort | uniq | awk '{ print "#: unknown\nmsgid \""$0"\"\nmsgstr \"\"\n"; }' >> "$outdir/$filename" + diff --git a/po/vi.po b/po/vi.po new file mode 100644 index 0000000..a3eb0d2 --- /dev/null +++ b/po/vi.po @@ -0,0 +1,254 @@ +# Vietnamese translations for ibus-unikey package +# Bản dịch Việt ngữ cho gói tin ibus-unikey. +# Copyright (C) 2009 Free Software Foundation, Inc. +# This file is distributed under the same license as the ibus-unikey package. +# +# Lê Quốc Tuấn , 2009. +# Weng Xuetian , 2012. +msgid "" +msgstr "" +"Project-Id-Version: ibus-unikey 0.6.1\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-05-05 16:38+0800\n" +"PO-Revision-Date: 2012-05-05 16:39+0800\n" +"Last-Translator: Weng Xuetian \n" +"Language-Team: Chinese Simplified \n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Poedit-Language: Vietnamese\n" +"X-Poedit-Country: VIET NAM\n" +"X-Poedit-SourceCharset: utf-8\n" +"X-Generator: Lokalize 1.4\n" + +#: /home/saber/Develop/fcitx-unikey/data/fcitx-unikey.desc:43 +msgid "Allow type with more freedom" +msgstr "Tự động trả phím khi gõ từ không hợp lệ" + +#: /home/saber/Develop/fcitx-unikey/data/fcitx-unikey.desc:48 +msgid "Auto restore keys with invalid words" +msgstr "Tự động trả phím khi gõ từ không hợp lệ" + +#: unknown +msgid "BK HCM 2" +msgstr "BK HCM 2" + +#: unknown +msgid "CString" +msgstr "CString" + +#: /home/saber/Develop/fcitx-unikey/build/po/../..//src/unikey-ui.cpp:86 +#: /home/saber/Develop/fcitx-unikey/build/po/../..//src/unikey-ui.cpp:153 +msgid "Choose input method" +msgstr "Chọn kiểu gõ" + +#: /home/saber/Develop/fcitx-unikey/build/po/../..//src/unikey-ui.cpp:94 +#: /home/saber/Develop/fcitx-unikey/build/po/../..//src/unikey-ui.cpp:159 +msgid "Choose output charset" +msgstr "Chọn bảng mã" + +#: /home/saber/Develop/fcitx-unikey/build/po/../..//src/unikey-ui.cpp:109 +#: /home/saber/Develop/fcitx-unikey/build/po/../..//src/unikey-ui.cpp:169 +msgid "Enable Macro" +msgstr "Bật gõ tắt" + +#: /home/saber/Develop/fcitx-unikey/build/po/../..//src/unikey-ui.cpp:101 +#: /home/saber/Develop/fcitx-unikey/build/po/../..//src/unikey-ui.cpp:164 +msgid "Enable Spell Check" +msgstr "Bật kiểm tra chính tả" + +#: /home/saber/Develop/fcitx-unikey/data/fcitx-unikey.desc:33 +msgid "Enable macro" +msgstr "Bật gõ tắt" + +#: /home/saber/Develop/fcitx-unikey/data/fcitx-unikey.desc:28 +msgid "Enable spell check" +msgstr "Bật kiểm tra chính tả" + +#: /home/saber/Develop/fcitx-unikey/data/fcitx-unikey.desc:4 +msgid "Input Method" +msgstr "Kiểu gõ" + +#: /home/saber/Develop/fcitx-unikey/build/po/../..//src/unikey-ui.cpp:108 +#: /home/saber/Develop/fcitx-unikey/build/po/../..//src/unikey-ui.cpp:168 +msgid "Macro" +msgstr "gõ tắt" + +#: /home/saber/Develop/fcitx-unikey/build/po/../..//src/unikey-ui.cpp:163 +#: /home/saber/Develop/fcitx-unikey/build/po/../..//src/unikey-ui.cpp:168 +msgid "N" +msgstr "N" + +#: unknown +msgid "NCR Decimal" +msgstr "NCR Decimal" + +#: unknown +msgid "NCR Hex" +msgstr "NCR Hex" + +#: /home/saber/Develop/fcitx-unikey/data/fcitx-unikey.desc:14 +#: /home/saber/Develop/fcitx-unikey/build/po/../..//src/unikey-ui.cpp:137 +msgid "Output Charset" +msgstr "Bảng mã" + +#: /home/saber/Develop/fcitx-unikey/data/fcitx-unikey.desc:53 +msgid "Process W at word begin" +msgstr "Xử lý phím W ở đầu từ" + +#: unknown +msgid "STelex" +msgstr "STelex" + +#: unknown +msgid "STelex2" +msgstr "STelex2" + +#: /home/saber/Develop/fcitx-unikey/build/po/../..//src/unikey-ui.cpp:100 +#: /home/saber/Develop/fcitx-unikey/build/po/../..//src/unikey-ui.cpp:163 +msgid "Spell Check" +msgstr "kiểm tra chính tả" + +#: unknown +msgid "TCVN3" +msgstr "TCVN3" + +#: unknown +msgid "Telex" +msgstr "Telex" + +#: unknown +msgid "Unicode" +msgstr "Unicode" + +# unknown +#: /home/saber/Develop/fcitx-unikey/build/po/tmp/fcitx-unikey.conf.in.h:1 +#: /home/saber/Develop/fcitx-unikey/build/po/tmp/unikey.conf.in.h:1 +#: /home/saber/Develop/fcitx-unikey/build/po/../..//src/unikey-im.cpp:131 +msgid "Unikey" +msgstr "Unikey" + +#: /home/saber/Develop/fcitx-unikey/build/po/../..//src/unikey-ui.cpp:123 +msgid "Unikey Input Method" +msgstr "Unikey Kiểu gõ" + +#: /home/saber/Develop/fcitx-unikey/build/po/tmp/fcitx-unikey.conf.in.h:2 +msgid "Unikey Wrapper For Fcitx" +msgstr "" + +#: /home/saber/Develop/fcitx-unikey/data/fcitx-unikey.desc:38 +msgid "Use oà, _uý (instead of òa, úy)" +msgstr "Dùng oà, _uý (thay vì òa, úy)" + +#: unknown +msgid "VIQR" +msgstr "VIQR" + +#: unknown +msgid "VNI Win" +msgstr "VNI Win" + +#: unknown +msgid "Vni" +msgstr "Vni" + +#~ msgid "(replace text)" +#~ msgstr "(chuỗi thay thế)" + +#~ msgid "Input/Output" +#~ msgstr "Nhập/Xuất" + +#~ msgid "Options" +#~ msgstr "Tùy chọn" + +#~ msgid "Auto send PreEdit string to Application when mouse move or click" +#~ msgstr "" +#~ "Tự động gửi chuỗi PreEdit đến ứng dụng khi chuột di chuyển hoặc click" + +#~ msgid "Capture _mouse event" +#~ msgstr "Bắt sự _kiện chuột" + +#~ msgid "Capture mouse event" +#~ msgstr "Bắt sự kiện chuột" + +#~ msgid "Choose file to export" +#~ msgstr "Chọn tập tin để xuất" + +#~ msgid "Choose file to import" +#~ msgstr "Chọn tập tin để nhập" + +#~ msgid "Delete _all" +#~ msgstr "Xóa _hết" + +#~ msgid "Full setup utility for IBus-Unikey" +#~ msgstr "Tiện ích cài đặt đầy đủ cho IBus-Unikey" + +#~ msgid "Full setup..." +#~ msgstr "Cài đặt đầy đủ..." + +#~ msgid "IBus-Unikey Setup" +#~ msgstr "Cài đặt IBus-Unikey" + +#~ msgid "If enable, you can decrease mistake when typing" +#~ msgstr "Nếu bật, bạn có thể giảm lỗi chính tả khi gõ" + +#~ msgid "Macro table definition" +#~ msgstr "Định nghĩa bảng gõ tắt" + +#~ msgid "Options" +#~ msgstr "Tùy chọn" + +#~ msgid "Options for Unikey" +#~ msgstr "Tùy chọn cho Unikey" + +#~ msgid "Replace with" +#~ msgstr "Thay thế bởi" + +#~ msgid "Simple Telex" +#~ msgstr "Simple Telex" + +#~ msgid "Simple Telex 2" +#~ msgstr "Simple Telex 2" + +#, fuzzy +#~ msgid "Toggle Macro" +#~ msgstr "Bật gõ tắt" + +#, fuzzy +#~ msgid "Toggle Spell Check" +#~ msgstr "Bật kiểm tra chính tả" + +#~ msgid "" +#~ "Vietnamese Input Method Engine for IBus using Unikey Engine\n" +#~ "Usage:\n" +#~ " - Choose input method, output charset, options in language bar.\n" +#~ " - There are 4 input methods: Telex, Vni, STelex (simple telex) and " +#~ "STelex2 (which same as STelex, the difference is it use w as ư).\n" +#~ " - And 7 output charsets: Unicode (UTF-8), TCVN3, VNI Win, VIQR, " +#~ "CString, NCR Decimal and NCR Hex.\n" +#~ " - Use + or + to restore keystrokes.\n" +#~ " - Use to commit a word." +#~ msgstr "" +#~ "Bộ gõ tiếng Việt cho IBus dùng Unikey Engine\n" +#~ "Sử dụng:\n" +#~ " - Chọn kiểu gõ, bảng mã, tùy chọn trên thanh ngôn ngữ.\n" +#~ " - Có 4 kiểu gõ: Telex, Vni, STelex (telex đơn giản) và STelex2 (giống " +#~ "như STelex, chỉ khác là nó dùng w như ư).\n" +#~ " - Và 7 bảng mã: Unicode (UTF-8), TCVN3, VNI Win, VIQR, CString, NCR " +#~ "Decimal và NCR Hex.\n" +#~ " - Dùng + hoặc + để khôi phục phím.\n" +#~ " - Dùng để xác nhận từ (kết thúc từ)." + +#~ msgid "Word" +#~ msgstr "Từ" + +#~ msgid "_Edit macro" +#~ msgstr "_Sửa bảng gõ tắt" + +#~ msgid "_Export..." +#~ msgstr "_Xuất..." + +#~ msgid "_Import..." +#~ msgstr "_Nhập..." diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..fb0af74 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,44 @@ +include_directories ( +${PROJECT_SOURCE_DIR}/unikey +${FCITX4_FCITX_INCLUDE_DIRS} +${FCITX4_FCITX_CONFIG_INCLUDE_DIRS} +${FCITX4_FCITX_UTILS_INCLUDE_DIRS} +${PROJECT_BINARY_DIR} +${LIBICONV_INCLUDE_DIR} +) + +set( fcitx_unikey_sources + unikey-im.cpp + unikey-config.cpp + unikey-ui.cpp + ) + +set(UNIKEY_SRCS + ../unikey/byteio.cpp + ../unikey/byteio.h + ../unikey/charset.cpp + ../unikey/charset.h + ../unikey/convert.cpp + ../unikey/data.cpp + ../unikey/data.h + ../unikey/error.cpp + ../unikey/inputproc.cpp + ../unikey/inputproc.h + ../unikey/keycons.h + ../unikey/mactab.cpp + ../unikey/mactab.h + ../unikey/pattern.cpp + ../unikey/pattern.h + ../unikey/ukengine.cpp + ../unikey/ukengine.h + ../unikey/unikey.cpp + ../unikey/unikey.h + ../unikey/usrkeymap.cpp + ../unikey/usrkeymap.h + ../unikey/vnconv.h + ../unikey/vnlexi.h +) + +add_definitions( -DLOCALEDIR=\"${CMAKE_INSTALL_PREFIX}/share/locale\" ) + +fcitx_add_addon(fcitx-unikey ${fcitx_unikey_sources} ${UNIKEY_SRCS} ) diff --git a/src/unikey-config.cpp b/src/unikey-config.cpp new file mode 100644 index 0000000..4d8e464 --- /dev/null +++ b/src/unikey-config.cpp @@ -0,0 +1,32 @@ +/*************************************************************************** + * Copyright (C) 2012~2012 by CSSlayer * + * wengxt@gmail.com * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + ***************************************************************************/ + +#include "unikey-config.h" + +/* USE fcitx provided macro to bind config and variable */ +CONFIG_BINDING_BEGIN(UnikeyConfig) +CONFIG_BINDING_REGISTER("Unikey", "InputMethod", im) +CONFIG_BINDING_REGISTER("Unikey", "OuputCharset", oc) +CONFIG_BINDING_REGISTER("Unikey", "SpellCheck", spellCheck) +CONFIG_BINDING_REGISTER("Unikey", "Macro", macro) +CONFIG_BINDING_REGISTER("Unikey", "ModernStyle", modernStyle) +CONFIG_BINDING_REGISTER("Unikey", "FreeMarking", freeMarking) +CONFIG_BINDING_REGISTER("Unikey", "AutoNonVnRestore", autoNonVnRestore) +CONFIG_BINDING_REGISTER("Unikey", "ProcessWAtBegin", process_w_at_begin) +CONFIG_BINDING_END() \ No newline at end of file diff --git a/src/unikey-config.h b/src/unikey-config.h new file mode 100644 index 0000000..543e9cb --- /dev/null +++ b/src/unikey-config.h @@ -0,0 +1,52 @@ +/*************************************************************************** + * Copyright (C) 2012~2012 by CSSlayer * + * wengxt@gmail.com * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + ***************************************************************************/ + +#ifndef UNIKEY_CONFIG_H +#define UNIKEY_CONFIG_H +#include +#include + +enum UkConv { + UKCONV_XUTF8, + UKCONV_TCVN3, + UKCONV_VNIWIN, + UKCONV_VIQR, + UKCONV_BKHCM2, + UKCONV_UNI_CSTRING, + UKCONV_UNIREF, + UKCONV_UNIREF_HEX +}; + +struct UnikeyConfig +{ + FcitxGenericConfig gconfig; + UkInputMethod im; + UkConv oc; + boolean spellCheck; + boolean macro; + boolean process_w_at_begin; + boolean autoNonVnRestore; + boolean modernStyle; + boolean freeMarking; +}; + + +CONFIG_BINDING_DECLARE(UnikeyConfig); + +#endif // UNIKEY_CONFIG_H \ No newline at end of file diff --git a/src/unikey-im.cpp b/src/unikey-im.cpp new file mode 100644 index 0000000..f8fc4fa --- /dev/null +++ b/src/unikey-im.cpp @@ -0,0 +1,574 @@ +/*************************************************************************** + * Copyright (C) 2012~2012 by CSSlayer * + * wengxt@gmail.com * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + ***************************************************************************/ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "unikey.h" +#include "keycons.h" +#include "vnconv.h" +#include "unikey-config.h" +#include "unikey-im.h" +#include "unikey-ui.h" + +#define CONVERT_BUF_SIZE 1024 + +#ifdef LIBICONV_SECOND_ARGUMENT_IS_CONST +typedef const char* IconvStr; +#else +typedef char* IconvStr; +#endif + +static void* FcitxUnikeyCreate(FcitxInstance* instance); +static void FcitxUnikeyDestroy(void* arg); +static INPUT_RETURN_VALUE FcitxUnikeyDoInput(void* arg, FcitxKeySym sym, unsigned int state); +static boolean FcitxUnikeyInit(void* arg); +static void FcitxUnikeyReset(void* arg); +static void FcitxUnikeyResetUI(void* arg); +static INPUT_RETURN_VALUE FcitxUnikeyDoInputPreedit(FcitxUnikey* unikey, FcitxKeySym sym, unsigned int state); +static void FcitxUnikeyEraseChars(FcitxUnikey *unikey, int num_chars); +static void FcitxUnikeyUpdatePreedit(FcitxUnikey *unikey); + +static boolean LoadUnikeyConfig(UnikeyConfig* config); +static void ConfigUnikey(FcitxUnikey* unikey); +static void ReloadConfigFcitxUnikey(void* arg); +static void SaveUnikeyConfig(UnikeyConfig* fa); + +static int latinToUtf(unsigned char* dst, unsigned char* src, int inSize, int* pOutSize); + +FCITX_EXPORT_API +FcitxIMClass ime = { + FcitxUnikeyCreate, + FcitxUnikeyDestroy +}; +FCITX_EXPORT_API +int ABI_VERSION = FCITX_ABI_VERSION; +static const unsigned int Unikey_OC[] = {CONV_CHARSET_XUTF8, + CONV_CHARSET_TCVN3, + CONV_CHARSET_VNIWIN, + CONV_CHARSET_VIQR, + CONV_CHARSET_BKHCM2, + CONV_CHARSET_UNI_CSTRING, + CONV_CHARSET_UNIREF, + CONV_CHARSET_UNIREF_HEX}; +static const unsigned int NUM_OUTPUTCHARSET = sizeof(Unikey_OC)/sizeof(Unikey_OC[0]); + +static const unsigned char WordBreakSyms[] = +{ + ',', ';', ':', '.', '\"', '\'', '!', '?', ' ', + '<', '>', '=', '+', '-', '*', '/', '\\', + '_', '~', '`', '@', '#', '$', '%', '^', '&', '(', ')', '{', '}', '[', ']', + '|' +}; + +static const unsigned char WordAutoCommit[] = +{ + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'b', 'c', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', + 'p', 'q', 'r', 's', 't', 'v', 'x', 'z', + 'B', 'C', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', + 'P', 'Q', 'R', 'S', 'T', 'V', 'X', 'Z' +}; + + + +int FcitxUnikeyUcs4ToUtf8(FcitxUnikey* unikey, const unsigned int c, char buf[UTF8_MAX_LENGTH + 1]) +{ + unsigned int str[2]; + str[0] = c; + str[1] = 0; + + size_t ucslen = 1; + size_t len = UTF8_MAX_LENGTH; + len *= sizeof(char); + ucslen *= sizeof(unsigned int); + char* p = buf; + IconvStr src = (IconvStr) str; + iconv(unikey->conv, &src, &ucslen, &p, &len); + return (UTF8_MAX_LENGTH - len) / sizeof(char); +} + + +void* FcitxUnikeyCreate(FcitxInstance* instance) +{ + FcitxUnikey* unikey = (FcitxUnikey*) fcitx_utils_malloc0(sizeof(FcitxUnikey)); + + if (!LoadUnikeyConfig(&unikey->config)) + { + free(unikey); + return NULL; + } + unikey->owner = instance; + unikey->preeditstr = new std::string; + union { + short s; + unsigned char b[2]; + } endian; + endian.s = 0x1234; + if (endian.b[0] == 0x12) + unikey->conv = iconv_open("utf-8", "ucs-4be"); + else + unikey->conv = iconv_open("utf-8", "ucs-4le"); + + FcitxIMIFace iface; + memset(&iface, 0, sizeof(FcitxIMIFace)); + iface.Init = FcitxUnikeyInit; + iface.ResetIM = FcitxUnikeyReset; + iface.DoInput = FcitxUnikeyDoInput; + iface.ReloadConfig = ReloadConfigFcitxUnikey; + + FcitxInstanceRegisterIMv2( + instance, + unikey, + "unikey", + _("Unikey"), + "unikey", + iface, + 1, + "vi" + ); + + UnikeySetup(); + + InitializeBar(unikey); + InitializeMenu(unikey); + + ConfigUnikey(unikey); + + FcitxIMEventHook hk; + hk.arg = unikey; + hk.func = FcitxUnikeyResetUI; + + FcitxInstanceRegisterResetInputHook(instance, hk); + + return unikey; +} + +void FcitxUnikeyDestroy(void* arg) +{ + UnikeyCleanup(); +} + + +boolean FcitxUnikeyInit(void* arg) +{ + return true; +} + +void FcitxUnikeyReset(void* arg) +{ + FcitxUnikey* unikey = (FcitxUnikey*) arg; + + UnikeyResetBuf(); + unikey->preeditstr->clear(); +} + +void FcitxUnikeyCommit(FcitxUnikey* unikey) +{ + if (unikey->preeditstr->length() > 0) { + FcitxInstanceCommitString(unikey->owner, FcitxInstanceGetCurrentIC(unikey->owner), unikey->preeditstr->c_str()); + } + FcitxUnikeyReset(unikey); +} + +INPUT_RETURN_VALUE FcitxUnikeyDoInput(void* arg, FcitxKeySym sym, unsigned int state) +{ + FcitxUnikey* unikey = (FcitxUnikey*) arg; + INPUT_RETURN_VALUE tmp; + FcitxInputState* input = FcitxInstanceGetInputState(unikey->owner); + /* use origin sym and state here */ + sym = (FcitxKeySym) FcitxInputStateGetKeySym(input); + state = FcitxInputStateGetKeyState(input); + + tmp = FcitxUnikeyDoInputPreedit(unikey, sym, state); + + // check last keyevent with shift + if (sym >= FcitxKey_space && sym <=FcitxKey_asciitilde) + { + unikey->last_key_with_shift = state & FcitxKeyState_Shift; + } + else + { + unikey->last_key_with_shift = false; + } // end check last keyevent with shift + + return tmp; +} + +INPUT_RETURN_VALUE FcitxUnikeyDoInputPreedit(FcitxUnikey* unikey, FcitxKeySym sym, unsigned int state) +{ + + if (state & FcitxKeyState_Ctrl + || state & FcitxKeyState_Alt // alternate mask + || sym == FcitxKey_Control_L + || sym == FcitxKey_Control_R + || sym == FcitxKey_Tab + || sym == FcitxKey_Return + || sym == FcitxKey_Delete + || sym == FcitxKey_KP_Enter + || (sym >= FcitxKey_Home && sym <= FcitxKey_Insert) + || (sym >= FcitxKey_KP_Home && sym <= FcitxKey_KP_Delete) + ) + { + FcitxUnikeyCommit(unikey); + return IRV_FLAG_FORWARD_KEY; + } + + else if ((sym >= FcitxKey_Caps_Lock && sym <= FcitxKey_Hyper_R) + || (!(state & FcitxKeyState_Shift) && (sym == FcitxKey_Shift_L || sym == FcitxKey_Shift_R)) // when press one shift key + ) + { + return IRV_TO_PROCESS; + } + + // capture BackSpace + else if (sym == FcitxKey_BackSpace) + { + UnikeyBackspacePress(); + + if (UnikeyBackspaces == 0 || unikey->preeditstr->empty()) + { + FcitxUnikeyCommit(unikey); + return IRV_FLAG_FORWARD_KEY; + } + else + { + if (unikey->preeditstr->length() <= (unsigned int)UnikeyBackspaces) + { + unikey->preeditstr->clear(); + unikey->auto_commit = true; + } + else + { + FcitxUnikeyEraseChars(unikey, UnikeyBackspaces); + FcitxUnikeyUpdatePreedit(unikey); + } + + // change tone position after press backspace + if (UnikeyBufChars > 0) + { + if (unikey->config.oc == UKCONV_XUTF8) + { + unikey->preeditstr->append((const char*)UnikeyBuf, UnikeyBufChars); + } + else + { + static unsigned char buf[CONVERT_BUF_SIZE]; + int bufSize = CONVERT_BUF_SIZE; + + latinToUtf(buf, UnikeyBuf, UnikeyBufChars, &bufSize); + unikey->preeditstr->append((const char*)buf, CONVERT_BUF_SIZE - bufSize); + } + + unikey->auto_commit = false; + FcitxUnikeyUpdatePreedit(unikey); + } + } + return IRV_DISPLAY_MESSAGE; + } // end capture BackSpace + + else if (sym >=FcitxKey_KP_Multiply && sym <=FcitxKey_KP_9) + { + FcitxUnikeyCommit(unikey); + return IRV_FLAG_FORWARD_KEY; + } + + // capture ascii printable char + else if ((sym >= FcitxKey_space && sym <=FcitxKey_asciitilde) + || sym == FcitxKey_Shift_L || sym == FcitxKey_Shift_R) // sure this have FcitxKey_SHIFT_MASK + { + unsigned int i = 0; + + UnikeySetCapsState(state & FcitxKeyState_Shift, state & FcitxKeyState_CapsLock); + + // process sym + + // auto commit word that never need to change later in preedit string (like consonant - phu am) + // if macro enabled, then not auto commit. Because macro may change any word + if (unikey->ukopt.macroEnabled == 0 && (UnikeyAtWordBeginning() || unikey->auto_commit)) + { + for (i =0; i < sizeof(WordAutoCommit); i++) + { + if (sym == WordAutoCommit[i]) + { + UnikeyPutChar(sym); + unikey->auto_commit = true; + return IRV_FLAG_FORWARD_KEY; + } + } + } // end auto commit + + if ((unikey->config.im == UkTelex || unikey->config.im == UkSimpleTelex2) + && unikey->config.process_w_at_begin == false + && UnikeyAtWordBeginning() + && (sym == FcitxKey_w || sym == FcitxKey_W)) + { + UnikeyPutChar(sym); + if (unikey->ukopt.macroEnabled == 0) + { + return IRV_TO_PROCESS; + } + else + { + unikey->preeditstr->append(sym==FcitxKey_w?"w":"W"); + FcitxUnikeyUpdatePreedit(unikey); + return IRV_DISPLAY_MESSAGE; + } + } + + unikey->auto_commit = false; + + // shift + space, shift + shift event + if ((unikey->last_key_with_shift == false && state & FcitxKeyState_Shift + && sym == FcitxKey_space && !UnikeyAtWordBeginning()) + || (sym == FcitxKey_Shift_L || sym == FcitxKey_Shift_R) // (&& state & FcitxKey_SHIFT_MASK), sure this have FcitxKey_SHIFT_MASK + ) + { + UnikeyRestoreKeyStrokes(); + } // end shift + space, shift + shift event + + else + { + UnikeyFilter(sym); + } + // end process sym + + // process result of ukengine + if (UnikeyBackspaces > 0) + { + if (unikey->preeditstr->length() <= (unsigned int)UnikeyBackspaces) + { + unikey->preeditstr->clear(); + } + else + { + FcitxUnikeyEraseChars(unikey, UnikeyBackspaces); + } + } + + if (UnikeyBufChars > 0) + { + if (unikey->config.oc == UKCONV_XUTF8) + { + unikey->preeditstr->append((const char*)UnikeyBuf, UnikeyBufChars); + } + else + { + unsigned char buf[CONVERT_BUF_SIZE + 1]; + int bufSize = CONVERT_BUF_SIZE; + + latinToUtf(buf, UnikeyBuf, UnikeyBufChars, &bufSize); + unikey->preeditstr->append((const char*)buf, CONVERT_BUF_SIZE - bufSize); + } + } + else if (sym != FcitxKey_Shift_L && sym != FcitxKey_Shift_R) // if ukengine not process + { + int n; + char s[7] = {0, 0, 0, 0, 0, 0, 0}; + + n = FcitxUnikeyUcs4ToUtf8(unikey, (unsigned int)sym, s); // convert ucs4 to utf8 char + unikey->preeditstr->append(s, n); + } + // end process result of ukengine + + // commit string: if need + if (unikey->preeditstr->length() > 0) + { + unsigned int i; + for (i = 0; i < sizeof(WordBreakSyms); i++) + { + if (WordBreakSyms[i] == unikey->preeditstr->at(unikey->preeditstr->length()-1) + && WordBreakSyms[i] == sym) + { + FcitxUnikeyCommit(unikey); + return IRV_DO_NOTHING; + } + } + } + // end commit string + + FcitxUnikeyUpdatePreedit(unikey); + return IRV_DISPLAY_MESSAGE; + } //end capture printable char + + // non process key + + FcitxUnikeyCommit(unikey); + return IRV_FLAG_FORWARD_KEY; +} + + +// code from x-unikey, for convert charset that not is XUtf-8 +int latinToUtf(unsigned char* dst, unsigned char* src, int inSize, int* pOutSize) +{ + int i; + int outLeft; + unsigned char ch; + + outLeft = *pOutSize; + + for (i=0; i= 0) + *dst++ = ch; + } + else + { + outLeft -= 2; + if (outLeft >= 0) + { + *dst++ = (0xC0 | ch >> 6); + *dst++ = (0x80 | (ch & 0x3F)); + } + } + } + + *pOutSize = outLeft; + return (outLeft >= 0); +} + + +static void FcitxUnikeyEraseChars(FcitxUnikey *unikey, int num_chars) +{ + int i, k; + unsigned char c; + k = num_chars; + + for ( i = unikey->preeditstr->length()-1; i >= 0 && k > 0; i--) + { + c = unikey->preeditstr->at(i); + + // count down if byte is begin byte of utf-8 char + if (c < (unsigned char)'\x80' || c >= (unsigned char)'\xC0') + { + k--; + } + } + + unikey->preeditstr->erase(i+1); +} + + +static void FcitxUnikeyUpdatePreedit(FcitxUnikey *unikey) +{ + FcitxInputState* input = FcitxInstanceGetInputState(unikey->owner); + FcitxMessages* preedit = FcitxInputStateGetPreedit(input); + FcitxMessages* clientPreedit = FcitxInputStateGetClientPreedit(input); + FcitxInputContext* ic = FcitxInstanceGetCurrentIC(unikey->owner); + FcitxProfile* profile = FcitxInstanceGetProfile(unikey->owner); + FcitxInstanceCleanInputWindowUp(unikey->owner); + if (ic && ((ic->contextCaps & CAPACITY_PREEDIT) == 0 || !profile->bUsePreedit)) { + FcitxMessagesAddMessageAtLast(preedit, MSG_INPUT, "%s", unikey->preeditstr->c_str()); + FcitxInputStateSetCursorPos(input, unikey->preeditstr->size()); + } + FcitxMessagesAddMessageAtLast(clientPreedit, MSG_INPUT, "%s", unikey->preeditstr->c_str()); + FcitxInputStateSetClientCursorPos(input, unikey->preeditstr->size()); +} + +CONFIG_DESC_DEFINE(GetUnikeyConfigDesc, "fcitx-unikey.desc") + +boolean LoadUnikeyConfig(UnikeyConfig* config) +{ + FcitxConfigFileDesc *configDesc = GetUnikeyConfigDesc(); + if (!configDesc) + return false; + + FILE *fp = FcitxXDGGetFileUserWithPrefix("conf", "fcitx-unikey.config", "r", NULL); + + if (!fp) + { + if (errno == ENOENT) + SaveUnikeyConfig(config); + } + FcitxConfigFile *cfile = FcitxConfigParseConfigFileFp(fp, configDesc); + + UnikeyConfigConfigBind(config, cfile, configDesc); + FcitxConfigBindSync(&config->gconfig); + + if (fp) + fclose(fp); + return true; +} + +void ConfigUnikey(FcitxUnikey* unikey) +{ + unikey->ukopt.macroEnabled = unikey->config.macro; + unikey->ukopt.spellCheckEnabled = unikey->config.spellCheck; + unikey->ukopt.autoNonVnRestore = unikey->config.autoNonVnRestore; + unikey->ukopt.modernStyle = unikey->config.modernStyle; + unikey->ukopt.freeMarking = unikey->config.freeMarking; + UnikeySetInputMethod(unikey->config.im); + UnikeySetOutputCharset(Unikey_OC[unikey->config.oc]); + UnikeySetOptions(&unikey->ukopt); + + UpdateUnikeyUI(unikey); +} + +void ReloadConfigFcitxUnikey(void* arg) +{ + FcitxUnikey* unikey = (FcitxUnikey*) arg; + LoadUnikeyConfig(&unikey->config); + ConfigUnikey(unikey); +} + +void SaveUnikeyConfig(UnikeyConfig* fa) +{ + FcitxConfigFileDesc *configDesc = GetUnikeyConfigDesc(); + FILE *fp = FcitxXDGGetFileUserWithPrefix("conf", "fcitx-unikey.config", "w", NULL); + FcitxConfigSaveConfigFileFp(fp, &fa->gconfig, configDesc); + if (fp) + fclose(fp); +} + +void FcitxUnikeyResetUI(void* arg) +{ + FcitxUnikey* unikey = (FcitxUnikey*) arg; + FcitxInstance* instance = unikey->owner; + FcitxIM* im = FcitxInstanceGetCurrentIM(instance); + boolean visible; + if (!im || strcmp(im->uniqueName, "unikey") != 0) + visible = false; + else + visible = true; + FcitxUISetStatusVisable(instance, "unikey-input-method", visible); + FcitxUISetStatusVisable(instance, "unikey-output-charset", visible); + FcitxUISetStatusVisable(instance, "unikey-spell-check", visible); + FcitxUISetStatusVisable(instance, "unikey-macro", visible); +} + +void UpdateUnikeyConfig(FcitxUnikey* unikey) +{ + ConfigUnikey(unikey); + SaveUnikeyConfig(&unikey->config); +} + diff --git a/src/unikey-im.h b/src/unikey-im.h new file mode 100644 index 0000000..9e503c0 --- /dev/null +++ b/src/unikey-im.h @@ -0,0 +1,45 @@ +/*************************************************************************** + * Copyright (C) 2012~2012 by CSSlayer * + * wengxt@gmail.com * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + ***************************************************************************/ + +#ifndef UNIKEY_IM_H +#define UNIKEY_IM_H +#include +#include +#include +#include + +#define _(x) dgettext("fcitx-unikey", (x)) +#include "unikey-config.h" + +struct FcitxUnikey +{ + UnikeyConfig config; + std::string* preeditstr; + UnikeyOptions ukopt; + FcitxInstance* owner; + bool auto_commit; + bool last_key_with_shift; + iconv_t conv; + FcitxUIMenu imMenu; + FcitxUIMenu ocMenu; +}; + +void UpdateUnikeyConfig(FcitxUnikey* unikey); + +#endif //UNIKEY_IM_H \ No newline at end of file diff --git a/src/unikey-ui.cpp b/src/unikey-ui.cpp new file mode 100644 index 0000000..83680cf --- /dev/null +++ b/src/unikey-ui.cpp @@ -0,0 +1,189 @@ +/*************************************************************************** + * Copyright (C) 2012~2012 by CSSlayer * + * wengxt@gmail.com * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + ***************************************************************************/ + +#include "unikey-im.h" + +const char* Unikey_IMNames[] = {"Telex", "Vni", "STelex", "STelex2"}; +const UkInputMethod Unikey_IM[] = {UkTelex, UkVni, UkSimpleTelex, UkSimpleTelex2}; +const unsigned int NUM_INPUTMETHOD = sizeof(Unikey_IM)/sizeof(Unikey_IM[0]); + +const char* Unikey_OCNames[] = {"Unicode", + "TCVN3", + "VNI Win", + "VIQR", + "BK HCM 2", + "CString", + "NCR Decimal", + "NCR Hex"}; +const unsigned int NUM_OUTPUTCHARSET = sizeof(Unikey_OCNames)/sizeof(Unikey_OCNames[0]); + +void UpdateIMMenu(FcitxUIMenu *menu) +{ + FcitxUnikey* unikey = (FcitxUnikey*) menu->priv; + menu->mark = unikey->config.im; +} + +boolean IMMenuAction(FcitxUIMenu *menu, int index) +{ + FcitxUnikey* unikey = (FcitxUnikey*) menu->priv; + unikey->config.im = (UkInputMethod) index; + UpdateUnikeyConfig(unikey); + return true; +} + +void UpdateOCMenu(FcitxUIMenu *menu) +{ + FcitxUnikey* unikey = (FcitxUnikey*) menu->priv; + menu->mark = unikey->config.oc; +} + +boolean OCMenuAction(FcitxUIMenu *menu, int index) +{ + FcitxUnikey* unikey = (FcitxUnikey*) menu->priv; + unikey->config.oc =(UkConv) index; + UpdateUnikeyConfig(unikey); + return true; +} + +static const char* GetIMIconName(void* arg) +{ + return ""; +} + +static const char* GetOCIconName(void* arg) +{ + return ""; +} + +void ToggleSpellCheck(void *arg) +{ + FcitxUnikey* unikey = (FcitxUnikey*) arg; + unikey->config.spellCheck = !unikey->config.spellCheck; + UpdateUnikeyConfig(unikey); +} + +boolean GetSpellCheck(void *arg) +{ + FcitxUnikey* unikey = (FcitxUnikey*) arg; + return unikey->config.spellCheck; +} + +void ToggleMacro(void *arg) +{ + FcitxUnikey* unikey = (FcitxUnikey*) arg; + unikey->config.macro = !unikey->config.macro; + UpdateUnikeyConfig(unikey); +} + +boolean GetMacro(void *arg) +{ + FcitxUnikey* unikey = (FcitxUnikey*) arg; + return unikey->config.spellCheck; +} + +void InitializeBar(FcitxUnikey* unikey) { + FcitxInstance* instance = unikey->owner; + FcitxUIRegisterComplexStatus(instance, unikey, + "unikey-input-method", + "", + _("Choose input method"), + NULL, + GetIMIconName + ); + + FcitxUIRegisterComplexStatus(instance, unikey, + "unikey-output-charset", + "", + _("Choose output charset"), + NULL, + GetOCIconName + ); + FcitxUIRegisterStatus(instance, unikey, + "unikey-spell-check", + _("Spell Check"), + _("Enable Spell Check"), + ToggleSpellCheck, + GetSpellCheck + ); + + FcitxUIRegisterStatus(instance, unikey, + "unikey-macro", + _("Macro"), + _("Enable Macro"), + ToggleMacro, + GetMacro + ); + FcitxUISetStatusVisable(instance, "unikey-input-method", false); + FcitxUISetStatusVisable(instance, "unikey-output-charset", false); + FcitxUISetStatusVisable(instance, "unikey-spell-check", false); + FcitxUISetStatusVisable(instance, "unikey-macro", false); +} + +void InitializeMenu(FcitxUnikey* unikey) { + FcitxInstance* instance = unikey->owner; + FcitxMenuInit(&unikey->imMenu); + FcitxUIMenu* imMenu = &unikey->imMenu; + imMenu->name = strdup(_("Unikey Input Method")); + imMenu->candStatusBind = strdup("unikey-input-method"); + imMenu->UpdateMenu = UpdateIMMenu; + imMenu->MenuAction = IMMenuAction; + imMenu->priv = unikey; + imMenu->isSubMenu = false; + int i; + for (i = 0; i < NUM_INPUTMETHOD; i ++) + FcitxMenuAddMenuItem(imMenu, _(Unikey_IMNames[i]), MENUTYPE_SIMPLE, NULL); + + FcitxUIRegisterMenu(instance, imMenu); + + FcitxMenuInit(&unikey->ocMenu); + FcitxUIMenu* ocMenu = &unikey->ocMenu; + ocMenu->name = strdup(_("Output Charset")); + ocMenu->candStatusBind = strdup("unikey-output-charset"); + ocMenu->UpdateMenu = UpdateOCMenu; + ocMenu->MenuAction = OCMenuAction; + ocMenu->priv = unikey; + ocMenu->isSubMenu = false; + for (i = 0; i < NUM_INPUTMETHOD; i ++) + FcitxMenuAddMenuItem(ocMenu, _(Unikey_OCNames[i]), MENUTYPE_SIMPLE, NULL); + FcitxUIRegisterMenu(instance, ocMenu); +} + +void UpdateUnikeyUI(FcitxUnikey* unikey) +{ + FcitxUISetStatusString(unikey->owner, + "unikey-input-method", + _(Unikey_IMNames[unikey->config.im]), + _("Choose input method")); + + + FcitxUISetStatusString(unikey->owner, + "unikey-output-charset", + _(Unikey_OCNames[unikey->config.oc]), + _("Choose output charset")); + + FcitxUISetStatusString(unikey->owner, + "unikey-spell-check", + unikey->config.spellCheck? _("Spell Check"): _("N"), + _("Enable Spell Check")); + + FcitxUISetStatusString(unikey->owner, + "unikey-macro", + unikey->config.macro? _("Macro"): _("N"), + _("Enable Macro")); +} diff --git a/src/unikey-ui.h b/src/unikey-ui.h new file mode 100644 index 0000000..4299d7f --- /dev/null +++ b/src/unikey-ui.h @@ -0,0 +1,28 @@ +/*************************************************************************** + * Copyright (C) 2012~2012 by CSSlayer * + * wengxt@gmail.com * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + ***************************************************************************/ + +#ifndef UNIKEY_UI_H +#define UNIKEY_UI_H +#include "unikey-im.h" + +void InitializeBar(FcitxUnikey* unikey); +void InitializeMenu(FcitxUnikey* unikey); +void UpdateUnikeyUI(FcitxUnikey* unikey); + +#endif //UNIKEY_UI_H \ No newline at end of file diff --git a/unikey/COPYING b/unikey/COPYING new file mode 100644 index 0000000..bf50f20 --- /dev/null +++ b/unikey/COPYING @@ -0,0 +1,482 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307 USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/unikey/README b/unikey/README new file mode 100644 index 0000000..34c1f77 --- /dev/null +++ b/unikey/README @@ -0,0 +1,6 @@ + This folder contains ukengine (with changes +for better use in my project) taking from project +x-unikey (http://www.unikey.org). + + Read COPYING for License of ukengine. + diff --git a/unikey/byteio.cpp b/unikey/byteio.cpp new file mode 100644 index 0000000..a69c222 --- /dev/null +++ b/unikey/byteio.cpp @@ -0,0 +1,528 @@ +// -*- coding:unix; mode:c++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- +#include +#include "byteio.h" + +//------------------------------------------------ +StringBIStream::StringBIStream(UKBYTE *data, int len, int elementSize) +{ + m_data = m_current = data; + m_len = m_left = len; + if (len == -1) { + if (elementSize == 2) + m_eos = (*(UKWORD *)data == 0); + else if (elementSize == 4) + m_eos = (*(UKDWORD *)data == 4); + else + m_eos = (*data == 0); + } + else + m_eos = (len <= 0); + m_didBookmark = 0; +} + +//------------------------------------------------ +int StringBIStream::eos() +{ + return m_eos; +} + +//------------------------------------------------ +int StringBIStream::getNext(UKBYTE & b) +{ + if (m_eos) + return 0; + b = *m_current++; + if (m_len == -1) { + m_eos = (b == 0); + } + else { + m_left--; + m_eos = (m_left <= 0); + } + return 1; +} + +//------------------------------------------------ +int StringBIStream::unget(UKBYTE b) +{ + if (m_current != m_data) { + *--m_current = b; + m_eos = 0; + if (m_len != -1) + m_left++; + } + return 1; +} + +//------------------------------------------------ +int StringBIStream::getNextW(UKWORD & w) +{ + if (m_eos) return 0; + w = *((UKWORD *)m_current); + m_current += 2; + if (m_len == -1) + m_eos = (w == 0); + else { + m_left -= 2; + m_eos = (m_left <= 0); + } + return 1; +} + +//------------------------------------------------ +int StringBIStream::getNextDW(UKDWORD & dw) +{ + if (m_eos) return 0; + + dw = *((UKDWORD *)m_current); + m_current += 4; + if (m_len == -1) + m_eos = (dw == 0); + else { + m_left -= 4; + m_eos = (m_left <= 0); + } + return 1; +} + +//------------------------------------------------ +int StringBIStream::peekNext(UKBYTE & b) +{ + if (m_eos) + return 0; + b = *m_current; + return 1; +} + +//------------------------------------------------ +int StringBIStream::peekNextW(UKWORD & w) +{ + if (m_eos) + return 0; + w = *((UKWORD *)m_current); + return 1; +} + +/* +//------------------------------------------------ +int StringBIStream::peekNextDW(UKDWORD & dw) +{ + if (m_eos) + return 0; + dw = *((UKDWORD *)m_current); + return 1; +} +*/ + +//------------------------------------------------ +void StringBIStream::reopen() +{ + m_current = m_data; + m_left = m_len; + if (m_len == -1) + m_eos = (m_data == 0); + else + m_eos = (m_len <= 0); + m_didBookmark = 0; +} + +//------------------------------------------------ +int StringBIStream::bookmark() +{ + m_didBookmark = 1; + m_bookmark.current = m_current; + m_bookmark.data = m_data; + m_bookmark.eos = m_eos; + m_bookmark.left = m_left; + m_bookmark.len = m_len; + return 1; +} + +//------------------------------------------------ +int StringBIStream::gotoBookmark() +{ + if (!m_didBookmark) + return 0; + m_current = m_bookmark.current; + m_data = m_bookmark.data; + m_eos = m_bookmark.eos; + m_left = m_bookmark.left; + m_len = m_bookmark.len; + return 1; +} + +//------------------------------------------------ +int StringBIStream::close() +{ + return 1; +}; + +////////////////////////////////////////////////// +// Class StringBOStream +////////////////////////////////////////////////// + +//------------------------------------------------ +StringBOStream::StringBOStream(UKBYTE *buf, int len) +{ + m_current = m_buf = buf; + m_len = len; + m_out = 0; + m_bad = 0; +} + +//------------------------------------------------ +int StringBOStream::putB(UKBYTE b) +{ + m_out++; +/* + if (m_out >= 2147483647) { + int err; + err = 1; + } +*/ + if (m_bad) + return 0; +/* + if (m_out < 0) { + int i; + i = 1; + } +*/ + if (m_out <= m_len) { + *m_current++ = b; + return 1; + } + m_bad = 1; + return 0; +} + +//------------------------------------------------ +int StringBOStream::putW(UKWORD w) +{ + m_out += 2; + if (m_bad) + return 0; + if (m_out <= m_len) { + *((UKWORD *)m_current) = w; + m_current += 2; + return 1; + } + m_bad = 1; + return 0; +} + +//------------------------------------------------ +int StringBOStream::puts(const char *s, int size) +{ + if (size == -1) { + while (*s) { + m_out++; + if (m_out <= m_len) + *m_current++ = *s; + s++; + } + if (!m_bad && m_out > m_len) + m_bad = 1; + return (!m_bad); + } + + int n; + if (!m_bad && m_out <= m_len) { + n = m_len - m_out; + if (n>size) + n = size; + memcpy(m_current, s, n); + m_current += n; + } + + m_out += size; + if (!m_bad && m_out > m_len) + m_bad = 1; + return (!m_bad); +} + +//------------------------------------------------ +void StringBOStream::reopen() +{ + m_current = m_buf; + m_out = 0; + m_bad = 0; +} + + +//------------------------------------------------ +int StringBOStream::isOK() +{ + return !m_bad; +} + + +//////////////////////////////////////////////////// +// Class FileBIStream // +//////////////////////////////////////////////////// + +//---------------------------------------------------- +FileBIStream::FileBIStream(int bufSize, char *buf) +{ + m_file = NULL; + m_buf = buf; + m_bufSize = bufSize; + m_own = 1; + m_didBookmark = 0; + + m_readAhead = 0; + m_lastIsAhead = 0; +} + +//---------------------------------------------------- +FileBIStream::~FileBIStream() +{ + if (m_own) + close(); +} + +//---------------------------------------------------- +int FileBIStream::open(const char *fileName) +{ + m_file = fopen(fileName, "rb"); + if (m_file == NULL) + return 0; + setvbuf(m_file, m_buf, _IOFBF, m_bufSize); + m_own = 0; + m_readAhead = 0; + m_lastIsAhead = 0; + return 1; +} + +//---------------------------------------------------- +int FileBIStream::close() +{ + if (m_file != NULL) { + fclose(m_file); + m_file = NULL; + } + return 1; +} + +//---------------------------------------------------- +void FileBIStream::attach(FILE * f) +{ + m_file = f; + m_own = 0; + m_readAhead = 0; + m_lastIsAhead = 0; +} + +//---------------------------------------------------- +int FileBIStream::eos() +{ + if (m_readAhead) + return 0; + return feof(m_file); +} + +//---------------------------------------------------- +int FileBIStream::getNext(UKBYTE &b) +{ + if (m_readAhead) { + m_readAhead = 0; + b = m_readByte; + m_lastIsAhead = 1; + return 1; + } + + m_lastIsAhead = 0; + b = fgetc(m_file); + return (!feof(m_file)); +} + +//---------------------------------------------------- +int FileBIStream::peekNext(UKBYTE &b) +{ + if (m_readAhead) { + b = m_readByte; + return 1; + } + + b = fgetc(m_file); + if (feof(m_file)) + return 0; + ungetc(b, m_file); + return 1; +} + +//---------------------------------------------------- +int FileBIStream::unget(UKBYTE b) +{ + if (m_lastIsAhead) { + m_lastIsAhead = 0; + m_readAhead = 1; + m_readByte = b; + return 1; + } + + ungetc(b, m_file); + return 1; +} + +//---------------------------------------------------- +int FileBIStream::getNextW(UKWORD &w) +{ + UKBYTE b1, b2; + + if (getNext(b1)) { + if (getNext(b2)) { + *((UKBYTE *)&w) = b1; + *(((UKBYTE *)&w)+1) = b2; + return 1; + } + } + return 0; +} + +//---------------------------------------------------- +int FileBIStream::getNextDW(UKDWORD &dw) +{ + UKWORD w1, w2; + if (getNextW(w1)) { + if (getNextW(w2)) { + *((UKWORD *)&dw) = w1; + *(((UKWORD *)&dw)+1) = w2; + return 1; + } + } + return 0; + +} +//---------------------------------------------------- +int FileBIStream::peekNextW(UKWORD &w) +{ + UKBYTE hi, low; + if (getNext(low)) { + if (getNext(hi)) { + unget(hi); + w = hi; + w = (w << 8) + low; + m_readAhead = 1; + m_readByte = low; + m_lastIsAhead = 0; + return 1; + } + + m_readAhead = 1; + m_readByte = low; + m_lastIsAhead = 0; + return 0; + } + return 0; +} + +//---------------------------------------------------- +int FileBIStream::bookmark() +{ + m_didBookmark = 1; + m_bookmark.pos = ftell(m_file); + return 1; +} + + +//---------------------------------------------------- +int FileBIStream::gotoBookmark() +{ + if (!m_didBookmark) + return 0; + fseek(m_file, m_bookmark.pos, SEEK_SET); + return 1; +} + +//////////////////////////////////////////////////// +// Class FileBOStream // +//////////////////////////////////////////////////// +//---------------------------------------------------- +FileBOStream::FileBOStream(int bufSize, char *buf) +{ + m_file = NULL; + m_buf = buf; + m_bufSize = bufSize; + m_own = 1; + m_bad = 1; +} + +//---------------------------------------------------- +FileBOStream::~FileBOStream() +{ + if (m_own) + close(); +} + +//---------------------------------------------------- +int FileBOStream::open(const char *fileName) +{ + m_file = fopen(fileName, "wb"); + if (m_file == NULL) + return 0; + m_bad = 0; + setvbuf(m_file, m_buf, _IOFBF, m_bufSize); + m_own = 1; + return 1; +} + +//---------------------------------------------------- +void FileBOStream::attach(FILE * f) +{ + m_file = f; + m_own = 0; + m_bad = 0; +} + +//---------------------------------------------------- +int FileBOStream::close() +{ + if (m_file != NULL) { + fclose(m_file); + m_file = NULL; + } + return 1; +} + +//---------------------------------------------------- +int FileBOStream::putB(UKBYTE b) +{ + if (m_bad) + return 0; + m_bad = (fputc(b, m_file) == EOF); + return (!m_bad); +} + +//---------------------------------------------------- +int FileBOStream::putW(UKWORD w) +{ + if (m_bad) + return 0; + // m_bad = (fputwc(w, m_file) == WEOF); + m_bad = (fputc((UKBYTE)w, m_file) == EOF); + if (m_bad) + return 0; + m_bad = (fputc((UKBYTE)(w >> 8), m_file) == EOF); + return (!m_bad); +} + +//---------------------------------------------------- +int FileBOStream::puts(const char *s, int size) +{ + if (m_bad) + return 0; + if (size == -1) { + m_bad = (fputs(s, m_file) == EOF); + return (!m_bad); + } + int out = fwrite(s, 1, size, m_file); + m_bad = (out != size); + return (!m_bad); +} + +//---------------------------------------------------- +int FileBOStream::isOK() +{ + return !m_bad; +} diff --git a/unikey/byteio.h b/unikey/byteio.h new file mode 100644 index 0000000..bc42678 --- /dev/null +++ b/unikey/byteio.h @@ -0,0 +1,194 @@ +// -*- coding:unix; mode:c++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- +#ifndef BYTE_IO_STREAM_H +#define BYTE_IO_STREAM_H + + +//#include "vnconv.h" +#include + +typedef unsigned char UKBYTE; +typedef unsigned short UKWORD; +typedef unsigned int UKDWORD; + +//---------------------------------------------------- +class ByteStream { + public: + virtual ~ByteStream(){}; +}; + +//---------------------------------------------------- +class ByteInStream: public ByteStream +{ +public: + virtual int getNext(UKBYTE &b) = 0; + virtual int peekNext(UKBYTE &b) = 0; + virtual int unget(UKBYTE b) = 0; + + virtual int getNextW(UKWORD &w) = 0; + virtual int peekNextW(UKWORD &w) = 0; + + virtual int getNextDW(UKDWORD &dw) = 0; + + virtual int bookmark() //no support for bookmark by default + { + return 0; + } + + virtual int gotoBookmark() + { + return 0; + } + + virtual int eos() = 0; //end of stream + virtual int close() = 0; +}; + +//---------------------------------------------------- +class ByteOutStream: public ByteStream +{ +public: + virtual int putB(UKBYTE b) = 0; + virtual int putW(UKWORD w) = 0; + virtual int puts(const char *s, int size = -1) = 0; // write an 8-bit string + virtual int isOK() = 0;// get current stream state +}; + +//---------------------------------------------------- +class StringBIStream : public ByteInStream +{ +protected: + int m_eos; + UKBYTE *m_data, *m_current; + int m_len, m_left; + + struct { + int eos; + UKBYTE *data, *current; + int len, left; + } m_bookmark; + + int m_didBookmark; + +public: + StringBIStream(UKBYTE *data, int len, int elementSize = 1); + virtual int getNext(UKBYTE &b); + virtual int peekNext(UKBYTE &b); + virtual int unget(UKBYTE b); + + virtual int getNextW(UKWORD &w); + virtual int peekNextW(UKWORD &w); + + virtual int getNextDW(UKDWORD &dw); + + virtual int eos(); //end of stream + virtual int close(); + + virtual int bookmark(); + virtual int gotoBookmark(); + + void reopen(); + int left() { + return m_left; + } +}; + +//---------------------------------------------------- +class FileBIStream : public ByteInStream +{ +protected: + FILE *m_file; + int m_bufSize; + char *m_buf; + int m_own; + int m_didBookmark; + + struct { + long pos; + } m_bookmark; + + //some systems don't have wide char IO functions + //we have to use this variables to implement that + UKBYTE m_readByte; + int m_readAhead; + int m_lastIsAhead; + +public: + + FileBIStream(int bufsize = 8192, char *buf = NULL); +// FileBIStream(char *fileName, int bufsize = 8192, void *buf = NULL); + + int open(const char *fileName); + void attach(FILE *f); + virtual int close(); + + virtual int getNext(UKBYTE &b); + virtual int peekNext(UKBYTE &b); + virtual int unget(UKBYTE b); + + virtual int getNextW(UKWORD &w); + virtual int peekNextW(UKWORD &w); + + virtual int getNextDW(UKDWORD &dw); + + virtual int eos(); //end of stream + + virtual int bookmark(); + virtual int gotoBookmark(); + + virtual ~FileBIStream(); +}; + + +//---------------------------------------------------- +class StringBOStream : public ByteOutStream +{ +protected: + UKBYTE *m_buf, *m_current; + int m_out; + int m_len; + int m_bad; +public: + StringBOStream(UKBYTE *buf, int len); + virtual int putB(UKBYTE b); + virtual int putW(UKWORD w); + virtual int puts(const char *s, int size = -1); + virtual int isOK(); // get current stream state + + virtual int close() + { + return 1; + }; + + void reopen(); + int getOutBytes() { + return m_out; + } +}; + +//---------------------------------------------------- +class FileBOStream : public ByteOutStream +{ +protected: + FILE *m_file; + int m_bufSize; + char *m_buf; + int m_own; + int m_bad; + +public: + FileBOStream(int bufsize = 8192, char *buf = NULL); +// FileBOStream(char *fileName, int bufsize = 8192, void *buf = NULL); + + int open(const char *fileName); + void attach(FILE *); + virtual int close(); + + virtual int putB(UKBYTE b); + virtual int putW(UKWORD w); + virtual int puts(const char *s, int size = -1); + virtual int isOK(); // get current stream state + virtual ~FileBOStream(); +}; + + +#endif diff --git a/unikey/charset.cpp b/unikey/charset.cpp new file mode 100644 index 0000000..f4d759f --- /dev/null +++ b/unikey/charset.cpp @@ -0,0 +1,1302 @@ +// -*- coding:unix; mode:c++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- +/*------------------------------------------------------------------------------ +VnConv: Vietnamese Encoding Converter Library +UniKey Project: http://unikey.sourceforge.net +Copyleft (C) 1998-2002 Pham Kim Long +Contact: longp@cslab.felk.cvut.cz + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +--------------------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include + +#include "charset.h" +#include "data.h" + +int LoVowel['z'-'a'+1]; +int HiVowel['Z'-'A'+1]; + +#define IS_VOWEL(x) ((x >= 'a' && x <= 'z' && LoVowel[x-'a']) || (x >= 'A' && x <= 'Z' && HiVowel[x-'A'])) + +SingleByteCharset *SgCharsets[CONV_TOTAL_SINGLE_CHARSETS]; +DoubleByteCharset *DbCharsets[CONV_TOTAL_DOUBLE_CHARSETS]; + +DllExport CVnCharsetLib VnCharsetLibObj; + +////////////////////////////////////////////////////// +// Generic VnCharset class +////////////////////////////////////////////////////// +int VnCharset::elementSize() +{ + return 1; +} + +//------------------------------------------- +int VnInternalCharset::nextInput(ByteInStream & is, StdVnChar & stdChar, int & bytesRead) +{ + if (!is.getNextDW(stdChar)) { + bytesRead = 0; + return 0; + } + bytesRead = sizeof(UKDWORD); + return 1; +} + +//------------------------------------------- +int VnInternalCharset::putChar(ByteOutStream & os, StdVnChar stdChar, int & outLen) +{ + outLen = sizeof(StdVnChar); + os.putW((UKWORD)stdChar); + return os.putW((UKWORD)(stdChar>>(sizeof(UKWORD)*8))); +} + +//------------------------------------------- +int VnInternalCharset::elementSize() +{ + return 4; +} + +//------------------------------------------- +SingleByteCharset::SingleByteCharset(unsigned char * vnChars) +{ + int i; + m_vnChars = vnChars; + memset(m_stdMap, 0, 256*sizeof(UKWORD)); + for (i=0; i= VnStdCharOffset) { + outLen = 1; + ch = m_vnChars[stdChar - VnStdCharOffset]; + if (ch == 0) + ch = (stdChar == StdStartQuote)? PadStartQuote : + ((stdChar == StdEndQuote)? PadEndQuote : + ((stdChar == StdEllipsis)? PadEllipsis: PadChar) ); + ret = os.putB(ch); + } + else { + if (stdChar > 255 || m_stdMap[stdChar]) { + //this character is missing in the charset + // output padding character + outLen = 1; + ret = os.putB(PadChar); + } + else { + outLen = 1; + ret = os.putB((UKBYTE)stdChar); + } + } + return ret; +} + +//------------------------------------------- +int wideCharCompare(const void *ele1, const void *ele2) +{ + UKWORD ch1 = LOWORD(*((UKDWORD *)ele1)); + UKWORD ch2 = LOWORD(*((UKDWORD *)ele2)); + return (ch1 == ch2)? 0 : ((ch1 > ch2)? 1 : -1); +} + +//------------------------------------------- +UnicodeCharset::UnicodeCharset(UnicodeChar *vnChars) +{ + UKDWORD i; + m_toUnicode = vnChars; + for (i=0; i= VnStdCharOffset)? + m_toUnicode[stdChar-VnStdCharOffset] : (UnicodeChar)stdChar); +} + +//------------------------------------------- +int UnicodeCharset::elementSize() +{ + return 2; +} + +//////////////////////////////////////// +// Unicode decomposed +//////////////////////////////////////// +//------------------------------------------- +int uniCompInfoCompare(const void *ele1, const void *ele2) +{ + UKDWORD ch1 = ((UniCompCharInfo *)ele1)->compChar; + UKDWORD ch2 = ((UniCompCharInfo *)ele2)->compChar; + return (ch1 == ch2)? 0 : ((ch1 > ch2)? 1 : -1); +} + +UnicodeCompCharset::UnicodeCompCharset(UnicodeChar *uniChars, UKDWORD *uniCompChars) +{ + int i,k; + m_uniCompChars = uniCompChars; + m_totalChars = 0; + for (i=0; istdIndex + VnStdCharOffset; + if (is.peekNextW(w)) { + UKDWORD hi = w; + if (hi > 0) { + key.compChar += hi << 16; + pInfo = (UniCompCharInfo *)bsearch(&key, m_info, m_totalChars, + sizeof(UniCompCharInfo), uniCompInfoCompare); + if (pInfo) { + stdChar = pInfo->stdIndex + VnStdCharOffset; + bytesRead += 2; + is.getNextW(w); + } + } + } + } + return 1; +} + +//--------------------------------------------- +int UnicodeCompCharset::putChar(ByteOutStream & os, StdVnChar stdChar, int & outLen) +{ + int ret; + if (stdChar >= VnStdCharOffset) { + UKDWORD uniCompCh = m_uniCompChars[stdChar-VnStdCharOffset]; + UKWORD lo = LOWORD(uniCompCh); + UKWORD hi = HIWORD(uniCompCh); + outLen = 2; + ret = os.putW(lo); + if (hi > 0) { + outLen += 2; + ret = os.putW(hi); + } + } + else { + outLen = 2; + ret = os.putW((UKWORD)stdChar); + } + return ret; +} + +//------------------------------------------- +int UnicodeCompCharset::elementSize() +{ + return 2; +} + +//////////////////////////////// +// Unicode UTF-8 // +//////////////////////////////// +int UnicodeUTF8Charset::nextInput(ByteInStream & is, StdVnChar & stdChar, int & bytesRead) +{ + UKWORD w1, w2, w3; + UKBYTE first, second, third; + UnicodeChar uniCh; + + bytesRead = 0; + if (!is.getNext(first)) + return 0; + bytesRead = 1; + + if (first < 0x80) + uniCh = first; // 1-byte sequence + else if ((first & 0xE0) == 0xC0) { + //2-byte sequence + if (!is.peekNext(second)) + return 0; + if ((second & 0xC0) != 0x80) { + stdChar = INVALID_STD_CHAR; + return 1; + } + is.getNext(second); + bytesRead = 2; + w1 = first; + w2 = second; + uniCh = ((w1 & 0x001F) << 6) | (w2 & 0x3F); + } + else if ((first & 0xF0) == 0xE0) { + //3-byte sequence + if (!is.peekNext(second)) + return 0; + if ((second & 0xC0) != 0x80) { + stdChar = INVALID_STD_CHAR; + return 1; + } + is.getNext(second); + bytesRead = 2; + if (!is.peekNext(third)) + return 0; + if ((third & 0xC0) != 0x80) { + stdChar = INVALID_STD_CHAR; + return 1; + } + is.getNext(third); + bytesRead = 3; + w1 = first; + w2 = second; + w3 = third; + uniCh = ((w1 & 0x000F) << 12) | ((w2 & 0x003F) << 6) | (w3 & 0x003F); + } + else { + stdChar = INVALID_STD_CHAR; + return 1; + } + + // translate to StdVnChar + UKDWORD key = uniCh; + UKDWORD *pChar = (UKDWORD *)bsearch(&key, m_vnChars, TOTAL_VNCHARS, sizeof(UKDWORD), wideCharCompare); + if (pChar) + stdChar = VnStdCharOffset + HIWORD(*pChar); + else stdChar = uniCh; + return 1; +} + +//------------------------------------------- +int UnicodeUTF8Charset::putChar(ByteOutStream & os, StdVnChar stdChar, int & outLen) +{ + UnicodeChar uChar = (stdChar < VnStdCharOffset)? + (UnicodeChar)stdChar : m_toUnicode[stdChar-VnStdCharOffset]; + int ret; + if (uChar < 0x0080) { + outLen = 1; + ret = os.putB((UKBYTE)uChar); + } else if (uChar < 0x0800) { + outLen = 2; + os.putB(0xC0 | (UKBYTE)(uChar >> 6)); + ret = os.putB(0x80 | (UKBYTE)(uChar & 0x003F)); + } else { + outLen = 3; + os.putB(0xE0 | (UKBYTE)(uChar >> 12)); + os.putB(0x80 | (UKBYTE)((uChar >> 6) & 0x003F)); + ret = os.putB(0x80 | (UKBYTE)(uChar & 0x003F)); + } + return ret; +} + +//////////////////////////////////////// +// Unicode character reference &#D; // +//////////////////////////////////////// +int hexDigitValue(unsigned char digit) +{ + if (digit >= 'a' && digit <= 'f') + return digit-'a'+10; + if (digit >= 'A' && digit <= 'F') + return digit-'A'+10; + if (digit >= '0' && digit <= '9') + return digit-'0'; + return 0; +} + + +//-------------------------------------- +int UnicodeRefCharset::nextInput(ByteInStream & is, StdVnChar & stdChar, int & bytesRead) +{ + unsigned char ch; + UnicodeChar uniCh; + bytesRead = 0; + if (!is.getNext(ch)) + return 0; + bytesRead = 1; + uniCh = ch; + if (ch == '&') { + if (is.peekNext(ch) && ch == '#') { + is.getNext(ch); + bytesRead++; + if (!is.eos()) { + is.peekNext(ch); + if (ch != 'x' && ch != 'X') { + UKWORD code = 0; + int digits = 0; + while (is.peekNext(ch) && isdigit(ch) && digits < 5) { + is.getNext(ch); + bytesRead++; + code = code*10 + (ch - '0'); + digits++; + } + if (is.peekNext(ch) && ch == ';') { + is.getNext(ch); + bytesRead++; + uniCh = code; + } + } + else { + is.getNext(ch); + bytesRead++; + UKWORD code = 0; + int digits = 0; + while (is.peekNext(ch) && isxdigit(ch) && digits < 4) { + is.getNext(ch); + bytesRead++; + code = (code << 4) + hexDigitValue(ch); + digits++; + } + if (is.peekNext(ch) && ch == ';') { + is.getNext(ch); + bytesRead++; + uniCh = code; + } + } // hex digits + } + } + } + + // translate to StdVnChar + UKDWORD key = uniCh; + UKDWORD *pChar = (UKDWORD *)bsearch(&key, m_vnChars, TOTAL_VNCHARS, sizeof(UKDWORD), wideCharCompare); + if (pChar) + stdChar = VnStdCharOffset + HIWORD(*pChar); + else stdChar = uniCh; + return 1; +} + + +//-------------------------------- +int UnicodeRefCharset::putChar(ByteOutStream & os, StdVnChar stdChar, int & outLen) +{ + UnicodeChar uChar = (stdChar < VnStdCharOffset)? + (UnicodeChar)stdChar : m_toUnicode[stdChar-VnStdCharOffset]; + int ret; + if (uChar < 128) { + outLen = 1; + ret = os.putB((UKBYTE)uChar); + } + else { + outLen = 2; + os.putB((UKBYTE)'&'); + os.putB((UKBYTE)'#'); + + int i, digit, prev, base; + prev = 0; + base = 10000; + for (i=0; i < 5; i++) { + digit = uChar / base; + if (digit || prev) { + prev = 1; + outLen++; + os.putB('0' + (unsigned char)digit); + } + uChar %= base; + base /= 10; + } + ret = os.putB((UKBYTE)';'); + outLen++; + } + return ret; +} + +#define HEX_DIGIT(x) ((x < 10)? ('0'+x) : ('A'+x-10)) + +//-------------------------------- +int UnicodeHexCharset::putChar(ByteOutStream & os, StdVnChar stdChar, int & outLen) +{ + UnicodeChar uChar = (stdChar < VnStdCharOffset)? + (UnicodeChar)stdChar : m_toUnicode[stdChar-VnStdCharOffset]; + int ret; + if (uChar < 256) { + outLen = 1; + ret = os.putB((UKBYTE)uChar); + } + else { + outLen = 3; + os.putB('&'); + os.putB('#'); + os.putB('x'); + + int i, digit; + int prev = 0; + int shifts = 12; + + for (i=0; i < 4; i++) { + digit = ((uChar >> shifts) & 0x000F); + if (digit > 0 || prev) { + prev = 1; + outLen++; + os.putB((UKBYTE)HEX_DIGIT(digit)); + } + shifts -= 4; + } + ret = os.putB(';'); + outLen++; + } + return ret; +} + + +///////////////////////////////// +// Class UnicodeCStringCharset / +///////////////////////////////// +void UnicodeCStringCharset::startInput() +{ + m_prevIsHex = 0; +} + +//---------------------------------------- +int UnicodeCStringCharset::nextInput(ByteInStream & is, StdVnChar & stdChar, int & bytesRead) +{ + unsigned char ch; + UnicodeChar uniCh; + bytesRead = 0; + if (!is.getNext(ch)) + return 0; + bytesRead = 1; + uniCh = ch; + if (ch == '\\') { + if (is.peekNext(ch) && (ch=='x' || ch=='X')) { + is.getNext(ch); + bytesRead++; + UKWORD code = 0; + int digits = 0; + while (is.peekNext(ch) && isxdigit(ch) && digits < 4) { + is.getNext(ch); + bytesRead++; + code = (code << 4) + hexDigitValue(ch); + digits++; + } + uniCh = code; + } + } + + // translate to StdVnChar + UKDWORD key = uniCh; + UKDWORD *pChar = (UKDWORD *)bsearch(&key, m_vnChars, TOTAL_VNCHARS, sizeof(UKDWORD), wideCharCompare); + if (pChar) + stdChar = VnStdCharOffset + HIWORD(*pChar); + else stdChar = uniCh; + return 1; +} + +//------------------------------------ +int UnicodeCStringCharset::putChar(ByteOutStream & os, StdVnChar stdChar, int & outLen) +{ + UnicodeChar uChar = (stdChar < VnStdCharOffset)? + (UnicodeChar)stdChar : m_toUnicode[stdChar-VnStdCharOffset]; + int ret; + if (uChar < 128 && !isxdigit(uChar) && uChar != 'x' && uChar != 'X') { + outLen = 1; + ret = os.putB((UKBYTE)uChar); + } + else { + outLen = 2; + os.putB('\\'); + os.putB('x'); + + int i, digit; + int prev = 0; + int shifts = 12; + + for (i=0; i < 4; i++) { + digit = ((uChar >> shifts) & 0x000F); + if (digit > 0 || prev) { + prev = 1; + outLen++; + os.putB((UKBYTE)HEX_DIGIT(digit)); + } + shifts -= 4; + } + ret = os.isOK(); + m_prevIsHex = 1; + } + return ret; +} + +///////////////////////////////// +// Double-byte charsets // +///////////////////////////////// +DoubleByteCharset::DoubleByteCharset(UKWORD *vnChars) +{ + m_toDoubleChar = vnChars; + memset(m_stdMap, 0, 256*sizeof(UKWORD)); + for (int i=0; i> 8) // a 2-byte character + m_stdMap[vnChars[i] >> 8] = 0xFFFF; //INVALID_STD_CHAR; + else if (m_stdMap[vnChars[i]] == 0) + m_stdMap[vnChars[i]] = i+1; + m_vnChars[i] = (i << 16) + vnChars[i]; // high word is used for StdChar index + } + qsort(m_vnChars, TOTAL_VNCHARS, sizeof(UKDWORD), wideCharCompare); +} + +//--------------------------------------------- +int DoubleByteCharset::nextInput(ByteInStream & is, StdVnChar & stdChar, int & bytesRead) +{ + unsigned char ch; + + // read first byte + bytesRead = 0; + if (!is.getNext(ch)) + return 0; + bytesRead = 1; + stdChar = m_stdMap[ch]; + if (stdChar == 0) + stdChar = ch; + else if (stdChar == 0xFFFF) + stdChar = INVALID_STD_CHAR; + else { + stdChar += VnStdCharOffset - 1; + UKBYTE hi; + if (is.peekNext(hi) && hi > 0) { + //test if a double-byte character is encountered + UKDWORD key = MAKEWORD(ch,hi); + UKDWORD *pChar = (UKDWORD *)bsearch(&key, m_vnChars, TOTAL_VNCHARS, sizeof(UKDWORD), wideCharCompare); + if (pChar) { + stdChar = VnStdCharOffset + HIWORD(*pChar); + bytesRead = 2; + is.getNext(hi); + } + } + } + return 1; +} + +//--------------------------------------------- +int DoubleByteCharset::putChar(ByteOutStream & os, StdVnChar stdChar, int & outLen) +{ + int ret; + if (stdChar >= VnStdCharOffset) { + UKWORD wCh = m_toDoubleChar[stdChar-VnStdCharOffset]; + + if (wCh & 0xFF00) { + outLen = 2; + os.putB((UKBYTE)(wCh & 0x00FF)); + ret = os.putB((UKBYTE)(wCh >> 8)); + } + else { + unsigned char b = (unsigned char)wCh; + if (m_stdMap[b] == 0xFFFF) + b = PadChar; + outLen = 1; + ret = os.putB(b); + } +/* + outLen = 1; + ret = os.putB((UKBYTE)(wCh & 0x00FF)); + if (wCh & 0xFF00) { + outLen = 2; + ret = os.putB((UKBYTE)(wCh >> 8)); + } +*/ + } + else { + if (stdChar > 255 || m_stdMap[stdChar]) { + outLen = 1; + ret = os.putB((UKBYTE)PadChar); + } + else { + outLen = 1; + ret = os.putB((UKBYTE)stdChar); + } + } + return ret; +} + +///////////////////////////////////////////// +// Class: VIQRCharset // +///////////////////////////////////////////// + +unsigned char VIQRTones[] = {'\'','`','?','~','.'}; + +const char *VIQREscapes[] = { + "://", + "/", + "@", + "mailto:", + "email:", + "news:", + "www", + "ftp" +}; + +const int VIQREscCount = sizeof(VIQREscapes) / sizeof(char*); + +VIQRCharset::VIQRCharset(UKDWORD *vnChars) +{ + memset(m_stdMap, 0, 256*sizeof(UKWORD)); + int i; + UKDWORD dw; + m_vnChars = vnChars; + for (i=0; i 0 && (!m_gotTone || (index!=6 && index!=10)) ) || + (index == 12 && (upper == 'A' || upper == 'E' || upper == 'O')) || + (m_stdMap[ch2] == 24 && upper== 'A') || + (m_stdMap[ch2] == 26 && (upper == 'O' || upper == 'U')) ); + + if (cond) { + if (index > 0) + m_gotTone = 1; //we have a tone/breve/hook in the current word + + // ok, take this byte + is.getNext(ch2); + bytesRead++; + int offset = m_stdMap[ch2]; + if (offset == 26) offset = 24; + if (offset == 24 && (ch1 == 'u' || ch1 == 'U')) + offset = 12; + stdChar += offset; + // check next byte + if (is.peekNext(ch2)) { + if (index > 10 && m_stdMap[ch2] > 0 && m_stdMap[ch2] <= 10) { + // ok, take one more byte + is.getNext(ch2); + bytesRead++; + stdChar += m_stdMap[ch2]; + } + } + } + } + } + m_atWordBeginning = (stdChar < 256); + if (stdChar < 256) { + m_gotTone = 0; //reset this flag because we are at the beginning of a new word + } + + // adjust stdChar + if (stdChar >= 256) + stdChar += VnStdCharOffset - 256; + return 1; +} + +//--------------------------------------------------- +void VIQRCharset::startOutput() +{ + m_escapeBowl = 0; + m_escapeRoof = 0; + m_escapeHook = 0; + m_escapeTone = 0; + m_noOutEsc = 0; + VnCharsetLibObj.m_VIQROutEscPatterns.reset(); +} + +//--------------------------------------------------- +int VIQRCharset::putChar(ByteOutStream & os, StdVnChar stdChar, int & outLen) +{ + int ret; + UKBYTE b; + if (stdChar >= VnStdCharOffset) { + outLen = 1; + UKDWORD dw = m_vnChars[stdChar-VnStdCharOffset]; + + unsigned char first = (unsigned char)dw; + unsigned char firstUpper = toupper(first); + + b = (UKBYTE)dw; + ret = os.putB(b); + if (VnCharsetLibObj.m_VIQROutEscPatterns.foundAtNextChar(b) != -1) + m_noOutEsc = 1; + + if (m_noOutEsc && (b==' ' || b=='\t' || b=='\r' || b=='\n')) + m_noOutEsc = 0; + + if (dw & 0x0000FF00) { + // second byte is present + unsigned char second = (UKBYTE)(dw >> 8); + outLen++; + ret = os.putB(second); + + if (dw & 0x00FF0000) { + //third byte is present + outLen++; + ret = os.putB((UKBYTE)(dw >> 16)); + m_escapeTone = 0; + } + else { + UKWORD index = m_stdMap[second]; + m_escapeTone = (index == 12 || index == 24 || index == 26); + } + + VnCharsetLibObj.m_VIQROutEscPatterns.reset(); + + m_escapeBowl = 0; + m_escapeHook = 0; + m_escapeRoof = 0; + } + else { + m_escapeTone = IS_VOWEL(first); + m_escapeBowl = (firstUpper == 'A'); + m_escapeHook = (firstUpper == 'U' || firstUpper == 'O'); + m_escapeRoof = (firstUpper == 'A' || firstUpper == 'E' || firstUpper == 'O'); + } + } + else { + if (stdChar > 255) { + outLen = 1; + ret = os.putB((UKBYTE)PadChar); + if (VnCharsetLibObj.m_VIQROutEscPatterns.foundAtNextChar((UKBYTE)PadChar) != -1) + m_noOutEsc = 1; + } + else { + outLen = 1; + UKWORD index = m_stdMap[stdChar]; + if (!VnCharsetLibObj.m_options.viqrMixed && !m_noOutEsc && + (stdChar=='\\' || + (index > 0 && index <= 10 && m_escapeTone) || + (index == 12 && m_escapeRoof) || + (index == 24 && m_escapeBowl) || + (index == 26 && m_escapeHook))) { + //(m_stdMap[stdChar] > 0 && m_stdMap[stdChar] <= 26)) { + // tone mark, needs an escape character + outLen++; + ret = os.putB('\\'); + if (VnCharsetLibObj.m_VIQROutEscPatterns.foundAtNextChar('\\') != -1) + m_noOutEsc = 1; + } + b = (UKBYTE)stdChar; + ret = os.putB(b); + if (VnCharsetLibObj.m_VIQROutEscPatterns.foundAtNextChar(b) != -1) + m_noOutEsc = 1; + if (m_noOutEsc && (b==' ' || b=='\t' || b=='\r' || b=='\n')) + m_noOutEsc = 0; + } + // reset escape marks + m_escapeBowl = 0; + m_escapeRoof = 0; + m_escapeHook = 0; + m_escapeTone = 0; + } + return ret; +} + +///////////////////////////////////////////// +// Class: UTF8VIQRCharset // +///////////////////////////////////////////// + +//----------------------------------------- +UTF8VIQRCharset::UTF8VIQRCharset(UnicodeUTF8Charset *pUtf, VIQRCharset *pViqr) +{ + m_pUtf = pUtf; + m_pViqr = pViqr; +} + +//----------------------------------------- +void UTF8VIQRCharset::startInput() +{ + m_pUtf->startInput(); + m_pViqr->startInput(); +} + +//----------------------------------------- +void UTF8VIQRCharset::startOutput() +{ + m_pUtf->startOutput(); + m_pViqr->startOutput(); +} + +//----------------------------------------- +int UTF8VIQRCharset::nextInput(ByteInStream & is, StdVnChar & stdChar, int & bytesRead) +{ + UKBYTE ch; + + if (!is.peekNext(ch)) + return 0; + + if (ch > 0xBF && ch < 0xFE) { + m_pViqr->startInput(); // just to reset the VIQR object state + m_pViqr->m_suspicious = 1; + return m_pUtf->nextInput(is, stdChar, bytesRead); + } + + return m_pViqr->nextInput(is, stdChar, bytesRead); +} + +//----------------------------------------- +int UTF8VIQRCharset::putChar(ByteOutStream & os, StdVnChar stdChar, int & outLen) +{ + return m_pViqr->putChar(os, stdChar, outLen); +} + + +//----------------------------------------- +CVnCharsetLib::CVnCharsetLib() +{ + unsigned char ch; + for (ch = 'a'; ch < 'z'; ch++) + LoVowel[ch-'a'] = 0; + LoVowel['a'-'a'] = 1; + LoVowel['e'-'a'] = 1; + LoVowel['i'-'a'] = 1; + LoVowel['o'-'a'] = 1; + LoVowel['u'-'a'] = 1; + LoVowel['y'-'a'] = 1; + + for (ch = 'A'; ch < 'Z'; ch++) + HiVowel[ch-'A'] = 0; + HiVowel['A'-'A'] = 1; + HiVowel['E'-'A'] = 1; + HiVowel['I'-'A'] = 1; + HiVowel['O'-'A'] = 1; + HiVowel['U'-'A'] = 1; + HiVowel['Y'-'A'] = 1; + + m_pUniCharset = NULL; + m_pUniCompCharset = NULL; + m_pUniUTF8 = NULL; + m_pUniRef = NULL; + m_pUniHex = NULL; + m_pVIQRCharObj = NULL; + m_pUVIQRCharObj = NULL; + m_pWinCP1258 = NULL; + m_pVnIntCharset = NULL; + + int i; + for (i = 0; i < CONV_TOTAL_SINGLE_CHARSETS; i++) + m_sgCharsets[i] = NULL; + + for (i = 0; i < CONV_TOTAL_DOUBLE_CHARSETS; i++) + m_dbCharsets[i] = NULL; + + VnConvResetOptions(&m_options); + m_VIQREscPatterns.init((char**)VIQREscapes, VIQREscCount); + m_VIQROutEscPatterns.init((char**)VIQREscapes, VIQREscCount); +} + + +//----------------------------------------- +CVnCharsetLib::~CVnCharsetLib() +{ + if (m_pUniCharset) + delete m_pUniCharset; + if (m_pUniUTF8) + delete m_pUniUTF8; + if (m_pUniRef) + delete m_pUniRef; + if (m_pUniHex) + delete m_pUniHex; + if (m_pVIQRCharObj) + delete m_pVIQRCharObj; + if (m_pUVIQRCharObj) + delete m_pUVIQRCharObj; + if (m_pWinCP1258) + delete m_pWinCP1258; + if (m_pUniCString) + delete m_pUniCString; + if (m_pVnIntCharset) + delete m_pVnIntCharset; + + int i; + for (i = 0; i < CONV_TOTAL_SINGLE_CHARSETS; i++) + if (m_sgCharsets[i]) delete m_sgCharsets[i]; + + for (i = 0; i < CONV_TOTAL_DOUBLE_CHARSETS; i++) + if (m_dbCharsets[i]) delete m_dbCharsets[i]; + +} + +//----------------------------------------- +VnCharset * CVnCharsetLib::getVnCharset(int charsetIdx) +{ + switch (charsetIdx) { + + case CONV_CHARSET_UNICODE: + if (m_pUniCharset == NULL) + m_pUniCharset = new UnicodeCharset(UnicodeTable); + return m_pUniCharset; + case CONV_CHARSET_UNIDECOMPOSED: + if (m_pUniCompCharset == NULL) + m_pUniCompCharset = new UnicodeCompCharset(UnicodeTable, UnicodeComposite); + return m_pUniCompCharset; + case CONV_CHARSET_UNIUTF8: + case CONV_CHARSET_XUTF8: + if (m_pUniUTF8 == NULL) + m_pUniUTF8 = new UnicodeUTF8Charset(UnicodeTable); + return m_pUniUTF8; + + case CONV_CHARSET_UNIREF: + if (m_pUniRef == NULL) + m_pUniRef = new UnicodeRefCharset(UnicodeTable); + return m_pUniRef; + + case CONV_CHARSET_UNIREF_HEX: + if (m_pUniHex == NULL) + m_pUniHex = new UnicodeHexCharset(UnicodeTable); + return m_pUniHex; + + case CONV_CHARSET_UNI_CSTRING: + if (m_pUniCString == NULL) + m_pUniCString = new UnicodeCStringCharset(UnicodeTable); + return m_pUniCString; + + case CONV_CHARSET_WINCP1258: + if (m_pWinCP1258 == NULL) + m_pWinCP1258 = new WinCP1258Charset(WinCP1258, WinCP1258Pre); + return m_pWinCP1258; + + case CONV_CHARSET_VIQR: + if (m_pVIQRCharObj == NULL) + m_pVIQRCharObj = new VIQRCharset(VIQRTable); + return m_pVIQRCharObj; + + case CONV_CHARSET_VNSTANDARD: + if (m_pVnIntCharset == NULL) + m_pVnIntCharset = new VnInternalCharset(); + return m_pVnIntCharset; + + case CONV_CHARSET_UTF8VIQR: + if (m_pUVIQRCharObj == NULL) { + if (m_pVIQRCharObj == NULL) + m_pVIQRCharObj = new VIQRCharset(VIQRTable); + + if (m_pUniUTF8 == NULL) + m_pUniUTF8 = new UnicodeUTF8Charset(UnicodeTable); + m_pUVIQRCharObj = new UTF8VIQRCharset(m_pUniUTF8, m_pVIQRCharObj); + } + return m_pUVIQRCharObj; + + default: + if (IS_SINGLE_BYTE_CHARSET(charsetIdx)) { + int i = charsetIdx - CONV_CHARSET_TCVN3; + if (m_sgCharsets[i] == NULL) + m_sgCharsets[i] = new SingleByteCharset(SingleByteTables[i]); + return m_sgCharsets[i]; + } + else if (IS_DOUBLE_BYTE_CHARSET(charsetIdx)) { + int i = charsetIdx - CONV_CHARSET_VNIWIN; + if (m_dbCharsets[i] == NULL) + m_dbCharsets[i] = new DoubleByteCharset(DoubleByteTables[i]); + return m_dbCharsets[i]; + } + } + return NULL; +} + + +//------------------------------------------------- +DllExport void VnConvSetOptions(VnConvOptions *pOptions) +{ + VnCharsetLibObj.m_options = *pOptions; +} + +//------------------------------------------------- +DllExport void VnConvGetOptions(VnConvOptions *pOptions) +{ + *pOptions = VnCharsetLibObj.m_options; +} + +//------------------------------------------------- +DllExport void VnConvResetOptions(VnConvOptions *pOptions) +{ + pOptions->viqrEsc = 1; + pOptions->viqrMixed = 0; + pOptions->toUpper = 0; + pOptions->toLower = 0; + pOptions->removeTone = 0; + pOptions->smartViqr = 1; +} + + +///////////////////////////////////////////// +// Class WinCP1258Charset +///////////////////////////////////////////// +WinCP1258Charset::WinCP1258Charset(UKWORD *compositeChars, UKWORD *precomposedChars) +{ + int i,k; + m_toDoubleChar = compositeChars; + memset(m_stdMap, 0, 256*sizeof(UKWORD)); + + // encode composite chars + for (i=0; i> 8) // a 2-byte character + m_stdMap[compositeChars[i] >> 8] = 0xFFFF; //INVALID_STD_CHAR; + else if (m_stdMap[compositeChars[i]] == 0) + m_stdMap[compositeChars[i]] = i+1; + + m_vnChars[i] = (i << 16) + compositeChars[i]; // high word is used for StdChar index + } + + m_totalChars = TOTAL_VNCHARS; + + //add precomposed chars to the table + for (k=0, i=TOTAL_VNCHARS; k> 8) // a 2-byte character + m_stdMap[precomposedChars[k] >> 8] = 0xFFFF; //INVALID_STD_CHAR; + else if (m_stdMap[precomposedChars[k]] == 0) + m_stdMap[precomposedChars[k]] = k+1; + + m_vnChars[i] = (k << 16) + precomposedChars[k]; + m_totalChars++; + i++; + } + + qsort(m_vnChars, m_totalChars, sizeof(UKDWORD), wideCharCompare); +} + + +//--------------------------------------------------------------------- +// This fuction is basically the same as that of DoubleByteCharset +// with m_totalChars is used instead of constant TOTAL_VNCHARS +//--------------------------------------------------------------------- +int WinCP1258Charset::nextInput(ByteInStream & is, StdVnChar & stdChar, int & bytesRead) +{ + unsigned char ch; + + // read first byte + bytesRead = 0; + if (!is.getNext(ch)) + return 0; + bytesRead = 1; + stdChar = m_stdMap[ch]; + if (stdChar == 0) + stdChar = ch; + else if (stdChar == 0xFFFF) + stdChar = INVALID_STD_CHAR; + else { + stdChar += VnStdCharOffset - 1; + UKBYTE hi; + if (is.peekNext(hi) && hi > 0) { + //test if a double-byte character is encountered + UKDWORD key = MAKEWORD(ch,hi); + UKDWORD *pChar = (UKDWORD *)bsearch(&key, m_vnChars, m_totalChars, sizeof(UKDWORD), wideCharCompare); + if (pChar) { + stdChar = VnStdCharOffset + HIWORD(*pChar); + bytesRead = 2; + is.getNext(hi); + } + } + } + return 1; +} + +//--------------------------------------------------------------------- +// This fuction is exactly the same as that of DoubleByteCharset +//--------------------------------------------------------------------- +int WinCP1258Charset::putChar(ByteOutStream & os, StdVnChar stdChar, int & outLen) +{ + int ret; + if (stdChar >= VnStdCharOffset) { + UKWORD wCh = m_toDoubleChar[stdChar-VnStdCharOffset]; + + if (wCh & 0xFF00) { + outLen = 2; + os.putB((UKBYTE)(wCh & 0x00FF)); + ret = os.putB((UKBYTE)(wCh >> 8)); + } + else { + unsigned char b = (unsigned char)wCh; + if (m_stdMap[b] == 0xFFFF) + b = PadChar; + outLen = 1; + ret = os.putB(b); + } + } + else { + if (stdChar > 255 || m_stdMap[stdChar]) { + outLen = 1; + ret = os.putB((UKBYTE)PadChar); + } + else { + outLen = 1; + ret = os.putB((UKBYTE)stdChar); + } + } + return ret; +} + +#define IS_ODD(x) (x & 1) +#define IS_EVEN(x) (!(x & 1)) + +StdVnChar StdVnToUpper(StdVnChar ch) +{ + if (ch >= VnStdCharOffset && + ch<(VnStdCharOffset + TOTAL_ALPHA_VNCHARS) && + IS_ODD(ch)) + ch -= 1; + return ch; +} + +//---------------------------------------- +StdVnChar StdVnToLower(StdVnChar ch) +{ + if (ch >= VnStdCharOffset && + ch<(VnStdCharOffset + TOTAL_ALPHA_VNCHARS) && + IS_EVEN(ch)) + ch += 1; + return ch; +} + +//---------------------------------------- +StdVnChar StdVnGetRoot(StdVnChar ch) +{ + if (ch >= VnStdCharOffset && ch +#endif + +#if defined(_WIN32) + #if defined(UNIKEYHOOK) + #define DllInterface __declspec( dllexport ) + #else + #define DllInterface __declspec( dllimport ) + #endif +#else + #define DllInterface //not used + #define DllExport + #define DllImport +#endif + +#include "vnconv.h" +#include "byteio.h" +#include "pattern.h" + +#define TOTAL_VNCHARS 213 +#define TOTAL_ALPHA_VNCHARS 186 + +#if defined(_WIN32) + typedef unsigned __int32 StdVnChar; + typedef unsigned __int16 UnicodeChar; + typedef unsigned __int16 UKWORD; + typedef unsigned __int32 UKDWORD; +#else +//typedef unsigned int StdVnChar; //the size should be more specific + typedef uint32_t StdVnChar; + typedef uint16_t UnicodeChar; + typedef uint16_t UKWORD; + typedef uint32_t UKDWORD; +#endif + +//typedef unsigned short UnicodeChar; +//typedef unsigned short UKWORD; + +//typedef unsigned int UKDWORD; //the size should be more specific + +#ifndef LOWORD +#define LOWORD(l) ((UKWORD)(l)) +#endif + +#ifndef HIWORD +#define HIWORD(l) ((UKWORD)(((UKDWORD)(l) >> 16) & 0xFFFF)) +#endif + +#ifndef MAKEWORD +#define MAKEWORD(a, b) ((UKWORD)(((UKBYTE)(a)) | ((UKWORD)((UKBYTE)(b))) << 8)) +#endif + +const StdVnChar VnStdCharOffset = 0x10000; +const StdVnChar INVALID_STD_CHAR = 0xFFFFFFFF; +//const unsigned char PadChar = '?'; //? is used for VIQR charset +const unsigned char PadChar = '#'; +const unsigned char PadStartQuote = '\"'; +const unsigned char PadEndQuote = '\"'; +const unsigned char PadEllipsis = '.'; + +class DllInterface VnCharset { +public: + virtual void startInput() {}; + virtual void startOutput() {}; +// virtual UKBYTE *nextInput(UKBYTE *input, int inLen, StdVnChar & stdChar, int & bytesRead) = 0; + virtual int nextInput(ByteInStream & is, StdVnChar & stdChar, int & bytesRead) = 0; + + //------------------------------------------------------------------------ + // put a character to the output after converting it + // Arguments: + // output[in]: output buffer + // stdChar[in]: character in standard charset + // outLen[out]: length of converted sequence + // maxAvail[in]: max length available. + // Returns: next position in output + //------------------------------------------------------------------------ + virtual int putChar(ByteOutStream & os, StdVnChar stdChar, int & outLen) = 0; + virtual int elementSize(); + virtual ~VnCharset() {} +}; + +//-------------------------------------------------- +class SingleByteCharset: public VnCharset { +protected: + UKWORD m_stdMap[256]; + unsigned char * m_vnChars; +public: + SingleByteCharset(unsigned char * vnChars); + virtual int nextInput(ByteInStream & is, StdVnChar & stdChar, int & bytesRead); + virtual int putChar(ByteOutStream & os, StdVnChar stdChar, int & outLen); +}; + +//-------------------------------------------------- +class VnInternalCharset: public VnCharset { +public: + VnInternalCharset() {}; + virtual int nextInput(ByteInStream & is, StdVnChar & stdChar, int & bytesRead); + virtual int putChar(ByteOutStream & os, StdVnChar stdChar, int & outLen); + virtual int elementSize(); +}; + +//-------------------------------------------------- +class UnicodeCharset: public VnCharset { +protected: + UKDWORD m_vnChars[TOTAL_VNCHARS]; + UnicodeChar * m_toUnicode; +public: + UnicodeCharset(UnicodeChar *vnChars); + virtual int nextInput(ByteInStream & is, StdVnChar & stdChar, int & bytesRead); + virtual int putChar(ByteOutStream & os, StdVnChar stdChar, int & outLen); + virtual int elementSize(); +}; + +//-------------------------------------------------- +class DoubleByteCharset: public VnCharset { +protected: + UKWORD m_stdMap[256]; + UKDWORD m_vnChars[TOTAL_VNCHARS]; + UKWORD * m_toDoubleChar; +public: + DoubleByteCharset(UKWORD *vnChars); + virtual int nextInput(ByteInStream & is, StdVnChar & stdChar, int & bytesRead); + virtual int putChar(ByteOutStream & os, StdVnChar stdChar, int & outLen); +}; + +//-------------------------------------------------- +class UnicodeUTF8Charset: public UnicodeCharset +{ +public: + UnicodeUTF8Charset(UnicodeChar *vnChars) : UnicodeCharset(vnChars) {} + + virtual int nextInput(ByteInStream & is, StdVnChar & stdChar, int & bytesRead); + virtual int putChar(ByteOutStream & os, StdVnChar stdChar, int & outLen); +}; + +//-------------------------------------------------- +class UnicodeRefCharset: public UnicodeCharset +{ +public: + UnicodeRefCharset(UnicodeChar *vnChars) : UnicodeCharset(vnChars) {} + + virtual int nextInput(ByteInStream & is, StdVnChar & stdChar, int & bytesRead); + virtual int putChar(ByteOutStream & os, StdVnChar stdChar, int & outLen); +}; + +//-------------------------------------------------- +class UnicodeHexCharset: public UnicodeRefCharset +{ +public: + UnicodeHexCharset(UnicodeChar *vnChars) : UnicodeRefCharset(vnChars) {} + virtual int putChar(ByteOutStream & os, StdVnChar stdChar, int & outLen); +}; + +//-------------------------------------------------- +class UnicodeCStringCharset: public UnicodeCharset +{ +protected: + int m_prevIsHex; +public: + UnicodeCStringCharset(UnicodeChar *vnChars) : UnicodeCharset(vnChars) {} + virtual int nextInput(ByteInStream & is, StdVnChar & stdChar, int & bytesRead); + virtual int putChar(ByteOutStream & os, StdVnChar stdChar, int & outLen); + virtual void startInput(); +}; + +//-------------------------------------------------- +class WinCP1258Charset: public VnCharset { +protected: + UKWORD m_stdMap[256]; + UKDWORD m_vnChars[TOTAL_VNCHARS*2]; + UKWORD *m_toDoubleChar; + int m_totalChars; + +public: + WinCP1258Charset(UKWORD *compositeChars, UKWORD *precomposedChars); + virtual int nextInput(ByteInStream & is, StdVnChar & stdChar, int & bytesRead); + virtual int putChar(ByteOutStream & os, StdVnChar stdChar, int & outLen); +}; + +//-------------------------------------------------- +struct UniCompCharInfo { + UKDWORD compChar; + int stdIndex; +}; + +class UnicodeCompCharset: public VnCharset { +protected: + UniCompCharInfo m_info[TOTAL_VNCHARS*2]; + UKDWORD *m_uniCompChars; + int m_totalChars; +public: + UnicodeCompCharset(UnicodeChar *uniChars, UKDWORD *uniCompChars); + virtual int nextInput(ByteInStream & is, StdVnChar & stdChar, int & bytesRead); + virtual int putChar(ByteOutStream & os, StdVnChar stdChar, int & outLen); + virtual int elementSize(); +}; + +//-------------------------------------------------- +class VIQRCharset: public VnCharset { +protected: + UKDWORD *m_vnChars; + UKWORD m_stdMap[256]; + int m_atWordBeginning; + int m_escapeBowl; + int m_escapeRoof; + int m_escapeHook; + int m_escapeTone; + int m_gotTone; + int m_escAll; + int m_noOutEsc; +public: + int m_suspicious; + VIQRCharset(UKDWORD *vnChars); + virtual void startInput(); + virtual void startOutput(); + virtual int nextInput(ByteInStream & is, StdVnChar & stdChar, int & bytesRead); + virtual int putChar(ByteOutStream & os, StdVnChar stdChar, int & outLen); +}; + +//-------------------------------------------------- +class UTF8VIQRCharset: public VnCharset { + +protected: + VIQRCharset *m_pViqr; + UnicodeUTF8Charset *m_pUtf; + +public: + UTF8VIQRCharset(UnicodeUTF8Charset *pUtf, VIQRCharset *pViqr); + virtual void startInput(); + virtual void startOutput(); + virtual int nextInput(ByteInStream & is, StdVnChar & stdChar, int & bytesRead); + virtual int putChar(ByteOutStream & os, StdVnChar stdChar, int & outLen); +}; + + +//-------------------------------------------------- +class DllInterface CVnCharsetLib { +protected: + SingleByteCharset * m_sgCharsets[CONV_TOTAL_SINGLE_CHARSETS]; + DoubleByteCharset * m_dbCharsets[CONV_TOTAL_DOUBLE_CHARSETS]; + UnicodeCharset * m_pUniCharset; + UnicodeCompCharset * m_pUniCompCharset; + UnicodeUTF8Charset * m_pUniUTF8; + UnicodeRefCharset * m_pUniRef; + UnicodeHexCharset * m_pUniHex; + VIQRCharset * m_pVIQRCharObj; + UTF8VIQRCharset * m_pUVIQRCharObj; + WinCP1258Charset * m_pWinCP1258; + UnicodeCStringCharset *m_pUniCString; + VnInternalCharset *m_pVnIntCharset; + +public: + PatternList m_VIQREscPatterns, m_VIQROutEscPatterns; + VnConvOptions m_options; + CVnCharsetLib(); + ~CVnCharsetLib(); + VnCharset * getVnCharset(int charsetIdx); +}; + +extern unsigned char SingleByteTables[][TOTAL_VNCHARS]; +extern UKWORD DoubleByteTables[][TOTAL_VNCHARS]; +extern UnicodeChar UnicodeTable[TOTAL_VNCHARS]; +extern UKDWORD VIQRTable[TOTAL_VNCHARS]; +extern UKDWORD UnicodeComposite[TOTAL_VNCHARS]; +extern UKWORD WinCP1258[TOTAL_VNCHARS]; +extern UKWORD WinCP1258Pre[TOTAL_VNCHARS]; + +extern DllInterface CVnCharsetLib VnCharsetLibObj; +extern VnConvOptions VnConvGlobalOptions; +extern int StdVnNoTone[TOTAL_VNCHARS]; +extern int StdVnRootChar[TOTAL_VNCHARS]; + +DllInterface int genConvert(VnCharset & incs, VnCharset & outcs, ByteInStream & input, ByteOutStream & output); + +StdVnChar StdVnToUpper(StdVnChar ch); +StdVnChar StdVnToLower(StdVnChar ch); +StdVnChar StdVnGetRoot(StdVnChar ch); + +#endif diff --git a/unikey/convert.cpp b/unikey/convert.cpp new file mode 100644 index 0000000..d6ee8fc --- /dev/null +++ b/unikey/convert.cpp @@ -0,0 +1,249 @@ +// -*- coding:unix; mode:c++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- +/*------------------------------------------------------------------------------ +VnConv: Vietnamese Encoding Converter Library +UniKey Project: http://unikey.sourceforge.net +Copyleft (C) 1998-2002 Pham Kim Long +Contact: longp@cslab.felk.cvut.cz + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +--------------------------------------------------------------------------------*/ + +#include "charset.h" +#include +#include +#include + +#if defined(_WIN32) + #include + #include +#endif + +#include "vnconv.h" + +int vnFileStreamConvert(int inCharset, int outCharset, FILE * inf, FILE *outf); + +DllExport int genConvert(VnCharset & incs, VnCharset & outcs, ByteInStream & input, ByteOutStream & output) +{ + StdVnChar stdChar; + int bytesRead, bytesWritten; + + incs.startInput(); + outcs.startOutput(); + + int ret = 1; + while (!input.eos()) { + stdChar = 0; + if (incs.nextInput(input, stdChar, bytesRead)) { + if (stdChar != INVALID_STD_CHAR) { + if (VnCharsetLibObj.m_options.toLower) + stdChar = StdVnToLower(stdChar); + else if (VnCharsetLibObj.m_options.toUpper) + stdChar = StdVnToUpper(stdChar); + if (VnCharsetLibObj.m_options.removeTone) + stdChar = StdVnGetRoot(stdChar); + ret = outcs.putChar(output, stdChar, bytesWritten); + } + } + else break; + } + return (ret? 0 : VNCONV_OUT_OF_MEMORY); +} + +//---------------------------------------------- +// Arguments: +// inCharset: charset of input +// outCharset: charset of output +// input: input data +// output: output data +// inLen: [in] size of input. if inLen = -1, input data is null-terminated. +// [out] if input inLen != -1, output iLen is the numbers of byte left in input. +// maxOutLen: [in] size of output. +// [out] number of bytes output, if enough memory +// number of bytes needed for output, if not enough memory +// Returns: 0 if successful +// error code: if failed +//---------------------------------------------- +//int VnConvert(int inCharset, int outCharset, UKBYTE *input, UKBYTE *output, int & inLen, int & maxOutLen) + +DllExport int VnConvert(int inCharset, int outCharset, UKBYTE *input, UKBYTE *output, + int * pInLen, int * pMaxOutLen) +{ + int inLen, maxOutLen; + int ret = -1; + + inLen = *pInLen; + maxOutLen = *pMaxOutLen; + + if (inLen != -1 && inLen < 0) // invalid inLen + return ret; + + VnCharset *pInCharset = VnCharsetLibObj.getVnCharset(inCharset); + VnCharset *pOutCharset = VnCharsetLibObj.getVnCharset(outCharset); + + if (!pInCharset || !pOutCharset) + return VNCONV_INVALID_CHARSET; + + StringBIStream is(input, inLen, pInCharset->elementSize()); + StringBOStream os(output, maxOutLen); + + ret = genConvert(*pInCharset, *pOutCharset, is, os); + *pMaxOutLen = os.getOutBytes(); + *pInLen = is.left(); + return ret; +} + +//--------------------------------------- +// Arguments: +// inFile: input file name. NULL if STDIN is used +// outFile: output file name, NULL if STDOUT is used +// Returns: +// 0: successful +// errCode: if failed +//--------------------------------------- +DllExport int VnFileConvert(int inCharset, int outCharset, const char *inFile, const char *outFile) +{ + FILE *inf = NULL; + FILE *outf = NULL; + int ret = 0; + char tmpName[32]; + + if (inFile == NULL) { + inf = stdin; +#if defined(_WIN32) + _setmode( _fileno(stdin), _O_BINARY); +#endif + } + else { + inf = fopen(inFile, "rb"); + if (inf == NULL) { + ret = VNCONV_ERR_INPUT_FILE; + goto end; + } + } + + if (outFile == NULL) + outf = stdout; + else { + // setup temporary output file (because real output file may be the same as input file + char outDir[256]; + strcpy(outDir, outFile); + +#if defined(_WIN32) + char *p = strrchr(outDir, '\\'); +#else + char *p = strrchr(outDir, '/'); +#endif + + if (p == NULL) + outDir[0] = 0; + else + *p = 0; + + strcpy(tmpName, outDir); + strcat(tmpName, "XXXXXX"); + + if (mkstemp(tmpName) == -1) { + fclose(inf); + ret = VNCONV_ERR_OUTPUT_FILE; + goto end; + } + outf = fopen(tmpName, "wb"); + + if (outf == NULL) { + fclose(inf); + ret = VNCONV_ERR_OUTPUT_FILE; + goto end; + } + } + + + ret = vnFileStreamConvert(inCharset, outCharset, inf, outf); + if (inf != stdin) + fclose(inf); + if (outf != stdout) { + fclose(outf); + + // delete output file if exisits + if (ret == 0) { + remove(outFile); +#if !defined(_WIN32) + char cmd[256]; + sprintf(cmd, "mv %s %s", tmpName, outFile); + cmd[0] = system(cmd); +#else + if (rename(tmpName, outFile) != 0) { + remove(tmpName); + ret = VNCONV_ERR_OUTPUT_FILE; + goto end; + } +#endif + } + else + remove(tmpName); + } + +end: +#if defined(_WIN32) + if (inf == stdin) { + _setmode( _fileno(stdin), _O_BINARY); + } +#endif + return ret; +} + +//------------------------------------------------ +// Returns: +// 0: successful +// errCode: if failed +//--------------------------------------- +int vnFileStreamConvert(int inCharset, int outCharset, FILE * inf, FILE *outf) +{ + VnCharset *pInCharset = VnCharsetLibObj.getVnCharset(inCharset); + VnCharset *pOutCharset = VnCharsetLibObj.getVnCharset(outCharset); + + if (!pInCharset || !pOutCharset) + return VNCONV_INVALID_CHARSET; + + if (outCharset == CONV_CHARSET_UNICODE) { + UKWORD sign = 0xFEFF; + fwrite(&sign, sizeof(UKWORD), 1, outf); + } + + FileBIStream is; + FileBOStream os; + + is.attach(inf); + os.attach(outf); + + return genConvert(*pInCharset, *pOutCharset, is, os); +} + +const char *ErrTable[VNCONV_LAST_ERROR] = +{"No error", + "Unknown error", + "Invalid charset", + "Error opening input file", + "Error opening output file", + "Error writing to output stream", + "Not enough memory", +}; + +DllExport const char * VnConvErrMsg(int errCode) +{ + if (errCode < 0 || errCode >= VNCONV_LAST_ERROR) + errCode = VNCONV_UNKNOWN_ERROR; + return ErrTable[errCode]; +} + diff --git a/unikey/data.cpp b/unikey/data.cpp new file mode 100644 index 0000000..ce2e662 --- /dev/null +++ b/unikey/data.cpp @@ -0,0 +1,571 @@ +// -*- coding:unix; mode:c++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- +/*------------------------------------------------------------------------------ +VnConv: Vietnamese Encoding Converter Library +UniKey Project: http://unikey.sourceforge.net +Copyleft (C) 1998-2002 Pham Kim Long +Contact: longp@cslab.felk.cvut.cz + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +--------------------------------------------------------------------------------*/ + +#include "charset.h" + +/* +Instructions on how to add more charset supports + +Each charset enumerates all its characters according to a fixed order. +To understand this order, copy the TCVN3 charset bellow to some application +and view it with some TCVN3 font. + +Steps to add an 1-byte charset: + +- Determine the Id for your charset. See "vnconv.h". The Id + for your charset is equal to the id of the last 1-byte charset PLUS 1. + Then define a constant for that Id (e.g. #define MY_NEW_CHARSET 25) +- In "vnconv.h": Increase the variable CONV_TOTAL_SINGLE_CHARSETS by 1. +- Add an entry for your charset to the end of CharsetIdMap (in this file) +- Add your charset to the end of SingleBytesTable +- Note that and the end of each charset (after character z) there's a section + for the symbols in western charsets (see TCVN3). Just copy + this section for your charset, and set zero for each code point + that is occupied by your charset (for representing Vietnamese characters). + +Steps to add a 2-byte charset: +- Determine the Id for your charset. See "vnconv.h". The Id + for your charset is equal to the id of the last 2-byte charset PLUS 1. + Then define a constant for that Id (e.g. #define MY_NEW_CHARSET 44) +- In "vnconv.h": Increase the variable CONV_TOTAL_DOUBLE_CHARSETS by 1. +- Add an entry for your charset to the end of CharsetIdMap (in this file) +- Add your charset to the end of DoubleByteTables +- Note that and the end of each charset (after character z) there's a section + for the symbols in western charsets. Just copy this section from + VNI-WIN charset to your charset +- Double-byte characters are represented as a word in which the + low byte is base character, high byte is tone mark (if present). +*/ +extern CharsetNameId CharsetIdMap[]; +extern const int CharsetCount; + +CharsetNameId CharsetIdMap[] = { + {"BKHCM1", CONV_CHARSET_BKHCM1}, + {"BKHCM2", CONV_CHARSET_BKHCM2}, + {"ISC", CONV_CHARSET_ISC}, + {"NCR-DEC", CONV_CHARSET_UNIREF}, + {"NCR-HEX", CONV_CHARSET_UNIREF_HEX}, + {"TCVN3", CONV_CHARSET_TCVN3}, + {"UNI-COMP", CONV_CHARSET_UNIDECOMPOSED}, + {"UNICODE", CONV_CHARSET_UNICODE}, + {"UTF-8", CONV_CHARSET_UNIUTF8}, + {"UTF8", CONV_CHARSET_UNIUTF8}, + {"UVIQR", CONV_CHARSET_UTF8VIQR}, + {"VIETWARE-F", CONV_CHARSET_VIETWAREF}, + {"VIETWARE-X", CONV_CHARSET_VIETWAREX}, + {"VIQR", CONV_CHARSET_VIQR}, + {"VISCII", CONV_CHARSET_VISCII}, + {"VNI-MAC", CONV_CHARSET_VNIMAC}, + {"VNI-WIN", CONV_CHARSET_VNIWIN}, + {"VPS", CONV_CHARSET_VPS}, + {"WINCP-1258", CONV_CHARSET_WINCP1258} +}; + +const int CharsetCount = sizeof(CharsetIdMap)/sizeof(CharsetNameId); + +/* Western symbols that need to be mapped + 0x80, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, + 0x89, 0x8A, 0x8B, 0x8C, 0x8E, 0x91, 0x92, 0x93, + 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, + 0x9C, 0x9E, 0x9F, + +If a single byte charset occupies a certain symbol, +its code point in the charset must be set to zero. +See TCVN3 & VPS below for examples +*/ + +unsigned char SingleByteTables[][TOTAL_VNCHARS] = + +// TCVN3 +{{'A','a','','','','','','','','','','', // 0: a + '','','','','','','','','','','','', // 1: a^ + '','','','','','','','','','','','', // 2: a( + 'B','b','C','c','D','d', + '','', + 'E','e','','','','','','','','','','', // 3: e + '','','','','','','','','','','','', // 4: e^ + 'F','f','G','g','H','h', + 'I','i','','','','','','','','','','', // 5: i + 'J','j','K','k','L','l','M','m','N','n', + 'O','o','','','','','','','','','','', // 6: o + '','','','','','','','','','','','', // 7: o^ + '','','','','','','','','','','','', // 8: o+ + 'P','p','Q','q','R','r','S','s','T','t', + 'U','u','','','','','','','','','','', // 9: u + '','','','','','','','','','','','', //10: u+ + 'V','v','W','w','X','x', + 'Y','y','','','','','','','','','','', //11: y + 'Z','z', + 0x80, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, + 0x89, 0x8A, 0x8B, 0x8C, 0x8E, 0x91, 0x92, 0x93, + 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, + 0x9C, 0x9E, 0x9F}, +//VPS +{ 'A','a','','','','','','','','','','', + '','','','','','','','','','','','', + '','','','','','','','','','','','', + 'B','b','C','c','D','d', + '','', + 'E','e','','','','','','','','','','', + '','','','','','','','','','','','', + 'F','f','G','g','H','h', + 'I','i','','','','','','','','','','', + 'J','j','K','k','L','l','M','m','N','n', + 'O','o','','','','','','','','','','', + '','','','','','','','','','','','', + '','','','','','','','','','','','', + 'P','p','Q','q','R','r','S','s','T','t', + 'U','u','','','','','','','','','','', + '','','','','','','','','','','','', + 'V','v','W','w','X','x', + 'Y','y','','','','','','','','','','', + 'Z','z', + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x8E, 0x91, 0x92, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x9E, 0x00}, +//VISCII +{ 'A','a','','','','','','','','','','', + '','','','','','','','','','','','', + '','','','','','','','','','','','', + 'B','b','C','c','D','d', + '','', + 'E','e','','','','','','','','','','', + '','','','','','','','','','','','', + 'F','f','G','g','H','h', + 'I','i','','','','','','','','','','', + 'J','j','K','k','L','l','M','m','N','n', + 'O','o','','','','','','','','','','', + '','','','','','','','','','','','', + '','','','','','','','','','','','', + 'P','p','Q','q','R','r','S','s','T','t', + 'U','u','','','','','','','','','','', + '','','','','','','','','','','','', + 'V','v','W','w','X','x', + 'Y','y','','','','','','','','','','', + 'Z','z', + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x8E, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x9E, 0x00}, +// BKHCM1 +{'A','a','','','','','','','','','','', + '','','~','','','','','','','','','', + '','','','','','','','','','','','', + 'B','b','C','c','D','d', + '}','', + 'E','e','','','','','','','','','','', + '','','','','','','','','','','','', + 'F','f','G','g','H','h', + 'I','i','','','','','','','','','','', + 'J','j','K','k','L','l','M','m','N','n', + 'O','o','','','','','','','','','','', + '','','','','','','','','','','','', + '','','','','','','','','','','','', + 'P','p','Q','q','R','r','S','s','T','t', + 'U','u','','','','','','','','','','', + '','','','','','','','','','','','', + 'V','v','W','w','X','x', + 'Y','y','{','','^','','`','','|','','','', + 'Z','z', + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x8E, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x9E, 0x00}, +//Vietware-F +{ 'A','a','','','','','','','','','','', + '','','','','','','','','','','','', + '','','','','','','','','','','','', + 'B','b','C','c','D','d', + '','', + 'E','e','','','','','','','','','','', + '','','','','','','','','','','','', + 'F','f','G','g','H','h', + 'I','i','','','','','','','','','','', + 'J','j','K','k','L','l','M','m','N','n', + 'O','o','','','','','','','','','','', + '','','','','','','','','','','','', + '','','','','','','','','','','','', + 'P','p','Q','q','R','r','S','s','T','t', + 'U','u','','','','','','','','','','', + '','','','','','','','','','','','', + 'V','v','W','w','X','x', + 'Y','y','','','','','','','','','','', + 'Z','z', + 0x80, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, + 0x89, 0x8A, 0x8B, 0x8C, 0x8E, 0x91, 0x92, 0x93, + 0x94, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x9E, 0x00}, +// ISC + {'A','a','','','','','','','','','','', + '','','','','','','','','','','','', + '','','','','','','','','','','','', + 'B','b','C','c','D','d', + '','', + 'E','e','','','','','','','','','','', + '','','','','','','','','','','','', + 'F','f','G','g','H','h', + 'I','i','','','','','','','','','','', + 'J','j','K','k','L','l','M','m','N','n', + 'O','o','','','','','','','','','','', + '','','','','','','','','','','','', + '','','','','','','','','','','','', + 'P','p','Q','q','R','r','S','s','T','t', + 'U','u','@','','','','','','','','|','', + '','','`','',0x5C,'','^','','~','','#','', + 'V','v','W','w','X','x', + 'Y','y','','','','','','','','','','', + 'Z','z', + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x12, 0x13, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00} +}; + +UKWORD DoubleByteTables[][TOTAL_VNCHARS] = { +//VNI-WIN +{ 0x0041, 0x0061, 0xd941, 0xf961, 0xd841, 0xf861, 0xdb41, 0xfb61, 0xd541, 0xf561, 0xcf41, 0xef61, //a + 0xc241, 0xe261, 0xc141, 0xe161, 0xc041, 0xe061, 0xc541, 0xe561, 0xc341, 0xe361, 0xc441, 0xe461, //a^ + 0xca41, 0xea61, 0xc941, 0xe961, 0xc841, 0xe861, 0xda41, 0xfa61, 0xdc41, 0xfc61, 0xcb41, 0xeb61, //a( + 0x0042, 0x0062, 0x0043, 0x0063, 0x0044, 0x0064, //B b C c D d + 0x00d1, 0x00f1, //DD, dd + 0x0045, 0x0065, 0xd945, 0xf965, 0xd845, 0xf865, 0xdb45, 0xfb65, 0xd545, 0xf565, 0xcf45, 0xef65, //e + 0xc245, 0xe265, 0xc145, 0xe165, 0xc045, 0xe065, 0xc545, 0xe565, 0xc345, 0xe365, 0xc445, 0xe465, //e^ + 0x0046, 0x0066, 0x0047, 0x0067, 0x0048, 0x0068, // F f G g H h + 0x0049, 0x0069, 0x00cd, 0x00ed, 0x00cc, 0x00ec, 0x00c6, 0x00e6, 0x00d3, 0x00f3, 0x00d2, 0x00f2, //i + 0x004a, 0x006a, 0x004b, 0x006b, 0x004c, 0x006c, 0x004d, 0x006d, 0x004e, 0x006e, // J j K k L l M m N n + 0x004f, 0x006f, 0xd94f, 0xf96f, 0xd84f, 0xf86f, 0xdb4f, 0xfb6f, 0xd54f, 0xf56f, 0xcf4f, 0xef6f, //o + 0xc24f, 0xe26f, 0xc14f, 0xe16f, 0xc04f, 0xe06f, 0xc54f, 0xe56f, 0xc34f, 0xe36f, 0xc44f, 0xe46f, //o^ + 0x00d4, 0x00f4, 0xd9d4, 0xf9f4, 0xd8d4, 0xf8f4, 0xdbd4, 0xfbf4, 0xd5d4, 0xf5f4, 0xcfd4, 0xeff4, //o+ + 0x0050, 0x0070, 0x0051, 0x0071, 0x0052, 0x0072, 0x0053, 0x0073, 0x0054, 0x0074, //P p Q q R r S s T t + 0x0055, 0x0075, 0xd955, 0xf975, 0xd855, 0xf875, 0xdb55, 0xfb75, 0xd555, 0xf575, 0xcf55, 0xef75, //u + 0x00d6, 0x00f6, 0xd9d6, 0xf9f6, 0xd8d6, 0xf8f6, 0xdbd6, 0xfbf6, 0xd5d6, 0xf5f6, 0xcfd6, 0xeff6, //u+ + 0x0056, 0x0076, 0x0057, 0x0077, 0x0058, 0x0078, // V v W w X x + 0x0059, 0x0079, 0xd959, 0xf979, 0xd859, 0xf879, 0xdb59, 0xfb79, 0xd559, 0xf579, 0x00ce, 0x00ee, //y + 0x005a, 0x007a, // Z z + 0x0080, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, + 0x0089, 0x008A, 0x008B, 0x008C, 0x008E, 0x0091, 0x0092, 0x0093, + 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009A, 0x009B, + 0x009C, 0x009E, 0x009F}, +//BKHCM2 +{ 0x0041, 0x0061, 0xC141, 0xe161, 0xC241, 0xe261, 0xC341, 0xe361, 0xC441, 0xe461, 0xC541, 0xe561, //a + 0x00CA, 0x00EA, 0xCBCA, 0xEBEA, 0xCCCA, 0xECEA, 0xCDCA, 0xEDEA, 0xCECA, 0xEEEA, 0xC5CA, 0xE5EA, //a^ + 0x00D9, 0x00F9, 0xC6D9, 0xE6F9, 0xC7D9, 0xE7F9, 0xC8D9, 0xE8F9, 0xC9D9, 0xE9F9, 0xC5D9, 0xE5F9, + 0x0042, 0x0062, 0x0043, 0x0063, 0x0044, 0x0064, //B b C c D d + 0x00C0, 0x00E0, + 0x0045, 0x0065, 0xC145, 0xE165, 0xC245, 0xE265, 0xC345, 0xE365, 0xC445, 0xE465, 0xC545, 0xE565, //e + 0x00CF, 0x00EF, 0xCBCF, 0xEBEF, 0xCCCF, 0xECEF, 0xCDCF, 0xEDEF, 0xCECF, 0xEEEF, 0xE5CF, 0xE5EF, //e^ + 0x0046, 0x0066, 0x0047, 0x0067, 0x0048, 0x0068, // F f G g H h + 0x0049, 0x0069, 0x00D1, 0x00F1, 0x00D2, 0x00F2, 0x00D3, 0x00F3, 0x00D4, 0x00F4, 0x00D5, 0x00F5, //i + 0x004a, 0x006a, 0x004b, 0x006b, 0x004c, 0x006c, 0x004d, 0x006d, 0x004e, 0x006e, // J j K k L l M m N n + 0x004F, 0x006F, 0xC14F, 0xE16F, 0xC24F, 0xE26F, 0xC34F, 0xE36F, 0xC44F, 0xE46F, 0xC54F, 0xE56F, //o + 0x00D6, 0x00F6, 0xCBD6, 0xEBF6, 0xCCD6, 0xECF6, 0xCDD6, 0xEDF6, 0xCED6, 0xEEF6, 0xC5D6, 0xE5F6, //o^ + 0x00DA, 0x00FA, 0xC1DA, 0xE1FA, 0xC2DA, 0xE2FA, 0xC3DA, 0xE3FA, 0xC4DA, 0xE4FA, 0xC5DA, 0xE5FA, //o+ + 0x0050, 0x0070, 0x0051, 0x0071, 0x0052, 0x0072, 0x0053, 0x0073, 0x0054, 0x0074, //P p Q q R r S s T t + 0x0055, 0x0075, 0xC155, 0xE175, 0xC255, 0xE275, 0xC355, 0xE375, 0xC455, 0xE475, 0xC555, 0xE575, //u + 0x00DB, 0x00FB, 0xC1DB, 0xE1FB, 0xC2DB, 0xE2FB, 0xC3DB, 0xE3FB, 0xC4DB, 0xE4FB, 0xC5DB, 0xE5FB, //u+ + 0x0056, 0x0076, 0x0057, 0x0077, 0x0058, 0x0078, // V v W w X x + 0x0059, 0x0079, 0xC159, 0xE179, 0xC259, 0xE279, 0xC359, 0xE379, 0xC459, 0xE479, 0xC559, 0xE579, + 0x005a, 0x007a,// Z z + 0x0080, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, + 0x0089, 0x008A, 0x008B, 0x008C, 0x008E, 0x0091, 0x0092, 0x0093, + 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009A, 0x009B, + 0x009C, 0x009E, 0x009F}, +//VIETWARE-X +{ 0x0041, 0x0061, 0xCF41, 0xEF61, 0xCC41, 0xEC61, 0xCD41, 0xED61, 0xCE41, 0xEE61, 0xDB41, 0xFB61, //a + 0x00C1, 0x00E1, 0xDAC1, 0xFAE1, 0xD6C1, 0xF6E1, 0xD8C1, 0xF8E1, 0xD9C1, 0xF9E1, 0xDBC1, 0xFBE1, //a^ + 0x00C0, 0x00E0, 0xD5C0, 0xF5E0, 0xD2C0, 0xF2E0, 0xD3C0, 0xF3E0, 0xD4C0, 0xF4E0, 0xDBC0, 0xFBE0, //a( + 0x0042, 0x0062, 0x0043, 0x0063, 0x0044, 0x0064, //B b C c D d + 0x00C2, 0x00E2, + 0x0045, 0x0065, 0xCF45, 0xEF65, 0xCC45, 0xEC65, 0xCD45, 0xED65, 0xCE45, 0xEE65, 0xDB45, 0xFB65, //e + 0x00C3, 0x00E3, 0xDAC3, 0xFAE3, 0xD6C3, 0xF6E3, 0xD8C3, 0xF8E3, 0xD9C3, 0xF9E3, 0xDBC3, 0xFBE3, //e^ + 0x0046, 0x0066, 0x0047, 0x0067, 0x0048, 0x0068, // F f G g H h + 0x0049, 0x0069, 0x00CA, 0x00EA, 0x00C7, 0x00E7, 0x00C8, 0x00E8, 0x00C9, 0x00E9, 0x00CB, 0x00EB, //i + 0x004a, 0x006a, 0x004b, 0x006b, 0x004c, 0x006c, 0x004d, 0x006d, 0x004e, 0x006e, // J j K k L l M m N n + 0x004F, 0x006F, 0xCF4F, 0xEF6F, 0xCC4F, 0xEC6F, 0xCD4F, 0xED6F, 0xCE4F, 0xEE6F, 0xDC4F, 0xFC6F, //o + 0x00C4, 0x00E4, 0xDAC4, 0xFAE4, 0xD6C4, 0xF6E4, 0xD8C4, 0xF8E4, 0xD9C4, 0xF9E4, 0xDCC4, 0xFCE4, //o^ + 0x00C5, 0x00E5, 0xCFC5, 0xEFE5, 0xCCC5, 0xECE5, 0xCDC5, 0xEDE5, 0xCEC5, 0xEEE5, 0xDCC5, 0xFCE5, //o+ + 0x0050, 0x0070, 0x0051, 0x0071, 0x0052, 0x0072, 0x0053, 0x0073, 0x0054, 0x0074, //P p Q q R r S s T t + 0x0055, 0x0075, 0xCF55, 0xEF75, 0xCC55, 0xEC75, 0xCD55, 0xED75, 0xCE55, 0xEE75, 0xDB55, 0xFB75, //u + 0x00C6, 0x00E6, 0xCFC6, 0xEFE6, 0xCCC6, 0xECE6, 0xCDC6, 0xEDE6, 0xCEC6, 0xEEE6, 0xDBC6, 0xFBE6, //u+ + 0x0056, 0x0076, 0x0057, 0x0077, 0x0058, 0x0078, // V v W w X x + 0x0059, 0x0079, 0xCF59, 0xEF79, 0xCC59, 0xEC79, 0xCD59, 0xED79, 0xCE59, 0xEE79, 0xD159, 0xF179, //Y + 0x005a, 0x007a,// Z z + 0x0080, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, + 0x0089, 0x008A, 0x008B, 0x008C, 0x008E, 0x0091, 0x0092, 0x0093, + 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009A, 0x009B, + 0x009C, 0x009E, 0x009F}, +// VNI-MAC +{ 0x0041, 0x0061, 0xf441, 0x9d61, 0xaf41, 0xbf61, 0xf341, 0x9e61, 0xcd41, 0x9b61, 0xec41, 0x9561, //a + 0xe541, 0x8961, 0xe741, 0x8761, 0xcb41, 0x8861, 0x8141, 0x8c61, 0xcc41, 0x8b61, 0x8041, 0x8a61, //a^ + 0xe641, 0x9061, 0x8341, 0x8e61, 0xe941, 0x8f61, 0xf241, 0x9c61, 0x8641, 0x9f61, 0xe841, 0x9161, //a( + 0x0042, 0x0062, 0x0043, 0x0063, 0x0044, 0x0064, //B b C c D d + 0x0084, 0x0096, //DD, dd + 0x0045, 0x0065, 0xf445, 0x9d65, 0xaf45, 0xbf65, 0xf345, 0x9e65, 0xcd45, 0x9b65, 0xec45, 0x9565, //e + 0xe545, 0x8965, 0xe745, 0x8765, 0xcb45, 0x8865, 0x8145, 0x8c65, 0xcc45, 0x8b65, 0x8045, 0x8a65, //e^ + 0x0046, 0x0066, 0x0047, 0x0067, 0x0048, 0x0068, // F f G g H h + 0x0049, 0x0069, 0x00ea, 0x0092, 0x00ed, 0x0093, 0x00ae, 0x00be, 0x00ee, 0x0097, 0x00f1, 0x0098, //i + 0x004a, 0x006a, 0x004b, 0x006b, 0x004c, 0x006c, 0x004d, 0x006d, 0x004e, 0x006e, // J j K k L l M m N n + 0x004f, 0x006f, 0xf44f, 0x9d6f, 0xaf4f, 0xbf6f, 0xf34f, 0x9e6f, 0xcd4f, 0x9b6f, 0xec4f, 0x956f, //o + 0xe54f, 0x896f, 0xe74f, 0x876f, 0xcb4f, 0x886f, 0x814f, 0x8c6f, 0xcc4f, 0x8b6f, 0x804f, 0x8a6f, //o^ + 0x00ef, 0x0099, 0xf4ef, 0x9d99, 0xafef, 0xbf99, 0xf3ef, 0x9e99, 0xcdef, 0x9b99, 0xecef, 0x9599, //o+ + 0x0050, 0x0070, 0x0051, 0x0071, 0x0052, 0x0072, 0x0053, 0x0073, 0x0054, 0x0074, //P p Q q R r S s T t + 0x0055, 0x0075, 0xf455, 0x9d75, 0xaf55, 0xbf75, 0xf355, 0x9e75, 0xcd55, 0x9b75, 0xec55, 0x9575, //u + 0x0085, 0x009a, 0xf485, 0x9d9a, 0xaf85, 0xbf9a, 0xf385, 0x9e9a, 0xcd85, 0x9b9a, 0xec85, 0x959a, //u+ + 0x0056, 0x0076, 0x0057, 0x0077, 0x0058, 0x0078, // V v W w X x + 0x0059, 0x0079, 0xf459, 0x9d79, 0xaf59, 0xbf79, 0xf359, 0x9e79, 0xcd59, 0x9b79, 0x00eb, 0x0094, //y + 0x005a, 0x007a, // Z z + 0x00db, 0x00e2, 0x00c4, 0x00e3, 0x00c9, 0x00a0, 0x00e0, 0x00f6, + 0x00e4, 0x003f, 0x00dc, 0x00ce, 0x003f, 0x00d4, 0x00d5, 0x00d2, + 0x00d3, 0x00a5, 0x00d0, 0x00d1, 0x00f7, 0x00aa, 0x003f, 0x00dd, + 0x00cf, 0x003f, 0x00d9} +}; + +UKWORD WinCP1258[TOTAL_VNCHARS]= +//Windows CP 1258 +{ 0x0041, 0x0061, 0xec41, 0xec61, 0xcc41, 0xcc61, 0xd241, 0xd261, 0xde41, 0xde61, 0xf241, 0xf261, //a + 0x00c2, 0x00e2, 0xecc2, 0xece2, 0xccc2, 0xcce2, 0xd2c2, 0xd2e2, 0xdec2, 0xdee2, 0xf2c2, 0xf2e2, //a^ + 0x00c3, 0x00e3, 0xecc3, 0xece3, 0xccc3, 0xcce3, 0xd2c3, 0xd2e3, 0xdec3, 0xdee3, 0xf2c3, 0xf2e3, //a( + 0x0042, 0x0062, 0x0043, 0x0063, 0x0044, 0x0064, //B b C c D d + 0x00d0, 0x00f0, //DD, dd + 0x0045, 0x0065, 0xec45, 0xec65, 0xcc45, 0xcc65, 0xd245, 0xd265, 0xde45, 0xde65, 0xf245, 0xf265, //e + 0x00ca, 0x00ea, 0xecca, 0xecea, 0xccca, 0xccea, 0xd2ca, 0xd2ea, 0xdeca, 0xdeea, 0xf2ca, 0xf2ea, //e^ + 0x0046, 0x0066, 0x0047, 0x0067, 0x0048, 0x0068, // F f G g H h + 0x0049, 0x0069, 0xec49, 0xec69, 0xcc49, 0xcc69, 0xd249, 0xd269, 0xde49, 0xde69, 0xf249, 0xf269, //i + 0x004a, 0x006a, 0x004b, 0x006b, 0x004c, 0x006c, 0x004d, 0x006d, 0x004e, 0x006e, // J j K k L l M m N n + 0x004f, 0x006f, 0xec4f, 0xec6f, 0xcc4f, 0xcc6f, 0xd24f, 0xd26f, 0xde4f, 0xde6f, 0xf24f, 0xf26f, //o + 0x00d4, 0x00f4, 0xecd4, 0xecf4, 0xccd4, 0xccf4, 0xd2d4, 0xd2f4, 0xded4, 0xdef4, 0xf2d4, 0xf2f4, //o^ + 0x00d5, 0x00f5, 0xecd5, 0xecf5, 0xccd5, 0xccf5, 0xd2d5, 0xd2f5, 0xded5, 0xdef5, 0xf2d5, 0xf2f5, //o+ + 0x0050, 0x0070, 0x0051, 0x0071, 0x0052, 0x0072, 0x0053, 0x0073, 0x0054, 0x0074, //P p Q q R r S s T t + 0x0055, 0x0075, 0xec55, 0xec75, 0xcc55, 0xcc75, 0xd255, 0xd275, 0xde55, 0xde75, 0xf255, 0xf275, //u + 0x00dd, 0x00fd, 0xecdd, 0xecfd, 0xccdd, 0xccfd, 0xd2dd, 0xd2fd, 0xdedd, 0xdefd, 0xf2dd, 0xf2fd, //u+ + 0x0056, 0x0076, 0x0057, 0x0077, 0x0058, 0x0078, // V v W w X x + 0x0059, 0x0079, 0xec59, 0xec79, 0xcc59, 0xcc79, 0xd259, 0xd279, 0xde59, 0xde79, 0xf259, 0xf279, //y + 0x005a, 0x007a, // Z z + 0x0080, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, + 0x0089, 0x008A, 0x008B, 0x008C, 0x008E, 0x0091, 0x0092, 0x0093, + 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009A, 0x009B, + 0x009C, 0x009E, 0x009F}; + +UKWORD WinCP1258Pre[TOTAL_VNCHARS]= +//Windows CP1258 - with some more precomposed characters +{ 0x0041, 0x0061, 0x00c1, 0x00e1, 0x00c0, 0x00e0, 0xd241, 0xd261, 0xde41, 0xde61, 0xf241, 0xf261, //a + 0x00c2, 0x00e2, 0xecc2, 0xece2, 0xccc2, 0xcce2, 0xd2c2, 0xd2e2, 0xdec2, 0xdee2, 0xf2c2, 0xf2e2, //a^ + 0x00c3, 0x00e3, 0xecc3, 0xece3, 0xccc3, 0xcce3, 0xd2c3, 0xd2e3, 0xdec3, 0xdee3, 0xf2c3, 0xf2e3, //a( + 0x0042, 0x0062, 0x0043, 0x0063, 0x0044, 0x0064, //B b C c D d + 0x00d0, 0x00f0, //DD, dd + 0x0045, 0x0065, 0x00c9, 0x00e9, 0x00c8, 0x00e8, 0xd245, 0xd265, 0xde45, 0xde65, 0xf245, 0xf265, //e + 0x00ca, 0x00ea, 0xecca, 0xecea, 0xccca, 0xccea, 0xd2ca, 0xd2ea, 0xdeca, 0xdeea, 0xf2ca, 0xf2ea, //e^ + 0x0046, 0x0066, 0x0047, 0x0067, 0x0048, 0x0068, // F f G g H h + 0x0049, 0x0069, 0x00cd, 0x00ed, 0xcc49, 0xcc69, 0xd249, 0xd269, 0xde49, 0xde69, 0xf249, 0xf269, //i + 0x004a, 0x006a, 0x004b, 0x006b, 0x004c, 0x006c, 0x004d, 0x006d, 0x004e, 0x006e, // J j K k L l M m N n + 0x004f, 0x006f, 0x00d3, 0x00f3, 0xcc4f, 0xcc6f, 0xd24f, 0xd26f, 0xde4f, 0xde6f, 0xf24f, 0xf26f, //o + 0x00d4, 0x00f4, 0xecd4, 0xecf4, 0xccd4, 0xccf4, 0xd2d4, 0xd2f4, 0xded4, 0xdef4, 0xf2d4, 0xf2f4, //o^ + 0x00d5, 0x00f5, 0xecd5, 0xecf5, 0xccd5, 0xccf5, 0xd2d5, 0xd2f5, 0xded5, 0xdef5, 0xf2d5, 0xf2f5, //o+ + 0x0050, 0x0070, 0x0051, 0x0071, 0x0052, 0x0072, 0x0053, 0x0073, 0x0054, 0x0074, //P p Q q R r S s T t + 0x0055, 0x0075, 0x00da, 0x00fa, 0x00d9, 0x00f9, 0xd255, 0xd275, 0xde55, 0xde75, 0xf255, 0xf275, //u + 0x00dd, 0x00fd, 0xecdd, 0xecfd, 0xccdd, 0xccfd, 0xd2dd, 0xd2fd, 0xdedd, 0xdefd, 0xf2dd, 0xf2fd, //u+ + 0x0056, 0x0076, 0x0057, 0x0077, 0x0058, 0x0078, // V v W w X x + 0x0059, 0x0079, 0xec59, 0xec79, 0xcc59, 0xcc79, 0xd259, 0xd279, 0xde59, 0xde79, 0xf259, 0xf279, //y + 0x005a, 0x007a, // Z z + 0x0080, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, + 0x0089, 0x008A, 0x008B, 0x008C, 0x008E, 0x0091, 0x0092, 0x0093, + 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009A, 0x009B, + 0x009C, 0x009E, 0x009F}; + +UnicodeChar UnicodeTable[TOTAL_VNCHARS] = + {0x0041, 0x0061, 0x00c1, 0x00e1, 0x00c0, 0x00e0, 0x1ea2, 0x1ea3, 0x00c3, 0x00e3, 0x1ea0, 0x1ea1, //a + 0x00c2, 0x00e2, 0x1ea4, 0x1ea5, 0x1ea6, 0x1ea7, 0x1ea8, 0x1ea9, 0x1eaa, 0x1eab, 0x1eac, 0x1ead, //a^ + 0x0102, 0x0103, 0x1eae, 0x1eaf, 0x1eb0, 0x1eb1, 0x1eb2, 0x1eb3, 0x1eb4, 0x1eb5, 0x1eb6, 0x1eb7, //a( + 0x0042, 0x0062, 0x0043, 0x0063, 0x0044, 0x0064, //B b C c D d + 0x0110, 0x0111, // DD, dd + 0x0045, 0x0065, 0x00c9, 0x00e9, 0x00c8, 0x00e8, 0x1eba, 0x1ebb, 0x1ebc, 0x1ebd, 0x1eb8, 0x1eb9, //e + 0x00ca, 0x00ea, 0x1ebe, 0x1ebf, 0x1ec0, 0x1ec1, 0x1ec2, 0x1ec3, 0x1ec4, 0x1ec5, 0x1ec6, 0x1ec7, //e^ + 0x0046, 0x0066, 0x0047, 0x0067, 0x0048, 0x0068, // F f G g H h + 0x0049, 0x0069, 0x00cd, 0x00ed, 0x00cc, 0x00ec, 0x1ec8, 0x1ec9, 0x0128, 0x0129, 0x1eca, 0x1ecb, //i + 0x004a, 0x006a, 0x004b, 0x006b, 0x004c, 0x006c, 0x004d, 0x006d, 0x004e, 0x006e, // J j K k L l M m N n + 0x004f, 0x006f, 0x00d3, 0x00f3, 0x00d2, 0x00f2, 0x1ece, 0x1ecf, 0x00d5, 0x00f5, 0x1ecc, 0x1ecd, //o + 0x00d4, 0x00f4, 0x1ed0, 0x1ed1, 0x1ed2, 0x1ed3, 0x1ed4, 0x1ed5, 0x1ed6, 0x1ed7, 0x1ed8, 0x1ed9, //o^ + 0x01a0, 0x01a1, 0x1eda, 0x1edb, 0x1edc, 0x1edd, 0x1ede, 0x1edf, 0x1ee0, 0x1ee1, 0x1ee2, 0x1ee3, //o+ + 0x0050, 0x0070, 0x0051, 0x0071, 0x0052, 0x0072, 0x0053, 0x0073, 0x0054, 0x0074, //P p Q q R r S s T t + 0x0055, 0x0075, 0x00da, 0x00fa, 0x00d9, 0x00f9, 0x1ee6, 0x1ee7, 0x0168, 0x0169, 0x1ee4, 0x1ee5, //u + 0x01af, 0x01b0, 0x1ee8, 0x1ee9, 0x1eea, 0x1eeb, 0x1eec, 0x1eed, 0x1eee, 0x1eef, 0x1ef0, 0x1ef1, //u+ + 0x0056, 0x0076, 0x0057, 0x0077, 0x0058, 0x0078, // V v W w X x + 0x0059, 0x0079, 0x00dd, 0x00fd, 0x1ef2, 0x1ef3, 0x1ef6, 0x1ef7, 0x1ef8, 0x1ef9, 0x1ef4, 0x1ef5, //y + 0x005a, 0x007a, // Z z +// Symbols that have different code points in Unicode and Western charsets + 0x20AC, 0x20A1, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, 0x02C6, + 0x2030, 0x0160, 0x2039, 0x0152, 0x017D, 0x2018, 0x2019, 0x201C, + 0x201D, 0x2022, 0x2013, 0x2014, 0x02DC, 0x2122, 0x0161, 0x203A, + 0x0153, 0x017E, 0x0178}; + +/* +unsigned char WesternSymbols[] = + {0x80, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, + 0x89, 0x8A, 0x8B, 0x8C, 0x8E, 0x91, 0x92, 0x93, + 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, + 0x9C, 0x9E, 0x9F}; +*/ + +/* +' 0x27 +` 0x60 +? 0x3f +~ 0x7e +. 0x2e + +^ 0x5e +( 0x28 ++ 0x2b + +*/ +UKDWORD VIQRTable[TOTAL_VNCHARS] = + { 0x41, 0x61, 0x2741, 0x2761, 0x6041, 0x6061, 0x3f41, 0x3f61, 0x7e41, 0x7e61, 0x2e41, 0x2e61, //a + 0x5e41, 0x5e61, 0x275e41, 0x275e61, 0x605e41, 0x605e61, 0x3f5e41, 0x3f5e61, 0x7e5e41, 0x7e5e61, 0x2e5e41, 0x2e5e61, //a^ + 0x2841, 0x2861, 0x272841, 0x272861, 0x602841, 0x602861, 0x3f2841, 0x3f2861, 0x7e2841, 0x7e2861, 0x2e2841, 0x2e2861, //a( + 0x42, 0x62, 0x43, 0x63, 0x44, 0x64, //B b C c D d + 0x4444, 0x6464, // DD, dd + 0x45, 0x65, 0x2745, 0x2765, 0x6045, 0x6065, 0x3f45, 0x3f65, 0x7e45, 0x7e65, 0x2e45, 0x2e65, //e + 0x5e45, 0x5e65, 0x275e45, 0x275e65, 0x605e45, 0x605e65, 0x3f5e45, 0x3f5e65, 0x7e5e45, 0x7e5e65, 0x2e5e45, 0x2e5e65, //e^ + 0x46, 0x66, 0x47, 0x67, 0x48, 0x68, // F f G g H h + 0x49, 0x69, 0x2749, 0x2769, 0x6049, 0x6069, 0x3f49, 0x3f69, 0x7e49, 0x7e69, 0x2e49, 0x2e69, //i + 0x4a, 0x6a, 0x4b, 0x6b, 0x4c, 0x6c, 0x4d, 0x6d, 0x4e, 0x6e, // J j K k L l M m N n + 0x4f, 0x6f, 0x274f, 0x276f, 0x604f, 0x606f, 0x3f4f, 0x3f6f, 0x7e4f, 0x7e6f, 0x2e4f, 0x2e6f, //o + 0x5e4f, 0x5e6f, 0x275e4f, 0x275e6f, 0x605e4f, 0x605e6f, 0x3f5e4f, 0x3f5e6f, 0x7e5e4f, 0x7e5e6f, 0x2e5e4f, 0x2e5e6f, //o^ + 0x2b4f, 0x2b6f, 0x272b4f, 0x272b6f, 0x602b4f, 0x602b6f, 0x3f2b4f, 0x3f2b6f, 0x7e2b4f, 0x7e2b6f, 0x2e2b4f, 0x2e2b6f, //o+ + 0x50, 0x70, 0x51, 0x71, 0x52, 0x72, 0x53, 0x73, 0x54, 0x74, //P p Q q R r S s T t + 0x55, 0x75, 0x2755, 0x2775, 0x6055, 0x6075, 0x3f55, 0x3f75, 0x7e55, 0x7e75, 0x2e55, 0x2e75, //u + 0x2b55, 0x2b75, 0x272b55, 0x272b75, 0x602b55, 0x602b75, 0x3f2b55, 0x3f2b75, 0x7e2b55, 0x7e2b75, 0x2e2b55, 0x2e2b75, //u+ + 0x56, 0x76, 0x57, 0x77, 0x58, 0x78, // V v W w X x + 0x59, 0x79, 0x2759, 0x2779, 0x6059, 0x6079, 0x3f59, 0x3f79, 0x7e59, 0x7e79, 0x2e59, 0x2e79, + 0x5a, 0x7a, // Z z + 0x80, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, + 0x89, 0x8A, 0x8B, 0x8C, 0x8E, 0x91, 0x92, 0x93, + 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, + 0x9C, 0x9E, 0x9F}; + + +UKDWORD UnicodeComposite[TOTAL_VNCHARS] = +{ 0x00000041, 0x00000061, 0x03010041, 0x03010061, 0x03000041, 0x03000061, //a + 0x03090041, 0x03090061, 0x03030041, 0x03030061, 0x03230041, 0x03230061, //a + + 0x000000c2, 0x000000e2, 0x030100c2, 0x030100e2, 0x030000c2, 0x030000e2, + 0x030900c2, 0x030900e2, 0x030300c2, 0x030300e2, 0x032300c2, 0x032300e2, //a^ + + 0x00000102, 0x00000103, 0x03010102, 0x03010103, 0x03000102, 0x03000103, + 0x03090102, 0x03090103, 0x03030102, 0x03030103, 0x03230102, 0x03230103, //a( + + 0x0042, 0x0062, 0x0043, 0x0063, 0x0044, 0x0064, //B b C c D d + 0x0110, 0x0111, //0x00d1, 0x00f1, //DD, dd + + 0x00000045, 0x00000065, 0x03010045, 0x03010065, 0x03000045, 0x03000065, + 0x03090045, 0x03090065, 0x03030045, 0x03030065, 0x03230045, 0x03230065, //e + + 0x000000ca, 0x000000ea, 0x030100ca, 0x030100ea, 0x030000ca, 0x030000ea, + 0x030900ca, 0x030900ea, 0x030300ca, 0x030300ea, 0x032300ca, 0x032300ea, //e^ + + 0x0046, 0x0066, 0x0047, 0x0067, 0x0048, 0x0068, // F f G g H h + + 0x00000049, 0x00000069, 0x03010049, 0x03010069, 0x03000049, 0x03000069, + 0x03090049, 0x03090069, 0x03030049, 0x03030069, 0x03230049, 0x03230069, //i + + 0x004a, 0x006a, 0x004b, 0x006b, 0x004c, 0x006c, 0x004d, 0x006d, 0x004e, 0x006e, // J j K k L l M m N n + + 0x0000004f, 0x0000006f, 0x0301004f, 0x0301006f, 0x0300004f, 0x0300006f, + 0x0309004f, 0x0309006f, 0x0303004f, 0x0303006f, 0x0323004f, 0x0323006f, //o + + 0x000000d4, 0x000000f4, 0x030100d4, 0x030100f4, 0x030000d4, 0x030000f4, + 0x030900d4, 0x030900f4, 0x030300d4, 0x030300f4, 0x032300d4, 0x032300f4, //o^ + + 0x000001a0, 0x000001a1, 0x030101a0, 0x030101a1, 0x030001a0, 0x030001a1, + 0x030901a0, 0x030901a1, 0x030301a0, 0x030301a1, 0x032301a0, 0x032301a1, //o+ + + 0x0050, 0x0070, 0x0051, 0x0071, 0x0052, 0x0072, 0x0053, 0x0073, 0x0054, 0x0074, //P p Q q R r S s T t + + 0x00000055, 0x00000075, 0x03010055, 0x03010075, 0x03000055, 0x03000075, + 0x03090055, 0x03090075, 0x03030055, 0x03030075, 0x03230055, 0x03230075, //u + + 0x000001af, 0x000001b0, 0x030101af, 0x030101b0, 0x030001af, 0x030001b0, + 0x030901af, 0x030901b0, 0x030301af, 0x030301b0, 0x032301af, 0x032301b0, //u+ + + 0x0056, 0x0076, 0x0057, 0x0077, 0x0058, 0x0078, // V v W w X x + + 0x00000059, 0x00000079, 0x03010059, 0x03010079, 0x03000059, 0x03000079, + 0x03090059, 0x03090079, 0x03030059, 0x03030079, 0x03230059, 0x03230079, //y + 0x005a, 0x007a, // Z z +// Symbols that have different code points in Unicode and Western charsets + 0x20AC, 0x20A1, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, 0x02C6, + 0x2030, 0x0160, 0x2039, 0x0152, 0x017D, 0x2018, 0x2019, 0x201C, + 0x201D, 0x2022, 0x2013, 0x2014, 0x02DC, 0x2122, 0x0161, 0x203A, + 0x0153, 0x017E, 0x0178}; + +int StdVnRootChar[TOTAL_VNCHARS] = { + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, //a [A=0] + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, //a^ -> a + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, //a( -> a + 36, 37, 38, 39, 40, 41, // bcd [D=40, d=41] + 40, 41, // DD dd [mapped to D, d] + 44, 45, 44, 45, 44, 45, 44, 45, 44, 45, 44, 45, // 3: e [E = 44] + 44, 45, 44, 45, 44, 45, 44, 45, 44, 45, 44, 45, // 4: e^ -> e + 68, 69, 70, 71, 72, 73, // fgh + 74, 75, 74, 75, 74, 75, 74, 75, 74, 75, 74, 75, // 5: i + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, //jklmn + 96, 97, 96, 97, 96, 97, 96, 97, 96, 97, 96, 97, // 6: o [o=96] + 96, 97, 96, 97, 96, 97, 96, 97, 96, 97, 96, 97, // 7: o^ -> o + 96, 97, 96, 97, 96, 97, 96, 97, 96, 97, 96, 97, // 8: o+ -> o + 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, // pqrst + 142, 143, 142, 143, 142, 143, 142, 143, 142, 143, 142, 143, // 9: u [U=142] + 142, 143, 142, 143, 142, 143, 142, 143, 142, 143, 142, 143, //10: u+ -> u + 166, 167, 168, 169, 170, 171, //vwx + 172, 173, 172, 173, 172, 173, 172, 173, 172, 173, 172, 173, //11: y [Y=172] + 184, 185, // z + 186, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 198, 199, 200, 201, + 202, 203, 204, 205, 206, 207, 208, 209, + 210, 211, 212 +}; + +int StdVnNoTone[TOTAL_VNCHARS] = { + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, //a [A=0] + 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, //a^ + 24, 25, 24, 25, 24, 25, 24, 25, 24, 25, 24, 25, //a( + 36, 37, 38, 39, 40, 41, // bcd [D=40, d=41] + 42, 43, // DD dd + 44, 45, 44, 45, 44, 45, 44, 45, 44, 45, 44, 45, // 3: e [E = 44] + 56, 57, 56, 57, 56, 57, 56, 57, 56, 57, 56, 57, // 4: e^ + 68, 69, 70, 71, 72, 73, // fgh + 74, 75, 74, 75, 74, 75, 74, 75, 74, 75, 74, 75, // 5: i + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, //jklmn + 96, 97, 96, 97, 96, 97, 96, 97, 96, 97, 96, 97, // 6: o [o=96] + 108, 109, 108, 109, 108, 109, 108, 109, 108, 109, 108, 109, // 7: o^ + 120, 121, 120, 121, 120, 121, 120, 121, 120, 121, 120, 121, // 8: o+ + 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, // pqrst + 142, 143, 142, 143, 142, 143, 142, 143, 142, 143, 142, 143, // 9: u [U=142] + 154, 155, 154, 155, 154, 155, 154, 155, 154, 155, 154, 155, //10: u+ + 166, 167, 168, 169, 170, 171, //vwx + 172, 173, 172, 173, 172, 173, 172, 173, 172, 173, 172, 173, //11: y [Y=172] + 184, 185, // z + 186, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 198, 199, 200, 201, + 202, 203, 204, 205, 206, 207, 208, 209, + 210, 211, 212 +}; diff --git a/unikey/data.h b/unikey/data.h new file mode 100644 index 0000000..d4b2be8 --- /dev/null +++ b/unikey/data.h @@ -0,0 +1,11 @@ +// -*- coding:unix; mode:c++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- +#ifndef VIETNAMESE_CHARSET_DATA_H +#define VIETNAMESE_CHARSET_DATA_H + +// This header defines some special characters +const StdVnChar StdStartQuote = (VnStdCharOffset + 201); // 0x93 in the Western charset +// 201 is the offset of character 0x93 (start quote) in Vn charsets +const StdVnChar StdEndQuote = (VnStdCharOffset + 202); // 0x94 in the Western charset +const StdVnChar StdEllipsis = (VnStdCharOffset + 190); // 0x85 in Western charet. + +#endif diff --git a/unikey/error.cpp b/unikey/error.cpp new file mode 100644 index 0000000..4b73526 --- /dev/null +++ b/unikey/error.cpp @@ -0,0 +1,46 @@ +// -*- coding:unix; mode:c++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- +/*------------------------------------------------------------------------------ +VnConv: Vietnamese Encoding Converter Library +UniKey Project: http://unikey.sourceforge.net +Copyleft (C) 1998-2002 Pham Kim Long +Contact: longp@cslab.felk.cvut.cz + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +--------------------------------------------------------------------------------*/ +// For some unknown reasons, the functions in this file cannot be exported +// We had to move them to convert.cpp. +// TODO: inspect this problem later! +/* +#include "stdafx.h" +#include "vnconv.h" + +char *ErrTable[VNCONV_LAST_ERROR] = +{"No error", + "Unknown error", + "Invalid charset", + "Error opening input file", + "Error opening output file", + "Error writing to output stream", + "Not enough memory", +}; + +DllExport const char * VnConvErrMsg(int errCode) +{ + if (errCode < 0 || errCode >= VNCONV_LAST_ERROR) + errCode = VNCONV_UNKNOWN_ERROR; + return ErrTable[errCode]; +} + +*/ \ No newline at end of file diff --git a/unikey/inputproc.cpp b/unikey/inputproc.cpp new file mode 100644 index 0000000..117c179 --- /dev/null +++ b/unikey/inputproc.cpp @@ -0,0 +1,401 @@ +// -*- mode:c++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- +/* Unikey Vietnamese Input Method + * Copyright (C) 2000-2005 Pham Kim Long + * Contact: + * unikey@gmail.com + * UniKey project: http://unikey.org + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include "inputproc.h" + +using namespace std; + +/* +unsigned char WordBreakSyms[] = { + ',', ';', ':', '.', '\"', '\'', '!', '?', ' ', + '<', '>', '=', '+', '-', '*', '/', '\\', + '_', '~', '`', '@', '#', '$', '%', '^', '&', '(', ')', '{', '}', '[', ']'}; +*/ + +unsigned char WordBreakSyms[] = { + ',', ';', ':', '.', '\"', '\'', '!', '?', ' ', + '<', '>', '=', '+', '-', '*', '/', '\\', + '_', '@', '#', '$', '%', '&', '(', ')', '{', '}', '[', ']', '|'}; //we excluded ~, `, ^ + +VnLexiName AZLexiUpper[] = + {vnl_A, vnl_B, vnl_C, vnl_D, vnl_E, vnl_F, vnl_G, vnl_H, vnl_I, vnl_J, + vnl_K, vnl_L, vnl_M, vnl_N, vnl_O, vnl_P, vnl_Q, vnl_R, vnl_S, vnl_T, + vnl_U, vnl_V, vnl_W, vnl_X, vnl_Y, vnl_Z}; + +VnLexiName AZLexiLower[] = + {vnl_a, vnl_b, vnl_c, vnl_d, vnl_e, vnl_f, vnl_g, vnl_h, vnl_i, vnl_j, + vnl_k, vnl_l, vnl_m, vnl_n, vnl_o, vnl_p, vnl_q, vnl_r, vnl_s, vnl_t, + vnl_u, vnl_v, vnl_w, vnl_x, vnl_y, vnl_z}; + +UkCharType UkcMap[256]; + +struct _ascVnLexi { + int asc; + VnLexiName lexi; +}; + +//List of western characters outside range A-Z that are +//also Vietnamese characters +_ascVnLexi AscVnLexiList[] = { + {0xC0, vnl_A2}, + {0xC1, vnl_A1}, + {0xC2, vnl_Ar}, + {0xC2, vnl_A4}, + {0xC8, vnl_E2}, + {0xC9, vnl_E1}, + {0xCA, vnl_Er}, + {0xCC, vnl_I2}, + {0xCD, vnl_I1}, + {0xD2, vnl_O2}, + {0xD3, vnl_O1}, + {0xD4, vnl_Or}, + {0xD5, vnl_O4}, + {0xD9, vnl_U2}, + {0xDA, vnl_U1}, + {0xDD, vnl_Y1}, + {0xE0, vnl_a2}, + {0xE1, vnl_a1}, + {0xE2, vnl_ar}, + {0xE3, vnl_a4}, + {0xE8, vnl_e2}, + {0xE9, vnl_e1}, + {0xEA, vnl_er}, + {0xEC, vnl_i2}, + {0xED, vnl_i1}, + {0xF2, vnl_o2}, + {0xF3, vnl_o1}, + {0xF4, vnl_or}, + {0xF5, vnl_o4}, + {0xF9, vnl_u2}, + {0xFA, vnl_u1}, + {0xFD, vnl_y1}, + {0x00, vnl_nonVnChar} +}; + +VnLexiName IsoVnLexiMap[256]; + +bool ClassifierTableInitialized = false; + +DllExport UkKeyMapping TelexMethodMapping[] = { + {'Z', vneTone0}, + {'S', vneTone1}, + {'F', vneTone2}, + {'R', vneTone3}, + {'X', vneTone4}, + {'J', vneTone5}, + {'W', vne_telex_w}, + {'A', vneRoof_a}, + {'E', vneRoof_e}, + {'O', vneRoof_o}, + {'D', vneDd}, + {'[', vneCount + vnl_oh}, + {']', vneCount + vnl_uh}, + {'{', vneCount + vnl_Oh}, + {'}', vneCount + vnl_Uh}, + {0, vneNormal} +}; + +DllExport UkKeyMapping SimpleTelexMethodMapping[] = { + {'Z', vneTone0}, + {'S', vneTone1}, + {'F', vneTone2}, + {'R', vneTone3}, + {'X', vneTone4}, + {'J', vneTone5}, + {'W', vneHookAll}, + {'A', vneRoof_a}, + {'E', vneRoof_e}, + {'O', vneRoof_o}, + {'D', vneDd}, + {0, vneNormal} +}; + +DllExport UkKeyMapping SimpleTelex2MethodMapping[] = { + {'Z', vneTone0}, + {'S', vneTone1}, + {'F', vneTone2}, + {'R', vneTone3}, + {'X', vneTone4}, + {'J', vneTone5}, + {'W', vne_telex_w}, + {'A', vneRoof_a}, + {'E', vneRoof_e}, + {'O', vneRoof_o}, + {'D', vneDd}, + {0, vneNormal} +}; + +DllExport UkKeyMapping VniMethodMapping[] = { + {'0', vneTone0}, + {'1', vneTone1}, + {'2', vneTone2}, + {'3', vneTone3}, + {'4', vneTone4}, + {'5', vneTone5}, + {'6', vneRoofAll}, + {'7', vneHook_uo}, + {'8', vneBowl}, + {'9', vneDd}, + {0, vneNormal} +}; + +DllExport UkKeyMapping VIQRMethodMapping[] = { + {'0', vneTone0}, + {'\'', vneTone1}, + {'`', vneTone2}, + {'?', vneTone3}, + {'~', vneTone4}, + {'.', vneTone5}, + {'^', vneRoofAll}, + {'+', vneHook_uo}, + {'*', vneHook_uo}, + {'(', vneBowl}, + {'D', vneDd}, + {'\\', vneEscChar}, + {0, vneNormal} +}; + +DllExport UkKeyMapping MsViMethodMapping[] = { + {'5', vneTone2}, + {'%', vneTone2}, + {'6', vneTone3}, + {'^', vneTone3}, + {'7', vneTone4}, + {'&', vneTone4}, + {'8', vneTone1}, + {'*', vneTone1}, + {'9', vneTone5}, + {'(', vneTone5}, + {'1', vneCount + vnl_ab}, + {'!', vneCount + vnl_Ab}, + {'2', vneCount + vnl_ar}, + {'@', vneCount + vnl_Ar}, + {'3', vneCount + vnl_er}, + {'#', vneCount + vnl_Er}, + {'4', vneCount + vnl_or}, + {'$', vneCount + vnl_Or}, + {'0', vneCount + vnl_dd}, + {')', vneCount + vnl_DD}, + {'[', vneCount + vnl_uh}, + {']', vneCount + vnl_oh}, + {'{', vneCount + vnl_Uh}, + {'}', vneCount + vnl_Oh}, + {0, vneNormal} +}; + +//------------------------------------------- +void SetupInputClassifierTable() +{ + unsigned int c; + int i; + + for (c=0; c<=32; c++) { + UkcMap[c] = ukcReset; + } + + for (c=33; c<256; c++) { + UkcMap[c] = ukcNonVn; + } + + /* + for (c = '0'; c <= '9'; c++) + UkcMap[c] = ukcNonVn; + */ + + for (c = 'a'; c <= 'z'; c++) + UkcMap[c] = ukcVn; + for (c = 'A'; c <= 'Z'; c++) + UkcMap[c] = ukcVn; + + for (i=0; AscVnLexiList[i].asc; i++) { + UkcMap[AscVnLexiList[i].asc] = ukcVn; + } + + UkcMap[(unsigned char)'j'] = ukcNonVn; + UkcMap[(unsigned char)'J'] = ukcNonVn; + UkcMap[(unsigned char)'f'] = ukcNonVn; + UkcMap[(unsigned char)'F'] = ukcNonVn; + UkcMap[(unsigned char)'w'] = ukcNonVn; + UkcMap[(unsigned char)'W'] = ukcNonVn; + + int count = sizeof(WordBreakSyms)/sizeof(unsigned char); + for (i = 0; i < count; i++) + UkcMap[WordBreakSyms[i]] = ukcWordBreak; + + //Calculate IsoVnLexiMap + for (i = 0; i < 256; i++) { + IsoVnLexiMap[i] = vnl_nonVnChar; + } + + for (i = 0; AscVnLexiList[i].asc; i++) { + IsoVnLexiMap[AscVnLexiList[i].asc] = AscVnLexiList[i].lexi; + } + + for (c = 'a'; c <= 'z'; c++) { + IsoVnLexiMap[c] = AZLexiLower[c - 'a']; + } + + for (c = 'A'; c <= 'Z'; c++) { + IsoVnLexiMap[c] = AZLexiUpper[c - 'A']; + } +} + +//------------------------------------------- +void UkInputProcessor::init() +{ + if (!ClassifierTableInitialized) { + SetupInputClassifierTable(); + ClassifierTableInitialized = true; + } + setIM(UkTelex); +} + +//------------------------------------------- +int UkInputProcessor::setIM(UkInputMethod im) +{ + m_im = im; + switch (im) { + case UkTelex: + useBuiltIn(TelexMethodMapping); + break; + case UkSimpleTelex: + useBuiltIn(SimpleTelexMethodMapping); + break; + case UkSimpleTelex2: + useBuiltIn(SimpleTelex2MethodMapping); + break; + case UkVni: + useBuiltIn(VniMethodMapping); + break; + case UkViqr: + useBuiltIn(VIQRMethodMapping); + break; + case UkMsVi: + useBuiltIn(MsViMethodMapping); + break; + default: + m_im = UkTelex; + useBuiltIn(TelexMethodMapping); + } + return 1; +} + +//------------------------------------------- +int UkInputProcessor::setIM(int map[256]) +{ + int i; + m_im = UkUsrIM; + for (i=0; i<256; i++) + m_keyMap[i] = map[i]; + return 1; +} + + +//------------------------------------------- +void UkResetKeyMap(int keyMap[256]) +{ + unsigned int c; + for (c=0; c<256; c++) + keyMap[c] = vneNormal; +} + +//------------------------------------------- +void UkInputProcessor::useBuiltIn(UkKeyMapping *map) +{ + UkResetKeyMap(m_keyMap); + for (int i=0; map[i].key; i++) { + m_keyMap[map[i].key] = map[i].action; + if (map[i].action < vneCount) { + if (islower(map[i].key)) { + m_keyMap[toupper(map[i].key)] = map[i].action; + } + else if (isupper(map[i].key)) { + m_keyMap[tolower(map[i].key)] = map[i].action; + } + } + } +} + +//------------------------------------------- +void UkInputProcessor::keyCodeToEvent(unsigned int keyCode, UkKeyEvent & ev) +{ + ev.keyCode = keyCode; + if (keyCode > 255) { + ev.evType = vneNormal; + ev.vnSym = IsoToVnLexi(keyCode); + ev.chType = (ev.vnSym == vnl_nonVnChar)? ukcNonVn : ukcVn; + } + else { + ev.chType = UkcMap[keyCode]; + ev.evType = m_keyMap[keyCode]; + + if (ev.evType >= vneTone0 && ev.evType <= vneTone5) { + ev.tone = ev.evType - vneTone0; + } + + if (ev.evType >= vneCount) { + ev.chType = ukcVn; + ev.vnSym = (VnLexiName)(ev.evType - vneCount); + ev.evType = vneMapChar; + } + else { + ev.vnSym = IsoToVnLexi(keyCode); + } + } +} + +//---------------------------------------------------------------- +// This method translates a key stroke to a symbol. +// Key strokes are simply considered character input, not action keys as in +// keyCodeToEvent method +//---------------------------------------------------------------- +void UkInputProcessor::keyCodeToSymbol(unsigned int keyCode, UkKeyEvent & ev) +{ + ev.keyCode = keyCode; + ev.evType = vneNormal; + ev.vnSym = IsoToVnLexi(keyCode); + if (keyCode > 255) { + ev.chType = (ev.vnSym == vnl_nonVnChar)? ukcNonVn : ukcVn; + } + else { + ev.chType = UkcMap[keyCode]; + } +} + +//------------------------------------------- +UkCharType UkInputProcessor::getCharType(unsigned int keyCode) +{ + if (keyCode > 255) + return (IsoToVnLexi(keyCode) == vnl_nonVnChar) ? ukcNonVn : ukcVn; + return UkcMap[keyCode]; +} + +//------------------------------------------- +void UkInputProcessor::getKeyMap(int map[256]) +{ + int i; + for (i=0; i<256; i++) + map[i] = m_keyMap[i]; +} + diff --git a/unikey/inputproc.h b/unikey/inputproc.h new file mode 100644 index 0000000..27babfe --- /dev/null +++ b/unikey/inputproc.h @@ -0,0 +1,124 @@ +// -*- coding:unix; mode:c++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- +/* Unikey Vietnamese Input Method + * Copyright (C) 2000-2005 Pham Kim Long + * Contact: + * unikey@gmail.com + * UniKey project: http://unikey.org + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#ifndef __UK_INPUT_PROCESSOR_H +#define __UK_INPUT_PROCESSOR_H + +#include "keycons.h" +#include "vnlexi.h" + +#if defined(_WIN32) + #define DllExport __declspec( dllexport ) + #define DllImport __declspec( dllimport ) + #if defined(UNIKEYHOOK) + #define DllInterface __declspec( dllexport ) + #else + #define DllInterface __declspec( dllimport ) + #endif +#else + #define DllInterface //not used + #define DllExport + #define DllImport +#endif + +enum UkKeyEvName { + vneRoofAll, vneRoof_a, vneRoof_e, vneRoof_o, + vneHookAll, vneHook_uo, vneHook_u, vneHook_o, vneBowl, + vneDd, + vneTone0, vneTone1, vneTone2, vneTone3, vneTone4, vneTone5, + vne_telex_w, //special for telex + vneMapChar, //e.g. [ -> u+ , ] -> o+ + vneEscChar, + vneNormal, //does not belong to any of the above categories + vneCount //just to count how many event types there are +}; + +enum UkCharType { + ukcVn, + ukcWordBreak, + ukcNonVn, + ukcReset +}; + +struct UkKeyEvent { + int evType; + UkCharType chType; + VnLexiName vnSym; //meaningful only when chType==ukcVn + unsigned int keyCode; + int tone; //meaningful only when this is a vowel +}; + +struct UkKeyMapping { + unsigned char key; + int action; +}; + +/////////////////////////////////////////// +class UkInputProcessor { + +public: + //don't do anything with constructor, because + //this object can be allocated in shared memory + //Use init method instead + //UkInputProcessor(); + + void init(); + + UkInputMethod getIM() + { + return m_im; + } + + void keyCodeToEvent(unsigned int keyCode, UkKeyEvent & ev); + void keyCodeToSymbol(unsigned int keyCode, UkKeyEvent & ev); + int setIM(UkInputMethod im); + int setIM(int map[256]); + void getKeyMap(int map[256]); + + UkCharType getCharType(unsigned int keyCode); + +protected: + static bool m_classInit; + + UkInputMethod m_im; + int m_keyMap[256]; + + void useBuiltIn(UkKeyMapping *map); + +}; + +void UkResetKeyMap(int keyMap[256]); +void SetupInputClassifierTable(); + +DllInterface extern UkKeyMapping TelexMethodMapping[]; +DllInterface extern UkKeyMapping SimpleTelexMethodMapping[]; +DllInterface extern UkKeyMapping VniMethodMapping[]; +DllInterface extern UkKeyMapping VIQRMethodMapping[]; +DllInterface extern UkKeyMapping MsViMethodMapping[]; + +extern VnLexiName IsoVnLexiMap[]; +inline VnLexiName IsoToVnLexi(unsigned int keyCode) +{ + return (keyCode >= 256)? vnl_nonVnChar : IsoVnLexiMap[keyCode]; +} + +#endif diff --git a/unikey/keycons.h b/unikey/keycons.h new file mode 100644 index 0000000..4f9c2f0 --- /dev/null +++ b/unikey/keycons.h @@ -0,0 +1,81 @@ +// -*- coding:unix; mode:c++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- +/*------------------------------------------------------------------------------ +UniKey - Open-source Vietnamese Keyboard +Copyright (C) 1998-2004 Pham Kim Long +Contact: + unikey@gmail.com + http://unikey.org + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +--------------------------------------------------------------------------------*/ +#ifndef __KEY_CONS_H +#define __KEY_CONS_H + +// macro table constants +#define MAX_MACRO_KEY_LEN 16 +//#define MAX_MACRO_TEXT_LEN 256 +#define MAX_MACRO_TEXT_LEN 1024 +#define MAX_MACRO_ITEMS 1024 +#define MAX_MACRO_LINE (MAX_MACRO_TEXT_LEN + MAX_MACRO_KEY_LEN) + +#define MACRO_MEM_SIZE (1024*128) //128 KB + +#define CP_US_ANSI 1252 + +typedef enum {UkTelex, UkVni, UkViqr, UkMsVi, UkUsrIM, UkSimpleTelex, UkSimpleTelex2} UkInputMethod; +typedef struct _UnikeyOptions UnikeyOptions; + +struct _UnikeyOptions +{ + int freeMarking; + int modernStyle; + int macroEnabled; + int useUnicodeClipboard; + int alwaysMacro; + int strictSpellCheck; + int useIME; //for Win32 only + int spellCheckEnabled; + int autoNonVnRestore; +}; + +#define UKOPT_FLAG_ALL 0xFFFFFFFF +#define UKOPT_FLAG_FREE_STYLE 0x00000001 +//#define UKOPT_FLAG_MANUAL_TONE 0x00000002 +#define UKOPT_FLAG_MODERN 0x00000004 +#define UKOPT_FLAG_MACRO_ENABLED 0x00000008 +#define UKOPT_FLAG_USE_CLIPBOARD 0x00000010 +#define UKOPT_FLAG_ALWAYS_MACRO 0x00000020 +#define UKOPT_FLAG_STRICT_SPELL 0x00000040 +#define UKOPT_FLAG_USE_IME 0x00000080 +#define UKOPT_FLAG_SPELLCHECK_ENABLED 0x00000100 + +#if defined(WIN32) +typedef struct _UnikeySysInfo UnikeySysInfo; +struct _UnikeySysInfo +{ + int switchKey; + HHOOK keyHook; + HHOOK mouseHook; + HWND hMainDlg; + UINT iconMsgId; + HICON hVietIcon,hEnIcon; + int unicodePlatform; + DWORD winMajorVersion, winMinorVersion; +}; +#endif + +typedef enum {UkCharOutput, UkKeyOutput} UkOutputType; + +#endif diff --git a/unikey/mactab.cpp b/unikey/mactab.cpp new file mode 100644 index 0000000..9abfa57 --- /dev/null +++ b/unikey/mactab.cpp @@ -0,0 +1,346 @@ +// -*- coding:unix; mode:c++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- +/* Unikey Vietnamese Input Method + * Copyright (C) 2000-2005 Pham Kim Long + * Contact: + * unikey@gmail.com + * UniKey project: http://unikey.org + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include "mactab.h" +#include "vnconv.h" + +using namespace std; +#define UKMACRO_VERSION_UTF8 1 + +//--------------------------------------------------------------- +void CMacroTable::init() +{ + m_memSize = MACRO_MEM_SIZE; + m_count = 0; + m_occupied = 0; +} + +//--------------------------------------------------------------- +char *MacCompareStartMem; + +#define STD_TO_LOWER(x) (((x) >= VnStdCharOffset && \ + (x) < (VnStdCharOffset + TOTAL_ALPHA_VNCHARS) && \ + !((x) & 1)) ? \ + (x+1) : (x)) + +int macCompare(const void *p1, const void *p2) +{ + StdVnChar *s1 = (StdVnChar *) ((char *)MacCompareStartMem + ((MacroDef *)p1)->keyOffset); + StdVnChar *s2 = (StdVnChar *) ((char *)MacCompareStartMem + ((MacroDef *)p2)->keyOffset); + + int i; + StdVnChar ls1, ls2; + + for (i=0; s1[i] != 0 && s2[i] != 0; i++) { + ls1 = STD_TO_LOWER(s1[i]); + ls2 = STD_TO_LOWER(s2[i]); + if (ls1 > ls2) + return 1; + if (ls1 < ls2) + return -1; + /* + if (s1[i] > s2[i]) + return 1; + if (s1[i] < s2[i]) + return -1; + */ + } + if (s1[i] == 0) + return (s2[i] == 0)? 0 : -1; + return 1; +} + +//--------------------------------------------------------------- +int macKeyCompare(const void *key, const void *ele) +{ + StdVnChar *s1 = (StdVnChar *)key; + StdVnChar *s2 = (StdVnChar *) ((char *)MacCompareStartMem + ((MacroDef *)ele)->keyOffset); + + StdVnChar ls1, ls2; + int i; + for (i=0; s1[i] != 0 && s2[i] != 0; i++) { + ls1 = STD_TO_LOWER(s1[i]); + ls2 = STD_TO_LOWER(s2[i]); + if (ls1 > ls2) + return 1; + if (ls1 < ls2) + return -1; + /* + if (s1[i] > s2[i]) + return 1; + if (s1[i] < s2[i]) + return -1; + */ + } + if (s1[i] == 0) + return (s2[i] == 0)? 0 : -1; + return 1; +} + +//--------------------------------------------------------------- +const StdVnChar *CMacroTable::lookup(StdVnChar *key) +{ + MacCompareStartMem = m_macroMem; + MacroDef *p = (MacroDef *)bsearch(key, m_table, m_count, sizeof(MacroDef), macKeyCompare); + if (p) + return (StdVnChar *)(m_macroMem + p->textOffset); + return 0; +} + +//---------------------------------------------------------------------------- +// Read header, if it's present in the file. Get the version of the file +// If header is absent, go back to the beginning of file and set version to 0 +// Return false if reading failed. +// +// Header format: ;[DO NOT DELETE THIS LINE]***version=n +//---------------------------------------------------------------------------- +bool CMacroTable::readHeader(FILE *f, int & version) +{ + char line[MAX_MACRO_LINE]; + if (!fgets(line, sizeof(line), f)) { + if (feof(f)) { + fseek(f, 0, SEEK_SET); + version = 0; + return true; + } + return false; + } + + //if BOM is available, skip it + char *p = line; + size_t len = strlen(line); + if (len >= 3 && (unsigned char)line[0] == 0xEF && (unsigned char)line[1] == 0xBB && + (unsigned char)line[2] == 0xBF) + { + p += 3; + } + + //read version number + p = strstr(p, "***"); + if (p) { + p += 3; + //skip possible spaces + while (*p == ' ') p++; + if (sscanf(p, "version=%d", &version) == 1) + return true; + } + + fseek(f, 0, SEEK_SET); + version = 0; + return true; +} + +//---------------------------------------------------------------- +void CMacroTable::writeHeader(FILE *f) +{ +#if defined(WIN32) + fprintf(f, "\xEF\xBB\xBF;DO NOT DELETE THIS LINE*** version=%d ***\n", UKMACRO_VERSION_UTF8); +#else + fprintf(f, "DO NOT DELETE THIS LINE*** version=%d ***\n", UKMACRO_VERSION_UTF8); +#endif +} +//--------------------------------------------------------------- +int CMacroTable::loadFromFile(const char *fname) +{ + FILE *f; +#if defined(WIN32) + f = _tfopen(fname, _TEXT("rt")); +#else + f = fopen(fname, "r"); +#endif + + if (f == NULL) + return 0; + char line[MAX_MACRO_LINE]; + size_t len; + + resetContent(); + + //read possible header + int version; + if (!readHeader(f, version)) { + version = 0; + } + + while (fgets(line, sizeof(line), f)) { + len = strlen(line); + if (len > 0 && line[len-1] == '\n') + line[len-1] = 0; + if (len > 1 && line[len-2] == '\r') + line[len-2] = 0; + if (version == UKMACRO_VERSION_UTF8) + addItem(line, CONV_CHARSET_UNIUTF8); + else + addItem(line, CONV_CHARSET_VIQR); + } + fclose(f); + MacCompareStartMem = m_macroMem; + qsort(m_table, m_count, sizeof(MacroDef), macCompare); + // Convert old version + if (version != UKMACRO_VERSION_UTF8) { + writeToFile(fname); + } + return 1; +} + +//--------------------------------------------------------------- +int CMacroTable::writeToFile(const char *fname) +{ + int ret; + int inLen, maxOutLen; + FILE *f; +#if defined(WIN32) + f = _tfopen(fname, _TEXT("wt")); +#else + f = fopen(fname, "w"); +#endif + + if (f == NULL) + return 0; + + char line[MAX_MACRO_LINE*3]; //1 VnChar may need 3 chars in UTF8 + char key[MAX_MACRO_KEY_LEN*3]; + char text[MAX_MACRO_TEXT_LEN*3]; + + writeHeader(f); + + UKBYTE *p; + for (int i=0; i < m_count; i++) { + p = (UKBYTE *)m_macroMem + m_table[i].keyOffset; + inLen = -1; + maxOutLen = sizeof(key); + ret = VnConvert(CONV_CHARSET_VNSTANDARD, CONV_CHARSET_UNIUTF8, + (UKBYTE *) p, (UKBYTE *)key, + &inLen, &maxOutLen); + if (ret != 0) + continue; + + p = (UKBYTE *)m_macroMem + m_table[i].textOffset; + inLen = -1; + maxOutLen = sizeof(text); + ret = VnConvert(CONV_CHARSET_VNSTANDARD, CONV_CHARSET_UNIUTF8, + p, (UKBYTE *)text, + &inLen, &maxOutLen); + if (ret != 0) + continue; + if (i < m_count-1) + sprintf(line, "%s:%s\n", key, text); + else + sprintf(line, "%s:%s", key, text); + fputs(line, f); + } + + fclose(f); + return 1; +} + +//--------------------------------------------------------------- +int CMacroTable::addItem(const void *key, const void *text, int charset) +{ + int ret; + int inLen, maxOutLen; + int offset = m_occupied; + char *p = m_macroMem + offset; + + if (m_count >= MAX_MACRO_ITEMS) + return -1; + + m_table[m_count].keyOffset = offset; + + // Convert macro key to VN standard + inLen = -1; //input is null-terminated + maxOutLen = MAX_MACRO_KEY_LEN * sizeof(StdVnChar); + if (maxOutLen + offset > m_memSize) + maxOutLen = m_memSize - offset; + ret = VnConvert(charset, CONV_CHARSET_VNSTANDARD, + (UKBYTE *)key, (UKBYTE *)p, + &inLen, &maxOutLen); + if (ret != 0) + return -1; + + offset += maxOutLen; + p += maxOutLen; + + //convert macro text to VN standard + m_table[m_count].textOffset = offset; + inLen = -1; //input is null-terminated + maxOutLen = MAX_MACRO_TEXT_LEN * sizeof(StdVnChar); + if (maxOutLen + offset > m_memSize) + maxOutLen = m_memSize - offset; + ret = VnConvert(charset, CONV_CHARSET_VNSTANDARD, + (UKBYTE *)text, (UKBYTE *)p, + &inLen, &maxOutLen); + if (ret != 0) + return -1; + + m_occupied = offset + maxOutLen; + m_count++; + return (m_count-1); +} + +//--------------------------------------------------------------- +// add a new macro into the sorted macro table +// item format: key:text (key and text are separated by a colon) +//--------------------------------------------------------------- +int CMacroTable::addItem(const char *item, int charset) +{ + char key[MAX_MACRO_KEY_LEN]; + + // Parse the input item + char * pos = (char*)strchr(item, ':'); + if (pos == NULL) + return -1; + int keyLen = (int)(pos - item); + if (keyLen > MAX_MACRO_KEY_LEN-1) + keyLen = MAX_MACRO_KEY_LEN-1; + strncpy(key, item, keyLen); + key[keyLen] = '\0'; + return addItem(key, ++pos, charset); +} + +//--------------------------------------------------------------- +void CMacroTable::resetContent() +{ + m_occupied = 0; + m_count = 0; +} + +//--------------------------------------------------------------- +const StdVnChar *CMacroTable::getKey(int idx) +{ + if (idx < 0 || idx >= m_count) + return 0; + return (StdVnChar *)(m_macroMem + m_table[idx].keyOffset); +} + +//--------------------------------------------------------------- +const StdVnChar *CMacroTable::getText(int idx) +{ + if (idx < 0 || idx >= m_count) + return 0; + return (StdVnChar *)(m_macroMem + m_table[idx].textOffset); +} diff --git a/unikey/mactab.h b/unikey/mactab.h new file mode 100644 index 0000000..c38965f --- /dev/null +++ b/unikey/mactab.h @@ -0,0 +1,78 @@ +// -*- coding:unix; mode:c++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- +/* Unikey Vietnamese Input Method + * Copyright (C) 2000-2005 Pham Kim Long + * Contact: + * unikey@gmail.com + * UniKey project: http://unikey.org + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __MACRO_TABLE_H +#define __MACRO_TABLE_H + +#include "keycons.h" +#include "charset.h" + +#if defined(_WIN32) + #if defined(UNIKEYHOOK) + #define DllInterface __declspec( dllexport ) + #else + #define DllInterface __declspec( dllimport ) + #endif +#else + #define DllInterface //not used + #define DllExport + #define DllImport +#endif + +struct MacroDef +{ + int keyOffset; + int textOffset; +}; + +#if !defined(WIN32) +typedef char TCHAR; +#endif + +class DllInterface CMacroTable +{ +public: + void init(); + int loadFromFile(const char *fname); + int writeToFile(const char *fname); + + const StdVnChar *lookup(StdVnChar *key); + const StdVnChar *getKey(int idx); + const StdVnChar *getText(int idx); + int getCount() { return m_count; } + void resetContent(); + int addItem(const char *item, int charset); + int addItem(const void *key, const void *text, int charset); + +protected: + bool readHeader(FILE *f, int & version); + void writeHeader(FILE *f); + + MacroDef m_table[MAX_MACRO_ITEMS]; + char m_macroMem[MACRO_MEM_SIZE]; + + int m_count; + int m_memSize, m_occupied; +}; + +#endif diff --git a/unikey/pattern.cpp b/unikey/pattern.cpp new file mode 100644 index 0000000..7e1f43b --- /dev/null +++ b/unikey/pattern.cpp @@ -0,0 +1,100 @@ +// -*- coding:unix; mode:c++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- +/*------------------------------------------------------------------------------ +VnConv: Vietnamese Encoding Converter Library +UniKey Project: http://unikey.sourceforge.net +Copyleft (C) 1998-2002 Pham Kim Long +Contact: longp@cslab.felk.cvut.cz + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +--------------------------------------------------------------------------------*/ + +#include "pattern.h" + +////////////////////////////////////////////////// +// Pattern matching (based on KPM algorithm) +////////////////////////////////////////////////// + +//---------------------------- +void PatternState::reset() +{ + m_pos = 0; + m_found = 0; +} + +//---------------------------- +void PatternState::init(char *pattern) +{ + m_pos = 0; + m_found = 0; + m_pattern = pattern; + + int i=0, j=-1; + m_border[i]=j; + while (m_pattern[i]) + { + while (j>=0 && m_pattern[i]!=m_pattern[j]) j=m_border[j]; + i++; j++; + m_border[i]=j; + } +} + +//----------------------------------------------------- +//get next input char, returns 1 if pattern is found. +//----------------------------------------------------- +int PatternState::foundAtNextChar(char ch) +{ + int ret = 0; + //int j = m_pos; + while (m_pos>=0 && ch!=m_pattern[m_pos]) m_pos=m_border[m_pos]; + m_pos++; + if (m_pattern[m_pos]==0) { + m_found++; + m_pos = m_border[m_pos]; + ret = 1; + } + return ret; +} + +//----------------------------------------------------- +void PatternList::init(char **patterns, int count) +{ + m_count = count; + delete [] m_patterns; + m_patterns = new PatternState[count]; + for (int i=0; i +#include +#include +#include "keycons.h" + +/* +#if defined(_WIN32) +#include "keyhook.h" +#endif +*/ + +#include "vnlexi.h" +#include "ukengine.h" + +#include "charset.h" + +using namespace std; + +#define ENTER_CHAR 13 +#define IS_ODD(x) (x & 1) +#define IS_EVEN(x) (!(x & 1)) + +#define IS_STD_VN_LOWER(x) ((x) >= VnStdCharOffset && (x) < (VnStdCharOffset + TOTAL_ALPHA_VNCHARS) && IS_ODD(x)) +#define IS_STD_VN_UPPER(x) ((x) >= VnStdCharOffset && (x) < (VnStdCharOffset + TOTAL_ALPHA_VNCHARS) && IS_EVEN(x)) + +bool IsVnVowel[vnl_lastChar]; + +extern VnLexiName AZLexiUpper[]; //defined in inputproc.cpp +extern VnLexiName AZLexiLower[]; + +//see vnconv/data.cpp for explanation of these characters +unsigned char SpecialWesternChars[] = { + 0x80, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, + 0x89, 0x8A, 0x8B, 0x8C, 0x8E, 0x91, 0x92, 0x93, + 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, + 0x9C, 0x9E, 0x9F, 0x00}; + +StdVnChar IsoStdVnCharMap[256]; + +inline StdVnChar IsoToStdVnChar(int keyCode) +{ + return (keyCode < 256)? IsoStdVnCharMap[keyCode] : keyCode; +} + +struct VowelSeqInfo { + int len; + int complete; + int conSuffix; //allow consonnant suffix + VnLexiName v[3]; + VowelSeq sub[3]; + + int roofPos; + VowelSeq withRoof; + + int hookPos; + VowelSeq withHook; //hook & bowl +}; + +VowelSeqInfo VSeqList[] = { + {1, 1, 1, {vnl_a, vnl_nonVnChar, vnl_nonVnChar}, {vs_a, vs_nil, vs_nil}, -1, vs_ar, -1, vs_ab}, + {1, 1, 1, {vnl_ar, vnl_nonVnChar, vnl_nonVnChar}, {vs_ar, vs_nil, vs_nil}, 0, vs_nil, -1, vs_ab}, + {1, 1, 1, {vnl_ab, vnl_nonVnChar, vnl_nonVnChar}, {vs_ab, vs_nil, vs_nil}, -1, vs_ar, 0, vs_nil}, + {1, 1, 1, {vnl_e, vnl_nonVnChar, vnl_nonVnChar}, {vs_e, vs_nil, vs_nil}, -1, vs_er, -1, vs_nil}, + {1, 1, 1, {vnl_er, vnl_nonVnChar, vnl_nonVnChar}, {vs_er, vs_nil, vs_nil}, 0, vs_nil, -1, vs_nil}, + {1, 1, 1, {vnl_i, vnl_nonVnChar, vnl_nonVnChar}, {vs_i, vs_nil, vs_nil}, -1, vs_nil, -1, vs_nil}, + {1, 1, 1, {vnl_o, vnl_nonVnChar, vnl_nonVnChar}, {vs_o, vs_nil, vs_nil}, -1, vs_or, -1, vs_oh}, + {1, 1, 1, {vnl_or, vnl_nonVnChar, vnl_nonVnChar}, {vs_or, vs_nil, vs_nil}, 0, vs_nil, -1, vs_oh}, + {1, 1, 1, {vnl_oh, vnl_nonVnChar, vnl_nonVnChar}, {vs_oh, vs_nil, vs_nil}, -1, vs_or, 0, vs_nil}, + {1, 1, 1, {vnl_u, vnl_nonVnChar, vnl_nonVnChar}, {vs_u, vs_nil, vs_nil}, -1, vs_nil, -1, vs_uh}, + {1, 1, 1, {vnl_uh, vnl_nonVnChar, vnl_nonVnChar}, {vs_uh, vs_nil, vs_nil}, -1, vs_nil, 0, vs_nil}, + {1, 1, 1, {vnl_y, vnl_nonVnChar, vnl_nonVnChar}, {vs_y, vs_nil, vs_nil}, -1, vs_nil, -1, vs_nil}, + {2, 1, 0, {vnl_a, vnl_i, vnl_nonVnChar}, {vs_a, vs_ai, vs_nil}, -1, vs_nil, -1, vs_nil}, + {2, 1, 0, {vnl_a, vnl_o, vnl_nonVnChar}, {vs_a, vs_ao, vs_nil}, -1, vs_nil, -1, vs_nil}, + {2, 1, 0, {vnl_a, vnl_u, vnl_nonVnChar}, {vs_a, vs_au, vs_nil}, -1, vs_aru, -1, vs_nil}, + {2, 1, 0, {vnl_a, vnl_y, vnl_nonVnChar}, {vs_a, vs_ay, vs_nil}, -1, vs_ary, -1, vs_nil}, + {2, 1, 0, {vnl_ar, vnl_u, vnl_nonVnChar}, {vs_ar, vs_aru, vs_nil}, 0, vs_nil, -1, vs_nil}, + {2, 1, 0, {vnl_ar, vnl_y, vnl_nonVnChar}, {vs_ar, vs_ary, vs_nil}, 0, vs_nil, -1, vs_nil}, + {2, 1, 0, {vnl_e, vnl_o, vnl_nonVnChar}, {vs_e, vs_eo, vs_nil}, -1, vs_nil, -1, vs_nil}, + {2, 0, 0, {vnl_e, vnl_u, vnl_nonVnChar}, {vs_e, vs_eu, vs_nil}, -1, vs_eru, -1, vs_nil}, + {2, 1, 0, {vnl_er, vnl_u, vnl_nonVnChar}, {vs_er, vs_eru, vs_nil}, 0, vs_nil, -1, vs_nil}, + {2, 1, 0, {vnl_i, vnl_a, vnl_nonVnChar}, {vs_i, vs_ia, vs_nil}, -1, vs_nil, -1, vs_nil}, + {2, 0, 1, {vnl_i, vnl_e, vnl_nonVnChar}, {vs_i, vs_ie, vs_nil}, -1, vs_ier, -1, vs_nil}, + {2, 1, 1, {vnl_i, vnl_er, vnl_nonVnChar}, {vs_i, vs_ier, vs_nil}, 1, vs_nil, -1, vs_nil}, + {2, 1, 0, {vnl_i, vnl_u, vnl_nonVnChar}, {vs_i, vs_iu, vs_nil}, -1, vs_nil, -1, vs_nil}, + {2, 1, 1, {vnl_o, vnl_a, vnl_nonVnChar}, {vs_o, vs_oa, vs_nil}, -1, vs_nil, -1, vs_oab}, + {2, 1, 1, {vnl_o, vnl_ab, vnl_nonVnChar}, {vs_o, vs_oab, vs_nil}, -1, vs_nil, 1, vs_nil}, + {2, 1, 1, {vnl_o, vnl_e, vnl_nonVnChar}, {vs_o, vs_oe, vs_nil}, -1, vs_nil, -1, vs_nil}, + {2, 1, 0, {vnl_o, vnl_i, vnl_nonVnChar}, {vs_o, vs_oi, vs_nil}, -1, vs_ori, -1, vs_ohi}, + {2, 1, 0, {vnl_or, vnl_i, vnl_nonVnChar}, {vs_or, vs_ori, vs_nil}, 0, vs_nil, -1, vs_ohi}, + {2, 1, 0, {vnl_oh, vnl_i, vnl_nonVnChar}, {vs_oh, vs_ohi, vs_nil}, -1, vs_ori, 0, vs_nil}, + {2, 1, 1, {vnl_u, vnl_a, vnl_nonVnChar}, {vs_u, vs_ua, vs_nil}, -1, vs_uar, -1, vs_uha}, + {2, 1, 1, {vnl_u, vnl_ar, vnl_nonVnChar}, {vs_u, vs_uar, vs_nil}, 1, vs_nil, -1, vs_nil}, + {2, 0, 1, {vnl_u, vnl_e, vnl_nonVnChar}, {vs_u, vs_ue, vs_nil}, -1, vs_uer, -1, vs_nil}, + {2, 1, 1, {vnl_u, vnl_er, vnl_nonVnChar}, {vs_u, vs_uer, vs_nil}, 1, vs_nil, -1, vs_nil}, + {2, 1, 0, {vnl_u, vnl_i, vnl_nonVnChar}, {vs_u, vs_ui, vs_nil}, -1, vs_nil, -1, vs_uhi}, + {2, 0, 1, {vnl_u, vnl_o, vnl_nonVnChar}, {vs_u, vs_uo, vs_nil}, -1, vs_uor, -1, vs_uho}, + {2, 1, 1, {vnl_u, vnl_or, vnl_nonVnChar}, {vs_u, vs_uor, vs_nil}, 1, vs_nil, -1, vs_uoh}, + {2, 1, 1, {vnl_u, vnl_oh, vnl_nonVnChar}, {vs_u, vs_uoh, vs_nil}, -1, vs_uor, 1, vs_uhoh}, + {2, 0, 0, {vnl_u, vnl_u, vnl_nonVnChar}, {vs_u, vs_uu, vs_nil}, -1, vs_nil, -1, vs_uhu}, + {2, 1, 1, {vnl_u, vnl_y, vnl_nonVnChar}, {vs_u, vs_uy, vs_nil}, -1, vs_nil, -1, vs_nil}, + {2, 1, 0, {vnl_uh, vnl_a, vnl_nonVnChar}, {vs_uh, vs_uha, vs_nil}, -1, vs_nil, 0, vs_nil}, + {2, 1, 0, {vnl_uh, vnl_i, vnl_nonVnChar}, {vs_uh, vs_uhi, vs_nil}, -1, vs_nil, 0, vs_nil}, + {2, 0, 1, {vnl_uh, vnl_o, vnl_nonVnChar}, {vs_uh, vs_uho, vs_nil}, -1, vs_nil, 0, vs_uhoh}, + {2, 1, 1, {vnl_uh, vnl_oh, vnl_nonVnChar}, {vs_uh, vs_uhoh, vs_nil}, -1, vs_nil, 0, vs_nil}, + {2, 1, 0, {vnl_uh, vnl_u, vnl_nonVnChar}, {vs_uh, vs_uhu, vs_nil}, -1, vs_nil, 0, vs_nil}, + {2, 0, 1, {vnl_y, vnl_e, vnl_nonVnChar}, {vs_y, vs_ye, vs_nil}, -1, vs_yer, -1, vs_nil}, + {2, 1, 1, {vnl_y, vnl_er, vnl_nonVnChar}, {vs_y, vs_yer, vs_nil}, 1, vs_nil, -1, vs_nil}, + {3, 0, 0, {vnl_i, vnl_e, vnl_u}, {vs_i, vs_ie, vs_ieu}, -1, vs_ieru, -1, vs_nil}, + {3, 1, 0, {vnl_i, vnl_er, vnl_u}, {vs_i, vs_ier, vs_ieru}, 1, vs_nil, -1, vs_nil}, + {3, 1, 0, {vnl_o, vnl_a, vnl_i}, {vs_o, vs_oa, vs_oai}, -1, vs_nil, -1, vs_nil}, + {3, 1, 0, {vnl_o, vnl_a, vnl_y}, {vs_o, vs_oa, vs_oay}, -1, vs_nil, -1, vs_nil}, + {3, 1, 0, {vnl_o, vnl_e, vnl_o}, {vs_o, vs_oe, vs_oeo}, -1, vs_nil, -1, vs_nil}, + {3, 0, 0, {vnl_u, vnl_a, vnl_y}, {vs_u, vs_ua, vs_uay}, -1, vs_uary, -1, vs_nil}, + {3, 1, 0, {vnl_u, vnl_ar, vnl_y}, {vs_u, vs_uar, vs_uary}, 1, vs_nil, -1, vs_nil}, + {3, 0, 0, {vnl_u, vnl_o, vnl_i}, {vs_u, vs_uo, vs_uoi}, -1, vs_uori, -1, vs_uhoi}, + {3, 0, 0, {vnl_u, vnl_o, vnl_u}, {vs_u, vs_uo, vs_uou}, -1, vs_nil, -1, vs_uhou}, + {3, 1, 0, {vnl_u, vnl_or, vnl_i}, {vs_u, vs_uor, vs_uori}, 1, vs_nil, -1, vs_uohi}, + {3, 0, 0, {vnl_u, vnl_oh, vnl_i}, {vs_u, vs_uoh, vs_uohi}, -1, vs_uori, 1, vs_uhohi}, + {3, 0, 0, {vnl_u, vnl_oh, vnl_u}, {vs_u, vs_uoh, vs_uohu}, -1, vs_nil, 1, vs_uhohu}, + {3, 1, 0, {vnl_u, vnl_y, vnl_a}, {vs_u, vs_uy, vs_uya}, -1, vs_nil, -1, vs_nil}, + {3, 0, 1, {vnl_u, vnl_y, vnl_e}, {vs_u, vs_uy, vs_uye}, -1, vs_uyer, -1, vs_nil}, + {3, 1, 1, {vnl_u, vnl_y, vnl_er}, {vs_u, vs_uy, vs_uyer}, 2, vs_nil, -1, vs_nil}, + {3, 1, 0, {vnl_u, vnl_y, vnl_u}, {vs_u, vs_uy, vs_uyu}, -1, vs_nil, -1, vs_nil}, + {3, 0, 0, {vnl_uh, vnl_o, vnl_i}, {vs_uh, vs_uho, vs_uhoi}, -1, vs_nil, 0, vs_uhohi}, + {3, 0, 0, {vnl_uh, vnl_o, vnl_u}, {vs_uh, vs_uho, vs_uhou}, -1, vs_nil, 0, vs_uhohu}, + {3, 1, 0, {vnl_uh, vnl_oh, vnl_i}, {vs_uh, vs_uhoh, vs_uhohi}, -1, vs_nil, 0, vs_nil}, + {3, 1, 0, {vnl_uh, vnl_oh, vnl_u}, {vs_uh, vs_uhoh, vs_uhohu}, -1, vs_nil, 0, vs_nil}, + {3, 0, 0, {vnl_y, vnl_e, vnl_u}, {vs_y, vs_ye, vs_yeu}, -1, vs_yeru, -1, vs_nil}, + {3, 1, 0, {vnl_y, vnl_er, vnl_u}, {vs_y, vs_yer, vs_yeru}, 1, vs_nil, -1, vs_nil} +}; + +struct ConSeqInfo { + int len; + VnLexiName c[3]; + bool suffix; +}; + +ConSeqInfo CSeqList[] = { + {1, {vnl_b, vnl_nonVnChar, vnl_nonVnChar}, false}, + {1, {vnl_c, vnl_nonVnChar, vnl_nonVnChar}, true}, + {2, {vnl_c, vnl_h, vnl_nonVnChar}, true}, + {1, {vnl_d, vnl_nonVnChar, vnl_nonVnChar}, false}, + {1, {vnl_dd, vnl_nonVnChar, vnl_nonVnChar}, false}, + {2, {vnl_d, vnl_z, vnl_nonVnChar}, false}, + {1, {vnl_g, vnl_nonVnChar, vnl_nonVnChar}, false}, + {2, {vnl_g, vnl_h, vnl_nonVnChar}, false}, + {2, {vnl_g, vnl_i, vnl_nonVnChar}, false}, + {3, {vnl_g, vnl_i, vnl_n}, false}, + {1, {vnl_h, vnl_nonVnChar, vnl_nonVnChar}, false}, + {1, {vnl_k, vnl_nonVnChar, vnl_nonVnChar}, false}, + {2, {vnl_k, vnl_h, vnl_nonVnChar}, false}, + {1, {vnl_l, vnl_nonVnChar, vnl_nonVnChar}, false}, + {1, {vnl_m, vnl_nonVnChar, vnl_nonVnChar}, true}, + {1, {vnl_n, vnl_nonVnChar, vnl_nonVnChar}, true}, + {2, {vnl_n, vnl_g, vnl_nonVnChar}, true}, + {3, {vnl_n, vnl_g, vnl_h}, false}, + {2, {vnl_n, vnl_h, vnl_nonVnChar}, true}, + {1, {vnl_p, vnl_nonVnChar, vnl_nonVnChar}, true}, + {2, {vnl_p, vnl_h, vnl_nonVnChar}, false}, + {1, {vnl_q, vnl_nonVnChar, vnl_nonVnChar}, false}, + {2, {vnl_q, vnl_u, vnl_nonVnChar}, false}, + {1, {vnl_r, vnl_nonVnChar, vnl_nonVnChar}, false}, + {1, {vnl_s, vnl_nonVnChar, vnl_nonVnChar}, false}, + {1, {vnl_t, vnl_nonVnChar, vnl_nonVnChar}, true}, + {2, {vnl_t, vnl_h, vnl_nonVnChar}, false}, + {2, {vnl_t, vnl_r, vnl_nonVnChar}, false}, + {1, {vnl_v, vnl_nonVnChar, vnl_nonVnChar}, false}, + {1, {vnl_x, vnl_nonVnChar, vnl_nonVnChar}, false} +}; + +const int VSeqCount = sizeof(VSeqList)/sizeof(VowelSeqInfo); +struct VSeqPair { + VnLexiName v[3]; + VowelSeq vs; +}; +VSeqPair SortedVSeqList[VSeqCount]; + +const int CSeqCount = sizeof(CSeqList)/sizeof(ConSeqInfo); +struct CSeqPair { + VnLexiName c[3]; + ConSeq cs; +}; +CSeqPair SortedCSeqList[CSeqCount]; + +struct VCPair { + VowelSeq v; + ConSeq c; +}; + +VCPair VCPairList [] = { + {vs_a, cs_c}, {vs_a, cs_ch}, {vs_a, cs_m}, {vs_a, cs_n}, {vs_a, cs_ng}, + {vs_a, cs_nh}, {vs_a, cs_p}, {vs_a, cs_t}, + {vs_ar, cs_c}, {vs_ar, cs_m}, {vs_ar, cs_n}, {vs_ar, cs_ng}, {vs_ar, cs_p}, {vs_ar, cs_t}, + {vs_ab, cs_c}, {vs_ab, cs_m}, {vs_ab, cs_n}, {vs_ab, cs_ng}, {vs_ab, cs_p}, {vs_ab, cs_t}, + + {vs_e, cs_c}, {vs_e, cs_ch}, {vs_e, cs_m}, {vs_e, cs_n}, {vs_e, cs_ng}, + {vs_e, cs_nh}, {vs_e, cs_p}, {vs_e, cs_t}, + {vs_er, cs_c}, {vs_er, cs_ch}, {vs_er, cs_m}, {vs_er, cs_n}, {vs_er, cs_nh}, + {vs_er, cs_p}, {vs_er, cs_t}, + + {vs_i, cs_c}, {vs_i, cs_ch}, {vs_i, cs_m}, {vs_i, cs_n}, {vs_i, cs_nh}, {vs_i, cs_p}, {vs_i, cs_t}, + + {vs_o, cs_c}, {vs_o, cs_m}, {vs_o, cs_n}, {vs_o, cs_ng}, {vs_o, cs_p}, {vs_o, cs_t}, + {vs_or, cs_c}, {vs_or, cs_m}, {vs_or, cs_n}, {vs_or, cs_ng}, {vs_or, cs_p}, {vs_or, cs_t}, + {vs_oh, cs_m}, {vs_oh, cs_n}, {vs_oh, cs_p}, {vs_oh, cs_t}, + + {vs_u, cs_c}, {vs_u, cs_m}, {vs_u, cs_n}, {vs_u, cs_ng}, {vs_u, cs_p}, {vs_u, cs_t}, + {vs_uh, cs_c}, {vs_uh, cs_m}, {vs_uh, cs_n}, {vs_uh, cs_ng}, {vs_uh, cs_t}, + + {vs_y, cs_t}, + {vs_ie, cs_c}, {vs_ie, cs_m}, {vs_ie, cs_n}, {vs_ie, cs_ng}, {vs_ie, cs_p}, {vs_ie, cs_t}, + {vs_ier, cs_c}, {vs_ier, cs_m}, {vs_ier, cs_n}, {vs_ier, cs_ng}, {vs_ier, cs_p}, {vs_ier, cs_t}, + + {vs_oa, cs_c}, {vs_oa, cs_ch}, {vs_oa, cs_m}, {vs_oa, cs_n}, {vs_oa, cs_ng}, + {vs_oa, cs_nh}, {vs_oa, cs_p}, {vs_oa, cs_t}, + {vs_oab, cs_c}, {vs_oab, cs_m}, {vs_oab, cs_n}, {vs_oab, cs_ng}, {vs_oab, cs_t}, + + {vs_oe, cs_n}, {vs_oe, cs_t}, + + {vs_ua, cs_n}, {vs_ua, cs_ng}, {vs_ua, cs_t}, + {vs_uar, cs_n}, {vs_uar, cs_ng}, {vs_uar, cs_t}, + + {vs_ue, cs_c}, {vs_ue, cs_ch}, {vs_ue, cs_n}, {vs_ue, cs_nh}, + {vs_uer, cs_c}, {vs_uer, cs_ch}, {vs_uer, cs_n}, {vs_uer, cs_nh}, + + {vs_uo, cs_c}, {vs_uo, cs_m}, {vs_uo, cs_n}, {vs_uo, cs_ng}, {vs_uo, cs_p}, {vs_uo, cs_t}, + {vs_uor, cs_c}, {vs_uor, cs_m}, {vs_uor, cs_n}, {vs_uor, cs_ng}, {vs_uor, cs_t}, + {vs_uho, cs_c}, {vs_uho, cs_m}, {vs_uho, cs_n}, {vs_uho, cs_ng}, {vs_uho, cs_p}, {vs_uho, cs_t}, + {vs_uhoh, cs_c}, {vs_uhoh, cs_m}, {vs_uhoh, cs_n}, {vs_uhoh, cs_ng}, {vs_uhoh, cs_p}, {vs_uhoh, cs_t}, + + {vs_uy, cs_c}, {vs_uy, cs_ch}, {vs_uy, cs_n}, {vs_uy, cs_nh}, {vs_uy, cs_p}, {vs_uy, cs_t}, + + {vs_ye, cs_m}, {vs_ye, cs_n}, {vs_ye, cs_ng}, {vs_ye, cs_p}, {vs_ye, cs_t}, + {vs_yer, cs_m}, {vs_yer, cs_n}, {vs_yer, cs_ng}, {vs_yer, cs_t}, + + {vs_uye, cs_n}, {vs_uye, cs_t}, + {vs_uyer, cs_n}, {vs_uyer, cs_t} + +}; + +const int VCPairCount = sizeof(VCPairList)/sizeof(VCPair); + +//TODO: auto-complete: e.g. luan -> lua^n + +typedef int (UkEngine::* UkKeyProc)(UkKeyEvent & ev); + +UkKeyProc UkKeyProcList[vneCount] = { + &UkEngine::processRoof, //vneRoofAll + &UkEngine::processRoof, //vneRoof_a + &UkEngine::processRoof, //vneRoof_e + &UkEngine::processRoof, //vneRoof_o + &UkEngine::processHook, //vneHookAll + &UkEngine::processHook, //vneHook_uo + &UkEngine::processHook, //vneHook_u + &UkEngine::processHook, //vneHook_o + &UkEngine::processHook, //vneBowl + &UkEngine::processDd, //vneDd + &UkEngine::processTone, //vneTone0 + &UkEngine::processTone, //vneTone1 + &UkEngine::processTone, //vneTone2 + &UkEngine::processTone, //vneTone3 + &UkEngine::processTone, //vneTone4 + &UkEngine::processTone, //vneTone5 + &UkEngine::processTelexW, //vne_telex_w + &UkEngine::processMapChar, //vneMapChar + &UkEngine::processEscChar, //vneEscChar + &UkEngine::processAppend //vneNormal +}; + + +VowelSeq lookupVSeq(VnLexiName v1, VnLexiName v2 = vnl_nonVnChar, VnLexiName v3 = vnl_nonVnChar); +ConSeq lookupCSeq(VnLexiName c1, VnLexiName c2 = vnl_nonVnChar, VnLexiName c3 = vnl_nonVnChar); + +bool UkEngine::m_classInit = false; + +//------------------------------------------------ +int tripleVowelCompare(const void *p1, const void *p2) +{ + VSeqPair *t1 = (VSeqPair *)p1; + VSeqPair *t2 = (VSeqPair *)p2; + + for (int i=0; i<3; i++) { + if (t1->v[i] < t2->v[i]) + return -1; + if (t1->v[i] > t2->v[i]) + return 1; + } + return 0; +} + +//------------------------------------------------ +int tripleConCompare(const void *p1, const void *p2) +{ + CSeqPair *t1 = (CSeqPair *)p1; + CSeqPair *t2 = (CSeqPair *)p2; + + for (int i=0; i<3; i++) { + if (t1->c[i] < t2->c[i]) + return -1; + if (t1->c[i] > t2->c[i]) + return 1; + } + return 0; +} + +//------------------------------------------------ +int VCPairCompare(const void *p1, const void *p2) +{ + VCPair *t1 = (VCPair *)p1; + VCPair *t2 = (VCPair *)p2; + + if (t1->v < t2->v) + return -1; + if (t1->v > t2->v) + return 1; + + if (t1->c < t2->c) + return -1; + if (t1->c > t2->c) + return 1; + return 0; +} + +//---------------------------------------------------------- +bool isValidCV(ConSeq c, VowelSeq v) +{ + if (c == cs_nil || v == vs_nil) + return true; + + VowelSeqInfo & vInfo = VSeqList[v]; + + if ((c == cs_gi && vInfo.v[0] == vnl_i) || + (c == cs_qu && vInfo.v[0] == vnl_u)) + return false; // gi doesn't go with i, qu doesn't go with u + + if (c == cs_k) { + // k can only go with the following vowel sequences + static VowelSeq kVseq[] = {vs_e, vs_i, vs_y, vs_er, vs_eo, vs_eu, + vs_eru, vs_ia, vs_ie, vs_ier, vs_ieu, vs_ieru, vs_nil}; + int i; + for (i=0; kVseq[i] != vs_nil && kVseq[i] != v; i++); + return (kVseq[i] != vs_nil); + } + + //More checks + return true; +} + +//---------------------------------------------------------- +bool isValidVC(VowelSeq v, ConSeq c) +{ + if (v == vs_nil || c == cs_nil) + return true; + + VowelSeqInfo & vInfo = VSeqList[v]; + if (!vInfo.conSuffix) + return false; + + ConSeqInfo & cInfo = CSeqList[c]; + if (!cInfo.suffix) + return false; + + VCPair p; + p.v = v; + p.c = c; + if (bsearch(&p, VCPairList, VCPairCount, sizeof(VCPair), VCPairCompare)) + return true; + + return false; +} + +//---------------------------------------------------------- +bool isValidCVC(ConSeq c1, VowelSeq v, ConSeq c2) +{ + if (v == vs_nil) + return (c1 == cs_nil || c2 != cs_nil); + + if (c1 == cs_nil) + return isValidVC(v, c2); + + if (c2 == cs_nil) + return isValidCV(c1, v); + + bool okCV = isValidCV(c1, v); + bool okVC = isValidVC(v, c2); + + if (okCV && okVC) + return true; + + if (!okVC) { + //check some exceptions: vc fails but cvc passes + + // quyn, quynh + if (c1 == cs_qu && v == vs_y && (c2 == cs_n || c2 == cs_nh)) + return true; + + // gieng, gie^ng + if (c1 == cs_gi && (v == vs_e || v == vs_er) && (c2 == cs_n || c2 == cs_ng)) + return true; + } + return false; +} + +//------------------------------------------------ +void engineClassInit() +{ + int i, j; + + for (i=0; i < VSeqCount; i++) { + for (j=0; j<3; j++) + SortedVSeqList[i].v[j] = VSeqList[i].v[j]; + SortedVSeqList[i].vs = (VowelSeq)i; + } + + for (i=0; i < CSeqCount; i++) { + for (j=0; j<3; j++) + SortedCSeqList[i].c[j] = CSeqList[i].c[j]; + SortedCSeqList[i].cs = (ConSeq)i; + } + + qsort(SortedVSeqList, VSeqCount, sizeof(VSeqPair), tripleVowelCompare); + qsort(SortedCSeqList, CSeqCount, sizeof(CSeqPair), tripleConCompare); + qsort(VCPairList, VCPairCount, sizeof(VCPair), VCPairCompare); + + for (i=0; ivs; +} + +//------------------------------------------------ +ConSeq lookupCSeq(VnLexiName c1, VnLexiName c2, VnLexiName c3) +{ + CSeqPair key; + key.c[0] = c1; + key.c[1] = c2; + key.c[2] = c3; + + CSeqPair *pInfo = (CSeqPair *)bsearch(&key, SortedCSeqList, CSeqCount, sizeof(CSeqPair), tripleConCompare); + if (pInfo == 0) + return cs_nil; + return pInfo->cs; +} + +//------------------------------------------------------------------ +int UkEngine::processRoof(UkKeyEvent & ev) +{ + if (!m_pCtrl->vietKey || m_current < 0 || m_buffer[m_current].vOffset < 0) + return processAppend(ev); + + VnLexiName target; + switch (ev.evType) { + case vneRoof_a: + target = vnl_ar; + break; + case vneRoof_e: + target = vnl_er; + break; + case vneRoof_o: + target = vnl_or; + break; + default: + target = vnl_nonVnChar; + } + + + VowelSeq vs, newVs; + int i, vStart, vEnd; + int curTonePos, newTonePos, tone; + int changePos; + bool roofRemoved = false; + + vEnd = m_current - m_buffer[m_current].vOffset; + vs = m_buffer[vEnd].vseq; + vStart = vEnd - (VSeqList[vs].len - 1); + curTonePos = vStart + getTonePosition(vs, vEnd == m_current); + tone = m_buffer[curTonePos].tone; + + bool doubleChangeUO = false; + if (vs == vs_uho || vs == vs_uhoh || vs == vs_uhoi || vs == vs_uhohi) { + //special cases: u+o+ -> uo^, u+o -> uo^, u+o+i -> uo^i, u+oi -> uo^i + newVs = lookupVSeq(vnl_u, vnl_or, VSeqList[vs].v[2]); + doubleChangeUO = true; + } + else { + newVs = VSeqList[vs].withRoof; + } + + VowelSeqInfo *pInfo; + + if (newVs == vs_nil) { + if (VSeqList[vs].roofPos == -1) + return processAppend(ev); //roof is not applicable + + //a roof already exists -> undo roof + VnLexiName curCh = m_buffer[vStart + VSeqList[vs].roofPos].vnSym; + if (target != vnl_nonVnChar && curCh != target) + return processAppend(ev); //specific roof and the roof character don't match + + VnLexiName newCh = (curCh == vnl_ar)? vnl_a : ((curCh == vnl_er)? vnl_e : vnl_o); + changePos = vStart + VSeqList[vs].roofPos; + + if (!m_pCtrl->options.freeMarking && changePos != m_current) + return processAppend(ev); + + markChange(changePos); + m_buffer[changePos].vnSym = newCh; + + if (VSeqList[vs].len == 3) + newVs = lookupVSeq(m_buffer[vStart].vnSym, m_buffer[vStart+1].vnSym, m_buffer[vStart+2].vnSym); + else if (VSeqList[vs].len == 2) + newVs = lookupVSeq(m_buffer[vStart].vnSym, m_buffer[vStart+1].vnSym); + else + newVs = lookupVSeq(m_buffer[vStart].vnSym); + + pInfo = &VSeqList[newVs]; + roofRemoved = true; + } + else { + pInfo = &VSeqList[newVs]; + if (target != vnl_nonVnChar && pInfo->v[pInfo->roofPos] != target) + return processAppend(ev); + + //check validity of new VC and CV + bool valid = true; + ConSeq c1 = cs_nil; + ConSeq c2 = cs_nil; + if (m_buffer[m_current].c1Offset != -1) + c1 = m_buffer[m_current-m_buffer[m_current].c1Offset].cseq; + + if (m_buffer[m_current].c2Offset != -1) + c2 = m_buffer[m_current-m_buffer[m_current].c2Offset].cseq; + + valid = isValidCVC(c1, newVs, c2); + if (!valid) + return processAppend(ev); + + if (doubleChangeUO) { + changePos = vStart; + } + else { + changePos = vStart + pInfo->roofPos; + } + if (!m_pCtrl->options.freeMarking && changePos != m_current) + return processAppend(ev); + markChange(changePos); + if (doubleChangeUO) { + m_buffer[vStart].vnSym = vnl_u; + m_buffer[vStart+1].vnSym = vnl_or; + } + else { + m_buffer[changePos].vnSym = pInfo->v[pInfo->roofPos]; + } + } + + for (i=0; i < pInfo->len; i++) { //update sub-sequences + m_buffer[vStart+i].vseq = pInfo->sub[i]; + } + + //check if tone re-position is needed + newTonePos = vStart + getTonePosition(newVs, vEnd == m_current); + /* //For now, users don't seem to like the following processing, thus commented out + if (roofRemoved && tone != 0 && + (!pInfo->complete || changePos == curTonePos)) { + //remove tone if the vowel sequence becomes incomplete as a result of roof removal OR + //if removed roof is at the same position as the current tone + markChange(curTonePos); + m_buffer[curTonePos].tone = 0; + } else + */ + if (curTonePos != newTonePos && tone != 0) { + markChange(newTonePos); + m_buffer[newTonePos].tone = tone; + markChange(curTonePos); + m_buffer[curTonePos].tone = 0; + } + + if (roofRemoved) { + m_singleMode = false; + processAppend(ev); + m_reverted = true; + } + + return 1; +} + +//------------------------------------------------------------------ +// can only be called from processHook +//------------------------------------------------------------------ +int UkEngine::processHookWithUO(UkKeyEvent & ev) +{ + VowelSeq vs, newVs; + int i, vStart, vEnd; + int curTonePos, newTonePos, tone; + bool hookRemoved = false; + bool removeWithUndo = true; + bool toneRemoved = false; + + (void)toneRemoved; // fix warning + + VnLexiName *v; + + if (!m_pCtrl->options.freeMarking && m_buffer[m_current].vOffset != 0) + return processAppend(ev); + + vEnd = m_current - m_buffer[m_current].vOffset; + vs = m_buffer[vEnd].vseq; + vStart = vEnd - (VSeqList[vs].len - 1); + v = VSeqList[vs].v; + curTonePos = vStart + getTonePosition(vs, vEnd == m_current); + tone = m_buffer[curTonePos].tone; + + switch (ev.evType) { + case vneHook_u: + if (v[0] == vnl_u) { + newVs = VSeqList[vs].withHook; + markChange(vStart); + m_buffer[vStart].vnSym = vnl_uh; + } + else {// v[0] = vnl_uh, -> uo + newVs = lookupVSeq(vnl_u, vnl_o, v[2]); + markChange(vStart); + m_buffer[vStart].vnSym = vnl_u; + m_buffer[vStart+1].vnSym = vnl_o; + hookRemoved = true; + toneRemoved = (m_buffer[vStart].tone != 0); + } + break; + case vneHook_o: + if (v[1] == vnl_o || v[1] == vnl_or) { + if (vEnd == m_current && VSeqList[vs].len == 2 && + m_buffer[m_current].form == vnw_cv && m_buffer[m_current-2].cseq == cs_th) + { + // o|o^ -> o+ + newVs = VSeqList[vs].withHook; + markChange(vStart+1); + m_buffer[vStart+1].vnSym = vnl_oh; + } + else { + newVs = lookupVSeq(vnl_uh, vnl_oh, v[2]); + if (v[0] == vnl_u) { + markChange(vStart); + m_buffer[vStart].vnSym = vnl_uh; + m_buffer[vStart+1].vnSym = vnl_oh; + } + else { + markChange(vStart+1); + m_buffer[vStart+1].vnSym = vnl_oh; + } + } + } + else {// v[1] = vnl_oh, -> uo + newVs = lookupVSeq(vnl_u, vnl_o, v[2]); + if (v[0] == vnl_uh) { + markChange(vStart); + m_buffer[vStart].vnSym = vnl_u; + m_buffer[vStart+1].vnSym = vnl_o; + } + else { + markChange(vStart+1); + m_buffer[vStart+1].vnSym = vnl_o; + } + hookRemoved = true; + toneRemoved = (m_buffer[vStart+1].tone != 0); + } + break; + default: //vneHookAll, vneHookUO: + if (v[0] == vnl_u) { + if (v[1] == vnl_o || v[1] == vnl_or) { + //uo -> uo+ if prefixed by "th" + if ((vs == vs_uo || vs == vs_uor) && vEnd == m_current && + m_buffer[m_current].form == vnw_cv && m_buffer[m_current-2].cseq == cs_th) + { + newVs = vs_uoh; + markChange(vStart+1); + m_buffer[vStart+1].vnSym = vnl_oh; + } + else { + //uo -> u+o+ + newVs = VSeqList[vs].withHook; + markChange(vStart); + m_buffer[vStart].vnSym = vnl_uh; + newVs = VSeqList[newVs].withHook; + m_buffer[vStart+1].vnSym = vnl_oh; + } + } + else {//uo+ -> u+o+ + newVs = VSeqList[vs].withHook; + markChange(vStart); + m_buffer[vStart].vnSym = vnl_uh; + } + } + else {//v[0] == vnl_uh + if (v[1] == vnl_o) { // u+o -> u+o+ + newVs = VSeqList[vs].withHook; + markChange(vStart+1); + m_buffer[vStart+1].vnSym = vnl_oh; + } + else { //v[1] == vnl_oh, u+o+ -> uo + newVs = lookupVSeq(vnl_u, vnl_o, v[2]); //vs_uo; + markChange(vStart); + m_buffer[vStart].vnSym = vnl_u; + m_buffer[vStart+1].vnSym = vnl_o; + hookRemoved = true; + toneRemoved = (m_buffer[vStart].tone != 0 || m_buffer[vStart+1].tone != 0); + } + } + break; + } + + VowelSeqInfo *p = &VSeqList[newVs]; + for (i=0; i < p->len; i++) { //update sub-sequences + m_buffer[vStart+i].vseq = p->sub[i]; + } + + //check if tone re-position is needed + newTonePos = vStart + getTonePosition(newVs, vEnd == m_current); + /* //For now, users don't seem to like the following processing, thus commented out + if (hookRemoved && tone != 0 && (!p->complete || toneRemoved)) { + //remove tone if the vowel sequence becomes incomplete as a result of hook removal + //OR if a removed hook is at the same position as the current tone + markChange(curTonePos); + m_buffer[curTonePos].tone = 0; + } + else + */ + if (curTonePos != newTonePos && tone != 0) { + markChange(newTonePos); + m_buffer[newTonePos].tone = tone; + markChange(curTonePos); + m_buffer[curTonePos].tone = 0; + } + + if (hookRemoved && removeWithUndo) { + m_singleMode = false; + processAppend(ev); + m_reverted = true; + } + + return 1; +} + +//------------------------------------------------------------------ +int UkEngine::processHook(UkKeyEvent & ev) +{ + if (!m_pCtrl->vietKey || m_current < 0 || m_buffer[m_current].vOffset < 0) + return processAppend(ev); + + VowelSeq vs, newVs; + int i, vStart, vEnd; + int curTonePos, newTonePos, tone; + int changePos; + bool hookRemoved = false; + VowelSeqInfo *pInfo; + VnLexiName *v; + + vEnd = m_current - m_buffer[m_current].vOffset; + vs = m_buffer[vEnd].vseq; + + v = VSeqList[vs].v; + + if (VSeqList[vs].len > 1 && + ev.evType != vneBowl && + (v[0] == vnl_u || v[0] == vnl_uh) && + (v[1] == vnl_o || v[1] == vnl_oh || v[1] == vnl_or)) + return processHookWithUO(ev); + + vStart = vEnd - (VSeqList[vs].len - 1); + curTonePos = vStart + getTonePosition(vs, vEnd == m_current); + tone = m_buffer[curTonePos].tone; + + newVs = VSeqList[vs].withHook; + if (newVs == vs_nil) { + if (VSeqList[vs].hookPos == -1) + return processAppend(ev); //hook is not applicable + + //a hook already exists -> undo hook + VnLexiName curCh = m_buffer[vStart + VSeqList[vs].hookPos].vnSym; + VnLexiName newCh = (curCh == vnl_ab)? vnl_a : ((curCh == vnl_uh)? vnl_u : vnl_o); + changePos = vStart + VSeqList[vs].hookPos; + if (!m_pCtrl->options.freeMarking && changePos != m_current) + return processAppend(ev); + + switch (ev.evType) { + case vneHook_u: + if (curCh != vnl_uh) + return processAppend(ev); + break; + case vneHook_o: + if (curCh != vnl_oh) + return processAppend(ev); + break; + case vneBowl: + if (curCh != vnl_ab) + return processAppend(ev); + break; + default: + if (ev.evType == vneHook_uo && curCh == vnl_ab) + return processAppend(ev); + } + + markChange(changePos); + m_buffer[changePos].vnSym = newCh; + + if (VSeqList[vs].len == 3) + newVs = lookupVSeq(m_buffer[vStart].vnSym, m_buffer[vStart+1].vnSym, m_buffer[vStart+2].vnSym); + else if (VSeqList[vs].len == 2) + newVs = lookupVSeq(m_buffer[vStart].vnSym, m_buffer[vStart+1].vnSym); + else + newVs = lookupVSeq(m_buffer[vStart].vnSym); + + pInfo = &VSeqList[newVs]; + hookRemoved = true; + } + else { + pInfo = &VSeqList[newVs]; + + switch (ev.evType) { + case vneHook_u: + if (pInfo->v[pInfo->hookPos] != vnl_uh) + return processAppend(ev); + break; + case vneHook_o: + if (pInfo->v[pInfo->hookPos] != vnl_oh) + return processAppend(ev); + break; + case vneBowl: + if (pInfo->v[pInfo->hookPos] != vnl_ab) + return processAppend(ev); + break; + default: //vneHook_uo, vneHookAll + if (ev.evType == vneHook_uo && pInfo->v[pInfo->hookPos] == vnl_ab) + return processAppend(ev); + } + + //check validity of new VC and CV + bool valid = true; + ConSeq c1 = cs_nil; + ConSeq c2 = cs_nil; + if (m_buffer[m_current].c1Offset != -1) + c1 = m_buffer[m_current-m_buffer[m_current].c1Offset].cseq; + + if (m_buffer[m_current].c2Offset != -1) + c2 = m_buffer[m_current-m_buffer[m_current].c2Offset].cseq; + + valid = isValidCVC(c1, newVs, c2); + + if (!valid) + return processAppend(ev); + + changePos = vStart + pInfo->hookPos; + if (!m_pCtrl->options.freeMarking && changePos != m_current) + return processAppend(ev); + + markChange(changePos); + m_buffer[changePos].vnSym = pInfo->v[pInfo->hookPos]; + } + + for (i=0; i < pInfo->len; i++) { //update sub-sequences + m_buffer[vStart+i].vseq = pInfo->sub[i]; + } + + //check if tone re-position is needed + newTonePos = vStart + getTonePosition(newVs, vEnd == m_current); + /* //For now, users don't seem to like the following processing, thus commented out + if (hookRemoved && tone != 0 && + (!pInfo->complete || (hookRemoved && curTonePos == changePos))) { + //remove tone if the vowel sequence becomes incomplete as a result of hook removal + //OR if a removed hook was at the same position as the current tone + markChange(curTonePos); + m_buffer[curTonePos].tone = 0; + } + else */ + if (curTonePos != newTonePos && tone != 0) { + markChange(newTonePos); + m_buffer[newTonePos].tone = tone; + markChange(curTonePos); + m_buffer[curTonePos].tone = 0; + } + + if (hookRemoved) { + m_singleMode = false; + processAppend(ev); + m_reverted = true; + } + + return 1; +} + +//---------------------------------------------------------- +int UkEngine::getTonePosition(VowelSeq vs, bool terminated) +{ + VowelSeqInfo & info = VSeqList[vs]; + if (info.len == 1) + return 0; + + if (info.roofPos != -1) + return info.roofPos; + if (info.hookPos != -1) { + if (vs == vs_uhoh || vs == vs_uhohi || vs == vs_uhohu) //u+o+, u+o+u, u+o+i + return 1; + return info.hookPos; + } + + if (info.len == 3) + return 1; + + if (m_pCtrl->options.modernStyle && + (vs == vs_oa || vs == vs_oe ||vs == vs_uy)) + return 1; + + return terminated ? 0 : 1; +} + +//---------------------------------------------------------- +int UkEngine::processTone(UkKeyEvent & ev) +{ + if (m_current < 0 || !m_pCtrl->vietKey) + return processAppend(ev); + + if (m_buffer[m_current].form == vnw_c && + (m_buffer[m_current].cseq == cs_gi || m_buffer[m_current].cseq == cs_gin)) { + int p = (m_buffer[m_current].cseq == cs_gi)? m_current : m_current - 1; + if (m_buffer[p].tone == 0 && ev.tone == 0) + return processAppend(ev); + markChange(p); + if (m_buffer[p].tone == ev.tone) { + m_buffer[p].tone = 0; + m_singleMode = false; + processAppend(ev); + m_reverted = true; + return 1; + } + m_buffer[p].tone = ev.tone; + return 1; + } + + if (m_buffer[m_current].vOffset < 0) + return processAppend(ev); + + int vEnd; + VowelSeq vs; + + vEnd = m_current - m_buffer[m_current].vOffset; + vs = m_buffer[vEnd].vseq; + VowelSeqInfo & info = VSeqList[vs]; + if (m_pCtrl->options.spellCheckEnabled && !m_pCtrl->options.freeMarking && !info.complete) + return processAppend(ev); + + if (m_buffer[m_current].form == vnw_vc || m_buffer[m_current].form == vnw_cvc) { + ConSeq cs = m_buffer[m_current].cseq; + if ((cs == cs_c || cs == cs_ch || cs == cs_p || cs == cs_t) && + (ev.tone == 2 || ev.tone == 3 || ev.tone == 4)) + return processAppend(ev); // c, ch, p, t suffixes don't allow ` ? ~ + } + + int toneOffset = getTonePosition(vs, vEnd == m_current); + int tonePos = vEnd - (info.len -1 ) + toneOffset; + if (m_buffer[tonePos].tone == 0 && ev.tone == 0) + return processAppend(ev); + + if (m_buffer[tonePos].tone == ev.tone) { + markChange(tonePos); + m_buffer[tonePos].tone = 0; + m_singleMode = false; + processAppend(ev); + m_reverted = true; + return 1; + } + + markChange(tonePos); + m_buffer[tonePos].tone = ev.tone; + return 1; +} + +//---------------------------------------------------------- +int UkEngine::processDd(UkKeyEvent & ev) +{ + if (!m_pCtrl->vietKey || m_current < 0) + return processAppend(ev); + + int pos; + + // we want to allow dd even in non-vn sequence, because dd is used a lot in abbreviation + // we allow dd only if preceding character is not a vowel + if (m_buffer[m_current].form == vnw_nonVn && + m_buffer[m_current].vnSym == vnl_d && + (m_buffer[m_current-1].vnSym == vnl_nonVnChar ||!IsVnVowel[m_buffer[m_current-1].vnSym])) + { + m_singleMode = true; + pos = m_current; + markChange(pos); + m_buffer[pos].cseq = cs_dd; + m_buffer[pos].vnSym = vnl_dd; + m_buffer[pos].form = vnw_c; + m_buffer[pos].c1Offset = 0; + m_buffer[pos].c2Offset = -1; + m_buffer[pos].vOffset = -1; + return 1; + } + + if (m_buffer[m_current].c1Offset < 0) { + return processAppend(ev); + } + + pos = m_current - m_buffer[m_current].c1Offset; + if (!m_pCtrl->options.freeMarking && pos != m_current) + return processAppend(ev); + + if (m_buffer[pos].cseq == cs_d) { + markChange(pos); + m_buffer[pos].cseq = cs_dd; + m_buffer[pos].vnSym = vnl_dd; + //never spellcheck a word which starts with dd, because it's used alot in abbreviation + m_singleMode = true; + return 1; + } + + if (m_buffer[pos].cseq == cs_dd) { + //undo dd + markChange(pos); + m_buffer[pos].cseq = cs_d; + m_buffer[pos].vnSym = vnl_d; + m_singleMode = false; + processAppend(ev); + m_reverted = true; + return 1; + } + + return processAppend(ev); +} + +//---------------------------------------------------------- +VnLexiName changeCase(VnLexiName x) +{ + if (x == vnl_nonVnChar) + return x; + if (!(x & 0x01)) + return (VnLexiName)(x+1); + return (VnLexiName)(x-1); +} + +//---------------------------------------------------------- +inline VnLexiName vnToLower(VnLexiName x) +{ + if (x == vnl_nonVnChar) + return x; + if (!(x & 0x01)) //even + return (VnLexiName)(x+1); + return x; +} + +//---------------------------------------------------------- +int UkEngine::processMapChar(UkKeyEvent & ev) +{ + int capsLockOn = 0; + int shiftPressed = 0; + if (m_keyCheckFunc) + m_keyCheckFunc(&shiftPressed, &capsLockOn); + + if (capsLockOn) + ev.vnSym = changeCase(ev.vnSym); + + int ret = processAppend(ev); + if (!m_pCtrl->vietKey) + return ret; + + if (m_current >= 0 && m_buffer[m_current].form != vnw_empty && + m_buffer[m_current].form != vnw_nonVn) { + return 1; + } + + if (m_current < 0) + return 0; + + // mapChar doesn't apply + m_current--; + WordInfo & entry = m_buffer[m_current]; + + bool undo = false; + // test if undo is needed + if (entry.form != vnw_empty && entry.form != vnw_nonVn) { + VnLexiName prevSym = entry.vnSym; + if (entry.caps) { + prevSym = (VnLexiName)(prevSym - 1); + } + if (prevSym == ev.vnSym) { + if (entry.form != vnw_c) { + int vStart, vEnd, curTonePos, newTonePos, tone; + VowelSeq vs, newVs; + + vEnd = m_current - entry.vOffset; + vs = m_buffer[vEnd].vseq; + vStart = vEnd - VSeqList[vs].len +1; + curTonePos = vStart + getTonePosition(vs, vEnd == m_current); + tone = m_buffer[curTonePos].tone; + markChange(m_current); + m_current--; + + //check if tone position is needed + if (tone != 0 && m_current >= 0 && + (m_buffer[m_current].form == vnw_v || m_buffer[m_current].form == vnw_cv)) { + newVs = m_buffer[m_current].vseq; + newTonePos = vStart + getTonePosition(newVs, true); + if (newTonePos != curTonePos) { + markChange(newTonePos); + m_buffer[newTonePos].tone = tone; + markChange(curTonePos); + m_buffer[curTonePos].tone = 0; + } + } + } + else { + markChange(m_current); + m_current--; + } + undo = true; + } + } + + ev.evType = vneNormal; + ev.chType = m_pCtrl->input.getCharType(ev.keyCode); + ev.vnSym = IsoToVnLexi(ev.keyCode); + ret = processAppend(ev); + if (undo) { + m_singleMode = false; + m_reverted = true; + return 1; + } + return ret; +} + +//---------------------------------------------------------- +int UkEngine::processTelexW(UkKeyEvent & ev) +{ + if (!m_pCtrl->vietKey) + return processAppend(ev); + + int ret; + static bool usedAsMapChar = false; + int capsLockOn = 0; + int shiftPressed = 0; + if (m_keyCheckFunc) + m_keyCheckFunc(&shiftPressed, &capsLockOn); + + if (usedAsMapChar) { + ev.evType = vneMapChar; + ev.vnSym = isupper(ev.keyCode)? vnl_Uh : vnl_uh; + if (capsLockOn) + ev.vnSym = changeCase(ev.vnSym); + ev.chType = ukcVn; + ret = processMapChar(ev); + if (ret == 0) { + if (m_current >= 0) + m_current--; + usedAsMapChar = false; + ev.evType = vneHookAll; + return processHook(ev); + } + return ret; + } + + ev.evType = vneHookAll; + usedAsMapChar = false; + ret = processHook(ev); + if (ret == 0) { + if (m_current >= 0) + m_current--; + ev.evType = vneMapChar; + ev.vnSym = isupper(ev.keyCode)? vnl_Uh : vnl_uh; + if (capsLockOn) + ev.vnSym = changeCase(ev.vnSym); + ev.chType = ukcVn; + usedAsMapChar = true; + return processMapChar(ev); + } + return ret; +} + +//---------------------------------------------------------- +int UkEngine::checkEscapeVIQR(UkKeyEvent & ev) +{ + if (m_current < 0) + return 0; + WordInfo & entry = m_buffer[m_current]; + int escape = 0; + if (entry.form == vnw_v || entry.form == vnw_cv) { + switch (ev.keyCode) { + case '^': + escape = (entry.vnSym == vnl_a || entry.vnSym == vnl_o || entry.vnSym == vnl_e); + break; + case '(': + escape = (entry.vnSym == vnl_a); + break; + case '+': + escape = (entry.vnSym == vnl_o || entry.vnSym == vnl_u); + break; + case '\'': + case '`': + case '?': + case '~': + case '.': + escape = (entry.tone == 0); + break; + } + } + else if (entry.form == vnw_nonVn) { + unsigned char ch = toupper(entry.keyCode); + switch (ev.keyCode) { + case '^': + escape = (ch == 'A' || ch == 'O' || ch == 'E'); + break; + case '(': + escape = (ch == 'A'); + break; + case '+': + escape = (ch == 'O' || ch == 'U'); + break; + case '\'': + case '`': + case '?': + case '~': + case '.': + escape = (ch == 'A' || ch == 'E' || ch == 'I' || + ch == 'O' || ch == 'U' || ch == 'Y'); + break; + } + } + + if (escape) { + m_current++; + WordInfo *p = &m_buffer[m_current]; + p->form = (ev.chType == ukcWordBreak) ? vnw_empty : vnw_nonVn; + p->c1Offset = p->c2Offset = p->vOffset = -1; + p->keyCode = '?'; + p->vnSym = vnl_nonVnChar; + + m_current++; + p++; + p->form = (ev.chType == ukcWordBreak) ? vnw_empty : vnw_nonVn; + p->c1Offset = p->c2Offset = p->vOffset = -1; + p->keyCode = ev.keyCode; + p->vnSym = vnl_nonVnChar; + + //write output + m_pOutBuf[0] = '\\'; + m_pOutBuf[1] = ev.keyCode; + *m_pOutSize = 2; + m_outputWritten = true; + } + return escape; +} + +//---------------------------------------------------------- +int UkEngine::processAppend(UkKeyEvent & ev) +{ + int ret = 0; + switch (ev.chType) { + case ukcReset: +#if defined(_WIN32) + if (ev.keyCode == ENTER_CHAR) { + if (m_pCtrl->options.macroEnabled && macroMatch(ev)) + return 1; + } +#endif + reset(); + return 0; + case ukcWordBreak: + m_singleMode = false; + return processWordEnd(ev); + case ukcNonVn: + { + if (m_pCtrl->vietKey && m_pCtrl->charsetId == CONV_CHARSET_VIQR && checkEscapeVIQR(ev)) + return 1; + + m_current++; + WordInfo & entry = m_buffer[m_current]; + entry.form = (ev.chType == ukcWordBreak) ? vnw_empty : vnw_nonVn; + entry.c1Offset = entry.c2Offset = entry.vOffset = -1; + entry.keyCode = ev.keyCode; + entry.vnSym = vnToLower(ev.vnSym); + entry.tone = 0; + entry.caps = (entry.vnSym != ev.vnSym); + if (!m_pCtrl->vietKey || m_pCtrl->charsetId != CONV_CHARSET_UNI_CSTRING) + return 0; + markChange(m_current); + return 1; + } + case ukcVn: + { + if (IsVnVowel[ev.vnSym]) { + VnLexiName v = (VnLexiName)StdVnNoTone[vnToLower(ev.vnSym)]; + if (m_current >= 0 && m_buffer[m_current].form == vnw_c && + ((m_buffer[m_current].cseq == cs_q && v == vnl_u) || + (m_buffer[m_current].cseq == cs_g && v == vnl_i))) { + return appendConsonnant(ev); //process u after q, i after g as consonnants + } + return appendVowel(ev); + } + return appendConsonnant(ev); + } + break; + } + + return ret; +} + +//---------------------------------------------------------- +int UkEngine::appendVowel(UkKeyEvent & ev) +{ + bool autoCompleted = false; + + m_current++; + WordInfo & entry = m_buffer[m_current]; + + VnLexiName lowerSym = vnToLower(ev.vnSym); + VnLexiName canSym = (VnLexiName)StdVnNoTone[lowerSym]; + + entry.vnSym = canSym; + entry.caps = (lowerSym != ev.vnSym); + entry.tone = (lowerSym - canSym)/2; + entry.keyCode = ev.keyCode; + + if (m_current == 0 || !m_pCtrl->vietKey) { + entry.form = vnw_v; + entry.c1Offset = entry.c2Offset = -1; + entry.vOffset = 0; + entry.vseq = lookupVSeq(canSym); + + if (!m_pCtrl->vietKey || + ((m_pCtrl->charsetId != CONV_CHARSET_UNI_CSTRING) && isalpha(entry.keyCode)) ) { + return 0; + } + markChange(m_current); + return 1; + } + + WordInfo & prev = m_buffer[m_current-1]; + VowelSeq vs, newVs; + ConSeq cs; + int prevTonePos; + int tone, newTone, tonePos, newTonePos; + + switch (prev.form) { + + case vnw_empty: + entry.form = vnw_v; + entry.c1Offset = entry.c2Offset = -1; + entry.vOffset = 0; + entry.vseq = newVs = lookupVSeq(canSym); + break; + + case vnw_nonVn: + case vnw_cvc: + case vnw_vc: + entry.form = vnw_nonVn; + entry.c1Offset = entry.c2Offset = entry.vOffset = -1; + break; + + case vnw_v: + case vnw_cv: + vs = prev.vseq; + prevTonePos = (m_current - 1) - (VSeqList[vs].len - 1) + getTonePosition(vs, true); + tone = m_buffer[prevTonePos].tone; + + if (lowerSym != canSym && tone != 0) //new sym has a tone, but there's is already a preceeding tone + newVs = vs_nil; + else { + if (VSeqList[vs].len == 3) + newVs = vs_nil; + else if (VSeqList[vs].len == 2) + newVs = lookupVSeq(VSeqList[vs].v[0], VSeqList[vs].v[1], canSym); + else + newVs = lookupVSeq(VSeqList[vs].v[0], canSym); + } + + if (newVs != vs_nil && prev.form == vnw_cv) { + cs = m_buffer[m_current - 1 - prev.c1Offset].cseq; + if (!isValidCV(cs, newVs)) + newVs = vs_nil; + } + + if (newVs == vs_nil) { + entry.form = vnw_nonVn; + entry.c1Offset = entry.c2Offset = entry.vOffset = -1; + break; + } + + entry.form = prev.form; + if (prev.form == vnw_cv) + entry.c1Offset = prev.c1Offset + 1; + else + entry.c1Offset = -1; + entry.c2Offset = -1; + entry.vOffset = 0; + entry.vseq = newVs; + entry.tone = 0; + + newTone = (lowerSym - canSym)/2; + if (tone == 0) { + if (newTone != 0) { + tone = newTone; + tonePos = getTonePosition(newVs, true) + ((m_current - 1) - VSeqList[vs].len + 1); + markChange(tonePos); + m_buffer[tonePos].tone = tone; + return 1; + } + } + else { + newTonePos = getTonePosition(newVs, true) + ((m_current - 1) - VSeqList[vs].len + 1); + if (newTonePos != prevTonePos) { + markChange(prevTonePos); + m_buffer[prevTonePos].tone = 0; + markChange(newTonePos); + if (newTone != 0) + tone = newTone; + m_buffer[newTonePos].tone = tone; + return 1; + } + if (newTone != 0 && newTone != tone) { + tone = newTone; + markChange(prevTonePos); + m_buffer[prevTonePos].tone = tone; + return 1; + } + + } + + break; + case vnw_c: + newVs = lookupVSeq(canSym); + cs = prev.cseq; + if (!isValidCV(cs, newVs)) { + entry.form = vnw_nonVn; + entry.c1Offset = entry.c2Offset = entry.vOffset = -1; + break; + } + + entry.form = vnw_cv; + entry.c1Offset = 1; + entry.c2Offset = -1; + entry.vOffset = 0; + entry.vseq = newVs; + + if (cs == cs_gi && prev.tone != 0) { + if (entry.tone == 0) + entry.tone = prev.tone; + markChange(m_current - 1); + prev.tone = 0; + return 1; + } + + break; + } + + if (!autoCompleted && + (m_pCtrl->charsetId != CONV_CHARSET_UNI_CSTRING) && + isalpha(entry.keyCode)) { + return 0; + } + + markChange(m_current); + return 1; +} + +//---------------------------------------------------------- +int UkEngine::appendConsonnant(UkKeyEvent & ev) +{ + bool complexEvent = false; + m_current++; + WordInfo & entry = m_buffer[m_current]; + + VnLexiName lowerSym = vnToLower(ev.vnSym); + + entry.vnSym = lowerSym; + entry.caps = (lowerSym != ev.vnSym); + entry.keyCode = ev.keyCode; + entry.tone = 0; + + if (m_current == 0 || !m_pCtrl->vietKey) { + entry.form = vnw_c; + entry.c1Offset = 0; + entry.c2Offset = -1; + entry.vOffset = -1; + entry.cseq = lookupCSeq(lowerSym); + if (!m_pCtrl->vietKey || m_pCtrl->charsetId != CONV_CHARSET_UNI_CSTRING) + return 0; + markChange(m_current); + return 1; + } + + ConSeq cs, newCs, c1; + VowelSeq vs, newVs; + bool isValid; + + WordInfo & prev = m_buffer[m_current-1]; + + switch (prev.form) { + case vnw_nonVn: + entry.form = vnw_nonVn; + entry.c1Offset = entry.c2Offset = entry.vOffset = -1; + if (m_pCtrl->charsetId != CONV_CHARSET_UNI_CSTRING) + return 0; + markChange(m_current); + return 1; + case vnw_empty: + entry.form = vnw_c; + entry.c1Offset = 0; + entry.c2Offset = -1; + entry.vOffset = -1; + entry.cseq = lookupCSeq(lowerSym); + if (m_pCtrl->charsetId != CONV_CHARSET_UNI_CSTRING) + return 0; + markChange(m_current); + return 1; + case vnw_v: + case vnw_cv: + vs = prev.vseq; + newVs = vs; + if (vs == vs_uoh || vs == vs_uho) { + newVs = vs_uhoh; + } + + c1 = cs_nil; + if (prev.c1Offset != -1) + c1 = m_buffer[m_current-1-prev.c1Offset].cseq; + + newCs = lookupCSeq(lowerSym); + isValid = isValidCVC(c1, newVs, newCs); + + if (isValid) { + //check u+o -> u+o+ + if (vs == vs_uho) { + markChange(m_current-1); + prev.vnSym = vnl_oh; + prev.vseq = vs_uhoh; + complexEvent = true; + } + else if (vs == vs_uoh) { + markChange(m_current-2); + m_buffer[m_current-2].vnSym = vnl_uh; + m_buffer[m_current-2].vseq = vs_uh; + prev.vseq = vs_uhoh; + complexEvent = true; + } + + if (prev.form == vnw_v) { + entry.form = vnw_vc; + entry.c1Offset = -1; + entry.c2Offset = 0; + entry.vOffset = 1; + } + else { //prev == vnw_cv + entry.form = vnw_cvc; + entry.c1Offset = prev.c1Offset + 1; + entry.c2Offset = 0; + entry.vOffset = 1; + } + entry.cseq = newCs; + + //reposition tone if needed + int oldIdx = (m_current-1) - (VSeqList[vs].len - 1) + getTonePosition(vs, true); + if (m_buffer[oldIdx].tone != 0) { + int newIdx = (m_current-1) - (VSeqList[newVs].len - 1) + getTonePosition(newVs, false); + if (newIdx != oldIdx) { + markChange(newIdx); + m_buffer[newIdx].tone = m_buffer[oldIdx].tone; + markChange(oldIdx); + m_buffer[oldIdx].tone = 0; + return 1; + } + } + } + else { + entry.form = vnw_nonVn; + entry.c1Offset = entry.c2Offset = entry.vOffset = -1; + } + + if (complexEvent) { + return 1; + } + + if (m_pCtrl->charsetId != CONV_CHARSET_UNI_CSTRING) + return 0; + markChange(m_current); + return 1; + case vnw_c: + case vnw_vc: + case vnw_cvc: + cs = prev.cseq; + if (CSeqList[cs].len == 3) + newCs = cs_nil; + else if (CSeqList[cs].len == 2) + newCs = lookupCSeq(CSeqList[cs].c[0], CSeqList[cs].c[1], lowerSym); + else + newCs = lookupCSeq(CSeqList[cs].c[0], lowerSym); + + if (newCs != cs_nil && (prev.form == vnw_vc || prev.form == vnw_cvc)) { + // Check CVC combination + c1 = cs_nil; + if (prev.c1Offset != -1) + c1 = m_buffer[m_current-1-prev.c1Offset].cseq; + + int vIdx = (m_current - 1) - prev.vOffset; + vs = m_buffer[vIdx].vseq; + isValid = isValidCVC(c1, vs, newCs); + + if (!isValid) + newCs = cs_nil; + } + + if (newCs == cs_nil) { + entry.form = vnw_nonVn; + entry.c1Offset = entry.c2Offset = entry.vOffset = -1; + } + else { + if (prev.form == vnw_c) { + entry.form = vnw_c; + entry.c1Offset = 0; + entry.c2Offset = -1; + entry.vOffset = -1; + } + else if (prev.form == vnw_vc) { + entry.form = vnw_vc; + entry.c1Offset = -1; + entry.c2Offset = 0; + entry.vOffset = prev.vOffset + 1; + } + else { //vnw_cvc + entry.form = vnw_cvc; + entry.c1Offset = prev.c1Offset + 1; + entry.c2Offset = 0; + entry.vOffset = prev.vOffset + 1; + } + entry.cseq = newCs; + } + if (m_pCtrl->charsetId != CONV_CHARSET_UNI_CSTRING) + return 0; + markChange(m_current); + return 1; + } + + if (m_pCtrl->charsetId != CONV_CHARSET_UNI_CSTRING) + return 0; + markChange(m_current); + return 1; +} + +//---------------------------------------------------------- +int UkEngine::processEscChar(UkKeyEvent & ev) +{ + if (m_pCtrl->vietKey && + m_current >=0 && m_buffer[m_current].form != vnw_empty && m_buffer[m_current].form != vnw_nonVn) { + m_toEscape = true; + } + return processAppend(ev); +} + +//---------------------------------------------------------- +void UkEngine::pass(int keyCode) +{ + UkKeyEvent ev; + m_pCtrl->input.keyCodeToEvent(keyCode, ev); + processAppend(ev); +} + +//--------------------------------------------- +// This can be called only after other processing have been done. +// The new event is supposed to be put into m_buffer already +//--------------------------------------------- +int UkEngine::processNoSpellCheck(UkKeyEvent & ev) +{ + WordInfo & entry = m_buffer[m_current]; + if (IsVnVowel[entry.vnSym]) { + entry.form = vnw_v; + entry.vOffset = 0; + entry.vseq = lookupVSeq(entry.vnSym); + entry.c1Offset = entry.c2Offset = -1; + } + else { + entry.form = vnw_c; + entry.c1Offset = 0; + entry.c2Offset = -1; + entry.vOffset = -1; + entry.cseq = lookupCSeq(entry.vnSym); + } + + if (ev.evType == vneNormal && + ((entry.keyCode >= 'a' && entry.keyCode <= 'z') || + (entry.keyCode >= 'A' && entry.keyCode <= 'Z') ) ) + return 0; + markChange(m_current); + return 1; +} +//---------------------------------------------------------- +int UkEngine::process(unsigned int keyCode, int & backs, unsigned char *outBuf, int & outSize, UkOutputType & outType) +{ + UkKeyEvent ev; + prepareBuffer(); + m_backs = 0; + m_changePos = m_current+1; + m_pOutBuf = outBuf; + m_pOutSize = &outSize; + m_outputWritten = false; + m_reverted = false; + m_keyRestored = false; + m_keyRestoring = false; + m_outType = UkCharOutput; + + m_pCtrl->input.keyCodeToEvent(keyCode, ev); + + int ret; + if (!m_toEscape) { + ret = (this->*UkKeyProcList[ev.evType])(ev); + } + else { + m_toEscape = false; + if (m_current < 0 || ev.evType == vneNormal || ev.evType == vneEscChar) { + ret = processAppend(ev); + } + else { + m_current--; + processAppend(ev); + markChange(m_current); //this will assign m_backs to 1 and mark the character for output + ret = 1; + } + } + + if ( m_pCtrl->vietKey && + m_current >= 0 && m_buffer[m_current].form == vnw_nonVn && + ev.chType == ukcVn && + (!m_pCtrl->options.spellCheckEnabled || m_singleMode) ) + { + + //The spell check has failed, but because we are in non-spellcheck mode, + //we consider the new character as the beginning of a new word + ret = processNoSpellCheck(ev); + /* + if ((!m_pCtrl->options.spellCheckEnabled || m_singleMode) || + ( !m_reverted && + (m_current < 1 || m_buffer[m_current-1].form != vnw_nonVn)) ) { + + ret = processNoSpellCheck(ev); + } + */ + } + + //we add key to key buffer only if that key has not caused a reset + if (m_current >= 0) { + ev.chType = m_pCtrl->input.getCharType(ev.keyCode); + m_keyCurrent++; + m_keyStrokes[m_keyCurrent].ev = ev; + m_keyStrokes[m_keyCurrent].converted = (ret && !m_keyRestored); + } + + if (ret == 0) { + backs = 0; + outSize = 0; + outType = m_outType; + return 0; + } + + backs = m_backs; + if (!m_outputWritten) { + writeOutput(outBuf, outSize); + } + outType = m_outType; + + return ret; +} + + +//---------------------------------------------------------- +// Returns 0 on success +// error code otherwise +// outBuf: buffer to write +// outSize: [in] size of buffer in bytes +// [out] bytes written to buffer +//---------------------------------------------------------- +int UkEngine::writeOutput(unsigned char *outBuf, int & outSize) +{ + StdVnChar stdChar; + int i, bytesWritten; + int ret = 1; + StringBOStream os(outBuf, outSize); + VnCharset *pCharset = VnCharsetLibObj.getVnCharset(m_pCtrl->charsetId); + pCharset->startOutput(); + + for (i = m_changePos; i <= m_current; i++) { + if (m_buffer[i].vnSym != vnl_nonVnChar) { + //process vn symbol + stdChar = m_buffer[i].vnSym + VnStdCharOffset; + if (m_buffer[i].caps) + stdChar--; + if (m_buffer[i].tone != 0) + stdChar += m_buffer[i].tone * 2; + } + else { + stdChar = IsoToStdVnChar(m_buffer[i].keyCode); + } + + if (stdChar != INVALID_STD_CHAR) + ret = pCharset->putChar(os, stdChar, bytesWritten); + } + + outSize = os.getOutBytes(); + return (ret? 0 : VNCONV_OUT_OF_MEMORY); +} + +//--------------------------------------------- +// Returns the number of backspaces needed to +// go back from last to first +//--------------------------------------------- +int UkEngine::getSeqSteps(int first, int last) +{ + StdVnChar stdChar; + + if (last < first) + return 0; + + if (m_pCtrl->charsetId == CONV_CHARSET_XUTF8 || + m_pCtrl->charsetId == CONV_CHARSET_UNICODE) + return (last - first + 1); + + StringBOStream os(0, 0); + int i, bytesWritten; + + VnCharset *pCharset = VnCharsetLibObj.getVnCharset(m_pCtrl->charsetId); + pCharset->startOutput(); + + for (i = first; i <= last; i++) { + if (m_buffer[i].vnSym != vnl_nonVnChar) { + //process vn symbol + stdChar = m_buffer[i].vnSym + VnStdCharOffset; + if (m_buffer[i].caps) + stdChar--; + if (m_buffer[i].tone != 0) + stdChar += m_buffer[i].tone*2; + } + else { + stdChar = m_buffer[i].keyCode; + } + + if (stdChar != INVALID_STD_CHAR) + pCharset->putChar(os, stdChar, bytesWritten); + } + + int len = os.getOutBytes(); + if (m_pCtrl->charsetId == CONV_CHARSET_UNIDECOMPOSED) + len = len / 2; + return len; +} + +//--------------------------------------------- +void UkEngine::markChange(int pos) +{ + if (pos < m_changePos) { + m_backs += getSeqSteps(pos, m_changePos-1); + m_changePos = pos; + } +} + +//---------------------------------------------------------------- +// Called from processBackspace to keep +// character buffer (m_buffer) and key stroke buffer in synch +//---------------------------------------------------------------- +void UkEngine::synchKeyStrokeBuffer() +{ + //synchronize with key-stroke buffer + if (m_keyCurrent >= 0) + m_keyCurrent--; + if (m_current >= 0 && m_buffer[m_current].form == vnw_empty) { + //in character buffer, we have reached a word break, + //so we also need to move key stroke pointer backward to corresponding word break + while (m_keyCurrent >= 0 && m_keyStrokes[m_keyCurrent].ev.chType != ukcWordBreak) + { + m_keyCurrent--; + } + } +} + +//--------------------------------------------- +int UkEngine::processBackspace(int & backs, unsigned char *outBuf, int & outSize, UkOutputType & outType) +{ + outType = UkCharOutput; + if (!m_pCtrl->vietKey || m_current < 0) { + backs = 0; + outSize = 0; + return 0; + } + + m_backs = 0; + m_changePos = m_current + 1; + markChange(m_current); + + if (m_current == 0 || + m_buffer[m_current].form == vnw_empty || + m_buffer[m_current].form == vnw_nonVn || + m_buffer[m_current].form == vnw_c || + m_buffer[m_current-1].form == vnw_c || + m_buffer[m_current-1].form == vnw_cvc || + m_buffer[m_current-1].form == vnw_vc) { + + m_current--; + backs = m_backs; + outSize = 0; + synchKeyStrokeBuffer(); + return (backs > 1); + } + + VowelSeq vs, newVs; + int curTonePos, newTonePos, tone, vStart, vEnd; + + vEnd = m_current - m_buffer[m_current].vOffset; + vs = m_buffer[vEnd].vseq; + vStart = vEnd - VSeqList[vs].len + 1; + newVs = m_buffer[m_current-1].vseq; + curTonePos = vStart + getTonePosition(vs, vEnd == m_current); + newTonePos = vStart + getTonePosition(newVs, true); + tone = m_buffer[curTonePos].tone; + + if (tone == 0 || curTonePos == newTonePos || + (curTonePos == m_current && m_buffer[m_current].tone != 0)) { + m_current--; + backs = m_backs; + outSize = 0; + synchKeyStrokeBuffer(); + return (backs > 1); + } + + markChange(newTonePos); + m_buffer[newTonePos].tone = tone; + markChange(curTonePos); + m_buffer[curTonePos].tone = 0; + m_current--; + synchKeyStrokeBuffer(); + backs = m_backs; + writeOutput(outBuf, outSize); + return 1; +} + +//------------------------------------------------ +void UkEngine::reset() +{ + m_current = -1; + m_keyCurrent = -1; + m_singleMode = false; + m_toEscape = false; +} + +//------------------------------------------------ +void UkEngine::resetKeyBuf() +{ + m_keyCurrent = -1; +} + +//------------------------------------------------ +UkEngine::UkEngine() +{ + if (!m_classInit) { + engineClassInit(); + m_classInit = true; + } + m_pCtrl = 0; + m_bufSize = MAX_UK_ENGINE; + m_keyBufSize = MAX_UK_ENGINE; + m_current = -1; + m_keyCurrent = -1; + m_singleMode = false; + m_keyCheckFunc = 0; + m_reverted = false; + m_toEscape = false; + m_keyRestored = false; +} + +//---------------------------------------------------- +// make sure there are at least 10 entries available +//---------------------------------------------------- +void UkEngine::prepareBuffer() +{ + int rid; + //prepare symbol buffer + if (m_current >= 0 && m_current + 10 >= m_bufSize) { + // Get rid of at least half of the current entries + // don't get rid from the middle of a word. + for (rid = m_current/2; m_buffer[rid].form != vnw_empty && rid < m_current; rid++); + if (rid == m_current) { + m_current = -1; + } + else { + rid++; + memmove(m_buffer, m_buffer+rid, (m_current-rid+1)*sizeof(WordInfo)); + m_current -= rid; + } + } + + //prepare key stroke buffer + if (m_keyCurrent > 0 && m_keyCurrent + 1 >= m_keyBufSize) { + // Get rid of at least half of the current entries + rid = m_keyCurrent/2; + memmove(m_keyStrokes, m_keyStrokes + rid, (m_keyCurrent-rid+1)*sizeof(m_keyStrokes[0])); + m_keyCurrent -= rid; + } + +} + +#define ENTER_CHAR 13 +enum VnCaseType {VnCaseNoChange, VnCaseAllCapital, VnCaseAllSmall}; + +//---------------------------------------------------- +int UkEngine::macroMatch(UkKeyEvent & ev) +{ + int capsLockOn = 0; + int shiftPressed = 0; + if (m_keyCheckFunc) + m_keyCheckFunc(&shiftPressed, &capsLockOn); + + if (shiftPressed && (ev.keyCode ==' ' || ev.keyCode == ENTER_CHAR)) + return 0; + + const StdVnChar *pMacText = NULL; + StdVnChar key[MAX_MACRO_KEY_LEN+1]; + StdVnChar *pKeyStart; + + // Use static macro text so we can gain a bit of performance + // by avoiding memory allocation each time this function is called + static StdVnChar macroText[MAX_MACRO_TEXT_LEN+1]; + + int i, j; + + i = m_current; + while (i >= 0 && (m_current-i + 1) < MAX_MACRO_KEY_LEN) { + while (i>=0 && m_buffer[i].form != vnw_empty && (m_current-i + 1) < MAX_MACRO_KEY_LEN) + i--; + if (i>=0 && m_buffer[i].form != vnw_empty) + return 0; + + if (i>=0) { + if (m_buffer[i].vnSym != vnl_nonVnChar) { + key[0] = m_buffer[i].vnSym + VnStdCharOffset; + if (m_buffer[i].caps) + key[0]--; + key[0] += m_buffer[i].tone*2; + } + else + key[0] = m_buffer[i].keyCode; + } + + for (j=i+1; j<=m_current; j++) { + if (m_buffer[j].vnSym != vnl_nonVnChar) { + key[j-i] = m_buffer[j].vnSym + VnStdCharOffset; + if (m_buffer[j].caps) + key[j-i]--; + key[j-i] += m_buffer[j].tone*2; + } + else + key[j-i] = m_buffer[j].keyCode; + } + key[m_current-i+1] = 0; + //search macro table + pMacText = m_pCtrl->macStore.lookup(key+1); + if (pMacText) { + i++; //mark the position where change is needed + pKeyStart = key + 1; + break; + } + if (i>=0) { + pMacText = m_pCtrl->macStore.lookup(key); + if (pMacText) { + pKeyStart = key; + break; + } + } + i--; + } + + if (!pMacText) { + return 0; + } + + markChange(i); + + // determine the form of macro replacements: ALL CAPITALS, First Character Capital, or no change + VnCaseType macroCase; + if (IS_STD_VN_LOWER(*pKeyStart)) { + macroCase = VnCaseAllSmall; + } + else if (IS_STD_VN_UPPER(*pKeyStart)) { + macroCase = VnCaseAllCapital; + for (i=1; pKeyStart[i]; i++) { + if (IS_STD_VN_LOWER(pKeyStart[i])) { + macroCase = VnCaseNoChange; + } + } + } + else macroCase = VnCaseNoChange; + + // Convert case of macro text according to macroCase + int charCount = 0; + while (pMacText[charCount] != 0) + charCount++; + + for (i = 0; i < charCount; i++) + { + if (macroCase == VnCaseAllCapital) + macroText[i] = StdVnToUpper(pMacText[i]); + else if (macroCase == VnCaseAllSmall) + macroText[i] = StdVnToLower(pMacText[i]); + else + macroText[i] = pMacText[i]; + } + + // Convert to target output charset + int outSize; + int maxOutSize = *m_pOutSize; + int inLen = charCount * sizeof(StdVnChar); + VnConvert(CONV_CHARSET_VNSTANDARD, m_pCtrl->charsetId, + (UKBYTE *) macroText, (UKBYTE *)m_pOutBuf, + &inLen, &maxOutSize); + outSize = maxOutSize; + + //write the last input character + StdVnChar vnChar; + if (outSize < *m_pOutSize) { + maxOutSize = *m_pOutSize - outSize; + if (ev.vnSym != vnl_nonVnChar) + vnChar = ev.vnSym + VnStdCharOffset; + else + vnChar = ev.keyCode; + inLen = sizeof(StdVnChar); + VnConvert(CONV_CHARSET_VNSTANDARD, m_pCtrl->charsetId, + (UKBYTE *) &vnChar, ((UKBYTE *)m_pOutBuf) + outSize, + &inLen, &maxOutSize); + outSize += maxOutSize; + } + int backs = m_backs; //store m_backs before calling reset + reset(); + m_outputWritten = true; + m_backs = backs; + *m_pOutSize = outSize; + return 1; +} + +//---------------------------------------------------- +int UkEngine::restoreKeyStrokes(int & backs, unsigned char *outBuf, int & outSize, UkOutputType & outType) +{ + outType = UkKeyOutput; + if (!lastWordHasVnMark()) { + backs = 0; + outSize = 0; + return 0; + } + + m_backs = 0; + m_changePos = m_current+1; + + int keyStart; + bool converted = false; + for (keyStart = m_keyCurrent; keyStart >= 0 && m_keyStrokes[keyStart].ev.chType != ukcWordBreak; keyStart--) { + if (m_keyStrokes[keyStart].converted) { + converted = true; + } + } + keyStart++; + + if (!converted) { + //no key stroke has been converted, so it doesn't make sense to restore key strokes + backs = 0; + outSize = 0; + return 0; + } + + //int i = m_current; + while (m_current >=0 && m_buffer[m_current].form != vnw_empty) + m_current--; + markChange(m_current+1); + backs = m_backs; + + int count; + int i; + UkKeyEvent ev; + m_keyRestoring = true; + for (i=keyStart, count = 0; i <= m_keyCurrent; i++) { + if (countinput.keyCodeToSymbol(m_keyStrokes[i].ev.keyCode, ev); + m_keyStrokes[i].converted = false; + processAppend(ev); + } + outSize = count; + m_keyRestoring = false; + + return 1; +} + +//-------------------------------------------------- +void UkEngine::setSingleMode() +{ + m_singleMode = true; +} + +//-------------------------------------------------- +void SetupUnikeyEngine() +{ + SetupInputClassifierTable(); + int i; + VnLexiName lexi; + + //Calculate IsoStdVnCharMap + for (i=0; i < 256; i++) { + IsoStdVnCharMap[i] = i; + } + + for (i=0; SpecialWesternChars[i]; i++) { + IsoStdVnCharMap[SpecialWesternChars[i]] = (vnl_lastChar + i) + VnStdCharOffset; + } + + for (i=0; i < 256; i++) { + if ((lexi = IsoToVnLexi(i)) != vnl_nonVnChar) { + IsoStdVnCharMap[i] = lexi + VnStdCharOffset; + } + } +} + +//-------------------------------------------------- +bool UkEngine::atWordBeginning() +{ + return (m_current < 0 || m_buffer[m_current].form == vnw_empty); +} + +//-------------------------------------------------- +// Check for macro first, if there's a match, expand macro. If not: +// Spell-check, if is valid Vietnamese, return normally, if not: +// restore key strokes if auto-restore is enabled +//-------------------------------------------------- +int UkEngine::processWordEnd(UkKeyEvent & ev) +{ + if (m_pCtrl->options.macroEnabled && macroMatch(ev)) + return 1; + + if (!m_pCtrl->options.spellCheckEnabled || m_singleMode || m_current < 0 || m_keyRestoring) { + m_current++; + WordInfo & entry = m_buffer[m_current]; + entry.form = vnw_empty; + entry.c1Offset = entry.c2Offset = entry.vOffset = -1; + entry.keyCode = ev.keyCode; + entry.vnSym = vnToLower(ev.vnSym); + entry.caps = (entry.vnSym != ev.vnSym); + return 0; + } + + int outSize = 0; + if (m_pCtrl->options.autoNonVnRestore && lastWordIsNonVn()) { + outSize = *m_pOutSize; + if (restoreKeyStrokes(m_backs, m_pOutBuf, outSize, m_outType)) { + m_keyRestored = true; + m_outputWritten = true; + } + } + + m_current++; + WordInfo & entry = m_buffer[m_current]; + entry.form = vnw_empty; + entry.c1Offset = entry.c2Offset = entry.vOffset = -1; + entry.keyCode = ev.keyCode; + entry.vnSym = vnToLower(ev.vnSym); + entry.caps = (entry.vnSym != ev.vnSym); + + if (m_keyRestored && outSize < *m_pOutSize) { + m_pOutBuf[outSize] = ev.keyCode; + outSize++; + *m_pOutSize = outSize; + return 1; + } + + return 0; +} + +//--------------------------------------------------------------------------- +// Test if last word is a non-Vietnamese word, so that +// the engine can restore key strokes if it is indeed not a Vietnamese word +//--------------------------------------------------------------------------- +bool UkEngine::lastWordIsNonVn() +{ + if (m_current < 0) + return false; + + switch (m_buffer[m_current].form) { + case vnw_nonVn: + return true; + case vnw_empty: + case vnw_c: + return false; + case vnw_v: + case vnw_cv: + return !VSeqList[m_buffer[m_current].vseq].complete; + case vnw_vc: + case vnw_cvc: { + int vIndex = m_current - m_buffer[m_current].vOffset; + VowelSeq vs = m_buffer[vIndex].vseq; + if (!VSeqList[vs].complete) + return true; + ConSeq cs = m_buffer[m_current].cseq; + ConSeq c1 = cs_nil; + if (m_buffer[m_current].c1Offset != -1) + c1 = m_buffer[m_current-m_buffer[m_current].c1Offset].cseq; + + if (!isValidCVC(c1, vs, cs)) { + return true; + } + + int tonePos = (vIndex - VSeqList[vs].len + 1) + getTonePosition(vs, false); + int tone = m_buffer[tonePos].tone; + if ((cs == cs_c || cs == cs_ch || cs == cs_p || cs == cs_t) && + (tone == 2 || tone == 3 || tone == 4)) + { + return true; + } + } + } + return false; +} + +//--------------------------------------------------------------------------- +// Test if last word has a Vietnamese mark, that is tones, decorators +//--------------------------------------------------------------------------- +bool UkEngine::lastWordHasVnMark() +{ + for (int i=m_current; i>=0 && m_buffer[i].form != vnw_empty; i--) { + VnLexiName sym = m_buffer[i].vnSym; + if (sym != vnl_nonVnChar) { + if (IsVnVowel[sym]) { + if (m_buffer[i].tone) + return true; + } + if (sym != StdVnRootChar[sym] ) + return true; + } + } + return false; +} diff --git a/unikey/ukengine.h b/unikey/ukengine.h new file mode 100644 index 0000000..54de801 --- /dev/null +++ b/unikey/ukengine.h @@ -0,0 +1,160 @@ +// -*- mode:c++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- +/* Unikey Vietnamese Input Method + * Copyright (C) 2000-2005 Pham Kim Long + * Contact: + * unikey@gmail.com + * UniKey project: http://unikey.org + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __UKENGINE_H +#define __UKENGINE_H + +#include "charset.h" +#include "vnlexi.h" +#include "inputproc.h" +#include "mactab.h" + +//This is a shared object among processes, do not put any pointer in it +struct UkSharedMem { + //states + int initialized; + int vietKey; + + UnikeyOptions options; + UkInputProcessor input; + int usrKeyMapLoaded; + int usrKeyMap[256]; + int charsetId; + + CMacroTable macStore; +}; + +#define MAX_UK_ENGINE 128 + +enum VnWordForm {vnw_nonVn, vnw_empty, vnw_c, vnw_v, vnw_cv, vnw_vc, vnw_cvc}; + +typedef void (* CheckKeyboardCaseCb)(int *pShiftPressed, int *pCapslockOn); + +struct KeyBufEntry { + UkKeyEvent ev; + bool converted; +}; + +class UkEngine +{ +public: + UkEngine(); + void setCtrlInfo(UkSharedMem *p) + { + m_pCtrl = p; + } + + void setCheckKbCaseFunc(CheckKeyboardCaseCb pFunc) + { + m_keyCheckFunc = pFunc; + } + + bool atWordBeginning(); + + int process(unsigned int keyCode, int & backs, unsigned char *outBuf, int & outSize, UkOutputType & outType); + void pass(int keyCode); //just pass through without filtering + void setSingleMode(); + + int processBackspace(int & backs, unsigned char *outBuf, int & outSize, UkOutputType & outType); + void reset(); + int restoreKeyStrokes(int & backs, unsigned char *outBuf, int & outSize, UkOutputType & outType); + + //following methods must be public just to enable the use of pointers to them + //they should not be called from outside. + int processTone(UkKeyEvent & ev); + int processRoof(UkKeyEvent & ev); + int processHook(UkKeyEvent & ev); + int processAppend(UkKeyEvent & ev); + int appendVowel(UkKeyEvent & ev); + int appendConsonnant(UkKeyEvent & ev); + int processDd(UkKeyEvent & ev); + int processMapChar(UkKeyEvent & ev); + int processTelexW(UkKeyEvent & ev); + int processEscChar(UkKeyEvent & ev); + +protected: + static bool m_classInit; + CheckKeyboardCaseCb m_keyCheckFunc; + UkSharedMem *m_pCtrl; + + int m_changePos; + int m_backs; + int m_bufSize; + int m_current; + int m_singleMode; + + int m_keyBufSize; + //unsigned int m_keyStrokes[MAX_UK_ENGINE]; + KeyBufEntry m_keyStrokes[MAX_UK_ENGINE]; + int m_keyCurrent; + bool m_toEscape; + + //varables valid in one session + unsigned char *m_pOutBuf; + int *m_pOutSize; + bool m_outputWritten; + bool m_reverted; + bool m_keyRestored; + bool m_keyRestoring; + UkOutputType m_outType; + + struct WordInfo { + //info for word ending at this position + VnWordForm form; + int c1Offset, vOffset, c2Offset; + + union { + VowelSeq vseq; + ConSeq cseq; + }; + + //info for current symbol + int caps, tone; + //canonical symbol, after caps, tone are removed + //for non-Vn, vnSym == -1 + VnLexiName vnSym; + int keyCode; + }; + + WordInfo m_buffer[MAX_UK_ENGINE]; + + int processHookWithUO(UkKeyEvent & ev); + int macroMatch(UkKeyEvent & ev); + void markChange(int pos); + void prepareBuffer(); //make sure we have a least 10 entries available + int writeOutput(unsigned char *outBuf, int & outSize); + //int getSeqLength(int first, int last); + int getSeqSteps(int first, int last); + int getTonePosition(VowelSeq vs, bool terminated); + void resetKeyBuf(); + int checkEscapeVIQR(UkKeyEvent & ev); + int processNoSpellCheck(UkKeyEvent & ev); + int processWordEnd(UkKeyEvent & ev); + void synchKeyStrokeBuffer(); + bool lastWordHasVnMark(); + bool lastWordIsNonVn(); +}; + +void SetupUnikeyEngine(); + +#endif diff --git a/unikey/unikey.cpp b/unikey/unikey.cpp new file mode 100644 index 0000000..be3a623 --- /dev/null +++ b/unikey/unikey.cpp @@ -0,0 +1,204 @@ +// -*- coding:unix; mode:c++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- +/*------------------------------------------------------------------------------ +UniKey - Open-source Vietnamese Keyboard +Copyright (C) 1998-2004 Pham Kim Long +Contact: + longcz@yahoo.com + http://unikey.sf.net + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +--------------------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include "unikey.h" +#include "ukengine.h" +#include "usrkeymap.h" + +using namespace std; + +//---- exported variables for use in UkEnginge class ---- +UkSharedMem *pShMem = 0; + +UkEngine MyKbEngine; + +int UnikeyCapsLockOn = 0; +int UnikeyShiftPressed = 0; +//---------------------------------------------------- + +unsigned char UnikeyBuf[1024]; +int UnikeyBackspaces; +int UnikeyBufChars; +UkOutputType UnikeyOutput; + +//-------------------------------------------- +void UnikeySetInputMethod(UkInputMethod im) +{ + if (im == UkTelex || im == UkVni || im == UkSimpleTelex || im == UkSimpleTelex2) { + pShMem->input.setIM(im); + MyKbEngine.reset(); + } + else if (im == UkUsrIM && pShMem->usrKeyMapLoaded) { + //cout << "Switched to user mode\n"; //DEBUG + pShMem->input.setIM(pShMem->usrKeyMap); + MyKbEngine.reset(); + } + + //cout << "IM changed to: " << im << endl; //DEBUG +} + + +//-------------------------------------------- +void UnikeySetCapsState(int shiftPressed, int CapsLockOn) +{ + //UnikeyCapsAll = (shiftPressed && !CapsLockOn) || (!shiftPressed && CapsLockOn); + UnikeyCapsLockOn = CapsLockOn; + UnikeyShiftPressed = shiftPressed; +} + +//-------------------------------------------- +int UnikeySetOutputCharset(int charset) +{ + pShMem->charsetId = charset; + MyKbEngine.reset(); + return 1; +} + +//-------------------------------------------- +void UnikeySetOptions(UnikeyOptions *pOpt) +{ + pShMem->options.freeMarking = pOpt->freeMarking; + pShMem->options.modernStyle = pOpt->modernStyle; + pShMem->options.macroEnabled = pOpt->macroEnabled; + pShMem->options.useUnicodeClipboard = pOpt->useUnicodeClipboard; + pShMem->options.alwaysMacro = pOpt->alwaysMacro; + pShMem->options.spellCheckEnabled = pOpt->spellCheckEnabled; + pShMem->options.autoNonVnRestore = pOpt->autoNonVnRestore; +} + +//-------------------------------------------- +void UnikeyGetOptions(UnikeyOptions *pOpt) +{ + *pOpt = pShMem->options; +} + +//-------------------------------------------- +void CreateDefaultUnikeyOptions(UnikeyOptions *pOpt) +{ + pOpt->freeMarking = 1; + pOpt->modernStyle = 0; + pOpt->macroEnabled = 0; + pOpt->useUnicodeClipboard = 0; + pOpt->alwaysMacro = 0; + pOpt->spellCheckEnabled = 1; + pOpt->autoNonVnRestore = 0; +} + +//-------------------------------------------- +void UnikeyCheckKbCase(int *pShiftPressed, int *pCapsLockOn) +{ + *pShiftPressed = UnikeyShiftPressed; + *pCapsLockOn = UnikeyCapsLockOn; +} + +//-------------------------------------------- +void UnikeySetup() +{ + SetupUnikeyEngine(); + pShMem = new UkSharedMem; + pShMem->input.init(); + pShMem->macStore.init(); + pShMem->vietKey = 1; + pShMem->usrKeyMapLoaded = 0; + MyKbEngine.setCtrlInfo(pShMem); + MyKbEngine.setCheckKbCaseFunc(&UnikeyCheckKbCase); + UnikeySetInputMethod(UkTelex); + UnikeySetOutputCharset(CONV_CHARSET_XUTF8); + pShMem->initialized = 1; + CreateDefaultUnikeyOptions(&pShMem->options); +} + +//-------------------------------------------- +void UnikeyCleanup() +{ + delete pShMem; +} + +//-------------------------------------------- +void UnikeyFilter(unsigned int ch) +{ + UnikeyBufChars = sizeof(UnikeyBuf); + MyKbEngine.process(ch, UnikeyBackspaces, UnikeyBuf, UnikeyBufChars, UnikeyOutput); +} + +//-------------------------------------------- +void UnikeyPutChar(unsigned int ch) +{ + MyKbEngine.pass(ch); + UnikeyBufChars = 0; + UnikeyBackspaces = 0; +} + +//-------------------------------------------- +void UnikeyResetBuf() +{ + MyKbEngine.reset(); +} + +//-------------------------------------------- +void UnikeySetSingleMode() +{ + MyKbEngine.setSingleMode(); +} + +//-------------------------------------------- +void UnikeyBackspacePress() +{ + UnikeyBufChars = sizeof(UnikeyBuf); + MyKbEngine.processBackspace(UnikeyBackspaces, UnikeyBuf, UnikeyBufChars, UnikeyOutput); + // printf("Backspaces: %d\n",UnikeyBackspaces); +} + +//-------------------------------------------- +int UnikeyLoadMacroTable(const char *fileName) +{ + return pShMem->macStore.loadFromFile(fileName); +} + +//-------------------------------------------- +int UnikeyLoadUserKeyMap(const char *fileName) +{ + if (UkLoadKeyMap(fileName, pShMem->usrKeyMap)) { + //cout << "User key map loaded!\n"; //DEBUG + pShMem->usrKeyMapLoaded = 1; + return 1; + } + return 0; +} + +//-------------------------------------------- +void UnikeyRestoreKeyStrokes() +{ + UnikeyBufChars = sizeof(UnikeyBuf); + MyKbEngine.restoreKeyStrokes(UnikeyBackspaces, UnikeyBuf, UnikeyBufChars, UnikeyOutput); +} + +bool UnikeyAtWordBeginning() +{ + return MyKbEngine.atWordBeginning(); +} + diff --git a/unikey/unikey.h b/unikey/unikey.h new file mode 100644 index 0000000..d9bf39b --- /dev/null +++ b/unikey/unikey.h @@ -0,0 +1,118 @@ +// -*- coding:unix; mode:c++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- +/*------------------------------------------------------------------------------ +UniKey - Open-source Vietnamese Keyboard +Copyright (C) 2000-2005 Pham Kim Long +Contact: + unikey@gmail.com + http://unikey.org + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +--------------------------------------------------------------------------------*/ + +#ifndef __UNIKEY_H +#define __UNIKEY_H + +#include "keycons.h" + +/*---------------------------------------------------- +Initialization steps: + 1. UnikeySetup: This will initialized Unikey module, + with default options, input method = TELEX, output format = UTF-8 + 2. If you want a different settings: + + Call UnikeySetInputMethod to change input method + + Call UnikeySetOutputVIQR/UTF8 to chang output format + + Call UnikeySetOptions to change extra options + +Key event handling: + +- Call UnikeyFilter when a key event occurs, examine results in + + UnikeyBackspaces: number of backspaces that need to be sent + + UnikeyBufChars: number of chars in buffer that need to be sent + + UnikeyAnsiBuf: buffer containing output characters. + + UnikeyUniBuf: not used + + You should also call UnikeySetCapsState() before calling UnikeyFilter. + + To make this module portable across platforms, UnikeyFilter should not + be called on special keys: Enter, Tab, movement keys, delete, backspace... + +- Special events: + + Call UnikeyResetBuf to reset the engine's state in situations such as: + focus lost, movement keys: arrow keys, pgup, pgdown.... + + If a backspace is received, call UnikeyBackspacePress, + then examine the result: + UnikeyBackspaces is the number of backspaces actually required to + remove one character. + +Clean up: +- When the Engine is no longer needed, call UnikeyCleanup +------------------------------------------------------*/ + +#if defined(__cplusplus) +extern "C" { +#endif + extern unsigned char UnikeyBuf[]; + extern int UnikeyBackspaces; + extern int UnikeyBufChars; + extern UkOutputType UnikeyOutput; + + void UnikeySetup(); // always call this first + void UnikeyCleanup(); // call this when unloading unikey module + + // call this to reset Unikey's state when focus, context is changed or + // some control key is pressed + void UnikeyResetBuf(); + + // main handler, call every time a character input is received + void UnikeyFilter(unsigned int ch); + void UnikeyPutChar(unsigned int ch); // put new char without filtering + + // call this before UnikeyFilter for correctly processing some TELEX shortcuts + void UnikeySetCapsState(int shiftPressed, int CapsLockOn); + + // call this when backspace is pressed + void UnikeyBackspacePress(); + + // call this to restore to original key strokes + void UnikeyRestoreKeyStrokes(); + + //set extra options + void UnikeySetOptions(UnikeyOptions *pOpt); + void CreateDefaultUnikeyOptions(UnikeyOptions *pOpt); + + void UnikeyGetOptions(UnikeyOptions *pOpt); + + // set input method + // im: TELEX_INPUT, VNI_INPUT, VIQR_INPUT, VIQR_STAR_INPUT + void UnikeySetInputMethod(UkInputMethod im); + // set output format + // void UnikeySetOutputVIQR(); + // void UnikeySetOutputUTF8(); + int UnikeySetOutputCharset(int charset); + + int UnikeyLoadMacroTable(const char *fileName); + int UnikeyLoadUserKeyMap(const char *fileName); + + //call this to enable typing vietnamese even in a non-vn sequence + //e.g: GD&DDT,QDDND... + //The engine will return to normal mode when a word-break occurs. + void UnikeySetSingleMode(); + + bool UnikeyAtWordBeginning(); +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/unikey/usrkeymap.cpp b/unikey/usrkeymap.cpp new file mode 100644 index 0000000..46a2fee --- /dev/null +++ b/unikey/usrkeymap.cpp @@ -0,0 +1,267 @@ +// -*- mode:c++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- +/* Unikey Vietnamese Input Method + * Copyright (C) 2000-2005 Pham Kim Long + * Contact: + * unikey@gmail.com + * UniKey project: http://unikey.org + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +using namespace std; + +#include +#include "usrkeymap.h" + + +int getLabelIndex(int action); +void initKeyMap(int keyMap[256]); + +#define OPT_COMMENT_CHAR ';' + +struct UkEventLabelPair +{ + char label[32]; + int ev; +}; + +UkEventLabelPair UkEvLabelList[] = { + {"Tone0", vneTone0}, + {"Tone1", vneTone1}, + {"Tone2", vneTone2}, + {"Tone3", vneTone3}, + {"Tone4", vneTone4}, + {"Tone5", vneTone5}, + {"Roof-All", vneRoofAll}, + {"Roof-A", vneRoof_a}, + {"Roof-E", vneRoof_e}, + {"Roof-O", vneRoof_o}, + {"Hook-Bowl", vneHookAll}, + {"Hook-UO", vneHook_uo}, + {"Hook-U", vneHook_u}, + {"Hook-O", vneHook_o}, + {"Bowl", vneBowl}, + {"D-Mark", vneDd}, + {"Telex-W", vne_telex_w}, + {"Escape", vneEscChar}, + {"DD", vneCount + vnl_DD}, + {"dd", vneCount + vnl_dd}, + {"A^", vneCount + vnl_Ar}, + {"a^", vneCount + vnl_ar}, + {"A(", vneCount + vnl_Ab}, + {"a(", vneCount + vnl_ab}, + {"E^", vneCount + vnl_Er}, + {"e^", vneCount + vnl_er}, + {"O^", vneCount + vnl_Or}, + {"o^", vneCount + vnl_or}, + {"O+", vneCount + vnl_Oh}, + {"o+", vneCount + vnl_oh}, + {"U+", vneCount + vnl_Uh}, + {"u+", vneCount + vnl_uh} +}; + +const int UkEvLabelCount = sizeof(UkEvLabelList)/sizeof(UkEventLabelPair); + +//-------------------------------------------------- +static int parseNameValue(char *line, char **name, char **value) +{ + char *p, *mark; + char ch; + + if (line == 0) + return 0; + + // get rid of comment + p = strchr(line, OPT_COMMENT_CHAR); + if (p) + *p = 0; + + //get option name + for (p=line; *p == ' '; p++); + if (*p == 0) + return 0; + + *name = p; + mark = p; //mark the last non-space character + p++; + while ((ch=*p) != '=' && ch!=0) { + if (ch != ' ') + mark = p; + p++; + } + + if (ch == 0) + return 0; + *(mark+1) = 0; //terminate name with a null character + + //get option value + p++; + while (*p == ' ') p++; + if (*p == 0) + return 0; + + *value = p; + mark = p; + while (*p) { //strip trailing spaces + if (*p != ' ') + mark = p; + p++; + } + *++mark = 0; + return 1; +} + +//----------------------------------------------------- +DllExport int UkLoadKeyMap(const char *fileName, int keyMap[256]) +{ + int i, mapCount; + UkKeyMapPair orderMap[256]; + if (!UkLoadKeyOrderMap(fileName, orderMap, &mapCount)) + return 0; + + initKeyMap(keyMap); + for (i=0; i < mapCount; i++) { + keyMap[orderMap[i].key] = orderMap[i].action; + if (orderMap[i].action < vneCount) { + keyMap[tolower(orderMap[i].key)] = orderMap[i].action; + } + } + return 1; +} + +//------------------------------------------------------------------ +DllExport int UkLoadKeyOrderMap(const char *fileName, UkKeyMapPair *pMap, int *pMapCount) +{ + FILE *f; + char *buf; + char *name, *value; + size_t len; + int i, bufSize, lineCount; + unsigned char c; + int mapCount; + int keyMap[256]; + + f = fopen(fileName, "r"); + if (f == 0) { + cerr << "Failed to open file: " << fileName << endl; + return 0; + } + + initKeyMap(keyMap); + bufSize = 256; + buf = new char[bufSize]; + + lineCount = 0; + mapCount = 0; + while (!feof(f)) { + if (fgets((char *)buf, bufSize, f) == 0) + break; + lineCount++; + len = strlen(buf); + if (len == 0) + break; + + if (buf[len-1] == '\n') + buf[len-1] = 0; + if (parseNameValue(buf, (char **)&name, (char **)&value)) { + if (strlen(name) == 1) { + for (i=0; i < UkEvLabelCount; i++) { + if (strcmp(UkEvLabelList[i].label, value) == 0) { + c = (unsigned char)name[0]; + if (keyMap[c] != vneNormal) { + //already assigned, don't accept this map + break; + } + //cout << "key: " << c << " value: " << UkEvLabelList[i].ev << endl; //DEBUG + keyMap[c] = UkEvLabelList[i].ev; + pMap[mapCount].action = UkEvLabelList[i].ev; + if (keyMap[c] < vneCount) { + pMap[mapCount].key = toupper(c); + keyMap[toupper(c)] = UkEvLabelList[i].ev; + } + else { + pMap[mapCount].key = c; + } + mapCount++; + break; + } + } + if (i == UkEvLabelCount) { + cerr << "Error in user key layout, line " << lineCount << ": command not found" << endl; + } + } + else { + cerr << "Error in user key layout, line " << lineCount + << ": key name is not a single character" << endl; + } + } + } + delete [] buf; + fclose(f); + + *pMapCount = mapCount; + + return 1; +} + +//------------------------------------------- +void initKeyMap(int keyMap[256]) +{ + unsigned int c; + for (c=0; c<256; c++) + keyMap[c] = vneNormal; +} + +const char *UkKeyMapHeader = + "; This is UniKey user-defined key mapping file, generated from UniKey (Windows)\n\n"; + +DllExport int UkStoreKeyOrderMap(const char *fileName, UkKeyMapPair *pMap, int mapCount) +{ + FILE *f; + int i; + int labelIndex; + char line[128]; + + f = fopen(fileName, "wt"); + if (f == 0) { + cerr << "Failed to open file: " << fileName << endl; + return 0; + } + + fputs(UkKeyMapHeader, f); + for (i=0; i < mapCount; i++) { + labelIndex = getLabelIndex(pMap[i].action); + if (labelIndex != -1) { + sprintf(line, "%c = %s\n", pMap[i].key, UkEvLabelList[labelIndex].label); + fputs(line, f); + } + } + fclose(f); + return 1; +} + +int getLabelIndex(int event) +{ + int i; + for (i = 0; i < UkEvLabelCount; i++) { + if (UkEvLabelList[i].ev == event) + return i; + } + return -1; +} diff --git a/unikey/usrkeymap.h b/unikey/usrkeymap.h new file mode 100644 index 0000000..4dc8ec6 --- /dev/null +++ b/unikey/usrkeymap.h @@ -0,0 +1,37 @@ +// -*- coding:unix; mode:c++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- +/* Unikey Vietnamese Input Method + * Copyright (C) 2000-2005 Pham Kim Long + * Contact: + * unikey@gmail.com + * UniKey project: http://unikey.org + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __UNIKEY_USER_KEY_MAP_H +#define __UNIKEY_USER_KEY_MAP_H + +#include "inputproc.h" +struct UkKeyMapPair { + unsigned char key; + int action; +}; + +DllInterface int UkLoadKeyMap(const char *fileName, int keyMap[256]); +DllInterface int UkLoadKeyOrderMap(const char *fileName, UkKeyMapPair *pMap, int *pMapCount); +DllInterface int UkStoreKeyOrderMap(const char *fileName, UkKeyMapPair *pMap, int mapCount); + +#endif diff --git a/unikey/vnconv.h b/unikey/vnconv.h new file mode 100644 index 0000000..c94a72f --- /dev/null +++ b/unikey/vnconv.h @@ -0,0 +1,122 @@ +// -*- coding:unix; mode:c++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- +/*------------------------------------------------------------------------------ +VnConv: Vietnamese Encoding Converter Library +UniKey Project: http://unikey.sourceforge.net +Copyleft (C) 1998-2002 Pham Kim Long +Contact: longp@cslab.felk.cvut.cz + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +--------------------------------------------------------------------------------*/ + +// +#ifndef __VN_CONVERT_H +#define __VN_CONVERT_H + +#if defined(_WIN32) + #if defined(UNIKEYHOOK) + #define DllInterface __declspec( dllexport ) + #else + #define DllInterface __declspec( dllimport ) + #endif + #define DllExport __declspec( dllexport ) + #define DllImport __declspec( dllimport ) +#else + #define DllInterface //not used + #define DllExport + #define DllImport +#endif + +#define CONV_CHARSET_UNICODE 0 +#define CONV_CHARSET_UNIUTF8 1 +#define CONV_CHARSET_UNIREF 2 //&#D; +#define CONV_CHARSET_UNIREF_HEX 3 +#define CONV_CHARSET_UNIDECOMPOSED 4 +#define CONV_CHARSET_WINCP1258 5 +#define CONV_CHARSET_UNI_CSTRING 6 +#define CONV_CHARSET_VNSTANDARD 7 + +#define CONV_CHARSET_VIQR 10 +#define CONV_CHARSET_UTF8VIQR 11 +#define CONV_CHARSET_XUTF8 12 + +#define CONV_CHARSET_TCVN3 20 +#define CONV_CHARSET_VPS 21 +#define CONV_CHARSET_VISCII 22 +#define CONV_CHARSET_BKHCM1 23 +#define CONV_CHARSET_VIETWAREF 24 +#define CONV_CHARSET_ISC 25 + +#define CONV_CHARSET_VNIWIN 40 +#define CONV_CHARSET_BKHCM2 41 +#define CONV_CHARSET_VIETWAREX 42 +#define CONV_CHARSET_VNIMAC 43 + +#define CONV_TOTAL_SINGLE_CHARSETS 6 +#define CONV_TOTAL_DOUBLE_CHARSETS 4 + + +#define IS_SINGLE_BYTE_CHARSET(x) (x >= CONV_CHARSET_TCVN3 && x < CONV_CHARSET_TCVN3+CONV_TOTAL_SINGLE_CHARSETS) +#define IS_DOUBLE_BYTE_CHARSET(x) (x >= CONV_CHARSET_VNIWIN && x < CONV_CHARSET_VNIWIN+CONV_TOTAL_DOUBLE_CHARSETS) + +typedef unsigned char UKBYTE; + +#if defined(__cplusplus) +extern "C" { +#endif +DllInterface int VnConvert(int inCharset, int outCharset, UKBYTE *input, UKBYTE *output, + int * pInLen, int * pMaxOutLen); + +DllInterface int VnFileConvert(int inCharset, int outCharset, const char *inFile, const char *outFile); + +#if defined(__cplusplus) +} +#endif + +DllInterface const char * VnConvErrMsg(int errCode); + +enum VnConvError { + VNCONV_NO_ERROR, + VNCONV_UNKNOWN_ERROR, + VNCONV_INVALID_CHARSET, + VNCONV_ERR_INPUT_FILE, + VNCONV_ERR_OUTPUT_FILE, + VNCONV_OUT_OF_MEMORY, + VNCONV_ERR_WRITING, + VNCONV_LAST_ERROR +}; + +typedef struct _CharsetNameId CharsetNameId; + +struct _CharsetNameId { + const char *name; + int id; +}; + +typedef struct _VnConvOptions VnConvOptions; + +struct _VnConvOptions { + int viqrMixed; + int viqrEsc; + int toUpper; + int toLower; + int removeTone; + int smartViqr; +}; + +DllInterface void VnConvSetOptions(VnConvOptions *pOptions); +DllInterface void VnConvGetOptions(VnConvOptions *pOptions); +DllInterface void VnConvResetOptions(VnConvOptions *pOptions); + +#endif diff --git a/unikey/vnlexi.h b/unikey/vnlexi.h new file mode 100644 index 0000000..8724013 --- /dev/null +++ b/unikey/vnlexi.h @@ -0,0 +1,162 @@ +// -*- coding:unix; mode:c++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- +/* Unikey Vietnamese Input Method + * Copyright (C) 2000-2005 Pham Kim Long + * Contact: + * unikey@gmail.com + * UniKey project: http://unikey.org + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __VN_LEXI_H +#define __VN_LEXI_H + +enum VnLexiName { + vnl_nonVnChar = -1, + vnl_A, vnl_a, vnl_A1, vnl_a1, vnl_A2, vnl_a2, vnl_A3, vnl_a3, vnl_A4, vnl_a4, vnl_A5, vnl_a5, + vnl_Ar, vnl_ar, vnl_Ar1, vnl_ar1, vnl_Ar2, vnl_ar2, vnl_Ar3, vnl_ar3, vnl_Ar4, vnl_ar4, vnl_Ar5, vnl_ar5, + vnl_Ab, vnl_ab, vnl_Ab1, vnl_ab1, vnl_Ab2, vnl_ab2, vnl_Ab3, vnl_ab3, vnl_Ab4, vnl_ab4, vnl_Ab5, vnl_ab5, + vnl_B, vnl_b, vnl_C, vnl_c, + vnl_D, vnl_d, vnl_DD, vnl_dd, + vnl_E, vnl_e, vnl_E1, vnl_e1, vnl_E2, vnl_e2, vnl_E3, vnl_e3, vnl_E4, vnl_e4, vnl_E5, vnl_e5, + vnl_Er, vnl_er, vnl_Er1, vnl_er1, vnl_Er2, vnl_er2, vnl_Er3, vnl_er3, vnl_Er4, vnl_er4, vnl_Er5, vnl_er5, + vnl_F, vnl_f, vnl_G, vnl_g, vnl_H, vnl_h, + vnl_I, vnl_i, vnl_I1, vnl_i1, vnl_I2, vnl_i2, vnl_I3, vnl_i3, vnl_I4, vnl_i4, vnl_I5, vnl_i5, + vnl_J, vnl_j, vnl_K, vnl_k, vnl_L, vnl_l, vnl_M, vnl_m, vnl_N, vnl_n, + vnl_O, vnl_o, vnl_O1, vnl_o1, vnl_O2, vnl_o2, vnl_O3, vnl_o3, vnl_O4, vnl_o4, vnl_O5, vnl_o5, + vnl_Or, vnl_or, vnl_Or1, vnl_or1, vnl_Or2, vnl_or2, vnl_Or3, vnl_or3, vnl_Or4, vnl_or4, vnl_Or5, vnl_or5, + vnl_Oh, vnl_oh, vnl_Oh1, vnl_oh1, vnl_Oh2, vnl_oh2, vnl_Oh3, vnl_oh3, vnl_Oh4, vnl_oh4, vnl_Oh5, vnl_oh5, + vnl_P, vnl_p, vnl_Q, vnl_q, vnl_R, vnl_r, vnl_S, vnl_s, vnl_T, vnl_t, + vnl_U, vnl_u, vnl_U1, vnl_u1, vnl_U2, vnl_u2, vnl_U3, vnl_u3, vnl_U4, vnl_u4, vnl_U5, vnl_u5, + vnl_Uh, vnl_uh, vnl_Uh1, vnl_uh1, vnl_Uh2, vnl_uh2, vnl_Uh3, vnl_uh3, vnl_Uh4, vnl_uh4, vnl_Uh5, vnl_uh5, + vnl_V, vnl_v, vnl_W, vnl_w, vnl_X, vnl_x, + vnl_Y, vnl_y, vnl_Y1, vnl_y1, vnl_Y2, vnl_y2, vnl_Y3, vnl_y3, vnl_Y4, vnl_y4, vnl_Y5, vnl_y5, + vnl_Z, vnl_z, + + vnl_lastChar, +}; + +enum VowelSeq { + vs_nil = -1, + vs_a, + vs_ar, + vs_ab, + vs_e, + vs_er, + vs_i, + vs_o, + vs_or, + vs_oh, + vs_u, + vs_uh, + vs_y, + vs_ai, + vs_ao, + vs_au, + vs_ay, + vs_aru, + vs_ary, + vs_eo, + vs_eu, + vs_eru, + vs_ia, + vs_ie, + vs_ier, + vs_iu, + vs_oa, + vs_oab, + vs_oe, + vs_oi, + vs_ori, + vs_ohi, + vs_ua, + vs_uar, + vs_ue, + vs_uer, + vs_ui, + vs_uo, + vs_uor, + vs_uoh, + vs_uu, + vs_uy, + vs_uha, + vs_uhi, + vs_uho, + vs_uhoh, + vs_uhu, + vs_ye, + vs_yer, + vs_ieu, + vs_ieru, + vs_oai, + vs_oay, + vs_oeo, + vs_uay, + vs_uary, + vs_uoi, + vs_uou, + vs_uori, + vs_uohi, + vs_uohu, + vs_uya, + vs_uye, + vs_uyer, + vs_uyu, + vs_uhoi, + vs_uhou, + vs_uhohi, + vs_uhohu, + vs_yeu, + vs_yeru +}; + +enum ConSeq { + cs_nil = -1, + cs_b, + cs_c, + cs_ch, + cs_d, + cs_dd, + cs_dz, + cs_g, + cs_gh, + cs_gi, + cs_gin, + cs_h, + cs_k, + cs_kh, + cs_l, + cs_m, + cs_n, + cs_ng, + cs_ngh, + cs_nh, + cs_p, + cs_ph, + cs_q, + cs_qu, + cs_r, + cs_s, + cs_t, + cs_th, + cs_tr, + cs_v, + cs_x +}; + + + +#endif