diff --git a/LICENSE b/LICENSE
new file mode 100644
index 000000000..94a9ed024
--- /dev/null
+++ b/LICENSE
@@ -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/PyWeasel/PyWeasel.cpp b/PyWeasel/PyWeasel.cpp
new file mode 100644
index 000000000..edbbaede9
--- /dev/null
+++ b/PyWeasel/PyWeasel.cpp
@@ -0,0 +1,133 @@
+#include "stdafx.h"
+#include
+
+PyWeaselHandler::PyWeaselHandler()
+{
+}
+
+PyWeaselHandler::~PyWeaselHandler()
+{
+}
+
+void PyWeaselHandler::Initialize()
+{
+ // 初始化Python解释器, 有必要在PyWeaselHandler创建之前调用
+ Py_Initialize();
+ try
+ {
+ python::object module = python::import("engine.weasel");
+ m_service = module.attr("service");
+ }
+ catch (python::error_already_set e)
+ {
+ python::handle_exception();
+ }
+
+ if (m_service.is_none())
+ {
+ throw std::exception("weasel service not found!");
+ }
+}
+
+void PyWeaselHandler::Finalize()
+{
+ try
+ {
+ m_service.attr("cleanup")();
+ }
+ catch (python::error_already_set e)
+ {
+ }
+ // Boost.Python doesn't support Py_Finalize yet, so don't call it!
+}
+
+UINT PyWeaselHandler::FindSession(UINT sessionID)
+{
+ bool found = false;
+ try
+ {
+ found = python::extract(m_service.attr("has_session")(sessionID));
+ }
+ catch (python::error_already_set e)
+ {
+ return 0;
+ }
+ return found ? sessionID : 0;
+}
+
+UINT PyWeaselHandler::AddSession(LPWSTR buffer)
+{
+ UINT id = 0;
+ try
+ {
+ id = python::extract(m_service.attr("create_session")());
+ if (!id)
+ {
+ return 0;
+ }
+ python::object session = m_service.attr("get_session")(id);
+ if (session.is_none())
+ {
+ return 0;
+ }
+ wstring resp = python::extract(session.attr("get_response")());
+ _Respond(buffer, resp);
+
+ }
+ catch (python::error_already_set e)
+ {
+ return 0;
+ }
+
+ return id;
+}
+
+UINT PyWeaselHandler::RemoveSession(UINT sessionID)
+{
+ bool done = false;
+ try
+ {
+ done = python::extract(m_service.attr("destroy_session")(sessionID));
+ }
+ catch (python::error_already_set e)
+ {
+ return 0;
+ }
+ return done ? sessionID : 0;
+}
+
+BOOL PyWeaselHandler::ProcessKeyEvent(weasel::KeyEvent keyEvent, UINT sessionID, LPWSTR buffer)
+{
+ bool taken = false;
+ try
+ {
+ python::object session = m_service.attr("get_session")(sessionID);
+ if (session.is_none())
+ {
+ return FALSE;
+ }
+
+ taken = python::extract(session.attr("process_key_event")(keyEvent.keycode, keyEvent.mask));
+ wstring resp = python::extract(session.attr("get_response")());
+ _Respond(buffer, resp);
+ }
+ catch (python::error_already_set e)
+ {
+ return FALSE;
+ }
+
+ return (BOOL)taken;
+}
+
+bool PyWeaselHandler::_Respond(LPWSTR buffer, wstring const& msg)
+{
+ memset(buffer, 0, WEASEL_IPC_BUFFER_SIZE);
+ wbufferstream bs(buffer, WEASEL_IPC_BUFFER_LENGTH);
+ bs << msg;
+ if (!bs.good())
+ {
+ // response text toooo long!
+ return false;
+ }
+ return true;
+}
diff --git a/PyWeasel/PyWeasel.vcproj b/PyWeasel/PyWeasel.vcproj
new file mode 100644
index 000000000..f38010724
--- /dev/null
+++ b/PyWeasel/PyWeasel.vcproj
@@ -0,0 +1,284 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/PyWeasel/ReadMe.txt b/PyWeasel/ReadMe.txt
new file mode 100644
index 000000000..f94e4584d
--- /dev/null
+++ b/PyWeasel/ReadMe.txt
@@ -0,0 +1,30 @@
+========================================================================
+ STATIC LIBRARY : PyWeasel Project Overview
+========================================================================
+
+AppWizard has created this PyWeasel library project for you.
+
+This file contains a summary of what you will find in each of the files that
+make up your PyWeasel application.
+
+
+PyWeasel.vcproj
+ This is the main project file for VC++ projects generated using an Application Wizard.
+ It contains information about the version of Visual C++ that generated the file, and
+ information about the platforms, configurations, and project features selected with the
+ Application Wizard.
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+StdAfx.h, StdAfx.cpp
+ These files are used to build a precompiled header (PCH) file
+ named PyWeasel.pch and a precompiled types file named StdAfx.obj.
+
+/////////////////////////////////////////////////////////////////////////////
+Other notes:
+
+AppWizard uses "TODO:" comments to indicate parts of the source code you
+should add to or customize.
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/PyWeasel/stdafx.cpp b/PyWeasel/stdafx.cpp
new file mode 100644
index 000000000..da2d33ebe
--- /dev/null
+++ b/PyWeasel/stdafx.cpp
@@ -0,0 +1,8 @@
+// stdafx.cpp : source file that includes just the standard includes
+// PyWeasel.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
diff --git a/PyWeasel/stdafx.h b/PyWeasel/stdafx.h
new file mode 100644
index 000000000..52eef3317
--- /dev/null
+++ b/PyWeasel/stdafx.h
@@ -0,0 +1,23 @@
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#pragma once
+
+#include "targetver.h"
+
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+
+#include
+
+#pragma warning(disable : 4819)
+
+#include
+#include
+
+#pragma warning(default : 4819)
+
+using namespace std;
+using boost::interprocess::wbufferstream;
+namespace python = boost::python;
diff --git a/PyWeasel/targetver.h b/PyWeasel/targetver.h
new file mode 100644
index 000000000..a38195a4e
--- /dev/null
+++ b/PyWeasel/targetver.h
@@ -0,0 +1,13 @@
+#pragma once
+
+// The following macros define the minimum required platform. The minimum required platform
+// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run
+// your application. The macros work by enabling all features available on platform versions up to and
+// including the version specified.
+
+// Modify the following defines if you have to target a platform prior to the ones specified below.
+// Refer to MSDN for the latest info on corresponding values for different platforms.
+#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista.
+#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows.
+#endif
+
diff --git a/ReadMe.txt b/ReadMe.txt
new file mode 100644
index 000000000..b40c9fb03
--- /dev/null
+++ b/ReadMe.txt
@@ -0,0 +1,49 @@
+developer notice:
+
+build boost libraries with msvc toolset (see boost documentation);
+
+then
+
+copy \boost\* to $(SolutionDir)\include\boost;
+copy \stage\lib\* to $(SolutionDir)\lib;
+copy X:\Python27\include\* to $(SolutionDir)\include\python;
+copy X:\Python27\libs\* to $(SolutionDir)\lib\python;
+
+or, alternatively
+
+add boost home path and Python include path to:
+Visual Studio Options > Projects and Solutions > VC++ Directories > Include files;
+add \stage\lib and X:\Python27\libs to:
+Visual Studio Options > Projects and Solutions > VC++ Directories > Library files;
+
+voila!
+
+now, make a release build, and run $(SolutionDir)\release.bat.
+the product will be place in $(SolutionDir)\output.
+
+
+usage:
+
+0. before you go...
+
+install Python 2.7;
+
+set Python path in $(WeaselRoot)\env.bat;
+in this case, $(WeaselRoot) refers to the directory $(SolutionDir)\output\weasel.
+
+issue the command populate-db.bat in $(SolutionDir)\data
+in case you never had a database at %UserProfile%\.ibus\zime\zime.db.
+if you don't, you will be noticed a message "NO SCHEMA" (in Chinese) once the IME is activated.
+
+1. to install...
+
+install.bat
+
+2. to uninstall...
+
+uninstall.bat
+
+stop_service.bat
+you may use this to terminate the service process.
+
+
diff --git a/WeaselIME/Imm.h b/WeaselIME/Imm.h
new file mode 100644
index 000000000..d7c38f777
--- /dev/null
+++ b/WeaselIME/Imm.h
@@ -0,0 +1,896 @@
+/**********************************************************************/
+/* IMM.H - Input Method Manager definitions */
+/* */
+/* Copyright (c) 1993-1995 Microsoft Corporation */
+/**********************************************************************/
+
+#ifndef _IMM_
+#define _IMM_ // defined if IMM.H has been included
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _WINUSER_
+#define VK_PROCESSKEY 0x0E5
+#endif
+
+#ifndef WINVER
+#define WINVER 0x040A
+#endif
+
+#if(WINVER >= 0x040A)
+DECLARE_HANDLE(HIMC);
+#else
+typedef DWORD HIMC;
+#endif
+
+#if(WINVER >= 0x040A)
+DECLARE_HANDLE(HIMCC);
+#else
+typedef DWORD HIMCC;
+#endif
+
+typedef HKL FAR *LPHKL;
+typedef UINT FAR *LPUINT;
+
+#define NULLIMC ((HIMC)0)
+
+typedef struct tagCOMPOSITIONFORM {
+ DWORD dwStyle;
+ POINT ptCurrentPos;
+ RECT rcArea;
+} COMPOSITIONFORM, *PCOMPOSITIONFORM, NEAR *NPCOMPOSITIONFORM, FAR *LPCOMPOSITIONFORM;
+
+typedef struct tagCANDIDATEFORM {
+ DWORD dwIndex;
+ DWORD dwStyle;
+ POINT ptCurrentPos;
+ RECT rcArea;
+} CANDIDATEFORM, *PCANDIDATEFORM, NEAR *NPCANDIDATEFORM, FAR *LPCANDIDATEFORM;
+
+typedef struct tagCOMPOSITIONSTRING {
+ DWORD dwSize;
+ DWORD dwCompReadAttrLen;
+ DWORD dwCompReadAttrOffset;
+ DWORD dwCompReadClauseLen;
+ DWORD dwCompReadClauseOffset;
+ DWORD dwCompReadStrLen;
+ DWORD dwCompReadStrOffset;
+ DWORD dwCompAttrLen;
+ DWORD dwCompAttrOffset;
+ DWORD dwCompClauseLen;
+ DWORD dwCompClauseOffset;
+ DWORD dwCompStrLen;
+ DWORD dwCompStrOffset;
+ DWORD dwCursorPos;
+ DWORD dwDeltaStart;
+ DWORD dwResultReadClauseLen;
+ DWORD dwResultReadClauseOffset;
+ DWORD dwResultReadStrLen;
+ DWORD dwResultReadStrOffset;
+ DWORD dwResultClauseLen;
+ DWORD dwResultClauseOffset;
+ DWORD dwResultStrLen;
+ DWORD dwResultStrOffset;
+ DWORD dwPrivateSize;
+ DWORD dwPrivateOffset;
+} COMPOSITIONSTRING, *PCOMPOSITIONSTRING, NEAR *NPCOMPOSITIONSTRING, FAR *LPCOMPOSITIONSTRING;
+
+
+typedef struct tagGUIDELINE {
+ DWORD dwSize;
+ DWORD dwLevel;
+ DWORD dwIndex;
+ DWORD dwStrLen;
+ DWORD dwStrOffset;
+ DWORD dwPrivateSize;
+ DWORD dwPrivateOffset;
+} GUIDELINE, *PGUIDELINE, NEAR *NPGUIDELINE, FAR *LPGUIDELINE;
+
+
+typedef struct tagCANDIDATELIST {
+ DWORD dwSize;
+ DWORD dwStyle;
+ DWORD dwCount;
+ DWORD dwSelection;
+ DWORD dwPageStart;
+ DWORD dwPageSize;
+ DWORD dwOffset[1];
+} CANDIDATELIST, *PCANDIDATELIST, NEAR *NPCANDIDATELIST, FAR *LPCANDIDATELIST;
+
+typedef struct tagREGISTERWORDA {
+ LPSTR lpReading;
+ LPSTR lpWord;
+} REGISTERWORDA, *PREGISTERWORDA, NEAR *NPREGISTERWORDA, FAR *LPREGISTERWORDA;
+typedef struct tagREGISTERWORDW {
+ LPWSTR lpReading;
+ LPWSTR lpWord;
+} REGISTERWORDW, *PREGISTERWORDW, NEAR *NPREGISTERWORDW, FAR *LPREGISTERWORDW;
+#ifdef UNICODE
+typedef REGISTERWORDW REGISTERWORD;
+typedef PREGISTERWORDW PREGISTERWORD;
+typedef NPREGISTERWORDW NPREGISTERWORD;
+typedef LPREGISTERWORDW LPREGISTERWORD;
+#else
+typedef REGISTERWORDA REGISTERWORD;
+typedef PREGISTERWORDA PREGISTERWORD;
+typedef NPREGISTERWORDA NPREGISTERWORD;
+typedef LPREGISTERWORDA LPREGISTERWORD;
+#endif // UNICODE
+
+#if(WINVER >= 0x040A)
+typedef struct tagRECONVERTSTRING {
+ DWORD dwSize;
+ DWORD dwVersion;
+ DWORD dwStrLen;
+ DWORD dwStrOffset;
+ DWORD dwCompStrLen;
+ DWORD dwCompStrOffset;
+ DWORD dwTargetStrLen;
+ DWORD dwTargetStrOffset;
+} RECONVERTSTRING, *PRECONVERTSTRING, NEAR *NPRECONVERTSTRING, FAR *LPRECONVERTSTRING;
+#endif
+
+typedef struct tagCANDIDATEINFO {
+ DWORD dwSize;
+ DWORD dwCount;
+ DWORD dwOffset[32];
+ DWORD dwPrivateSize;
+ DWORD dwPrivateOffset;
+} CANDIDATEINFO, *PCANDIDATEINFO, NEAR *NPCANDIDATEINFO, FAR *LPCANDIDATEINFO;
+
+
+typedef struct tagINPUTCONTEXT {
+ HWND hWnd;
+ BOOL fOpen;
+ POINT ptStatusWndPos;
+ POINT ptSoftKbdPos;
+ DWORD fdwConversion;
+ DWORD fdwSentence;
+ union {
+ LOGFONTA A;
+ LOGFONTW W;
+ } lfFont;
+ COMPOSITIONFORM cfCompForm;
+ CANDIDATEFORM cfCandForm[4];
+ HIMCC hCompStr;
+ HIMCC hCandInfo;
+ HIMCC hGuideLine;
+ HIMCC hPrivate;
+ DWORD dwNumMsgBuf;
+ HIMCC hMsgBuf;
+ DWORD fdwInit;
+ DWORD dwReserve[3];
+} INPUTCONTEXT, *PINPUTCONTEXT, NEAR *NPINPUTCONTEXT, FAR *LPINPUTCONTEXT;
+
+
+typedef struct tagIMEINFO {
+ DWORD dwPrivateDataSize;
+ DWORD fdwProperty;
+ DWORD fdwConversionCaps;
+ DWORD fdwSentenceCaps;
+ DWORD fdwUICaps;
+ DWORD fdwSCSCaps;
+ DWORD fdwSelectCaps;
+} IMEINFO, *PIMEINFO, NEAR *NPIMEINFO, FAR *LPIMEINFO;
+
+
+#define STYLE_DESCRIPTION_SIZE 32
+
+typedef struct tagSTYLEBUFA {
+ DWORD dwStyle;
+ CHAR szDescription[STYLE_DESCRIPTION_SIZE];
+} STYLEBUFA, *PSTYLEBUFA, NEAR *NPSTYLEBUFA, FAR *LPSTYLEBUFA;
+typedef struct tagSTYLEBUFW {
+ DWORD dwStyle;
+ WCHAR szDescription[STYLE_DESCRIPTION_SIZE];
+} STYLEBUFW, *PSTYLEBUFW, NEAR *NPSTYLEBUFW, FAR *LPSTYLEBUFW;
+#ifdef UNICODE
+typedef STYLEBUFW STYLEBUF;
+typedef PSTYLEBUFW PSTYLEBUF;
+typedef NPSTYLEBUFW NPSTYLEBUF;
+typedef LPSTYLEBUFW LPSTYLEBUF;
+#else
+typedef STYLEBUFA STYLEBUF;
+typedef PSTYLEBUFA PSTYLEBUF;
+typedef NPSTYLEBUFA NPSTYLEBUF;
+typedef LPSTYLEBUFA LPSTYLEBUF;
+#endif // UNICODE
+
+#if(WINVER >= 0x040A)
+#define IMEMENUITEM_STRING_SIZE 80
+
+typedef struct tagIMEMENUITEMINFOA {
+ UINT cbSize;
+ UINT fType;
+ UINT fState;
+ UINT wID;
+ HBITMAP hbmpChecked;
+ HBITMAP hbmpUnchecked;
+ DWORD dwItemData;
+ CHAR szString[IMEMENUITEM_STRING_SIZE];
+ HBITMAP hbmpItem;
+} IMEMENUITEMINFOA, *PIMEMENUITEMINFOA, NEAR *NPIMEMENUITEMINFOA, FAR *LPIMEMENUITEMINFOA;
+typedef struct tagIMEMENUITEMINFOW {
+ UINT cbSize;
+ UINT fType;
+ UINT fState;
+ UINT wID;
+ HBITMAP hbmpChecked;
+ HBITMAP hbmpUnchecked;
+ DWORD dwItemData;
+ WCHAR szString[IMEMENUITEM_STRING_SIZE];
+ HBITMAP hbmpItem;
+} IMEMENUITEMINFOW, *PIMEMENUITEMINFOW, NEAR *NPIMEMENUITEMINFOW, FAR *LPIMEMENUITEMINFOW;
+#ifdef UNICODE
+typedef IMEMENUITEMINFOW IMEMENUITEMINFO;
+typedef PIMEMENUITEMINFOW PIMEMENUITEMINFO;
+typedef NPIMEMENUITEMINFOW NPIMEMENUITEMINFO;
+typedef LPIMEMENUITEMINFOW LPIMEMENUITEMINFO;
+#else
+typedef IMEMENUITEMINFOA IMEMENUITEMINFO;
+typedef PIMEMENUITEMINFOA PIMEMENUITEMINFO;
+typedef NPIMEMENUITEMINFOA NPIMEMENUITEMINFO;
+typedef LPIMEMENUITEMINFOA LPIMEMENUITEMINFO;
+#endif // UNICODE
+
+typedef struct tagIMECHARPOSITION {
+ DWORD dwSize;
+ DWORD dwCharPos;
+ POINT pt;
+ UINT cLineHeight;
+ RECT rcDocument;
+} IMECHARPOSITION, *PIMECHARPOSITION, NEAR *NPIMECHARPOSITION, FAR *LPIMECHARPOSITION;
+
+#endif /* WINVER >= 0x040A */
+
+typedef struct tagSOFTKBDDATA {
+ UINT uCount;
+ WORD wCode[1][256];
+} SOFTKBDDATA, *PSOFTKBDDATA, NEAR *NPSOFTKBDDATA, FAR * LPSOFTKBDDATA;
+
+
+// prototype of IMM API
+
+HKL WINAPI ImmInstallIMEA(LPCSTR lpszIMEFileName, LPCSTR lpszLayoutText);
+HKL WINAPI ImmInstallIMEW(LPCWSTR lpszIMEFileName, LPCWSTR lpszLayoutText);
+#ifdef UNICODE
+#define ImmInstallIME ImmInstallIMEW
+#else
+#define ImmInstallIME ImmInstallIMEA
+#endif // !UNICODE
+
+HWND WINAPI ImmGetDefaultIMEWnd(HWND);
+
+UINT WINAPI ImmGetDescriptionA(HKL, LPSTR, UINT uBufLen);
+UINT WINAPI ImmGetDescriptionW(HKL, LPWSTR, UINT uBufLen);
+#ifdef UNICODE
+#define ImmGetDescription ImmGetDescriptionW
+#else
+#define ImmGetDescription ImmGetDescriptionA
+#endif // !UNICODE
+
+UINT WINAPI ImmGetIMEFileNameA(HKL, LPSTR, UINT uBufLen);
+UINT WINAPI ImmGetIMEFileNameW(HKL, LPWSTR, UINT uBufLen);
+#ifdef UNICODE
+#define ImmGetIMEFileName ImmGetIMEFileNameW
+#else
+#define ImmGetIMEFileName ImmGetIMEFileNameA
+#endif // !UNICODE
+
+DWORD WINAPI ImmGetProperty(HKL, DWORD);
+
+BOOL WINAPI ImmIsIME(HKL);
+
+BOOL WINAPI ImmGetHotKey(DWORD, LPUINT, LPUINT, LPHKL);
+BOOL WINAPI ImmSetHotKey(DWORD, UINT, UINT, HKL);
+BOOL WINAPI ImmSimulateHotKey(HWND, DWORD);
+
+HIMC WINAPI ImmCreateContext(void);
+BOOL WINAPI ImmDestroyContext(HIMC);
+HIMC WINAPI ImmGetContext(HWND);
+BOOL WINAPI ImmReleaseContext(HWND, HIMC);
+HIMC WINAPI ImmAssociateContext(HWND, HIMC);
+#if(WINVER >= 0x040A)
+BOOL WINAPI ImmAssociateContextEx(HWND, HIMC, DWORD);
+#endif /* WINVER >= 0x040A */
+
+LONG WINAPI ImmGetCompositionStringA(HIMC, DWORD, LPVOID, DWORD);
+LONG WINAPI ImmGetCompositionStringW(HIMC, DWORD, LPVOID, DWORD);
+#ifdef UNICODE
+#define ImmGetCompositionString ImmGetCompositionStringW
+#else
+#define ImmGetCompositionString ImmGetCompositionStringA
+#endif // !UNICODE
+
+BOOL WINAPI ImmSetCompositionStringA(HIMC, DWORD, LPCVOID, DWORD, LPCVOID, DWORD);
+BOOL WINAPI ImmSetCompositionStringW(HIMC, DWORD, LPCVOID, DWORD, LPCVOID, DWORD);
+#ifdef UNICODE
+#define ImmSetCompositionString ImmSetCompositionStringW
+#else
+#define ImmSetCompositionString ImmSetCompositionStringA
+#endif // !UNICODE
+
+DWORD WINAPI ImmGetCandidateListCountA(HIMC, LPDWORD);
+DWORD WINAPI ImmGetCandidateListCountW(HIMC, LPDWORD);
+#ifdef UNICODE
+#define ImmGetCandidateListCount ImmGetCandidateListCountW
+#else
+#define ImmGetCandidateListCount ImmGetCandidateListCountA
+#endif // !UNICODE
+
+DWORD WINAPI ImmGetCandidateListA(HIMC, DWORD, LPCANDIDATELIST, DWORD);
+DWORD WINAPI ImmGetCandidateListW(HIMC, DWORD, LPCANDIDATELIST, DWORD);
+#ifdef UNICODE
+#define ImmGetCandidateList ImmGetCandidateListW
+#else
+#define ImmGetCandidateList ImmGetCandidateListA
+#endif // !UNICODE
+
+DWORD WINAPI ImmGetGuideLineA(HIMC, DWORD, LPSTR, DWORD);
+DWORD WINAPI ImmGetGuideLineW(HIMC, DWORD, LPWSTR, DWORD);
+#ifdef UNICODE
+#define ImmGetGuideLine ImmGetGuideLineW
+#else
+#define ImmGetGuideLine ImmGetGuideLineA
+#endif // !UNICODE
+
+BOOL WINAPI ImmGetConversionStatus(HIMC, LPDWORD, LPDWORD);
+BOOL WINAPI ImmSetConversionStatus(HIMC, DWORD, DWORD);
+BOOL WINAPI ImmGetOpenStatus(HIMC);
+BOOL WINAPI ImmSetOpenStatus(HIMC, BOOL);
+
+BOOL WINAPI ImmGetCompositionFontA(HIMC, LPLOGFONTA);
+BOOL WINAPI ImmGetCompositionFontW(HIMC, LPLOGFONTW);
+#ifdef UNICODE
+#define ImmGetCompositionFont ImmGetCompositionFontW
+#else
+#define ImmGetCompositionFont ImmGetCompositionFontA
+#endif // !UNICODE
+
+BOOL WINAPI ImmSetCompositionFontA(HIMC, LPLOGFONTA);
+BOOL WINAPI ImmSetCompositionFontW(HIMC, LPLOGFONTW);
+#ifdef UNICODE
+#define ImmSetCompositionFont ImmSetCompositionFontW
+#else
+#define ImmSetCompositionFont ImmSetCompositionFontA
+#endif // !UNICODE
+
+BOOL WINAPI ImmConfigureIMEA(HKL, HWND, DWORD, LPVOID);
+BOOL WINAPI ImmConfigureIMEW(HKL, HWND, DWORD, LPVOID);
+#ifdef UNICODE
+#define ImmConfigureIME ImmConfigureIMEW
+#else
+#define ImmConfigureIME ImmConfigureIMEA
+#endif // !UNICODE
+
+LRESULT WINAPI ImmEscapeA(HKL, HIMC, UINT, LPVOID);
+LRESULT WINAPI ImmEscapeW(HKL, HIMC, UINT, LPVOID);
+#ifdef UNICODE
+#define ImmEscape ImmEscapeW
+#else
+#define ImmEscape ImmEscapeA
+#endif // !UNICODE
+
+DWORD WINAPI ImmGetConversionListA(HKL, HIMC, LPCSTR, LPCANDIDATELIST, DWORD, UINT);
+DWORD WINAPI ImmGetConversionListW(HKL, HIMC, LPCWSTR, LPCANDIDATELIST, DWORD, UINT);
+#ifdef UNICODE
+#define ImmGetConversionList ImmGetConversionListW
+#else
+#define ImmGetConversionList ImmGetConversionListA
+#endif // !UNICODE
+
+BOOL WINAPI ImmNotifyIME(HIMC, DWORD, DWORD, DWORD);
+
+BOOL WINAPI ImmGetStatusWindowPos(HIMC, LPPOINT);
+BOOL WINAPI ImmSetStatusWindowPos(HIMC, LPPOINT);
+BOOL WINAPI ImmGetCompositionWindow(HIMC, LPCOMPOSITIONFORM);
+BOOL WINAPI ImmSetCompositionWindow(HIMC, LPCOMPOSITIONFORM);
+BOOL WINAPI ImmGetCandidateWindow(HIMC, DWORD, LPCANDIDATEFORM);
+BOOL WINAPI ImmSetCandidateWindow(HIMC, LPCANDIDATEFORM);
+
+BOOL WINAPI ImmIsUIMessageA(HWND, UINT, WPARAM, LPARAM);
+BOOL WINAPI ImmIsUIMessageW(HWND, UINT, WPARAM, LPARAM);
+#ifdef UNICODE
+#define ImmIsUIMessage ImmIsUIMessageW
+#else
+#define ImmIsUIMessage ImmIsUIMessageA
+#endif // !UNICODE
+
+BOOL WINAPI ImmGenerateMessage(HIMC);
+UINT WINAPI ImmGetVirtualKey(HWND);
+
+typedef int (CALLBACK *REGISTERWORDENUMPROCA)(LPCSTR, DWORD, LPCSTR, LPVOID);
+typedef int (CALLBACK *REGISTERWORDENUMPROCW)(LPCWSTR, DWORD, LPCWSTR, LPVOID);
+#ifdef UNICODE
+#define REGISTERWORDENUMPROC REGISTERWORDENUMPROCW
+#else
+#define REGISTERWORDENUMPROC REGISTERWORDENUMPROCA
+#endif // !UNICODE
+
+BOOL WINAPI ImmRegisterWordA(HKL, LPCSTR, DWORD, LPCSTR);
+BOOL WINAPI ImmRegisterWordW(HKL, LPCWSTR, DWORD, LPCWSTR);
+#ifdef UNICODE
+#define ImmRegisterWord ImmRegisterWordW
+#else
+#define ImmRegisterWord ImmRegisterWordA
+#endif // !UNICODE
+
+BOOL WINAPI ImmUnregisterWordA(HKL, LPCSTR, DWORD, LPCSTR);
+BOOL WINAPI ImmUnregisterWordW(HKL, LPCWSTR, DWORD, LPCWSTR);
+#ifdef UNICODE
+#define ImmUnregisterWord ImmUnregisterWordW
+#else
+#define ImmUnregisterWord ImmUnregisterWordA
+#endif // !UNICODE
+
+UINT WINAPI ImmGetRegisterWordStyleA(HKL, UINT, LPSTYLEBUFA);
+UINT WINAPI ImmGetRegisterWordStyleW(HKL, UINT, LPSTYLEBUFW);
+#ifdef UNICODE
+#define ImmGetRegisterWordStyle ImmGetRegisterWordStyleW
+#else
+#define ImmGetRegisterWordStyle ImmGetRegisterWordStyleA
+#endif // !UNICODE
+
+UINT WINAPI ImmEnumRegisterWordA(HKL, REGISTERWORDENUMPROCA, LPCSTR, DWORD, LPCSTR, LPVOID);
+UINT WINAPI ImmEnumRegisterWordW(HKL, REGISTERWORDENUMPROCW, LPCWSTR, DWORD, LPCWSTR, LPVOID);
+#ifdef UNICODE
+#define ImmEnumRegisterWord ImmEnumRegisterWordW
+#else
+#define ImmEnumRegisterWord ImmEnumRegisterWordA
+#endif // !UNICODE
+
+#if(WINVER >= 0x040A)
+BOOL WINAPI ImmDisableIME(DWORD);
+DWORD WINAPI ImmGetImeMenuItemsA(HIMC, DWORD, DWORD, LPIMEMENUITEMINFOA, LPIMEMENUITEMINFOA, DWORD);
+DWORD WINAPI ImmGetImeMenuItemsW(HIMC, DWORD, DWORD, LPIMEMENUITEMINFOW, LPIMEMENUITEMINFOW, DWORD);
+#ifdef UNICODE
+#define ImmGetImeMenuItems ImmGetImeMenuItemsW
+#else
+#define ImmGetImeMenuItems ImmGetImeMenuItemsA
+#endif // !UNICODE
+LRESULT WINAPI ImmRequestMessageA(HIMC, WPARAM, LPARAM);
+LRESULT WINAPI ImmRequestMessageW(HIMC, WPARAM, LPARAM);
+#ifdef UNICODE
+#define ImmRequestMessage ImmRequestMessageW
+#else
+#define ImmRequestMessage ImmRequestMessageA
+#endif // !UNICODE
+#endif /* WINVER >= 0x040A */
+
+//
+// Prototype of soft keyboard APIs
+//
+
+HWND WINAPI ImmCreateSoftKeyboard(UINT, HWND, int, int);
+BOOL WINAPI ImmDestroySoftKeyboard(HWND);
+BOOL WINAPI ImmShowSoftKeyboard(HWND, int);
+
+
+LPINPUTCONTEXT WINAPI ImmLockIMC(HIMC);
+BOOL WINAPI ImmUnlockIMC(HIMC);
+DWORD WINAPI ImmGetIMCLockCount(HIMC);
+
+
+HIMCC WINAPI ImmCreateIMCC(DWORD);
+HIMCC WINAPI ImmDestroyIMCC(HIMCC);
+LPVOID WINAPI ImmLockIMCC(HIMCC);
+BOOL WINAPI ImmUnlockIMCC(HIMCC);
+DWORD WINAPI ImmGetIMCCLockCount(HIMCC);
+HIMCC WINAPI ImmReSizeIMCC(HIMCC, DWORD);
+DWORD WINAPI ImmGetIMCCSize(HIMCC);
+
+
+// the window extra offset
+#define IMMGWL_IMC 0
+#define IMMGWL_PRIVATE (sizeof(LONG))
+
+
+
+// the IME related messages
+#define WM_CONVERTREQUESTEX 0x0108
+#define WM_IME_STARTCOMPOSITION 0x010D
+#define WM_IME_ENDCOMPOSITION 0x010E
+#define WM_IME_COMPOSITION 0x010F
+#define WM_IME_KEYLAST 0x010F
+
+#define WM_IME_SETCONTEXT 0x0281
+#define WM_IME_NOTIFY 0x0282
+#define WM_IME_CONTROL 0x0283
+#define WM_IME_COMPOSITIONFULL 0x0284
+#define WM_IME_SELECT 0x0285
+#define WM_IME_CHAR 0x0286
+#define WM_IME_REQUEST 0x0288
+
+#define WM_IME_KEYDOWN 0x0290
+#define WM_IME_KEYUP 0x0291
+
+// wParam for WM_IME_CONTROL
+#define IMC_GETCANDIDATEPOS 0x0007
+#define IMC_SETCANDIDATEPOS 0x0008
+#define IMC_GETCOMPOSITIONFONT 0x0009
+#define IMC_SETCOMPOSITIONFONT 0x000A
+#define IMC_GETCOMPOSITIONWINDOW 0x000B
+#define IMC_SETCOMPOSITIONWINDOW 0x000C
+#define IMC_GETSTATUSWINDOWPOS 0x000F
+#define IMC_SETSTATUSWINDOWPOS 0x0010
+#define IMC_CLOSESTATUSWINDOW 0x0021
+#define IMC_OPENSTATUSWINDOW 0x0022
+
+// for NI_CONTEXTUPDATED
+#define IMC_SETCONVERSIONMODE 0x0002
+#define IMC_SETSENTENCEMODE 0x0004
+#define IMC_SETOPENSTATUS 0x0006
+
+// wParam for WM_IME_CONTROL to the soft keyboard
+#define IMC_GETSOFTKBDFONT 0x0011
+#define IMC_SETSOFTKBDFONT 0x0012
+#define IMC_GETSOFTKBDPOS 0x0013
+#define IMC_SETSOFTKBDPOS 0x0014
+#define IMC_GETSOFTKBDSUBTYPE 0x0015
+#define IMC_SETSOFTKBDSUBTYPE 0x0016
+#define IMC_SETSOFTKBDDATA 0x0018
+
+
+// dwAction for ImmNotifyIME
+#define NI_CONTEXTUPDATED 0x0003
+#define NI_OPENCANDIDATE 0x0010
+#define NI_CLOSECANDIDATE 0x0011
+#define NI_SELECTCANDIDATESTR 0x0012
+#define NI_CHANGECANDIDATELIST 0x0013
+#define NI_FINALIZECONVERSIONRESULT 0x0014
+#define NI_COMPOSITIONSTR 0x0015
+#define NI_SETCANDIDATE_PAGESTART 0x0016
+#define NI_SETCANDIDATE_PAGESIZE 0x0017
+#define NI_IMEMENUSELECTED 0x0018
+
+// lParam for WM_IME_SETCONTEXT
+#define ISC_SHOWUICANDIDATEWINDOW 0x00000001
+#define ISC_SHOWUICOMPOSITIONWINDOW 0x80000000
+#define ISC_SHOWUIGUIDELINE 0x40000000
+#define ISC_SHOWUIALLCANDIDATEWINDOW 0x0000000F
+#define ISC_SHOWUIALL 0xC000000F
+
+// dwIndex for ImmNotifyIME/NI_COMPOSITIONSTR
+#define CPS_COMPLETE 0x0001
+#define CPS_CONVERT 0x0002
+#define CPS_REVERT 0x0003
+#define CPS_CANCEL 0x0004
+
+// the modifiers of hot key
+#define MOD_ALT 0x0001
+#define MOD_CONTROL 0x0002
+#define MOD_SHIFT 0x0004
+
+#define MOD_LEFT 0x8000
+#define MOD_RIGHT 0x4000
+
+#define MOD_ON_KEYUP 0x0800
+#define MOD_IGNORE_ALL_MODIFIER 0x0400
+
+// Windows for Simplified Chinese Edition hot key ID from 0x10 - 0x2F
+#define IME_CHOTKEY_IME_NONIME_TOGGLE 0x10
+#define IME_CHOTKEY_SHAPE_TOGGLE 0x11
+#define IME_CHOTKEY_SYMBOL_TOGGLE 0x12
+
+// Windows for Japanese Edition hot key ID from 0x30 - 0x4F
+#define IME_JHOTKEY_CLOSE_OPEN 0x30
+
+// Windows for Korean Edition hot key ID from 0x50 - 0x6F
+#define IME_KHOTKEY_SHAPE_TOGGLE 0x50
+#define IME_KHOTKEY_HANJACONVERT 0x51
+#define IME_KHOTKEY_ENGLISH 0x52
+
+// Windows for Tranditional Chinese Edition hot key ID from 0x70 - 0x8F
+#define IME_THOTKEY_IME_NONIME_TOGGLE 0x70
+#define IME_THOTKEY_SHAPE_TOGGLE 0x71
+#define IME_THOTKEY_SYMBOL_TOGGLE 0x72
+
+// direct switch hot key ID from 0x100 - 0x11F
+#define IME_HOTKEY_DSWITCH_FIRST 0x100
+#define IME_HOTKEY_DSWITCH_LAST 0x11F
+
+// IME private hot key from 0x200 - 0x21F
+#define IME_HOTKEY_PRIVATE_FIRST 0x200
+#define IME_ITHOTKEY_RESEND_RESULTSTR 0x200
+#define IME_ITHOTKEY_PREVIOUS_COMPOSITION 0x201
+#define IME_ITHOTKEY_UISTYLE_TOGGLE 0x202
+#define IME_ITHOTKEY_RECONVERTSTRING 0x203
+#define IME_HOTKEY_PRIVATE_LAST 0x21F
+
+// dwSystemInfoFlags bits
+#define IME_SYSINFO_WINLOGON 0x0001
+#define IME_SYSINFO_WOW16 0x0002
+
+// parameter of ImmGetCompositionString
+#define GCS_COMPREADSTR 0x0001
+#define GCS_COMPREADATTR 0x0002
+#define GCS_COMPREADCLAUSE 0x0004
+#define GCS_COMPSTR 0x0008
+#define GCS_COMPATTR 0x0010
+#define GCS_COMPCLAUSE 0x0020
+#define GCS_CURSORPOS 0x0080
+#define GCS_DELTASTART 0x0100
+#define GCS_RESULTREADSTR 0x0200
+#define GCS_RESULTREADCLAUSE 0x0400
+#define GCS_RESULTSTR 0x0800
+#define GCS_RESULTCLAUSE 0x1000
+
+// style bit flags for WM_IME_COMPOSITION
+#define CS_INSERTCHAR 0x2000
+#define CS_NOMOVECARET 0x4000
+
+#define GCS_COMP (GCS_COMPSTR|GCS_COMPATTR|GCS_COMPCLAUSE)
+#define GCS_COMPREAD (GCS_COMPREADSTR|GCS_COMPREADATTR |GCS_COMPREADCLAUSE)
+#define GCS_RESULT (GCS_RESULTSTR|GCS_RESULTCLAUSE)
+#define GCS_RESULTREAD (GCS_RESULTREADSTR|GCS_RESULTREADCLAUSE)
+
+// bits of fdwInit of INPUTCONTEXT
+#define INIT_STATUSWNDPOS 0x00000001
+#define INIT_CONVERSION 0x00000002
+#define INIT_SENTENCE 0x00000004
+#define INIT_LOGFONT 0x00000008
+#define INIT_COMPFORM 0x00000010
+#define INIT_SOFTKBDPOS 0x00000020
+
+
+// IME version constants
+#define IMEVER_0310 0x0003000A
+#define IMEVER_0400 0x00040000
+
+// IME property bits
+#define IME_PROP_END_UNLOAD 0x0001
+#define IME_PROP_KBD_CHAR_FIRST 0x0002
+#define IME_PROP_IGNORE_UPKEYS 0x0004
+#define IME_PROP_NEED_ALTKEY 0x0008
+#define IME_PROP_NO_KEYS_ON_CLOSE 0x0010
+#define IME_PROP_AT_CARET 0x00010000
+#define IME_PROP_SPECIAL_UI 0x00020000
+#define IME_PROP_CANDLIST_START_FROM_1 0x00040000
+#define IME_PROP_UNICODE 0x00080000
+#define IME_PROP_COMPLETE_ON_UNSELECT 0x00100000
+
+// IME UICapability bits
+#define UI_CAP_2700 0x00000001
+#define UI_CAP_ROT90 0x00000002
+#define UI_CAP_ROTANY 0x00000004
+#define UI_CAP_SOFTKBD 0x00010000
+
+// ImmSetCompositionString Capability bits
+#define SCS_CAP_COMPSTR 0x00000001
+#define SCS_CAP_MAKEREAD 0x00000002
+#define SCS_CAP_SETRECONVERTSTRING 0x00000004
+
+// IME WM_IME_SELECT inheritance Capability bits
+#define SELECT_CAP_CONVERSION 0x00000001
+#define SELECT_CAP_SENTENCE 0x00000002
+
+// ID for deIndex of ImmGetGuideLine
+#define GGL_LEVEL 0x00000001
+#define GGL_INDEX 0x00000002
+#define GGL_STRING 0x00000003
+#define GGL_PRIVATE 0x00000004
+
+// ID for dwLevel of GUIDELINE Structure
+#define GL_LEVEL_NOGUIDELINE 0x00000000
+#define GL_LEVEL_FATAL 0x00000001
+#define GL_LEVEL_ERROR 0x00000002
+#define GL_LEVEL_WARNING 0x00000003
+#define GL_LEVEL_INFORMATION 0x00000004
+
+// ID for dwIndex of GUIDELINE Structure
+#define GL_ID_UNKNOWN 0x00000000
+#define GL_ID_NOMODULE 0x00000001
+#define GL_ID_NODICTIONARY 0x00000010
+#define GL_ID_CANNOTSAVE 0x00000011
+#define GL_ID_NOCONVERT 0x00000020
+#define GL_ID_TYPINGERROR 0x00000021
+#define GL_ID_TOOMANYSTROKE 0x00000022
+#define GL_ID_READINGCONFLICT 0x00000023
+#define GL_ID_INPUTREADING 0x00000024
+#define GL_ID_INPUTRADICAL 0x00000025
+#define GL_ID_INPUTCODE 0x00000026
+#define GL_ID_INPUTSYMBOL 0x00000027
+#define GL_ID_CHOOSECANDIDATE 0x00000028
+#define GL_ID_REVERSECONVERSION 0x00000029
+#define GL_ID_PRIVATE_FIRST 0x00008000
+#define GL_ID_PRIVATE_LAST 0x0000FFFF
+
+// ID for dwIndex of ImmGetProperty
+#define IGP_GETIMEVERSION (DWORD)(-4)
+#define IGP_PROPERTY 0x00000004
+#define IGP_CONVERSION 0x00000008
+#define IGP_SENTENCE 0x0000000c
+#define IGP_UI 0x00000010
+#define IGP_SETCOMPSTR 0x00000014
+#define IGP_SELECT 0x00000018
+
+// dwIndex for ImmSetCompositionString API
+#define SCS_SETSTR (GCS_COMPREADSTR|GCS_COMPSTR)
+#define SCS_CHANGEATTR (GCS_COMPREADATTR|GCS_COMPATTR)
+#define SCS_CHANGECLAUSE (GCS_COMPREADCLAUSE|GCS_COMPCLAUSE)
+#define SCS_SETRECONVERTSTRING 0x00010000
+#define SCS_QUERYRECONVERTSTRING 0x00020000
+
+// attribute for COMPOSITIONSTRING Structure
+#define ATTR_INPUT 0x00
+#define ATTR_TARGET_CONVERTED 0x01
+#define ATTR_CONVERTED 0x02
+#define ATTR_TARGET_NOTCONVERTED 0x03
+#define ATTR_INPUT_ERROR 0x04
+#define ATTR_FIXEDCONVERTED 0x05
+
+// bit field for IMC_SETCOMPOSITIONWINDOW, IMC_SETCANDIDATEWINDOW
+#define CFS_DEFAULT 0x0000
+#define CFS_RECT 0x0001
+#define CFS_POINT 0x0002
+#define CFS_FORCE_POSITION 0x0020
+#define CFS_CANDIDATEPOS 0x0040
+#define CFS_EXCLUDE 0x0080
+
+// conversion direction for ImmGetConversionList
+#define GCL_CONVERSION 0x0001
+#define GCL_REVERSECONVERSION 0x0002
+#define GCL_REVERSE_LENGTH 0x0003
+
+// bit field for conversion mode
+#define IME_CMODE_ALPHANUMERIC 0x0000
+#define IME_CMODE_NATIVE 0x0001
+#define IME_CMODE_CHINESE IME_CMODE_NATIVE
+#define IME_CMODE_HANGEUL IME_CMODE_NATIVE
+#define IME_CMODE_JAPANESE IME_CMODE_NATIVE
+#define IME_CMODE_KATAKANA 0x0002 // only effect under IME_CMODE_NATIVE
+#define IME_CMODE_LANGUAGE 0x0003
+#define IME_CMODE_FULLSHAPE 0x0008
+#define IME_CMODE_ROMAN 0x0010
+#define IME_CMODE_CHARCODE 0x0020
+#define IME_CMODE_HANJACONVERT 0x0040
+#define IME_CMODE_SOFTKBD 0x0080
+#define IME_CMODE_NOCONVERSION 0x0100
+#define IME_CMODE_EUDC 0x0200
+#define IME_CMODE_SYMBOL 0x0400
+#define IME_CMODE_FIXED 0x0800
+
+#define IME_SMODE_NONE 0x0000
+#define IME_SMODE_PLAURALCLAUSE 0x0001
+#define IME_SMODE_SINGLECONVERT 0x0002
+#define IME_SMODE_AUTOMATIC 0x0004
+#define IME_SMODE_PHRASEPREDICT 0x0008
+#define IME_SMODE_CONVERSATION 0x0010
+
+// style of candidate
+#define IME_CAND_UNKNOWN 0x0000
+#define IME_CAND_READ 0x0001
+#define IME_CAND_CODE 0x0002
+#define IME_CAND_MEANING 0x0003
+#define IME_CAND_RADICAL 0x0004
+#define IME_CAND_STROKE 0x0005
+
+// wParam of report message WM_IME_NOTIFY
+#define IMN_CLOSESTATUSWINDOW 0x0001
+#define IMN_OPENSTATUSWINDOW 0x0002
+#define IMN_CHANGECANDIDATE 0x0003
+#define IMN_CLOSECANDIDATE 0x0004
+#define IMN_OPENCANDIDATE 0x0005
+#define IMN_SETCONVERSIONMODE 0x0006
+#define IMN_SETSENTENCEMODE 0x0007
+#define IMN_SETOPENSTATUS 0x0008
+#define IMN_SETCANDIDATEPOS 0x0009
+#define IMN_SETCOMPOSITIONFONT 0x000A
+#define IMN_SETCOMPOSITIONWINDOW 0x000B
+#define IMN_SETSTATUSWINDOWPOS 0x000C
+#define IMN_GUIDELINE 0x000D
+#define IMN_PRIVATE 0x000E
+
+#if(WINVER >= 0x040A)
+// wParam of report message WM_IME_REQUEST
+#define IMR_COMPOSITIONWINDOW 0x0001
+#define IMR_CANDIDATEWINDOW 0x0002
+#define IMR_COMPOSITIONFONT 0x0003
+#define IMR_RECONVERTSTRING 0x0004
+#define IMR_CONFIRMRECONVERTSTRING 0x0005
+#define IMR_QUERYCHARPOSITION 0x0006
+#define IMR_DOCUMENTFEED 0x0007
+#endif
+
+#define IMN_SOFTKBDDESTROYED 0x0011
+
+
+// error code of ImmGetCompositionString
+#define IMM_ERROR_NODATA (-1)
+#define IMM_ERROR_GENERAL (-2)
+
+// dialog mode of ImmConfigureIME
+#define IME_CONFIG_GENERAL 1
+#define IME_CONFIG_REGISTERWORD 2
+#define IME_CONFIG_SELECTDICTIONARY 3
+
+// dialog mode of ImmEscape
+#define IME_ESC_QUERY_SUPPORT 0x0003
+#define IME_ESC_RESERVED_FIRST 0x0004
+#define IME_ESC_RESERVED_LAST 0x07FF
+#define IME_ESC_PRIVATE_FIRST 0x0800
+#define IME_ESC_PRIVATE_LAST 0x0FFF
+#define IME_ESC_SEQUENCE_TO_INTERNAL 0x1001
+#define IME_ESC_GET_EUDC_DICTIONARY 0x1003
+#define IME_ESC_SET_EUDC_DICTIONARY 0x1004
+#define IME_ESC_MAX_KEY 0x1005
+#define IME_ESC_IME_NAME 0x1006
+#define IME_ESC_SYNC_HOTKEY 0x1007
+#define IME_ESC_HANJA_MODE 0x1008
+#define IME_ESC_AUTOMATA 0x1009
+#define IME_ESC_PRIVATE_HOTKEY 0x100a
+#define IME_ESC_GETHELPFILENAME 0x100b
+
+// style of word registration
+#define IME_REGWORD_STYLE_EUDC 0x00000001
+#define IME_REGWORD_STYLE_USER_FIRST 0x80000000
+#define IME_REGWORD_STYLE_USER_LAST 0xFFFFFFFF
+
+#if(WINVER >= 0x040A)
+// dwFlags for ImmAssociateContextEx
+#define IACE_CHILDREN 0x0001
+#define IACE_DEFAULT 0x0010
+#define IACE_IGNORENOCONTEXT 0x0020
+
+// dwFlags for ImmGetImeMenuItems
+#define IGIMIF_RIGHTMENU 0x00000001
+
+// dwType for ImmGetImeMenuItems
+#define IGIMII_CMODE 0x00000001
+#define IGIMII_SMODE 0x00000002
+#define IGIMII_CONFIGURE 0x00000004
+#define IGIMII_TOOLS 0x00000008
+#define IGIMII_HELP 0x00000010
+#define IGIMII_OTHER 0x00000020
+#define IGIMII_INPUTTOOLS 0x00000040
+
+// fType of IMEMENUITEMINFO structure
+#define IMFT_RADIOCHECK 0x00001
+#define IMFT_SEPARATOR 0x00002
+#define IMFT_SUBMENU 0x00004
+
+// fState of IMEMENUITEMINFO structure
+#define IMFS_GRAYED MFS_GRAYED
+#define IMFS_DISABLED MFS_DISABLED
+#define IMFS_CHECKED MFS_CHECKED
+#define IMFS_HILITE MFS_HILITE
+#define IMFS_ENABLED MFS_ENABLED
+#define IMFS_UNCHECKED MFS_UNCHECKED
+#define IMFS_UNHILITE MFS_UNHILITE
+#define IMFS_DEFAULT MFS_DEFAULT
+#endif /* WINVER >= 0x040A */
+
+// type of soft keyboard
+// for Windows Tranditional Chinese Edition
+#define SOFTKEYBOARD_TYPE_T1 0x0001
+// for Windows Simplified Chinese Edition
+#define SOFTKEYBOARD_TYPE_C1 0x0002
+
+// protype of IME APIs
+BOOL WINAPI ImeInquire(LPIMEINFO, LPTSTR lpszUIClass,DWORD dwSystemInfoFlags);
+BOOL WINAPI ImeConfigure(HKL, HWND, DWORD, LPVOID);
+DWORD WINAPI ImeConversionList(HIMC, LPCTSTR, LPCANDIDATELIST, DWORD dwBufLen, UINT uFlag);
+BOOL WINAPI ImeDestroy(UINT);
+LRESULT WINAPI ImeEscape(HIMC, UINT, LPVOID);
+BOOL WINAPI ImeProcessKey(HIMC, UINT, LPARAM, CONST LPBYTE);
+BOOL WINAPI ImeSelect(HIMC, BOOL);
+BOOL WINAPI ImeSetActiveContext(HIMC, BOOL);
+UINT WINAPI ImeToAsciiEx(UINT uVirtKey, UINT uScaCode, CONST LPBYTE lpbKeyState, LPDWORD lpdwTransBuf, UINT fuState, HIMC);
+BOOL WINAPI NotifyIME(HIMC, DWORD, DWORD, DWORD);
+BOOL WINAPI ImeRegisterWord(LPCTSTR, DWORD, LPCTSTR);
+BOOL WINAPI ImeUnregisterWord(LPCTSTR, DWORD, LPCTSTR);
+UINT WINAPI ImeGetRegisterWordStyle(UINT nItem, LPSTYLEBUF);
+UINT WINAPI ImeEnumRegisterWord(REGISTERWORDENUMPROC, LPCTSTR, DWORD, LPCTSTR, LPVOID);
+BOOL WINAPI ImeSetCompositionString(HIMC, DWORD dwIndex, LPCVOID lpComp, DWORD, LPCVOID lpRead, DWORD);
+#if(WINVER >= 0x040A)
+DWORD WINAPI ImeGetImeMenuItems(HIMC, DWORD, DWORD, LPIMEMENUITEMINFO, LPIMEMENUITEMINFO, DWORD);
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _IMM_
diff --git a/WeaselIME/KeyEvent.cpp b/WeaselIME/KeyEvent.cpp
new file mode 100644
index 000000000..d94041891
--- /dev/null
+++ b/WeaselIME/KeyEvent.cpp
@@ -0,0 +1,175 @@
+#include "stdafx.h"
+#include "KeyEvent.h"
+
+
+bool ConvertKeyEvent(UINT vkey, KeyInfo kinfo, const LPBYTE keyState, weasel::KeyEvent& result)
+{
+ const BYTE KEY_DOWN = 0x80;
+ const BYTE TOGGLED = 0x01;
+ ibus::Keycode TranslateKeycode(UINT vkey);
+
+ // set mask
+ result.mask = ibus::NULL_MASK;
+
+ if ((keyState[VK_SHIFT] & KEY_DOWN) != 0)
+ result.mask |= ibus::SHIFT_MASK;
+
+ if ((keyState[VK_CAPITAL] & TOGGLED) != 0)
+ result.mask |= ibus::LOCK_MASK;
+
+ if ((keyState[VK_CONTROL] & KEY_DOWN) != 0)
+ result.mask |= ibus::CONTROL_MASK;
+
+ if ((keyState[VK_MENU] & KEY_DOWN) != 0)
+ result.mask |= ibus::ALT_MASK;
+
+ if (kinfo.isKeyUp)
+ result.mask |= ibus::RELEASE_MASK;
+
+ // set keycode
+ ibus::Keycode code = TranslateKeycode(vkey);
+ if (code)
+ {
+ result.keycode = code;
+ return true;
+ }
+
+ const int buf_len = 8;
+ static WCHAR buf[buf_len];
+ static BYTE table[256];
+ // 清除Ctrl、Alt鍵狀態,以令ToUnicodeEx()返回字符
+ memcpy(table, keyState, sizeof(table));
+ table[VK_CONTROL] = 0;
+ table[VK_MENU] = 0;
+ int ret = ToUnicodeEx(vkey, UINT(kinfo), table, buf, buf_len, 0, NULL);
+ if (ret == 1)
+ {
+ result.keycode = UINT(buf[0]);
+ return true;
+ }
+
+ result.keycode = 0;
+ return false;
+}
+
+ibus::Keycode TranslateKeycode(UINT vkey)
+{
+ switch (vkey)
+ {
+ case VK_BACK: return ibus::BackSpace;
+ case VK_TAB: return ibus::Tab;
+ case VK_CLEAR: return ibus::Clear;
+ case VK_RETURN: return ibus::Return;
+
+ case VK_SHIFT: return ibus::Shift_L;
+ case VK_CONTROL: return ibus::Control_L;
+ case VK_MENU: return ibus::Alt_L;
+ case VK_PAUSE: return ibus::Pause;
+ case VK_CAPITAL: return ibus::Caps_Lock;
+
+ case VK_KANA: return ibus::Hiragana_Katakana;
+ //case VK_JUNJA: return 0;
+ //case VK_FINAL: return 0;
+ case VK_KANJI: return ibus::Kanji;
+
+ case VK_ESCAPE: return ibus::Escape;
+
+ //case VK_CONVERT: return 0;
+ //case VK_NONCONVERT: return 0;
+ //case VK_ACCEPT: return 0;
+ //case VK_MODECHANGE: return 0;
+
+ case VK_SPACE: return ibus::space;
+ case VK_PRIOR: return ibus::Prior;
+ case VK_NEXT: return ibus::Next;
+ case VK_END: return ibus::End;
+ case VK_HOME: return ibus::Home;
+ case VK_LEFT: return ibus::Left;
+ case VK_UP: return ibus::Up;
+ case VK_RIGHT: return ibus::Right;
+ case VK_DOWN: return ibus::Down;
+ case VK_SELECT: return ibus::Select;
+ case VK_PRINT: return ibus::Print;
+ case VK_EXECUTE: return ibus::Execute;
+ //case VK_SNAPSHOT: return 0;
+ case VK_INSERT: return ibus::Insert;
+ case VK_DELETE: return ibus::Delete;
+ case VK_HELP: return ibus::Help;
+
+ case VK_LWIN: return ibus::Meta_L;
+ case VK_RWIN: return ibus::Meta_R;
+ //case VK_APPS: return 0;
+ //case VK_SLEEP: return 0;
+ case VK_NUMPAD0: return ibus::KP_0;
+ case VK_NUMPAD1: return ibus::KP_1;
+ case VK_NUMPAD2: return ibus::KP_2;
+ case VK_NUMPAD3: return ibus::KP_3;
+ case VK_NUMPAD4: return ibus::KP_4;
+ case VK_NUMPAD5: return ibus::KP_5;
+ case VK_NUMPAD6: return ibus::KP_6;
+ case VK_NUMPAD7: return ibus::KP_7;
+ case VK_NUMPAD8: return ibus::KP_8;
+ case VK_NUMPAD9: return ibus::KP_9;
+ case VK_MULTIPLY: return ibus::KP_Multiply;
+ case VK_ADD: return ibus::KP_Add;
+ case VK_SEPARATOR: return ibus::KP_Separator;
+ case VK_SUBTRACT: return ibus::KP_Subtract;
+ case VK_DECIMAL: return ibus::KP_Decimal;
+ case VK_DIVIDE: return ibus::KP_Divide;
+ case VK_F1: return ibus::F1;
+ case VK_F2: return ibus::F2;
+ case VK_F3: return ibus::F3;
+ case VK_F4: return ibus::F4;
+ case VK_F5: return ibus::F5;
+ case VK_F6: return ibus::F6;
+ case VK_F7: return ibus::F7;
+ case VK_F8: return ibus::F8;
+ case VK_F9: return ibus::F9;
+ case VK_F10: return ibus::F10;
+ case VK_F11: return ibus::F11;
+ case VK_F12: return ibus::F12;
+ case VK_F13: return ibus::F13;
+ case VK_F14: return ibus::F14;
+ case VK_F15: return ibus::F15;
+ case VK_F16: return ibus::F16;
+ case VK_F17: return ibus::F17;
+ case VK_F18: return ibus::F18;
+ case VK_F19: return ibus::F19;
+ case VK_F20: return ibus::F20;
+ case VK_F21: return ibus::F21;
+ case VK_F22: return ibus::F22;
+ case VK_F23: return ibus::F23;
+ case VK_F24: return ibus::F24;
+
+ case VK_NUMLOCK: return ibus::Num_Lock;
+ case VK_SCROLL: return ibus::Scroll_Lock;
+
+ case VK_LSHIFT: return ibus::Shift_L;
+ case VK_RSHIFT: return ibus::Shift_R;
+ case VK_LCONTROL: return ibus::Control_L;
+ case VK_RCONTROL: return ibus::Control_R;
+ case VK_LMENU: return ibus::Alt_L;
+ case VK_RMENU: return ibus::Alt_R;
+ }
+ return ibus::Null;
+}
+
+/*
+struct ModifierNameTableEntry
+{
+ LPCTSTR name;
+ ibus::Modifier modifier;
+};
+
+ModifierNameTableEntry MODIFIER_NAME_TABLE[] = {
+ { L"Shift", ibus::SHIFT_MASK },
+ { L"CapsLock", ibus::LOCK_MASK },
+ { L"Ctrl", ibus::CONTROL_MASK },
+ { L"Alt", ibus::MOD1_MASK },
+ { L"SUPER", ibus::SUPER_MASK },
+ { L"Hyper", ibus::HYPER_MASK },
+ { L"Meta", ibus::META_MASK },
+ { L"Release", ibus::RELEASE_MASK },
+ { NULL, ibus::NULL_MASK }
+ };
+*/
diff --git a/WeaselIME/KeyEvent.h b/WeaselIME/KeyEvent.h
new file mode 100644
index 000000000..8c4a99e2b
--- /dev/null
+++ b/WeaselIME/KeyEvent.h
@@ -0,0 +1,240 @@
+#pragma once
+#include
+
+struct KeyInfo
+{
+ UINT repeatCount: 16;
+ UINT scanCode: 8;
+ UINT isExtended: 1;
+ UINT reserved: 4;
+ UINT contextCode: 1;
+ UINT prevKeyState: 1;
+ UINT isKeyUp: 1;
+
+ KeyInfo(LPARAM lparam)
+ {
+ *this = *reinterpret_cast(&lparam);
+ }
+
+ operator UINT32()
+ {
+ return *reinterpret_cast(this);
+ }
+};
+
+bool ConvertKeyEvent(UINT vkey, KeyInfo kinfo, const LPBYTE keyState, weasel::KeyEvent& result);
+
+
+namespace ibus
+{
+ // keycodes
+
+ enum Keycode
+ {
+ VoidSymbol = 0xFFFFFF,
+ space = 0x020,
+ grave = 0x060,
+ BackSpace = 0xFF08,
+ Tab = 0xFF09,
+ Linefeed = 0xFF0A,
+ Clear = 0xFF0B,
+ Return = 0xFF0D,
+ Pause = 0xFF13,
+ Scroll_Lock = 0xFF14,
+ Sys_Req = 0xFF15,
+ Escape = 0xFF1B,
+ Delete = 0xFFFF,
+ Multi_key = 0xFF20,
+ Codeinput = 0xFF37,
+ SingleCandidate = 0xFF3C,
+ MultipleCandidate = 0xFF3D,
+ PreviousCandidate = 0xFF3E,
+ Kanji = 0xFF21,
+ Muhenkan = 0xFF22,
+ Henkan_Mode = 0xFF23,
+ Henkan = 0xFF23,
+ Romaji = 0xFF24,
+ Hiragana = 0xFF25,
+ Katakana = 0xFF26,
+ Hiragana_Katakana = 0xFF27,
+ Zenkaku = 0xFF28,
+ Hankaku = 0xFF29,
+ Zenkaku_Hankaku = 0xFF2A,
+ Touroku = 0xFF2B,
+ Massyo = 0xFF2C,
+ Kana_Lock = 0xFF2D,
+ Kana_Shift = 0xFF2E,
+ Eisu_Shift = 0xFF2F,
+ Eisu_toggle = 0xFF30,
+ Kanji_Bangou = 0xFF37,
+ Zen_Koho = 0xFF3D,
+ Mae_Koho = 0xFF3E,
+ Home = 0xFF50,
+ Left = 0xFF51,
+ Up = 0xFF52,
+ Right = 0xFF53,
+ Down = 0xFF54,
+ Prior = 0xFF55,
+ Page_Up = 0xFF55,
+ Next = 0xFF56,
+ Page_Down = 0xFF56,
+ End = 0xFF57,
+ Begin = 0xFF58,
+ Select = 0xFF60,
+ Print = 0xFF61,
+ Execute = 0xFF62,
+ Insert = 0xFF63,
+ Undo = 0xFF65,
+ Redo = 0xFF66,
+ Menu = 0xFF67,
+ Find = 0xFF68,
+ Cancel = 0xFF69,
+ Help = 0xFF6A,
+ Break = 0xFF6B,
+ Mode_switch = 0xFF7E,
+ script_switch = 0xFF7E,
+ Num_Lock = 0xFF7F,
+ KP_Space = 0xFF80,
+ KP_Tab = 0xFF89,
+ KP_Enter = 0xFF8D,
+ KP_F1 = 0xFF91,
+ KP_F2 = 0xFF92,
+ KP_F3 = 0xFF93,
+ KP_F4 = 0xFF94,
+ KP_Home = 0xFF95,
+ KP_Left = 0xFF96,
+ KP_Up = 0xFF97,
+ KP_Right = 0xFF98,
+ KP_Down = 0xFF99,
+ KP_Prior = 0xFF9A,
+ KP_Page_Up = 0xFF9A,
+ KP_Next = 0xFF9B,
+ KP_Page_Down = 0xFF9B,
+ KP_End = 0xFF9C,
+ KP_Begin = 0xFF9D,
+ KP_Insert = 0xFF9E,
+ KP_Delete = 0xFF9F,
+ KP_Equal = 0xFFBD,
+ KP_Multiply = 0xFFAA,
+ KP_Add = 0xFFAB,
+ KP_Separator = 0xFFAC,
+ KP_Subtract = 0xFFAD,
+ KP_Decimal = 0xFFAE,
+ KP_Divide = 0xFFAF,
+ KP_0 = 0xFFB0,
+ KP_1 = 0xFFB1,
+ KP_2 = 0xFFB2,
+ KP_3 = 0xFFB3,
+ KP_4 = 0xFFB4,
+ KP_5 = 0xFFB5,
+ KP_6 = 0xFFB6,
+ KP_7 = 0xFFB7,
+ KP_8 = 0xFFB8,
+ KP_9 = 0xFFB9,
+ F1 = 0xFFBE,
+ F2 = 0xFFBF,
+ F3 = 0xFFC0,
+ F4 = 0xFFC1,
+ F5 = 0xFFC2,
+ F6 = 0xFFC3,
+ F7 = 0xFFC4,
+ F8 = 0xFFC5,
+ F9 = 0xFFC6,
+ F10 = 0xFFC7,
+ F11 = 0xFFC8,
+ L1 = 0xFFC8,
+ F12 = 0xFFC9,
+ L2 = 0xFFC9,
+ F13 = 0xFFCA,
+ L3 = 0xFFCA,
+ F14 = 0xFFCB,
+ L4 = 0xFFCB,
+ F15 = 0xFFCC,
+ L5 = 0xFFCC,
+ F16 = 0xFFCD,
+ L6 = 0xFFCD,
+ F17 = 0xFFCE,
+ L7 = 0xFFCE,
+ F18 = 0xFFCF,
+ L8 = 0xFFCF,
+ F19 = 0xFFD0,
+ L9 = 0xFFD0,
+ F20 = 0xFFD1,
+ L10 = 0xFFD1,
+ F21 = 0xFFD2,
+ R1 = 0xFFD2,
+ F22 = 0xFFD3,
+ R2 = 0xFFD3,
+ F23 = 0xFFD4,
+ R3 = 0xFFD4,
+ F24 = 0xFFD5,
+ R4 = 0xFFD5,
+ F25 = 0xFFD6,
+ R5 = 0xFFD6,
+ F26 = 0xFFD7,
+ R6 = 0xFFD7,
+ F27 = 0xFFD8,
+ R7 = 0xFFD8,
+ F28 = 0xFFD9,
+ R8 = 0xFFD9,
+ F29 = 0xFFDA,
+ R9 = 0xFFDA,
+ F30 = 0xFFDB,
+ R10 = 0xFFDB,
+ F31 = 0xFFDC,
+ R11 = 0xFFDC,
+ F32 = 0xFFDD,
+ R12 = 0xFFDD,
+ F33 = 0xFFDE,
+ R13 = 0xFFDE,
+ F34 = 0xFFDF,
+ R14 = 0xFFDF,
+ F35 = 0xFFE0,
+ R15 = 0xFFE0,
+ Shift_L = 0xFFE1,
+ Shift_R = 0xFFE2,
+ Control_L = 0xFFE3,
+ Control_R = 0xFFE4,
+ Caps_Lock = 0xFFE5,
+ Shift_Lock = 0xFFE6,
+ Meta_L = 0xFFE7,
+ Meta_R = 0xFFE8,
+ Alt_L = 0xFFE9,
+ Alt_R = 0xFFEA,
+ Super_L = 0xFFEB,
+ Super_R = 0xFFEC,
+ Hyper_L = 0xFFED,
+ Hyper_R = 0xFFEE,
+ Null = 0
+ };
+
+ // modifiers, modified to fit a UINT16
+
+ enum Modifier
+ {
+ NULL_MASK = 0,
+
+ SHIFT_MASK = 1 << 0,
+ LOCK_MASK = 1 << 1,
+ CONTROL_MASK = 1 << 2,
+ ALT_MASK = 1 << 3,
+ MOD1_MASK = 1 << 3,
+ MOD2_MASK = 1 << 4,
+ MOD3_MASK = 1 << 5,
+ MOD4_MASK = 1 << 6,
+ MOD5_MASK = 1 << 7,
+
+ HANDLED_MASK = 1 << 8,
+ IGNORED_MASK = 1 << 9,
+ FORWARD_MASK = 1 << 9,
+
+ SUPER_MASK = 1 << 10,
+ HYPER_MASK = 1 << 11,
+ META_MASK = 1 << 12,
+
+ RELEASE_MASK = 1 << 14,
+
+ MODIFIER_MASK = 0x2fff
+ };
+
+}
diff --git a/WeaselIME/ReadMe.txt b/WeaselIME/ReadMe.txt
new file mode 100644
index 000000000..b2c5ceb04
--- /dev/null
+++ b/WeaselIME/ReadMe.txt
@@ -0,0 +1,33 @@
+========================================================================
+ DYNAMIC LINK LIBRARY : WeaselIME Project Overview
+========================================================================
+
+AppWizard has created this WeaselIME DLL for you.
+
+This file contains a summary of what you will find in each of the files that
+make up your WeaselIME application.
+
+
+WeaselIME.vcproj
+ This is the main project file for VC++ projects generated using an Application Wizard.
+ It contains information about the version of Visual C++ that generated the file, and
+ information about the platforms, configurations, and project features selected with the
+ Application Wizard.
+
+WeaselIME.cpp
+ This is the main DLL source file.
+
+/////////////////////////////////////////////////////////////////////////////
+Other standard files:
+
+StdAfx.h, StdAfx.cpp
+ These files are used to build a precompiled header (PCH) file
+ named WeaselIME.pch and a precompiled types file named StdAfx.obj.
+
+/////////////////////////////////////////////////////////////////////////////
+Other notes:
+
+AppWizard uses "TODO:" comments to indicate parts of the source code you
+should add to or customize.
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/WeaselIME/WeaselIME.cpp b/WeaselIME/WeaselIME.cpp
new file mode 100644
index 000000000..7befe561d
--- /dev/null
+++ b/WeaselIME/WeaselIME.cpp
@@ -0,0 +1,618 @@
+锘// WeaselIME.cpp : Defines the exported functions for the DLL application.
+//
+
+#include "stdafx.h"
+#include
+#include "WeaselIME.h"
+
+const WCHAR WEASEL[] = L"灏忕嫾姣";
+const WCHAR WEASEL_IME_FILE[] = L"weasel.ime";
+
+HINSTANCE WeaselIME::s_hModule = 0;
+HIMCMap WeaselIME::s_instances;
+
+static bool launch_server()
+{
+
+ // 寰炶ɑ鍐婅〃鍙栧緱server浣嶇疆
+ HKEY hKey;
+ LSTATUS ret = RegOpenKey(HKEY_LOCAL_MACHINE, WeaselIME::GetRegKey(), &hKey);
+ if (ret != ERROR_SUCCESS)
+ {
+ MessageBox(NULL, L"瑷诲唺琛ㄤ俊鎭劇褰变簡", WEASEL, MB_ICONERROR | MB_OK);
+ return false;
+ }
+
+ WCHAR value[MAX_PATH];
+ DWORD len = sizeof(value);
+ DWORD type = 0;
+ ret = RegQueryValueEx(hKey, L"WeaselRoot", NULL, &type, (LPBYTE)value, &len);
+ if (ret != ERROR_SUCCESS)
+ {
+ MessageBox(NULL, L"鏈ō缃 WeaselRoot", WEASEL, MB_ICONERROR | MB_OK);
+ RegCloseKey(hKey);
+ return false;
+ }
+ wpath weaselRoot(value);
+
+ len = sizeof(value);
+ type = 0;
+ ret = RegQueryValueEx(hKey, L"ServerExecutable", NULL, &type, (LPBYTE)value, &len);
+ if (ret != ERROR_SUCCESS)
+ {
+ MessageBox(NULL, L"鏈ō缃 ServerExecutable", WEASEL, MB_ICONERROR | MB_OK);
+ RegCloseKey(hKey);
+ return false;
+ }
+ wpath serverPath(weaselRoot / value);
+
+ RegCloseKey(hKey);
+
+ // 鍟撳嫊鏈嶅嫏閫茬▼
+ wstring exe = serverPath.native_file_string();
+ wstring dir = weaselRoot.native_file_string();
+ int retCode = (int)ShellExecute(NULL, L"open", exe.c_str(), NULL, dir.c_str(), SW_HIDE);
+ if (retCode <= 32)
+ {
+ MessageBox(NULL, L"鏈嶅嫏閫茬▼鍟撳嫊涓嶈捣渚 :(", WEASEL, MB_ICONERROR | MB_OK);
+ return false;
+ }
+ return true;
+}
+
+WeaselIME::WeaselIME(HIMC hIMC)
+ : m_hIMC(hIMC), m_alwaysDetectCaretPos(false)
+{
+ WCHAR path[MAX_PATH];
+ GetModuleFileName(NULL, path, _countof(path));
+ wstring exe = wpath(path).filename();
+ if (boost::iequals(L"chrome.exe", exe))
+ m_alwaysDetectCaretPos = true;
+}
+
+LPCWSTR WeaselIME::GetIMEName()
+{
+ return WEASEL;
+}
+
+LPCWSTR WeaselIME::GetIMEFileName()
+{
+ return WEASEL_IME_FILE;
+}
+
+LPCWSTR WeaselIME::GetRegKey()
+{
+ return L"Software\\Rime\\Weasel";
+}
+
+HINSTANCE WeaselIME::GetModuleInstance()
+{
+ return s_hModule;
+}
+
+void WeaselIME::SetModuleInstance(HINSTANCE hModule)
+{
+ s_hModule = hModule;
+}
+
+HRESULT WeaselIME::RegisterUIClass()
+{
+ WNDCLASSEX wc;
+ wc.cbSize = sizeof(WNDCLASSEX);
+ wc.style = CS_IME;
+ wc.lpfnWndProc = WeaselIME::UIWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 2 * sizeof(LONG);
+ wc.hInstance = GetModuleInstance();
+ wc.hCursor = NULL;
+ wc.hIcon = NULL;
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = GetUIClassName();
+ wc.hbrBackground = NULL;
+ wc.hIconSm = NULL;
+
+ if (RegisterClassExW(&wc) == 0)
+ {
+ DWORD dwErr = GetLastError();
+ return HRESULT_FROM_WIN32(dwErr);
+ }
+
+ return S_OK;
+}
+
+HRESULT WeaselIME::UnregisterUIClass()
+{
+ if (!UnregisterClassW(GetUIClassName(), GetModuleInstance()))
+ {
+ DWORD dwErr = GetLastError();
+ return HRESULT_FROM_WIN32(dwErr);
+ }
+ return S_OK;
+}
+
+LPCWSTR WeaselIME::GetUIClassName()
+{
+ return L"WeaselUIClass";
+}
+
+LRESULT WINAPI WeaselIME::UIWndProc(HWND hWnd, UINT uMsg, WPARAM wp, LPARAM lp)
+{
+ HIMC hIMC = (HIMC)GetWindowLongPtr(hWnd, 0);
+ if (hIMC)
+ {
+ shared_ptr p = WeaselIME::GetInstance(hIMC);
+ if (!p)
+ return 0;
+ return p->OnUIMessage(hWnd, uMsg, wp, lp);
+ }
+ else
+ {
+ if (!IsIMEMessage(uMsg))
+ {
+ return DefWindowProcW(hWnd, uMsg, wp, lp);
+ }
+ }
+
+ return 0;
+}
+
+BOOL WeaselIME::IsIMEMessage(UINT uMsg)
+{
+ switch(uMsg)
+ {
+ case WM_IME_STARTCOMPOSITION:
+ case WM_IME_ENDCOMPOSITION:
+ case WM_IME_COMPOSITION:
+ case WM_IME_NOTIFY:
+ case WM_IME_SETCONTEXT:
+ case WM_IME_CONTROL:
+ case WM_IME_COMPOSITIONFULL:
+ case WM_IME_SELECT:
+ case WM_IME_CHAR:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+
+ return FALSE;
+}
+
+shared_ptr WeaselIME::GetInstance(HIMC hIMC)
+{
+ if (!s_instances.is_valid())
+ {
+ return shared_ptr();
+ }
+ boost::lock_guard lock(s_instances.get_mutex());
+ shared_ptr& p = s_instances[hIMC];
+ if (!p)
+ {
+ p.reset(new WeaselIME(hIMC));
+ }
+ return p;
+}
+
+void WeaselIME::Cleanup()
+{
+ for (map >::const_iterator i = s_instances.begin(); i != s_instances.end(); ++i)
+ {
+ shared_ptr p = i->second;
+ p->OnIMESelect(FALSE);
+ }
+ boost::lock_guard lock(s_instances.get_mutex());
+ s_instances.clear();
+}
+
+LRESULT WeaselIME::OnIMESelect(BOOL fSelect)
+{
+ if (fSelect)
+ {
+ if (!m_ui.Create(NULL))
+ return 0;
+
+ m_ui.SetStyle(GetUIStyleSettings());
+
+ // initialize weasel client
+ m_client.Connect(launch_server);
+ m_client.StartSession();
+
+ wstring ignored;
+ m_ctx.clear();
+ m_status.reset();
+ weasel::ResponseParser parser(ignored, m_ctx, m_status);
+ m_client.GetResponseData(boost::ref(parser));
+
+ m_ui.UpdateContext(m_ctx);
+ //m_ui.UpdateStatus(m_status);
+
+ return _Initialize();
+ }
+ else
+ {
+ m_client.EndSession();
+ m_ui.Destroy();
+
+ return _Finalize();
+ }
+}
+
+LRESULT WeaselIME::OnIMEFocus(BOOL fFocus)
+{
+ if (fFocus)
+ {
+ LPINPUTCONTEXT lpIMC = ImmLockIMC(m_hIMC);
+ if(lpIMC)
+ {
+ if(!(lpIMC->fdwInit & INIT_COMPFORM))
+ {
+ lpIMC->cfCompForm.dwStyle = CFS_DEFAULT;
+ GetCursorPos(&lpIMC->cfCompForm.ptCurrentPos);
+ ScreenToClient(lpIMC->hWnd, &lpIMC->cfCompForm.ptCurrentPos);
+ lpIMC->fdwInit |= INIT_COMPFORM;
+ }
+ ImmUnlockIMC(m_hIMC);
+ }
+
+ if (!m_ctx.empty())
+ m_ui.Show();
+ }
+ else
+ {
+ m_ui.Hide();
+ }
+
+ return 0;
+}
+
+LRESULT WeaselIME::OnUIMessage(HWND hWnd, UINT uMsg, WPARAM wp, LPARAM lp)
+{
+ LPINPUTCONTEXT lpIMC = (LPINPUTCONTEXT)ImmLockIMC(m_hIMC);
+ switch (uMsg)
+ {
+ case WM_IME_NOTIFY:
+ {
+ _OnIMENotify(lpIMC, wp, lp);
+ }
+ break;
+ case WM_IME_SELECT:
+ {
+ // detect caret pos
+ POINT pt = {-1, -1};
+ this->_UpdateInputPosition(lpIMC, pt);
+ }
+ break;
+ default:
+ if (!IsIMEMessage(uMsg))
+ {
+ ImmUnlockIMC(m_hIMC);
+ return DefWindowProcW(hWnd, uMsg, wp, lp);
+ }
+ }
+
+ ImmUnlockIMC(m_hIMC);
+ return 0;
+}
+
+LRESULT WeaselIME::_OnIMENotify(LPINPUTCONTEXT lpIMC, WPARAM wp, LPARAM lp)
+{
+ switch (wp)
+ {
+ case IMN_SETCANDIDATEPOS:
+ {
+ POINT pt = lpIMC->cfCandForm[0].ptCurrentPos;
+ _UpdateInputPosition(lpIMC, pt);
+ }
+
+ case IMN_SETCOMPOSITIONWINDOW:
+ {
+ POINT pt = {-1, -1};
+ switch (lpIMC->cfCompForm.dwStyle)
+ {
+ case CFS_DEFAULT:
+ // require caret pos detection
+ break;
+ default:
+ pt = lpIMC->cfCompForm.ptCurrentPos;
+ break;
+ }
+ _UpdateInputPosition(lpIMC, pt);
+ }
+ break;
+ }
+
+ return 0;
+}
+
+BOOL WeaselIME::ProcessKeyEvent(UINT vKey, KeyInfo kinfo, const LPBYTE lpbKeyState)
+{
+ bool taken = false;
+
+#ifdef KEYCODE_VIEWER
+ {
+ weasel::KeyEvent ke;
+ if (!ConvertKeyEvent(vKey, kinfo, lpbKeyState, ke))
+ {
+ // unknown key event
+ m_ctx.clear();
+ m_ctx.aux.str = (boost::wformat(L"unknown key event vKey: %x, scanCode: %x, isKeyUp: %u") % vKey % kinfo.scanCode % kinfo.isKeyUp).str();
+ return FALSE;
+ }
+ m_ctx.aux.str = (boost::wformat(L"keycode: %x, mask: %x, isKeyUp: %u") % ke.keycode % ke.mask % kinfo.isKeyUp).str();
+ _UpdateContext(m_ctx);
+ return FALSE;
+ }
+#endif
+
+ // 瑕佸鐞咾EY_UP浜嬩欢锛堝淇濇嫾闊崇敤KEY_UP锛
+ //if (kinfo.isKeyUp)
+ //{
+ // return FALSE;
+ //}
+
+ if (!m_client.Echo())
+ {
+ m_client.Connect(launch_server);
+ m_client.StartSession();
+ }
+
+ weasel::KeyEvent ke;
+ if (!ConvertKeyEvent(vKey, kinfo, lpbKeyState, ke))
+ {
+ // unknown key event
+ return FALSE;
+ }
+
+ taken = m_client.ProcessKeyEvent(ke);
+
+ wstring commit;
+ weasel::ResponseParser parser(commit, m_ctx, m_status);
+ bool ok = m_client.GetResponseData(boost::ref(parser));
+ if (!ok)
+ {
+ // may suffer loss of data...
+ m_ctx.aux.clear();
+ m_ctx.aux.str = L"鏈兘瀹屾暣璁鍙栧欓伕淇℃伅锛";
+ //return TRUE;
+ }
+
+ if (!commit.empty())
+ {
+ if (!m_status.composing)
+ {
+ _StartComposition();
+ }
+ _EndComposition(commit.c_str());
+ m_status.composing = false;
+ }
+
+ if (!m_ctx.preedit.empty())
+ {
+ if (!m_status.composing)
+ {
+ _StartComposition();
+ m_status.composing = true;
+ }
+ }
+ else
+ {
+ if (m_status.composing)
+ {
+ _EndComposition(L"");
+ m_status.composing = false;
+ }
+ }
+
+ _UpdateContext(m_ctx);
+
+ return (BOOL)taken;
+}
+
+HRESULT WeaselIME::_Initialize()
+{
+ LPINPUTCONTEXT lpIMC = ImmLockIMC(m_hIMC);
+ if(!lpIMC)
+ return E_FAIL;
+
+ lpIMC->fOpen = TRUE;
+
+ HIMCC& hIMCC = lpIMC->hCompStr;
+ if (!hIMCC)
+ hIMCC = ImmCreateIMCC(sizeof(CompositionInfo));
+ else
+ hIMCC = ImmReSizeIMCC(hIMCC, sizeof(CompositionInfo));
+ if(!hIMCC)
+ {
+ ImmUnlockIMC(m_hIMC);
+ return E_FAIL;
+ }
+
+ CompositionInfo* pInfo = (CompositionInfo*)ImmLockIMCC(hIMCC);
+ if (!pInfo)
+ {
+ ImmUnlockIMC(m_hIMC);
+ return E_FAIL;
+ }
+
+ pInfo->Reset();
+ ImmUnlockIMCC(hIMCC);
+ ImmUnlockIMC(m_hIMC);
+
+ return S_OK;
+}
+
+HRESULT WeaselIME::_Finalize()
+{
+ LPINPUTCONTEXT lpIMC = ImmLockIMC(m_hIMC);
+ if (lpIMC)
+ {
+ lpIMC->fOpen = FALSE;
+ if (lpIMC->hCompStr)
+ {
+ ImmDestroyIMCC(lpIMC->hCompStr);
+ lpIMC->hCompStr = NULL;
+ }
+ }
+ ImmUnlockIMC(m_hIMC);
+
+ return S_OK;
+}
+
+HRESULT WeaselIME::_StartComposition()
+{
+ _AddIMEMessage(WM_IME_STARTCOMPOSITION, 0, 0);
+ _AddIMEMessage(WM_IME_NOTIFY, IMN_OPENCANDIDATE, 0);
+
+ return S_OK;
+}
+
+HRESULT WeaselIME::_EndComposition(LPCWSTR composition)
+{
+ LPINPUTCONTEXT lpIMC;
+ LPCOMPOSITIONSTRING lpCompStr;
+
+ lpIMC = ImmLockIMC(m_hIMC);
+ if (!lpIMC)
+ return E_FAIL;
+
+ lpCompStr = (LPCOMPOSITIONSTRING)ImmLockIMCC(lpIMC->hCompStr);
+ if (!lpCompStr)
+ {
+ ImmUnlockIMC(m_hIMC);
+ return E_FAIL;
+ }
+
+ CompositionInfo* pInfo = (CompositionInfo*)lpCompStr;
+ wcscpy_s(pInfo->szResultStr, composition);
+ lpCompStr->dwResultStrLen = wcslen(pInfo->szResultStr);
+
+ ImmUnlockIMCC(lpIMC->hCompStr);
+ ImmUnlockIMC(m_hIMC);
+
+ _AddIMEMessage(WM_IME_COMPOSITION, 0, GCS_COMP|GCS_RESULTSTR);
+ _AddIMEMessage(WM_IME_ENDCOMPOSITION, 0, 0);
+ _AddIMEMessage(WM_IME_NOTIFY, IMN_CLOSECANDIDATE, 0);
+
+ return S_OK;
+}
+
+HRESULT WeaselIME::_AddIMEMessage(UINT msg, WPARAM wp, LPARAM lp)
+{
+ if(!m_hIMC)
+ return S_FALSE;
+
+ LPINPUTCONTEXT lpIMC = (LPINPUTCONTEXT)ImmLockIMC(m_hIMC);
+ if(!lpIMC)
+ return E_FAIL;
+
+ HIMCC hBuf = ImmReSizeIMCC(lpIMC->hMsgBuf,
+ sizeof(TRANSMSG) * (lpIMC->dwNumMsgBuf + 1));
+ if(!hBuf)
+ {
+ ImmUnlockIMC(m_hIMC);
+ return E_FAIL;
+ }
+ lpIMC->hMsgBuf = hBuf;
+
+ LPTRANSMSG pBuf = (LPTRANSMSG)ImmLockIMCC(hBuf);
+ if(!pBuf)
+ {
+ ImmUnlockIMC(m_hIMC);
+ return E_FAIL;
+ }
+
+ DWORD last = lpIMC->dwNumMsgBuf;
+ pBuf[last].message = msg;
+ pBuf[last].wParam = wp;
+ pBuf[last].lParam = lp;
+ lpIMC->dwNumMsgBuf++;
+ ImmUnlockIMCC(hBuf);
+
+ ImmUnlockIMC(m_hIMC);
+
+ if (!ImmGenerateMessage(m_hIMC))
+ {
+ return E_FAIL;
+ }
+
+ return S_OK;
+}
+
+void WeaselIME::_UpdateInputPosition(LPINPUTCONTEXT lpIMC, POINT pt)
+{
+ if (m_alwaysDetectCaretPos || pt.x == -1 && pt.y == -1)
+ {
+ // caret pos detection required
+ GUITHREADINFO threadInfo;
+ threadInfo.cbSize = sizeof(GUITHREADINFO);
+ BOOL ret = GetGUIThreadInfo(GetCurrentThreadId(), &threadInfo);
+ if (ret && IsWindow(threadInfo.hwndCaret) && IsWindowVisible(threadInfo.hwndCaret))
+ {
+ pt.x = threadInfo.rcCaret.left;
+ pt.y = threadInfo.rcCaret.top;
+ }
+ else
+ pt.x = pt.y = 0;
+ }
+
+ ClientToScreen(lpIMC->hWnd, &pt);
+ int height = abs(lpIMC->lfFont.W.lfHeight);
+ if (height == 0)
+ {
+ HDC hDC = GetDC(lpIMC->hWnd);
+ SIZE sz = {0};
+ GetTextExtentPoint(hDC, L"A", 1, &sz);
+ height = sz.cy;
+ ReleaseDC(lpIMC->hWnd, hDC);
+ }
+ const int width = 6;
+ RECT rc;
+ SetRect(&rc, pt.x, pt.y, pt.x + width, pt.y + height);
+ m_ui.UpdateInputPosition(rc);
+}
+
+void WeaselIME::_UpdateContext(weasel::Context const& ctx)
+{
+ if (!ctx.empty())
+ {
+ m_ui.UpdateContext(m_ctx);
+ m_ui.Show();
+ }
+ else
+ {
+ m_ui.Hide();
+ m_ui.UpdateContext(m_ctx);
+ }
+}
+
+weasel::UIStyle const WeaselIME::GetUIStyleSettings()
+{
+ weasel::UIStyle style;
+
+ HKEY hKey;
+ LSTATUS ret = RegOpenKey(HKEY_LOCAL_MACHINE, WeaselIME::GetRegKey(), &hKey);
+ if (ret != ERROR_SUCCESS)
+ {
+ return style;
+ }
+
+ {
+ WCHAR value[100];
+ DWORD len = sizeof(value);
+ DWORD type = REG_SZ;
+ ret = RegQueryValueEx(hKey, L"FontFace", NULL, &type, (LPBYTE)value, &len);
+ if (ret == ERROR_SUCCESS)
+ style.fontFace = value;
+ }
+
+ {
+ DWORD dword = 0;
+ DWORD len = sizeof(dword);
+ DWORD type = REG_DWORD;
+ ret = RegQueryValueEx(hKey, L"FontPoint", NULL, &type, (LPBYTE)&dword, &len);
+ if (ret == ERROR_SUCCESS)
+ style.fontPoint = (int)dword;
+ }
+
+ RegCloseKey(hKey);
+ return style;
+}
diff --git a/WeaselIME/WeaselIME.h b/WeaselIME/WeaselIME.h
new file mode 100644
index 000000000..86bff77f3
--- /dev/null
+++ b/WeaselIME/WeaselIME.h
@@ -0,0 +1,85 @@
+#pragma once
+#include
+#include
+#include "KeyEvent.h"
+
+#define MAX_COMPOSITION_SIZE 256
+
+struct CompositionInfo
+{
+ COMPOSITIONSTRING cs;
+ WCHAR szCompStr[MAX_COMPOSITION_SIZE];
+ WCHAR szResultStr[MAX_COMPOSITION_SIZE];
+ void Reset()
+ {
+ memset(this, 0, sizeof(*this));
+ cs.dwSize = sizeof(*this);
+ cs.dwCompStrOffset = (char*)&szCompStr - (char*)this;
+ cs.dwResultStrOffset = (char*)&szResultStr - (char*)this;
+ }
+};
+
+typedef struct _tagTRANSMSG {
+ UINT message;
+ WPARAM wParam;
+ LPARAM lParam;
+} TRANSMSG, *LPTRANSMSG;
+
+class WeaselIME;
+
+class HIMCMap : public std::map >
+{
+public:
+ HIMCMap() : m_valid(true) {}
+ ~HIMCMap() { m_valid = false; }
+ boost::mutex& get_mutex() { return m_mutex; }
+ bool is_valid() const { return m_valid; }
+private:
+ bool m_valid;
+ boost::mutex m_mutex;
+};
+
+class WeaselIME
+{
+public:
+ static LPCWSTR GetIMEName();
+ static LPCWSTR GetIMEFileName();
+ static LPCWSTR GetRegKey();
+ static LPCWSTR GetRegValueName();
+ static HINSTANCE GetModuleInstance();
+ static void SetModuleInstance(HINSTANCE hModule);
+ static HRESULT RegisterUIClass();
+ static HRESULT UnregisterUIClass();
+ static LPCWSTR GetUIClassName();
+ static LRESULT WINAPI UIWndProc(HWND hWnd, UINT uMsg, WPARAM wp, LPARAM lp);
+ static BOOL IsIMEMessage(UINT uMsg);
+ static boost::shared_ptr GetInstance(HIMC hIMC);
+ static void Cleanup();
+
+ WeaselIME(HIMC hIMC);
+ LRESULT OnIMESelect(BOOL fSelect);
+ LRESULT OnIMEFocus(BOOL fFocus);
+ LRESULT OnUIMessage(HWND hWnd, UINT uMsg, WPARAM wp, LPARAM lp);
+ BOOL ProcessKeyEvent(UINT vKey, KeyInfo kinfo, const LPBYTE lpbKeyState);
+
+private:
+ HRESULT _Initialize();
+ HRESULT _Finalize();
+ LRESULT _OnIMENotify(LPINPUTCONTEXT lpIMC, WPARAM wp, LPARAM lp);
+ HRESULT _StartComposition();
+ HRESULT _EndComposition(LPCWSTR composition);
+ HRESULT _AddIMEMessage(UINT msg, WPARAM wp, LPARAM lp);
+ void _UpdateInputPosition(LPINPUTCONTEXT lpIMC, POINT pt);
+ void _UpdateContext(weasel::Context const& ctx);
+ weasel::UIStyle const GetUIStyleSettings();
+
+private:
+ static HINSTANCE s_hModule;
+ static HIMCMap s_instances;
+ HIMC m_hIMC;
+ bool m_alwaysDetectCaretPos;
+ weasel::UI m_ui;
+ weasel::Client m_client;
+ weasel::Context m_ctx;
+ weasel::Status m_status;
+};
diff --git a/WeaselIME/WeaselIME.rc b/WeaselIME/WeaselIME.rc
new file mode 100644
index 000000000..6fbb978ca
--- /dev/null
+++ b/WeaselIME/WeaselIME.rc
@@ -0,0 +1,127 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Chinese (P.R.C.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
+#ifdef _WIN32
+LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
+#pragma code_page(936)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 0,3,0,0
+ PRODUCTVERSION 0,3,0,0
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x3L
+ FILESUBTYPE 0xbL
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040404b0"
+ BEGIN
+ VALUE "CompanyName", "中州式恕堂"
+ VALUE "FileDescription", "小狼毫"
+ VALUE "FileVersion", "0, 3, 0, 0"
+ VALUE "InternalName", "WeaselIME"
+ VALUE "LegalCopyright", "版權所無 中州式恕堂 2011"
+ VALUE "OriginalFilename", "weasel.ime"
+ VALUE "ProductName", "小狼毫"
+ VALUE "ProductVersion", "0, 3, 0, 0"
+ END
+ BLOCK "080404b0"
+ BEGIN
+ VALUE "CompanyName", "中州式恕堂"
+ VALUE "FileDescription", "小狼毫"
+ VALUE "FileVersion", "0, 3, 0, 0"
+ VALUE "InternalName", "WeaselIME"
+ VALUE "LegalCopyright", "版權所無 中州式恕堂 2011"
+ VALUE "OriginalFilename", "weasel.ime"
+ VALUE "ProductName", "小狼毫"
+ VALUE "ProductVersion", "0, 3, 0, 0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+#ifdef WEASEL_HANT
+ VALUE "Translation", 0x404, 1200
+#else
+ VALUE "Translation", 0x804, 1200
+#endif
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_ZHUNG ICON "..\\resource\\zhung.ico"
+IDI_ALPHA ICON "..\\resource\\alpha.ico"
+#endif // Chinese (P.R.C.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/WeaselIME/WeaselIME.vcproj b/WeaselIME/WeaselIME.vcproj
new file mode 100644
index 000000000..0b1d9b39c
--- /dev/null
+++ b/WeaselIME/WeaselIME.vcproj
@@ -0,0 +1,404 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/WeaselIME/dllmain.cpp b/WeaselIME/dllmain.cpp
new file mode 100644
index 000000000..49abbf109
--- /dev/null
+++ b/WeaselIME/dllmain.cpp
@@ -0,0 +1,245 @@
+锘// dllmain.cpp : Defines the entry point for the DLL application.
+#include "stdafx.h"
+#include "WeaselIME.h"
+
+
+BOOL APIENTRY DllMain( HMODULE hModule,
+ DWORD ul_reason_for_call,
+ LPVOID lpReserved
+ )
+{
+ WeaselIME::SetModuleInstance(hModule);
+
+ switch (ul_reason_for_call)
+ {
+ case DLL_PROCESS_ATTACH:
+ {
+ HRESULT hr = WeaselIME::RegisterUIClass();
+ if (FAILED(hr))
+ return FALSE;
+ }
+ break;
+ case DLL_THREAD_ATTACH:
+ break;
+ case DLL_THREAD_DETACH:
+ break;
+ case DLL_PROCESS_DETACH:
+ WeaselIME::Cleanup();
+ WeaselIME::UnregisterUIClass();
+ break;
+ }
+ return TRUE;
+}
+
+BOOL copy_file(const wstring& src, const wstring& dest)
+{
+ BOOL ret = CopyFile(src.c_str(), dest.c_str(), FALSE);
+ if (!ret)
+ {
+ for (int i = 0; i < 10; ++i)
+ {
+ wstring old = (boost::wformat(L"%1%.old.%2%") % dest % i).str();
+ if (MoveFileEx(dest.c_str(), old.c_str(), MOVEFILE_REPLACE_EXISTING))
+ {
+ MoveFileEx(old.c_str(), NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
+ break;
+ }
+ }
+ ret = CopyFile(src.c_str(), dest.c_str(), FALSE);
+ }
+ return ret;
+}
+
+BOOL delete_file(const wstring& file)
+{
+ BOOL ret = DeleteFile(file.c_str());
+ if (!ret)
+ {
+ for (int i = 0; i < 10; ++i)
+ {
+ wstring old = (boost::wformat(L"%1%.old.%2%") % file % i).str();
+ if (MoveFileEx(file.c_str(), old.c_str(), MOVEFILE_REPLACE_EXISTING))
+ {
+ MoveFileEx(old.c_str(), NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
+ return TRUE;
+ }
+ }
+ }
+ return ret;
+}
+
+//
+// rundll32
+//
+
+extern "C" __declspec(dllexport)
+void install(HWND hWnd, HINSTANCE hInstance, LPWSTR lpszCmdLine, int nCmdShow)
+{
+ WCHAR path[MAX_PATH];
+
+ GetModuleFileName(WeaselIME::GetModuleInstance(), path, _countof(path));
+ wpath srcPath(path);
+
+ ExpandEnvironmentStrings(L"%SystemRoot%\\system32\\", path, _countof(path));
+ wpath destPath(path);
+ destPath /= WeaselIME::GetIMEFileName();
+
+ // 澶嶅埗 weasel.ime 鍒扮郴缁熺洰褰
+ if (!copy_file(srcPath.native_file_string(), destPath.native_file_string()))
+ {
+ MessageBox(hWnd, destPath.native_file_string().c_str(), L"瀹夎澶辨晽", MB_ICONERROR | MB_OK);
+ return;
+ }
+
+ // 鍐欐敞鍐岃〃
+ HKEY hKey;
+ LSTATUS ret = RegCreateKeyEx(HKEY_LOCAL_MACHINE, WeaselIME::GetRegKey(),
+ 0, NULL, 0, KEY_ALL_ACCESS, 0, &hKey, NULL);
+ if (FAILED(HRESULT_FROM_WIN32(ret)))
+ {
+ MessageBox(hWnd, WeaselIME::GetRegKey(), L"瀹夎澶辨晽", MB_ICONERROR | MB_OK);
+ return;
+ }
+
+ wstring rootDir = srcPath.parent_path().native_directory_string();
+ ret = RegSetValueEx(hKey, L"WeaselRoot", 0, REG_SZ,
+ (const BYTE*)rootDir.c_str(),
+ (rootDir.length() + 1) * sizeof(WCHAR));
+ if (FAILED(HRESULT_FROM_WIN32(ret)))
+ {
+ MessageBox(hWnd, L"鐒℃硶瀵叆 WeaselRoot", L"瀹夎澶辨晽", MB_ICONERROR | MB_OK);
+ return;
+ }
+
+ const wstring executable = L"WeaselServer.exe";
+ ret = RegSetValueEx(hKey, L"ServerExecutable", 0, REG_SZ,
+ (const BYTE*)executable.c_str(),
+ (executable.length() + 1) * sizeof(WCHAR));
+ if (FAILED(HRESULT_FROM_WIN32(ret)))
+ {
+ MessageBox(hWnd, L"鐒℃硶瀵叆 ServerExecutable", L"瀹夎澶辨晽", MB_ICONERROR | MB_OK);
+ return;
+ }
+
+ RegCloseKey(hKey);
+
+ // 娉ㄥ唽杈撳叆娉
+ HKL hKL = ImmInstallIME(destPath.native_file_string().c_str(), WeaselIME::GetIMEName());
+ if (!hKL)
+ {
+ DWORD dwErr = GetLastError();
+ WCHAR msg[100];
+ wsprintf(msg, L"ImmInstallIME: HKL=%x Err=%x", hKL, dwErr);
+ MessageBox(hWnd, msg, L"瀹夎澶辨晽", MB_ICONERROR | MB_OK);
+ return;
+ }
+
+ MessageBox(hWnd, L"灏忕嫾姣 :)", L"瀹夎瀹屾垚", MB_OK);
+}
+
+extern "C" __declspec(dllexport)
+void uninstall(HWND hWnd, HINSTANCE hInstance, LPWSTR lpszCmdLine, int nCmdShow)
+{
+ const WCHAR KL_KEY[] = L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts";
+ const WCHAR PRELOAD_KEY[] = L"Keyboard Layout\\Preload";
+
+ HKEY hKey;
+ LSTATUS ret = RegOpenKey(HKEY_LOCAL_MACHINE, KL_KEY, &hKey);
+ if (ret != ERROR_SUCCESS)
+ {
+ MessageBox(hWnd, KL_KEY, L"鍗歌級澶辨晽", MB_ICONERROR | MB_OK);
+ return;
+ }
+
+ for (int i = 0; true; ++i)
+ {
+ WCHAR subKey[16];
+ ret = RegEnumKey(hKey, i, subKey, _countof(subKey));
+ if (ret != ERROR_SUCCESS)
+ break;
+
+ // 涓枃閿洏甯冨眬?
+ if (wcscmp(subKey + 4, L"0804") == 0 || wcscmp(subKey + 4, L"0404") == 0)
+ {
+ HKEY hSubKey;
+ ret = RegOpenKey(hKey, subKey, &hSubKey);
+ if (ret != ERROR_SUCCESS)
+ continue;
+
+ WCHAR imeFile[32];
+ DWORD len = sizeof(imeFile);
+ DWORD type = 0;
+ ret = RegQueryValueEx(hSubKey, L"Ime File", NULL, &type, (LPBYTE)imeFile, &len);
+ RegCloseKey(hSubKey);
+ if (ret != ERROR_SUCCESS)
+ continue;
+
+ // 灏忕嫾姣?
+ if (_wcsicmp(imeFile, WeaselIME::GetIMEFileName()) == 0)
+ {
+ DWORD value;
+ swscanf_s(subKey, L"%x", &value);
+ UnloadKeyboardLayout((HKL)value);
+
+ RegDeleteKey(hKey, subKey);
+
+ // 绉婚櫎preload
+ HKEY hPreloadKey;
+ ret = RegOpenKey(HKEY_CURRENT_USER, PRELOAD_KEY, &hPreloadKey);
+ if (ret != ERROR_SUCCESS)
+ continue;
+ vector preloads;
+ wstring number;
+ for (size_t i = 1; true; ++i)
+ {
+ number = (boost::wformat(L"%1%") % i).str();
+ DWORD type = 0;
+ WCHAR value[32];
+ DWORD len = sizeof(value);
+ ret = RegQueryValueEx(hPreloadKey, number.c_str(), 0, &type, (LPBYTE)value, &len);
+ if (ret != ERROR_SUCCESS)
+ {
+ if (i > preloads.size())
+ {
+ // 鍒犻櫎鏈澶т竴鍙锋敞鍐岃〃鍊
+ number = (boost::wformat(L"%1%") % (i - 1)).str();
+ RegDeleteValue(hPreloadKey, number.c_str());
+ }
+ break;
+ }
+ if (_wcsicmp(subKey, value) != 0)
+ {
+ preloads.push_back(value);
+ }
+ }
+ // 閲嶅啓preloads
+ for (size_t i = 0; i < preloads.size(); ++i)
+ {
+ number = (boost::wformat(L"%1%") % (i + 1)).str();
+ RegSetValueEx(hPreloadKey, number.c_str(), 0, REG_SZ,
+ (const BYTE*)preloads[i].c_str(),
+ (preloads[i].length() + 1) * sizeof(WCHAR));
+ }
+ RegCloseKey(hPreloadKey);
+ }
+ }
+ }
+
+ RegCloseKey(hKey);
+
+ // 娓呴櫎娉ㄥ唽淇℃伅
+ RegDeleteKey(HKEY_LOCAL_MACHINE, WeaselIME::GetRegKey());
+
+ // 鍒犻櫎鏂囦欢
+ WCHAR path[MAX_PATH];
+ ExpandEnvironmentStrings(L"%SystemRoot%\\system32\\", path, _countof(path));
+ wstring file = path;
+ file += WeaselIME::GetIMEFileName();
+ if (!delete_file(file))
+ {
+ MessageBox(hWnd, file.c_str(), L"鍗歌級澶辨晽", MB_ICONERROR | MB_OK);
+ return;
+ }
+
+ MessageBox(hWnd, L"灏忕嫾姣 :)", L"鍗歌級瀹屾垚", MB_OK);
+}
diff --git a/WeaselIME/ime.cpp b/WeaselIME/ime.cpp
new file mode 100644
index 000000000..0d2201192
--- /dev/null
+++ b/WeaselIME/ime.cpp
@@ -0,0 +1,135 @@
+#include "stdafx.h"
+#include "WeaselIME.h"
+
+#pragma warning(disable: 4996)
+
+//
+// IME export functions
+//
+
+BOOL WINAPI ImeInquire(IMEINFO* lpIMEInfo, LPWSTR lpszUIClass, DWORD dwSystemInfoFlags)
+{
+ if (!lpIMEInfo || !lpszUIClass)
+ return FALSE;
+
+ if (dwSystemInfoFlags & IME_SYSINFO_WINLOGON)
+ {
+ // TODO: disable input method in winlogon.exe (not tested)
+ return FALSE;
+ }
+
+ wcscpy(lpszUIClass, WeaselIME::GetUIClassName());
+
+ lpIMEInfo->dwPrivateDataSize = 0;
+ lpIMEInfo->fdwProperty = IME_PROP_UNICODE | IME_PROP_SPECIAL_UI;
+ lpIMEInfo->fdwConversionCaps = IME_CMODE_FULLSHAPE | IME_CMODE_NATIVE;
+ lpIMEInfo->fdwSentenceCaps = IME_SMODE_NONE;
+ lpIMEInfo->fdwUICaps = UI_CAP_2700;
+ lpIMEInfo->fdwSCSCaps = 0;
+ lpIMEInfo->fdwSelectCaps = SELECT_CAP_CONVERSION;
+
+ return TRUE;
+}
+
+BOOL WINAPI ImeConfigure(HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData)
+{
+ // TODO:
+ MessageBox(hWnd, L"本品無設定介面 :)", L"輸入法設定", MB_OK);
+ return TRUE;
+}
+
+DWORD WINAPI ImeConversionList(HIMC hIMC, LPCTSTR lpSource, LPCANDIDATELIST lpCandList, DWORD dwBufLen, UINT uFlag)
+{
+ //
+ return TRUE;
+}
+
+BOOL WINAPI ImeDestroy(UINT uForce)
+{
+ //
+ return TRUE;
+}
+
+LRESULT WINAPI ImeEscape(HIMC hIMC, UINT uSubFunc, LPVOID lpData)
+{
+ //
+ return TRUE;
+}
+
+BOOL WINAPI ImeProcessKey(HIMC hIMC, UINT vKey, LPARAM lKeyData, const LPBYTE lpbKeyState)
+{
+ BOOL bEaten = FALSE;
+ shared_ptr p = WeaselIME::GetInstance(hIMC);
+ if (!p)
+ return FALSE;
+ bEaten = p->ProcessKeyEvent(vKey, lKeyData, lpbKeyState);
+ return bEaten;
+}
+
+BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect)
+{
+ shared_ptr p = WeaselIME::GetInstance(hIMC);
+ if (!p)
+ return FALSE;
+ HRESULT hr = p->OnIMESelect(fSelect);
+ if (FAILED(hr))
+ return FALSE;
+
+ return TRUE;
+}
+
+BOOL WINAPI ImeSetActiveContext(HIMC hIMC, BOOL fFocus)
+{
+ if (hIMC)
+ {
+ shared_ptr p = WeaselIME::GetInstance(hIMC);
+ if (!p)
+ return FALSE;
+ HRESULT hr = p->OnIMEFocus(fFocus);
+ if (FAILED(hr))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+UINT WINAPI ImeToAsciiEx (UINT uVKey, UINT uScanCode, CONST LPBYTE lpbKeyState, LPDWORD lpdwTransKey, UINT fuState, HIMC hIMC)
+{
+ //
+ return 0;
+}
+
+BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue)
+{
+ //
+ return TRUE;
+}
+BOOL WINAPI ImeRegisterWord(LPCTSTR lpRead, DWORD dw, LPCTSTR lpStr)
+{
+ //
+ return FALSE;
+}
+
+BOOL WINAPI ImeUnregisterWord(LPCTSTR lpRead, DWORD dw, LPCTSTR lpStr)
+{
+ //
+ return FALSE;
+}
+
+UINT WINAPI ImeGetRegisterWordStyle(UINT nItem, LPSTYLEBUF lp)
+{
+ //
+ return 0;
+}
+
+UINT WINAPI ImeEnumRegisterWord(REGISTERWORDENUMPROC lpfn, LPCTSTR lpRead, DWORD dw, LPCTSTR lpStr, LPVOID lpData)
+{
+ //
+ return 0;
+}
+
+BOOL WINAPI ImeSetCompositionString(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp, DWORD dwComp, LPCVOID lpRead, DWORD dwRead)
+{
+ //
+ return FALSE;
+}
diff --git a/WeaselIME/resource.h b/WeaselIME/resource.h
new file mode 100644
index 000000000..1f00a556c
--- /dev/null
+++ b/WeaselIME/resource.h
@@ -0,0 +1,17 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by WeaselIME.rc
+//
+#define IDI_ZHUNG 101
+#define IDI_ALPHA 102
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 103
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/WeaselIME/stdafx.cpp b/WeaselIME/stdafx.cpp
new file mode 100644
index 000000000..b11d5c022
--- /dev/null
+++ b/WeaselIME/stdafx.cpp
@@ -0,0 +1,8 @@
+// stdafx.cpp : source file that includes just the standard includes
+// WeaselIME.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
diff --git a/WeaselIME/stdafx.h b/WeaselIME/stdafx.h
new file mode 100644
index 000000000..a801f2898
--- /dev/null
+++ b/WeaselIME/stdafx.h
@@ -0,0 +1,33 @@
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#pragma once
+
+#include "targetver.h"
+
+#define NOIME
+
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+#include
+#include
+
+#include "Imm.h"
+
+#pragma warning(disable : 4819)
+
+#include
+#include
+#include
+#include
+#include
+
+#pragma warning(default : 4819)
+
+#include